From bd78c34b99ab2f02fd8e19237646b9083c186ba1 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 23 Jul 2018 23:50:41 +0100 Subject: [PATCH 01/84] Encore mode - a fresh take on mirror mode! * Palette remaps. * Branding. TODO: * Doesn't work in GL. (Mostly.) I have SOME ideas on how to tackle this, but... * Transmaps are broken in Encore for some reason. * I tried to make in-level colormaps shimmy over, but it didn't quite work, so I commented it out and only semi-fixed it. --- src/d_netcmd.c | 14 ++--- src/d_netcmd.h | 2 +- src/doomstat.h | 2 +- src/g_game.c | 8 +-- src/hardware/hw_defs.h | 2 +- src/hardware/hw_main.c | 8 ++- src/info.c | 4 +- src/k_kart.c | 18 +++--- src/m_menu.c | 4 +- src/p_mobj.c | 2 +- src/p_saveg.c | 4 +- src/p_setup.c | 57 +++++++++--------- src/p_user.c | 2 +- src/r_bsp.c | 22 +++++-- src/r_data.c | 130 ++++++++++++++++++++++++++++++++++------- src/r_data.h | 2 +- src/r_draw8.c | 4 ++ src/r_plane.c | 10 +++- src/r_plane.h | 4 +- src/r_segs.c | 20 +++++++ src/r_state.h | 1 + src/r_things.c | 7 +++ src/s_sound.c | 4 +- src/st_stuff.c | 15 ++++- src/y_inter.c | 6 ++ 25 files changed, 256 insertions(+), 96 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a83f23b2..bb9a9f76 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -112,7 +112,7 @@ static void SoundTest_OnChange(void); static void BaseNumLaps_OnChange(void); static void KartFrantic_OnChange(void); static void KartSpeed_OnChange(void); -static void KartMirror_OnChange(void); +static void KartEncore_OnChange(void); static void KartComeback_OnChange(void); #ifdef NETGAME_DEVMODE @@ -362,7 +362,7 @@ static CV_PossibleValue_t kartbumpers_cons_t[] = {{1, "MIN"}, {12, "MAX"}, {0, N consvar_t cv_kartbumpers = {"kartbumpers", "3", CV_NETVAR|CV_CHEAT, kartbumpers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartFrantic_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_kartmirror = {"kartmirror", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartMirror_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display @@ -5231,16 +5231,16 @@ static void KartSpeed_OnChange(void) } } -static void KartMirror_OnChange(void) +static void KartEncore_OnChange(void) { if (G_RaceGametype()) { - if ((boolean)cv_kartmirror.value != mirrormode && gamestate == GS_LEVEL /*&& leveltime > starttime*/) - CONS_Printf(M_GetText("Mirrored tracks will be turned %s next round.\n"), cv_kartmirror.value ? M_GetText("on") : M_GetText("off")); + if ((boolean)cv_kartencore.value != encoremode && gamestate == GS_LEVEL /*&& leveltime > starttime*/) + CONS_Printf(M_GetText("Encore tracks will be turned %s next round.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); else { - CONS_Printf(M_GetText("Mirrored tracks has been turned %s.\n"), cv_kartmirror.value ? M_GetText("on") : M_GetText("off")); - mirrormode = (boolean)cv_kartmirror.value; + CONS_Printf(M_GetText("Encore tracks has been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); + encoremode = (boolean)cv_kartencore.value; } } } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 0805a41f..960390ef 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -124,7 +124,7 @@ extern consvar_t cv_kartspeed; extern consvar_t cv_kartbumpers; extern consvar_t cv_kartfrantic; extern consvar_t cv_kartcomeback; -extern consvar_t cv_kartmirror; +extern consvar_t cv_kartencore; extern consvar_t cv_kartspeedometer; extern consvar_t cv_votetime; diff --git a/src/doomstat.h b/src/doomstat.h index 8f1469a3..0f2657b0 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -446,7 +446,7 @@ extern INT32 cheats; // SRB2kart extern UINT8 gamespeed; extern boolean franticitems; -extern boolean mirrormode; +extern boolean encoremode; extern boolean comeback; extern SINT8 battlewanted[4]; diff --git a/src/g_game.c b/src/g_game.c index a652e83f..59042ff2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -248,7 +248,7 @@ INT32 cheats; //for multiplayer cheat commands // SRB2Kart // Cvars that we don't want changed mid-game UINT8 gamespeed; // Game's current speed (or difficulty, or cc, or etc); 0 for easy, 1 for normal, 2 for hard -boolean mirrormode; // Mirror Mode currently enabled? +boolean encoremode; // Encore Mode currently enabled? boolean franticitems; // Frantic items currently enabled? boolean comeback; // Battle Mode's karma comeback is on/off @@ -1267,7 +1267,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) axis = JoyAxis(AXISTURN, ssplayer); - if (mirrormode) + if (encoremode) { turnright ^= turnleft; // swap these using three XORs turnleft ^= turnright; @@ -1318,8 +1318,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // Specator mouse turning if (player->spectator) { - cmd->angleturn = (INT16)(cmd->angleturn - (mousex*(mirrormode ? -1 : 1)*8)); - cmd->driftturn = (INT16)(cmd->driftturn - (mousex*(mirrormode ? -1 : 1)*8)); + cmd->angleturn = (INT16)(cmd->angleturn - (mousex*(encoremode ? -1 : 1)*8)); + cmd->driftturn = (INT16)(cmd->driftturn - (mousex*(encoremode ? -1 : 1)*8)); } // Speed bump strafing diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 9a490a96..2d346878 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -109,7 +109,7 @@ typedef struct FLOAT fovxangle, fovyangle; UINT8 splitscreen; boolean flip; // screenflip - boolean mirror; // SRB2Kart: Mirror Mode + boolean mirror; // SRB2Kart: Encore Mode } FTransform; // Transformed vector, as passed to HWR API diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4b088dfd..be176f7d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3147,7 +3147,6 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y); } - if (planecolormap) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, planecolormap->rgba, planecolormap->fadergba, false, true); else @@ -5441,7 +5440,11 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->colormap = R_GetTranslationColormap(TC_DEFAULT, thing->color, GTC_CACHE); } else + { vis->colormap = colormaps; + if (encoremap && (thing->flags & (MF_SCENERY|MF_NOTHINK))) + vis->colormap += (256*32); + } // set top/bottom coords vis->ty = gzt; @@ -5545,6 +5548,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->mobj = (mobj_t *)thing; vis->colormap = colormaps; + if (encoremap) + vis->colormap += (256*32); // set top/bottom coords vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); @@ -6537,6 +6542,7 @@ static void HWR_RenderWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, FBITFIE alpha = pSurf->FlatColor.s.alpha; // retain the alpha // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting + if (wallcolormap) { if (fogwall) diff --git a/src/info.c b/src/info.c index 939efd44..8565702c 100644 --- a/src/info.c +++ b/src/info.c @@ -13240,7 +13240,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_SLIDEME, // flags S_NULL // raisestate }, @@ -14349,7 +14349,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_SLIDEME, // flags S_NULL // raisestate }, diff --git a/src/k_kart.c b/src/k_kart.c index 8d64af57..e65942a3 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -24,7 +24,7 @@ // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: // gamespeed is cc (0 for easy, 1 for normal, 2 for hard) // franticitems is Frantic Mode items, bool -// mirrormode is Mirror Mode (duh), bool +// encoremode is Encore Mode (duh), bool // comeback is Battle Mode's karma comeback, also bool // battlewanted is an array of the WANTED player nums, -1 for no player in that slot // indirectitemcooldown is timer before anyone's allowed another Shrink/SPB @@ -401,7 +401,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartbumpers); CV_RegisterVar(&cv_kartfrantic); CV_RegisterVar(&cv_kartcomeback); - CV_RegisterVar(&cv_kartmirror); + CV_RegisterVar(&cv_kartencore); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_votetime); @@ -5174,7 +5174,7 @@ fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my else x = (FixedMul(FINETANGENT(((diff+ANGLE_90)>>ANGLETOFINESHIFT) & 4095), 160<>FRACBITS; - if (mirrormode) + if (encoremode) x = 320-x; if (splitscreen > 1) @@ -5383,14 +5383,14 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat amnumxpos = (FixedMul(mo->x, zoom) - FixedMul(xoffset, zoom)); amnumypos = -(FixedMul(mo->y, zoom) - FixedMul(yoffset, zoom)); - if (mirrormode) + if (encoremode) amnumxpos = -amnumxpos; amxpos = amnumxpos + ((x + AutomapPic->width/2 - (iconprefix[skin]->width/2))<height/2 - (iconprefix[skin]->height/2))<width/2 + (iconprefix[skin]->width/2))<width), y, splitflags|V_FLIP, AutomapPic); else V_DrawScaledPatch(x, y, splitflags, AutomapPic); @@ -5462,7 +5462,7 @@ static void K_drawKartMinimap(void) } // let offsets transfer to the heads, too! - if (mirrormode) + if (encoremode) x += SHORT(AutomapPic->leftoffset); else x -= SHORT(AutomapPic->leftoffset); @@ -5730,7 +5730,7 @@ static void K_drawKartFirstPerson(void) else // forward target = 0; - if (mirrormode) + if (encoremode) target = -target; if (pn < target) @@ -5797,7 +5797,7 @@ static void K_drawKartFirstPerson(void) if (stplyr->mo->momz > 0) // TO-DO: Draw more of the kart so we can remove this if! yoffs += stplyr->mo->momz/3; - if (mirrormode) + if (encoremode) x -= xoffs; else x += xoffs; diff --git a/src/m_menu.c b/src/m_menu.c index 48857e20..9cc87453 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1413,7 +1413,7 @@ static menuitem_t OP_GameOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Game Speed", &cv_kartspeed, 30}, {IT_STRING | IT_CVAR, NULL, "Frantic Items", &cv_kartfrantic, 40}, - {IT_STRING | IT_CVAR, NULL, "Mirror Mode", &cv_kartmirror, 50}, + {IT_STRING | IT_CVAR, NULL, "Encore Mode", &cv_kartencore, 50}, {IT_STRING | IT_CVAR, NULL, "Number of Laps", &cv_basenumlaps, 70}, {IT_STRING | IT_CVAR, NULL, "Exit Countdown Timer", &cv_countdowntime, 80}, @@ -1470,7 +1470,7 @@ static menuitem_t OP_ServerOptionsMenu[] = { {IT_HEADER, NULL, "RACE", NULL, 2}, {IT_STRING | IT_CVAR, NULL, "Game Speed", &cv_kartspeed, 10}, - {IT_STRING | IT_CVAR, NULL, "Mirror Mode", &cv_kartmirror, 18}, + {IT_STRING | IT_CVAR, NULL, "Encore Mode", &cv_kartencore, 18}, {IT_STRING | IT_CVAR, NULL, "Number of Laps", &cv_numlaps, 26}, {IT_STRING | IT_CVAR, NULL, "Use Map Lap Counts", &cv_usemapnumlaps, 34}, diff --git a/src/p_mobj.c b/src/p_mobj.c index 9e13db6d..74b9e54c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3643,7 +3643,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled || (thiscam == &camera4 && players[fourthdisplayplayer].mo && (players[fourthdisplayplayer].mo->flags2 & MF2_TWOD))) itsatwodlevel = true; - if (mirrormode) + if (encoremode) postimg = postimg_mirror; else if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) postimg = postimg_flip; diff --git a/src/p_saveg.c b/src/p_saveg.c index fdbe4033..8f4e12d4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3256,7 +3256,7 @@ static void P_NetArchiveMisc(void) WRITEINT32(save_p, numgotboxes); WRITEUINT8(save_p, gamespeed); - WRITEUINT8(save_p, mirrormode); + WRITEUINT8(save_p, encoremode); WRITEUINT8(save_p, franticitems); WRITEUINT8(save_p, comeback); @@ -3361,7 +3361,7 @@ static inline boolean P_NetUnArchiveMisc(void) numgotboxes = READINT32(save_p); gamespeed = READUINT8(save_p); - mirrormode = (boolean)READUINT8(save_p); + encoremode = (boolean)READUINT8(save_p); franticitems = (boolean)READUINT8(save_p); comeback = (boolean)READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index f4c28663..30e882d5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2726,7 +2726,35 @@ boolean P_SetupLevel(boolean skipprecip) // internal game map lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap)); - R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); + // SRB2Kart: map load variables + if (modeattacking) // Just play it safe and set everything + { + gamespeed = 2; + encoremode = false; + franticitems = false; + comeback = true; + } + else + { + if (G_BattleGametype()) + { + gamespeed = 0; + encoremode = false; + } + else + { + gamespeed = (UINT8)cv_kartspeed.value; + encoremode = (boolean)cv_kartencore.value; + } + franticitems = (boolean)cv_kartfrantic.value; + comeback = (boolean)cv_kartcomeback.value; + } + + for (i = 0; i < 4; i++) + battlewanted[i] = -1; + + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, + (encoremode ? W_CheckNumForName(va("%sE", maplumpname)) : LUMPERROR)); CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. @@ -2986,33 +3014,6 @@ boolean P_SetupLevel(boolean skipprecip) CV_SetValue(&cv_analog, false); }*/ - // SRB2Kart: map load variables - if (modeattacking) // Just play it safe and set everything - { - gamespeed = 2; - mirrormode = false; - franticitems = false; - comeback = true; - } - else - { - if (G_BattleGametype()) - { - gamespeed = 0; - mirrormode = false; - } - else - { - gamespeed = (UINT8)cv_kartspeed.value; - mirrormode = (boolean)cv_kartmirror.value; - } - franticitems = (boolean)cv_kartfrantic.value; - comeback = (boolean)cv_kartcomeback.value; - } - - for (i = 0; i < 4; i++) - battlewanted[i] = -1; - wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; spbincoming = 0; diff --git a/src/p_user.c b/src/p_user.c index f612e81d..0a54696e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9015,7 +9015,7 @@ static void P_CalcPostImg(player_t *player) } #endif - if (mirrormode) // srb2kart + if (encoremode) // srb2kart *type = postimg_mirror; } diff --git a/src/r_bsp.c b/src/r_bsp.c index 56f159c2..48f2f179 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -37,6 +37,16 @@ drawseg_t *ds_p = NULL; // indicates doors closed wrt automap bugfix: INT32 doorclosed; +static boolean R_NoEncore(sector_t *sector) +{ + INT32 val = GETSECSPECIAL(sector->special, 3); + if (val == 1 || val == 3) + return true; + if (GETSECSPECIAL(sector->special, 4) == 6) + return true; + return false; +} + // // R_ClearDrawSegs // @@ -935,7 +945,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , frontsector->f_slope #endif - ); + , R_NoEncore(frontsector)); } else floorplane = NULL; @@ -957,7 +967,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , frontsector->c_slope #endif - ); + , R_NoEncore(frontsector)); } else ceilingplane = NULL; @@ -1018,7 +1028,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , *rover->b_slope #endif - ); + , R_NoEncore(rover->master->frontsector)); #ifdef ESLOPE ffloor[numffloors].slope = *rover->b_slope; @@ -1064,7 +1074,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , *rover->t_slope #endif - ); + , R_NoEncore(rover->master->frontsector)); #ifdef ESLOPE ffloor[numffloors].slope = *rover->t_slope; @@ -1133,7 +1143,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , NULL // will ffloors be slopable eventually? #endif - ); + , R_NoEncore(polysec)); ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].polyobj = po; @@ -1179,7 +1189,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , NULL // will ffloors be slopable eventually? #endif - ); + , R_NoEncore(polysec)); ffloor[numffloors].polyobj = po; ffloor[numffloors].height = polysec->ceilingheight; diff --git a/src/r_data.c b/src/r_data.c index d19882dd..4719b908 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -112,6 +112,7 @@ INT32 *texturetranslation; sprcache_t *spritecachedinfo; lighttable_t *colormaps; +lighttable_t *encoremap; // for debugging/info purposes static size_t flatmemory, spritememory, texturememory; @@ -932,7 +933,7 @@ static inline lumpnum_t R_CheckNumForNameList(const char *name, lumplist_t *list return LUMPERROR; } -static lumplist_t *colormaplumps = NULL; ///\todo free leak +/*static lumplist_t *colormaplumps = NULL; ///\todo free leak static size_t numcolormaplumps = 0; static void R_InitExtraColormaps(void) @@ -966,7 +967,7 @@ static void R_InitExtraColormaps(void) numcolormaplumps++; } CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps)); -} +}*/ // 12/14/14 -- only take flats in F_START/F_END lumpnum_t R_GetFlatNumForName(const char *name) @@ -1010,15 +1011,17 @@ static void R_InitColormaps(void) // Load in the light tables lump = W_GetNumForName("COLORMAP"); - colormaps = Z_MallocAlign(W_LumpLength (lump), PU_STATIC, NULL, 8); + //Z_MallocAlign(W_LumpLength (lump), PU_STATIC, NULL, 8); + colormaps = Z_MallocAlign((256 * 64), PU_STATIC, NULL, 8); W_ReadLump(lump, colormaps); + // no need to init encoremap at this stage // Init Boom colormaps. R_ClearColormaps(); - R_InitExtraColormaps(); + //R_InitExtraColormaps(); } -void R_ReInitColormaps(UINT16 num) +void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap) { char colormap[9] = "COLORMAP"; lumpnum_t lump; @@ -1032,6 +1035,30 @@ void R_ReInitColormaps(UINT16 num) lump = W_GetNumForName("COLORMAP"); W_ReadLump(lump, colormaps); + // Encore mode. + if (newencoremap != LUMPERROR) + { + lighttable_t *colormap_p, *colormap_p2; + size_t p, i; + + encoremap = Z_MallocAlign(256 + 10, PU_LEVEL, NULL, 8); + W_ReadLump(newencoremap, encoremap); + colormap_p = colormap_p2 = colormaps; + colormap_p += (256 * 32); + + for (p = 0; p < 32; p++) + { + for (i = 0; i < 256; i++) + { + *colormap_p = colormap_p2[encoremap[i]]; + colormap_p++; + } + colormap_p2 += 256; + } + } + else + encoremap = NULL; + // Init Boom colormaps. R_ClearColormaps(); } @@ -1060,7 +1087,7 @@ void R_ClearColormaps(void) memset(extra_colormaps, 0, sizeof (extra_colormaps)); } -INT32 R_ColormapNumForName(char *name) +/*INT32 R_ColormapNumForName(char *name) { lumpnum_t lump, i; @@ -1092,7 +1119,7 @@ INT32 R_ColormapNumForName(char *name) num_extra_colormaps++; return (INT32)num_extra_colormaps - 1; -} +}*/ // // R_CreateColormap @@ -1121,10 +1148,20 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) if (p1[0] == '#') { cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2])); - cmaskr = cr; cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); - cmaskg = cg; cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); + + // i don't know why this doesn't work... + /*if (encoremap) + { + i = NearestColor(cr, cg, cb); + cr = pLocalPalette[encoremap[i]].s.red; + cg = pLocalPalette[encoremap[i]].s.green; + cb = pLocalPalette[encoremap[i]].s.blue; + }*/ + + cmaskr = cr; + cmaskg = cg; cmaskb = cb; // Create a rough approximation of the color (a 16 bit color) maskcolor = ((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11); @@ -1167,9 +1204,22 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) if (p3[0] == '#') { - cdestr = cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); - cdestg = cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); - cdestb = cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); + cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); + cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); + cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); + + // i don't know why this doesn't work... + /*if (encoremap) + { + i = NearestColor(cr, cg, cb); + cr = pLocalPalette[encoremap[i]].s.red; + cg = pLocalPalette[encoremap[i]].s.green; + cb = pLocalPalette[encoremap[i]].s.blue; + }*/ + + cdestr = cr; + cdestg = cg; + cdestb = cb; fadecolor = (((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11)); } else @@ -1257,10 +1307,10 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb; double r, g, b, cbrightness; double maskamt = 0, othermask = 0; - int mask, p, fog = 0; + INT32 mask, p, fog = 0; size_t mapnum = num_extra_colormaps; size_t i; - char *colormap_p; + lighttable_t *colormap_p, *colormap_p2; UINT32 cr, cg, cb, maskcolor, fadecolor; UINT32 fadestart = 0, fadeend = 33, fadedist = 33; @@ -1268,10 +1318,20 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) if (p1[0] == '#') { cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2])); - cmaskr = cr; cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); - cmaskg = cg; cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); + + // i don't know why this doesn't work... + /*if (encoremap) + { + i = NearestColor(cr, cg, cb); + cr = pLocalPalette[encoremap[i]].s.red; + cg = pLocalPalette[encoremap[i]].s.green; + cb = pLocalPalette[encoremap[i]].s.blue; + }*/ + + cmaskr = cr; + cmaskg = cg; cmaskb = cb; // Create a rough approximation of the color (a 16 bit color) maskcolor = ((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11); @@ -1314,9 +1374,22 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) if (p3[0] == '#') { - cdestr = cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); - cdestg = cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); - cdestb = cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); + cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); + cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); + cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); + + // i don't know why this doesn't work... + /*if (encoremap) + { + i = NearestColor(cr, cg, cb); + cr = pLocalPalette[encoremap[i]].s.red; + cg = pLocalPalette[encoremap[i]].s.green; + cb = pLocalPalette[encoremap[i]].s.blue; + }*/ + + cdestr = cr; + cdestg = cg; + cdestb = cb; fadecolor = (((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11)); } else @@ -1383,10 +1456,10 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) #define ABS2(x) ((x) < 0 ? -(x) : (x)) if (rendermode == render_soft) { - colormap_p = Z_MallocAlign((256 * 34) + 10, PU_LEVEL, NULL, 8); + colormap_p = Z_MallocAlign((256 * (encoremap ? 64 : 32)) + 10, PU_LEVEL, NULL, 8); extra_colormaps[mapnum].colormap = (UINT8 *)colormap_p; - for (p = 0; p < 34; p++) + for (p = 0; p < 32; p++) { for (i = 0; i < 256; i++) { @@ -1414,6 +1487,21 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) map[i][2] = cdestb; } } + + if (!encoremap) + return; + + colormap_p2 = extra_colormaps[mapnum].colormap; + + for (p = 0; p < 32; p++) + { + for (i = 0; i < 256; i++) + { + *colormap_p = colormap_p2[encoremap[i]]; + colormap_p++; + } + colormap_p2 += 256; + } } #undef ABS2 diff --git a/src/r_data.h b/src/r_data.h index 1e9e0eb5..fb8756df 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -89,7 +89,7 @@ void R_ClearTextureNumCache(boolean btell); INT32 R_TextureNumForName(const char *name); INT32 R_CheckTextureNumForName(const char *name); -void R_ReInitColormaps(UINT16 num); +void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap); void R_ClearColormaps(void); INT32 R_ColormapNumForName(char *name); INT32 R_CreateColormap(char *p1, char *p2, char *p3); diff --git a/src/r_draw8.c b/src/r_draw8.c index 39585f58..b6efd6cf 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -1379,6 +1379,8 @@ void R_DrawColumnShadowed_8(void) if (height <= dc_yl) { dc_colormap = dc_lightlist[i].rcolormap; + if (encoremap) + dc_colormap += (256*32); if (solid && dc_yl < bheight) dc_yl = bheight; continue; @@ -1395,6 +1397,8 @@ void R_DrawColumnShadowed_8(void) dc_yl = dc_yh + 1; dc_colormap = dc_lightlist[i].rcolormap; + if (encoremap) + dc_colormap += (256*32); } dc_yh = realyh; if (dc_yl <= realyh) diff --git a/src/r_plane.c b/src/r_plane.c index 92e0cacb..22515639 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -335,6 +335,8 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) else #endif ds_colormap = planezlight[pindex]; + if (encoremap && !currentplane->noencore) + ds_colormap += (256*32); if (currentplane->extra_colormap) ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); @@ -437,7 +439,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, #ifdef ESLOPE , pslope_t *slope #endif - ) + , boolean noencore) { visplane_t *check; unsigned hash; @@ -486,7 +488,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, #ifdef ESLOPE && check->slope == slope #endif - ) + && check->noencore == noencore) { return check; } @@ -514,6 +516,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, #ifdef ESLOPE check->slope = slope; #endif + check->noencore = noencore; memset(check->top, 0xff, sizeof (check->top)); memset(check->bottom, 0x00, sizeof (check->bottom)); @@ -586,6 +589,7 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) #ifdef ESLOPE new_pl->slope = pl->slope; #endif + new_pl->noencore = pl->noencore; pl = new_pl; pl->minx = start; pl->maxx = stop; @@ -703,6 +707,8 @@ void R_DrawPlanes(void) // Because of this hack, sky is not affected // by INVUL inverse mapping. dc_colormap = colormaps; + if (encoremap) + dc_colormap += (256*32); dc_texturemid = skytexturemid; dc_texheight = textureheight[skytexture] >>FRACBITS; diff --git a/src/r_plane.h b/src/r_plane.h index dff58669..9b25c65e 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -65,6 +65,8 @@ typedef struct visplane_s #ifdef ESLOPE pslope_t *slope; #endif + + boolean noencore; } visplane_t; extern visplane_t *floorplane; @@ -103,7 +105,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t #ifdef ESLOPE , pslope_t *slope #endif - ); + , boolean noencore); visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); diff --git a/src/r_segs.c b/src/r_segs.c index 025c920c..5c09d34e 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -202,6 +202,8 @@ static void R_DrawWallSplats(void) if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; + if (encoremap) + dc_colormap += (256*32); if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); @@ -596,6 +598,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (height <= windowtop) { dc_colormap = rlight->rcolormap; + if (encoremap) + dc_colormap += (256*32); continue; } @@ -615,6 +619,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) colfunc_2s(col); windowtop = windowbottom + 1; dc_colormap = rlight->rcolormap; + if (encoremap) + dc_colormap += (256*32); } windowbottom = realbot; if (windowtop < windowbottom) @@ -631,6 +637,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; + if (encoremap) + dc_colormap += (256*32); if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); @@ -1210,7 +1218,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (height <= windowtop) { if (lighteffect) + { dc_colormap = rlight->rcolormap; + if (encoremap) + dc_colormap += (256*32); + } if (solid && windowtop < bheight) windowtop = bheight; continue; @@ -1236,7 +1248,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) else windowtop = windowbottom + 1; if (lighteffect) + { dc_colormap = rlight->rcolormap; + if (encoremap) + dc_colormap += (256*32); + } } windowbottom = sprbotscreen; if (windowtop < windowbottom) @@ -1253,6 +1269,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; + if (encoremap) + dc_colormap += (256*32); if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap) @@ -1483,6 +1501,8 @@ static void R_RenderSegLoop (void) pindex = MAXLIGHTSCALE-1; dc_colormap = walllights[pindex]; + if (encoremap) + dc_colormap += (256*32); dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; diff --git a/src/r_state.h b/src/r_state.h index 8436413b..a651bda7 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -38,6 +38,7 @@ typedef struct extern sprcache_t *spritecachedinfo; extern lighttable_t *colormaps; +extern lighttable_t *encoremap; // Boom colormaps. // Had to put a limit on colormaps :( diff --git a/src/r_things.c b/src/r_things.c index ae935897..d6596913 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -873,6 +873,11 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!dc_colormap) dc_colormap = colormaps; + if (encoremap && !vis->mobj->color + && (vis->mobj->flags & (MF_SCENERY|MF_NOTHINK)) + && !(vis->mobj->flags & ~(MF_SCENERY|MF_NOTHINK|MF_NOCLIP|MF_NOBLOCKMAP|MF_NOGRAVITY))) + dc_colormap += (256*32); + dc_texturemid = vis->texturemid; dc_texheight = 0; @@ -973,6 +978,8 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) } dc_colormap = colormaps; + if (encoremap) + dc_colormap += (256*32); dc_iscale = FixedDiv(FRACUNIT, vis->scale); dc_texturemid = vis->texturemid; diff --git a/src/s_sound.c b/src/s_sound.c index 44e7e7ae..3c7715d0 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -391,7 +391,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) { INT32 sep, pitch, priority, cnum; sfxinfo_t *sfx; - const boolean reverse = (stereoreverse.value ^ mirrormode); + const boolean reverse = (stereoreverse.value ^ encoremode); const mobj_t *origin = (const mobj_t *)origin_p; listener_t listener = {0,0,0,0}; @@ -1198,7 +1198,7 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v listener_t listensource; - const boolean reverse = (stereoreverse.value ^ mirrormode); + const boolean reverse = (stereoreverse.value ^ encoremode); (void)pitch; if (!listener) diff --git a/src/st_stuff.c b/src/st_stuff.c index 7efbe6d2..5c2c1c03 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -797,15 +797,24 @@ static void ST_drawLevelTitle(void) } { + const char *subttlstr; + dupcalc = (dupcalc - BASEVIDWIDTH)>>1; V_DrawFill(sub - dupcalc, bary+9, ttlnumxpos+dupcalc + 1, 2, 31); V_DrawDiag(sub + ttlnumxpos + 1, bary, 11, 31); V_DrawFill(sub - dupcalc, bary, ttlnumxpos+dupcalc, 10, gtc); V_DrawDiag(sub + ttlnumxpos, bary, 10, gtc); - if (subttl[0]) - V_DrawRightAlignedString(sub + zonexpos - 8, bary+1, V_ALLOWLOWERCASE, subttl); + + if (encoremode) + subttlstr = "Encore Mode"; + else if (subttl[0]) + subttlstr = subttl; + else if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) + subttlstr = "MAP HELL"; else - V_DrawRightAlignedString(sub + zonexpos - 8, bary+1, V_ALLOWLOWERCASE, va("%s Mode", gametype_cons_t[gametype].strvalue)); + subttlstr = va("%s Mode", gametype_cons_t[gametype].strvalue); + + V_DrawRightAlignedString(sub + zonexpos - 8, bary+1, V_ALLOWLOWERCASE, subttlstr); } ttlnumxpos += sub; diff --git a/src/y_inter.c b/src/y_inter.c index 4c5d9e26..18495bf9 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -93,6 +93,7 @@ typedef union UINT32 val[MAXPLAYERS]; //Gametype-specific value UINT8 pos[MAXPLAYERS]; // player positions. used for ties boolean rankingsmode; // rankings mode + boolean encore; // encore mode } match; } y_data; @@ -204,6 +205,8 @@ static void Y_CalculateMatchData(boolean rankingsmode, void (*comparison)(INT32) if ((data.match.rankingsmode = rankingsmode)) sprintf(data.match.levelstring, "* Total Rankings *"); + data.match.encore = (!rankingsmode && encoremode); + for (i = 0; i < MAXPLAYERS; i++) { data.match.val[i] = UINT32_MAX; @@ -379,6 +382,9 @@ void Y_IntermissionDrawer(void) V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 20, 0, data.match.levelstring); V_DrawFill(x, 42, 312, 1, 0); + if (data.match.encore) + V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 20-8, hilicol, "ENCORE MODE"); + if (data.match.numplayers > 8) { V_DrawFill(160, 32, 1, 152, 0); From 7577d289c378bc6f8184a50f373a3c84dff44eec Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 8 Aug 2018 15:03:02 +0100 Subject: [PATCH 02/84] Encore mode is shippable, if still a tad incomplete! * Turns out the Linedef Type 606 support WAS working and I just had a bad MAP01E lump. * Ruby fade and ambience start track. * Fix bad phrasing. --- src/d_netcmd.c | 2 +- src/p_setup.c | 87 +++++++++++++++++++++++++++----------------------- src/p_user.c | 2 +- src/r_data.c | 53 +++++++++++++++--------------- src/sounds.c | 2 ++ src/sounds.h | 2 ++ 6 files changed, 78 insertions(+), 70 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e6ff6a42..e1e0a635 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5252,7 +5252,7 @@ static void KartEncore_OnChange(void) CONS_Printf(M_GetText("Encore tracks will be turned %s next round.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); else { - CONS_Printf(M_GetText("Encore tracks has been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); + CONS_Printf(M_GetText("Encore tracks have been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); encoremode = (boolean)cv_kartencore.value; } } diff --git a/src/p_setup.c b/src/p_setup.c index 30e882d5..196eb5c7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2244,6 +2244,33 @@ static void P_LevelInitStuff(void) // and this stupid flag as a result players[i].pflags &= ~PF_TRANSFERTOCLOSEST; } + + // SRB2Kart: map load variables + if (modeattacking) // Just play it safe and set everything + { + gamespeed = 2; + encoremode = false; + franticitems = false; + comeback = true; + } + else + { + if (G_BattleGametype()) + { + gamespeed = 0; + encoremode = false; + } + else + { + gamespeed = (UINT8)cv_kartspeed.value; + encoremode = (boolean)cv_kartencore.value; + } + franticitems = (boolean)cv_kartfrantic.value; + comeback = (boolean)cv_kartcomeback.value; + } + + for (i = 0; i < 4; i++) + battlewanted[i] = -1; } // @@ -2618,23 +2645,31 @@ boolean P_SetupLevel(boolean skipprecip) // will be set by player think. players[consoleplayer].viewz = 1; - // Special stage fade to white + // Encore mode fade to pink to white // This is handled BEFORE sounds are stopped. - /*if (rendermode != render_none && G_IsSpecialStage(gamemap)) + if (rendermode != render_none && encoremode) { - tic_t starttime = I_GetTime(); - tic_t endtime = starttime + (3*TICRATE)/2; - tic_t nowtime; + tic_t starttime, endtime, nowtime; - S_StartSound(NULL, sfx_s3kaf); + S_StopMusic(); // er, about that... + + S_StartSound(NULL, sfx_ruby1); F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 122); F_WipeEndScreen(); F_RunWipe(wipedefs[wipe_speclevel_towhite], false); - nowtime = lastwipetic; + F_WipeStartScreen(); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + + F_WipeEndScreen(); + F_RunWipe(wipedefs[wipe_level_final], false); + + starttime = nowtime = lastwipetic; + endtime = starttime + (3*TICRATE)/2; + // Hold on white for extra effect. while (nowtime < endtime) { @@ -2647,23 +2682,22 @@ boolean P_SetupLevel(boolean skipprecip) } ranspecialwipe = 1; - }*/ + } // Make sure all sounds are stopped before Z_FreeTags. S_StopSounds(); S_ClearSfx(); - // As oddly named as this is, this handles music only. // We should be fine starting it here. S_Start(); // SRB2 Kart - Yes this is weird, but we don't want the music to start until after the countdown is finished // but we do still need the mapmusname to be changed if (leveltime < (starttime + (TICRATE/2))) - S_ChangeMusicInternal("kstart", false); //S_StopMusic(); + S_ChangeMusicInternal((encoremode ? "estart" : "kstart"), false); //S_StopMusic(); - // Let's fade to black here - // But only if we didn't do the special stage wipe + // Let's fade to white here + // But only if we didn't do the encore wipe if (rendermode != render_none && !ranspecialwipe) { F_WipeStartScreen(); @@ -2726,33 +2760,6 @@ boolean P_SetupLevel(boolean skipprecip) // internal game map lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap)); - // SRB2Kart: map load variables - if (modeattacking) // Just play it safe and set everything - { - gamespeed = 2; - encoremode = false; - franticitems = false; - comeback = true; - } - else - { - if (G_BattleGametype()) - { - gamespeed = 0; - encoremode = false; - } - else - { - gamespeed = (UINT8)cv_kartspeed.value; - encoremode = (boolean)cv_kartencore.value; - } - franticitems = (boolean)cv_kartfrantic.value; - comeback = (boolean)cv_kartcomeback.value; - } - - for (i = 0; i < 4; i++) - battlewanted[i] = -1; - R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, (encoremode ? W_CheckNumForName(va("%sE", maplumpname)) : LUMPERROR)); CON_SetupBackColormap(); diff --git a/src/p_user.c b/src/p_user.c index 8f0f3dec..771161b3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1221,7 +1221,7 @@ void P_RestoreMusic(player_t *player) // Event - Level Start if (leveltime < (starttime + (TICRATE/2))) - S_ChangeMusicInternal("kstart", false); //S_StopMusic(); + S_ChangeMusicInternal((encoremode ? "estart" : "kstart"), false); //S_StopMusic(); else // see also where time overs are handled - search for "lives = 2" in this file { // Item - Grow diff --git a/src/r_data.c b/src/r_data.c index 4719b908..1e2bc628 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1151,14 +1151,14 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); - // i don't know why this doesn't work... - /*if (encoremap) + if (encoremap) { - i = NearestColor(cr, cg, cb); - cr = pLocalPalette[encoremap[i]].s.red; - cg = pLocalPalette[encoremap[i]].s.green; - cb = pLocalPalette[encoremap[i]].s.blue; - }*/ + i = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)]; + //CONS_Printf("R_CreateColormap: encoremap[%d] = %d\n", i, encoremap[i]); -- moved encoremap upwards for optimisation + cr = pLocalPalette[i].s.red; + cg = pLocalPalette[i].s.green; + cb = pLocalPalette[i].s.blue; + } cmaskr = cr; cmaskg = cg; @@ -1208,14 +1208,13 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); - // i don't know why this doesn't work... - /*if (encoremap) + if (encoremap) { - i = NearestColor(cr, cg, cb); - cr = pLocalPalette[encoremap[i]].s.red; - cg = pLocalPalette[encoremap[i]].s.green; - cb = pLocalPalette[encoremap[i]].s.blue; - }*/ + i = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)]; + cr = pLocalPalette[i].s.red; + cg = pLocalPalette[i].s.green; + cb = pLocalPalette[i].s.blue; + } cdestr = cr; cdestg = cg; @@ -1321,14 +1320,13 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); - // i don't know why this doesn't work... - /*if (encoremap) + if (encoremap) { - i = NearestColor(cr, cg, cb); - cr = pLocalPalette[encoremap[i]].s.red; - cg = pLocalPalette[encoremap[i]].s.green; - cb = pLocalPalette[encoremap[i]].s.blue; - }*/ + i = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)]; + cr = pLocalPalette[i].s.red; + cg = pLocalPalette[i].s.green; + cb = pLocalPalette[i].s.blue; + } cmaskr = cr; cmaskg = cg; @@ -1378,14 +1376,13 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); - // i don't know why this doesn't work... - /*if (encoremap) + if (encoremap) { - i = NearestColor(cr, cg, cb); - cr = pLocalPalette[encoremap[i]].s.red; - cg = pLocalPalette[encoremap[i]].s.green; - cb = pLocalPalette[encoremap[i]].s.blue; - }*/ + i = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)]; + cr = pLocalPalette[i].s.red; + cg = pLocalPalette[i].s.green; + cb = pLocalPalette[i].s.blue; + } cdestr = cr; cdestg = cg; diff --git a/src/sounds.c b/src/sounds.c index 3b41dfa1..984f5a57 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -809,6 +809,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"yeeeah", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"noooo1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"noooo2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"ruby1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"ruby2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"hogbom", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds diff --git a/src/sounds.h b/src/sounds.h index 0f8d5a3b..210feba7 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -881,6 +881,8 @@ typedef enum sfx_yeeeah, sfx_noooo1, sfx_noooo2, + sfx_ruby1, + sfx_ruby2, sfx_hogbom, sfx_kwin, From 6f2840fe19b39a45bc961617c3cba262d1a03e45 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 8 Aug 2018 20:48:29 +0100 Subject: [PATCH 03/84] * Make Encore Mode an unlockable, rather than freely available. * Make unlockables have a "showing" conditionset, for when you're able to see them on the Extras screen. * A shorter Encore ruby-pulse fade, for when encore mode is already active! --- src/command.c | 7 +++++++ src/d_netcmd.c | 8 ++++---- src/dehacked.c | 6 ++++-- src/m_cond.c | 16 +++++++++++----- src/m_cond.h | 4 +++- src/m_menu.c | 8 ++++++-- src/p_setup.c | 14 +++++++++----- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/command.c b/src/command.c index 305a5eee..54406ade 100644 --- a/src/command.c +++ b/src/command.c @@ -28,6 +28,7 @@ #include "byteptr.h" #include "p_saveg.h" #include "g_game.h" // for player_names +#include "m_cond.h" // for encore mode #include "d_netcmd.h" #include "hu_stuff.h" #include "p_setup.h" @@ -1373,6 +1374,12 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth) return; } + if (var == &cv_kartencore && !M_SecretUnlocked(SECRET_ENCORE)) + { + CONS_Printf(M_GetText("You haven't unlocked Encore Mode yet!\n")); + return; + } + // Only add to netcmd buffer if in a netgame, otherwise, just change it. if (netgame || multiplayer) { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e1e0a635..a504453e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -352,7 +352,7 @@ static CV_PossibleValue_t kartbumpers_cons_t[] = {{1, "MIN"}, {12, "MAX"}, {0, N consvar_t cv_kartbumpers = {"kartbumpers", "3", CV_NETVAR|CV_CHEAT, kartbumpers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartFrantic_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; @@ -5249,11 +5249,11 @@ static void KartEncore_OnChange(void) if (G_RaceGametype()) { if ((boolean)cv_kartencore.value != encoremode && gamestate == GS_LEVEL /*&& leveltime > starttime*/) - CONS_Printf(M_GetText("Encore tracks will be turned %s next round.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); + CONS_Printf(M_GetText("Encore Mode will be turned %s next round.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); else { - CONS_Printf(M_GetText("Encore tracks have been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); - encoremode = (boolean)cv_kartencore.value; + CONS_Printf(M_GetText("Encore Mode has been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); + //encoremode = (boolean)cv_kartencore.value; } } } diff --git a/src/dehacked.c b/src/dehacked.c index 8fcf597d..15586934 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2384,8 +2384,8 @@ static void readunlockable(MYFILE *f, INT32 num) else if (fastcmp(word, "OBJECTIVE")) deh_strlcpy(unlockables[num].objective, word2, sizeof (unlockables[num].objective), va("Unlockable %d: objective", num)); - else if (fastcmp(word, "HEIGHT")) - unlockables[num].height = (UINT16)i; + else if (fastcmp(word, "SHOWCONDITIONSET")) + unlockables[num].showconditionset = (UINT8)i; else if (fastcmp(word, "CONDITIONSET")) unlockables[num].conditionset = (UINT8)i; else if (fastcmp(word, "NOCECHO")) @@ -2416,6 +2416,8 @@ static void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_WARP; else if (fastcmp(word2, "SOUNDTEST")) unlockables[num].type = SECRET_SOUNDTEST; + else if (fastcmp(word2, "ENCORE")) + unlockables[num].type = SECRET_ENCORE; else unlockables[num].type = (INT16)i; } diff --git a/src/m_cond.c b/src/m_cond.c index 7d07d00a..63f88cb6 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -96,12 +96,14 @@ extraemblem_t extraemblems[MAXEXTRAEMBLEMS] = // Default Unlockables unlockable_t unlockables[MAXUNLOCKABLES] = { - // Name, Objective, Menu Height, ConditionSet, Unlock Type, Variable, NoCecho, NoChecklist - /* 01 */ {"Egg Cup", "", 0, 1, SECRET_NONE, 0, false, false, 0}, - /* 02 */ {"SMK Cup", "", 0, 2, SECRET_NONE, 0, false, false, 0}, - /* 03 */ {"Chao Cup", "", 0, 3, SECRET_NONE, 0, false, false, 0}, + // Name, Objective, Showing Conditionset, ConditionSet, Unlock Type, Variable, NoCecho, NoChecklist + /* 01 */ {"Egg Cup", "", -1, 1, SECRET_NONE, 0, false, false, 0}, + /* 02 */ {"SMK Cup", "", -1, 2, SECRET_NONE, 0, false, false, 0}, + /* 03 */ {"Chao Cup", "", -1, 3, SECRET_NONE, 0, false, false, 0}, - /* 04 */ {"Record Attack", "", 0, -1, SECRET_RECORDATTACK, 0, true, true, 0}, + /* 04 */ {"Encore Mode", "", 3, 4, SECRET_ENCORE, 0, false, false, 0}, + + /* 05 */ {"Record Attack", "", -1, -1, SECRET_RECORDATTACK, 0, true, true, 0}, }; // Default number of emblems and extra emblems @@ -125,6 +127,10 @@ void M_SetupDefaultConditionSets(void) M_AddRawCondition(3, 1, UC_TOTALEMBLEMS, 30, 0, 0); M_AddRawCondition(3, 2, UC_MATCHESPLAYED, 50, 0, 0); + // -- 4: Collect 50 emblems OR play 150 matches + M_AddRawCondition(4, 1, UC_TOTALEMBLEMS, 50, 0, 0); + M_AddRawCondition(4, 2, UC_MATCHESPLAYED, 150, 0, 0); + // -- 10: Play 100 matches M_AddRawCondition(10, 1, UC_MATCHESPLAYED, 100, 0, 0); } diff --git a/src/m_cond.h b/src/m_cond.h index 052c31f2..5c8762ad 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -103,7 +103,7 @@ typedef struct { char name[64]; char objective[64]; - UINT16 height; // menu height + UINT8 showconditionset; UINT8 conditionset; INT16 type; INT16 variable; @@ -112,6 +112,7 @@ typedef struct UINT8 unlocked; } unlockable_t; +// I have NO idea why these are going negative, but whatever. #define SECRET_NONE -6 // Does nil. Use with levels locked by UnlockRequired #define SECRET_ITEMFINDER -5 // Enables Item Finder/Emblem Radar #define SECRET_EMBLEMHINTS -4 // Enables Emblem Hints @@ -123,6 +124,7 @@ typedef struct #define SECRET_WARP 2 // Selectable warp #define SECRET_SOUNDTEST 3 // Sound Test #define SECRET_CREDITS 4 // Enables Credits +#define SECRET_ENCORE 5 // Enables Encore mode cvar // If you have more secrets than these variables allow in your game, // you seriously need to get a life. diff --git a/src/m_menu.c b/src/m_menu.c index 3e12c65d..07a2a9c3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1444,7 +1444,7 @@ static menuitem_t OP_GameOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Game Speed", &cv_kartspeed, 30}, {IT_STRING | IT_CVAR, NULL, "Frantic Items", &cv_kartfrantic, 40}, - {IT_STRING | IT_CVAR, NULL, "Encore Mode", &cv_kartencore, 50}, + {IT_SECRET, NULL, "Encore Mode", &cv_kartencore, 50}, {IT_STRING | IT_CVAR, NULL, "Number of Laps", &cv_basenumlaps, 70}, {IT_STRING | IT_CVAR, NULL, "Exit Countdown Timer", &cv_countdowntime, 80}, @@ -4311,6 +4311,9 @@ static void M_Options(INT32 choice) OP_MainMenu[7].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_GameOptionsMenu[3].status = + (M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore + OP_MainDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_MainDef); } @@ -4463,7 +4466,8 @@ static void M_DrawChecklist(void) for (i = 0; i < MAXUNLOCKABLES; i++) { if (unlockables[i].name[0] == 0 || unlockables[i].nochecklist - || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS) + || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS + || !M_Achieved(unlockables[i].showconditionset - 1)) continue; ++line; diff --git a/src/p_setup.c b/src/p_setup.c index 196eb5c7..39a26260 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -136,6 +136,8 @@ mapthing_t *playerstarts[MAXPLAYERS]; mapthing_t *bluectfstarts[MAXPLAYERS]; mapthing_t *redctfstarts[MAXPLAYERS]; +boolean prevencoremode = false; + /** Logs an error about a map being corrupt, then terminate. * This allows reporting highly technical errors for usefulness, without * confusing a novice map designer who simply needs to run ZenNode. @@ -2245,6 +2247,8 @@ static void P_LevelInitStuff(void) players[i].pflags &= ~PF_TRANSFERTOCLOSEST; } + prevencoremode = ((wipegamestate == GS_TITLESCREEN) ? false : encoremode); + // SRB2Kart: map load variables if (modeattacking) // Just play it safe and set everything { @@ -2647,7 +2651,7 @@ boolean P_SetupLevel(boolean skipprecip) // Encore mode fade to pink to white // This is handled BEFORE sounds are stopped. - if (rendermode != render_none && encoremode) + if (rendermode != render_none && encoremode && !prevencoremode) { tic_t starttime, endtime, nowtime; @@ -2697,14 +2701,14 @@ boolean P_SetupLevel(boolean skipprecip) S_ChangeMusicInternal((encoremode ? "estart" : "kstart"), false); //S_StopMusic(); // Let's fade to white here - // But only if we didn't do the encore wipe + // But only if we didn't do the encore startup wipe if (rendermode != render_none && !ranspecialwipe) { F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (encoremode ? 122 : 120)); F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_level_toblack], false); + F_RunWipe(wipedefs[(encoremode ? wipe_level_final : wipe_level_toblack)], false); } // Reset the palette now all fades have been done @@ -3045,7 +3049,7 @@ boolean P_SetupLevel(boolean skipprecip) // Remove the loading shit from the screen if (rendermode != render_none) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (encoremode && !ranspecialwipe ? 122 : 120)); if (precache || dedicated) R_PrecacheLevel(); From 500b71c0b3730a5fb868982e4eeac14eb6707066 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 10 Aug 2018 19:31:30 +0100 Subject: [PATCH 04/84] More control over what stuff get Encore mapping applied to it, with sensible defaults so you don't have to do much to your map to get it to be supported! * Objects! * Gone is the arcane, difficult-to-remember list of random flags. Say hello to MF_DONTENCOREMAP! * Alternatively, if the object has a skincolour applied to it, it isn't encoremapped either. (Useful for ghosts, for example.) * Sectors! * The autodetecting of sneaker and spring panels is now much more intelligent, and only avoids remapping the plane(s) the effect is availible upon. * Sector special group 2 no. 15 is now "Invert Encore Remap". It inverts the above detection. * Linedefs! * The "Transfer Line" linedef flag can now also be used to deny Encore remappings on linedef textures. * Right now it applies to every pixel drawn specifically belonging to that linedef, but if people decide it needs changing, we CAN make it apply to midtextures only (like linedef types 900-910). --- src/dehacked.c | 1 + src/info.c | 180 ++++++++++++++++++++++++------------------------- src/p_mobj.h | 4 +- src/p_spec.c | 2 + src/r_bsp.c | 31 +++++---- src/r_segs.c | 16 ++--- src/r_things.c | 4 +- 7 files changed, 124 insertions(+), 114 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 5ef770d3..af72719b 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7367,6 +7367,7 @@ static const char *const MOBJFLAG_LIST[] = { "NOCLIPTHING", "GRENADEBOUNCE", "RUNSPAWNFUNC", + "DONTENCOREMAP", NULL }; diff --git a/src/info.c b/src/info.c index b8fc8182..5c3de123 100644 --- a/src/info.c +++ b/src/info.c @@ -3028,7 +3028,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -3055,7 +3055,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -3082,7 +3082,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -3109,7 +3109,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass MT_THOK, // damage sfx_None, // activesound - MF_SOLID|MF_SHOOTABLE, // flags + MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags (statenum_t)MT_THOK // raisestate }, @@ -5135,7 +5135,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5162,7 +5162,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5189,7 +5189,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5216,7 +5216,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP, // flags + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5243,7 +5243,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL, // flags + MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5270,7 +5270,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL, // flags + MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5297,7 +5297,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5324,7 +5324,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, { // MT_EMERALD2 @@ -5350,7 +5350,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, { // MT_EMERALD3 @@ -5376,7 +5376,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, { // MT_EMERALD4 @@ -5402,7 +5402,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, { // MT_EMERALD5 @@ -5428,7 +5428,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, { // MT_EMERALD6 @@ -5454,7 +5454,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, { // MT_EMERALD7 @@ -5480,7 +5480,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5507,7 +5507,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY, // flags + MF_SPECIAL|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5561,7 +5561,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL, // flags + MF_SLIDEME|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5615,7 +5615,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID, // flags + MF_SOLID|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5642,7 +5642,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 14*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_BLUESPRING2 // raisestate }, @@ -5669,7 +5669,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 26*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_YELLOWSPRING2 // raisestate }, @@ -5696,7 +5696,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 40*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_REDSPRING2 // raisestate }, @@ -5723,7 +5723,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 26*FRACUNIT, // mass 26*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_YDIAG2 // raisestate }, @@ -5750,7 +5750,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 40*FRACUNIT, // mass 40*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_RDIAG2 // raisestate }, @@ -5804,7 +5804,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOCLIP|MF_SCENERY, // flags + MF_NOCLIP|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -5912,7 +5912,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -8022,7 +8022,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -8049,7 +8049,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -8076,7 +8076,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_mswing, // activesound - MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -8103,7 +8103,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_mswing, // activesound - MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -10482,7 +10482,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -10509,7 +10509,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -10753,7 +10753,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -10942,7 +10942,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14277,7 +14277,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 6*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_GRAYSPRING2 // raisestate }, @@ -14331,7 +14331,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 14*FRACUNIT, // mass 14*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_BDIAG2 // raisestate }, @@ -14358,7 +14358,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass MT_RANDOMITEMPOP, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14385,7 +14385,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MT_EXPLODE, // mass 0, // damage sfx_None, // activesound - MF_NOCLIP, // flags + MF_NOCLIP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14412,7 +14412,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_SLIDEME, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_SLIDEME|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14439,7 +14439,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14466,7 +14466,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14493,7 +14493,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14520,7 +14520,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14547,7 +14547,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_FLOAT|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_FLOAT|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14574,7 +14574,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14601,7 +14601,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_fake, // activesound - MF_BOUNCE|MF_SHOOTABLE, // flags + MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14628,7 +14628,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_peel, // activesound - MF_BOUNCE|MF_SHOOTABLE, // flags + MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14655,7 +14655,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14682,7 +14682,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k96, // activesound - MF_SHOOTABLE|MF_BOUNCE, // flags + MF_SHOOTABLE|MF_BOUNCE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14709,7 +14709,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14736,7 +14736,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3kc0s, // activesound - MF_SHOOTABLE, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14763,7 +14763,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3kc0s, // activesound - MF_SHOOTABLE, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14790,7 +14790,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14817,7 +14817,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k5c, // activesound - MF_BOUNCE|MF_SHOOTABLE, // flags + MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14844,7 +14844,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14871,7 +14871,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_NOGRAVITY, // flags + MF_SOLID|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14925,7 +14925,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14952,7 +14952,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_BOUNCE|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_BOUNCE|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -14979,7 +14979,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_BOUNCE|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_BOUNCE|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15006,7 +15006,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_BOUNCE, // flags + MF_SHOOTABLE|MF_BOUNCE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15033,7 +15033,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING, // flags + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15060,7 +15060,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15087,7 +15087,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_BOUNCE|MF_FLOAT|MF_NOCLIPTHING|MF_MISSILE|MF_SHOOTABLE, // flags + MF_BOUNCE|MF_FLOAT|MF_NOCLIPTHING|MF_MISSILE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15114,7 +15114,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15141,7 +15141,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15168,7 +15168,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_bomb, // activesound - MF_BOUNCE|MF_SHOOTABLE, // flags + MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15195,7 +15195,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15222,7 +15222,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15249,7 +15249,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15357,7 +15357,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15384,7 +15384,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15411,7 +15411,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15438,7 +15438,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15465,7 +15465,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15492,7 +15492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15519,7 +15519,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15546,7 +15546,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15573,7 +15573,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - 2, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16626,7 +16626,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SCENERY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + MF_NOGRAVITY|MF_SCENERY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16653,7 +16653,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16680,7 +16680,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_clash, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_RUNSPAWNFUNC|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16707,7 +16707,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16734,7 +16734,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16761,7 +16761,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16788,7 +16788,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16815,7 +16815,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16842,7 +16842,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + MF_SPECIAL|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16869,7 +16869,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + MF_NOTHINK|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/p_mobj.h b/src/p_mobj.h index 50645e4b..34d1f644 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -160,7 +160,9 @@ typedef enum MF_GRENADEBOUNCE = 1<<28, // Run the action thinker on spawn. MF_RUNSPAWNFUNC = 1<<29, - // free: 1<<30 and 1<<31 + // Don't remap in Encore mode. + MF_DONTENCOREMAP = 1<<30, + // free: 1<<31 } mobjflag_t; typedef enum diff --git a/src/p_spec.c b/src/p_spec.c index 02d94d90..ccb895f1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3745,6 +3745,8 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers break; case 12: // Lua sector special break; + case 15: // Invert Encore Remap + break; } DoneSection2: diff --git a/src/r_bsp.c b/src/r_bsp.c index 48f2f179..981d0b56 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -37,14 +37,21 @@ drawseg_t *ds_p = NULL; // indicates doors closed wrt automap bugfix: INT32 doorclosed; -static boolean R_NoEncore(sector_t *sector) +static boolean R_NoEncore(sector_t *sector, boolean ceiling) { + boolean invertencore = (GETSECSPECIAL(sector->special, 2) != 15); +#if 0 // perfect implementation INT32 val = GETSECSPECIAL(sector->special, 3); - if (val == 1 || val == 3) - return true; - if (GETSECSPECIAL(sector->special, 4) == 6) - return true; - return false; + if (val != 1 && val != 3 // spring panel +#else // optimised, see #define GETSECSPECIAL(i,j) ((i >> ((j-1)*4))&15) + if ((!(sector->special & (1<<8)) || (sector->special & ((4|8)<<8))) // spring panel +#endif + && GETSECSPECIAL(sector->special, 4) != 6) // sneaker panel + return !invertencore; + + if (ceiling) + return ((boolean)(sector->flags & SF_FLIPSPECIAL_CEILING) == invertencore); + return ((boolean)(sector->flags & SF_FLIPSPECIAL_FLOOR) == invertencore); } // @@ -945,7 +952,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , frontsector->f_slope #endif - , R_NoEncore(frontsector)); + , R_NoEncore(frontsector, false)); } else floorplane = NULL; @@ -967,7 +974,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , frontsector->c_slope #endif - , R_NoEncore(frontsector)); + , R_NoEncore(frontsector, true)); } else ceilingplane = NULL; @@ -1028,7 +1035,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , *rover->b_slope #endif - , R_NoEncore(rover->master->frontsector)); + , R_NoEncore(rover->master->frontsector, true)); #ifdef ESLOPE ffloor[numffloors].slope = *rover->b_slope; @@ -1074,7 +1081,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , *rover->t_slope #endif - , R_NoEncore(rover->master->frontsector)); + , R_NoEncore(rover->master->frontsector, false)); #ifdef ESLOPE ffloor[numffloors].slope = *rover->t_slope; @@ -1143,7 +1150,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , NULL // will ffloors be slopable eventually? #endif - , R_NoEncore(polysec)); + , R_NoEncore(polysec, false)); ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].polyobj = po; @@ -1189,7 +1196,7 @@ static void R_Subsector(size_t num, UINT8 viewnumber) #ifdef ESLOPE , NULL // will ffloors be slopable eventually? #endif - , R_NoEncore(polysec)); + , R_NoEncore(polysec, true)); ffloor[numffloors].polyobj = po; ffloor[numffloors].height = polysec->ceilingheight; diff --git a/src/r_segs.c b/src/r_segs.c index 5c09d34e..11287f16 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -202,7 +202,7 @@ static void R_DrawWallSplats(void) if (pindex >= MAXLIGHTSCALE) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; - if (encoremap) + if (encoremap && !(seg->linedef->flags & ML_TFERLINE)) dc_colormap += (256*32); if (frontsector->extra_colormap) @@ -598,7 +598,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (height <= windowtop) { dc_colormap = rlight->rcolormap; - if (encoremap) + if (encoremap && !(ldef->flags & ML_TFERLINE)) dc_colormap += (256*32); continue; } @@ -619,7 +619,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) colfunc_2s(col); windowtop = windowbottom + 1; dc_colormap = rlight->rcolormap; - if (encoremap) + if (encoremap && !(ldef->flags & ML_TFERLINE)) dc_colormap += (256*32); } windowbottom = realbot; @@ -637,7 +637,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; - if (encoremap) + if (encoremap && !(ldef->flags & ML_TFERLINE)) dc_colormap += (256*32); if (frontsector->extra_colormap) @@ -1220,7 +1220,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (lighteffect) { dc_colormap = rlight->rcolormap; - if (encoremap) + if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) dc_colormap += (256*32); } if (solid && windowtop < bheight) @@ -1250,7 +1250,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (lighteffect) { dc_colormap = rlight->rcolormap; - if (encoremap) + if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) dc_colormap += (256*32); } } @@ -1269,7 +1269,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; - if (encoremap) + if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) dc_colormap += (256*32); if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); @@ -1501,7 +1501,7 @@ static void R_RenderSegLoop (void) pindex = MAXLIGHTSCALE-1; dc_colormap = walllights[pindex]; - if (encoremap) + if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) dc_colormap += (256*32); dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; diff --git a/src/r_things.c b/src/r_things.c index d6596913..67b1a5c7 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -873,9 +873,7 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!dc_colormap) dc_colormap = colormaps; - if (encoremap && !vis->mobj->color - && (vis->mobj->flags & (MF_SCENERY|MF_NOTHINK)) - && !(vis->mobj->flags & ~(MF_SCENERY|MF_NOTHINK|MF_NOCLIP|MF_NOBLOCKMAP|MF_NOGRAVITY))) + if (encoremap && !vis->mobj->color && !(vis->mobj->flags & MF_DONTENCOREMAP)) dc_colormap += (256*32); dc_texturemid = vis->texturemid; From 202e98957d1f0d4f36f9edf90d4a593f76be100a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 10 Aug 2018 21:11:45 +0100 Subject: [PATCH 05/84] * For testing purposes, show Encoremaps on the level select icons. * HOWEVER, we should seriously address this again later, because the antialiasing DOES result in some unfortunate bullshit... * Encoremap maces per Oni's request and Sal's suggestion --- src/info.c | 8 ++++---- src/m_menu.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/info.c b/src/info.c index 5c3de123..2109f74b 100644 --- a/src/info.c +++ b/src/info.c @@ -8022,7 +8022,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -8049,7 +8049,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -8076,7 +8076,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_mswing, // activesound - MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -8103,7 +8103,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_mswing, // activesound - MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, diff --git a/src/m_menu.c b/src/m_menu.c index b23f28a5..18bdf09e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6749,9 +6749,11 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) lumpnum_t lumpnum; patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; + const char *mapname = G_BuildMapName(cv_nextmap.value); + boolean doencore = (cv_kartencore.value && cv_newgametype.value == GT_RACE); // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); + lumpnum = W_CheckNumForName(va("%sP", mapname)); if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); @@ -6770,13 +6772,24 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) V_DrawFill(x-1, y-1, w+2, i+2, trans); // variable reuse... - V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); + if (!doencore) + V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); + else + { + UINT8 *mappingforencore = NULL; + if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR) + mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE); + + V_DrawFixedPatch((x+w)<width)/4; - V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); + x -= horizspac + w/2; + + if (!doencore) + V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); + else + { + UINT8 *mappingforencore = NULL; + if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR) + mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE); + + V_DrawFixedPatch((x+(w/2))< horizspac-dupadjust); x = (BASEVIDWIDTH + w)/2 + horizspac; i = cv_nextmap.value - 1; trans = (rightfade ? V_TRANSLUCENT : 0); + if (doencore) + trans |= V_FLIP; while (x < BASEVIDWIDTH+dupadjust-horizspac) { @@ -6830,15 +6856,26 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1))); + mapname = G_BuildMapName(i+1); + lumpnum = W_CheckNumForName(va("%sP", mapname)); if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); - V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); - x += horizspac + SHORT(PictureOfLevel->width)/4; + if (!doencore) + V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); + else + { + UINT8 *mappingforencore = NULL; + if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR) + mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE); + + V_DrawFixedPatch((x+(w/2))< Date: Sat, 11 Aug 2018 22:23:40 +0100 Subject: [PATCH 06/84] * Encore on the voting screen! Appears randomly once unlocked in the same slot as that which sometimes represents a gametype change (odds inflated for testing purposes). * A better representation of an Encore level, now with inverted graphics (a special remapping we can now use elsewhere whenever if we want!) and a floating Ruby! * Decouple encore's setting from cv_kartencore on mapload. Instead, bake it into D_MapChange and related, which will only some of the time be fed by cv_kartencore's value. * Encore mode now has a special mapheader palette setting, "encorepal", rather than using the same one as non-encore. --- src/d_clisrv.c | 2 +- src/d_main.c | 2 +- src/d_netcmd.c | 40 ++++++++++++------------ src/d_netcmd.h | 2 +- src/dehacked.c | 2 ++ src/doomstat.h | 5 +-- src/f_finale.c | 2 +- src/g_game.c | 26 ++++++++------- src/g_game.h | 4 +-- src/m_menu.c | 51 +++++++++++------------------- src/p_setup.c | 13 ++------ src/p_tick.c | 2 +- src/r_data.c | 12 ++++++- src/r_data.h | 1 + src/r_state.h | 3 +- src/v_video.c | 3 +- src/y_inter.c | 85 ++++++++++++++++++++++++++++++++++++-------------- 17 files changed, 144 insertions(+), 111 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 13650c59..63393690 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4758,7 +4758,7 @@ void TryRunTics(tic_t realtics) { COM_BufExecute(); if (mapchangepending) - D_MapChange(-1, 0, ultimatemode, false, 2, false, fromlevelselect); // finish the map change + D_MapChange(-1, 0, encoremode, false, 2, false, fromlevelselect); // finish the map change } NetUpdate(); diff --git a/src/d_main.c b/src/d_main.c index 0100db38..bf6af7ea 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1489,7 +1489,7 @@ void D_SRB2Main(void) else if (!dedicated && M_MapLocked(pstartmap)) I_Error("You need to unlock this level before you can warp to it!\n"); else - D_MapChange(pstartmap, gametype, ultimatemode, true, 0, false, false); + D_MapChange(pstartmap, gametype, (boolean)cv_kartencore.value, true, 0, false, false); } } else if (M_CheckParm("-skipintro")) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c157f21c..28d33be9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -446,6 +446,7 @@ consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL INT16 gametype = GT_RACE; // SRB2kart boolean forceresetplayers = false; +boolean deferencoremode = false; UINT8 splitscreen = 0; boolean circuitmap = true; // SRB2kart INT32 adminplayers[MAXPLAYERS]; @@ -1872,7 +1873,7 @@ INT32 mapchangepending = 0; * * \param mapnum Map number to change to. * \param gametype Gametype to switch to. - * \param pultmode Is this 'Ultimate Mode'? + * \param pencoremode Is this 'Encore Mode'? * \param resetplayers 1 to reset player scores and lives and such, 0 not to. * \param delay Determines how the function will be executed: 0 to do * it all right now (must not be done from a menu), 1 to @@ -1881,18 +1882,16 @@ INT32 mapchangepending = 0; * \sa D_GameTypeChanged, Command_Map_f * \author Graue */ -void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean resetplayers, INT32 delay, boolean skipprecutscene, boolean FLS) +void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean resetplayers, INT32 delay, boolean skipprecutscene, boolean FLS) { static char buf[2+MAX_WADPATH+1+4]; static char *buf_p = buf; - forceresetplayers = false; - // The supplied data are assumed to be good. I_Assert(delay >= 0 && delay <= 2); - CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", - mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene); + CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d encoremode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", + mapnum, newgametype, pencoremode, resetplayers, delay, skipprecutscene); if (netgame || multiplayer) FLS = false; @@ -1905,7 +1904,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese I_Assert(W_CheckNumForName(mapname) != LUMPERROR); buf_p = buf; - if (pultmode) + if (pencoremode) flags |= 1; if (!resetplayers) flags |= 1<<1; @@ -1973,8 +1972,12 @@ void D_SetupVote(void) INT32 i; UINT8 secondgt = G_SometimesGetDifferentGametype(); - WRITEUINT8(p, gametype); + if (cv_kartencore.value && G_RaceGametype()) + WRITEUINT8(p, (gametype|0x80)); + else + WRITEUINT8(p, gametype); WRITEUINT8(p, secondgt); + secondgt &= ~0x80; for (i = 0; i < 5; i++) { @@ -2109,10 +2112,6 @@ static void Command_Map_f(void) return; } - // Ultimate Mode only in SP via menu - if (netgame || multiplayer) - ultimatemode = false; - // new gametype value // use current one by default i = COM_CheckParm("-gametype"); @@ -2177,7 +2176,7 @@ static void Command_Map_f(void) } fromlevelselect = false; - D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, false); + D_MapChange(newmapnum, newgametype, (boolean)cv_kartencore.value, newresetplayers, 0, false, false); } /** Receives a map command and changes the map. @@ -2193,6 +2192,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) UINT8 flags; INT32 resetplayer = 1, lastgametype; UINT8 skipprecutscene, FLS; + boolean pencoremode; + + forceresetplayers = deferencoremode = false; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -2213,9 +2215,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) flags = READUINT8(*cp); - ultimatemode = ((flags & 1) != 0); - if (netgame || multiplayer) - ultimatemode = false; + pencoremode = ((flags & 1) != 0); resetplayer = ((flags & (1<<1)) == 0); @@ -2225,6 +2225,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (gametype != lastgametype) D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype + if (!G_RaceGametype()) + pencoremode = false; + skipprecutscene = ((flags & (1<<2)) != 0); FLS = ((flags & (1<<3)) != 0); @@ -2256,7 +2259,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) LUAh_MapChange(); #endif - G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene); + G_InitNew(pencoremode, mapname, resetplayer, skipprecutscene); if (demoplayback && !timingdemo) precache = true; CON_ToggleOff(); @@ -5250,10 +5253,7 @@ static void KartEncore_OnChange(void) if ((boolean)cv_kartencore.value != encoremode && gamestate == GS_LEVEL /*&& leveltime > starttime*/) CONS_Printf(M_GetText("Encore Mode will be turned %s next round.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); else - { CONS_Printf(M_GetText("Encore Mode has been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off")); - //encoremode = (boolean)cv_kartencore.value; - } } } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index b7721b79..5238c44e 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -251,7 +251,7 @@ void D_SendPlayerConfig(void); void Command_ExitGame_f(void); void Command_Retry_f(void); void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore -void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); +void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); void D_SetupVote(void); void D_ModifyClientVote(SINT8 voted, UINT8 splitplayer); void D_PickVote(void); diff --git a/src/dehacked.c b/src/dehacked.c index af72719b..cd013148 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1221,6 +1221,8 @@ static void readlevelheader(MYFILE *f, INT32 num) mapheaderinfo[num-1]->countdown = (INT16)i; else if (fastcmp(word, "PALETTE")) mapheaderinfo[num-1]->palette = (UINT16)i; + else if (fastcmp(word, "ENCOREPAL")) + mapheaderinfo[num-1]->encorepal = (UINT16)i; else if (fastcmp(word, "NUMLAPS")) mapheaderinfo[num-1]->numlaps = (UINT8)i; else if (fastcmp(word, "UNLOCKABLE")) diff --git a/src/doomstat.h b/src/doomstat.h index dbe9fa34..f54abebc 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -80,7 +80,7 @@ extern INT16 gametype; extern UINT8 splitscreen; extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean fromlevelselect; -extern boolean forceresetplayers; +extern boolean forceresetplayers, deferencoremode; // ======================================== // Internal parameters for sound rendering. @@ -243,6 +243,7 @@ typedef struct UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. INT16 countdown; ///< Countdown until level end? UINT16 palette; ///< PAL lump to use on this map + UINT16 encorepal; ///< PAL for encore mode UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? @@ -448,7 +449,7 @@ extern INT32 cheats; // SRB2kart extern UINT8 gamespeed; extern boolean franticitems; -extern boolean encoremode; +extern boolean encoremode, prevencoremode; extern boolean comeback; extern SINT8 battlewanted[4]; diff --git a/src/f_finale.c b/src/f_finale.c index ab79fa78..e5d342ad 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1252,7 +1252,7 @@ void F_EndCutScene(void) if (runningprecutscene) { if (server) - D_MapChange(gamemap, gametype, ultimatemode, precutresetplayer, 0, true, false); + D_MapChange(gamemap, gametype, false, precutresetplayer, 0, true, false); } else { diff --git a/src/g_game.c b/src/g_game.c index 48ba8724..cb7f276c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -248,7 +248,8 @@ INT32 cheats; //for multiplayer cheat commands // SRB2Kart // Cvars that we don't want changed mid-game UINT8 gamespeed; // Game's current speed (or difficulty, or cc, or etc); 0 for easy, 1 for normal, 2 for hard -boolean encoremode; // Encore Mode currently enabled? +boolean encoremode = false; // Encore Mode currently enabled? +boolean prevencoremode; boolean franticitems; // Frantic items currently enabled? boolean comeback; // Battle Mode's karma comeback is on/off @@ -3097,13 +3098,16 @@ boolean G_BattleGametype(void) // // G_SometimesGetDifferentGametype // -// I pity the fool who adds more gametypes later, because it'll require some element of randomisation which needs to be synched... -// Although given this only gets called for the host, you could probably get away with M_Random. +// Oh, yeah, and we sometimes flip encore mode on here too. // INT16 G_SometimesGetDifferentGametype(void) { if (randmapbuffer[NUMMAPS] != -1) + { + if (M_SecretUnlocked(SECRET_ENCORE) && (M_RandomChance(FRACUNIT/2/*56*/) != cv_kartencore.value) && G_RaceGametype()) + return (gametype|0x80); return gametype; + } randmapbuffer[NUMMAPS] = gametype; @@ -3477,6 +3481,7 @@ void G_NextLevel(void) } forceresetplayers = false; + deferencoremode = (boolean)cv_kartencore.value; } gameaction = ga_worlddone; @@ -3489,7 +3494,7 @@ static void G_DoWorldDone(void) // SRB2Kart D_MapChange(nextmap+1, gametype, - ultimatemode, + deferencoremode, forceresetplayers, 0, false, @@ -3561,7 +3566,7 @@ static void G_DoContinued(void) // Reset # of lives pl->lives = (ultimatemode) ? 1 : 3; - D_MapChange(gamemap, gametype, ultimatemode, false, 0, false, false); + D_MapChange(gamemap, gametype, false, false, 0, false, false); gameaction = ga_nothing; } @@ -4075,7 +4080,7 @@ void G_SaveGame(UINT32 savegameslot) // Can be called by the startup code or the menu task, // consoleplayer, displayplayer, playeringame[] should be set. // -void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS) +void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { INT32 i; UINT8 color = 0; @@ -4120,14 +4125,14 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, U CV_StealthSetValue(&cv_playercolor, color); if (mapname) - D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pultmode, true, 1, false, FLS); + D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pencoremode, true, 1, false, FLS); } // // This is the map command interpretation something like Command_Map_f // // called at: map cmd execution, doloadgame, doplaydemo -void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean skipprecutscene) +void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, boolean skipprecutscene) { INT32 i; @@ -4137,8 +4142,8 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean S_ResumeAudio(); } - if (netgame || multiplayer) // Nice try, haxor. - ultimatemode = false; + prevencoremode = ((gamestate == GS_TITLESCREEN) ? false : encoremode); + encoremode = pencoremode; legitimateexit = false; // SRB2Kart comebackshowninfo = false; @@ -4227,7 +4232,6 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean // Don't carry over custom music change to another map. mapmusflags |= MUSIC_RELOADRESET; - ultimatemode = pultmode; playerdeadview = false; automapactive = false; imcontinuing = false; diff --git a/src/g_game.h b/src/g_game.h index ad099bf2..10eb4c68 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -107,7 +107,7 @@ extern boolean camspin, camspin2, camspin3, camspin4; // SRB2Kart void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo); void G_DoReborn(INT32 playernum); void G_PlayerReborn(INT32 player); -void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, +void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, boolean skipprecutscene); char *G_BuildMapTitle(INT32 mapnum); @@ -119,7 +119,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost); // Can be called by the startup code or M_Responder. // A normal game starts at map 1, but a warp test can start elsewhere -void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, +void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS); void G_DoLoadLevel(boolean resetplayer); diff --git a/src/m_menu.c b/src/m_menu.c index 18bdf09e..5d557f89 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5420,7 +5420,7 @@ static void M_ChoosePlayer(INT32 choice) { char *skin1,*skin2; INT32 skinnum; - boolean ultmode = (ultimate_selectable && SP_PlayerDef.prevMenu == &SP_LoadDef && saveSlotSelected == NOSAVESLOT); + //boolean ultmode = (ultimate_selectable && SP_PlayerDef.prevMenu == &SP_LoadDef && saveSlotSelected == NOSAVESLOT); // skip this if forcecharacter if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->forcecharacter[0] == '\0') @@ -5457,7 +5457,7 @@ static void M_ChoosePlayer(INT32 choice) lastmapsaved = 0; gamecomplete = false; - G_DeferedInitNew(ultmode, G_BuildMapName(startmap), (UINT8)skinnum, 0, fromlevelselect); + G_DeferedInitNew(false, G_BuildMapName(startmap), (UINT8)skinnum, 0, fromlevelselect); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this } @@ -6724,7 +6724,7 @@ static void M_StartServer(INT32 choice) if (ssplayers < 1) { - D_MapChange(cv_nextmap.value, cv_newgametype.value, false, 1, 1, false, false); + D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); COM_BufAddText("dummyconsvar 1\n"); } else // split screen @@ -6738,7 +6738,7 @@ static void M_StartServer(INT32 choice) SplitScreen_OnChange(); } - D_MapChange(cv_nextmap.value, cv_newgametype.value, false, 1, 1, false, false); + D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); } M_ClearMenus(true); @@ -6750,7 +6750,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; const char *mapname = G_BuildMapName(cv_nextmap.value); - boolean doencore = (cv_kartencore.value && cv_newgametype.value == GT_RACE); + //boolean doencore = (cv_kartencore.value && cv_newgametype.value == GT_RACE); // A 160x100 image of the level as entry MAPxxP lumpnum = W_CheckNumForName(va("%sP", mapname)); @@ -6772,15 +6772,22 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) V_DrawFill(x-1, y-1, w+2, i+2, trans); // variable reuse... - if (!doencore) + if (!cv_kartencore.value || cv_newgametype.value != GT_RACE) V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); else { - UINT8 *mappingforencore = NULL; + /*UINT8 *mappingforencore = NULL; if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR) - mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE); + mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE);*/ - V_DrawFixedPatch((x+w)<>ANGLETOFINESHIFT); + V_DrawFixedPatch((x+w/2)< horizspac-dupadjust); x = (BASEVIDWIDTH + w)/2 + horizspac; i = cv_nextmap.value - 1; trans = (rightfade ? V_TRANSLUCENT : 0); - if (doencore) - trans |= V_FLIP; while (x < BASEVIDWIDTH+dupadjust-horizspac) { @@ -6864,16 +6858,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); - if (!doencore) - V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); - else - { - UINT8 *mappingforencore = NULL; - if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR) - mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE); - - V_DrawFixedPatch((x+(w/2))<countdown = 0; DEH_WriteUndoline("PALLETE", va("%u", mapheaderinfo[num]->palette), UNDO_NONE); mapheaderinfo[num]->palette = UINT16_MAX; + DEH_WriteUndoline("ENCOREPAL", va("%u", mapheaderinfo[num]->encorepal), UNDO_NONE); + mapheaderinfo[num]->encorepal = UINT16_MAX; DEH_WriteUndoline("NUMLAPS", va("%u", mapheaderinfo[num]->numlaps), UNDO_NONE); mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT; DEH_WriteUndoline("UNLOCKABLE", va("%s", mapheaderinfo[num]->unlockrequired), UNDO_NONE); @@ -2247,28 +2247,19 @@ static void P_LevelInitStuff(void) players[i].pflags &= ~PF_TRANSFERTOCLOSEST; } - prevencoremode = ((wipegamestate == GS_TITLESCREEN) ? false : encoremode); - // SRB2Kart: map load variables if (modeattacking) // Just play it safe and set everything { gamespeed = 2; - encoremode = false; franticitems = false; comeback = true; } else { if (G_BattleGametype()) - { gamespeed = 0; - encoremode = false; - } else - { gamespeed = (UINT8)cv_kartspeed.value; - encoremode = (boolean)cv_kartencore.value; - } franticitems = (boolean)cv_kartfrantic.value; comeback = (boolean)cv_kartcomeback.value; } diff --git a/src/p_tick.c b/src/p_tick.c index b9aaccf7..bf0777aa 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -744,7 +744,7 @@ void P_Ticker(boolean run) if (mapreset > 1 && --mapreset <= 1 && server) // Remember: server uses it for mapchange, but EVERYONE ticks down for the animation - D_MapChange(gamemap, gametype, ultimatemode, true, 0, false, false); + D_MapChange(gamemap, gametype, encoremode, true, 0, false, false); } P_MapEnd(); diff --git a/src/r_data.c b/src/r_data.c index 1e2bc628..e3d23dd7 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -112,7 +112,8 @@ INT32 *texturetranslation; sprcache_t *spritecachedinfo; lighttable_t *colormaps; -lighttable_t *encoremap; +UINT8 *encoremap; +UINT8 invertmap[256]; // for debugging/info purposes static size_t flatmemory, spritememory, texturememory; @@ -1019,6 +1020,7 @@ static void R_InitColormaps(void) // Init Boom colormaps. R_ClearColormaps(); //R_InitExtraColormaps(); + R_MakeInvertmap(); // this isn't the BEST place to do it the first time, but whatever } void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap) @@ -1301,6 +1303,14 @@ void R_MakeColormaps(void) colormapFixingArray[i][2]); } +void R_MakeInvertmap(void) +{ + size_t i; + + for (i = 0; i < 256; i++) + invertmap[i] = NearestColor(256 - pLocalPalette[i].s.red, 256 - pLocalPalette[i].s.green, 256 - pLocalPalette[i].s.blue); +} + void R_CreateColormap2(char *p1, char *p2, char *p3) { double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb; diff --git a/src/r_data.h b/src/r_data.h index fb8756df..4cc6f206 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -95,6 +95,7 @@ INT32 R_ColormapNumForName(char *name); INT32 R_CreateColormap(char *p1, char *p2, char *p3); void R_CreateColormap2(char *p1, char *p2, char *p3); void R_MakeColormaps(void); +void R_MakeInvertmap(void); const char *R_ColormapNameForNum(INT32 num); extern INT32 numtextures; diff --git a/src/r_state.h b/src/r_state.h index a651bda7..88a38f25 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -38,7 +38,8 @@ typedef struct extern sprcache_t *spritecachedinfo; extern lighttable_t *colormaps; -extern lighttable_t *encoremap; +extern UINT8 *encoremap; +extern UINT8 invertmap[256]; // Boom colormaps. // Had to put a limit on colormaps :( diff --git a/src/v_video.c b/src/v_video.c index 8013ae82..6f9ff219 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -207,7 +207,7 @@ const char *R_GetPalname(UINT16 num) const char *GetPalette(void) { if (gamestate == GS_LEVEL) - return R_GetPalname(mapheaderinfo[gamemap-1]->palette); + return R_GetPalname((encoremode ? mapheaderinfo[gamemap-1]->encorepal : mapheaderinfo[gamemap-1]->palette)); return "PLAYPAL"; } @@ -248,6 +248,7 @@ void V_SetPaletteLump(const char *pal) #endif if (rendermode != render_none) I_SetPalette(pLocalPalette); + R_MakeInvertmap(); } static void CV_usegamma_OnChange(void) diff --git a/src/y_inter.c b/src/y_inter.c index 14421ad7..d34e5d59 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -126,6 +126,7 @@ typedef struct UINT8 gtc; const char *gts; patch_t *pic; + boolean encore; } y_votelvlinfo; // Clientside & splitscreen player info. @@ -156,6 +157,7 @@ static patch_t *cursor2 = NULL; static patch_t *cursor3 = NULL; static patch_t *cursor4 = NULL; static patch_t *randomlvl = NULL; +static patch_t *rubyicon = NULL; static void Y_UnloadVoteData(void); @@ -930,6 +932,7 @@ void Y_VoteDrawer(void) { INT32 i, x, y = 0, height = 0; UINT8 selected[4]; + fixed_t rubyheight = 0; if (rendermode == render_none) return; @@ -940,6 +943,11 @@ void Y_VoteDrawer(void) if (!voteclient.loaded) return; + { + angle_t rubyfloattime = (ANGLE_MAX/NEWTICRATE)*(votetic % NEWTICRATE); + rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); + } + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx > 320) @@ -974,19 +982,18 @@ void Y_VoteDrawer(void) y = (200-height)/2; for (i = 0; i < 4; i++) { - char str[40]; + const char *str; patch_t *pic; UINT8 j, color; if (i == 3) { - snprintf(str, sizeof str, "%.32s", "RANDOM"); - str[sizeof str - 1] = '\0'; + str = "RANDOM"; pic = randomlvl; } else { - strcpy(str, levelinfo[i].str); + str = levelinfo[i].str; pic = levelinfo[i].pic; } @@ -1051,7 +1058,14 @@ void Y_VoteDrawer(void) sizeadd--; } - V_DrawSmallScaledPatch(BASEVIDWIDTH-100, y, V_SNAPTORIGHT, pic); + if (!levelinfo[i].encore) + V_DrawSmallScaledPatch(BASEVIDWIDTH-100, y, V_SNAPTORIGHT, pic); + else + { + V_DrawFixedPatch((BASEVIDWIDTH-20)<zonttl) > 0) + // set up the levelstring + if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0]) { - if (strlen(mapheaderinfo[votelevels[i][0]]->actnum) > 0) + if (mapheaderinfo[votelevels[i][0]]->actnum[0]) snprintf(levelinfo[i].str, sizeof levelinfo[i].str, - "%.32s %.32s %s", + "%s %s", + mapheaderinfo[prevmap]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); + else + snprintf(levelinfo[i].str, + sizeof levelinfo[i].str, + "%s", + mapheaderinfo[votelevels[i][0]]->lvlttl); + } + else + { + if (mapheaderinfo[votelevels[i][0]]->actnum[0]) + snprintf(levelinfo[i].str, + sizeof levelinfo[i].str, + "%s %s %s", mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl, mapheaderinfo[votelevels[i][0]]->actnum); else snprintf(levelinfo[i].str, sizeof levelinfo[i].str, - "%.32s %.32s", + "%s %s", mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl); } - else - { - if (strlen(mapheaderinfo[votelevels[i][0]]->actnum) > 0) - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%.32s %s", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); - else - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%.32s", - mapheaderinfo[votelevels[i][0]]->lvlttl); - } levelinfo[i].str[sizeof levelinfo[i].str - 1] = '\0'; } @@ -1493,6 +1529,7 @@ static void Y_UnloadVoteData(void) UNLOAD(cursor3); UNLOAD(cursor4); UNLOAD(randomlvl); + UNLOAD(rubyicon); UNLOAD(levelinfo[4].pic); UNLOAD(levelinfo[3].pic); From dd6259c44f1884557ea538078470ca753c5e8142 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 11 Aug 2018 22:51:11 +0100 Subject: [PATCH 07/84] Encore mapload linedef executor (number 328), as requested by Oni. --- src/p_spec.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index d1ee7e7c..90166104 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1940,6 +1940,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller || specialtype == 318 // Unlockable trigger - Once || specialtype == 320 // Unlockable - Once || specialtype == 321 || specialtype == 322 // Trigger on X calls - Continuous + Each Time + || specialtype == 328 // Encore Load || specialtype == 399) // Level Load triggerline->special = 0; // Clear it out @@ -1975,6 +1976,7 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) // "No More Enemies" and "Level Load" take care of themselves. if (lines[masterline].special == 313 || lines[masterline].special == 399 + || lines[masterline].special == 328 // Each-time executors handle themselves, too || lines[masterline].special == 301 // Each time || lines[masterline].special == 306 // Character ability - Each time @@ -5561,7 +5563,7 @@ static void P_RunLevelLoadExecutors(void) for (i = 0; i < numlines; i++) { - if (lines[i].special == 399) + if (lines[i].special == 399 || lines[i].special == 328) P_RunTriggerLinedef(&lines[i], NULL, NULL); } } @@ -6452,6 +6454,12 @@ void P_SpawnSpecials(INT32 fromnetsave) } break; + case 328: // Encore-only linedef execute on map load + if (!encoremode) + lines[i].special = 0; + // This is handled in P_RunLevelLoadExecutors. + break; + case 399: // Linedef execute on map load // This is handled in P_RunLevelLoadExecutors. break; From 806353c86a142c6b8f479bf6bc853d8bcc19c9c9 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 12 Aug 2018 11:20:53 +0100 Subject: [PATCH 08/84] Fixed Encore remappings not being loaded when joining mid-netgame. --- src/p_saveg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 8f4e12d4..d9f43000 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3207,6 +3207,8 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, tokenlist); + WRITEUINT8(save_p, encoremode); + WRITEUINT32(save_p, leveltime); WRITEUINT32(save_p, totalrings); WRITEINT16(save_p, lastmap); @@ -3256,7 +3258,6 @@ static void P_NetArchiveMisc(void) WRITEINT32(save_p, numgotboxes); WRITEUINT8(save_p, gamespeed); - WRITEUINT8(save_p, encoremode); WRITEUINT8(save_p, franticitems); WRITEUINT8(save_p, comeback); @@ -3308,6 +3309,8 @@ static inline boolean P_NetUnArchiveMisc(void) tokenlist = READUINT32(save_p); + encoremode = (boolean)READUINT8(save_p); + if (!P_SetupLevel(true)) return false; @@ -3361,7 +3364,6 @@ static inline boolean P_NetUnArchiveMisc(void) numgotboxes = READINT32(save_p); gamespeed = READUINT8(save_p); - encoremode = (boolean)READUINT8(save_p); franticitems = (boolean)READUINT8(save_p); comeback = (boolean)READUINT8(save_p); From b7f7da4f6c4dcc6ff1daa2895a59282fa5236c5f Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 12 Aug 2018 15:10:47 +0100 Subject: [PATCH 09/84] Bugfix for "Blue Mountain 0", "Green Hills K". Also, minor tweak. --- src/st_stuff.c | 2 +- src/y_inter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index ac3391de..72266ba2 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -770,7 +770,7 @@ static void ST_drawLevelTitle(void) lvlw = V_LevelNameWidth(lvlttl); - if (strlen(actnum) > 0) + if (actnum[0]) lvlttlxpos = ((BASEVIDWIDTH/2) - (lvlw/2)) - V_LevelNameWidth(actnum); else lvlttlxpos = ((BASEVIDWIDTH/2) - (lvlw/2)); diff --git a/src/y_inter.c b/src/y_inter.c index d34e5d59..d88f3d34 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1460,7 +1460,7 @@ void Y_StartVote(void) snprintf(levelinfo[i].str, sizeof levelinfo[i].str, "%s %s", - mapheaderinfo[prevmap]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); + mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); else snprintf(levelinfo[i].str, sizeof levelinfo[i].str, From 19b2c20bda92097d909ca5cf127aabb27e2944a5 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 14 Aug 2018 15:32:17 +0100 Subject: [PATCH 10/84] * Disable inverting on encore level select pictures at unanimous request of last night's netgame. * Also, correct their alignment in y_inter.c. --- src/m_menu.c | 2 +- src/r_data.c | 6 ++++++ src/r_data.h | 2 ++ src/r_state.h | 2 ++ src/v_video.c | 2 ++ src/y_inter.c | 12 ++++++------ 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 5d557f89..ae46549c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6780,7 +6780,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR) mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE);*/ - V_DrawFixedPatch((x+w)< Date: Wed, 15 Aug 2018 16:12:36 +0100 Subject: [PATCH 11/84] Added "Random" to the level selection list, for those days when you know you *want* to race but don't have any idea what to do. --- src/command.c | 8 ++---- src/g_game.c | 16 ++++++++++- src/m_menu.c | 79 +++++++++++++++++++++++++++++++++------------------ 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/command.c b/src/command.c index 54406ade..03c8869d 100644 --- a/src/command.c +++ b/src/command.c @@ -1482,14 +1482,12 @@ void CV_AddValue(consvar_t *var, INT32 increment) { if(increment > 0) // Going up! { - newvalue++; - if (newvalue == NUMMAPS) - newvalue = 0; + if (++newvalue == NUMMAPS) + newvalue = -1; } else // Going down! { - newvalue--; - if (newvalue == -1) + if (--newvalue == -2) newvalue = NUMMAPS-1; } diff --git a/src/g_game.c b/src/g_game.c index d60ca57b..6f5c5e69 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -765,9 +765,20 @@ const char *G_BuildMapName(INT32 map) { static char mapname[10] = "MAPXX"; // internal map name (wad resource name) - I_Assert(map > 0); + I_Assert(map >= 0); I_Assert(map <= NUMMAPS); + if (map == 0) // hack??? + { + if (gamestate == GS_TITLESCREEN) + map = -1; + else if (gamestate == GS_LEVEL) + map = gamemap; + else + map = prevmap; + map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, false, false, 0, false); + } + if (map < 100) sprintf(&mapname[3], "%.2d", map); else @@ -4260,6 +4271,9 @@ char *G_BuildMapTitle(INT32 mapnum) { char *title = NULL; + if (mapnum == 0) + return Z_StrDup("Random"); + if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, "")) { size_t len = 1; diff --git a/src/m_menu.c b/src/m_menu.c index ae46549c..910076e5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -383,7 +383,7 @@ static void Dummystaff_OnChange(void); // ========================================================================== static CV_PossibleValue_t map_cons_t[] = { - {1,"MIN"}, + {0,"MIN"}, {NUMMAPS, "MAX"}, {0, NULL} }; @@ -2147,9 +2147,9 @@ static void Dummystaff_OnChange(void) // Newgametype. Used for gametype changes. static void Newgametype_OnChange(void) { - if (menuactive) + if (cv_nextmap.value && menuactive) { - if(!mapheaderinfo[cv_nextmap.value-1]) + if (!mapheaderinfo[cv_nextmap.value-1]) P_AllocMapHeader((INT16)(cv_nextmap.value-1)); if ((cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) || // SRB2kart @@ -3852,6 +3852,10 @@ static void M_PrepareLevelSelect(void) // boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) { + // Random map! + if (mapnum == -1) + return (gamestate != GS_TIMEATTACK && !modeattacking); + // Does the map exist? if (!mapheaderinfo[mapnum]) return false; @@ -5874,11 +5878,16 @@ static void M_TimeAttack(INT32 choice) M_PrepareLevelSelect(); M_SetupNextMenu(&SP_TimeAttackDef); - Nextmap_OnChange(); + + G_SetGamestate(GS_TIMEATTACK); + + if (cv_nextmap.value) + Nextmap_OnChange(); + else + CV_AddValue(&cv_nextmap, 1); itemOn = tastart; // "Start" is selected. - G_SetGamestate(GS_TIMEATTACK); S_ChangeMusicInternal("racent", true); } @@ -6689,8 +6698,11 @@ static INT32 M_FindFirstMap(INT32 gtype) for (i = 0; i < NUMMAPS; i++) { - if (mapheaderinfo[i] && (mapheaderinfo[i]->typeoflevel & gtype)) - return i + 1; + if (!mapheaderinfo[i]) + continue; + if (!(mapheaderinfo[i]->typeoflevel & gtype)) + continue; + return i + 1; } return 1; @@ -6722,6 +6734,9 @@ static void M_StartServer(INT32 choice) if (metalrecording) G_StopMetalDemo(); + if (!cv_nextmap.value) + CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, false, 0, false)); + if (ssplayers < 1) { D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); @@ -6749,16 +6764,18 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) lumpnum_t lumpnum; patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; - const char *mapname = G_BuildMapName(cv_nextmap.value); - //boolean doencore = (cv_kartencore.value && cv_newgametype.value == GT_RACE); // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", mapname)); - - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + if (cv_nextmap.value) + { + lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); + if (lumpnum != LUMPERROR) + PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + else + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + } else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); w = SHORT(PictureOfLevel->width)/2; i = SHORT(PictureOfLevel->height)/2; @@ -6803,7 +6820,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) do { i--; - if (i == -1) + if (i == -2) i = NUMMAPS-1; if (i == oldval) @@ -6815,13 +6832,16 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); // A 160x100 image of the level as entry MAPxxP - mapname = G_BuildMapName(i+1); - lumpnum = W_CheckNumForName(va("%sP", mapname)); - - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + if (i+1) + { + lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1))); + if (lumpnum != LUMPERROR) + PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + else + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + } else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); x -= horizspac + w/2; @@ -6839,7 +6859,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { i++; if (i == NUMMAPS) - i = 0; + i = -1; if (i == oldval) return; @@ -6850,13 +6870,16 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); // A 160x100 image of the level as entry MAPxxP - mapname = G_BuildMapName(i+1); - lumpnum = W_CheckNumForName(va("%sP", mapname)); - - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + if (i+1) + { + lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1))); + if (lumpnum != LUMPERROR) + PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); + else + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + } else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); From 1d894f36c35b2b78508689389a4a163f9c36cfaf Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 15 Aug 2018 16:56:26 +0100 Subject: [PATCH 12/84] Correct minor issue with random map name selection. --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 6f5c5e69..15c9bab2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -773,10 +773,10 @@ const char *G_BuildMapName(INT32 map) if (gamestate == GS_TITLESCREEN) map = -1; else if (gamestate == GS_LEVEL) - map = gamemap; + map = gamemap-1; else map = prevmap; - map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, false, false, 0, false); + map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, false, false, 0, false)+1; } if (map < 100) From 77ba3e3c2d40c6dd06592de259daee5d37bd1a82 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 15 Aug 2018 16:59:28 +0100 Subject: [PATCH 13/84] Additional oversight corrected. --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 83e28594..82e6ac2f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6737,7 +6737,7 @@ static void M_StartServer(INT32 choice) G_StopMetalDemo(); if (!cv_nextmap.value) - CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, false, 0, false)); + CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, false, 0, false)+1); if (ssplayers < 1) { From acba635c902de1663c68bfb00fa741de5a1d47ea Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 16 Aug 2018 15:29:34 +0100 Subject: [PATCH 14/84] Realised I'd forgotten to stop the item explosion from being encoremapped. --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 66b6bb4b..1652fb88 100644 --- a/src/info.c +++ b/src/info.c @@ -13303,7 +13303,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_SLIDEME, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, From cdf5874ff5fcb7bd731a3511dd6ac2f06a8ab930 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 26 Aug 2018 15:15:03 +0100 Subject: [PATCH 15/84] * Exempt drop shadows from encore remapping. * Make MT_GHOST's encoremapping depend on whether the source was encoremapped. * Revamp how sector typegroup 2, type 15 inverts the encoremapping (so planes don't get awkwardly desynchronised). --- src/info.c | 4 ++-- src/p_user.c | 3 +++ src/r_bsp.c | 11 +++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/info.c b/src/info.c index 1652fb88..464c4166 100644 --- a/src/info.c +++ b/src/info.c @@ -13114,7 +13114,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 8, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16599,7 +16599,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/p_user.c b/src/p_user.c index a4d624c1..ba7cb80b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1599,6 +1599,9 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) if (mobj->flags2 & MF2_OBJECTFLIP) ghost->flags |= MF2_OBJECTFLIP; + if (!(mobj->flags & MF_DONTENCOREMAP)) + mobj->flags &= ~MF_DONTENCOREMAP; + return ghost; } diff --git a/src/r_bsp.c b/src/r_bsp.c index 981d0b56..34b082ca 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -39,7 +39,7 @@ INT32 doorclosed; static boolean R_NoEncore(sector_t *sector, boolean ceiling) { - boolean invertencore = (GETSECSPECIAL(sector->special, 2) != 15); + boolean invertencore = (GETSECSPECIAL(sector->special, 2) == 15); #if 0 // perfect implementation INT32 val = GETSECSPECIAL(sector->special, 3); if (val != 1 && val != 3 // spring panel @@ -47,11 +47,14 @@ static boolean R_NoEncore(sector_t *sector, boolean ceiling) if ((!(sector->special & (1<<8)) || (sector->special & ((4|8)<<8))) // spring panel #endif && GETSECSPECIAL(sector->special, 4) != 6) // sneaker panel - return !invertencore; + return invertencore; + + if (invertencore) + return false; if (ceiling) - return ((boolean)(sector->flags & SF_FLIPSPECIAL_CEILING) == invertencore); - return ((boolean)(sector->flags & SF_FLIPSPECIAL_FLOOR) == invertencore); + return ((boolean)(sector->flags & SF_FLIPSPECIAL_CEILING)); + return ((boolean)(sector->flags & SF_FLIPSPECIAL_FLOOR)); } // From 10380284685aea47bb4a99992d0e95a9ac947eac Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 26 Aug 2018 16:23:50 +0100 Subject: [PATCH 16/84] Real time reordering of intermission rankings as rank counts up! Also features jittering of the intermission elements because I thought it'd be fun, plus some better handling of players leaving (and then new ones joining) mid-intermission. --- src/y_inter.c | 64 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 43bbf6bf..562457e1 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -89,8 +89,9 @@ typedef union INT32 numplayers; // Number of players being displayed char levelstring[64]; // holds levelnames up to 64 characters // SRB2kart - UINT8 increase[MAXPLAYERS]; //how much did the score increase by? - UINT32 val[MAXPLAYERS]; //Gametype-specific value + UINT8 increase[MAXPLAYERS]; // how much did the score increase by? + UINT8 jitter[MAXPLAYERS]; // wiggle + UINT32 val[MAXPLAYERS]; // Gametype-specific value UINT8 pos[MAXPLAYERS]; // player positions. used for ties boolean rankingsmode; // rankings mode boolean encore; // encore mode @@ -191,22 +192,28 @@ static void Y_CompareBattle(INT32 i) static void Y_CompareRank(INT32 i) { - if (!(data.match.val[data.match.numplayers] == UINT32_MAX || players[i].score > data.match.val[data.match.numplayers])) + UINT8 increase = ((data.match.increase[i] == UINT8_MAX) ? 0 : data.match.increase[i]); + if (!(data.match.val[data.match.numplayers] == UINT32_MAX || (players[i].score - increase) > data.match.val[data.match.numplayers])) return; - data.match.val[data.match.numplayers] = players[i].score; + data.match.val[data.match.numplayers] = (players[i].score - increase); data.match.num[data.match.numplayers] = i; } -static void Y_CalculateMatchData(boolean rankingsmode, void (*comparison)(INT32)) +static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) { INT32 i, j; boolean completed[MAXPLAYERS]; INT32 numplayersingame = 0; // Initialize variables - if ((data.match.rankingsmode = rankingsmode)) + if (rankingsmode > 1) + ; + else if ((data.match.rankingsmode = (boolean)rankingsmode)) + { sprintf(data.match.levelstring, "* Total Rankings *"); + data.match.encore = false; + } else { // set up the levelstring @@ -239,18 +246,24 @@ static void Y_CalculateMatchData(boolean rankingsmode, void (*comparison)(INT32) } data.match.levelstring[sizeof data.match.levelstring - 1] = '\0'; - } - data.match.encore = (!rankingsmode && encoremode); + data.match.encore = encoremode; + + memset(data.match.jitter, 0, sizeof (data.match.jitter)); + } for (i = 0; i < MAXPLAYERS; i++) { data.match.val[i] = UINT32_MAX; - if (!rankingsmode) - data.match.increase[i] = UINT8_MAX; if (!playeringame[i] || players[i].spectator) + { + data.match.increase[i] = UINT8_MAX; continue; + } + + if (!rankingsmode) + data.match.increase[i] = UINT8_MAX; numplayersingame++; } @@ -432,10 +445,16 @@ void Y_IntermissionDrawer(void) for (i = 0; i < data.match.numplayers; i++) { + boolean dojitter = data.match.jitter[data.match.num[i]]; + data.match.jitter[data.match.num[i]] = 0; + if (data.match.num[i] != MAXPLAYERS && playeringame[data.match.num[i]] && !players[data.match.num[i]].spectator) { char strtime[MAXPLAYERNAME+1]; + if (dojitter) + y--; + V_DrawCenteredString(x+6, y, 0, va("%d", data.match.pos[i])); if (data.match.color[i] == 0) @@ -470,11 +489,9 @@ void Y_IntermissionDrawer(void) V_DrawRightAlignedString(x+120, y, 0, strtime); else V_DrawRightAlignedString(x+120+BASEVIDWIDTH/2, y, 0, strtime); - - snprintf(strtime, sizeof strtime, "%d", data.match.val[i]-data.match.increase[data.match.num[i]]); } - else - snprintf(strtime, sizeof strtime, "%d", data.match.val[i]); + + snprintf(strtime, sizeof strtime, "%d", data.match.val[i]); if (data.match.numplayers > 8) V_DrawRightAlignedString(x+152, y, 0, strtime); @@ -512,12 +529,12 @@ void Y_IntermissionDrawer(void) } } } + + if (dojitter) + y++; } else - { - data.match.increase[data.match.num[i]] = 0; data.match.num[i] = MAXPLAYERS; // this should be the only field setting in this function - } y += 16; @@ -598,7 +615,7 @@ void Y_Ticker(void) else { if (!data.match.rankingsmode && (intertic >= sorttic + 8)) - Y_CalculateMatchData(true, Y_CompareRank); + Y_CalculateMatchData(1, Y_CompareRank); if (data.match.rankingsmode && intertic > sorttic+(2*TICRATE)) { @@ -612,14 +629,17 @@ void Y_Ticker(void) || data.match.increase[data.match.num[q]] == UINT8_MAX) continue; - data.match.increase[data.match.num[q]]--; r++; - if (data.match.increase[data.match.num[q]]) + data.match.jitter[data.match.num[q]] = 1; + if (--data.match.increase[data.match.num[q]]) kaching = false; } if (r) + { S_StartSound(NULL, (kaching ? sfx_chchng : sfx_ptally)); + Y_CalculateMatchData(2, Y_CompareRank); + } else endtic = intertic + 3*TICRATE; // 3 second pause after end of tally } @@ -762,7 +782,7 @@ void Y_StartIntermission(void) case int_match: { // Calculate who won - Y_CalculateMatchData(false, Y_CompareBattle); + Y_CalculateMatchData(0, Y_CompareBattle); if (cv_inttime.value > 0) S_ChangeMusicInternal("racent", true); // loop it break; @@ -785,7 +805,7 @@ void Y_StartIntermission(void) } // Calculate who won - Y_CalculateMatchData(false, Y_CompareRace); + Y_CalculateMatchData(0, Y_CompareRace); break; } From fc6b0b23ec4c9ae0f9c6462db3baeccf5a9409c1 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 26 Aug 2018 17:31:04 +0100 Subject: [PATCH 17/84] Increase the amount of time between the switch to the Rankings half of intermission and ranking is calculated a tad. Turns out it wasn't taking the length of the level-to-rankings switch animation into account! --- src/y_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/y_inter.c b/src/y_inter.c index 562457e1..636b2d23 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -617,7 +617,7 @@ void Y_Ticker(void) if (!data.match.rankingsmode && (intertic >= sorttic + 8)) Y_CalculateMatchData(1, Y_CompareRank); - if (data.match.rankingsmode && intertic > sorttic+(2*TICRATE)) + if (data.match.rankingsmode && intertic > sorttic+16+(2*TICRATE)) { INT32 q=0,r=0; boolean kaching = true; From b6dbecd2f830fd90d40cbf9fc6e2261e3ed404d8 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 28 Aug 2018 21:08:47 +0100 Subject: [PATCH 18/84] Addons menu. Bitch. --- src/console.c | 4 + src/d_clisrv.h | 3 +- src/d_main.c | 34 ++- src/d_netcmd.c | 50 ++-- src/d_netfil.c | 81 ++----- src/d_netfil.h | 1 - src/filesrch.c | 473 +++++++++++++++++++++++++++++++++++++- src/filesrch.h | 67 ++++++ src/m_menu.c | 608 +++++++++++++++++++++++++++++++++++++++++++++++-- src/m_menu.h | 5 + src/p_setup.c | 3 + src/w_wad.c | 76 ++++--- src/w_wad.h | 1 + 13 files changed, 1259 insertions(+), 147 deletions(-) diff --git a/src/console.c b/src/console.c index 212e6c8d..b335885d 100644 --- a/src/console.c +++ b/src/console.c @@ -33,6 +33,7 @@ #include "i_system.h" #include "d_main.h" #include "m_menu.h" +#include "filesrch.h" #ifdef _WINDOWS #include "win32/win_main.h" @@ -1281,12 +1282,15 @@ void CONS_Alert(alerttype_t level, const char *fmt, ...) switch (level) { case CONS_NOTICE: + // no notice for notices, hehe CONS_Printf("\x83" "%s" "\x80 ", M_GetText("NOTICE:")); break; case CONS_WARNING: + refreshdirmenu |= REFRESHDIR_WARNING; CONS_Printf("\x82" "%s" "\x80 ", M_GetText("WARNING:")); break; case CONS_ERROR: + refreshdirmenu |= REFRESHDIR_ERROR; CONS_Printf("\x85" "%s" "\x80 ", M_GetText("ERROR:")); break; } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 12ff0a96..c8e8b008 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -343,6 +343,7 @@ typedef struct } ATTRPACK clientconfig_pak; #define MAXSERVERNAME 32 +#define MAXFILENEEDED 915 // This packet is too large typedef struct { @@ -364,7 +365,7 @@ typedef struct unsigned char mapmd5[16]; UINT8 actnum; UINT8 iszone; - UINT8 fileneeded[915]; // is filled with writexxx (byteptr.h) + UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) } ATTRPACK serverinfo_pak; typedef struct diff --git a/src/d_main.c b/src/d_main.c index 6c3f9a42..65a2bc5a 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -74,6 +74,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "m_cond.h" // condition initialization #include "fastcmp.h" #include "keys.h" +#include "filesrch.h" // refreshdirmenu, mainwadstally #ifdef CMAKECONFIG #include "config.h" @@ -681,6 +682,8 @@ void D_SRB2Loop(void) realtics = entertic - oldentertics; oldentertics = entertic; + refreshdirmenu = 0; // not sure where to put this, here as good as any? + #ifdef DEBUGFILE if (!realtics) if (debugload) @@ -1253,23 +1256,38 @@ void D_SRB2Main(void) #ifndef DEVELOP // md5s last updated 12/14/14 // Check MD5s of autoloaded files - mainwads = 0; - W_VerifyFileMD5(mainwads, ASSET_HASH_SRB2_SRB); mainwads++; // srb2.srb/srb2.wad + W_VerifyFileMD5(mainwads, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad #ifdef USE_PATCH_DTA - W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); mainwads++; // patch.dta + W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); // patch.dta #endif - W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); mainwads++; // gfx.kart - W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); mainwads++; // chars.kart - W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); mainwads++; // maps.kart - //W_VerifyFileMD5(mainwads, ASSET_HASH_SOUNDS_KART); mainwads++; // sounds.kart - doesn't trigger modifiedgame, doesn't need an MD5...? + W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); // gfx.kart + W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); // chars.kart + W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); // maps.kart + /*W_VerifyFileMD5(mainwads, ASSET_HASH_SOUNDS_KART);*/ // sounds.kart - doesn't trigger modifiedgame, doesn't need an MD5...? #ifdef USE_PATCH_KART - W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); mainwads++; // patch.kart + W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); // patch.kart #endif // don't check music.dta because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. #endif //ifndef DEVELOP + mainwads = 0; + mainwads++; // srb2.srb/srb2.wad +#ifdef USE_PATCH_DTA + mainwads++; // patch.dta +#endif + mainwads++; // gfx.kart + mainwads++; // chars.kart + mainwads++; // maps.kart + mainwads++; // sounds.kart +#ifdef USE_PATCH_KART + mainwads++; // patch.kart +#endif + mainwads++; // music.kart + + mainwadstally = packetsizetally; + cht_Init(); //---------------------------------------------------- READY SCREEN diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9b635cb0..304ff5e9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -38,6 +38,7 @@ #include "d_main.h" #include "m_random.h" #include "f_finale.h" +#include "filesrch.h" #include "mserv.h" #include "md5.h" #include "z_zone.h" @@ -824,6 +825,14 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_driftaxis3); CV_RegisterVar(&cv_driftaxis4); + // filesrch.c + CV_RegisterVar(&cv_addons_option); + CV_RegisterVar(&cv_addons_folder); + CV_RegisterVar(&cv_addons_md5); + CV_RegisterVar(&cv_addons_showall); + CV_RegisterVar(&cv_addons_search_type); + CV_RegisterVar(&cv_addons_search_case); + // WARNING: the order is important when initialising mouse2 // we need the mouse2port CV_RegisterVar(&cv_mouse2port); @@ -3749,25 +3758,12 @@ static void Command_Addfile(void) break; ++p; // check total packet size and no of files currently loaded + // See W_LoadWadFile in w_wad.c + if ((numwadfiles >= MAX_WADFILES) + || ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) { - size_t packetsize = 0; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; - - // See W_LoadWadFile in w_wad.c - for (i = 0; i < numwadfiles; i++) - packetsize += nameonlylength(wadfiles[i]->filename) + 22; - - packetsize += nameonlylength(fn) + 22; - - if ((numwadfiles >= MAX_WADFILES) - || (packetsize > sizeof(dummycheck->fileneeded))) - { - CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); - return; - } + CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + return; } WRITESTRINGN(buf_p,p,240); @@ -3853,11 +3849,6 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) boolean kick = false; boolean toomany = false; INT32 i,j; - size_t packetsize = 0; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; READSTRINGN(*cp, filename, 240); READMEM(*cp, md5sum, 16); @@ -3884,13 +3875,8 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) } // See W_LoadWadFile in w_wad.c - for (i = 0; i < numwadfiles; i++) - packetsize += nameonlylength(wadfiles[i]->filename) + 22; - - packetsize += nameonlylength(filename) + 22; - if ((numwadfiles >= MAX_WADFILES) - || (packetsize > sizeof(dummycheck->fileneeded))) + || ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8))) toomany = true; else ncs = findfile(filename,md5sum,true); @@ -4059,6 +4045,9 @@ static void Command_Playintro_f(void) if (netgame) return; + if (dirmenu) + closefilemenu(true); + F_StartIntro(); } @@ -4768,6 +4757,9 @@ void Command_ExitGame_f(void) cv_debug = 0; emeralds = 0; + if (dirmenu) + closefilemenu(true); + if (!modeattacking) D_StartTitle(); } diff --git a/src/d_netfil.c b/src/d_netfil.c index 6742cfe2..7927c4ec 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -104,6 +104,7 @@ INT32 lastfilenum = -1; /** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. + * Used to have size limiting built in - now handed via W_LoadWadFile in w_wad.c * */ UINT8 *PutFileNeeded(void) @@ -112,29 +113,22 @@ UINT8 *PutFileNeeded(void) UINT8 *p = netbuffer->u.serverinfo.fileneeded; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus; - size_t bytesused = 0; for (i = 0; i < numwadfiles; i++) { - // If it has only music/sound lumps, mark it as unimportant - if (W_VerifyNMUSlumps(wadfiles[i]->filename)) - filestatus = 0; - else - filestatus = 1; // Important + // If it has only music/sound lumps, don't put it in the list + if (!wadfiles[i]->important) + continue; + + filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS // Store in the upper four bits if (!cv_downloading.value) filestatus += (2 << 4); // Won't send - else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)) - filestatus += (0 << 4); // Won't send - else + else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024)) filestatus += (1 << 4); // Will send if requested - - bytesused += (nameonlylength(wadfilename) + 22); - - // Don't write too far... - if (bytesused > sizeof(netbuffer->u.serverinfo.fileneeded)) - I_Error("Too many wad files added to host a game. (%s, stopped on %s)\n", sizeu1(bytesused), wadfilename); + // else + // filestatus += (0 << 4); -- Won't send, too big WRITEUINT8(p, filestatus); @@ -167,7 +161,6 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) { fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet filestatus = READUINT8(p); // The first byte is the file status - fileneeded[i].important = (UINT8)(filestatus & 3); fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size fileneeded[i].file = NULL; // The file isn't open yet @@ -197,7 +190,7 @@ boolean CL_CheckDownloadable(void) UINT8 i,dlstatus = 0; for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && fileneeded[i].important) + if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { if (fileneeded[i].willsend == 1) continue; @@ -218,7 +211,7 @@ boolean CL_CheckDownloadable(void) // not downloadable, put reason in console CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && fileneeded[i].important) + if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); @@ -271,7 +264,7 @@ boolean CL_SendRequestFile(void) for (i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN - && fileneeded[i].important && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) + && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) { I_Error("Attempted to download files that were not sendable"); } @@ -280,8 +273,7 @@ boolean CL_SendRequestFile(void) netbuffer->packettype = PT_REQUESTFILE; p = (char *)netbuffer->u.textcmd; for (i = 0; i < fileneedednum; i++) - if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) - && fileneeded[i].important) + if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) { totalfreespaceneeded += fileneeded[i].totalsize; nameonly(fileneeded[i].filename); @@ -339,10 +331,6 @@ INT32 CL_CheckFiles(void) INT32 ret = 1; size_t packetsize = 0; size_t filestoget = 0; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; // if (M_CheckParm("-nofiles")) // return 1; @@ -360,13 +348,7 @@ INT32 CL_CheckFiles(void) CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n"); for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;) { - if (i < fileneedednum && !fileneeded[i].important) - { - // Eh whatever, don't care - ++i; - continue; - } - if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename)) + if (j < numwadfiles && !wadfiles[j]->important) { // Unimportant on our side. still don't care. ++j; @@ -392,8 +374,7 @@ INT32 CL_CheckFiles(void) } // See W_LoadWadFile in w_wad.c - for (i = 0; i < numwadfiles; i++) - packetsize += nameonlylength(wadfiles[i]->filename) + 22; + packetsize = packetsizetally; for (i = 1; i < fileneedednum; i++) { @@ -411,13 +392,13 @@ INT32 CL_CheckFiles(void) break; } } - if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important) + if (fileneeded[i].status != FS_NOTFOUND) continue; packetsize += nameonlylength(fileneeded[i].filename) + 22; if ((numwadfiles+filestoget >= MAX_WADFILES) - || (packetsize > sizeof(dummycheck->fileneeded))) + || (packetsize > MAXFILENEEDED*sizeof(UINT8))) return 3; filestoget++; @@ -449,27 +430,8 @@ void CL_LoadServerFiles(void) fileneeded[i].status = FS_OPEN; } else if (fileneeded[i].status == FS_MD5SUMBAD) - { - // If the file is marked important, don't even bother proceeding. - if (fileneeded[i].important) - I_Error("Wrong version of important file %s", fileneeded[i].filename); - - // If it isn't, no need to worry the user with a console message, - // although it can't hurt to put something in the debug file. - - // ...but wait a second. What if the local version is "important"? - if (!W_VerifyNMUSlumps(fileneeded[i].filename)) - I_Error("File %s should only contain music and sound effects!", - fileneeded[i].filename); - - // Okay, NOW we know it's safe. Whew. - P_AddWadFile(fileneeded[i].filename, NULL); - if (fileneeded[i].important) - G_SetGameModified(true); - fileneeded[i].status = FS_OPEN; - DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename)); - } - else if (fileneeded[i].important) + I_Error("Wrong version of file %s", fileneeded[i].filename); + else { const char *s; switch(fileneeded[i].status) @@ -939,10 +901,11 @@ void nameonly(char *s) { ns = &(s[j+1]); len = strlen(ns); - if (false) +#if 0 M_Memcpy(s, ns, len+1); - else +#else memmove(s, ns, len+1); +#endif return; } } diff --git a/src/d_netfil.h b/src/d_netfil.h index b9b7b2f2..6fdd0a8a 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -35,7 +35,6 @@ typedef enum typedef struct { - UINT8 important; UINT8 willsend; // Is the server willing to send it? char filename[MAX_WADPATH]; UINT8 md5sum[16]; diff --git a/src/filesrch.c b/src/filesrch.c index 2463e717..59868653 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -31,6 +31,8 @@ #include "filesrch.h" #include "d_netfil.h" #include "m_misc.h" +#include "z_zone.h" +#include "m_menu.h" // Addons_option_Onchange #if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX) @@ -255,6 +257,28 @@ readdir (DIR * dirp) return (struct dirent *) 0; } +/* + * rewinddir + * + * Makes the next readdir start from the beginning. + */ +int +rewinddir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return -1; + } + + dirp->dd_stat = 0; + + return 0; +} + /* * closedir * @@ -285,6 +309,41 @@ closedir (DIR * dirp) return rc; } #endif + +static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"}, +#if 1 + {1, "HOME"}, {2, "SRB2"}, +#endif + {3, "CUSTOM"}, {0, NULL}}; + +consvar_t cv_addons_option = {"addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_addons_folder = {"addons_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; + +static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}}; +consvar_t cv_addons_md5 = {"addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_addons_showall = {"addons_showall", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_addons_search_case = {"addons_search_case", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + +static CV_PossibleValue_t addons_search_type_cons_t[] = {{0, "Start"}, {1, "Anywhere"}, {0, NULL}}; +consvar_t cv_addons_search_type = {"addons_search_type", "Anywhere", CV_SAVE, addons_search_type_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +char menupath[1024]; +size_t menupathindex[menudepth]; +size_t menudepthleft = menudepth; + +char menusearch[MAXSTRINGLENGTH+1]; + +char **dirmenu, **coredirmenu; // core only local for this file +size_t sizedirmenu, sizecoredirmenu; // ditto +size_t dir_on[menudepth]; +UINT8 refreshdirmenu = 0; +char *refreshdirname = NULL; + +size_t packetsizetally = 0; +size_t mainwadstally = 0; + #if defined (_XBOX) && defined (_MSC_VER) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -296,6 +355,25 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want completepath = false; return FS_NOTFOUND; } + +void closefilemenu(boolean validsize) +{ + (void)validsize; + return; +} + +void searchfilemenu(char *tempname) +{ + (void)tempname; + return; +} + +boolean preparefilemenu(boolean samedepth) +{ + (void)samedepth; + return false; +} + #elif defined (_WIN32_WCE) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -346,7 +424,27 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want #endif return FS_NOTFOUND; } + +void closefilemenu(boolean validsize) +{ + (void)validsize; + return; +} + +void searchfilemenu(char *tempname) +{ + (void)tempname; + return; +} + +boolean preparefilemenu(boolean samedepth) +{ + (void)samedepth; + return false; +} + #else + filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) { filestatus_t retval = FS_NOTFOUND; @@ -387,25 +485,29 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want { searchpath[searchpathindex[depthleft]]=0; dent = readdir(dirhandle[depthleft]); - if (dent) - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); if (!dent) + { closedir(dirhandle[depthleft++]); - else if (dent->d_name[0]=='.' && + continue; + } + + if (dent->d_name[0]=='.' && (dent->d_name[1]=='\0' || (dent->d_name[1]=='.' && dent->d_name[2]=='\0'))) { // we don't want to scan uptree + continue; } - else if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat - { - // was the file (re)moved? can't stat it - } + + // okay, now we actually want searchpath to incorporate d_name + strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); + + if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it else if (S_ISDIR(fsstat.st_mode) && depthleft) { - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); searchpathindex[--depthleft] = strlen(searchpath) + 1; dirhandle[depthleft] = opendir(searchpath); if (!dirhandle[depthleft]) @@ -444,6 +546,361 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want free(searchname); free(searchpathindex); free(dirhandle); + return retval; } + +char exttable[NUM_EXT_TABLE][5] = { + ".txt", ".cfg", // exec + ".wad", /*".pk3",*/ ".soc", ".lua"}; // addfile + +char filenamebuf[MAX_WADFILES][MAX_WADPATH]; + + +static boolean filemenucmp(char *haystack, char *needle) +{ + static char localhaystack[128]; + strlcpy(localhaystack, haystack, 128); + if (!cv_addons_search_case.value) + strupr(localhaystack); + return ((cv_addons_search_type.value) + ? (strstr(localhaystack, needle) != 0) + : (!strncmp(localhaystack, needle, menusearch[0]))); +} + +void closefilemenu(boolean validsize) +{ + // search + if (dirmenu) + { + if (dirmenu != coredirmenu) + { + if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS)) + { + Z_Free(dirmenu[0]); + dirmenu[0] = NULL; + } + Z_Free(dirmenu); + } + dirmenu = NULL; + sizedirmenu = 0; + } + + if (coredirmenu) + { + // core + if (validsize) + { + for (; sizecoredirmenu > 0; sizecoredirmenu--) + { + Z_Free(coredirmenu[sizecoredirmenu-1]); + coredirmenu[sizecoredirmenu-1] = NULL; + } + } + else + sizecoredirmenu = 0; + + Z_Free(coredirmenu); + coredirmenu = NULL; + } + + if (refreshdirname) + Z_Free(refreshdirname); + refreshdirname = NULL; +} + +void searchfilemenu(char *tempname) +{ + size_t i, first; + char localmenusearch[MAXSTRINGLENGTH] = ""; + + if (dirmenu) + { + if (dirmenu != coredirmenu) + { + if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS)) + { + Z_Free(dirmenu[0]); + dirmenu[0] = NULL; + } + //Z_Free(dirmenu); -- Z_Realloc later tho... + } + else + dirmenu = NULL; + } + + first = (((UINT8)(coredirmenu[0][DIR_TYPE]) == EXT_UP) ? 1 : 0); // skip UP... + + if (!menusearch[0]) + { + if (dirmenu) + Z_Free(dirmenu); + dirmenu = coredirmenu; + sizedirmenu = sizecoredirmenu; + + if (tempname) + { + for (i = first; i < sizedirmenu; i++) + { + if (!strcmp(dirmenu[i]+DIR_STRING, tempname)) + { + dir_on[menudepthleft] = i; + break; + } + } + + if (i == sizedirmenu) + dir_on[menudepthleft] = first; + + Z_Free(tempname); + } + + return; + } + + strcpy(localmenusearch, menusearch+1); + if (!cv_addons_search_case.value) + strupr(localmenusearch); + + sizedirmenu = 0; + for (i = first; i < sizecoredirmenu; i++) + { + if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch)) + sizedirmenu++; + } + + if (!sizedirmenu) // no results... + { + if ((!(dirmenu = Z_Realloc(dirmenu, sizeof(char *), PU_STATIC, NULL))) + || !(dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS)))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + sizedirmenu = 1; + dir_on[menudepthleft] = 0; + if (tempname) + Z_Free(tempname); + return; + } + + if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + + sizedirmenu = 0; + for (i = first; i < sizecoredirmenu; i++) + { + if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch)) + { + if (tempname && !strcmp(coredirmenu[i]+DIR_STRING, tempname)) + { + dir_on[menudepthleft] = sizedirmenu; + Z_Free(tempname); + tempname = NULL; + } + dirmenu[sizedirmenu++] = coredirmenu[i]; // pointer reuse + } + } + + if (tempname) + { + dir_on[menudepthleft] = first; + Z_Free(tempname); + } +} + +boolean preparefilemenu(boolean samedepth) +{ + DIR *dirhandle; + struct dirent *dent; + struct stat fsstat; + size_t pos = 0, folderpos = 0, numfolders = 0; + char *tempname = NULL; + + if (samedepth) + { + if (dirmenu && dirmenu[dir_on[menudepthleft]]) + tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL + } + else + menusearch[0] = menusearch[1] = 0; // clear search + + if (!(dirhandle = opendir(menupath))) // get directory + { + closefilemenu(true); + return false; + } + + for (; sizecoredirmenu > 0; sizecoredirmenu--) // clear out existing items + { + Z_Free(coredirmenu[sizecoredirmenu-1]); + coredirmenu[sizecoredirmenu-1] = NULL; + } + + while (true) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + if (!S_ISDIR(fsstat.st_mode)) // file + { + if (!cv_addons_showall.value) + { + size_t len = strlen(dent->d_name)+1; + UINT8 ext; + for (ext = 0; ext < NUM_EXT_TABLE; ext++) + if (!strcasecmp(exttable[ext], dent->d_name+len-5)) break; // extension comparison + if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file + } + } + else // directory + numfolders++; + + sizecoredirmenu++; + } + } + + if (!sizecoredirmenu) + { + closedir(dirhandle); + closefilemenu(false); + if (tempname) + Z_Free(tempname); + return false; + } + + if (menudepthleft != menudepth-1) // Make room for UP... + { + sizecoredirmenu++; + numfolders++; + folderpos++; + } + + if (dirmenu && dirmenu == coredirmenu) + dirmenu = NULL; + + if (!(coredirmenu = Z_Realloc(coredirmenu, sizecoredirmenu*sizeof(char *), PU_STATIC, NULL))) + { + closedir(dirhandle); // just in case + I_Error("Ran out of memory whilst preparing add-ons menu"); + } + + rewinddir(dirhandle); + + while ((pos+folderpos) < sizecoredirmenu) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + char *temp; + size_t len = strlen(dent->d_name)+1; + UINT8 ext = EXT_FOLDER; + UINT8 folder; + + if (!S_ISDIR(fsstat.st_mode)) // file + { + if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention + for (; ext < NUM_EXT_TABLE; ext++) + if (!strcasecmp(exttable[ext], dent->d_name+len-5)) break; // extension comparison + if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file + ext += EXT_START; // moving to be appropriate position + + if (ext >= EXT_LOADSTART) + { + size_t i; + for (i = 0; i < numwadfiles; i++) + { + if (!filenamebuf[i][0]) + { + strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH); + filenamebuf[i][MAX_WADPATH - 1] = '\0'; + nameonly(filenamebuf[i]); + } + + if (strcmp(dent->d_name, filenamebuf[i])) + continue; + if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum)) + continue; + + ext |= EXT_LOADED; + } + } + else if (ext == EXT_TXT) + { + if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + ext |= EXT_LOADED; + } + + if (!strcmp(dent->d_name, configfile)) + ext |= EXT_LOADED; + + folder = 0; + } + else // directory + len += (folder = 1); + + if (len > 255) + len = 255; + + if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + temp[DIR_TYPE] = ext; + temp[DIR_LEN] = (UINT8)(len); + strlcpy(temp+DIR_STRING, dent->d_name, len); + if (folder) + { + strcpy(temp+len, PATHSEP); + coredirmenu[folderpos++] = temp; + } + else + coredirmenu[numfolders + pos++] = temp; + } + } + + closedir(dirhandle); + + if ((menudepthleft != menudepth-1) // now for UP... entry + && !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP)))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + + menupath[menupathindex[menudepthleft]] = 0; + sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind + + if (!sizecoredirmenu) + { + dir_on[menudepthleft] = 0; + closefilemenu(false); + return false; + } + + searchfilemenu(tempname); + + return true; +} + #endif diff --git a/src/filesrch.h b/src/filesrch.h index 33b148d4..51615308 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -6,6 +6,9 @@ #include "doomdef.h" #include "d_netfil.h" +#include "m_menu.h" // MAXSTRINGLENGTH + +extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type; /** \brief The filesearch function @@ -25,4 +28,68 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth); +#define menudepth 20 + +extern char menupath[1024]; +extern size_t menupathindex[menudepth]; +extern size_t menudepthleft; + +extern char menusearch[MAXSTRINGLENGTH+1]; + +extern char **dirmenu; +extern size_t sizedirmenu; +extern size_t dir_on[menudepth]; +extern UINT8 refreshdirmenu; +extern char *refreshdirname; + +extern size_t packetsizetally; +extern size_t mainwadstally; + +typedef enum +{ + EXT_FOLDER = 0, + EXT_UP, + EXT_NORESULTS, + EXT_START, + EXT_TXT = EXT_START, + EXT_CFG, + EXT_LOADSTART, + EXT_WAD = EXT_LOADSTART, + //EXT_PK3, + EXT_SOC, + EXT_LUA, // allowed even if not HAVE_BLUA so that we can yell on load attempt + NUM_EXT, + NUM_EXT_TABLE = NUM_EXT-EXT_START, + EXT_LOADED = 0x80 + /* + obviously there can only be 0x7F supported extensions in + addons menu because we're cramming this into a char out of + laziness/easy memory allocation (what's the difference?) + and have stolen a bit to show whether it's loaded or not + in practice the size of the data type is probably overkill + toast 02/05/17 + */ +} ext_enum; + +typedef enum +{ + DIR_TYPE = 0, + DIR_LEN, + DIR_STRING +} dirname_enum; + +typedef enum +{ + REFRESHDIR_NORMAL = 1, + REFRESHDIR_ADDFILE = 2, + REFRESHDIR_WARNING = 4, + REFRESHDIR_ERROR = 8, + REFRESHDIR_NOTLOADED = 16, + REFRESHDIR_MAX = 32 +} refreshdir_enum; + +void closefilemenu(boolean validsize); +void searchfilemenu(char *tempname); +boolean preparefilemenu(boolean samedepth); + #endif // __FILESRCH_H__ diff --git a/src/m_menu.c b/src/m_menu.c index eb8123e9..5ba5d81b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -33,6 +33,9 @@ #include "s_sound.h" #include "i_system.h" +// Addfile +#include "filesrch.h" + #include "v_video.h" #include "i_video.h" #include "keys.h" @@ -67,6 +70,10 @@ int snprintf(char *str, size_t n, const char *fmt, ...); //int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); #endif +#if defined (__GNUC__) && (__GNUC__ >= 4) +#define FIXUPO0 +#endif + #define SKULLXOFF -32 #define LINEHEIGHT 16 #define STRINGHEIGHT 8 @@ -74,7 +81,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #define SMALLLINEHEIGHT 8 #define SLIDER_RANGE 10 #define SLIDER_WIDTH (8*SLIDER_RANGE+6) -#define MAXSTRINGLENGTH 32 #define SERVERS_PER_PAGE 11 typedef enum @@ -206,6 +212,8 @@ menu_t MessageDef; menu_t SPauseDef; +#define lsheadingheight 16 + // Sky Room //static void M_CustomLevelSelect(INT32 choice); //static void M_CustomWarp(INT32 choice); @@ -321,9 +329,16 @@ menu_t OP_MonitorToggleDef; static void M_ScreenshotOptions(INT32 choice); static void M_EraseData(INT32 choice); +static void M_Addons(INT32 choice); +static void M_AddonsOptions(INT32 choice); +static patch_t *addonsp[NUM_EXT+5]; + +#define numaddonsshown 4 + // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawCenteredMenu(void); +static void M_DrawAddons(void); static void M_DrawSkyRoom(void); static void M_DrawChecklist(void); static void M_DrawEmblemHints(void); @@ -359,6 +374,7 @@ static boolean M_CancelConnect(void); #endif static boolean M_ExitPandorasBox(void); static boolean M_QuitMultiPlayerMenu(void); +static void M_HandleAddons(INT32 choice); static void M_HandleSoundTest(INT32 choice); static void M_HandleImageDef(INT32 choice); static void M_HandleLoadSave(INT32 choice); @@ -479,15 +495,16 @@ static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaf // --------- static menuitem_t MainMenu[] = { - {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 84}, - {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 92}, + {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 76}, + {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, #ifdef NONET M_StartSplitServerMenu - {IT_CALL |IT_STRING, NULL, "Splitscreen", M_StartSplitServerMenu,100}, + {IT_CALL |IT_STRING, NULL, "Splitscreen", M_StartSplitServerMenu, 92}, #else - {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 100}, + {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, #endif - {IT_CALL |IT_STRING, NULL, "Options", M_Options, 108}, + {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, + {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, }; @@ -497,9 +514,15 @@ typedef enum singleplr, multiplr, options, + addons, quitdoom } main_e; +static menuitem_t MISC_AddonsMenu[] = +{ + {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func +}; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -522,8 +545,9 @@ typedef enum // --------------------- static menuitem_t MPauseMenu[] = { - {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, - {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, + {IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8}, + {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, + {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,40}, {IT_CALL | IT_STRING, NULL, "P1 Setup...", M_SetupMultiPlayer, 48}, // splitscreen @@ -546,7 +570,8 @@ static menuitem_t MPauseMenu[] = typedef enum { - mpause_scramble = 0, + mpause_addons = 0, + mpause_scramble, mpause_switchmap, mpause_continue, @@ -1054,9 +1079,10 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU|IT_STRING, NULL, "Gameplay Options...", &OP_GameOptionsDef, 90}, {IT_SUBMENU|IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 100}, + {IT_STRING|IT_CALL, NULL, "Add-on Options...", M_AddonsOptions, 110}, - {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 120}, - {IT_SUBMENU|IT_STRING, NULL, "Erase Data...", &OP_EraseDataDef, 130}, + {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 130}, + {IT_SUBMENU|IT_STRING, NULL, "Erase Data...", &OP_EraseDataDef, 140}, }; static menuitem_t OP_ControlsMenu[] = @@ -1413,6 +1439,24 @@ static menuitem_t OP_EraseDataMenu[] = {IT_STRING | IT_CALL, NULL, "\x85" "Erase ALL Data", M_EraseData, 40}, }; +static menuitem_t OP_AddonsOptionsMenu[] = +{ + {IT_HEADER, NULL, "Menu", NULL, 0}, + {IT_STRING|IT_CVAR, NULL, "Location", &cv_addons_option, 10}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_addons_folder, 20}, + {IT_STRING|IT_CVAR, NULL, "Identify add-ons via", &cv_addons_md5, 48}, + {IT_STRING|IT_CVAR, NULL, "Show unsupported file types", &cv_addons_showall, 58}, + + {IT_HEADER, NULL, "Search", NULL, 76}, + {IT_STRING|IT_CVAR, NULL, "Matching", &cv_addons_search_type, 86}, + {IT_STRING|IT_CVAR, NULL, "Case-sensitive", &cv_addons_search_case, 96}, +}; + +enum +{ + op_addons_folder = 2, +}; + static menuitem_t OP_HUDOptionsMenu[] = { {IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 10}, @@ -1549,6 +1593,18 @@ static menuitem_t OP_MonitorToggleMenu[] = // Main Menu and related menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); +menu_t MISC_AddonsDef = +{ + NULL, + sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), + &MainDef, + MISC_AddonsMenu, + M_DrawAddons, + 50, 28, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -2004,7 +2060,8 @@ menu_t OP_OpenGLColorDef = #endif //menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_MainDef, 60, 30); +menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_MainDef, 30, 30); +menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_MainDef, 30, 30); // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE @@ -2223,6 +2280,12 @@ void Moviemode_mode_Onchange(void) OP_ScreenshotOptionsMenu[i].status = IT_STRING|IT_CVAR; } +void Addons_option_Onchange(void) +{ + OP_AddonsOptionsMenu[op_addons_folder].status = + (cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); +} + // ========================================================================== // END ORGANIZATION STUFF. // ========================================================================== @@ -2877,6 +2940,7 @@ void M_StartControlPanel(void) else // multiplayer { MPauseMenu[mpause_switchmap].status = IT_DISABLED; + MPauseMenu[mpause_addons].status = IT_DISABLED; MPauseMenu[mpause_scramble].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED; @@ -2897,6 +2961,7 @@ void M_StartControlPanel(void) if ((server || IsPlayerAdmin(consoleplayer))) { MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL; + MPauseMenu[mpause_addons].status = IT_STRING | IT_CALL; if (G_GametypeHasTeams()) MPauseMenu[mpause_scramble].status = IT_STRING | IT_SUBMENU; } @@ -4215,6 +4280,521 @@ static void M_HandleImageDef(INT32 choice) // MISC MAIN MENU OPTIONS // ====================== +static void M_AddonsOptions(INT32 choice) +{ + (void)choice; + Addons_option_Onchange(); + + M_SetupNextMenu(&OP_AddonsOptionsDef); +} + +#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make add-ons!" +#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make add-ons!" + +static void M_Addons(INT32 choice) +{ + const char *pathname = "."; + + (void)choice; + +#if 1 + if (cv_addons_option.value == 0) + pathname = usehome ? srb2home : srb2path; + else if (cv_addons_option.value == 1) + pathname = srb2home; + else if (cv_addons_option.value == 2) + pathname = srb2path; + else +#endif + if (cv_addons_option.value == 3 && *cv_addons_folder.string != '\0') + pathname = cv_addons_folder.string; + + strlcpy(menupath, pathname, 1024); + menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath) + 1; + + if (menupath[menupathindex[menudepthleft]-2] != PATHSEP[0]) + { + menupath[menupathindex[menudepthleft]-1] = PATHSEP[0]; + menupath[menupathindex[menudepthleft]] = 0; + } + else + --menupathindex[menudepthleft]; + + if (!preparefilemenu(false)) + { + M_StartMessage(va("No files/folders found.\n\n%s\n\n(Press a key)\n", (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)),NULL,MM_NOTHING); + return; + } + else + dir_on[menudepthleft] = 0; + + if (addonsp[0]) // never going to have some provided but not all, saves individually checking + { + size_t i; + for (i = 0; i < NUM_EXT+5; i++) + W_UnlockCachedPatch(addonsp[i]); + } + + addonsp[EXT_FOLDER] = W_CachePatchName("M_FFLDR", PU_STATIC); + addonsp[EXT_UP] = W_CachePatchName("M_FBACK", PU_STATIC); + addonsp[EXT_NORESULTS] = W_CachePatchName("M_FNOPE", PU_STATIC); + addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC); + addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC); + addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC); + //addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC); + addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC); + addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC); + addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_STATIC); + addonsp[NUM_EXT+1] = W_CachePatchName("M_FSEL", PU_STATIC); + addonsp[NUM_EXT+2] = W_CachePatchName("M_FLOAD", PU_STATIC); + addonsp[NUM_EXT+3] = W_CachePatchName("M_FSRCH", PU_STATIC); + addonsp[NUM_EXT+4] = W_CachePatchName("M_FSAVE", PU_STATIC); + + MISC_AddonsDef.prevMenu = currentMenu; + M_SetupNextMenu(&MISC_AddonsDef); +} + +#define width 4 +#define vpadding 27 +#define h (BASEVIDHEIGHT-(2*vpadding)) +#define NUMCOLOURS 8 // when toast's coding it's british english hacker fucker +static void M_DrawTemperature(INT32 x, fixed_t t) +{ + INT32 y; + + // bounds check + if (t > FRACUNIT) + t = FRACUNIT; + /*else if (t < 0) -- not needed + t = 0;*/ + + // scale + if (t > 1) + t = (FixedMul(h<>FRACBITS); + + // border + V_DrawFill(x - 1, vpadding, 1, h, 120); + V_DrawFill(x + width, vpadding, 1, h, 120); + V_DrawFill(x - 1, vpadding-1, width+2, 1, 120); + V_DrawFill(x - 1, vpadding+h, width+2, 1, 120); + + // bar itself + y = h; + if (t) + for (t = h - t; y > 0; y--) + { + UINT8 colours[NUMCOLOURS] = {135, 133, 92, 77, 114, 178, 161, 162}; + UINT8 c; + if (y <= t) break; + if (y+vpadding >= BASEVIDHEIGHT/2) + c = 185; + else + c = colours[(NUMCOLOURS*(y-1))/(h/2)]; + V_DrawFill(x, y-1 + vpadding, width, 1, c); + } + + // fill the rest of the backing + if (y) + V_DrawFill(x, vpadding, width, y, 30); +} +#undef width +#undef vpadding +#undef h +#undef NUMCOLOURS + +static char *M_AddonsHeaderPath(void) +{ + UINT32 len; + static char header[1024]; + + strlcpy(header, va("%s folder%s", cv_addons_option.string, menupath+menupathindex[menudepth-1]-1), 1024); + len = strlen(header); + if (len > 34) + { + len = len-34; + header[len] = header[len+1] = header[len+2] = '.'; + } + else + len = 0; + + return header+len; +} + +#define UNEXIST S_StartSound(NULL, sfx_lose);\ + M_SetupNextMenu(MISC_AddonsDef.prevMenu);\ + M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING) + +#define CLEARNAME Z_Free(refreshdirname);\ + refreshdirname = NULL + +static void M_AddonsClearName(INT32 choice) +{ + CLEARNAME; + M_StopMessage(choice); +} + +// returns whether to do message draw +static boolean M_AddonsRefresh(void) +{ + if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true)) + { + UNEXIST; + return true; + } + + if (refreshdirmenu & REFRESHDIR_ADDFILE) + { + char *message = NULL; + + if (refreshdirmenu & REFRESHDIR_NOTLOADED) + { + S_StartSound(NULL, sfx_lose); + if (refreshdirmenu & REFRESHDIR_MAX) + message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + else + message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + } + else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR)) + { + S_StartSound(NULL, sfx_skid); + message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); + } + + if (message) + { + M_StartMessage(message,M_AddonsClearName,MM_EVENTHANDLER); + return true; + } + + S_StartSound(NULL, sfx_strpst); + CLEARNAME; + } + + return false; +} + +#ifdef FIXUPO0 +#pragma GCC optimize ("0") +#endif + +static void M_DrawAddons(void) +{ + INT32 x, y; + ssize_t i, max; + const UINT8 *flashcol = NULL; + + // hack - need to refresh at end of frame to handle addfile... + if (refreshdirmenu & M_AddonsRefresh()) + { + M_DrawMessageMenu(); + return; + } + + if (Playing()) + V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); + else + V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)); + + if (numwadfiles <= mainwads+1) + y = 0; + else if (numwadfiles >= MAX_WADFILES) + y = FRACUNIT; + else + { + x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< y) + y = x; + if (y > FRACUNIT) // happens because of how we're shrinkin' it a little + y = FRACUNIT; + } + + M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y); + + // DRAW MENU + x = currentMenu->x; + y = currentMenu->y + 1; + + V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath()); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), (MAXSTRINGLENGTH*8+6 - 1), 1, V_GetStringColormap(highlightflags)[120]); + V_DrawFill(x-21 + (MAXSTRINGLENGTH*8+6 - 1), (y - 16) + (lsheadingheight - 3), 1, 1, 30); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30); + + V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1), 239); + + // get bottom... + max = dir_on[menudepthleft] + numaddonsshown + 1; + if (max > (ssize_t)sizedirmenu) + max = sizedirmenu; + + // then top... + i = max - (2*numaddonsshown + 1); + + // then adjust! + if (i < 0) + { + if ((max -= i) > (ssize_t)sizedirmenu) + max = sizedirmenu; + i = 0; + } + + if (i != 0) + V_DrawString(19, y+4 - (skullAnimCounter/5), highlightflags, "\x1A"); + + if (skullAnimCounter < 4) + flashcol = V_GetStringColormap(highlightflags); + + for (; i < max; i++) + { + UINT32 flags = V_ALLOWLOWERCASE; + if (y > BASEVIDHEIGHT) break; + if (dirmenu[i]) +#define type (UINT8)(dirmenu[i][DIR_TYPE]) + { + if (type & EXT_LOADED) + flags |= V_TRANSLUCENT; + + V_DrawSmallScaledPatch(x-(16+4), y, (flags & V_TRANSLUCENT), addonsp[((UINT8)(dirmenu[i][DIR_TYPE]) & ~EXT_LOADED)]); + + if (type & EXT_LOADED) + V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+2]); + + if ((size_t)i == dir_on[menudepthleft]) + { + V_DrawFixedPatch((x-(16+4))< (charsonside*2 + 3)) + V_DrawString(x, y+4, flags, va("%.*s...%s", charsonside, dirmenu[i]+DIR_STRING, dirmenu[i]+DIR_STRING+dirmenu[i][DIR_LEN]-(charsonside+1))); +#undef charsonside + else + V_DrawString(x, y+4, flags, dirmenu[i]+DIR_STRING); + } +#undef type + y += 16; + } + + if (max != (ssize_t)sizedirmenu) + V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B"); + + y = BASEVIDHEIGHT - currentMenu->y + 1; + + M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1); + if (menusearch[0]) + V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE, menusearch+1); + else + V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE|V_TRANSLUCENT, "Type to search..."); + if (skullAnimCounter < 4) + V_DrawCharacter(x - 18 + V_StringWidth(menusearch+1, 0), y + 8, + '_' | 0x80, false); + + x -= (21 + 5 + 16); + V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); + + x = BASEVIDWIDTH - x - 16; + V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); + + if (modifiedgame) + V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+2]); +} + +#ifdef FIXUPO0 +#pragma GCC reset_options +#endif + +static void M_AddonExec(INT32 ch) +{ + if (ch != 'y' && ch != KEY_ENTER) + return; + + S_StartSound(NULL, sfx_zoom); + COM_BufAddText(va("exec %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); +} + +#define len menusearch[0] +static boolean M_ChangeStringAddons(INT32 choice) +{ + if (shiftdown && choice >= 32 && choice <= 127) + choice = shiftxform[choice]; + + switch (choice) + { + case KEY_DEL: + if (len) + { + len = menusearch[1] = 0; + return true; + } + break; + case KEY_BACKSPACE: + if (len) + { + menusearch[1+--len] = 0; + return true; + } + break; + default: + if (choice >= 32 && choice <= 127) + { + if (len < MAXSTRINGLENGTH - 1) + { + menusearch[1+len++] = (char)choice; + menusearch[1+len] = 0; + return true; + } + } + break; + } + return false; +} +#undef len + +static void M_HandleAddons(INT32 choice) +{ + boolean exitmenu = false; // exit to previous menu + + if (M_ChangeStringAddons(choice)) + { + char *tempname = NULL; + if (dirmenu && dirmenu[dir_on[menudepthleft]]) + tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL + searchfilemenu(tempname); + /*if (!preparefilemenu(true)) + { + UNEXIST; + return; + }*/ + } + + switch (choice) + { + case KEY_DOWNARROW: + if (dir_on[menudepthleft] < sizedirmenu-1) + dir_on[menudepthleft]++; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_UPARROW: + if (dir_on[menudepthleft]) + dir_on[menudepthleft]--; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_PGDN: + { + UINT8 i; + for (i = numaddonsshown; i && (dir_on[menudepthleft] < sizedirmenu-1); i--) + dir_on[menudepthleft]++; + } + S_StartSound(NULL, sfx_menu1); + break; + case KEY_PGUP: + { + UINT8 i; + for (i = numaddonsshown; i && (dir_on[menudepthleft]); i--) + dir_on[menudepthleft]--; + } + S_StartSound(NULL, sfx_menu1); + break; + case KEY_ENTER: + { + boolean refresh = true; + if (!dirmenu[dir_on[menudepthleft]]) + S_StartSound(NULL, sfx_lose); + else + { + switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE]) + { + case EXT_FOLDER: + strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING); + if (menudepthleft) + { + menupathindex[--menudepthleft] = strlen(menupath); + menupath[menupathindex[menudepthleft]] = 0; + + if (!preparefilemenu(false)) + { + S_StartSound(NULL, sfx_skid); + M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); + menupath[menupathindex[++menudepthleft]] = 0; + + if (!preparefilemenu(true)) + { + UNEXIST; + return; + } + } + else + { + S_StartSound(NULL, sfx_menu1); + dir_on[menudepthleft] = 1; + } + refresh = false; + } + else + { + S_StartSound(NULL, sfx_lose); + M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); + menupath[menupathindex[menudepthleft]] = 0; + } + break; + case EXT_UP: + S_StartSound(NULL, sfx_menu1); + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu(false)) + { + UNEXIST; + return; + } + break; + case EXT_TXT: + M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),M_AddonExec,MM_YESNO); + break; + case EXT_CFG: + M_AddonExec(KEY_ENTER); + break; + case EXT_LUA: +#ifndef HAVE_BLUA + S_StartSound(NULL, sfx_lose); + M_StartMessage(va("%c%s\x80\nThis copy of SRB2 was compiled\nwithout support for .lua files.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING); + break; +#endif + // else intentional fallthrough + case EXT_SOC: + case EXT_WAD: + //case EXT_PK3: + COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + break; + default: + S_StartSound(NULL, sfx_lose); + } + } + if (refresh) + refreshdirmenu |= REFRESHDIR_NORMAL; + } + break; + + case KEY_ESCAPE: + exitmenu = true; + break; + + default: + break; + } + if (exitmenu) + { + closefilemenu(true); + + // secrets disabled by addfile... + MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + + if (currentMenu->prevMenu) + M_SetupNextMenu(currentMenu->prevMenu); + else + M_ClearMenus(true); + } +} + static void M_PandorasBox(INT32 choice) { (void)choice; @@ -4317,8 +4897,8 @@ static void M_Options(INT32 choice) OP_MainMenu[5].status = OP_MainMenu[6].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // if the player is playing _at all_, disable the erase data & credits options - OP_MainMenu[7].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); - OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); + OP_MainMenu[9].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_MainDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_MainDef); diff --git a/src/m_menu.h b/src/m_menu.h index 51559489..cb083b0e 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -124,6 +124,8 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_HEADER (IT_SPACE +IT_HEADERTEXT) #define IT_SECRET (IT_SPACE +IT_QUESTIONMARKS) +#define MAXSTRINGLENGTH 32 + typedef union { struct menu_s *submenu; // IT_SUBMENU @@ -223,6 +225,9 @@ void M_CheatActivationResponder(INT32 ch); void Moviemode_mode_Onchange(void); void Screenshot_option_Onchange(void); +// Addons menu updating +void Addons_option_Onchange(void); + // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(header, source, prev, x, y)\ {\ diff --git a/src/p_setup.c b/src/p_setup.c index f4c28663..704df2a5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -54,6 +54,8 @@ #include "v_video.h" +#include "filesrch.h" // refreshdirmenu + // wipes #include "f_finale.h" @@ -3126,6 +3128,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX) { + refreshdirmenu |= REFRESHDIR_NOTLOADED; CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); return false; } diff --git a/src/w_wad.c b/src/w_wad.c index 3a828559..c4850905 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -34,6 +34,8 @@ #include "z_zone.h" #include "fastcmp.h" +#include "filesrch.h" + #include "i_video.h" // rendermode #include "d_netfil.h" #include "dehacked.h" @@ -294,12 +296,22 @@ UINT16 W_LoadWadFile(const char *filename) UINT32 numlumps; size_t i; INT32 compressed = 0; - size_t packetsize = 0; - serverinfo_pak *dummycheck = NULL; + size_t packetsize; UINT8 md5sum[16]; + boolean important; - // Shut the compiler up. - (void)dummycheck; + if (!(refreshdirmenu & REFRESHDIR_ADDFILE)) + refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier + + if (refreshdirname) + Z_Free(refreshdirname); + if (dirmenu) + { + refreshdirname = Z_StrDup(filename); + nameonly(refreshdirname); + } + else + refreshdirname = NULL; //CONS_Debug(DBG_SETUP, "Loading %s\n", filename); // @@ -308,6 +320,7 @@ UINT16 W_LoadWadFile(const char *filename) if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); + refreshdirmenu |= REFRESHDIR_MAX; return INT16_MAX; } @@ -317,21 +330,21 @@ UINT16 W_LoadWadFile(const char *filename) // Check if wad files will overflow fileneededbuffer. Only the filename part // is send in the packet; cf. - for (i = 0; i < numwadfiles; i++) + // see PutFileNeeded in d_netfil.c + if ((important = !W_VerifyNMUSlumps(filename))) { - packetsize += nameonlylength(wadfiles[i]->filename); - packetsize += 22; // MD5, etc. - } + packetsize = packetsizetally + nameonlylength(filename) + 22; - packetsize += nameonlylength(filename); - packetsize += 22; + if (packetsize > MAXFILENEEDED*sizeof(UINT8)) + { + CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); + refreshdirmenu |= REFRESHDIR_MAX; + if (handle) + fclose(handle); + return INT16_MAX; + } - if (packetsize > sizeof(dummycheck->fileneeded)) - { - CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); - if (handle) - fclose(handle); - return INT16_MAX; + packetsizetally = packetsize; } // detect dehacked file with the "soc" extension @@ -470,6 +483,7 @@ UINT16 W_LoadWadFile(const char *filename) wadfile->handle = handle; wadfile->numlumps = (UINT16)numlumps; wadfile->lumpinfo = lumpinfo; + wadfile->important = important; fseek(handle, 0, SEEK_END); wadfile->filesize = (unsigned)ftell(handle); @@ -1217,19 +1231,27 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, */ int W_VerifyNMUSlumps(const char *filename) { - // MIDI, MOD/S3M/IT/XM/OGG/MP3/WAV, WAVE SFX - // ENDOOM text and palette lumps lumpchecklist_t NMUSlist[] = { - {"D_", 2}, - {"O_", 2}, - {"DS", 2}, - {"ENDOOM", 6}, - {"PLAYPAL", 7}, - {"COLORMAP", 8}, - {"PAL", 3}, - {"CLM", 3}, - {"TRANS", 5}, + {"D_", 2}, // MIDI music + {"O_", 2}, // Digital music + {"DS", 2}, // Sound effects + + {"ENDOOM", 6}, // ENDOOM text lump + {"PLAYPAL", 7}, // Palette + {"COLORMAP", 8}, // Colormap + {"PAL", 3}, // Palette changes + {"CLM", 3}, // Colormap changes + {"TRANS", 5}, // Translucency map + + {"LTFNT", 5}, // Level title font changes + {"STCFN", 5}, // Console font changes + {"TNYFN", 5}, // Tiny console font changes + {"MKFNT", 5}, // Kart font changes + + {"M_", 2}, // Menu changes + {"K_", 2}, // Kart graphic changes + {NULL, 0}, }; return W_VerifyFile(filename, NMUSlist, false); diff --git a/src/w_wad.h b/src/w_wad.h index f7ea64a5..8da22804 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -70,6 +70,7 @@ typedef struct wadfile_s FILE *handle; UINT32 filesize; // for network UINT8 md5sum[16]; + boolean important; } wadfile_t; #define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word From 118d9caad1abb32e3710458b1839b8f1033c1a3b Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 28 Aug 2018 16:29:50 -0400 Subject: [PATCH 19/84] New voices - Following Oni's proposal. This means taunts are split into 2 types for offensive items and boost, 2 less hurt sounds, and there's another clip for using invincibility item (or whatever other powerful items we want to apply it to later; maybe size-down?) - Win/lose quotes are played at full volume for the person who said it. - A new sound effect plays when you hit someone with voices disabled. - Reduce amount of RNG being called from the vanilla P_Play[whatever]Sound functions - Added our skin sound constants to the dehacked list. - Unrelated: finish line sfx plays in splitscreen --- src/dehacked.c | 12 +++++++ src/f_finale.c | 4 +-- src/k_kart.c | 90 +++++++++++++++++++++++++------------------------- src/p_spec.c | 2 +- src/p_user.c | 17 ++++------ src/sounds.c | 19 ++++++----- src/sounds.h | 34 +++++++++++-------- 7 files changed, 97 insertions(+), 81 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 28f20332..e4baf095 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8038,6 +8038,18 @@ struct { {"SKSSKID",SKSSKID}, {"SKSGASP",SKSGASP}, {"SKSJUMP",SKSJUMP}, + // SRB2kart + {"SKSKWIN",SKSKWIN}, // Win quote + {"SKSKLOSE",SKSKLOSE}, // Lose quote + {"SKSKPAN1",SKSKPAN1}, // Pain + {"SKSKPAN2",SKSKPAN2}, + {"SKSKATK1",SKSKATK1}, // Offense item taunt + {"SKSKATK2",SKSKATK2}, + {"SKSKBST1",SKSKBST1}, // Boost item taunt + {"SKSKBST2",SKSKBST2}, + {"SKSKSLOW",SKSKSLOW}, // Overtake taunt + {"SKSKHITM",SKSKHITM}, // Hit confirm taunt + {"SKSKPOWR",SKSKPOWR}, // Power item taunt // 3D Floor/Fake Floor/FOF/whatever flags {"FF_EXISTS",FF_EXISTS}, ///< Always set, to check for validity. diff --git a/src/f_finale.c b/src/f_finale.c index ab79fa78..e4854988 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -308,8 +308,8 @@ static void F_IntroDrawScene(void) { // Need to use M_Random otherwise it always uses the same sound INT32 rskin = M_RandomKey(numskins); - UINT8 rtaunt = M_RandomKey(4); - sfxenum_t rsound = skins[rskin].soundsid[SKSPLTNT1+rtaunt]; + UINT8 rtaunt = M_RandomKey(2); + sfxenum_t rsound = skins[rskin].soundsid[SKSKBST1+rtaunt]; S_StartSound(NULL, rsound); } background = W_CachePatchName("KARTKREW", PU_CACHE); diff --git a/src/k_kart.c b/src/k_kart.c index da085225..c4490a9b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1360,32 +1360,36 @@ static void K_RegularVoiceTimers(player_t *player) player->kartstuff[k_tauntvoices] = 4*TICRATE; } -static void K_PlayTauntSound(mobj_t *source) +static void K_PlayAttackTaunt(mobj_t *source) { -#if 1 - sfxenum_t pick = P_RandomKey(4); // Gotta roll the RNG every time this is called for sync reasons + sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]); if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2)) - S_StartSound(source, sfx_taunt1+pick); + S_StartSound(source, sfx_kattk1+pick); if (!tasteful) return; K_TauntVoiceTimers(source->player); -#else - if (source->player && source->player->kartstuff[k_tauntvoices]) // Prevents taunt sounds from playing every time the button is pressed +} + +static void K_PlayBoostTaunt(mobj_t *source) +{ + sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons + boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]); + + if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2)) + S_StartSound(source, sfx_kbost1+pick); + + if (!tasteful) return; - S_StartSound(source, sfx_taunt1+P_RandomKey(4)); - K_TauntVoiceTimers(source->player); -#endif } static void K_PlayOvertakeSound(mobj_t *source) { -#if 1 boolean tasteful = (!source->player || !source->player->kartstuff[k_voices]); if (!G_RaceGametype()) // Only in race @@ -1396,33 +1400,28 @@ static void K_PlayOvertakeSound(mobj_t *source) return; if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2)) - S_StartSound(source, sfx_slow); + S_StartSound(source, sfx_kslow); if (!tasteful) return; K_RegularVoiceTimers(source->player); -#else - if (source->player && source->player->kartstuff[k_voices]) // Prevents taunt sounds from playing every time the button is pressed - return; - - if (!G_RaceGametype()) // Only in race - return; - - // 4 seconds from before race begins, 10 seconds afterwards - if (leveltime < starttime+(10*TICRATE)) - return; - - S_StartSound(source, sfx_slow); - - K_RegularVoiceTimers(source->player); -#endif } static void K_PlayHitEmSound(mobj_t *source) { if (cv_kartvoices.value) - S_StartSound(source, sfx_hitem); + S_StartSound(source, sfx_khitem); + else + S_StartSound(source, sfx_s1c9); // The only lost gameplay functionality with voices disabled + + K_RegularVoiceTimers(source->player); +} + +static void K_PlayPowerGloatSound(mobj_t *source) +{ + if (cv_kartvoices.value) + S_StartSound(source, sfx_kgloat); K_RegularVoiceTimers(source->player); } @@ -2671,8 +2670,6 @@ void K_DoSneaker(player_t *player, boolean doPFlag) if (doPFlag) player->pflags |= PF_ATTACKDOWN; - - K_PlayTauntSound(player->mo); } static void K_DoShrink(player_t *player) @@ -2691,8 +2688,6 @@ static void K_DoShrink(player_t *player) && players[i].kartstuff[k_position] < player->kartstuff[k_position]) P_DamageMobj(players[i].mo, player->mo, player->mo, 64); } - - K_PlayTauntSound(player->mo); } static void K_DoSPB(player_t *victim, player_t *source) @@ -3765,7 +3760,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanheld]) { K_ThrowKartItem(player, false, MT_FAKEITEM, -1, false); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); player->kartstuff[k_eggmanheld] = 0; K_CleanHnextList(player->mo); } @@ -3774,6 +3769,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) && player->kartstuff[k_rocketsneakertimer] > 1) { K_DoSneaker(player, true); + K_PlayBoostTaunt(player->mo); player->kartstuff[k_rocketsneakertimer] -= 5; if (player->kartstuff[k_rocketsneakertimer] < 1) player->kartstuff[k_rocketsneakertimer] = 1; @@ -3790,6 +3786,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) { K_DoSneaker(player, true); + K_PlayBoostTaunt(player->mo); player->kartstuff[k_itemamount]--; } break; @@ -3798,6 +3795,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) && player->kartstuff[k_rocketsneakertimer] == 0) { K_DoSneaker(player, true); + K_PlayBoostTaunt(player->mo); player->kartstuff[k_rocketsneakertimer] = itemtime; player->kartstuff[k_itemamount]--; } @@ -3816,7 +3814,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_RestoreMusic(player); if (!cv_kartinvinsfx.value && !P_IsLocalPlayer(player)) S_StartSound(player->mo, sfx_kinvnc); - K_PlayTauntSound(player->mo); + K_PlayPowerGloatSound(player->mo); player->kartstuff[k_itemamount]--; } break; @@ -3827,7 +3825,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) mobj_t *mo; mobj_t *prev = player->mo; - //K_PlayTauntSound(player->mo); + //K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemheld] = 1; S_StartSound(player->mo, sfx_s254); @@ -3852,7 +3850,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown { K_ThrowKartItem(player, false, MT_BANANA, -1, false); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; K_UpdateHnextList(player); } @@ -3886,7 +3884,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) mobj_t *mo = NULL; mobj_t *prev = player->mo; - //K_PlayTauntSound(player->mo); + //K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemheld] = 1; S_StartSound(player->mo, sfx_s3k3a); @@ -3916,7 +3914,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown { K_ThrowKartItem(player, true, MT_ORBINAUT, 1, false); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; K_UpdateHnextList(player); } @@ -3931,7 +3929,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) mobj_t *mo = NULL; mobj_t *prev = player->mo; - //K_PlayTauntSound(player->mo); + //K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemheld] = 1; S_StartSound(player->mo, sfx_s3k3a); @@ -3963,7 +3961,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_JAWZ, 1, false); else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, false); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; K_UpdateHnextList(player); } @@ -3988,7 +3986,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) { K_ThrowKartItem(player, false, MT_SSMINE, 1, true); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; player->kartstuff[k_itemheld] = 0; K_CleanHnextList(player->mo); @@ -4000,7 +3998,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemamount]--; K_ThrowKartItem(player, true, MT_BALLHOG, 1, false); S_StartSound(player->mo, sfx_mario7); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); } break; case KITEM_SPB: @@ -4038,14 +4036,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemamount]--; - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); } break; case KITEM_GROW: if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage { - K_PlayTauntSound(player->mo); + K_PlayPowerGloatSound(player->mo); player->mo->scalespeed = FRACUNIT/TICRATE; player->mo->destscale = 3*(mapheaderinfo[gamemap-1]->mobj_scale)/2; if (cv_kartdebugshrink.value && !player->bot) @@ -4063,6 +4061,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { K_DoShrink(player); player->kartstuff[k_itemamount]--; + K_PlayPowerGloatSound(player->mo); } break; case KITEM_THUNDERSHIELD: @@ -4076,6 +4075,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { K_DoThunderShield(player); player->kartstuff[k_itemamount]--; + K_PlayAttackTaunt(player->mo); } break; case KITEM_HYUDORO: @@ -4089,7 +4089,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && !player->kartstuff[k_pogospring]) { - K_PlayTauntSound(player->mo); + K_PlayBoostTaunt(player->mo); K_DoPogoSpring(player->mo, 32<kartstuff[k_pogospring] = 1; player->kartstuff[k_itemamount]--; @@ -4099,7 +4099,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { K_ThrowKartItem(player, false, MT_SINK, 1, true); - K_PlayTauntSound(player->mo); + K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; player->kartstuff[k_itemheld] = 0; } diff --git a/src/p_spec.c b/src/p_spec.c index 87894d05..103b31aa 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4231,7 +4231,7 @@ DoneSection2: if (player->laps >= (unsigned)cv_numlaps.value) { - if (!splitscreen && P_IsLocalPlayer(player)) + if (P_IsLocalPlayer(player)) S_StartSound(NULL, sfx_s3k6a); else if (player->kartstuff[k_position] == 1) S_StartSound(NULL, sfx_s253); diff --git a/src/p_user.c b/src/p_user.c index 53faf8f3..f5fd405c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1120,27 +1120,22 @@ void P_PlayLivesJingle(player_t *player) void P_PlayRinglossSound(mobj_t *source) { - sfxenum_t key = P_RandomKey(4); + sfxenum_t key = P_RandomKey(2); if (cv_kartvoices.value) - S_StartSound(source, (mariomode) ? sfx_mario8 : sfx_altow1 + key); + S_StartSound(source, (mariomode) ? sfx_mario8 : sfx_khurt1 + key); else S_StartSound(source, sfx_slip); } void P_PlayDeathSound(mobj_t *source) { - sfxenum_t key = P_RandomKey(4); - if (cv_kartvoices.value) - S_StartSound(source, sfx_altdi1 + key); - else - S_StartSound(source, sfx_s3k35); + S_StartSound(source, sfx_s3k35); } void P_PlayVictorySound(mobj_t *source) { - sfxenum_t key = P_RandomKey(4); if (cv_kartvoices.value) - S_StartSound(source, sfx_victr1 + key); + S_StartSound(source, sfx_kwin); } // @@ -1736,9 +1731,9 @@ void P_DoPlayerExit(player_t *player) if (cv_kartvoices.value) { if (K_IsPlayerLosing(player)) - S_StartSound(player->mo, sfx_klose); + S_StartSound((P_IsLocalPlayer(player) ? player->mo : NULL), sfx_klose); else - S_StartSound(player->mo, sfx_kwin); + S_StartSound((P_IsLocalPlayer(player) ? player->mo : NULL), sfx_kwin); } player->exiting = 3*TICRATE; diff --git a/src/sounds.c b/src/sounds.c index 991941e0..3a739a94 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -814,14 +814,17 @@ sfxinfo_t S_sfx[NUMSFX] = {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds - {"kwin", false, 64, 0, -1, NULL, 0, SKSWIN, -1, LUMPERROR}, - {"klose", false, 64, 0, -1, NULL, 0, SKSLOSE, -1, LUMPERROR}, - {"slow", false, 128, 32, -1, NULL, 0, SKSSLOW, -1, LUMPERROR}, - {"taunt1", false, 64, 96, -1, NULL, 0, SKSPLTNT1, -1, LUMPERROR}, - {"taunt2", false, 64, 96, -1, NULL, 0, SKSPLTNT2, -1, LUMPERROR}, - {"taunt3", false, 64, 96, -1, NULL, 0, SKSPLTNT3, -1, LUMPERROR}, - {"taunt4", false, 64, 96, -1, NULL, 0, SKSPLTNT4, -1, LUMPERROR}, - {"hitem", false, 64, 32, -1, NULL, 0, SKSHITEM, -1, LUMPERROR}, + {"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR}, + {"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR}, + {"khurt1", false, 64, 96, -1, NULL, 0, SKSKPAN1, -1, LUMPERROR}, + {"khurt2", false, 64, 96, -1, NULL, 0, SKSKPAN2, -1, LUMPERROR}, + {"kattk1", false, 64, 96, -1, NULL, 0, SKSKATK1, -1, LUMPERROR}, + {"kattk2", false, 64, 96, -1, NULL, 0, SKSKATK2, -1, LUMPERROR}, + {"kbost1", false, 64, 96, -1, NULL, 0, SKSKBST1, -1, LUMPERROR}, + {"kbost2", false, 64, 96, -1, NULL, 0, SKSKBST2, -1, LUMPERROR}, + {"kslow", false, 128, 32, -1, NULL, 0, SKSKSLOW, -1, LUMPERROR}, + {"khitem", false, 64, 32, -1, NULL, 0, SKSKHITM, -1, LUMPERROR}, + {"kgloat", false, 64, 40, -1, NULL, 0, SKSKPOWR, -1, LUMPERROR}, // skin sounds free slots to add sounds at run time (Boris HACK!!!) // initialized to NULL diff --git a/src/sounds.h b/src/sounds.h index 2f073273..b9daad4e 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -39,14 +39,17 @@ typedef enum SKSGASP, SKSJUMP, // SRB2kart - SKSWIN, - SKSLOSE, - SKSSLOW, - SKSPLTNT1, - SKSPLTNT2, - SKSPLTNT3, - SKSPLTNT4, - SKSHITEM, + SKSKWIN, // Win quote + SKSKLOSE, // Lose quote + SKSKPAN1, // Pain + SKSKPAN2, + SKSKATK1, // Offense item taunt + SKSKATK2, + SKSKBST1, // Boost item taunt + SKSKBST2, + SKSKSLOW, // Overtake taunt + SKSKHITM, // Hit confirm taunt + SKSKPOWR, // Power item taunt NUMSKINSOUNDS } skinsound_t; @@ -887,12 +890,15 @@ typedef enum sfx_kwin, sfx_klose, - sfx_slow, - sfx_taunt1, - sfx_taunt2, - sfx_taunt3, - sfx_taunt4, - sfx_hitem, + sfx_kslow, + sfx_kattk1, + sfx_kattk2, + sfx_kbost1, + sfx_kbost2, + sfx_khurt1, + sfx_khurt2, + sfx_kgloat, + sfx_khitem, // free slots for S_AddSoundFx() at run-time -------------------- sfx_freeslot0, From 2564d2f017059352bd0a3ff2a8ee706a883701e6 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 28 Aug 2018 18:50:59 -0400 Subject: [PATCH 20/84] Wrong order here --- src/sounds.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sounds.h b/src/sounds.h index b9daad4e..b879e8e3 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -890,15 +890,15 @@ typedef enum sfx_kwin, sfx_klose, - sfx_kslow, + sfx_khurt1, + sfx_khurt2, sfx_kattk1, sfx_kattk2, sfx_kbost1, sfx_kbost2, - sfx_khurt1, - sfx_khurt2, - sfx_kgloat, + sfx_kslow, sfx_khitem, + sfx_kgloat, // free slots for S_AddSoundFx() at run-time -------------------- sfx_freeslot0, From a745417a3f87f4cbf1725850b6f01a753082c067 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 28 Aug 2018 22:50:53 -0400 Subject: [PATCH 21/84] This doesn't work 1.) I mixed it up, so opponent win/lose quotes would play globally instead of your own 2.) You can't even play skin-specific sounds globally, so it'd always be Sonic --- src/p_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index f5fd405c..d2395aab 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1731,9 +1731,9 @@ void P_DoPlayerExit(player_t *player) if (cv_kartvoices.value) { if (K_IsPlayerLosing(player)) - S_StartSound((P_IsLocalPlayer(player) ? player->mo : NULL), sfx_klose); + S_StartSound(player->mo, sfx_klose); else - S_StartSound((P_IsLocalPlayer(player) ? player->mo : NULL), sfx_kwin); + S_StartSound(player->mo, sfx_kwin); } player->exiting = 3*TICRATE; From 0776460643463490c475eb22f26bc0efb89ff3f6 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 29 Aug 2018 12:50:25 +0100 Subject: [PATCH 22/84] * Make some minor performance improvements. * Make the I_Errors in filesrch.c more descriptive. * Fix up the loading of sounds.kart such that it has SOME protection against being loaded with game-modifying lumps. * SERIOUSLY fix up the MD5/mainwads++ section in D_SRB2Main, since 1) I broke it and 2) it was already a little broken in the first place but we just didn't notice it because #ifndef DEVELOP. --- src/d_main.c | 68 +++++++++++++++++++++----------------------------- src/filesrch.c | 16 ++++++------ src/v_video.c | 7 ++++++ 3 files changed, 43 insertions(+), 48 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 65a2bc5a..f2063861 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -957,43 +957,29 @@ static void IdentifyVersion(void) D_AddFile(va(pandf,srb2waddir,"patch.dta")); #endif +#define MUSICTEST(str) \ + {\ + const char *musicpath = va(pandf,srb2waddir,str);\ + int ms = W_VerifyNMUSlumps(musicpath); \ + if (ms == 1) \ + D_AddFile(musicpath); \ + else if (ms == 0) \ + I_Error("File "str" has been modified with non-music/sound lumps"); \ + } + // SRB2kart - Add graphics (temp) // The command for md5 checks is "W_VerifyFileMD5" - looks for ASSET_HASH_SRB2_SRB in config.h.in D_AddFile(va(pandf,srb2waddir,"gfx.kart")); D_AddFile(va(pandf,srb2waddir,"chars.kart")); D_AddFile(va(pandf,srb2waddir,"maps.kart")); - D_AddFile(va(pandf,srb2waddir,"sounds.kart")); + //D_AddFile(va(pandf,srb2waddir,"sounds.kart")); + MUSICTEST("sounds.kart") #ifdef USE_PATCH_KART D_AddFile(va(pandf,srb2waddir,"patch.kart")); #endif -#if !defined (HAVE_SDL) || defined (HAVE_MIXER) - { -#if defined (DC) && 0 - const char *musicfile = "music_dc.dta"; -#else - const char *musicfile = "music.dta"; -#endif - const char *kmusicfile; - const char *musicpath = va(pandf,srb2waddir,musicfile); - const char *kmusicpath; - int ms = W_VerifyNMUSlumps(musicpath); // Don't forget the music! - int kms; - if (ms == 1) - D_AddFile(musicpath); - else if (ms == 0) - I_Error("File %s has been modified with non-music lumps",musicfile); - - kmusicfile = "music.kart"; - kmusicpath = va(pandf,srb2waddir,kmusicfile); - kms = W_VerifyNMUSlumps(kmusicpath); // kill me now - - if (kms == 1) - D_AddFile(kmusicpath); - else if (kms == 0) - I_Error("File %s has been modified with non-music lumps",kmusicfile); - } -#endif + MUSICTEST("music.dta") + MUSICTEST("music.kart") } /* ======================================================================== */ @@ -1253,27 +1239,27 @@ void D_SRB2Main(void) #endif D_CleanFile(); + mainwads = 0; + #ifndef DEVELOP // md5s last updated 12/14/14 // Check MD5s of autoloaded files W_VerifyFileMD5(mainwads, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad #ifdef USE_PATCH_DTA - W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); // patch.dta + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); // patch.dta #endif - W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); // gfx.kart - W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); // chars.kart - W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); // maps.kart - /*W_VerifyFileMD5(mainwads, ASSET_HASH_SOUNDS_KART);*/ // sounds.kart - doesn't trigger modifiedgame, doesn't need an MD5...? + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); // gfx.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); // chars.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); // maps.kart + mainwads++; //W_VerifyFileMD5(5, ASSET_HASH_SOUNDS_KART); -- sounds.kart - doesn't trigger modifiedgame, doesn't need an MD5...? #ifdef USE_PATCH_KART - W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); // patch.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); // patch.kart #endif - - // don't check music.dta because people like to modify it, and it doesn't matter if they do + mainwads++; // music.dta + mainwads++; // music.kart + // don't check music.dta or kart because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. -#endif //ifndef DEVELOP - - mainwads = 0; - mainwads++; // srb2.srb/srb2.wad +#else #ifdef USE_PATCH_DTA mainwads++; // patch.dta #endif @@ -1284,7 +1270,9 @@ void D_SRB2Main(void) #ifdef USE_PATCH_KART mainwads++; // patch.kart #endif + mainwads++; // music.dta mainwads++; // music.kart +#endif //ifndef DEVELOP mainwadstally = packetsizetally; diff --git a/src/filesrch.c b/src/filesrch.c index 59868653..94c1190b 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -563,9 +563,9 @@ static boolean filemenucmp(char *haystack, char *needle) strlcpy(localhaystack, haystack, 128); if (!cv_addons_search_case.value) strupr(localhaystack); - return ((cv_addons_search_type.value) - ? (strstr(localhaystack, needle) != 0) - : (!strncmp(localhaystack, needle, menusearch[0]))); + if (cv_addons_search_type.value) + return (strstr(localhaystack, needle) != 0); + return (!strncmp(localhaystack, needle, menusearch[0])); } void closefilemenu(boolean validsize) @@ -673,7 +673,7 @@ void searchfilemenu(char *tempname) { if ((!(dirmenu = Z_Realloc(dirmenu, sizeof(char *), PU_STATIC, NULL))) || !(dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS)))) - I_Error("Ran out of memory whilst preparing add-ons menu"); + I_Error("searchfilemenu(): could not create \"No results...\"."); sizedirmenu = 1; dir_on[menudepthleft] = 0; if (tempname) @@ -682,7 +682,7 @@ void searchfilemenu(char *tempname) } if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL))) - I_Error("Ran out of memory whilst preparing add-ons menu"); + I_Error("searchfilemenu(): could not reallocate dirmenu."); sizedirmenu = 0; for (i = first; i < sizecoredirmenu; i++) @@ -793,7 +793,7 @@ boolean preparefilemenu(boolean samedepth) if (!(coredirmenu = Z_Realloc(coredirmenu, sizecoredirmenu*sizeof(char *), PU_STATIC, NULL))) { closedir(dirhandle); // just in case - I_Error("Ran out of memory whilst preparing add-ons menu"); + I_Error("preparefilemenu(): could not reallocate coredirmenu."); } rewinddir(dirhandle); @@ -868,7 +868,7 @@ boolean preparefilemenu(boolean samedepth) len = 255; if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL))) - I_Error("Ran out of memory whilst preparing add-ons menu"); + I_Error("preparefilemenu(): could not create file entry."); temp[DIR_TYPE] = ext; temp[DIR_LEN] = (UINT8)(len); strlcpy(temp+DIR_STRING, dent->d_name, len); @@ -886,7 +886,7 @@ boolean preparefilemenu(boolean samedepth) if ((menudepthleft != menudepth-1) // now for UP... entry && !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP)))) - I_Error("Ran out of memory whilst preparing add-ons menu"); + I_Error("searchfilemenu(): could not create \"UP...\"."); menupath[menupathindex[menudepthleft]] = 0; sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind diff --git a/src/v_video.c b/src/v_video.c index e39663a7..8c8bd342 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1250,6 +1250,7 @@ void V_DrawFadeConsBack(INT32 plines) // const UINT8 *V_GetStringColormap(INT32 colorflags) { +#if 0 // perfect switch ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT) { case 1: // 0x81, purple @@ -1271,6 +1272,12 @@ const UINT8 *V_GetStringColormap(INT32 colorflags) default: // reset return NULL; } +#else // optimised + colorflags = ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT); + if (!colorflags || colorflags > 8) // INT32 is signed, but V_CHARCOLORMASK is a very restrictive mask. + return NULL; + return (purplemap+((colorflags-1)<<8)); +#endif } // Writes a single character (draw WHITE if bit 7 set) From 7a758708c63ac9df92d07fcb7879eca431228fd3 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 29 Aug 2018 14:19:08 +0100 Subject: [PATCH 23/84] * Add support for .kart files. * Wrap behind-the-scenes `addfile/exec` contents in quotation marks to allow for files with spaces in them. --- src/filesrch.c | 10 +++++----- src/filesrch.h | 1 + src/m_menu.c | 6 ++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/filesrch.c b/src/filesrch.c index 94c1190b..e1e2b39d 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -550,9 +550,9 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want return retval; } -char exttable[NUM_EXT_TABLE][5] = { - ".txt", ".cfg", // exec - ".wad", /*".pk3",*/ ".soc", ".lua"}; // addfile +char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two) + "\5.txt", "\5.cfg", // exec + "\5.wad", "\6.kart", /*"\5.pk3",*/ "\5.soc", "\5.lua"}; // addfile char filenamebuf[MAX_WADFILES][MAX_WADPATH]; @@ -760,7 +760,7 @@ boolean preparefilemenu(boolean samedepth) size_t len = strlen(dent->d_name)+1; UINT8 ext; for (ext = 0; ext < NUM_EXT_TABLE; ext++) - if (!strcasecmp(exttable[ext], dent->d_name+len-5)) break; // extension comparison + if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file } } @@ -826,7 +826,7 @@ boolean preparefilemenu(boolean samedepth) { if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention for (; ext < NUM_EXT_TABLE; ext++) - if (!strcasecmp(exttable[ext], dent->d_name+len-5)) break; // extension comparison + if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file ext += EXT_START; // moving to be appropriate position diff --git a/src/filesrch.h b/src/filesrch.h index 51615308..75fd70af 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -55,6 +55,7 @@ typedef enum EXT_CFG, EXT_LOADSTART, EXT_WAD = EXT_LOADSTART, + EXT_KART, //EXT_PK3, EXT_SOC, EXT_LUA, // allowed even if not HAVE_BLUA so that we can yell on load attempt diff --git a/src/m_menu.c b/src/m_menu.c index 5ba5d81b..dcfe4fb8 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4341,6 +4341,7 @@ static void M_Addons(INT32 choice) addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC); addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC); addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC); + addonsp[EXT_KART] = W_CachePatchName("M_FKART", PU_STATIC); //addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC); addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC); addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC); @@ -4610,7 +4611,7 @@ static void M_AddonExec(INT32 ch) return; S_StartSound(NULL, sfx_zoom); - COM_BufAddText(va("exec %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + COM_BufAddText(va("exec \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); } #define len menusearch[0] @@ -4762,8 +4763,9 @@ static void M_HandleAddons(INT32 choice) // else intentional fallthrough case EXT_SOC: case EXT_WAD: + case EXT_KART: //case EXT_PK3: - COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); break; default: S_StartSound(NULL, sfx_lose); From 22be81ef021531a79cbf5e380c1f6dba050a3df8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 29 Aug 2018 21:37:47 +0100 Subject: [PATCH 24/84] * Prettier record attack screen! * Uses the in-game timer element to draw its times. * This includes showing them time emblems-to-get! * good night sweet prince * Make the emblem time use the same ' and " as the normal time. --- src/k_kart.c | 97 ++++++++++++++++++++++++++++++---------------------- src/k_kart.h | 1 + src/m_menu.c | 21 ++++++++++-- 3 files changed, 77 insertions(+), 42 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 615b8970..b4c1e6ca 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5160,78 +5160,90 @@ static void K_drawKartItem(void) V_DrawScaledPatch(ITEM_X+17, ITEM_Y+13, V_HUDTRANS|splitflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]); } -static void K_drawKartTimestamp(void) +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, boolean playing) { // TIME_X = BASEVIDWIDTH-124; // 196 // TIME_Y = 6; // 6 - INT32 TIME_XB, splitflags = V_HUDTRANS|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTORIGHT); - tic_t drawtime = stplyr->realtime; + tic_t worktime; - if (cv_timelimit.value && timelimitintics > 0) + INT32 splitflags = 0; + if (playing) { - if (drawtime >= timelimitintics) - drawtime = 0; - else - drawtime = timelimitintics - drawtime; + splitflags = V_HUDTRANS|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTORIGHT); + if (cv_timelimit.value && timelimitintics > 0) + { + if (drawtime >= timelimitintics) + drawtime = 0; + else + drawtime = timelimitintics - drawtime; + } } - V_DrawScaledPatch(TIME_X, TIME_Y, splitflags, kp_timestickerwide); + V_DrawScaledPatch(TX, TY, splitflags, kp_timestickerwide); - TIME_XB = TIME_X+33; + TX += 33; - if (drawtime/(60*TICRATE) < 100) // 99:99:99 only + worktime = drawtime/(60*TICRATE); + + if (!playing && !drawtime) + V_DrawKartString(TX, TY+3, splitflags, va("--'--\"--")); + else if (worktime < 100) // 99:99:99 only { // zero minute - if (drawtime/(60*TICRATE) < 10) + if (worktime < 10) { - V_DrawKartString(TIME_XB, TIME_Y+3, splitflags, va("0")); + V_DrawKartString(TX, TY+3, splitflags, va("0")); // minutes time 0 __ __ - V_DrawKartString(TIME_XB+12, TIME_Y+3, splitflags, va("%d", drawtime/(60*TICRATE))); + V_DrawKartString(TX+12, TY+3, splitflags, va("%d", worktime)); } // minutes time 0 __ __ else - V_DrawKartString(TIME_XB, TIME_Y+3, splitflags, va("%d", drawtime/(60*TICRATE))); + V_DrawKartString(TX, TY+3, splitflags, va("%d", worktime)); // apostrophe location _'__ __ - V_DrawKartString(TIME_XB+24, TIME_Y+3, splitflags, va("'")); + V_DrawKartString(TX+24, TY+3, splitflags, va("'")); + + worktime = (drawtime/TICRATE % 60); // zero second _ 0_ __ - if ((drawtime/TICRATE % 60) < 10) + if (worktime < 10) { - V_DrawKartString(TIME_XB+36, TIME_Y+3, splitflags, va("0")); + V_DrawKartString(TX+36, TY+3, splitflags, va("0")); // seconds time _ _0 __ - V_DrawKartString(TIME_XB+48, TIME_Y+3, splitflags, va("%d", drawtime/TICRATE % 60)); + V_DrawKartString(TX+48, TY+3, splitflags, va("%d", worktime)); } // zero second _ 00 __ else - V_DrawKartString(TIME_XB+36, TIME_Y+3, splitflags, va("%d", drawtime/TICRATE % 60)); + V_DrawKartString(TX+36, TY+3, splitflags, va("%d", worktime)); // quotation mark location _ __"__ - V_DrawKartString(TIME_XB+60, TIME_Y+3, splitflags, va("\"")); + V_DrawKartString(TX+60, TY+3, splitflags, va("\"")); + + worktime = G_TicsToCentiseconds(drawtime); // zero tick _ __ 0_ - if (G_TicsToCentiseconds(drawtime) < 10) + if (worktime < 10) { - V_DrawKartString(TIME_XB+72, TIME_Y+3, splitflags, va("0")); + V_DrawKartString(TX+72, TY+3, splitflags, va("0")); // tics _ __ _0 - V_DrawKartString(TIME_XB+84, TIME_Y+3, splitflags, va("%d", G_TicsToCentiseconds(drawtime))); + V_DrawKartString(TX+84, TY+3, splitflags, va("%d", worktime)); } // zero tick _ __ 00 - if (G_TicsToCentiseconds(drawtime) >= 10) - V_DrawKartString(TIME_XB+72, TIME_Y+3, splitflags, va("%d", G_TicsToCentiseconds(drawtime))); + else + V_DrawKartString(TX+72, TY+3, splitflags, va("%d", worktime)); } else if ((drawtime/TICRATE) & 1) - V_DrawKartString(TIME_XB, TIME_Y+3, splitflags, va("99'59\"99")); + V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99")); - if (modeattacking) // emblem time! + if (emblemmap && (modeattacking || !playing)) // emblem time! { - INT32 workx = TIME_XB + 96, worky = TIME_Y+18; + INT32 workx = TX + 96, worky = TY+18; SINT8 curemb = 0; patch_t *emblempic[3] = {NULL, NULL, NULL}; UINT8 *emblemcol[3] = {NULL, NULL, NULL}; - emblem_t *emblem = M_GetLevelEmblems(gamemap); + emblem_t *emblem = M_GetLevelEmblems(emblemmap); while (emblem) { char targettext[9]; @@ -5252,22 +5264,25 @@ static void K_drawKartTimestamp(void) goto bademblem; } - snprintf(targettext, 9, "%i:%02i.%02i", + snprintf(targettext, 9, "%i'%02i\"%02i", G_TicsToMinutes(timetoreach, false), G_TicsToSeconds(timetoreach), G_TicsToCentiseconds(timetoreach)); - if (stplyr->realtime > timetoreach) + if (playing) { - splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; - if (canplaysound) + if (stplyr->realtime > timetoreach) { - S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks - canplaysound = false; + splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; + if (canplaysound) + { + S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks + canplaysound = false; + } } + else if (!canplaysound) + canplaysound = true; } - else if (!canplaysound) - canplaysound = true; targettext[8] = 0; } @@ -5277,7 +5292,7 @@ static void K_drawKartTimestamp(void) } V_DrawRightAlignedString(workx, worky, splitflags, targettext); - workx -= 69; // i SWEAR i wasn't aiming for this + workx -= 72; //69; -- good night sweet prince V_DrawSmallScaledPatch(workx + 4, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE)); break; @@ -5286,6 +5301,8 @@ static void K_drawKartTimestamp(void) emblem = M_GetLevelEmblems(-1); } + if (playing) + splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS; while (curemb--) { workx -= 16; @@ -6469,7 +6486,7 @@ void K_drawKartHUD(void) if (!splitscreen) { // Draw the timestamp - K_drawKartTimestamp(); + K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, true); if (!modeattacking) { diff --git a/src/k_kart.h b/src/k_kart.h index 89f1ea7e..7c7d66fc 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -61,6 +61,7 @@ void K_LoadKartHUDGraphics(void); fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my); void K_drawKartHUD(void); void K_drawKartFreePlay(UINT32 flashtime); +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, boolean playing); void K_LoadIconGraphics(char *facestr, INT32 skinnum); void K_ReloadSkinIconGraphics(void); diff --git a/src/m_menu.c b/src/m_menu.c index 82e6ac2f..3bdcc964 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5705,7 +5705,6 @@ void M_DrawTimeAttackMenu(void) INT32 i, x, y, cursory = 0; UINT16 dispstatus; patch_t *PictureOfUrFace; - char beststr[40]; //S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback @@ -5786,6 +5785,24 @@ void M_DrawTimeAttackMenu(void) // Level record list if (cv_nextmap.value) { + INT32 dupadjust = (vid.width/vid.dupx); + tic_t lap = 0, time = 0; + if (mainrecords[cv_nextmap.value-1]) + { + lap = mainrecords[cv_nextmap.value-1]->lap; + time = mainrecords[cv_nextmap.value-1]->time; + } + + V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 239); + + V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:"); + K_drawKartTimestamp(lap, 19, 86, 0, false); + + V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:"); + K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, false); + } + /*{ + char beststr[40]; emblem_t *em; if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time) @@ -5828,7 +5845,7 @@ void M_DrawTimeAttackMenu(void) skipThisOne: em = M_GetLevelEmblems(-1); } - } + }*/ // ALWAYS DRAW player name, level name, skin and color even when not on this menu! if (currentMenu != &SP_TimeAttackDef) From 7c7a7bf849594fff67e8fce36ff25174a4a9f140 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 29 Aug 2018 22:02:42 +0100 Subject: [PATCH 25/84] disable encore ruby/flip on record attack menu with kartencore on --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 3bdcc964..8e83f3a6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6808,7 +6808,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) V_DrawFill(x-1, y-1, w+2, i+2, trans); // variable reuse... - if (!cv_kartencore.value || cv_newgametype.value != GT_RACE) + if (!cv_kartencore.value || gamestate == GS_TIMEATTACK || cv_newgametype.value != GT_RACE) V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); else { From bd7e0e75f036860ea63166105a9159680ebe9f56 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 30 Aug 2018 13:13:25 +0100 Subject: [PATCH 26/84] Overlays and rings now properly handle encore-ness, in that they are sans encore (most of the time). ... :V --- src/info.c | 4 ++-- src/p_mobj.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/info.c b/src/info.c index 464c4166..0e6d5abd 100644 --- a/src/info.c +++ b/src/info.c @@ -5054,7 +5054,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -13141,7 +13141,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 8, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/p_mobj.c b/src/p_mobj.c index 102f99d4..129ea333 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6212,6 +6212,9 @@ void P_RunOverlays(void) mo->scale = mo->destscale = mo->target->scale; mo->angle = mo->target->angle; + if ((mo->flags & MF_DONTENCOREMAP) != (mo->target->flags & MF_DONTENCOREMAP)) + mo->flags ^= MF_DONTENCOREMAP; + if (!(mo->state->frame & FF_ANIMATE)) zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale); // if you're using FF_ANIMATE on an overlay, From c323b821d6112a5b9bc3451df0de0f4da1c93514 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 31 Aug 2018 13:30:40 +0200 Subject: [PATCH 27/84] Coloured names for chat --- src/hu_stuff.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 36b2812e..b82ffe26 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -757,8 +757,37 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) } else if (target == 0) // To everyone { - fmt = "\3%s\x83<%s%s%s\x83>\x80 %s\n"; - fmt2 = "%s\x83<%s%s%s\x83>\x80 %s"; + + + /* 31/8/18: Lat': Exclusive to kart, use a CLOSE ENOUGH colour to the player's for text (we're quite limited with our options, + drawstring really should be able to remap to any palette index........*/ + + // there's a lot of fucking colors wtf + INT32 color = players[playernum].mo->color; + if (color >= SKINCOLOR_IVORY && color <= SKINCOLOR_SILVER) + prefix = "\x80"; + else if ((color >= SKINCOLOR_CLOUDY && color <= SKINCOLOR_BLACK) || color == SKINCOLOR_JET) // jet is more black than blue so it goes here. + prefix = "\x86"; + else if (color >= SKINCOLOR_SALMON && color <= SKINCOLOR_CRIMSON) + prefix = "\x85"; + else if (color >= SKINCOLOR_DAWN && color <= SKINCOLOR_CARAMEL) + prefix = "\x87"; + else if (color >= SKINCOLOR_TANGERINE && color <= SKINCOLOR_CANARY) + prefix = "\x82"; + else if (color >= SKINCOLOR_OLIVE && color <= SKINCOLOR_SWAMP) + prefix = "\x83"; + else if ((color >= SKINCOLOR_AQUA && color <= SKINCOLOR_STEEL) || color == SKINCOLOR_SAPPHIRE) // toaster wanted that specific one too shrug + prefix = "\x88"; + else if (color >= SKINCOLOR_PERIWINKLE && color <= SKINCOLOR_NAVY) + prefix = "\x84"; + else if (color >= SKINCOLOR_DUSK && color <= SKINCOLOR_LILAC) + prefix = "\x81"; + else + prefix = "\x83"; + + strcat(cstart, prefix); + fmt = "\3%s<%s%s%s>\x80 %s\n"; + fmt2 = "%s<%s%s%s>\x80 %s"; } else if (target-1 == consoleplayer) // To you { @@ -793,6 +822,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) } + HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, msg)); // add it reguardless, in case we decide to change our mind about our chat type. if OLDCHAT From a7bb16ada9dc2ec4832f3d3434739c3c6f2a7f93 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 31 Aug 2018 12:37:15 +0100 Subject: [PATCH 28/84] Improve intermission drawer further. * Change `MM:SS.MS` to `MM'SS"MS' to match all other recorded instances of time in-game. * Add a full stop to NO CONTEST to scrounge up an extra four pixels to match the increased width of above. * Make it such that the number of players per column will never be desynced with future code changes by tying it to a local #define. * Other minor code improvements. --- src/y_inter.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 636b2d23..77cea21f 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -413,7 +413,8 @@ void Y_IntermissionDrawer(void) } else*/ if (intertype == int_race || intertype == int_match) { - INT32 y = 48; +#define NUMFORNEWCOLUMN 8 + INT32 y = 48, gutter = ((data.match.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2)); const char *timeheader; if (data.match.rankingsmode) @@ -428,7 +429,7 @@ void Y_IntermissionDrawer(void) if (data.match.encore) V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 20-8, hilicol, "ENCORE MODE"); - if (data.match.numplayers > 8) + if (!gutter) { V_DrawFill(x+156, 32, 1, 152, 0); @@ -465,7 +466,7 @@ void Y_IntermissionDrawer(void) V_DrawSmallMappedPatch(x+16, y-4, 0,faceprefix[*data.match.character[i]], colormap); } - if (data.match.numplayers > 8) + if (!gutter) strlcpy(strtime, data.match.name[i], 6); else STRBUFCPY(strtime, data.match.name[i]); @@ -485,48 +486,29 @@ void Y_IntermissionDrawer(void) else snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[data.match.num[i]]); - if (data.match.numplayers > 8) - V_DrawRightAlignedString(x+120, y, 0, strtime); - else - V_DrawRightAlignedString(x+120+BASEVIDWIDTH/2, y, 0, strtime); + V_DrawRightAlignedString(x+120+gutter, y, 0, strtime); } snprintf(strtime, sizeof strtime, "%d", data.match.val[i]); - if (data.match.numplayers > 8) - V_DrawRightAlignedString(x+152, y, 0, strtime); - else - V_DrawRightAlignedString(x+152+BASEVIDWIDTH/2, y, 0, strtime); + V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); } else { if (data.match.val[i] == (UINT32_MAX-1)) - { - if (data.match.numplayers > 8) - V_DrawRightAlignedThinString(x+152, y-1, 0, "NO CONTEST"); - else - V_DrawRightAlignedThinString(x+152+BASEVIDWIDTH/2, y-1, 0, "NO CONTEST"); - } + V_DrawRightAlignedThinString(x+152+gutter, y-1, 0, "NO CONTEST."); else { if (intertype == int_race) { - snprintf(strtime, sizeof strtime, "%i:%02i.%02i", G_TicsToMinutes(data.match.val[i], true), + snprintf(strtime, sizeof strtime, "%i'%02i\"%02i", G_TicsToMinutes(data.match.val[i], true), G_TicsToSeconds(data.match.val[i]), G_TicsToCentiseconds(data.match.val[i])); strtime[sizeof strtime - 1] = '\0'; - if (data.match.numplayers > 8) - V_DrawRightAlignedString(x+152, y, 0, strtime); - else - V_DrawRightAlignedString(x+152+BASEVIDWIDTH/2, y, 0, strtime); + V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); } else - { - if (data.match.numplayers > 8) - V_DrawRightAlignedString(x+152, y, 0, va("%i", data.match.val[i])); - else - V_DrawRightAlignedString(x+152+BASEVIDWIDTH/2, y, 0, va("%i", data.match.val[i])); - } + V_DrawRightAlignedString(x+152+gutter, y, 0, va("%i", data.match.val[i])); } } @@ -538,11 +520,12 @@ void Y_IntermissionDrawer(void) y += 16; - if (i == 7) + if (i == NUMFORNEWCOLUMN-1) { y = 48; x += BASEVIDWIDTH/2; } +#undef NUMFORNEWCOLUMN } } From c9303cb180977d43850cda5757bc4d79327c3aa7 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 31 Aug 2018 13:52:53 +0200 Subject: [PATCH 29/84] Cleaned up a little, courtesy of toaster --- src/hu_stuff.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index b82ffe26..4eeaa79c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -763,28 +763,26 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) drawstring really should be able to remap to any palette index........*/ // there's a lot of fucking colors wtf - INT32 color = players[playernum].mo->color; - if (color >= SKINCOLOR_IVORY && color <= SKINCOLOR_SILVER) - prefix = "\x80"; - else if ((color >= SKINCOLOR_CLOUDY && color <= SKINCOLOR_BLACK) || color == SKINCOLOR_JET) // jet is more black than blue so it goes here. - prefix = "\x86"; - else if (color >= SKINCOLOR_SALMON && color <= SKINCOLOR_CRIMSON) - prefix = "\x85"; - else if (color >= SKINCOLOR_DAWN && color <= SKINCOLOR_CARAMEL) - prefix = "\x87"; - else if (color >= SKINCOLOR_TANGERINE && color <= SKINCOLOR_CANARY) - prefix = "\x82"; - else if (color >= SKINCOLOR_OLIVE && color <= SKINCOLOR_SWAMP) - prefix = "\x83"; - else if ((color >= SKINCOLOR_AQUA && color <= SKINCOLOR_STEEL) || color == SKINCOLOR_SAPPHIRE) // toaster wanted that specific one too shrug - prefix = "\x88"; - else if (color >= SKINCOLOR_PERIWINKLE && color <= SKINCOLOR_NAVY) - prefix = "\x84"; - else if (color >= SKINCOLOR_DUSK && color <= SKINCOLOR_LILAC) - prefix = "\x81"; - else - prefix = "\x83"; - + const UINT8 color = players[playernum].skincolor; + if (color <= SKINCOLOR_SILVER) + prefix = "\x80"; + else if (color <= SKINCOLOR_BLACK || color == SKINCOLOR_JET) // jet is more black than blue so it goes here. + prefix = "\x86"; + else if (color <= SKINCOLOR_CRIMSON) + prefix = "\x85"; + else if (color <= SKINCOLOR_CARAMEL) + prefix = "\x87"; + else if (color <= SKINCOLOR_CANARY) + prefix = "\x82"; + else if (color <= SKINCOLOR_SWAMP) + prefix = "\x83"; + else if (color <= SKINCOLOR_STEEL || color == SKINCOLOR_SAPPHIRE) // toaster wanted that specific one too shrug + prefix = "\x88"; + else if (color <= SKINCOLOR_NAVY) + prefix = "\x84"; + else + prefix = "\x81"; + strcat(cstart, prefix); fmt = "\3%s<%s%s%s>\x80 %s\n"; fmt2 = "%s<%s%s%s>\x80 %s"; From 8bb8eef99793c1082b72f8640edb5818208befd5 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 31 Aug 2018 13:56:11 +0200 Subject: [PATCH 30/84] Removed that one empty space thing --- src/hu_stuff.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 4eeaa79c..e6650593 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -820,7 +820,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) } - HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, msg)); // add it reguardless, in case we decide to change our mind about our chat type. if OLDCHAT From ccc6f719808ebc8c48fe2c6b1c2fbc1ed291ccc7 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 31 Aug 2018 15:02:48 +0200 Subject: [PATCH 31/84] Cleanup + coloured text for spectators / PMs --- src/hu_stuff.c | 99 ++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e6650593..29303157 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -713,24 +713,41 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) || target == 0 // To everyone || consoleplayer == target-1) // To you { - const char *prefix = "", *cstart = "", *cend = "", *adminchar = "\x82~\x83", *remotechar = "\x82@\x83", *fmt, *fmt2; + const char *prefix = "", *cstart = "", *cend = "", *adminchar = "\x82~\x83", *remotechar = "\x82@\x83", *fmt, *fmt2, *textcolor = "\x80"; char *tempchar = NULL; - // In CTF and team match, color the player's name. - if (G_GametypeHasTeams()) - { - cend = ""; - if (players[playernum].ctfteam == 1) // red - cstart = "\x85"; - else if (players[playernum].ctfteam == 2) // blue - cstart = "\x84"; - - } - // player is a spectator? - if (players[playernum].spectator) - cstart = "\x86"; // grey name - + if (players[playernum].spectator) + { + cstart = "\x86"; // grey name + textcolor = "\x86"; + } + else + { + const UINT8 color = players[playernum].skincolor; + if (color >= SKINCOLOR_IVORY && color <= SKINCOLOR_SILVER) + cstart = "\x80"; + else if ((color >= SKINCOLOR_CLOUDY && color <= SKINCOLOR_BLACK) || color == SKINCOLOR_JET) // jet is more black than blue so it goes here. + cstart = "\x86"; + else if (color >= SKINCOLOR_SALMON && color <= SKINCOLOR_CRIMSON) + cstart = "\x85"; + else if (color >= SKINCOLOR_DAWN && color <= SKINCOLOR_CARAMEL) + cstart = "\x87"; + else if (color >= SKINCOLOR_TANGERINE && color <= SKINCOLOR_CANARY) + cstart = "\x82"; + else if (color >= SKINCOLOR_OLIVE && color <= SKINCOLOR_SWAMP) + cstart = "\x83"; + else if ((color >= SKINCOLOR_AQUA && color <= SKINCOLOR_STEEL) || color == SKINCOLOR_SAPPHIRE) // toaster wanted that specific one too shrug + cstart = "\x88"; + else if (color >= SKINCOLOR_PERIWINKLE && color <= SKINCOLOR_NAVY) + cstart = "\x84"; + else if (color >= SKINCOLOR_DUSK && color <= SKINCOLOR_LILAC) + cstart = "\x81"; + else + cstart = "\x83"; + } + prefix = cstart; + // Give admins and remote admins their symbols. if (playernum == serverplayer) tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(adminchar) + 1, PU_STATIC, NULL); @@ -757,53 +774,25 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) } else if (target == 0) // To everyone { - - - /* 31/8/18: Lat': Exclusive to kart, use a CLOSE ENOUGH colour to the player's for text (we're quite limited with our options, - drawstring really should be able to remap to any palette index........*/ - - // there's a lot of fucking colors wtf - const UINT8 color = players[playernum].skincolor; - if (color <= SKINCOLOR_SILVER) - prefix = "\x80"; - else if (color <= SKINCOLOR_BLACK || color == SKINCOLOR_JET) // jet is more black than blue so it goes here. - prefix = "\x86"; - else if (color <= SKINCOLOR_CRIMSON) - prefix = "\x85"; - else if (color <= SKINCOLOR_CARAMEL) - prefix = "\x87"; - else if (color <= SKINCOLOR_CANARY) - prefix = "\x82"; - else if (color <= SKINCOLOR_SWAMP) - prefix = "\x83"; - else if (color <= SKINCOLOR_STEEL || color == SKINCOLOR_SAPPHIRE) // toaster wanted that specific one too shrug - prefix = "\x88"; - else if (color <= SKINCOLOR_NAVY) - prefix = "\x84"; - else - prefix = "\x81"; - - strcat(cstart, prefix); - fmt = "\3%s<%s%s%s>\x80 %s\n"; - fmt2 = "%s<%s%s%s>\x80 %s"; + fmt = "\3%s<%s%s%s>\x80 %s%s\n"; + fmt2 = "%s<%s%s%s>\x80 %s%s"; } else if (target-1 == consoleplayer) // To you { prefix = "\x82[PM]"; cstart = "\x82"; - fmt = "\4%s<%s%s>%s\x80 %s\n"; // make this yellow, however. - fmt2 = "%s<%s%s>%s\x80 %s"; + textcolor = "\x82"; + fmt = "\4%s<%s%s>%s\x80 %s%s\n"; // make this yellow, however. + fmt2 = "%s<%s%s>%s\x80 %s%s"; } else if (target > 0) // By you, to another player { // Use target's name. dispname = player_names[target-1]; - /*fmt = "\3\x82[TO]\x80%s%s%s* %s\n"; - fmt2 = "\x82[TO]\x80%s%s%s* %s";*/ prefix = "\x82[TO]"; cstart = "\x82"; - fmt = "\4%s<%s%s>%s\x80 %s\n"; // make this yellow, however. - fmt2 = "%s<%s%s>%s\x80 %s"; + fmt = "\4%s<%s%s>%s\x80 %s%s\n"; // make this yellow, however. + fmt2 = "%s<%s%s>%s\x80 %s%s"; } else // To your team @@ -815,17 +804,17 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) else prefix = "\x83"; // makes sure this doesn't implode if you sayteam on non-team gamemodes - fmt = "\3%s<%s%s>\x80%s %s\n"; - fmt2 = "%s<%s%s>\x80%s %s"; + fmt = "\3%s<%s%s>\x80%s %s%s\n"; + fmt2 = "%s<%s%s>\x80%s %s%s"; } - HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, msg)); // add it reguardless, in case we decide to change our mind about our chat type. + HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg)); // add it reguardless, in case we decide to change our mind about our chat type. if OLDCHAT - CONS_Printf(fmt, prefix, cstart, dispname, cend, msg); + CONS_Printf(fmt, prefix, cstart, dispname, cend, textcolor, msg); else - CON_LogMessage(va(fmt, prefix, cstart, dispname, cend, msg)); // save to log.txt + CON_LogMessage(va(fmt, prefix, cstart, dispname, cend, textcolor, msg)); // save to log.txt if (tempchar) Z_Free(tempchar); From e01f2ff096275d9203ad70fdd2a83d20cfcabe4d Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 31 Aug 2018 22:38:56 +0100 Subject: [PATCH 32/84] Update arrow rendering to use simple character function rather than overkill string function. --- src/m_menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 8e83f3a6..1c4e9015 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5519,7 +5519,7 @@ static void M_DrawStatsMaps(int location) boolean dotopname = true, dobottomarrow = (location < statsMax); if (location) - V_DrawString(10, y-(skullAnimCounter/5), highlightflags, "\x1A"); + V_DrawCharacter(10, y-(skullAnimCounter/5), '\x1A' | highlightflags, false); while (statsMapList[++i] != -1) { @@ -5601,7 +5601,7 @@ static void M_DrawStatsMaps(int location) } bottomarrow: if (dobottomarrow) - V_DrawString(10, y-8 + (skullAnimCounter/5), highlightflags, "\x1B"); + V_DrawCharacter(10, y-8 + (skullAnimCounter/5), '\x1B' | highlightflags, false); } static void M_DrawLevelStats(void) From 4de68f7fe2e10346c3fe9a43bf00ce2606bbb545 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 6 Sep 2018 22:17:29 +0100 Subject: [PATCH 33/84] Dropping items! * Shield Drop... * Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.) * Pops your Thunder Shield. * Happens upon ANY hit, except for deathpits. * HUD Drop... * Also does the above, except for the Thunder Shield thing. * If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item! * You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type. * Happens upon Size Down and battle elimination. * Can also be forced on with `cv_kartdebughuddrop on`! * Some other random stuff. * Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity. * Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter). * Allow shrunken players to pick up item boxes again. * Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.) * Break NiGHTS a little through my machinations. --- src/d_netcmd.c | 1 + src/d_netcmd.h | 2 +- src/dehacked.c | 3 + src/info.c | 29 ++++++ src/info.h | 3 + src/k_kart.c | 268 ++++++++++++++++++++++++++++++++++++++++--------- src/k_kart.h | 6 +- src/p_inter.c | 38 +++++-- src/p_map.c | 2 +- src/p_mobj.c | 202 +++++++++++++++++++++++++++---------- src/sounds.c | 1 + src/sounds.h | 1 + 12 files changed, 446 insertions(+), 110 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8e046d92..c9343b07 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -370,6 +370,7 @@ static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, consvar_t cv_kartdebugamount = {"kartdebugamount", "1", CV_NETVAR|CV_CHEAT, kartdebugamount_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugshrink = {"kartdebugshrink", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugdistribution = {"kartdebugdistribution", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartdebughuddrop = {"kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugcheckpoint = {"kartdebugcheckpoint", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 3f118944..97dac8a9 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -133,7 +133,7 @@ extern consvar_t cv_karteliminatelast; extern consvar_t cv_votetime; -extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution; +extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugcheckpoint; extern consvar_t cv_itemfinder; diff --git a/src/dehacked.c b/src/dehacked.c index 3473eb87..78d6c4df 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6233,6 +6233,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RANDOMITEMPOP4", //} + "S_ITEMICON", + // Drift Sparks "S_DRIFTSPARK1", "S_DRIFTSPARK2", @@ -7208,6 +7210,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BLUEDIAG", "MT_RANDOMITEM", "MT_RANDOMITEMPOP", + "MT_FLOATINGITEM", "MT_SNEAKERTRAIL", "MT_SPARKLETRAIL", diff --git a/src/info.c b/src/info.c index 60cac109..75a7655f 100644 --- a/src/info.c +++ b/src/info.c @@ -2566,6 +2566,8 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3 {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 + {SPR_NULL, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON + {SPR_DRIF, 0|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DRIFTSPARK2}, // S_DRIFTSPARK1 {SPR_DRIF, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DRIFTSPARK3}, // S_DRIFTSPARK2 {SPR_DRIF, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DRIFTSPARK1}, // S_DRIFTSPARK3 @@ -14390,6 +14392,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_FLOATINGITEM + -1, // doomednum + S_ITEMICON, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_mcitm1, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SPECIAL, // flags + S_NULL // raisestate + }, + { // MT_SNEAKERTRAIL -1, // doomednum S_KARTFIRE1, // spawnstate diff --git a/src/info.h b/src/info.h index 736fdfde..ad876dc7 100644 --- a/src/info.h +++ b/src/info.h @@ -3078,6 +3078,8 @@ typedef enum state S_RANDOMITEMPOP4, //} + S_ITEMICON, + // Drift Sparks S_DRIFTSPARK1, S_DRIFTSPARK2, @@ -4070,6 +4072,7 @@ typedef enum mobj_type MT_BLUEDIAG, MT_RANDOMITEM, MT_RANDOMITEMPOP, + MT_FLOATINGITEM, MT_SNEAKERTRAIL, MT_SPARKLETRAIL, diff --git a/src/k_kart.c b/src/k_kart.c index 40956016..0c75635b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -414,6 +414,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebugamount); CV_RegisterVar(&cv_kartdebugshrink); CV_RegisterVar(&cv_kartdebugdistribution); + CV_RegisterVar(&cv_kartdebughuddrop); CV_RegisterVar(&cv_kartdebugcheckpoint); } @@ -1101,7 +1102,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) fx->eflags |= MFE_VERTICALFLIP; else fx->eflags &= ~MFE_VERTICALFLIP; - fx->scale = mobj1->scale; + P_SetScale(fx, mobj1->scale); // Because this is done during collision now, rmomx and rmomy need to be recalculated // so that friction doesn't immediately decide to stop the player if they're at a standstill @@ -1715,6 +1716,10 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem P_SetPlayerMobjState(player->mo, S_KART_SPIN); player->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(player); + else + K_DropHnextList(player); return; } @@ -1784,6 +1789,10 @@ void K_SquishPlayer(player_t *player, mobj_t *source) P_PlayRinglossSound(player->mo); player->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(player); + else + K_DropHnextList(player); return; } @@ -1861,6 +1870,10 @@ void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we ju } player->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(player); + else + K_DropHnextList(player); return; } @@ -1936,6 +1949,10 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force) victim->kartstuff[k_comebacktimer] = comebacktime;*/ victim->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(victim); + else + K_DropHnextList(victim); return; } @@ -2043,14 +2060,14 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) { dust = P_SpawnMobj(source->x, source->y, source->z, MT_SMOKE); dust->angle = (ANGLE_180/16) * i; - dust->scale = source->scale; + P_SetScale(dust, source->scale); dust->destscale = source->scale*10; P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale)); truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMEXPLODE); - truc->scale = source->scale*2; + P_SetScale(truc, source->scale); truc->destscale = source->scale*6; speed = FixedMul(10*FRACUNIT, source->scale)>>FRACBITS; truc->momx = P_RandomRange(-speed, speed)*FRACUNIT; @@ -2065,7 +2082,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE); - dust->scale = source->scale; + P_SetScale(dust, source->scale); dust->destscale = source->scale*10; dust->tics = 30; dust->momz = P_RandomRange(FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT; @@ -2073,7 +2090,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMPARTICLE); - truc->scale = source->scale; + P_SetScale(truc, source->scale); truc->destscale = source->scale*5; speed = FixedMul(20*FRACUNIT, source->scale)>>FRACBITS; truc->momx = P_RandomRange(-speed, speed)*FRACUNIT; @@ -2350,7 +2367,7 @@ void K_DriftDustHandling(mobj_t *spawner) dust->momx = FixedMul(spawner->momx + (P_RandomRange(-speedrange, speedrange)<momy = FixedMul(spawner->momy + (P_RandomRange(-speedrange, speedrange)<momz = P_MobjFlip(spawner) * P_RandomRange(1, 4)<scale = spawner->scale/2; + P_SetScale(dust, spawner->scale/2); dust->destscale = spawner->scale * 3; if (leveltime % 6 == 0) @@ -2808,46 +2825,190 @@ killnext: } // Just for firing/dropping items. -void K_CleanHnextList(mobj_t *work) -{ - mobj_t *nextwork; - - if (!work) - return; - - work = work->hnext; - - while (work && !P_MobjWasRemoved(work)) - { - nextwork = work->hnext; - - P_RemoveMobj(work); - - work = nextwork; - } -} - -// Ditto. -void K_UpdateHnextList(player_t *player) +void K_UpdateHnextList(player_t *player, boolean clean) { mobj_t *work = player->mo, *nextwork; if (!work) return; - work = work->hnext; + nextwork = work->hnext; - while (work && !P_MobjWasRemoved(work)) + while ((work = nextwork) && !P_MobjWasRemoved(work)) { nextwork = work->hnext; - if (work->movedir > 0 && work->movedir > (UINT16)player->kartstuff[k_itemamount]) - P_RemoveMobj(work); + if (!clean && (!work->movedir || work->movedir <= (UINT16)player->kartstuff[k_itemamount])) + continue; - work = nextwork; + P_RemoveMobj(work); } } +// For getting hit! +void K_DropHnextList(player_t *player) +{ + mobj_t *work = player->mo, *nextwork, *dropwork; + INT32 flip; + mobjtype_t type; + boolean orbit, ponground; + + if (!work) + return; + + flip = P_MobjFlip(player->mo); + ponground = P_IsObjectOnGround(player->mo); + + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD && player->kartstuff[k_itemamount]) + { + K_DoThunderShield(player); + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_itemtype] = KITEM_NONE; + } + + nextwork = work->hnext; + + while ((work = nextwork) && !P_MobjWasRemoved(work)) + { + nextwork = work->hnext; + + switch (work->type) + { + // Kart orbit items + case MT_ORBINAUT_SHIELD: + orbit = true; + type = MT_ORBINAUT; + break; + case MT_JAWZ_SHIELD: + orbit = true; + type = MT_JAWZ_DUD; + break; + // Kart trailing items + case MT_BANANA_SHIELD: + orbit = false; + type = MT_BANANA; + break; + case MT_SSMINE_SHIELD: + orbit = false; + type = MT_SSMINE; + break; + case MT_FAKESHIELD: + orbit = false; + type = MT_FAKEITEM; + break; + // intentionally do nothing + case MT_SINK_SHIELD: + return; + default: + continue; + } + + dropwork = P_SpawnMobj(work->x, work->y, work->z, type); + P_SetTarget(&dropwork->target, player->mo); + dropwork->angle = work->angle; + dropwork->flags2 = work->flags2; + dropwork->flags |= MF_NOCLIPTHING; + dropwork->floorz = work->floorz; + dropwork->ceilingz = work->ceilingz; + + if (ponground) + { + // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn + // This should set it for FOFs + //P_TeleportMove(dropwork, dropwork->x, dropwork->y, dropwork->z); -- handled better by above floorz/ceilingz passing + + if (flip == 1) + { + if (dropwork->floorz > dropwork->target->z - dropwork->height) + { + dropwork->z = dropwork->floorz; + } + } + else + { + if (dropwork->ceilingz < dropwork->target->z + dropwork->target->height + dropwork->height) + { + dropwork->z = dropwork->ceilingz - dropwork->height; + } + } + } + + if (orbit) // splay out + { + dropwork->flags2 |= MF2_AMBUSH; + dropwork->z += flip; + dropwork->momx = player->mo->momx>>1; + dropwork->momy = player->mo->momy>>1; + dropwork->momz = 3*flip*mapheaderinfo[gamemap-1]->mobj_scale; + P_Thrust(dropwork, work->angle - ANGLE_90, 6*(mapheaderinfo[gamemap-1]->mobj_scale)); + dropwork->movecount = 2; + dropwork->movedir = work->angle - ANGLE_90; + P_SetMobjState(dropwork, dropwork->info->deathstate); + dropwork->tics = -1; + if (type == MT_JAWZ_DUD) + dropwork->z += 20*flip*dropwork->scale; + else + { + dropwork->color = work->color; + dropwork->angle -= ANGLE_90; + } + } + else // plop on the ground + { + dropwork->flags &= ~MF_NOCLIPTHING; + dropwork->threshold = 10; + } + + P_RemoveMobj(work); + } + + { + // we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic... + P_SetTarget(&player->mo->hnext, NULL); + player->kartstuff[k_bananadrag] = 0; + if (player->kartstuff[k_eggmanheld]) + player->kartstuff[k_eggmanheld] = 0; + else if (player->kartstuff[k_itemheld]) + { + player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; + player->kartstuff[k_itemtype] = KITEM_NONE; + } + } +} + +// For getting EXTRA hit! +void K_DropItems(player_t *player) +{ + boolean thunderhack = (player->kartstuff[k_curshield] && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD); + + if (thunderhack) + player->kartstuff[k_itemtype] = KITEM_NONE; + + K_DropHnextList(player); + + if (player->mo && player->kartstuff[k_itemamount]) + { + mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM); + P_SetScale(drop, drop->scale>>5); + drop->destscale = (3*drop->destscale)/2;; + + drop->angle = player->mo->angle + ANGLE_90; + drop->momx = player->mo->momx>>1; + drop->momy = player->mo->momy>>1; + P_Thrust(drop, + FixedAngle(P_RandomFixed()*180) + player->mo->angle + ANGLE_90, + 8*(mapheaderinfo[gamemap-1]->mobj_scale)); + drop->momz = P_MobjFlip(player->mo)*3*(mapheaderinfo[gamemap-1]->mobj_scale); + + drop->threshold = (thunderhack ? KITEM_THUNDERSHIELD : player->kartstuff[k_itemtype]); + drop->movecount = player->kartstuff[k_itemamount]; + + drop->flags |= MF_NOCLIPTHING; + } + + K_StripItems(player); +} + // When an item in the hnext chain dies. void K_RepairOrbitChain(mobj_t *orbit) { @@ -3859,20 +4020,18 @@ static void K_KartUpdatePosition(player_t *player) // void K_StripItems(player_t *player) { - player->kartstuff[k_itemtype] = 0; + player->kartstuff[k_itemtype] = KITEM_NONE; player->kartstuff[k_itemamount] = 0; player->kartstuff[k_itemheld] = 0; - player->kartstuff[k_itemroulette] = 0; - player->kartstuff[k_roulettetype] = 0; - player->kartstuff[k_rocketsneakertimer] = 0; - player->kartstuff[k_invincibilitytimer] = 0; - player->kartstuff[k_growshrinktimer] = 0; + if (!player->kartstuff[k_itemroulette] || player->kartstuff[k_roulettetype] != 2) + { + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + } player->kartstuff[k_eggmanheld] = 0; - player->kartstuff[k_eggmanexplode] = 0; - player->kartstuff[k_eggmanblame] = 0; player->kartstuff[k_hyudorotimer] = 0; player->kartstuff[k_stealingtimer] = 0; @@ -3884,7 +4043,19 @@ void K_StripItems(player_t *player) player->kartstuff[k_sadtimer] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); +} + +void K_StripOther(player_t *player) +{ + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + + player->kartstuff[k_invincibilitytimer] = 0; + player->kartstuff[k_growshrinktimer] = 0; + + player->kartstuff[k_eggmanexplode] = 0; + player->kartstuff[k_eggmanblame] = 0; } // @@ -3950,7 +4121,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, false, MT_FAKEITEM, -1, 0); K_PlayTauntSound(player->mo); player->kartstuff[k_eggmanheld] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); } // Rocket Sneaker else if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO @@ -4037,7 +4208,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, false, MT_BANANA, -1, 0); K_PlayTauntSound(player->mo); player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player); + K_UpdateHnextList(player, false); } break; case KITEM_EGGMAN: @@ -4097,7 +4268,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); K_PlayTauntSound(player->mo); player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player); + K_UpdateHnextList(player, false); } break; case KITEM_JAWZ: @@ -4140,7 +4311,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); K_PlayTauntSound(player->mo); player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player); + K_UpdateHnextList(player, false); } break; case KITEM_MINE: @@ -4166,7 +4337,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayTauntSound(player->mo); player->kartstuff[k_itemamount]--; player->kartstuff[k_itemheld] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); } break; case KITEM_BALLHOG: @@ -4293,7 +4464,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayTauntSound(player->mo); player->kartstuff[k_itemamount]--; player->kartstuff[k_itemheld] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); } break; case KITEM_SAD: @@ -4372,7 +4543,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) // dead in match? you da bomb { - K_StripItems(player); + K_DropItems(player); //K_StripItems(player); + K_StripOther(player); player->mo->flags2 |= MF2_SHADOW; player->powers[pw_flashing] = player->kartstuff[k_comebacktimer]; } diff --git a/src/k_kart.h b/src/k_kart.h index 9865d373..bbef6c00 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -39,14 +39,16 @@ void K_DriftDustHandling(mobj_t *spawner); void K_DoSneaker(player_t *player, boolean doPFlag); void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, boolean mute); void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); -void K_CleanHnextList(mobj_t *work); -void K_UpdateHnextList(player_t *player); +void K_UpdateHnextList(player_t *player, boolean clean); +void K_DropHnextList(player_t *player); void K_RepairOrbitChain(mobj_t *orbit); player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); fixed_t K_GetKartDriftSparkValue(player_t *player); +void K_DropItems(player_t *player); void K_StripItems(player_t *player); +void K_StripOther(player_t *player); void K_MomentumToFacing(player_t *player); fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower); fixed_t K_GetKartAccel(player_t *player); diff --git a/src/p_inter.c b/src/p_inter.c index 7e35731a..c8d42b23 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -181,13 +181,13 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Item-specific timer going off if (player->kartstuff[k_stealingtimer] || player->kartstuff[k_stolentimer] - || player->kartstuff[k_growshrinktimer] != 0 || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode]) return false; // Item slot already taken up if (player->kartstuff[k_itemroulette] - || player->kartstuff[k_itemamount] + || (weapon != 3 && player->kartstuff[k_itemamount]) || player->kartstuff[k_itemheld]) return false; } @@ -429,6 +429,27 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // We now identify by object type, not sprite! Tails 04-11-2001 switch (special->type) { + case MT_FLOATINGITEM: // SRB2kart + if (!P_CanPickupItem(player, 3) || (player->kartstuff[k_itemamount] && player->kartstuff[k_itemtype] != special->threshold)) + return; + + if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) + return; + + player->kartstuff[k_itemtype] = special->threshold; + player->kartstuff[k_itemamount] += special->movecount; + if (player->kartstuff[k_itemamount] > 255) + player->kartstuff[k_itemamount] = 255; + + S_StartSound(special, special->info->deathsound); + + P_SetTarget(&special->tracer, toucher); + special->flags2 |= MF2_NIGHTSPULL; + special->destscale = mapheaderinfo[gamemap-1]->mobj_scale>>5; + special->scalespeed <<= 1; + + special->flags &= ~MF_SPECIAL; + return; case MT_RANDOMITEM: // SRB2kart if (!P_CanPickupItem(player, 1)) return; @@ -469,9 +490,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); S_StartSound(poof, special->info->deathsound); - K_StripItems(player); - if (player->kartstuff[k_itemroulette] <= 0) - player->kartstuff[k_itemroulette] = 1; + K_DropItems(player); //K_StripItems(player); + K_StripOther(player); + player->kartstuff[k_itemroulette] = 1; player->kartstuff[k_roulettetype] = 2; if (special->target && special->target->player && (G_RaceGametype() || special->target->player->kartstuff[k_bumper] > 0)) @@ -2626,6 +2647,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) } } + if ((target->type == MT_JAWZ || target->type == MT_JAWZ_DUD || target->type == MT_JAWZ_SHIELD) && !(target->flags2 & MF2_AMBUSH)) + { + target->z += P_MobjFlip(target)*20*target->scale; + } + if (target->type == MT_SPIKE && inflictor && target->info->deathstate != S_NULL) { const fixed_t x=target->x,y=target->y,z=target->z; @@ -3335,6 +3361,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->mo->destscale = 6*player->mo->destscale/8; // Wipeout + K_DropItems(player); K_SpinPlayer(player, source, 1, false); damage = player->mo->health - 1; P_RingDamage(player, inflictor, source, damage); @@ -3346,7 +3373,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da quake.time = 5; } - K_StripItems(player); player->kartstuff[k_growshrinktimer] -= (200+(40*(16-player->kartstuff[k_position]))); } // Grow? Let's take that away. diff --git a/src/p_map.c b/src/p_map.c index 88045a3e..c97ee909 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -497,7 +497,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE))) + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE)) || (thing->flags & MF_NOCLIPTHING)) return true; // Don't collide with your buddies while NiGHTS-flying. diff --git a/src/p_mobj.c b/src/p_mobj.c index fb6eed54..dc4ac036 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6006,7 +6006,7 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y return; // change angle - source->angle = R_PointToAngle2(source->x, source->y, tx, ty); + //source->angle = R_PointToAngle2(source->x, source->y, tx, ty); // change slope dist = P_AproxDistance(P_AproxDistance(tx - source->x, ty - source->y), tz - source->z); @@ -6015,7 +6015,7 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y dist = 1; if (nightsgrab) - speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(8*FRACUNIT, source->scale); + speedmul = P_AproxDistance(dest->momx, dest->momy) + source->scale; else speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(source->info->speed, source->scale); @@ -6348,6 +6348,9 @@ void P_RunShadows(void) break; } } + + if (mobj->target->type == MT_FLOATINGITEM) + P_SetScale(mobj, mobj->scale/2); } P_SetTarget(&shadowcap, NULL); } @@ -6727,7 +6730,7 @@ void P_MobjThinker(mobj_t *mobj) /*if (mobj->health > 0 && mobj->target && mobj->target->player && mobj->target->player->health > 0 && !mobj->target->player->spectator) { - // Was this so hard? -- Handled this with K_UpdateHnextList and K_ClearHnextList instead of thinking it away... + // Was this so hard? -- Handled this with K_UpdateHnextList instead of thinking it away... if ((mobj->type == MT_ORBINAUT_SHIELD && mobj->target->player->kartstuff[k_itemtype] != KITEM_ORBINAUT) || (mobj->type == MT_JAWZ_SHIELD && mobj->target->player->kartstuff[k_itemtype] != KITEM_JAWZ) || (mobj->movedir > 0 && ((UINT16)mobj->target->player->kartstuff[k_itemamount] < mobj->movedir)) @@ -6911,14 +6914,16 @@ void P_MobjThinker(mobj_t *mobj) mobj->x = mobj->target->x; mobj->y = mobj->target->y; + mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's + if (!(mobj->target->eflags & MFE_VERTICALFLIP)) { - mobj->z = mobj->target->z + P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT; + mobj->z = mobj->target->z + P_GetPlayerHeight(mobj->target->player)+(16+11)*mapheaderinfo[gamemap-1]->mobj_scale; mobj->eflags &= ~MFE_VERTICALFLIP; } else { - mobj->z = mobj->target->z - P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT; + mobj->z = mobj->target->z - P_GetPlayerHeight(mobj->target->player)+(16+11)*mapheaderinfo[gamemap-1]->mobj_scale; mobj->eflags |= MFE_VERTICALFLIP; } P_SetThingPosition(mobj); @@ -6934,7 +6939,8 @@ void P_MobjThinker(mobj_t *mobj) mobj->tracer = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); P_SetTarget(&mobj->tracer->target, mobj); P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); - P_SetScale(mobj->tracer, mobj->scale); + P_SetMobjState(mobj->tracer, S_ITEMICON); // null sprite and frame to be overwritten later + P_SetScale(mobj->tracer, (mobj->tracer->destscale = mobj->scale)); } if (!(mobj->flags2 & MF2_DONTDRAW)) @@ -7027,7 +7033,7 @@ void P_MobjThinker(mobj_t *mobj) else { P_SetMobjState(mobj, S_PLAYERARROW); - P_SetMobjState(mobj->tracer, S_INVISIBLE); + P_SetMobjState(mobj->tracer, S_ITEMICON); // null sprite and frame to be overwritten later } mobj->tracer->destscale = scale; @@ -7097,12 +7103,12 @@ void P_MobjThinker(mobj_t *mobj) if (!(mobj->target->eflags & MFE_VERTICALFLIP)) { - mobj->z = mobj->target->z + (P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT+(64*mobj->scale)); + mobj->z = mobj->target->z + (P_GetPlayerHeight(mobj->target->player)+16*mapheaderinfo[gamemap-1]->mobj_scale+(64*mobj->scale)); mobj->eflags &= ~MFE_VERTICALFLIP; } else { - mobj->z = mobj->target->z - (P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT+(64*mobj->scale)); + mobj->z = mobj->target->z - (P_GetPlayerHeight(mobj->target->player)+16*mapheaderinfo[gamemap-1]->mobj_scale+(64*mobj->scale)); mobj->eflags |= MFE_VERTICALFLIP; } P_SetThingPosition(mobj); @@ -8007,46 +8013,120 @@ void P_MobjThinker(mobj_t *mobj) mobj->threshold = 0; } break; - case MT_ORBINAUT: + case MT_FLOATINGITEM: { - sector_t *sec2; - fixed_t finalspeed = mobj->info->speed; - - P_SpawnGhostMobj(mobj); - - if (gamespeed == 0) - finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); - else if (gamespeed == 2) - finalspeed = FixedMul(finalspeed, FRACUNIT+FRACUNIT/4); - - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); - if (mobj->health <= 5) + if (mobj->flags & MF_NOCLIPTHING) { - INT32 i; - for (i = 5; i >= mobj->health; i--) + if (P_IsObjectOnGround(mobj)) { - finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + mobj->momx = 1; + mobj->momy = 0; + mobj->flags &= ~MF_NOCLIPTHING; + mobj->flags |= MF_NOGRAVITY; } - finalspeed = FixedMul(finalspeed, mapheaderinfo[gamemap-1]->mobj_scale); - P_InstaThrust(mobj, mobj->angle, finalspeed); } else { - finalspeed = FixedMul(finalspeed, mapheaderinfo[gamemap-1]->mobj_scale); - P_InstaThrust(mobj, mobj->angle, finalspeed); + mobj->angle += 2*ANG2; + if (mobj->flags2 & MF2_NIGHTSPULL) + { + if (!mobj->tracer || !mobj->tracer->health + || mobj->scale <= mapheaderinfo[gamemap-1]->mobj_scale>>5) + { + P_RemoveMobj(mobj); + return; + } + P_Attract(mobj, mobj->tracer, true); + } + else + { + fixed_t adj = FixedMul(FRACUNIT - FINECOSINE((mobj->movedir>>ANGLETOFINESHIFT) & FINEMASK), (mapheaderinfo[gamemap-1]->mobj_scale<<3)); + mobj->movedir += 2*ANG2; + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->ceilingz - mobj->height - adj; + else + mobj->z = mobj->floorz + adj; + } } - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) - || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) - && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) - K_DoPogoSpring(mobj, 0, false); + switch (mobj->threshold) + { + case KITEM_ORBINAUT: + mobj->sprite = SPR_ITMO; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(min(mobj->movecount-1, 3)); + break; + case KITEM_INVINCIBILITY: + mobj->sprite = SPR_ITMI; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|((leveltime % (7*3)) / 3); + break; + case KITEM_SAD: + mobj->sprite = SPR_ITEM; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE; + break; + default: + mobj->sprite = SPR_ITEM; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(mobj->threshold); + break; + } + break; + } + case MT_ORBINAUT: + { + boolean grounded = P_IsObjectOnGround(mobj); + if (mobj->flags2 & MF2_AMBUSH) + { + if (grounded && (mobj->flags & MF_NOCLIPTHING)) + { + mobj->momx = 1; + mobj->momy = 0; + mobj->frame = 3; + S_StartSound(mobj, mobj->info->activesound); + mobj->flags &= ~MF_NOCLIPTHING; + } + else if (mobj->movecount) + mobj->movecount--; + else if (mobj->frame < 3) + { + mobj->movecount = 2; + mobj->frame++; + } + } + else + { + fixed_t finalspeed = mobj->info->speed; - if (mobj->threshold > 0) - mobj->threshold--; + P_SpawnGhostMobj(mobj); - if (leveltime % 6 == 0) - S_StartSound(mobj, mobj->info->activesound); + if (gamespeed == 0) + finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + else if (gamespeed == 2) + finalspeed = FixedMul(finalspeed, FRACUNIT+FRACUNIT/4); + + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + if (mobj->health <= 5) + { + INT32 i; + for (i = 5; i >= mobj->health; i--) + finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + } + finalspeed = FixedMul(finalspeed, mapheaderinfo[gamemap-1]->mobj_scale); + P_InstaThrust(mobj, mobj->angle, finalspeed); + + if (grounded) + { + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) + || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) + && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) + K_DoPogoSpring(mobj, 0, false); + } + + if (mobj->threshold > 0) + mobj->threshold--; + + if (leveltime % 6 == 0) + S_StartSound(mobj, mobj->info->activesound); + } break; } case MT_JAWZ: @@ -8119,23 +8199,38 @@ void P_MobjThinker(mobj_t *mobj) } case MT_JAWZ_DUD: { - sector_t *sec2; + boolean grounded = P_IsObjectOnGround(mobj); + if (mobj->flags2 & MF2_AMBUSH) + { + if (grounded && (mobj->flags & MF_NOCLIPTHING)) + { + mobj->momx = 1; + mobj->momy = 0; + S_StartSound(mobj, mobj->info->deathsound); + mobj->flags &= ~MF_NOCLIPTHING; + } + } + else + { + P_SpawnGhostMobj(mobj); + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + P_InstaThrust(mobj, mobj->angle, mobj->info->speed); - P_SpawnGhostMobj(mobj); - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); - P_InstaThrust(mobj, mobj->angle, mobj->info->speed); + if (grounded) + { + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) + || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) + && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) + K_DoPogoSpring(mobj, 0, false); + } - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) - || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) - && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) - K_DoPogoSpring(mobj, 0, false); + if (mobj->threshold > 0) + mobj->threshold--; - if (mobj->threshold > 0) - mobj->threshold--; - - if (leveltime % TICRATE == 0) - S_StartSound(mobj, mobj->info->activesound); + if (leveltime % TICRATE == 0) + S_StartSound(mobj, mobj->info->activesound); + } break; } @@ -9155,6 +9250,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BIGMACE: case MT_SMALLMACE: case MT_FALLINGROCK: //case MT_RANDOMITEM: + case MT_FLOATINGITEM: case MT_BATTLEBUMPER: case MT_BANANA: case MT_BANANA_SHIELD: //case MT_FAKEITEM: case MT_FAKESHIELD: @@ -9254,6 +9350,8 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) if (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->mobj_scale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN) mobj->destscale = mapheaderinfo[gamemap-1]->mobj_scale; + P_SetScale(mobj, mobj->destscale); + // set subsector and/or block links P_SetThingPosition(mobj); I_Assert(mobj->subsector != NULL); diff --git a/src/sounds.c b/src/sounds.c index 6e956260..b68c8afa 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -811,6 +811,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"noooo1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"noooo2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"hogbom", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"mcitm1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds diff --git a/src/sounds.h b/src/sounds.h index 2f073273..86319c33 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -883,6 +883,7 @@ typedef enum sfx_noooo1, sfx_noooo2, sfx_hogbom, + sfx_mcitm1, sfx_dbgsal, sfx_kwin, From baf50a1dbfc35eb1b1888def5a93bdd571e43baf Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 7 Sep 2018 14:26:00 +0100 Subject: [PATCH 34/84] * Slightly more papersprite stability! * Slightly more sane Minecraft item scaling! --- src/k_kart.c | 2 +- src/p_inter.c | 2 +- src/p_mobj.c | 2 +- src/r_things.c | 9 +++------ 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 477f710e..55c1802a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3008,7 +3008,7 @@ void K_DropItems(player_t *player) if (player->mo && player->kartstuff[k_itemamount]) { mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM); - P_SetScale(drop, drop->scale>>5); + P_SetScale(drop, drop->scale>>4); drop->destscale = (3*drop->destscale)/2;; drop->angle = player->mo->angle + ANGLE_90; diff --git a/src/p_inter.c b/src/p_inter.c index c8d42b23..aab44b5f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -445,7 +445,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->tracer, toucher); special->flags2 |= MF2_NIGHTSPULL; - special->destscale = mapheaderinfo[gamemap-1]->mobj_scale>>5; + special->destscale = mapheaderinfo[gamemap-1]->mobj_scale>>4; special->scalespeed <<= 1; special->flags &= ~MF_SPECIAL; diff --git a/src/p_mobj.c b/src/p_mobj.c index 7093e781..baf0f1f2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8031,7 +8031,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags2 & MF2_NIGHTSPULL) { if (!mobj->tracer || !mobj->tracer->health - || mobj->scale <= mapheaderinfo[gamemap-1]->mobj_scale>>5) + || mobj->scale <= mapheaderinfo[gamemap-1]->mobj_scale>>4) { P_RemoveMobj(mobj); return; diff --git a/src/r_things.c b/src/r_things.c index 5adcecd4..dbe31cb1 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1266,7 +1266,6 @@ static void R_ProjectSprite(mobj_t *thing) if (papersprite) { fixed_t yscale2, cosmul, sinmul, tz2; - INT32 range; if (ang >= ANGLE_180) { @@ -1296,12 +1295,10 @@ static void R_ProjectSprite(mobj_t *thing) if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; - if (x2 > x1) - range = (x2 - x1); - else - range = 1; + if (x2 <= x1) + return; - scalestep = (yscale2 - yscale)/range; + scalestep = (yscale2 - yscale)/(x2 - x1); // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? // sortscale = max(yscale, yscale2); From 2cc07df3d2c6dace12271dc2dc284d6d939312f2 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 7 Sep 2018 15:50:24 -0400 Subject: [PATCH 35/84] Minor tweakings - Win/lose quotes are only played for your player - Win, lose, and gloat lines are played from farther away --- src/p_user.c | 2 +- src/sounds.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d2395aab..4600ca12 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1728,7 +1728,7 @@ void P_DoPlayerExit(player_t *player) else if (!countdown) countdown = cv_countdowntime.value*TICRATE + 1; // Use cv_countdowntime - if (cv_kartvoices.value) + if (cv_kartvoices.value && P_IsLocalPlayer(player)) { if (K_IsPlayerLosing(player)) S_StartSound(player->mo, sfx_klose); diff --git a/src/sounds.c b/src/sounds.c index 3a739a94..a672694d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -814,8 +814,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds - {"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR}, - {"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR}, + {"kwin", false, 64, 48, -1, NULL, 0, SKSKWIN, -1, LUMPERROR}, + {"klose", false, 64, 48, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR}, {"khurt1", false, 64, 96, -1, NULL, 0, SKSKPAN1, -1, LUMPERROR}, {"khurt2", false, 64, 96, -1, NULL, 0, SKSKPAN2, -1, LUMPERROR}, {"kattk1", false, 64, 96, -1, NULL, 0, SKSKATK1, -1, LUMPERROR}, @@ -824,7 +824,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"kbost2", false, 64, 96, -1, NULL, 0, SKSKBST2, -1, LUMPERROR}, {"kslow", false, 128, 32, -1, NULL, 0, SKSKSLOW, -1, LUMPERROR}, {"khitem", false, 64, 32, -1, NULL, 0, SKSKHITM, -1, LUMPERROR}, - {"kgloat", false, 64, 40, -1, NULL, 0, SKSKPOWR, -1, LUMPERROR}, + {"kgloat", false, 64, 48, -1, NULL, 0, SKSKPOWR, -1, LUMPERROR}, // skin sounds free slots to add sounds at run time (Boris HACK!!!) // initialized to NULL From f907a3c21567fdf0382b156e643936fafd1d5fab Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 7 Sep 2018 16:20:20 -0400 Subject: [PATCH 36/84] Speed pads always play a boost voice clip For the extra SA1 feel :P --- src/p_spec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index 103b31aa..f67b3939 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3853,6 +3853,13 @@ DoneSection2: player->powers[pw_flashing] = TICRATE/3; S_StartSound(player->mo, sfx_spdpad); + + { + sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons + if (cv_kartvoices.value) + S_StartSound(player->mo, sfx_kbost1+pick); + //K_TauntVoiceTimers(player); + } } break; From 6317ae59962a7baefafc200970ac7bf858e8ea6e Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 7 Sep 2018 16:56:34 -0400 Subject: [PATCH 37/84] Okay do this correctly by doing a reacharound to grab the actual sfx id --- src/p_user.c | 23 ++++++++++++++++++++--- src/sounds.c | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 4600ca12..240d0aee 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1730,10 +1730,27 @@ void P_DoPlayerExit(player_t *player) if (cv_kartvoices.value && P_IsLocalPlayer(player)) { - if (K_IsPlayerLosing(player)) - S_StartSound(player->mo, sfx_klose); + if (P_IsLocalPlayer(player)) + { + sfxenum_t sfx_id; + if (K_IsPlayerLosing(player)) + { + sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound]; + S_StartSound(NULL, sfx_id); + } + else + { + sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound]; + S_StartSound(NULL, sfx_id); + } + } else - S_StartSound(player->mo, sfx_kwin); + { + if (K_IsPlayerLosing(player)) + S_StartSound(player->mo, sfx_klose); + else + S_StartSound(player->mo, sfx_kwin); + } } player->exiting = 3*TICRATE; diff --git a/src/sounds.c b/src/sounds.c index a672694d..2f772a69 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -814,8 +814,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds - {"kwin", false, 64, 48, -1, NULL, 0, SKSKWIN, -1, LUMPERROR}, - {"klose", false, 64, 48, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR}, + {"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR}, + {"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR}, {"khurt1", false, 64, 96, -1, NULL, 0, SKSKPAN1, -1, LUMPERROR}, {"khurt2", false, 64, 96, -1, NULL, 0, SKSKPAN2, -1, LUMPERROR}, {"kattk1", false, 64, 96, -1, NULL, 0, SKSKATK1, -1, LUMPERROR}, From f887ae6628b8ac3a3db3bb63b0637c5d4d03d421 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 8 Sep 2018 12:12:28 +0100 Subject: [PATCH 38/84] Watertight fix I was avoiding because it's definitely slower to check ranges at runtime, but papersprites are used intermittently enough that I don't think it's a super big deal. --- src/r_things.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index dbe31cb1..6166c762 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -917,6 +917,16 @@ static void R_DrawVisSprite(vissprite_t *vis) for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { + if (vis->scalestep) // currently papersprites only + { +#ifndef RANGECHECK + if ((frac>>FRACBITS) >= SHORT(patch->width)) // slower but kills intermittent crashes... + break; +#endif + sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); + dc_iscale = (0xffffffffu / (unsigned)spryscale); + spryscale += vis->scalestep; + } #ifdef RANGECHECK texturecolumn = frac>>FRACBITS; @@ -926,16 +936,10 @@ static void R_DrawVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); #endif - if (vis->scalestep) - { - sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); - dc_iscale = (0xffffffffu / (unsigned)spryscale); - } if (vis->vflip) R_DrawFlippedMaskedColumn(column, patch->height); else R_DrawMaskedColumn(column); - spryscale += vis->scalestep; } colfunc = basecolfunc; @@ -1257,7 +1261,7 @@ static void R_ProjectSprite(mobj_t *thing) offset2 = FixedMul(spritecachedinfo[lump].width, this_scale); tx += FixedMul(offset2, ang_scale); - x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - (papersprite ? 2 : 1); + x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - 1; // off the left side if (x2 < 0) From 9eeefde0f42ae11ab4d5c6dd17190d041024401b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 8 Sep 2018 23:45:51 +0100 Subject: [PATCH 39/84] Make bomb attacks HUD drop. (Karma may be changed later, but Oni said let's try all together first...) --- src/k_kart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index a53eb7f4..61c9446d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1886,10 +1886,10 @@ void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we ju } player->kartstuff[k_instashield] = 15; - if (cv_kartdebughuddrop.value) + //if (cv_kartdebughuddrop.value) K_DropItems(player); - else - K_DropHnextList(player); + /*else + K_DropHnextList(player);*/ return; } From dc0144540b55ef12d196824150395bb5d88f4a74 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 9 Sep 2018 13:47:19 +0100 Subject: [PATCH 40/84] `// if this doesn't work i'm removing papersprites` (check both the left and right side overflow of the sprite column being drawn) --- src/r_things.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 6166c762..7f6e3974 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -920,7 +920,7 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->scalestep) // currently papersprites only { #ifndef RANGECHECK - if ((frac>>FRACBITS) >= SHORT(patch->width)) // slower but kills intermittent crashes... + if ((frac>>FRACBITS) < 0 || (frac>>FRACBITS) >= SHORT(patch->width)) // if this doesn't work i'm removing papersprites break; #endif sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); @@ -1271,6 +1271,9 @@ static void R_ProjectSprite(mobj_t *thing) { fixed_t yscale2, cosmul, sinmul, tz2; + if (x2 <= x1) + return; + if (ang >= ANGLE_180) { offset *= -1; @@ -1299,9 +1302,6 @@ static void R_ProjectSprite(mobj_t *thing) if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; - if (x2 <= x1) - return; - scalestep = (yscale2 - yscale)/(x2 - x1); // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? From 1010950148edeea34f797010850f892abebb1d19 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 9 Sep 2018 15:17:41 +0100 Subject: [PATCH 41/84] This isn't vanilla, don't be a shit about secrets and addfile (plus it helps that this fixes a crash) --- src/m_menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index dcfe4fb8..5becef4e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4787,8 +4787,8 @@ static void M_HandleAddons(INT32 choice) { closefilemenu(true); - // secrets disabled by addfile... - MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + // Secret menu! + //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); From fd7bc1c1ac59ca233e2ccdfa3e38b2ec50ace044 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 11 Sep 2018 15:41:41 +0100 Subject: [PATCH 42/84] Do a bunch of major modifications to the voting system's rule change system! * Add `kartvoterulechanges`, or "Voting Rule Changes" on the menu, to allow some user control over event frequency. * "Never" - does what it says on the tin. * "Sometimes" - 1/8 chance of Encore if host has unlocked it, only gametype change when buffer is full * "Frequent" - 1/2 chance of Encore if host has unlocked it, gametype change every 5 maps * "Always" - If host has unlocked Encore, alternates between Encore and Gametype. Otherwise, always a gametype change * There's probably room for a setting between "Sometimes" and "Frequent", but I didn't want to overload the host with options and these were the ones that made sense. * Better handling of buffer refreshes, to prevent two of the same map appearing next to each other in the voting unless there literally aren't that many maps. * Mostly unrelated: Minor bugfix for Y_SetupVoteFinish, preventing music changes/random sounds playing on the You Will Join Next Race screen. (Branch-appropriate, at least.) --- src/d_netcmd.c | 2 ++ src/d_netcmd.h | 1 + src/g_game.c | 78 +++++++++++++++++++++++++++++++++++++++++++------- src/k_kart.c | 1 + src/m_menu.c | 11 +++---- src/y_inter.c | 17 +++++------ 6 files changed, 85 insertions(+), 25 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 28d33be9..cb2ed49d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -353,6 +353,8 @@ consvar_t cv_kartbumpers = {"kartbumpers", "3", CV_NETVAR|CV_CHEAT, kartbumpers_ consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartFrantic_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}}; +consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 5238c44e..5814f2ae 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -125,6 +125,7 @@ extern consvar_t cv_kartbumpers; extern consvar_t cv_kartfrantic; extern consvar_t cv_kartcomeback; extern consvar_t cv_kartencore; +extern consvar_t cv_kartvoterulechanges; extern consvar_t cv_kartspeedometer; extern consvar_t cv_kartvoices; diff --git a/src/g_game.c b/src/g_game.c index 15c9bab2..00a2828d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3113,14 +3113,48 @@ boolean G_BattleGametype(void) // INT16 G_SometimesGetDifferentGametype(void) { - if (randmapbuffer[NUMMAPS] != -1) + boolean encorepossible = (M_SecretUnlocked(SECRET_ENCORE) && G_RaceGametype()); + + if (!cv_kartvoterulechanges.value) // never + return gametype; + + if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3)) { - if (M_SecretUnlocked(SECRET_ENCORE) && (M_RandomChance(FRACUNIT/2/*56*/) != cv_kartencore.value) && G_RaceGametype()) - return (gametype|0x80); + if (cv_kartvoterulechanges.value != 1) + randmapbuffer[NUMMAPS]--; + if (encorepossible) + { + switch (cv_kartvoterulechanges.value) + { + case 3: // always + randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set + break; + case 2: // frequent + encorepossible = M_RandomChance(FRACUNIT>>1); + break; + case 1: // sometimes + default: + encorepossible = M_RandomChance(FRACUNIT>>3); + break; + } + if (encorepossible != cv_kartencore.value) + return (gametype|0x80); + } return gametype; } - randmapbuffer[NUMMAPS] = gametype; + switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv? + { + case 3: // always + randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible) + break; + case 1: // sometimes + default: + // fallthrough - happens when clearing buffer, but needs a reasonable countdown if cvar is modified + case 2: // frequent + randmapbuffer[NUMMAPS] = 5; // per "cup" + break; + } if (gametype == GT_MATCH) return GT_RACE; @@ -3188,6 +3222,7 @@ INT16 G_TOLFlag(INT32 pgametype) return INT16_MAX; } +#ifdef FLUSHMAPBUFFEREARLY static INT32 TOLMaps(INT16 tolflags) { INT32 num = 0; @@ -3205,6 +3240,7 @@ static INT32 TOLMaps(INT16 tolflags) return num; } +#endif /** Select a random map with the given typeoflevel flags. * If no map has those flags, this arbitrarily gives you map 1. @@ -3223,6 +3259,8 @@ INT16 G_RandMap(INT16 tolflags, INT16 pprevmap, boolean dontadd, boolean ignoreb if (!okmaps) okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL); +tryagain: + // Find all the maps that are ok and and put them in an array. for (ix = 0; ix < NUMMAPS; ix++) { @@ -3256,12 +3294,28 @@ INT16 G_RandMap(INT16 tolflags, INT16 pprevmap, boolean dontadd, boolean ignoreb okmaps[numokmaps++] = ix; } - if (numokmaps == 0) + if (numokmaps == 0) // If there's no matches... (Goodbye, incredibly silly function chains :V) { if (!ignorebuffer) - return G_RandMap(tolflags, pprevmap, dontadd, true, maphell, callagainsoon); // If there's no matches, (An incredibly silly function chain, buuut... :V) - if (maphell) - return G_RandMap(tolflags, pprevmap, dontadd, true, maphell-1, callagainsoon); + { + if (randmapbuffer[3] == -1) // Is the buffer basically empty? + { + ignorebuffer = true; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it + goto tryagain; //return G_RandMap(tolflags, pprevmap, dontadd, true, maphell, callagainsoon); + } + + for (bufx = 3; bufx < NUMMAPS; bufx++) // Let's clear all but the three most recent maps... + randmapbuffer[bufx] = -1; + if (cv_kartvoterulechanges.value == 1) // sometimes + randmapbuffer[NUMMAPS] = 0; + goto tryagain; //return G_RandMap(tolflags, pprevmap, dontadd, ignorebuffer, maphell, callagainsoon); + } + + if (maphell) // Any wiggle room to loosen our restrictions here? + { + maphell--; + goto tryagain; //return G_RandMap(tolflags, pprevmap, dontadd, true, maphell-1, callagainsoon); + } ix = 0; // Sorry, none match. You get MAP01. for (bufx = 0; bufx < NUMMAPS+1; bufx++) @@ -3423,11 +3477,15 @@ static void G_DoCompleted(void) automapactive = false; - if (randmapbuffer[TOLMaps(G_TOLFlag(gametype))-4] != -1) // we're getting pretty full, so lets clear it +#ifdef FLUSHMAPBUFFEREARLY + if (randmapbuffer[TOLMaps(G_TOLFlag(gametype))-5] != -1) // We're getting pretty full, so! -- no need for this, handled in G_RandMap { - for (i = 0; i < NUMMAPS+1; i++) + for (i = 3; i < NUMMAPS; i++) // Let's clear all but the three most recent maps... randmapbuffer[i] = -1; + if (cv_kartvoterulechanges.value == 1) // sometimes + randmapbuffer[NUMMAPS] = 0; } +#endif if (gametype != GT_COOP) { diff --git a/src/k_kart.c b/src/k_kart.c index b4c1e6ca..ae09c3ba 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -402,6 +402,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartfrantic); CV_RegisterVar(&cv_kartcomeback); CV_RegisterVar(&cv_kartencore); + CV_RegisterVar(&cv_kartvoterulechanges); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_kartvoices); CV_RegisterVar(&cv_karteliminatelast); diff --git a/src/m_menu.c b/src/m_menu.c index 1c4e9015..536edd20 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1474,14 +1474,15 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 40}, {IT_STRING | IT_CVAR, NULL, "Map Progression", &cv_advancemap, 50}, {IT_STRING | IT_CVAR, NULL, "Voting Timer", &cv_votetime, 60}, + {IT_STRING | IT_CVAR, NULL, "Voting Rule Changes", &cv_kartvoterulechanges, 70}, #ifndef NONET - {IT_STRING | IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 80}, - {IT_STRING | IT_CVAR, NULL, "Allow Players to Join", &cv_allownewplayer, 90}, - //{IT_STRING | IT_CVAR, NULL, "Join on Map Change", &cv_joinnextround, 100}, + {IT_STRING | IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 90}, + {IT_STRING | IT_CVAR, NULL, "Allow Players to Join", &cv_allownewplayer, 100}, + //{IT_STRING | IT_CVAR, NULL, "Join on Map Change", &cv_joinnextround, 110}, - {IT_STRING | IT_CVAR, NULL, "Allow WAD Downloading", &cv_downloading, 100}, - {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 110}, + {IT_STRING | IT_CVAR, NULL, "Allow WAD Downloading", &cv_downloading, 110}, + {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 120}, #endif }; diff --git a/src/y_inter.c b/src/y_inter.c index 77cea21f..f5e1ba6e 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1548,13 +1548,13 @@ static void Y_UnloadVoteData(void) // void Y_SetupVoteFinish(SINT8 pick, SINT8 level) { + if (!voteclient.loaded) + return; + if (pick == -1) // No other votes? We gotta get out of here, then! { - if (voteclient.loaded) - { - Y_EndVote(); - Y_FollowIntermission(); - } + Y_EndVote(); + Y_FollowIntermission(); return; } @@ -1600,11 +1600,8 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) } else if (endtype == 0) // Might as well put this here, too. { - if (voteclient.loaded) - { - Y_EndVote(); - Y_FollowIntermission(); - } + Y_EndVote(); + Y_FollowIntermission(); return; } else From b1db70b38a0f4039ed01cd652518fec5cd4cab89 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 12 Sep 2018 19:03:45 +0100 Subject: [PATCH 43/84] * Chao audience! * Replaces the CZ64-era hopping Mario guys. * ~50% randomised colours! * 1/9 are FANS! * On mapload, some Chao select a random player in the server (even spectators) as their idol. * The fans cheer for their idol when they cross the finish line in a winning position! * They also sob when their idol loses. * The remaining percentage are the canon Aqua. * Minor on-field spikeball/fake radius alterations requested by Oni. --- src/dehacked.c | 15 ++++------- src/info.c | 27 +++++++++---------- src/info.h | 15 ++++------- src/p_mobj.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/sounds.c | 1 + src/sounds.h | 1 + 6 files changed, 93 insertions(+), 37 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 6365453f..a6f3074d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6519,16 +6519,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Audience Members "S_RANDOMAUDIENCE", - "S_AUDIENCE_TOAD1", - "S_AUDIENCE_TOAD2", - "S_AUDIENCE_BOO1", - "S_AUDIENCE_BOO2", - "S_AUDIENCE_GMBA1", - "S_AUDIENCE_GMBA2", - "S_AUDIENCE_SHYG1", - "S_AUDIENCE_SHYG2", - "S_AUDIENCE_SNIF1", - "S_AUDIENCE_SNIF2", + "S_AUDIENCE_CHAO_CHEER1", + "S_AUDIENCE_CHAO_CHEER2", + "S_AUDIENCE_CHAO_WIN1", + "S_AUDIENCE_CHAO_WIN2", + "S_AUDIENCE_CHAO_LOSE", "S_FANCHAR_KOTE", "S_FANCHAR_RYAN", diff --git a/src/info.c b/src/info.c index e7c40cb9..554f410a 100644 --- a/src/info.c +++ b/src/info.c @@ -2831,18 +2831,15 @@ state_t states[NUMSTATES] = {SPR_POKE, 3, 2, {A_MoveAbsolute}, 180, 2, S_POKEY5}, // S_POKEY8 {SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POKEYIDLE - {SPR_NULL, 0, 1, {A_RandomStateRange}, S_AUDIENCE_TOAD1, S_AUDIENCE_SNIF1, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE + {SPR_NULL, 0, 1, {A_RandomStateRange}, S_AUDIENCE_CHAO_CHEER1, S_AUDIENCE_CHAO_CHEER2, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE - {SPR_AUDI, 0, 5, {NULL}, 0, 0, S_AUDIENCE_TOAD2}, // S_AUDIENCE_TOAD1 - {SPR_AUDI, 1, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_TOAD1}, // S_AUDIENCE_TOAD2 - {SPR_AUDI, 2, 5, {NULL}, 0, 0, S_AUDIENCE_BOO2}, // S_AUDIENCE_BOO1 - {SPR_AUDI, 3, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_BOO1}, // S_AUDIENCE_BOO2 - {SPR_AUDI, 4, 5, {NULL}, 0, 0, S_AUDIENCE_GMBA2}, // S_AUDIENCE_GMBA1 - {SPR_AUDI, 5, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_GMBA1}, // S_AUDIENCE_GMBA2 - {SPR_AUDI, 6, 5, {NULL}, 0, 0, S_AUDIENCE_SHYG2}, // S_AUDIENCE_SHYG1 - {SPR_AUDI, 7, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_SHYG1}, // S_AUDIENCE_SHYG2 - {SPR_AUDI, 8, 5, {NULL}, 0, 0, S_AUDIENCE_SNIF2}, // S_AUDIENCE_SNIF1 - {SPR_AUDI, 9, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_SNIF1}, // S_AUDIENCE_SNIF2 + {SPR_AUDI, 0, 5, {NULL}, 0, 0, S_AUDIENCE_CHAO_CHEER2}, // S_AUDIENCE_CHAO_CHEER1 + {SPR_AUDI, 1, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_CHAO_CHEER1}, // S_AUDIENCE_CHAO_CHEER2 + + {SPR_AUDI, 2, 5, {NULL}, 0, 0, S_AUDIENCE_CHAO_WIN2}, // S_AUDIENCE_CHAO_WIN1 + {SPR_AUDI, 3, 25, {A_BunnyHop}, 10, 0, S_AUDIENCE_CHAO_WIN1}, // S_AUDIENCE_CHAO_WIN2 + + {SPR_AUDI, 4|FF_ANIMATE, -1, {NULL}, 1, 17, S_NULL}, // S_AUDIENCE_CHAO_LOSE {SPR_AUDI, 10, -1, {NULL}, 0, 0, S_NULL}, // S_FANCHAR_KOTE {SPR_AUDI, 11, -1, {NULL}, 0, 0, S_NULL}, // S_FANCHAR_RYAN @@ -14691,7 +14688,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_kc2e, // deathsound 0, // speed - 16*FRACUNIT, // radius + 24*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass @@ -14772,7 +14769,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_s3k5d, // deathsound 64*FRACUNIT, // speed - 16*FRACUNIT, // radius + 24*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass @@ -15501,8 +15498,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 16*FRACUNIT, // radius - 40*FRACUNIT, // height + 8*FRACUNIT, // radius + 20*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage diff --git a/src/info.h b/src/info.h index 53b5809a..c5f98983 100644 --- a/src/info.h +++ b/src/info.h @@ -3366,16 +3366,11 @@ typedef enum state // Audience Members S_RANDOMAUDIENCE, - S_AUDIENCE_TOAD1, - S_AUDIENCE_TOAD2, - S_AUDIENCE_BOO1, - S_AUDIENCE_BOO2, - S_AUDIENCE_GMBA1, - S_AUDIENCE_GMBA2, - S_AUDIENCE_SHYG1, - S_AUDIENCE_SHYG2, - S_AUDIENCE_SNIF1, - S_AUDIENCE_SNIF2, + S_AUDIENCE_CHAO_CHEER1, + S_AUDIENCE_CHAO_CHEER2, + S_AUDIENCE_CHAO_WIN1, + S_AUDIENCE_CHAO_WIN2, + S_AUDIENCE_CHAO_LOSE, S_FANCHAR_KOTE, S_FANCHAR_RYAN, diff --git a/src/p_mobj.c b/src/p_mobj.c index 59b5c6cf..6c946e09 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8927,6 +8927,39 @@ void P_SceneryThinker(mobj_t *mobj) } P_CycleMobjState(mobj); + + if (mobj->type != MT_RANDOMAUDIENCE) + return; + + { + if (!mobj->colorized) // a fan of someone? + return; + + if (mobj->threshold >= 0) // not already happy or sad? + { + if (!playeringame[mobj->threshold] || players[mobj->threshold].spectator) // focused on a valid player? + return; + + if (!(players[mobj->threshold].exiting) && !(players[mobj->threshold].pflags & PF_TIMEOVER)) // not finished yet? + return; + + if (K_IsPlayerLosing(&players[mobj->threshold])) + mobj->threshold = -2; + else + { + mobj->threshold = -1; + S_StartSound(mobj, sfx_chaooo); + } + } + + if (mobj->threshold == -1) + mobj->angle += ANGLE_22h; + + if (((statenum_t)(mobj->state-states) != S_AUDIENCE_CHAO_CHEER2) || (mobj->tics != states[S_AUDIENCE_CHAO_CHEER2].tics)) // not at the start of your cheer jump? + return; + + P_SetMobjState(mobj, ((mobj->threshold == -1) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE)); + } } // @@ -9174,9 +9207,43 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } break; case MT_BIGRING: - mobj->destscale = 3*FRACUNIT; - P_SetScale(mobj, 3*FRACUNIT); + P_SetScale(mobj, (mobj->destscale = 3*FRACUNIT)); break; + case MT_RANDOMAUDIENCE: + { + fixed_t randu = P_RandomFixed(); + P_SetScale(mobj, (mobj->destscale <<= 1)); + if (randu < (FRACUNIT/9)) // a fan of someone? + { + UINT8 i, pcount = 0; + UINT8 pnum[MAXPLAYERS]; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + pnum[pcount] = i; + pcount++; + } + + if (pcount) + { + mobj->threshold = pnum[P_RandomKey(pcount)]; + mobj->color = players[mobj->threshold].skincolor; + mobj->colorized = true; + break; + } + } + + if (randu > (FRACUNIT/2)) + { + mobj->color = P_RandomKey(MAXSKINCOLORS-1)+1; + break; + } + + mobj->color = SKINCOLOR_AQUA; + break; + } default: break; } diff --git a/src/sounds.c b/src/sounds.c index 7c69eed7..938f35ea 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -813,6 +813,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"hogbom", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"ddash", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"mcitm1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"chaooo", false, 110, 24, -1, NULL, 0, -1, -1, LUMPERROR}, {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds diff --git a/src/sounds.h b/src/sounds.h index 13669e3a..9aaaf281 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -885,6 +885,7 @@ typedef enum sfx_hogbom, sfx_ddash, sfx_mcitm1, + sfx_chaooo, sfx_dbgsal, sfx_kwin, From 591ef1e3945849cf4bb0e722b1661ceb1d09742e Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Sep 2018 14:34:41 +0100 Subject: [PATCH 44/84] Make the chao quieter (if it's still too loud, I can tone it down further, but not by much) --- src/sounds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sounds.c b/src/sounds.c index 938f35ea..c30a3e52 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -813,7 +813,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"hogbom", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"ddash", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"mcitm1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, - {"chaooo", false, 110, 24, -1, NULL, 0, -1, -1, LUMPERROR}, + {"chaooo", false, 110, 64, -1, NULL, 0, -1, -1, LUMPERROR}, {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds From 395a83a56cd57ce3fc16b6cbf1d18c8ec8aec91f Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Sep 2018 14:36:48 +0100 Subject: [PATCH 45/84] Dark SPB background --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 32b4a894..270bdf8a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5652,7 +5652,7 @@ static void K_drawKartItem(void) case KITEM_JAWZ: localpatch = kp_jawz[offset]; break; case KITEM_MINE: localpatch = kp_mine[offset]; break; case KITEM_BALLHOG: localpatch = kp_ballhog[offset]; break; - case KITEM_SPB: localpatch = kp_selfpropelledbomb[offset]; break; + case KITEM_SPB: localpatch = kp_selfpropelledbomb[offset]; localbg = kp_itembg[offset+1]; break; case KITEM_GROW: localpatch = kp_grow[offset]; break; case KITEM_SHRINK: localpatch = kp_shrink[offset]; break; case KITEM_THUNDERSHIELD: localpatch = kp_thundershield[offset]; break; From fd721d37614533dac45ddda6b84bd8fc9f5c116b Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Sep 2018 14:40:50 +0100 Subject: [PATCH 46/84] Bugfix sad chao jumping in their sad state --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 6c946e09..c6bcc2ba 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8958,6 +8958,8 @@ void P_SceneryThinker(mobj_t *mobj) if (((statenum_t)(mobj->state-states) != S_AUDIENCE_CHAO_CHEER2) || (mobj->tics != states[S_AUDIENCE_CHAO_CHEER2].tics)) // not at the start of your cheer jump? return; + mobj->momz = 0; + P_SetMobjState(mobj, ((mobj->threshold == -1) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE)); } } From 57d333b6b552d22182d49cf0e66048e6876b5d1e Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Sep 2018 19:01:36 +0100 Subject: [PATCH 47/84] Thunder shield stuff! * Slightly bigger visual size! * Light-shadow! * Makes player fullbright if you have it! * Visuals finally removed instantly on shield drop! * Uses dark background for item icons! * Goes behind the player on some frames, faking layering! --- src/info.c | 50 +++++++++++++++++++++++++------------------------- src/k_kart.c | 7 +++++-- src/p_mobj.c | 43 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/info.c b/src/info.c index 554f410a..172439f7 100644 --- a/src/info.c +++ b/src/info.c @@ -2784,30 +2784,30 @@ state_t states[NUMSTATES] = {SPR_LIGH, 2, 2, {NULL}, 0, 0, S_LIGHTNING4}, // S_LIGHTNING3 {SPR_LIGH, 3, 2, {NULL}, 0, 0, S_NULL}, // S_LIGHTNING4 - {SPR_THNS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_THUNDERSHIELD2}, // S_THUNDERSHIELD1 - {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD3}, // S_THUNDERSHIELD2 - {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD4}, // S_THUNDERSHIELD3 - {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD5}, // S_THUNDERSHIELD4 - {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD6}, // S_THUNDERSHIELD5 - {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD7}, // S_THUNDERSHIELD6 - {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD8}, // S_THUNDERSHIELD7 - {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD9}, // S_THUNDERSHIELD8 - {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD10}, // S_THUNDERSHIELD9 - {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD11}, // S_THUNDERSHIELD10 - {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD12}, // S_THUNDERSHIELD11 - {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD13}, // S_THUNDERSHIELD12 - {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD14}, // S_THUNDERSHIELD13 - {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD15}, // S_THUNDERSHIELD14 - {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD16}, // S_THUNDERSHIELD15 - {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD17}, // S_THUNDERSHIELD16 - {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD18}, // S_THUNDERSHIELD17 - {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD19}, // S_THUNDERSHIELD18 - {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD20}, // S_THUNDERSHIELD19 - {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD21}, // S_THUNDERSHIELD20 - {SPR_THNS, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_THUNDERSHIELD22}, // S_THUNDERSHIELD21 - {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD23}, // S_THUNDERSHIELD22 - {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD24}, // S_THUNDERSHIELD23 - {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD1}, // S_THUNDERSHIELD24 + {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD2}, // S_THUNDERSHIELD1 + {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD3}, // S_THUNDERSHIELD2 + {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD4}, // S_THUNDERSHIELD3 + {SPR_THNS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_THUNDERSHIELD5}, // S_THUNDERSHIELD4 + {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD6}, // S_THUNDERSHIELD5 + {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD7}, // S_THUNDERSHIELD6 + {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD8}, // S_THUNDERSHIELD7 + {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD9}, // S_THUNDERSHIELD8 + {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD10}, // S_THUNDERSHIELD9 + {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD11}, // S_THUNDERSHIELD10 + {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD12}, // S_THUNDERSHIELD11 + {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD13}, // S_THUNDERSHIELD12 + {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD14}, // S_THUNDERSHIELD13 + {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD15}, // S_THUNDERSHIELD14 + {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD16}, // S_THUNDERSHIELD15 + {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD17}, // S_THUNDERSHIELD16 + {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD18}, // S_THUNDERSHIELD17 + {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD19}, // S_THUNDERSHIELD18 + {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD20}, // S_THUNDERSHIELD19 + {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD21}, // S_THUNDERSHIELD20 + {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD22}, // S_THUNDERSHIELD21 + {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD23}, // S_THUNDERSHIELD22 + {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD24}, // S_THUNDERSHIELD23 + {SPR_THNS, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_THUNDERSHIELD1}, // S_THUNDERSHIELD24 {SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK {SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD @@ -15255,7 +15255,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 16*FRACUNIT, // radius + 20*FRACUNIT, // radius 56*FRACUNIT, // height 1, // display offset 16, // mass diff --git a/src/k_kart.c b/src/k_kart.c index 270bdf8a..ed13612f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2985,6 +2985,7 @@ void K_DropHnextList(player_t *player) K_DoThunderShield(player); player->kartstuff[k_itemamount] = 0; player->kartstuff[k_itemtype] = KITEM_NONE; + player->kartstuff[k_curshield] = 0; } nextwork = work->hnext; @@ -3771,7 +3772,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) void K_KartPlayerAfterThink(player_t *player) { - if (player->kartstuff[k_invincibilitytimer] + if (player->kartstuff[k_curshield] + || player->kartstuff[k_invincibilitytimer] || (player->kartstuff[k_growshrinktimer] != 0 && player->kartstuff[k_growshrinktimer] % 5 == 4)) // 4 instead of 0 because this is afterthink! { player->mo->frame |= FF_FULLBRIGHT; @@ -4539,6 +4541,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_curshield] <= 0) { mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); P_SetTarget(&shield->target, player->mo); player->kartstuff[k_curshield] = 1; } @@ -5655,7 +5658,7 @@ static void K_drawKartItem(void) case KITEM_SPB: localpatch = kp_selfpropelledbomb[offset]; localbg = kp_itembg[offset+1]; break; case KITEM_GROW: localpatch = kp_grow[offset]; break; case KITEM_SHRINK: localpatch = kp_shrink[offset]; break; - case KITEM_THUNDERSHIELD: localpatch = kp_thundershield[offset]; break; + case KITEM_THUNDERSHIELD: localpatch = kp_thundershield[offset]; localbg = kp_itembg[offset+1]; break; case KITEM_HYUDORO: localpatch = kp_hyudoro[offset]; break; case KITEM_POGOSPRING: localpatch = kp_pogospring[offset]; break; case KITEM_KITCHENSINK: localpatch = kp_kitchensink[offset]; break; diff --git a/src/p_mobj.c b/src/p_mobj.c index c6bcc2ba..1381cefa 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6276,8 +6276,7 @@ static void P_RemoveOverlay(mobj_t *thing) void P_RunShadows(void) { - mobj_t *mobj; - mobj_t *next; + mobj_t *mobj, *next, *dest; for (mobj = shadowcap; mobj; mobj = next) { @@ -6322,7 +6321,12 @@ void P_RunShadows(void) // First scale to the same radius P_SetScale(mobj, FixedDiv(mobj->target->radius, mobj->info->radius)); - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); + dest = mobj->target; + + if (dest->type == MT_THUNDERSHIELD) + dest = dest->target; + + P_TeleportMove(mobj, dest->x, dest->y, mobj->target->z); if (((mobj->eflags & MFE_VERTICALFLIP) && (mobj->ceilingz > mobj->z+mobj->height)) || (!(mobj->eflags & MFE_VERTICALFLIP) && (mobj->floorz < mobj->z))) @@ -6340,7 +6344,7 @@ void P_RunShadows(void) P_SetScale(mobj, FixedDiv(mobj->scale, max(FRACUNIT, ((mobj->target->z-mobj->z)/200)+FRACUNIT))); // Check new position to see if you should still be on that ledge - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->z); + P_TeleportMove(mobj, dest->x, dest->y, mobj->z); mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : mobj->floorz); @@ -8301,13 +8305,41 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; case MT_THUNDERSHIELD: + { + fixed_t destx, desty; if (!mobj->target || !mobj->target->health || (mobj->target->player && mobj->target->player->kartstuff[k_curshield] != 1)) { P_RemoveMobj(mobj); return; } - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->destscale)>>2)); + + if (!splitscreen /*&& rendermode != render_soft*/) + { + angle_t viewingangle; + statenum_t curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); + + if (players[displayplayer].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); + else if (!camera.chase && players[displayplayer].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); + else + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera.x, camera.y); + + if (curstate > S_THUNDERSHIELD15) + viewingangle += ANGLE_180; + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); + desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); + } + else + { + destx = mobj->target->x; + desty = mobj->target->y; + } + + P_TeleportMove(mobj, destx, desty, mobj->target->z); break; + } case MT_KARMAHITBOX: if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator || (G_RaceGametype() || mobj->target->player->kartstuff[k_bumper])) @@ -9264,6 +9296,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_JAWZ: case MT_JAWZ_DUD: case MT_JAWZ_SHIELD: case MT_SSMINE: case MT_SSMINE_SHIELD: case MT_BALLHOG: case MT_SINK: + case MT_THUNDERSHIELD: P_SpawnShadowMobj(mobj); default: break; From ccc615e9b16eeab2e9c4f50a559233f3233506e0 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Sep 2018 20:41:12 +0100 Subject: [PATCH 48/84] Fix a potential crash vector in the shadows code. (It DEFINITELY crashed when I was testing the thunder shield, for example.) --- src/p_mobj.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1381cefa..79d9c994 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6283,8 +6283,11 @@ void P_RunShadows(void) next = mobj->hnext; P_SetTarget(&mobj->hnext, NULL); - if (!mobj->target) + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + mobj->flags2 |= MF2_DONTDRAW; continue; // shouldn't you already be dead? + } if ((mobj->target->flags2 & MF2_DONTDRAW) || (((mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z+mobj->target->height > mobj->target->ceilingz) From 32d64a8282361c1bb0721124e9ebed4c94a5ed74 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Sep 2018 20:51:30 +0100 Subject: [PATCH 49/84] Make these sparks fullbright (thanks, Ancient Tomb!) --- src/info.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/info.c b/src/info.c index 172439f7..9581f238 100644 --- a/src/info.c +++ b/src/info.c @@ -1756,11 +1756,11 @@ state_t states[NUMSTATES] = {SPR_IVSP, FF_ANIMATE, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP // Super Sonic Spark - {SPR_SSPK, 0, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1 - {SPR_SSPK, 1, 2, {NULL}, 0, 0, S_SSPK3}, // S_SSPK2 - {SPR_SSPK, 2, 2, {NULL}, 0, 0, S_SSPK4}, // S_SSPK3 - {SPR_SSPK, 1, 2, {NULL}, 0, 0, S_SSPK5}, // S_SSPK4 - {SPR_SSPK, 0, 2, {NULL}, 0, 0, S_NULL}, // S_SSPK5 + {SPR_SSPK, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1 + {SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK3}, // S_SSPK2 + {SPR_SSPK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK4}, // S_SSPK3 + {SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK5}, // S_SSPK4 + {SPR_SSPK, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_SSPK5 // Freed Birdie {SPR_BIRD, 0, 4, {NULL}, 0, 0, S_BIRD2}, // S_BIRD1 From 250c61dd00019ec38575c97e5572d8001c1c9f9b Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 13 Sep 2018 17:42:34 -0400 Subject: [PATCH 50/84] This is a sign Signpost with the face of the person in 1st falls down at a pre-determined location on race finish (or at the finishing player if none is found) --- src/dehacked.c | 1 + src/info.c | 42 +++++++++++++++++++++++++++++++++++------- src/info.h | 1 + src/p_mobj.c | 23 +++++++++++++++++++++++ src/p_spec.c | 27 +++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 54d87618..576695d0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7218,6 +7218,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BLUEDIAG", "MT_RANDOMITEM", "MT_RANDOMITEMPOP", + "MT_RINGSPARKLE", "MT_BOOSTFLAME", "MT_BOOSTSMOKE", diff --git a/src/info.c b/src/info.c index 47b9e2c7..89c9deb1 100644 --- a/src/info.c +++ b/src/info.c @@ -175,14 +175,15 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY // 1-Up Box Sprites (uses player sprite) - {SPR_PLAY, 35, 2, {NULL}, 0, 16, S_PLAY_BOX2}, // S_PLAY_BOX1 + // Kart: default to signpost just to ensure there are no missing sprite errors... + {SPR_PLAY, 24, 2, {NULL}, 0, 16, S_PLAY_BOX2}, // S_PLAY_BOX1 {SPR_NULL, 0, 1, {NULL}, 0, 0, S_PLAY_BOX1}, // S_PLAY_BOX2 - {SPR_PLAY, 35, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1 + {SPR_PLAY, 24, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1 {SPR_NULL, 0, 12, {NULL}, 0, 0, S_PLAY_ICON3}, // S_PLAY_ICON2 - {SPR_PLAY, 35, 18, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3 + {SPR_PLAY, 24, 18, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3 // Level end sign (uses player sprite) - {SPR_PLAY, 34, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN + {SPR_PLAY, 24, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN // Blue Crawla {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND @@ -1090,7 +1091,7 @@ state_t states[NUMSTATES] = {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN49}, // S_SIGN48 {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN50}, // S_SIGN49 {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN51}, // S_SIGN50 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN53}, // S_SIGN51 + {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN1}, // S_SIGN51 {SPR_SIGN, 3, -1, {NULL}, 0, 0, S_NULL}, // S_SIGN52 Eggman {SPR_SIGN, 7, -1, {A_SignPlayer}, 0, 0, S_NULL}, // S_SIGN53 Blank @@ -5796,7 +5797,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_SIGN 501, // doomednum - S_SIGN52, // spawnstate + S_INVISIBLE, // spawnstate 1000, // spawnhealth S_PLAY_SIGN, // seestate sfx_lvpass, // seesound @@ -5817,7 +5818,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOCLIP|MF_SCENERY, // flags + MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -14402,6 +14403,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_RINGSPARKLE + -1, // doomednum + S_SPRK1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 14*FRACUNIT, // radius + 14*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_BOOSTFLAME -1, // doomednum S_BOOSTFLAME, // spawnstate diff --git a/src/info.h b/src/info.h index b359bef5..432b3456 100644 --- a/src/info.h +++ b/src/info.h @@ -4082,6 +4082,7 @@ typedef enum mobj_type MT_BLUEDIAG, MT_RANDOMITEM, MT_RANDOMITEMPOP, + MT_RINGSPARKLE, MT_BOOSTFLAME, MT_BOOSTSMOKE, diff --git a/src/p_mobj.c b/src/p_mobj.c index 2c311bee..93fd864f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1409,6 +1409,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_SINK: gravityadd = FixedMul(gravityadd, 5*FRACUNIT); // Double gravity break; + case MT_SIGN: + gravityadd /= 3; + break; default: break; } @@ -8282,6 +8285,26 @@ void P_MobjThinker(mobj_t *mobj) } } break; + case MT_SIGN: // Kart's unique sign behavior + if (mobj->movecount) + { + if (mobj->z <= mobj->movefactor) + { + P_SetMobjState(mobj, S_SIGN53); + //mobj->flags |= MF_NOGRAVITY; // ? + mobj->flags &= ~MF_NOCLIPHEIGHT; + mobj->movecount = 0; + } + else + { + P_SpawnMobj(mobj->x + (P_RandomRange(-32,32)<y + (P_RandomRange(-32,32)<z + (24<flags &= ~MF_NOGRAVITY; + } + } + break; //} case MT_TURRET: P_MobjCheckWater(mobj); diff --git a/src/p_spec.c b/src/p_spec.c index 9e3393ac..e32deb7f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3227,6 +3227,11 @@ void P_SetupSignExit(player_t *player) if (thing->info->seesound) S_StartSound(thing, thing->info->seesound); + // SRB2Kart: Set sign spinning variables + thing->movefactor = thing->z; + thing->z += (512<movecount = 1; + ++numfound; } @@ -3252,8 +3257,29 @@ void P_SetupSignExit(player_t *player) if (thing->info->seesound) S_StartSound(thing, thing->info->seesound); + // SRB2Kart: Set sign spinning variables + thing->movefactor = thing->z; + thing->z += (512<movecount = 1; + ++numfound; } + + if (numfound) + return; + + // SRB2Kart: FINALLY, add in an alternative if no place is found + if (player->mo) + { + mobj_t *sign = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + (512<target, player->mo); + P_SetMobjState(sign, S_SIGN1); + if (sign->info->seesound) + S_StartSound(sign, sign->info->seesound); + sign->movefactor = player->mo->z; + sign->movecount = 1; + } } // @@ -4239,6 +4265,7 @@ DoneSection2: S_StartSound(NULL, sfx_s253); P_DoPlayerExit(player); + P_SetupSignExit(player); } } break; From ce85c2b7bda1ce32a839808f460cb66f6231deb3 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 13 Sep 2018 19:13:43 -0400 Subject: [PATCH 51/84] Delay falling, longer exit timer --- src/p_inter.c | 2 +- src/p_mobj.c | 2 +- src/p_spec.c | 6 +++--- src/p_tick.c | 4 ++-- src/p_user.c | 16 ++++++++-------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 6f3685d6..68124671 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -694,7 +694,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!playeringame[i] || players[i].spectator) continue; - players[i].exiting = (14*TICRATE)/5 + 1; + players[i].exiting = (21*TICRATE)/5 + 1; } S_StartSound(NULL, sfx_lvpass); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 93fd864f..38149f91 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1410,7 +1410,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) gravityadd = FixedMul(gravityadd, 5*FRACUNIT); // Double gravity break; case MT_SIGN: - gravityadd /= 3; + gravityadd /= 4; break; default: break; diff --git a/src/p_spec.c b/src/p_spec.c index e32deb7f..fc22c6bf 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3229,7 +3229,7 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: Set sign spinning variables thing->movefactor = thing->z; - thing->z += (512<z += (640<movecount = 1; ++numfound; @@ -3259,7 +3259,7 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: Set sign spinning variables thing->movefactor = thing->z; - thing->z += (512<z += (640<movecount = 1; ++numfound; @@ -3271,7 +3271,7 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: FINALLY, add in an alternative if no place is found if (player->mo) { - mobj_t *sign = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + (512<mo->x, player->mo->y, player->mo->z + (640<target, player->mo); P_SetMobjState(sign, S_SIGN1); diff --git a/src/p_tick.c b/src/p_tick.c index b9aaccf7..4cfba90f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -448,7 +448,7 @@ static inline void P_DoSpecialStageStuff(void) { if (playeringame[i]) { - players[i].exiting = (14*TICRATE)/5 + 1; + players[i].exiting = (21*TICRATE)/5 + 1; players[i].pflags &= ~PF_GLIDING; } @@ -485,7 +485,7 @@ static inline void P_DoSpecialStageStuff(void) if (playeringame[i]) { players[i].mo->momx = players[i].mo->momy = 0; - players[i].exiting = (14*TICRATE)/5 + 1; + players[i].exiting = (21*TICRATE)/5 + 1; } sstimer = 0; diff --git a/src/p_user.c b/src/p_user.c index f499b7ec..3120351c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -673,7 +673,7 @@ static void P_DeNightserizePlayer(player_t *player) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) players[i].nightstime = 1; // force everyone else to fall too. - player->exiting = 3*TICRATE; + player->exiting = 6*TICRATE; stagefailed = true; // NIGHT OVER } @@ -1741,7 +1741,7 @@ void P_DoPlayerExit(player_t *player) S_StartSound(player->mo, sfx_kwin); } - player->exiting = 3*TICRATE; + player->exiting = 6*TICRATE; if (cv_inttime.value > 0) P_EndingMusic(player); @@ -1751,7 +1751,7 @@ void P_DoPlayerExit(player_t *player) //countdown2 = countdown + 8*TICRATE; if (P_CheckRacers()) - player->exiting = (14*TICRATE)/5 + 1; + player->exiting = (21*TICRATE)/5 + 1; } else if (G_BattleGametype()) // Battle Mode exiting { @@ -1759,7 +1759,7 @@ void P_DoPlayerExit(player_t *player) P_EndingMusic(player); } else - player->exiting = (14*TICRATE)/5 + 2; // Accidental death safeguard??? + player->exiting = (21*TICRATE)/5 + 2; // Accidental death safeguard??? //player->pflags &= ~PF_GLIDING; /* // SRB2kart - don't need @@ -6569,7 +6569,7 @@ static void P_MovePlayer(player_t *player) S_StartSound(NULL, sfx_s3k6a); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) - players[i].exiting = (14*TICRATE)/5 + 1; + players[i].exiting = (21*TICRATE)/5 + 1; } else if (player->health > 1) P_DamageMobj(player->mo, NULL, NULL, 1); @@ -9037,8 +9037,8 @@ void P_PlayerThink(player_t *player) } } - if (i == MAXPLAYERS && player->exiting == 3*TICRATE) // finished - player->exiting = (14*TICRATE)/5 + 1; + if (i == MAXPLAYERS && player->exiting == 6*TICRATE) // finished + player->exiting = (21*TICRATE)/5 + 1; // If 10 seconds are left on the timer, // begin the drown music for countdown! @@ -9063,7 +9063,7 @@ void P_PlayerThink(player_t *player) // If it is set, start subtracting // Don't allow it to go back to 0 - if (player->exiting > 1 && (player->exiting < 3*TICRATE || !G_RaceGametype())) // SRB2kart - "&& player->exiting > 1" + if (player->exiting > 1 && (player->exiting < 6*TICRATE || !G_RaceGametype())) // SRB2kart - "&& player->exiting > 1" player->exiting--; if (player->exiting && countdown2) From fadef55b1e5d295105a9d06d93619c2d5f2c71d2 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 14 Sep 2018 00:19:23 +0100 Subject: [PATCH 52/84] angel island drift strat plus ketchup --- src/d_player.h | 1 + src/dehacked.c | 4 ++++ src/info.c | 31 ++++++++++++++++++++++++- src/info.h | 6 +++++ src/k_kart.c | 63 ++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 97 insertions(+), 8 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 822ea305..373110dd 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -305,6 +305,7 @@ typedef enum k_accelboost, // Boost value smoothing for acceleration k_boostcam, // Camera push forward on boost k_destboostcam, // Ditto + k_aizdriftstrat, // Let go of your drift while boosting? Helper for the SICK STRATZ you have just unlocked k_itemroulette, // Used for the roulette when deciding what item to give you (was "pw_kartitem") k_roulettetype, // Used for the roulette, for deciding type (currently only used for Battle, to give you better items from Karma items) diff --git a/src/dehacked.c b/src/dehacked.c index 4658108a..fc0529a9 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6271,6 +6271,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_KARTFIRE7", "S_KARTFIRE8", + // Angel Island Drift Strat Dust (what a mouthful!) + "S_KARTAIZDRIFTSTRAT", + // Invincibility Sparks "S_KARTINVULN_SMALL1", "S_KARTINVULN_SMALL2", @@ -7220,6 +7223,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BOOSTFLAME", "MT_BOOSTSMOKE", "MT_SNEAKERTRAIL", + "MT_AIZDRIFTSTRAT", "MT_SPARKLETRAIL", "MT_INVULNFLASH", "MT_WIPEOUTTRAIL", diff --git a/src/info.c b/src/info.c index 9581f238..b0783a69 100644 --- a/src/info.c +++ b/src/info.c @@ -60,7 +60,7 @@ char sprnames[NUMSPRITES + 1][5] = "BLIG","LIGH","THNS","SINK","SITR","KBLN","DEZL","POKE","AUDI","DECO", "DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO","CRAB","SHAD","BRNG", "BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM","ITMO","ITMI", - "ITMN","WANT","PBOM","RETI","VIEW" + "ITMN","WANT","PBOM","RETI","AIDU","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -2601,6 +2601,8 @@ state_t states[NUMSTATES] = {SPR_KFRE, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_KARTFIRE8}, // S_KARTFIRE7 {SPR_KFRE, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_NULL}, // S_KARTFIRE8 + {SPR_AIDU, FF_ANIMATE|FF_PAPERSPRITE, 5*2, {NULL}, 5, 2, S_NULL}, // S_KARTAIZDRIFTSTRAT + {SPR_KINV, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_KARTINVULN_SMALL2}, // S_KARTINVULN_SMALL1 {SPR_KINV, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_KARTINVULN_SMALL3}, // S_KARTINVULN_SMALL2 {SPR_KINV, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_KARTINVULN_SMALL4}, // S_KARTINVULN_SMALL3 @@ -14509,6 +14511,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_AIZDRIFTSTRAT + -1, // doomednum + S_KARTAIZDRIFTSTRAT,// spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 14*FRACUNIT, // radius + 14*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_SPARKLETRAIL -1, // doomednum S_KARTINVULN_SMALL1, // spawnstate diff --git a/src/info.h b/src/info.h index c5f98983..13498810 100644 --- a/src/info.h +++ b/src/info.h @@ -641,6 +641,8 @@ typedef enum sprite SPR_PBOM, // player bomb SPR_RETI, // player reticule + SPR_AIDU, + SPR_VIEW, // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw! SPR_FIRSTFREESLOT, @@ -3118,6 +3120,9 @@ typedef enum state S_KARTFIRE7, S_KARTFIRE8, + // Angel Island Drift Strat Dust (what a mouthful!) + S_KARTAIZDRIFTSTRAT, + // Invincibility Sparks S_KARTINVULN_SMALL1, S_KARTINVULN_SMALL2, @@ -4084,6 +4089,7 @@ typedef enum mobj_type MT_BOOSTFLAME, MT_BOOSTSMOKE, MT_SNEAKERTRAIL, + MT_AIZDRIFTSTRAT, MT_SPARKLETRAIL, MT_INVULNFLASH, MT_WIPEOUTTRAIL, diff --git a/src/k_kart.c b/src/k_kart.c index ed13612f..6ab905dc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2271,7 +2271,7 @@ static void K_SpawnDriftSparks(player_t *player) if (player->kartstuff[k_driftcharge] <= (K_GetKartDriftSparkValue(player)*2)+(32*3)) spark->color = SKINCOLOR_DUSK; // transition else - spark->color = SKINCOLOR_RUBY; + spark->color = SKINCOLOR_KETCHUP; } else spark->color = SKINCOLOR_SAPPHIRE; @@ -2306,6 +2306,46 @@ static void K_SpawnDriftSparks(player_t *player) } } +static void K_SpawnAIZDust(player_t *player) +{ + fixed_t newx; + fixed_t newy; + mobj_t *spark; + angle_t travelangle; + + I_Assert(player != NULL); + I_Assert(player->mo != NULL); + I_Assert(!P_MobjWasRemoved(player->mo)); + + if (leveltime % 2 == 1) + return; + + if (!P_IsObjectOnGround(player->mo)) + return; + + travelangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + + { + newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle - (player->kartstuff[k_aizdriftstrat]*ANGLE_45), FixedMul(24*FRACUNIT, player->mo->scale)); + newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle - (player->kartstuff[k_aizdriftstrat]*ANGLE_45), FixedMul(24*FRACUNIT, player->mo->scale)); + spark = P_SpawnMobj(newx, newy, player->mo->z, MT_AIZDRIFTSTRAT); + + spark->angle = travelangle+(player->kartstuff[k_aizdriftstrat]*ANGLE_90); + P_SetScale(spark, (spark->destscale = (3*player->mo->scale)>>2)); + + spark->momx = (6*player->mo->momx)/5; + spark->momy = (6*player->mo->momy)/5; + //spark->momz = player->mo->momz/2; + + spark->flags2 = (spark->flags2 & ~MF2_DONTDRAW)|(player->mo->eflags & MF2_DONTDRAW); + spark->eflags = (spark->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); + spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP1)|(player->mo->eflags & MFE_DRAWONLYFORP1); + spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP2)|(player->mo->eflags & MFE_DRAWONLYFORP2); + spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP3)|(player->mo->eflags & MFE_DRAWONLYFORP3); + spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP4)|(player->mo->eflags & MFE_DRAWONLYFORP4); + } +} + void K_SpawnBoostTrail(player_t *player) { fixed_t newx; @@ -3947,16 +3987,14 @@ static void K_KartDrift(player_t *player, boolean onground) { // Starting left drift player->kartstuff[k_drift] = 1; - player->kartstuff[k_driftend] = 0; - player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0; } else if ((player->cmd.driftturn < 0) && player->speed > FixedMul(10<<16, player->mo->scale) && player->kartstuff[k_jmp] == 1 && (player->kartstuff[k_drift] == 0 || player->kartstuff[k_driftend] == 1)) // && player->kartstuff[k_drift] != -1) { // Starting right drift player->kartstuff[k_drift] = -1; - player->kartstuff[k_driftend] = 0; - player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0; } else if (player->kartstuff[k_jmp] == 0) // || player->kartstuff[k_turndir] == 0) { @@ -4015,9 +4053,20 @@ static void K_KartDrift(player_t *player, boolean onground) if (player->kartstuff[k_spinouttimer] > 0 // banana peel || player->speed < FixedMul(10<<16, player->mo->scale)) // you're too slow! { - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = player->kartstuff[k_aizdriftstrat] = 0; } + + if ((!player->kartstuff[k_sneakertimer]) + || (!player->cmd.driftturn) + || (player->cmd.driftturn > 0) != (player->kartstuff[k_aizdriftstrat] > 0)) + { + if (!player->kartstuff[k_drift]) + player->kartstuff[k_aizdriftstrat] = 0; + else + player->kartstuff[k_aizdriftstrat] = ((player->kartstuff[k_drift] > 0) ? 1 : -1); + } + else if (player->kartstuff[k_aizdriftstrat] && !player->kartstuff[k_drift]) + K_SpawnAIZDust(player); } // // K_KartUpdatePosition From 6c6ca1a11000c05f45496f311e5c25d157b5d431 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 13 Sep 2018 23:49:24 -0400 Subject: [PATCH 53/84] Bug fix --- src/p_spec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index fc22c6bf..cba294e6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3213,6 +3213,9 @@ void P_SetupSignExit(player_t *player) thinker_t *think; INT32 numfound = 0; + if (player->kartstuff[k_position] != 1) + return; + for (; node; node = node->m_thinglist_next) { thing = node->m_thing; From 6532c9ccf7176f5cb64d3a6a4e288760eb629d0c Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 14 Sep 2018 00:29:39 -0400 Subject: [PATCH 54/84] Add to DeHackEd! --- src/dehacked.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dehacked.c b/src/dehacked.c index fc0529a9..4621357a 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7703,6 +7703,7 @@ static const char *const KARTSTUFF_LIST[] = { "ACCELBOOST", "BOOSTCAM", "DESTBOOSTCAM", + "AIZDRIFTSTRAT", "ITEMROULETTE", "ROULETTETYPE", From 0bb24a392eb5bb5754cb25705e3e07c336cdc83c Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Sun, 16 Sep 2018 11:01:00 +0200 Subject: [PATCH 55/84] Fixed crash when replacing first character. --- src/hu_stuff.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 29303157..794a89d7 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -856,6 +856,9 @@ static inline boolean HU_keyInChatString(char *s, char ch) { if (s[m]) s[m+1] = (s[m]); + + if (m < 1) + break; // fix the chat going ham if your replace the first character. (For whatever reason this didn't happen in vanilla????) } s[c_input] = ch; // and replace this. } From a1045d232bc488e2dd61884916560ac228a5434f Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Sep 2018 17:40:39 +0100 Subject: [PATCH 56/84] :boi: (fix driftsparks, and subsequently sliptides because i copypasted most of the code for them, disappearing underwater) --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 6ab905dc..b294b9f5 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2297,7 +2297,7 @@ static void K_SpawnDriftSparks(player_t *player) P_SetMobjState(spark, S_DRIFTSPARK_A1); } - spark->flags2 = (spark->flags2 & ~MF2_DONTDRAW)|(player->mo->eflags & MF2_DONTDRAW); + spark->flags2 = (spark->flags2 & ~MF2_DONTDRAW)|(player->mo->flags2 & MF2_DONTDRAW); spark->eflags = (spark->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP1)|(player->mo->eflags & MFE_DRAWONLYFORP1); spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP2)|(player->mo->eflags & MFE_DRAWONLYFORP2); @@ -2337,7 +2337,7 @@ static void K_SpawnAIZDust(player_t *player) spark->momy = (6*player->mo->momy)/5; //spark->momz = player->mo->momz/2; - spark->flags2 = (spark->flags2 & ~MF2_DONTDRAW)|(player->mo->eflags & MF2_DONTDRAW); + spark->flags2 = (spark->flags2 & ~MF2_DONTDRAW)|(player->mo->flags2 & MF2_DONTDRAW); spark->eflags = (spark->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP1)|(player->mo->eflags & MFE_DRAWONLYFORP1); spark->eflags = (spark->eflags & ~MFE_DRAWONLYFORP2)|(player->mo->eflags & MFE_DRAWONLYFORP2); From cb629303d6580fea25a5e440b3a4159dd444407f Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Sep 2018 19:37:03 +0100 Subject: [PATCH 57/84] Update a bunch of icons - `SDL_icon.xpm` and other targets' `.ico`s. --- src/sdl/SDL_icon.xpm | 499 +++++++++++++++++++++++----------------- src/sdl/Srb2SDL.ico | Bin 372798 -> 82992 bytes src/sdl12/Srb2SDL.ico | Bin 372798 -> 82992 bytes src/win32ce/Srb2win.ico | Bin 372798 -> 82992 bytes 4 files changed, 289 insertions(+), 210 deletions(-) diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm index 30259d55..17eb78dd 100644 --- a/src/sdl/SDL_icon.xpm +++ b/src/sdl/SDL_icon.xpm @@ -1,213 +1,292 @@ /* XPM */ static const char *SDL_icon_xpm[] = { /* columns rows colors chars-per-pixel */ -"32 32 175 2 ", -" c None", -". c #2E2E2E", -"X c #3C3C3C", -"o c #493939", -"O c #4E473F", -"+ c #161658", -"@ c #131369", -"# c #06067B", -"$ c #111173", -"% c #16167F", -"& c #252567", -"* c #372B7C", -"= c #3D3679", -"- c #41414A", -"; c #575655", -": c #6A5841", -"> c #5B4B72", -", c #616160", -"< c #7B7B7B", -"1 c #906E49", -"2 c #89685D", -"3 c #A67B4A", -"4 c #AA7F50", -"5 c #9B7560", -"6 c #856C78", -"7 c #997B7D", -"8 c #B48552", -"9 c #BA8A55", -"0 c #A48665", -"q c #B98F67", -"w c #B9946A", -"e c #B7937A", -"r c #C8955C", -"t c #CA9966", -"y c #DAA469", -"u c #C9A37B", -"i c #D7AB7B", -"p c #DFB07D", -"a c #EBAE6A", -"s c #E5B27A", -"d c #F1B779", -"f c #0A0A83", -"g c #05058B", -"h c #060687", -"j c #101089", -"k c #131382", -"l c #040494", -"z c #02029D", -"x c #0C0B9C", -"c c #120F9E", -"v c #19199B", -"b c #382D84", -"n c #39398D", -"m c #222296", -"M c #0101A6", -"N c #0A0AA2", -"B c #0202AC", -"V c #1919A2", -"C c #1616AD", -"Z c #0000B5", -"A c #0202BC", -"S c #0C0CB6", -"D c #1313B3", -"F c #1011BD", -"G c #1B1BBE", -"H c #2B2BAC", -"J c #3737A1", -"K c #2A26BE", -"L c #2A29B4", -"P c #3B3BB8", -"I c #48478B", -"U c #57578A", -"Y c #4A499A", -"T c #524F95", -"R c #565399", -"E c #4C4CA8", -"W c #524DA7", -"Q c #5353A4", -"! c #5555A9", -"~ c #5555B4", -"^ c #5656B7", -"/ c #6464A6", -"( c #6F67B5", -") c #0404C3", -"_ c #0707CA", -"` c #1414CB", -"' c #1A1AC6", -"] c #0A0AD3", -"[ c #0D0DDC", -"{ c #1A1AD4", -"} c #1010DF", -"| c #1E1EDE", -" . c #1817DE", -".. c #221FCA", -"X. c #2B2BCC", -"o. c #2727C9", -"O. c #3434C3", -"+. c #3434D4", -"@. c #0F0FE2", -"#. c #1313E5", -"$. c #1515ED", -"%. c #1B1BEA", -"&. c #1C1CE4", -"*. c #1515F4", -"=. c #1818F3", -"-. c #1717FD", -";. c #1818FF", -":. c #2B2BE9", -">. c #2424FF", -",. c #2A2AFF", -"<. c #2222F1", -"1. c #3737FF", -"2. c #5D5DC3", -"3. c #5F5FC9", -"4. c #5655C2", -"5. c #4747D1", -"6. c #5B5BD4", -"7. c #6565C8", -"8. c #6363DA", -"9. c #4545FF", -"0. c #4D4DFC", -"q. c #5454FF", -"w. c #5959FF", -"e. c #6969E5", -"r. c #6B6CEA", -"t. c #6666E7", -"y. c #6B6BFE", -"u. c #6767F8", -"i. c #7070F6", -"p. c #7373FF", -"a. c #7C7CFF", -"s. c #91918F", -"d. c #8F9090", -"f. c #979797", -"g. c #9C9C9C", -"h. c #8585A1", -"j. c #9C9CA7", -"k. c #9292B6", -"l. c #A4A4A4", -"z. c #BDB2A4", -"x. c #A4A4B1", -"c. c #BFBFBD", -"v. c #BABAB7", -"b. c #C8AA87", -"n. c #DAAE82", -"m. c #DBB081", -"M. c #EBBA85", -"N. c #F3BF84", -"B. c #F2BE88", -"V. c #C2B3A3", -"C. c #FBC386", -"Z. c #FCC68C", -"A. c #FFC88F", -"S. c #F4C387", -"D. c #FFC990", -"F. c #C3C1BF", -"G. c #8F8FCB", -"H. c #BDBDC2", -"J. c #BDBDD1", -"K. c #8888F9", -"L. c #A4A4FB", -"P. c #CDCDCC", -"I. c #CECAC6", -"U. c #D3CFCA", -"Y. c #D3D0CC", -"T. c #C0C0D5", -"R. c #D6D5D4", -"E. c #D7D7DD", -"W. c #E1E1DF", -"Q. c #DEDEE1", -"!. c #E4E4E4", -"~. c #E8E8E8", -"^. c #F0F0EE", -"/. c #F5F5F2", -"(. c #FFFFFF", -/* pixels */ -" ", -" ", -" ", -" I Q T = ", -" Q 7.e.r.i.8.E E 3.r.6.J ", -" H ~ n 4.r.p.p.p.p.8.R > 5.^ w.,.-.{ v ", -" { 9.^ & P t.p.p.p.p.p.8.I 5 q K L <.;.;.;.-.' ", -" { %.H +.y.p.p.p.p.p.e.Y 2 a n.K F $.*.$.@.} ] N ", -" x D :.y.p.p.p.p.p.p.r.R 8 C.u ..F A ) A Z M h $ ", -" f =.q.p.p.p.p.p.p.p.p.i.( e 6 $.` l B M g ", -" ` ;.q.p.p.p.p.p.a.K.a.p.p.4.L -.` l N % ", -" V =.-.>.q.y.p.p.p.L.L.K.i.w.,.-.;.$.<.q.u.2. ", -" D { =.-.;.>.1.1.9.( h.h.Q &.-.-.-.;.9.p.p.p.r.! ", -" U j.o.-.;.-.;.-.P x.Q.^.R.~ *.-.;.;.>.1.q.y.p.i.2. ", -" H./.! *.;.;.;.o.x./.(.(.(.J.| -.-.;.-.-.;.,.9.u.p.7. ", -" !.(.k.#.;.-.=./ !.(.(.(.(.Q.X.-.;.;.;.;.-.-.;.;.1.w.6. ", -" ~.(.H.G ;.-.D j.(.(.(.(.(.!.O.-.-.;.;.;.-.;.-.;.-.;.,.O. ", -" ~.(.v.@ *.$.+ d.(.(.(.(.(.E.o.-.-.;.;.-.;.;.;.*.=.=.*.$.v ", -" ~.(.l.- Y T ; < (.(.(.(.(.J.&.-.;.;.$.@.[ ] _ ) ) Z B B f ", -" P.(.F.X c.I.X f.(.(.(.(.(.G.=.-.=.] A Z Z Z Z z f $ ", -" l.!.R.s.F.I.g.W.(.(.(.(.R.E .[ A Z Z Z B g $ ", -" . , ; - 0 M.b.V.U.R.Y.z.u n.7 c Z Z B g # + ", -" : w p Z.D.A.S.p u i M.A.A.S.* Z B h z ] C ", -" s D.D.A.A.A.A.A.A.A.i B.B.b A Z Z @.-.` ", -" 1 y C.D.A.A.A.A.A.M.u Z.e c A Z Z [ ;.&. ", -" 8 y d C.A.A.A.C.B.t * B Z Z Z A #.=.m ", -" 3 9 r t r 9 8 o @ $ # f j l B #.V ", -" j k ", -" ", -" ", -" ", -" " -}; +"256 256 32 1", +" c None", +". c #E7E7E7", +"+ c #DFDFDF", +"@ c #AFAFAF", +"# c #979797", +"$ c #8F8F8F", +"% c #B7B7B7", +"& c #F7F7F7", +"* c #D7D7D7", +"= c #4F4F4F", +"- c #0F0F0F", +"; c #070707", +"> c #575757", +", c #C7C7C7", +"' c #676767", +") c #7F7F7F", +"! c #5F5F5F", +"~ c #777777", +"{ c #474747", +"] c #878787", +"^ c #6F6F6F", +"/ c #BFBFBF", +"( c #373737", +"_ c #1F1F1F", +": c #272727", +"< c #2F2F2F", +"[ c #3F3F3F", +"} c #EFEFEF", +"| c #A7A7A7", +"1 c #9F9F9F", +"2 c #171717", +"3 c #CFCFCF", +" ", +" ", +" ", +" ", +" ................................................................................ ", +" ................................................................................ ", +" ................................................................................ ", +" ................................................................................ ", +" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", +" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", +" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", +" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", +" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", +" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", +" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", +" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", +" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", +" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", +" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", +" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", +" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", +" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", +" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", +" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", +" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", +" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", +" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", +" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", +" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", +" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", +" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", +" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", +" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", +" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", +" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", +" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", +" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", +" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", +" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", +" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", +" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", +" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", +" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", +" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", +" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", +" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", +" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", +" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", +" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", +" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", +" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", +" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", +" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", +" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", +" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", +" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", +" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", +" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", +" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", +" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", +" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", +" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", +" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", +" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", +" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", +" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", +" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", +" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", +" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", +" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", +" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", +" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", +" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", +" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", +" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", +" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", +" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", +" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", +" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", +" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", +" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", +" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", +" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", +" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", +" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", +" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", +" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", +" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", +" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", +" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", +" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", +" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", +" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", +" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", +" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", +" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", +" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", +" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", +" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", +" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", +" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", +" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", +" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", +" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", +" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", +" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", +" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", +" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", +" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", +" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", +" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", +" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", +" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", +" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", +" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", +" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", +" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", +" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", +" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", +" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", +" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", +" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", +" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", +" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", +" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", +" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", +" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", +" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", +" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", +" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", +" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", +" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", +" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", +" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", +" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", +" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", +" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", +" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", +" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", +" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", +" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", +" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", +" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", +" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", +" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", +" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", +" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", +" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", +" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", +" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", +" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", +" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", +" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", +" ....####____________________________####____________________::::<<<<________________~~~~........ ", +" ....####____________________________####____________________::::<<<<________________~~~~........ ", +" ....####____________________________####____________________::::<<<<________________~~~~........ ", +" ....####____________________________####____________________::::<<<<________________~~~~........ ", +" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", +" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", +" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", +" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", +" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", +" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", +" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", +" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", +" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", +" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", +" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", +" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", +" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", +" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", +" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", +" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", +" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", +" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", +" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", +" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", +" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", +" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", +" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", +" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", +" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", +" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", +" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", +" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", +" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", +" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", +" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", +" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", +" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", +" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", +" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", +" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", +" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", +" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", +" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", +" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", +" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", +" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", +" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", +" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", +" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", +" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", +" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", +" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", +" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", +" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", +" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", +" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", +" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", +" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", +" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", +" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", +" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", +" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", +" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", +" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", +" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", +" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", +" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", +" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", +" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", +" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", +" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", +" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", +" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", +" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", +" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", +" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", +" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", +" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", +" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", +" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", +" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", +" ............................................................................ ", +" ............................................................................ ", +" ............................................................................ ", +" ............................................................................ ", +" ", +" ", +" ", +" "}; diff --git a/src/sdl/Srb2SDL.ico b/src/sdl/Srb2SDL.ico index 700276fd4b9ac2810a6981eb054921f3708c702b..6e667b61c84414bc9758ea57721bb07d85a62083 100644 GIT binary patch literal 82992 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 G1OE?SzcGja diff --git a/src/sdl12/Srb2SDL.ico b/src/sdl12/Srb2SDL.ico index 700276fd4b9ac2810a6981eb054921f3708c702b..6e667b61c84414bc9758ea57721bb07d85a62083 100644 GIT binary patch literal 82992 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 G1OE?SzcGja diff --git a/src/win32ce/Srb2win.ico b/src/win32ce/Srb2win.ico index 700276fd4b9ac2810a6981eb054921f3708c702b..6e667b61c84414bc9758ea57721bb07d85a62083 100644 GIT binary patch literal 82992 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 G1OE?SzcGja From e90139c5b3b4a7f5690935bb5238dfcb0cc42b60 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 20 Sep 2018 17:45:09 +0100 Subject: [PATCH 58/84] :shitsfree: --- src/m_menu.c | 25 ++++++++++++++++++++++++- src/sounds.c | 1 + src/sounds.h | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index da45ea8a..847e126d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8516,6 +8516,8 @@ static consvar_t *kartitemcvs[NUMKARTRESULTS-1] = { &cv_dualjawz }; +static tic_t shitsfree = 0; + static void M_DrawMonitorToggles(void) { const INT32 edges = 4; @@ -8632,7 +8634,18 @@ static void M_DrawMonitorToggles(void) { #ifdef ITEMTOGGLEBOTTOMRIGHT if (currentMenu->menuitems[itemOn].alphaKey == 255) + { V_DrawScaledPatch(onx-1, ony-2, V_TRANSLUCENT, W_CachePatchName("K_ITBG", PU_CACHE)); + if (shitsfree) + { + INT32 trans = V_TRANSLUCENT; + if (shitsfree-1 > TICRATE-5) + trans = ((10-TICRATE)+shitsfree-1)<menuitems[itemOn].alphaKey == 0) @@ -8679,6 +8692,9 @@ static void M_DrawMonitorToggles(void) } } + if (shitsfree) + shitsfree--; + V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, highlightflags, va("* %s *", currentMenu->menuitems[itemOn].text)); } @@ -8739,7 +8755,14 @@ static void M_HandleMonitorToggles(INT32 choice) case KEY_ENTER: #ifdef ITEMTOGGLEBOTTOMRIGHT if (currentMenu->menuitems[itemOn].alphaKey == 255) - S_StartSound(NULL, sfx_lose); + { + //S_StartSound(NULL, sfx_lose); + if (!shitsfree) + { + shitsfree = TICRATE; + S_StartSound(NULL, sfx_itfree); + } + } else #endif if (currentMenu->menuitems[itemOn].alphaKey == 0) diff --git a/src/sounds.c b/src/sounds.c index 921450d6..e717574a 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -813,6 +813,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"hogbom", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"kpogos", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"ddash", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds diff --git a/src/sounds.h b/src/sounds.h index 8e065e69..173b13b4 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -885,6 +885,7 @@ typedef enum sfx_hogbom, sfx_kpogos, sfx_ddash, + sfx_itfree, sfx_dbgsal, sfx_kwin, From 1a2f84a5ba76d7644617ada019e76108c663218d Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 20 Sep 2018 22:36:01 +0100 Subject: [PATCH 59/84] Smaller XPM with no redundant pixels --- src/sdl/SDL_icon.xpm | 322 +++++++++---------------------------------- 1 file changed, 65 insertions(+), 257 deletions(-) diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm index 17eb78dd..0acac88e 100644 --- a/src/sdl/SDL_icon.xpm +++ b/src/sdl/SDL_icon.xpm @@ -1,7 +1,7 @@ /* XPM */ static const char *SDL_icon_xpm[] = { /* columns rows colors chars-per-pixel */ -"256 256 32 1", +"64 64 32 1", " c None", ". c #E7E7E7", "+ c #DFDFDF", @@ -34,259 +34,67 @@ static const char *SDL_icon_xpm[] = { "1 c #9F9F9F", "2 c #171717", "3 c #CFCFCF", -" ", -" ", -" ", -" ", -" ................................................................................ ", -" ................................................................................ ", -" ................................................................................ ", -" ................................................................................ ", -" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", -" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", -" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", -" ............++++@@@@########$$$$$$$$$$$$$$$$############@@@@%%%%&&&&............................ ", -" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", -" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", -" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", -" ........****====----;;;;;;;;;;;;----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@................................ ", -" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", -" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", -" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", -" ........++++----;;;;;;;;;;;;;;;;--------;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>........................................ ", -" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", -" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", -" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", -" ............,,,,''''))))!!!!!!!!''''~~~~>>>>{{{{!!!!))))$$$$))))>>>>''''................****]]]]>>>>^^^^%%%%&&&&........ ", -" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", -" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", -" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", -" ........////((((________((((>>>>::::{{{{<<<<))))$$$$!!!![[[[[[[[[[[[%%%%&&&&............^^^^!!!!!!!!!!!!!!!!!!!!~~~~****.... ", -" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", -" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", -" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", -" ........@@@@;;;;;;;;;;;;;;;;;;;;(((({{{{====]]]]::::;;;;;;;;;;;;;;;;;;;;~~~~........****____;;;;;;;;;;;;;;;;;;;;;;;;;;;;____........ ", -" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", -" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", -" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", -" ....}}}}>>>>;;;;;;;;;;;;;;;;;;;;^^^^####====;;;;;;;;;;;;;;;;;;;;;;;;>>>>............<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;||||........ ", -" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", -" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", -" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", -" ........****1111))))))))))))))))))))%%%%]]]]))))))))))))))))))))))))%%%%&&&&........1111]]]]))))))))))))))))))))))))))))))))))))####}}}}.... ", -" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", -" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", -" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", -" ........%%%%[[[[;;;;;;;;;;;;;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::........####;;;;;;;;;;;;2222[[[[[[[[----;;;;;;;;;;;;;;;;;;;;====........ ", -" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", -" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", -" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", -" ....&&&&::::;;;;[[[[{{{{;;;;;;;;;;;;{{{{;;;;;;;;;;;;~~~~===={{{{::::;;;;^^^^........____;;;;;;;;''''}}}}............>>>>;;;;;;;;;;;;;;;;;;;;,,,,.... ", -" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", -" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", -" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", -" ....}}}}<<<<;;;;;;;;::::{{{{;;;;____::::2222!!!!''''----;;;;;;;;;;;;]]]]****....&&&&((((____]]]]....||||{{{{====@@@@....~~~~____________[[[[////........ ", -" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", -" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", -" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", -" ........****$$$$))))))))]]]]@@@@%%%%////////,,,,111111111111111111111111}}}}........||||1111****....@@@@1111111111111111@@@@....3333111111111111||||&&&&.... ", -" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", -" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", -" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", -" ....,,,,::::;;;;;;;;;;;;;;;;;;;;''''####^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]....////;;;;;;;;++++))));;;;;;;;;;;;;;;;;;;;;;;;$$$$****;;;;;;;;;;;;;;;;........ ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;))))))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$$$$....~~~~;;;;$$$$****;;;;;;;;;;;;;;;;;;;;;;;;;;;;----++++^^^^;;;;;;;;;;;;####.... ", -" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", -" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", -" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", -" ........$$$$;;;;;;;;;;;;;;;;;;;;;;;;>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>}}}}....^^^^----....!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;))))****::::;;;;;;;;||||.... ", -" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", -" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", -" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", -" ....&&&&@@@@$$$$||||####))))))))))))||||))))))))))))1111||||||||####]]]]++++........$$$$////}}}}]]]]))))))))))))))))))))))))))))))))$$$$....3333))))))))####........ ", -" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", -" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", -" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", -" ....####;;;;;;;;;;;;[[[[{{{{;;;;---->>>>;;;;----^^^^[[[[;;;;;;;;;;;;;;;;]]]]....~~~~;;;;@@@@]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1111####;;;;;;;;----}}}}.... ", -" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", -" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", -" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", -" ....{{{{;;;;;;;;;;;;;;;;{{{{<<<<[[[[::::((((~~~~----;;;;;;;;;;;;;;;;;;;;$$$$....((((----....<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{}}}};;;;;;;;;;;;3333.... ", -" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", -" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", -" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", -" ........))));;;;;;;;;;;;;;;;;;;;~~~~~~~~[[[[!!!!;;;;;;;;;;;;;;;;;;;;;;;;----////....>>>>====....>>>>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222}}}}^^^^;;;;::::3333.... ", -" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", -" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", -" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", -" ....&&&&####))))))))))))))))))))$$$$}}}}@@@@))))))))))))))))))))))))))))@@@@....}}}}]]]]3333....****))))))))))))))))))))))))))))))))))))))))))))....,,,,))))))))........ ", -" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", -" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", -" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", -" ....3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2222++++||||;;;;%%%%....'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]]1111;;;;;;;;1111.... ", -" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", -" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", -" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", -" ....1111____((((::::;;;;;;;;;;;;;;;;{{{{;;;;;;;;;;;;[[[[====[[[[::::;;;;;;;;....]]]];;;;}}}}....))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;====,,,,;;;;;;;;]]]].... ", -" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", -" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", -" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", -" ....%%%%2222----((((!!!!2222;;;;2222{{{{;;;;____''''::::;;;;;;;;;;;;;;;;))))....1111;;;;........++++::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....;;;;;;;;1111.... ", -" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", -" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", -" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", -" ....++++))))))))))))))))@@@@1111$$$$1111####@@@@))))))))))))))))))))))))3333....,,,,@@@@............1111))))))))))))))))))))))))))))))))))))))))]]]]....1111####3333.... ", -" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", -" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", -" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", -" ....{{{{;;;;;;;;;;;;;;;;;;;;^^^^<<<<>>>>))));;;;;;;;;;;;;;;;;;;;;;;;;;;;----....[[[[)))).... ....----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333{{{{;;;;####.... ", -" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", -" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", -" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", -" ....____;;;;;;;;;;;;;;;;;;;;----~~~~]]]];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}};;;;####.... ....____;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;////^^^^;;;;####.... ", -" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", -" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", -" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", -" ....$$$$''''!!!!!!!!!!!!!!!!!!!!1111]]]]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%%%%}}}}[[[[,,,,.... ....''''[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,,,,||||>>>>}}}}.... ", -" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", -" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", -" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", -" ........''''{{{{::::::::____________!!!!{{{{____________::::((((>>>>____________::::[[[[@@@@............~~~~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[1111####{{{{,,,,.... ", -" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", -" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", -" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", -" ....++++;;;;----<<<<====((((;;;;;;;;[[[[::::;;;;;;;;((((====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)))).... ", -" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", -" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", -" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", -" ....****;;;;;;;;;;;;;;;;[[[[====;;;;[[[[____;;;;{{{{((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----####.... ", -" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", -" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", -" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", -" ....&&&&))))!!!!!!!!!!!!!!!!))))$$$$]]]]~~~~))))$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^^^++++.... ", -" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", -" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", -" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", -" ....&&&&((((____________________!!!!$$$$))))!!!!________________________________________________________________________________________________________________<<<<3333.... ", -" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", -" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", -" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", -" ....%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@||||;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;========))))))))))))))))))))))))))))))))))))))))))))))))))))))))]]]]****&&&&.... ", -" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", -" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", -" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", -" ....****22222222;;;;;;;;;;;;;;;;;;;;(((({{{{;;;;;;;;;;;;;;;;;;;;____----;;;;;;;;;;;;;;;;%%%%....&&&&........................................................................ ", -" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", -" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", -" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", -" ....&&&&++++~~~~####]]]]!!!!!!!!!!!!~~~~]]]]!!!!====[[[[!!!!^^^^>>>>[[[[[[[[[[[[[[[[{{{{}}}}............ ", -" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", -" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", -" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", -" ........////________::::^^^^^^^^::::((((!!!!____[[[[$$$$>>>>[[[[[[[[[[[[[[[[[[[[[[[[{{{{++++.... ", -" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....<<<<;;;;;;;;;;;;;;;;<<<<^^^^2222{{{{;;;;''''2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....;;;;;;;;;;;;;;;;;;;;;;;;::::~~~~====>>>>::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]]]].... ", -" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", -" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", -" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", -" ....@@@@!!!!!!!!!!!!!!!!!!!!!!!!]]]]3333||||!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****.... ", -" ....####____________________________####____________________::::<<<<________________~~~~........ ", -" ....####____________________________####____________________::::<<<<________________~~~~........ ", -" ....####____________________________####____________________::::<<<<________________~~~~........ ", -" ....####____________________________####____________________::::<<<<________________~~~~........ ", -" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", -" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", -" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", -" ....^^^^____{{{{[[[[____;;;;;;;;;;;;====2222;;;;;;;;;;;;<<<<<<<<----;;;;;;;;;;;;;;;;;;;;,,,,........................................................................ ", -" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", -" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", -" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", -" ....@@@@<<<<;;;;;;;;{{{{~~~~2222;;;;____>>>>;;;;;;;;((((((((;;;;;;;;;;;;;;;;;;;;;;;;;;;;3333,,,,--------------------------------------------||||....$$$$----!!!!.... ", -" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", -" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", -" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", -" ........@@@@))))))))))))))))||||@@@@))))||||))))$$$$||||))))))))))))))))))))))))))))####}}}}&&&&////))))))))))))))))))))))))))))))))))))))))}}}}....////))))////.... ", -" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", -" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", -" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", -" ....&&&&::::;;;;;;;;;;;;;;;;;;;;====>>>>>>>>;;;;^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;____....[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^^....{{{{;;;;||||.... ", -" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", -" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", -" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", -" ........2222;;;;;;;;;;;;;;;;;;;;;;;;{{{{####<<<<[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++'''';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;~~~~****;;;;;;;;........ ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", -" ....^^^^;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''%%%%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{{{{&&&&}}}}####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[[[[++++||||;;;;----........ ", -" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", -" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", -" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", -" ....&&&&3333$$$$1111$$$$))))))))))))))))%%%%))))))))))))))))1111]]]]))))))))))))))))]]]]++++&&&&}}}}$$$$))))))))))))))))))))))))@@@@&&&&....////))))@@@@.... ", -" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", -" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", -" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", -" ........((((;;;;____<<<<''''{{{{;;;;;;;;((((----;;;;;;;;[[[[2222;;;;;;;;;;;;;;;;;;;;;;;;----@@@@3333;;;;;;;;;;;;;;;;;;;;;;;;;;;;____}}}}}}}};;;;;;;;~~~~.... ", -" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", -" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", -" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", -" ....====;;;;;;;;;;;;;;;;::::~~~~<<<<----((((;;;;----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::....====;;;;;;;;;;;;;;;;;;;;;;;;>>>>....!!!!;;;;;;;;,,,,.... ", -" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", -" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", -" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", -" ....////::::;;;;;;;;;;;;;;;;;;;;!!!!!!!!!!!!;;;;====----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>....++++$$$$;;;;;;;;;;;;;;;;[[[[....&&&&____;;;;====........ ", -" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", -" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", -" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", -" ........&&&&||||))))))))))))))))))))$$$$,,,,||||%%%%))))))))))))))))))))))))))))))))))))]]]]1111&&&&....||||]]]]]]]]@@@@&&&&....||||]]]]]]]]}}}}.... ", -" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", -" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", -" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", -" ....&&&&;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::@@@@====;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----////................3333::::;;;;;;;;;;;;}}}}.... ", -" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", -" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", -" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", -" ........!!!!;;;;;;;;;;;;;;;;;;;;;;;;;;;;(((([[[[;;;;;;;;;;;;;;;;____2222;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>>>)))))))){{{{;;;;;;;;;;;;;;;;^^^^........ ", -" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", -" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", -" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", -" ........====2222____::::----;;;;;;;;;;;;((((;;;;;;;;;;;;2222<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----))))........ ", -" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", -" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", -" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", -" ............%%%%$$$$####@@@@%%%%####))))####))))))))||||))))))))))))))))))))))))))))))))))))))))))))))))))))))))||||}}}}&&&&.... ", -" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", -" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", -" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", -" ........!!!!;;;;;;;;;;;;2222!!!!]]]]{{{{____----[[[[;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&&&&........ ", -" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", -" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", -" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", -" ........^^^^----;;;;;;;;;;;;;;;;^^^^))))((((::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;''''........ ", -" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", -" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", -" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", -" ........****''''----;;;;;;;;;;;;::::]]]]----;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;----$$$$........ ", -" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", -" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", -" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", -" ................}}}}....////1111))))))))))))))))))))))))))))))))))))))))))))))))]]]]////............ ", -" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", -" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", -" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", -" ................................}}}}3333||||||||1111####$$$$$$$$$$$$]]]]1111............ ", -" ............................................................................ ", -" ............................................................................ ", -" ............................................................................ ", -" ............................................................................ ", -" ", -" ", -" ", -" "}; +" ", +" .................... ", +" ...+@##$$$$###@%&....... ", +" ..*=-;;;-;;;;;;;;@........ ", +" ..+-;;;;--;;;;;;;>.......... ", +" ...,')!!'~>{!)$)>'....*]>^%&.. ", +" ../(__(>:{<)$![[[%&...^!!!!!~*. ", +" ..@;;;;;({=]:;;;;;~..*_;;;;;;;_.. ", +" .}>;;;;;^#=;;;;;;>...<;;;;;;;;;|.. ", +" ..*1)))))%]))))))%&..1])))))))))#}. ", +" ..%[;;;;;[2;;;;;;;:..#;;;2[[-;;;;;=.. ", +" .&:;[{;;;{;;;~={:;^.._;;'}...>;;;;;,. ", +" .}<;;:{;_:2!'-;;;]*.&(_].|{=@.~___[/.. ", +" ..*$))]@%//,111111}..|1*.@1111@.3111|&. ", +" .,:;;;;;'#^;;;;;;;]./;;+);;;;;;$*;;;;.. ", +" .^;;;;;;));;;;;;;;$.~;$*;;;;;;;-+^;;;#. ", +" ..$;;;;;;>;;;;;;;;>}.^-.!;;;;;;;;)*:;;|. ", +" .&@$|#)))|)))1||#]+..$/}]))))))))$.3))#.. ", +" .#;;;[{;->;-^[;;;;].~;@];;;;;;;;;;1#;;-}. ", +" .{;;;;{<[:(~-;;;;;$.(-.<;;;;;;;;;;{};;;3. ", +" ..);;;;;~~[!;;;;;;-/.>=.>;;;;;;;;;;2}^;:3. ", +" .&#)))))$}@)))))))@.}]3.*))))))))))).,)).. ", +" .3;;;;;;;);;;;;;;;2+|;%.';;;;;;;;;;;]1;;1. ", +" .1_(:;;;;{;;;[=[:;;.];}.);;;;;;;;;;;=,;;]. ", +" .%2-(!2;2{;_':;;;;).1;..+:;;;;;;;;;;_.;;1. ", +" .+))))@1$1#@))))))3.,@...1))))))))))].1#3. ", +" .{;;;;;^<>);;;;;;;-.[). .-;;;;;;;;;;;3{;#. ", +" ._;;;;;-~];;;;;;;;;};#. ._;;;;;;;;;;;/^;#. ", +" .$'!!!!!1]!!!!!!!!%}[,. .'[[[[[[[[[[[,|>}. ", +" ..'{::___!{___:(>___:[@...~[[[[[[[[[[[1#{,. ", +" .+;-<=(;;[:;;(=-;;;;;;;;;;;;;;;;;;;;;;;;;). ", +" .*;;;;[=;[_;{(;;;;;;;;;;;;;;;;;;;;;;;;;;-#. ", +" .&)!!!!)$]~)$!!!!!!!!!!!!!!!!!!!!!!!!!!!^+. ", +" .&(_____!$)!____________________________<3. ", +" .%;;;;;;;@|;;;;;;;;;;;;==))))))))))))))]*&. ", +" .*22;;;;;({;;;;;_-;;;;%.&.................. ", +" .&+~#]!!!~]!=[!^>[[[[{}... ", +" ../__:^^:(!_[$>[[[[[[{+. ", +" .<;;;;<^2{;'2;;;;;;;;]. ", +" .;;;;;;:~=>:;;;;;;;;;]. ", +" .@!!!!!!]3|!!!!!!!!!!*. ", +" .#_______#_____:<____~.. ", +" .^_{[_;;;=2;;;<<-;;;;;,.................. ", +" .@<;;{~2;_>;;((;;;;;;;3,-----------|.$-!. ", +" ..@))))|@)|)$|)))))))#}&/))))))))))}./)/. ", +" .&:;;;;;=>>;^;;;;;;;;;_.[;;;;;;;;;;^.{;|. ", +" ..2;;;;;;{#<[;;;;;;;;;;+';;;;;;;;;;~*;;.. ", +" .^;;;;;;;'%;;;;;;;;;;{&}#;;;;;;;;[+|;-.. ", +" .&3$1$))))%))))1]))))]+&}$))))))@&./)@. ", +" ..(;_<'{;;(-;;[2;;;;;;-@3;;;;;;;_}};;~. ", +" .=;;;;:~<-(;-[;;;;;;;;:.=;;;;;;>.!;;,. ", +" ./:;;;;;!!!;=-;;;;;;;;>.+$;;;;[.&_;=.. ", +" ..&|)))))$,|%)))))))))]1&.|]]@&.|]]}. ", +" .&;;;;;;;:@=;;;;;;;;;;;-/....3:;;;}. ", +" ..!;;;;;;;([;;;;_2;;;;;;;>)){;;;;^.. ", +" ..=2_:-;;;(;;;2<;;;;;;;;;;;;;;-).. ", +" ...%$#@%#)#))|))))))))))))))|}&. ", +" ..!;;;2!]{_-[;;;;;;;;;;;;;;;&.. ", +" ..^-;;;;^)(:;;;;;;;;;;;;;;'.. ", +" ..*'-;;;:]-;;;;;;;;;;;;-$.. ", +" ....}./1))))))))))))]/... ", +" ........}3||1#$$$]1... ", +" ................... ", +" "}; From 4320e0f3a8e9edec4e8f5b94d8e78227ca282233 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 21 Sep 2018 12:23:00 +0200 Subject: [PATCH 60/84] Fix visual error related to moving the cursor on multi-line messages. --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 794a89d7..cab5937c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1565,7 +1565,7 @@ static void HU_DrawChat(void) if (hu_tick < 4) V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL); - if (cursorx == chatx+1) // a weirdo hack + if (cursorx == chatx+1 && strlen(w_chat) == i) // a weirdo hack { typelines += 1; skippedline = true; From 25ae5a5e7f1708fabdabd335f7cd458ca9b11e67 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 21 Sep 2018 12:12:17 +0100 Subject: [PATCH 61/84] Partially address Sal's review last night by switching to a more sensible default. I'm still unconvinced on the need to make encore mode a seperate knob on the grounds of overcomplexity and "you can't turn map hell off", but hopefully this'll be a shippable state we can come back to later. Also, thank you for reminding me, Sryder - disable my very, very limited progress on encore mode in openGL so that stages aren't an unintended hodgepodge of different colourschemes for the objects versus the level environment. --- src/d_netcmd.c | 2 +- src/hardware/hw_main.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index cb2ed49d..5f5e7e30 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -354,7 +354,7 @@ consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_ consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}}; -consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Sometimes", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 87de473e..4c206337 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5452,8 +5452,10 @@ static void HWR_ProjectSprite(mobj_t *thing) else { vis->colormap = colormaps; +#ifdef GLENCORE if (encoremap && (thing->flags & (MF_SCENERY|MF_NOTHINK))) vis->colormap += (256*32); +#endif } // set top/bottom coords @@ -5558,8 +5560,10 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->mobj = (mobj_t *)thing; vis->colormap = colormaps; +#ifdef GLENCORE if (encoremap) vis->colormap += (256*32); +#endif // set top/bottom coords vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); From 58a0206783a88bd1bd65c8703f814fdacdc7fb15 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 21 Sep 2018 17:03:09 +0200 Subject: [PATCH 62/84] Moved strlen(w_chat) out of the loop. --- src/hu_stuff.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index cab5937c..77b87328 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1523,6 +1523,7 @@ static void HU_DrawChat(void) INT32 charwidth = 4, charheight = 6; INT32 t = 0, c = 0, y = chaty - (typelines*charheight) - (cv_kartspeedometer.value ? 16 : 0); UINT32 i = 0; + INT32 saylen = strlen(w_chat); // You learn new things everyday! const char *ntalk = "Say: ", *ttalk = "Team: "; const char *talk = ntalk; @@ -1538,7 +1539,7 @@ static void HU_DrawChat(void) } V_DrawFillConsoleMap(chatx, y-1, cv_chatwidth.value, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT); - + while (talk[i]) { if (talk[i] < HU_FONTSTART) @@ -1565,7 +1566,7 @@ static void HU_DrawChat(void) if (hu_tick < 4) V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL); - if (cursorx == chatx+1 && strlen(w_chat) == i) // a weirdo hack + if (cursorx == chatx+1 && saylen == i) // a weirdo hack { typelines += 1; skippedline = true; From 06a4a5e4dc2ee6cc186d301dea750deb8b3163bf Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 21 Sep 2018 15:37:30 -0400 Subject: [PATCH 63/84] Prevent signs from disappearing --- src/p_mobj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 38149f91..9f16b778 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8291,6 +8291,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->z <= mobj->movefactor) { P_SetMobjState(mobj, S_SIGN53); + mobj->z = mobj->movefactor; //mobj->flags |= MF_NOGRAVITY; // ? mobj->flags &= ~MF_NOCLIPHEIGHT; mobj->movecount = 0; From cb3c93e56e3be2990f5497f9b44432bb204812ba Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 21 Sep 2018 16:54:29 -0400 Subject: [PATCH 64/84] Minor adjustments to the endsign color back table --- src/k_kart.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index d923c5c9..7b38874c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -128,13 +128,13 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_GREEN,8, // 14 // SKINCOLOR_RED SKINCOLOR_SAPPHIRE,8, // 15 // SKINCOLOR_RUBY SKINCOLOR_PINETREE,6, // 16 // SKINCOLOR_CRIMSON - SKINCOLOR_MUSTARD,6, // 17 // SKINCOLOR_KETCHUP + SKINCOLOR_MUSTARD,10, // 17 // SKINCOLOR_KETCHUP SKINCOLOR_DUSK,8, // 18 // SKINCOLOR_DAWN SKINCOLOR_PERIWINKLE,8, // 19 // SKINCOLOR_CREAMSICLE SKINCOLOR_BLUE,8, // 20 // SKINCOLOR_ORANGE SKINCOLOR_BLUEBERRY,8, // 21 // SKINCOLOR_PUMPKIN - SKINCOLOR_NAVY,8, // 22 // SKINCOLOR_ROSEWOOD - SKINCOLOR_JET,6, // 23 // SKINCOLOR_BURGUNDY + SKINCOLOR_NAVY,6, // 22 // SKINCOLOR_ROSEWOOD + SKINCOLOR_JET,8, // 23 // SKINCOLOR_BURGUNDY SKINCOLOR_LIME,8, // 24 // SKINCOLOR_TANGERINE SKINCOLOR_CYAN,8, // 25 // SKINCOLOR_PEACH SKINCOLOR_CERULEAN,8, // 26 // SKINCOLOR_CARAMEL @@ -144,36 +144,36 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_KETCHUP,8, // 30 // SKINCOLOR_MUSTARD SKINCOLOR_TEAL,8, // 31 // SKINCOLOR_OLIVE SKINCOLOR_ROBOHOOD,8, // 32 // SKINCOLOR_VOMIT - SKINCOLOR_LAVENDER,8, // 33 // SKINCOLOR_GARDEN + SKINCOLOR_LAVENDER,6, // 33 // SKINCOLOR_GARDEN SKINCOLOR_TANGERINE,8, // 34 // SKINCOLOR_LIME SKINCOLOR_POMEGRANATE,8, // 35 // SKINCOLOR_DREAM SKINCOLOR_SALMON,8, // 36 // SKINCOLOR_TEA - SKINCOLOR_PINK,8, // 37 // SKINCOLOR_PISTACHIO + SKINCOLOR_PINK,6, // 37 // SKINCOLOR_PISTACHIO SKINCOLOR_VOMIT,8, // 38 // SKINCOLOR_ROBOHOOD SKINCOLOR_ROSE,8, // 39 // SKINCOLOR_MOSS - SKINCOLOR_RASPBERRY,6, // 40 // SKINCOLOR_MINT + SKINCOLOR_RASPBERRY,8, // 40 // SKINCOLOR_MINT SKINCOLOR_RED,8, // 41 // SKINCOLOR_GREEN SKINCOLOR_CRIMSON,8, // 42 // SKINCOLOR_PINETREE SKINCOLOR_PURPLE,8, // 43 // SKINCOLOR_EMERALD - SKINCOLOR_BYZANTIUM,6, // 44 // SKINCOLOR_SWAMP + SKINCOLOR_BYZANTIUM,8, // 44 // SKINCOLOR_SWAMP SKINCOLOR_YELLOW,8, // 45 // SKINCOLOR_AQUA SKINCOLOR_OLIVE,8, // 46 // SKINCOLOR_TEAL SKINCOLOR_PEACH,8, // 47 // SKINCOLOR_CYAN - SKINCOLOR_LILAC,6, // 48 // SKINCOLOR_JAWZ + SKINCOLOR_LILAC,10, // 48 // SKINCOLOR_JAWZ SKINCOLOR_CARAMEL,8, // 49 // SKINCOLOR_CERULEAN SKINCOLOR_ROSEWOOD,8, // 50 // SKINCOLOR_NAVY - SKINCOLOR_GOLD,8, // 51 // SKINCOLOR_SLATE - SKINCOLOR_BRONZE,8, // 52 // SKINCOLOR_STEEL - SKINCOLOR_BURGUNDY,6, // 53 // SKINCOLOR_JET + SKINCOLOR_GOLD,10, // 51 // SKINCOLOR_SLATE + SKINCOLOR_BRONZE,10, // 52 // SKINCOLOR_STEEL + SKINCOLOR_BURGUNDY,8, // 53 // SKINCOLOR_JET SKINCOLOR_CREAMSICLE,8, // 54 // SKINCOLOR_PERIWINKLE SKINCOLOR_ORANGE,8, // 55 // SKINCOLOR_BLUE - SKINCOLOR_RUBY,8, // 56 // SKINCOLOR_SAPPHIRE + SKINCOLOR_RUBY,6, // 56 // SKINCOLOR_SAPPHIRE SKINCOLOR_PUMPKIN,8, // 57 // SKINCOLOR_BLUEBERRY - SKINCOLOR_DAWN,8, // 58 // SKINCOLOR_DUSK + SKINCOLOR_DAWN,6, // 58 // SKINCOLOR_DUSK SKINCOLOR_EMERALD,8, // 59 // SKINCOLOR_PURPLE - SKINCOLOR_GARDEN,8, // 60 // SKINCOLOR_LAVENDER + SKINCOLOR_GARDEN,6, // 60 // SKINCOLOR_LAVENDER SKINCOLOR_SWAMP,8, // 61 // SKINCOLOR_BYZANTIUM - SKINCOLOR_DREAM,6, // 62 // SKINCOLOR_POMEGRANATE + SKINCOLOR_DREAM,8, // 62 // SKINCOLOR_POMEGRANATE SKINCOLOR_JAWZ,6 // 63 // SKINCOLOR_LILAC }; From 20222c47e70e62ca267ddf7f1a88be667f9e97b6 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 21 Sep 2018 22:06:27 +0100 Subject: [PATCH 65/84] Okay, seems like reducing it to 1x is enough - making it singular is overkill and means that often if the furthest one away from you is the one to yell, you'll barely hear it. At least this way you'll only hear overkill chao if you're super close to the stands and the mapper's placed way too many --- src/sounds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sounds.c b/src/sounds.c index 469427ae..a85da8e0 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -814,7 +814,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"kpogos", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"ddash", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"mcitm1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, - {"chaooo", false, 110, 64, -1, NULL, 0, -1, -1, LUMPERROR}, + {"chaooo", false, 110, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // SRB2kart - Skin sounds From 3fa7f4e7b4cbd584c1f4e21f79a66e912675e8cc Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 21 Sep 2018 18:40:18 -0400 Subject: [PATCH 66/84] Address review - Reduced states - Metal Sonic on sign roulette - Landing sound - New falling sound --- src/dehacked.c | 34 +--------------------------------- src/info.c | 49 ++++++++----------------------------------------- src/info.h | 34 +--------------------------------- src/p_mobj.c | 4 +++- src/p_spec.c | 2 +- 5 files changed, 14 insertions(+), 109 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 43c9c78b..4cde7882 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4787,39 +4787,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SIGN18", "S_SIGN19", "S_SIGN20", - "S_SIGN21", - "S_SIGN22", - "S_SIGN23", - "S_SIGN24", - "S_SIGN25", - "S_SIGN26", - "S_SIGN27", - "S_SIGN28", - "S_SIGN29", - "S_SIGN30", - "S_SIGN31", - "S_SIGN32", - "S_SIGN33", - "S_SIGN34", - "S_SIGN35", - "S_SIGN36", - "S_SIGN37", - "S_SIGN38", - "S_SIGN39", - "S_SIGN40", - "S_SIGN41", - "S_SIGN42", - "S_SIGN43", - "S_SIGN44", - "S_SIGN45", - "S_SIGN46", - "S_SIGN47", - "S_SIGN48", - "S_SIGN49", - "S_SIGN50", - "S_SIGN51", - "S_SIGN52", // Eggman - "S_SIGN53", + "S_SIGN_END", // Steam Riser "S_STEAM1", diff --git a/src/info.c b/src/info.c index 70e08f9e..15b30fea 100644 --- a/src/info.c +++ b/src/info.c @@ -1044,56 +1044,24 @@ state_t states[NUMSTATES] = {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN2}, // S_SIGN1 {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN3}, // S_SIGN2 {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN4}, // S_SIGN3 - {SPR_SIGN, 5, 1, {NULL}, 0, 0, S_SIGN5}, // S_SIGN4 + {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN5}, // S_SIGN4 {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN6}, // S_SIGN5 {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN7}, // S_SIGN6 {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN8}, // S_SIGN7 - {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN9}, // S_SIGN8 + {SPR_SIGN, 4, 1, {NULL}, 0, 0, S_SIGN9}, // S_SIGN8 {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN10}, // S_SIGN9 {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN11}, // S_SIGN10 {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN12}, // S_SIGN11 - {SPR_SIGN, 4, 1, {NULL}, 0, 0, S_SIGN13}, // S_SIGN12 + {SPR_SIGN, 5, 1, {NULL}, 0, 0, S_SIGN13}, // S_SIGN12 {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN14}, // S_SIGN13 {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN15}, // S_SIGN14 {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN16}, // S_SIGN15 - {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN17}, // S_SIGN16 + {SPR_SIGN, 6, 1, {NULL}, 0, 0, S_SIGN17}, // S_SIGN16 {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN18}, // S_SIGN17 {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN19}, // S_SIGN18 {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN20}, // S_SIGN19 - {SPR_SIGN, 6, 1, {NULL}, 0, 0, S_SIGN21}, // S_SIGN20 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN22}, // S_SIGN21 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN23}, // S_SIGN22 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN24}, // S_SIGN23 - {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN25}, // S_SIGN24 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN26}, // S_SIGN25 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN27}, // S_SIGN26 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN28}, // S_SIGN27 - {SPR_SIGN, 5, 1, {NULL}, 0, 0, S_SIGN29}, // S_SIGN28 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN30}, // S_SIGN29 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN31}, // S_SIGN30 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN32}, // S_SIGN31 - {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN33}, // S_SIGN32 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN34}, // S_SIGN33 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN35}, // S_SIGN34 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN36}, // S_SIGN35 - {SPR_SIGN, 4, 1, {NULL}, 0, 0, S_SIGN37}, // S_SIGN36 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN38}, // S_SIGN37 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN39}, // S_SIGN38 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN40}, // S_SIGN39 - {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN41}, // S_SIGN40 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN42}, // S_SIGN41 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN43}, // S_SIGN42 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN44}, // S_SIGN43 - {SPR_SIGN, 6, 1, {NULL}, 0, 0, S_SIGN45}, // S_SIGN44 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN46}, // S_SIGN45 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN47}, // S_SIGN46 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN48}, // S_SIGN47 - {SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN49}, // S_SIGN48 - {SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN50}, // S_SIGN49 - {SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN51}, // S_SIGN50 - {SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN1}, // S_SIGN51 - {SPR_SIGN, 3, -1, {NULL}, 0, 0, S_NULL}, // S_SIGN52 Eggman - {SPR_SIGN, 7, -1, {A_SignPlayer}, 0, 0, S_NULL}, // S_SIGN53 Blank + {SPR_SIGN, 7, 1, {NULL}, 0, 0, S_SIGN1}, // S_SIGN20 + {SPR_SIGN, 8, -1, {A_SignPlayer}, 0, 0, S_NULL}, // S_SIGN_END // Steam Riser {SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2}, // S_STEAM1 @@ -5814,9 +5782,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_INVISIBLE, // spawnstate 1000, // spawnhealth S_PLAY_SIGN, // seestate - sfx_lvpass, // seesound + sfx_s3kb8, // seesound 8, // reactiontime - sfx_None, // attacksound + sfx_s3k7e, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound @@ -14496,7 +14464,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // activesound MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate ->>>>>>> master }, { // MT_BOOSTFLAME diff --git a/src/info.h b/src/info.h index c6461f15..1891b481 100644 --- a/src/info.h +++ b/src/info.h @@ -1636,39 +1636,7 @@ typedef enum state S_SIGN18, S_SIGN19, S_SIGN20, - S_SIGN21, - S_SIGN22, - S_SIGN23, - S_SIGN24, - S_SIGN25, - S_SIGN26, - S_SIGN27, - S_SIGN28, - S_SIGN29, - S_SIGN30, - S_SIGN31, - S_SIGN32, - S_SIGN33, - S_SIGN34, - S_SIGN35, - S_SIGN36, - S_SIGN37, - S_SIGN38, - S_SIGN39, - S_SIGN40, - S_SIGN41, - S_SIGN42, - S_SIGN43, - S_SIGN44, - S_SIGN45, - S_SIGN46, - S_SIGN47, - S_SIGN48, - S_SIGN49, - S_SIGN50, - S_SIGN51, - S_SIGN52, // Eggman - S_SIGN53, + S_SIGN_END, // Steam Riser S_STEAM1, diff --git a/src/p_mobj.c b/src/p_mobj.c index 9f16b778..4787cf3d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8290,7 +8290,9 @@ void P_MobjThinker(mobj_t *mobj) { if (mobj->z <= mobj->movefactor) { - P_SetMobjState(mobj, S_SIGN53); + P_SetMobjState(mobj, S_SIGN_END); + if (thing->info->attacksound) + S_StartSound(thing, thing->info->attacksound); mobj->z = mobj->movefactor; //mobj->flags |= MF_NOGRAVITY; // ? mobj->flags &= ~MF_NOCLIPHEIGHT; diff --git a/src/p_spec.c b/src/p_spec.c index cba294e6..b429f65a 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3280,7 +3280,7 @@ void P_SetupSignExit(player_t *player) P_SetMobjState(sign, S_SIGN1); if (sign->info->seesound) S_StartSound(sign, sign->info->seesound); - sign->movefactor = player->mo->z; + sign->movefactor = player->mo->floorz; sign->movecount = 1; } } From dd6b63f9da95a0c4f0e1a55c37aee63638ff30c2 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 21 Sep 2018 19:44:14 -0400 Subject: [PATCH 67/84] Different timings --- src/p_inter.c | 2 +- src/p_mobj.c | 12 +++++++++--- src/p_spec.c | 12 +++--------- src/p_tick.c | 4 ++-- src/p_user.c | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 68124671..74612949 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -694,7 +694,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!playeringame[i] || players[i].spectator) continue; - players[i].exiting = (21*TICRATE)/5 + 1; + players[i].exiting = (28*TICRATE)/5 + 1; } S_StartSound(NULL, sfx_lvpass); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 4787cf3d..c4f29486 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1410,7 +1410,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) gravityadd = FixedMul(gravityadd, 5*FRACUNIT); // Double gravity break; case MT_SIGN: - gravityadd /= 4; + gravityadd /= 8; break; default: break; @@ -8291,8 +8291,8 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->z <= mobj->movefactor) { P_SetMobjState(mobj, S_SIGN_END); - if (thing->info->attacksound) - S_StartSound(thing, thing->info->attacksound); + if (mobj->info->attacksound) + S_StartSound(mobj, mobj->info->attacksound); mobj->z = mobj->movefactor; //mobj->flags |= MF_NOGRAVITY; // ? mobj->flags &= ~MF_NOCLIPHEIGHT; @@ -8305,6 +8305,12 @@ void P_MobjThinker(mobj_t *mobj) mobj->z + (24<flags &= ~MF_NOGRAVITY; + if (abs(mobj->z - mobj->movefactor) <= 512<cvmem) + { + if (mobj->info->seesound) + S_StartSound(mobj, mobj->info->seesound); + mobj->cvmem = 1; + } } } break; diff --git a/src/p_spec.c b/src/p_spec.c index b429f65a..68334c33 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3227,12 +3227,10 @@ void P_SetupSignExit(player_t *player) P_SetTarget(&thing->target, player->mo); P_SetMobjState(thing, S_SIGN1); - if (thing->info->seesound) - S_StartSound(thing, thing->info->seesound); // SRB2Kart: Set sign spinning variables thing->movefactor = thing->z; - thing->z += (640<z += (768<movecount = 1; ++numfound; @@ -3257,12 +3255,10 @@ void P_SetupSignExit(player_t *player) P_SetTarget(&thing->target, player->mo); P_SetMobjState(thing, S_SIGN1); - if (thing->info->seesound) - S_StartSound(thing, thing->info->seesound); // SRB2Kart: Set sign spinning variables thing->movefactor = thing->z; - thing->z += (640<z += (768<movecount = 1; ++numfound; @@ -3274,12 +3270,10 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: FINALLY, add in an alternative if no place is found if (player->mo) { - mobj_t *sign = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + (640<mo->x, player->mo->y, player->mo->z + (768<target, player->mo); P_SetMobjState(sign, S_SIGN1); - if (sign->info->seesound) - S_StartSound(sign, sign->info->seesound); sign->movefactor = player->mo->floorz; sign->movecount = 1; } diff --git a/src/p_tick.c b/src/p_tick.c index 4cfba90f..357a4b1e 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -448,7 +448,7 @@ static inline void P_DoSpecialStageStuff(void) { if (playeringame[i]) { - players[i].exiting = (21*TICRATE)/5 + 1; + players[i].exiting = (28*TICRATE)/5 + 1; players[i].pflags &= ~PF_GLIDING; } @@ -485,7 +485,7 @@ static inline void P_DoSpecialStageStuff(void) if (playeringame[i]) { players[i].mo->momx = players[i].mo->momy = 0; - players[i].exiting = (21*TICRATE)/5 + 1; + players[i].exiting = (28*TICRATE)/5 + 1; } sstimer = 0; diff --git a/src/p_user.c b/src/p_user.c index 3120351c..0476777e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1751,7 +1751,7 @@ void P_DoPlayerExit(player_t *player) //countdown2 = countdown + 8*TICRATE; if (P_CheckRacers()) - player->exiting = (21*TICRATE)/5 + 1; + player->exiting = (28*TICRATE)/5 + 1; } else if (G_BattleGametype()) // Battle Mode exiting { @@ -1759,7 +1759,7 @@ void P_DoPlayerExit(player_t *player) P_EndingMusic(player); } else - player->exiting = (21*TICRATE)/5 + 2; // Accidental death safeguard??? + player->exiting = (28*TICRATE)/5 + 2; // Accidental death safeguard??? //player->pflags &= ~PF_GLIDING; /* // SRB2kart - don't need @@ -6569,7 +6569,7 @@ static void P_MovePlayer(player_t *player) S_StartSound(NULL, sfx_s3k6a); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) - players[i].exiting = (21*TICRATE)/5 + 1; + players[i].exiting = (28*TICRATE)/5 + 1; } else if (player->health > 1) P_DamageMobj(player->mo, NULL, NULL, 1); @@ -9038,7 +9038,7 @@ void P_PlayerThink(player_t *player) } if (i == MAXPLAYERS && player->exiting == 6*TICRATE) // finished - player->exiting = (21*TICRATE)/5 + 1; + player->exiting = (28*TICRATE)/5 + 1; // If 10 seconds are left on the timer, // begin the drown music for countdown! From 0e39bf2821669e3b631d6ef48b71bcd58114419c Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Fri, 21 Sep 2018 19:51:31 -0400 Subject: [PATCH 68/84] Slightly darker green backgrounds --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7b38874c..16a19c53 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -124,8 +124,8 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_TEA,8, // 10 // SKINCOLOR_SALMON SKINCOLOR_PISTACHIO,8, // 11 // SKINCOLOR_PINK SKINCOLOR_MOSS,8, // 12 // SKINCOLOR_ROSE - SKINCOLOR_MINT,10, // 13 // SKINCOLOR_RASPBERRY - SKINCOLOR_GREEN,8, // 14 // SKINCOLOR_RED + SKINCOLOR_MINT,8, // 13 // SKINCOLOR_RASPBERRY + SKINCOLOR_GREEN,6, // 14 // SKINCOLOR_RED SKINCOLOR_SAPPHIRE,8, // 15 // SKINCOLOR_RUBY SKINCOLOR_PINETREE,6, // 16 // SKINCOLOR_CRIMSON SKINCOLOR_MUSTARD,10, // 17 // SKINCOLOR_KETCHUP From 84c2a8c28f8d561225a57677d374f2dd6568433b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Sep 2018 11:59:07 +0100 Subject: [PATCH 69/84] Sign compare fix via boolean cast --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 79fb89f1..73d20bfd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3175,7 +3175,7 @@ INT16 G_SometimesGetDifferentGametype(void) encorepossible = M_RandomChance(FRACUNIT>>3); break; } - if (encorepossible != cv_kartencore.value) + if (encorepossible != (boolean)cv_kartencore.value) return (gametype|0x80); } return gametype; From 4fd4deff8a524eb177bc3f0dcfe922daf0163d98 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Sep 2018 12:43:54 +0100 Subject: [PATCH 70/84] One last thing - make the OpenGL level loading bar screen have the correct background colour. --- src/hardware/hw_bsp.c | 2 +- src/p_setup.c | 7 +++++-- src/p_setup.h | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 17eb8761..38a6026f 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -646,7 +646,7 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b sprintf(s, "%d%%", (++ls_percent)<<1); x = BASEVIDWIDTH/2; y = BASEVIDHEIGHT/2; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Black background to match fade in effect + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); // White background to match fade in effect //V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright. M_DrawTextBox(x-58, y-8, 13, 1); V_DrawString(x-50, y, V_YELLOWMAP, "Loading..."); diff --git a/src/p_setup.c b/src/p_setup.c index a416f991..501c80d9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -101,6 +101,7 @@ side_t *sides; mapthing_t *mapthings; INT32 numstarposts; boolean levelloading; +UINT8 levelfadecol; // BLOCKMAP // Created from axis aligned bounding box @@ -2691,12 +2692,14 @@ boolean P_SetupLevel(boolean skipprecip) if (leveltime < (starttime + (TICRATE/2))) S_ChangeMusicInternal((encoremode ? "estart" : "kstart"), false); //S_StopMusic(); + levelfadecol = (encoremode && !ranspecialwipe ? 122 : 120); + // Let's fade to white here // But only if we didn't do the encore startup wipe if (rendermode != render_none && !ranspecialwipe) { F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (encoremode ? 122 : 120)); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); F_WipeEndScreen(); F_RunWipe(wipedefs[(encoremode ? wipe_level_final : wipe_level_toblack)], false); @@ -3040,7 +3043,7 @@ boolean P_SetupLevel(boolean skipprecip) // Remove the loading shit from the screen if (rendermode != render_none) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (encoremode && !ranspecialwipe ? 122 : 120)); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); if (precache || dedicated) R_PrecacheLevel(); diff --git a/src/p_setup.h b/src/p_setup.h index 3bca1104..c3c206a5 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -27,6 +27,7 @@ extern mapthing_t *deathmatchstarts[MAX_DM_STARTS]; extern INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts; extern boolean levelloading; +extern UINT8 levelfadecol; extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame // From 3a766057722b0824dd43179ef3489da092f1ae33 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Sep 2018 18:22:04 +0100 Subject: [PATCH 71/84] * Seven new text colours! Gold, Lavender, Tea-green, Steel, Pink, Teal, and Peach, all added to the menu highlights cvar. * Revamp the saycmd colour list to take advantage of them. Peach and Purple are used the least... * In all of the string drawers, replace colormap only when charflags changes. * Add V_SKYMAP to dehacked.c alongside the above (oversight from when I added it yonks ago...) --- src/console.c | 68 +++++++++++++++++++++++++------------- src/console.h | 3 +- src/dehacked.c | 8 +++++ src/hu_stuff.c | 89 +++++++++++++++++++++----------------------------- src/v_video.c | 60 ++++++++++++++++++++++++---------- src/v_video.h | 11 +++++-- 6 files changed, 143 insertions(+), 96 deletions(-) diff --git a/src/console.c b/src/console.c index 212e6c8d..bd19cdf3 100644 --- a/src/console.c +++ b/src/console.c @@ -150,6 +150,13 @@ static CV_PossibleValue_t menuhighlight_cons_t[] = {V_GRAYMAP, "Always gray"}, {V_ORANGEMAP, "Always orange"}, {V_SKYMAP, "Always sky-blue"}, + {V_GOLDMAP, "Always gold"}, + {V_LAVENDERMAP, "Always lavender"}, + {V_TEAMAP, "Always tea-green"}, + {V_STEELMAP, "Always steel"}, + {V_PINKMAP, "Always pink"}, + {V_TEALMAP, "Always teal"}, + {V_PEACHMAP, "Always peach"}, {0, NULL} }; consvar_t cons_menuhighlight = {"menuhighlight", "Game type", CV_SAVE, menuhighlight_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -239,11 +246,6 @@ static void CONS_Bind_f(void) // CONSOLE SETUP //====================================================================== -// Font colormap colors -// TODO: This could probably be improved somehow... -// These colormaps are 99% identical, with just a few changed bytes -UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap, *skymap; - // Console BG color UINT8 *consolebgmap = NULL; @@ -284,37 +286,57 @@ static void CONS_backcolor_Change(void) CON_SetupBackColormap(); } +// Font colormap colors +// TODO: This could probably be improved somehow... +// These colormaps are 99% identical, with just a few changed bytes +UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap,\ + *skymap, *goldmap, *lavendermap, *teamap, *steelmap, *pinkmap, *tealmap, *peachmap; + static void CON_SetupColormaps(void) { INT32 i; - UINT8 *memorysrc = (UINT8 *)Z_Malloc((256*8), PU_STATIC, NULL); + UINT8 *memorysrc = (UINT8 *)Z_Malloc((256*15), PU_STATIC, NULL); - purplemap = memorysrc; - yellowmap = (purplemap+256); - greenmap = (yellowmap+256); - bluemap = (greenmap+256); - redmap = (bluemap+256); - graymap = (redmap+256); - orangemap = (graymap+256); - skymap = (orangemap+256); + purplemap = memorysrc; + yellowmap = (purplemap+256); + greenmap = (yellowmap+256); + bluemap = (greenmap+256); + redmap = (bluemap+256); + graymap = (redmap+256); + orangemap = (graymap+256); + skymap = (orangemap+256); + lavendermap = (skymap+256); + goldmap = (lavendermap+256); + teamap = (goldmap+256); + steelmap = (teamap+256); + pinkmap = (steelmap+256); + tealmap = (pinkmap+256); + peachmap = (tealmap+256); // setup the other colormaps, for console text // these don't need to be aligned, unless you convert the // V_DrawMappedPatch() into optimised asm. - for (i = 0; i < (256*8); i++, ++memorysrc) + for (i = 0; i < (256*15); i++, ++memorysrc) *memorysrc = (UINT8)(i & 0xFF); // remap each color to itself... // SRB2Kart: Different console font, new colors - purplemap[120] = (UINT8)194; - yellowmap[120] = (UINT8)103; - greenmap[120] = (UINT8)162; - bluemap[120] = (UINT8)228; - graymap[120] = (UINT8)10; - redmap[120] = (UINT8)126; // battle - orangemap[120] = (UINT8)85; // record attack - skymap[120] = (UINT8)214; // race + purplemap[120] = (UINT8)194; + yellowmap[120] = (UINT8)103; + greenmap[120] = (UINT8)162; + bluemap[120] = (UINT8)228; + redmap[120] = (UINT8)126; // battle + graymap[120] = (UINT8)10; + orangemap[120] = (UINT8)85; // record attack + skymap[120] = (UINT8)214; // race + lavendermap[120] = (UINT8)248; + goldmap[120] = (UINT8)114; + teamap[120] = (UINT8)177; + steelmap[120] = (UINT8)201; + pinkmap[120] = (UINT8)124; + tealmap[120] = (UINT8)220; + peachmap[120] = (UINT8)69; // nice // Init back colormap CON_SetupBackColormap(); diff --git a/src/console.h b/src/console.h index 896214c9..b15ccb6f 100644 --- a/src/console.h +++ b/src/console.h @@ -38,7 +38,8 @@ extern UINT32 con_scalefactor; // console text scale factor extern consvar_t cons_backcolor, cons_menuhighlight; -extern UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap, *skymap; +extern UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap,\ + *skymap, *goldmap, *lavendermap, *teamap, *steelmap, *pinkmap, *tealmap, *peachmap; // Console bg color (auto updated to match) extern UINT8 *consolebgmap; diff --git a/src/dehacked.c b/src/dehacked.c index 1c18e003..8c11cb8f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8206,6 +8206,14 @@ struct { {"V_REDMAP",V_REDMAP}, {"V_GRAYMAP",V_GRAYMAP}, {"V_ORANGEMAP",V_ORANGEMAP}, + {"V_SKYMAP",V_SKYMAP}, + {"V_LAVENDERMAP",V_LAVENDERMAP}, + {"V_GOLDMAP",V_GOLDMAP}, + {"V_TEAMAP",V_TEAMAP}, + {"V_STEELMAP",V_STEELMAP}, + {"V_PINKMAP",V_PINKMAP}, + {"V_TEALMAP",V_TEALMAP}, + {"V_PEACHMAP",V_PEACHMAP}, {"V_TRANSLUCENT",V_TRANSLUCENT}, {"V_10TRANS",V_10TRANS}, {"V_20TRANS",V_20TRANS}, diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 8ff23e4d..33d4f2aa 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -726,25 +726,39 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) { const UINT8 color = players[playernum].skincolor; if (color <= SKINCOLOR_SILVER) - cstart = "\x80"; - else if (color <= SKINCOLOR_BLACK || color == SKINCOLOR_JET) // jet is more black than blue so it goes here. - cstart = "\x86"; + cstart = "\x80"; // white + else if (color <= SKINCOLOR_BEIGE || color == SKINCOLOR_JET) + cstart = "\x86"; // V_GRAYMAP + else if (color <= SKINCOLOR_LEATHER) + cstart = "\x8A"; // V_GOLDMAP + else if (color <= SKINCOLOR_ROSE || color == SKINCOLOR_RUBY || color == SKINCOLOR_DAWN || color == SKINCOLOR_LILAC) + cstart = "\x8d"; // V_PINKMAP else if (color <= SKINCOLOR_KETCHUP) - cstart = "\x85"; + cstart = "\x85"; // V_REDMAP + else if (color <= SKINCOLOR_TANGERINE) + cstart = "\x87"; // V_ORANGEMAP else if (color <= SKINCOLOR_CARAMEL) - cstart = "\x87"; - else if (color <= SKINCOLOR_MUSTARD) - cstart = "\x82"; - else if (SKINCOLOR_SWAMP) - cstart = "\x83"; - else if (color <= SKINCOLOR_STEEL || color == SKINCOLOR_SAPPHIRE) // toaster wanted that specific one too shrug - cstart = "\x88"; - else if (color <= SKINCOLOR_NAVY) - cstart = "\x84"; - else if (color <= SKINCOLOR_LILAC) - cstart = "\x81"; - else - cstart = "\x83"; + cstart = "\x8f"; // V_PEACHMAP + else if (color <= SKINCOLOR_BRONZE) + cstart = "\x8A"; // V_GOLDMAP + else if (color <= SKINCOLOR_MUSTARD || color == SKINCOLOR_LIME) + cstart = "\x82"; // V_YELLOWMAP + else if (color <= SKINCOLOR_PISTACHIO) + cstart = "\x8b"; // V_TEAMAP + else if (color <= SKINCOLOR_SWAMP) + cstart = "\x83"; // V_GREENMAP + else if (color <= SKINCOLOR_TEAL) + cstart = "\x8e"; // V_TEALMAP + else if (color <= SKINCOLOR_NAVY || color == SKINCOLOR_SAPPHIRE) + cstart = "\x88"; // V_SKYMAP + else if (color <= SKINCOLOR_STEEL) + cstart = "\x8c"; // V_STEELMAP + else if (color <= SKINCOLOR_BLUEBERRY) + cstart = "\x84"; // V_BLUEMAP + else if (color == SKINCOLOR_PURPLE) + cstart = "\x81"; // V_PURPLEMAP + else //if (color <= SKINCOLOR_POMEGRANATE) + cstart = "\x89"; // V_LAVENDERMAP } prefix = cstart; @@ -1171,33 +1185,6 @@ boolean HU_Responder(event_t *ev) // HEADS UP DRAWING //====================================================================== -// Gets string colormap, used for 0x80 color codes -// -static UINT8 *CHAT_GetStringColormap(INT32 colorflags) // pasted from video.c, sorry for the mess. -{ - switch ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT) - { - case 1: // 0x81, purple - return purplemap; - case 2: // 0x82, yellow - return yellowmap; - case 3: // 0x83, lgreen - return greenmap; - case 4: // 0x84, blue - return bluemap; - case 5: // 0x85, red - return redmap; - case 6: // 0x86, gray - return graymap; - case 7: // 0x87, orange - return orangemap; - case 8: // 0x88, sky - return skymap; - default: // reset - return NULL; - } -} - // Precompile a wordwrapped string to any given width. // This is a muuuch better method than V_WORDWRAP. // again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day. @@ -1216,7 +1203,7 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) for (i = 0; i < slen; ++i) { c = newstring[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09 continue; if (c == '\n') @@ -1333,6 +1320,7 @@ static void HU_drawMiniChat(void) INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one. size_t j = 0; const char *msg = CHAT_WordWrap(x+2, cv_chatwidth.value-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. + UINT8 *colormap = NULL; while(msg[j]) // iterate through msg { @@ -1352,6 +1340,7 @@ static void HU_drawMiniChat(void) else if (msg[j] & 0x80) // stolen from video.c, nice. { clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK; + colormap = V_GetStringColormap(clrflag); ++j; continue; } @@ -1360,8 +1349,6 @@ static void HU_drawMiniChat(void) } else { - UINT8 *colormap = CHAT_GetStringColormap(clrflag); - if (cv_chatbacktint.value) // on request of wolfy V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); @@ -1411,6 +1398,7 @@ static void HU_drawChatLog(INT32 offset) INT32 clrflag = 0; INT32 j = 0; const char *msg = CHAT_WordWrap(x+2, cv_chatwidth.value-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it. + UINT8 *colormap = NULL; while(msg[j]) // iterate through msg { if (msg[j] < HU_FONTSTART) // don't draw @@ -1425,6 +1413,7 @@ static void HU_drawChatLog(INT32 offset) else if (msg[j] & 0x80) // stolen from video.c, nice. { clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK; + colormap = V_GetStringColormap(clrflag); ++j; continue; } @@ -1434,10 +1423,7 @@ static void HU_drawChatLog(INT32 offset) else { if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy))) - { - UINT8 *colormap = CHAT_GetStringColormap(clrflag); V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, !cv_allcaps.value, colormap); - } else j++; // don't forget to increment this or we'll get stuck in the limbo. } @@ -1498,8 +1484,7 @@ static void HU_DrawChat(void) { INT32 charwidth = 4, charheight = 6; INT32 t = 0, c = 0, y = chaty - (typelines*charheight) - (cv_kartspeedometer.value ? 16 : 0); - UINT32 i = 0; - INT32 saylen = strlen(w_chat); // You learn new things everyday! + UINT32 i = 0, saylen = strlen(w_chat); // You learn new things everyday! const char *ntalk = "Say: ", *ttalk = "Team: "; const char *talk = ntalk; diff --git a/src/v_video.c b/src/v_video.c index 58115e02..a56a5cfc 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1248,26 +1248,40 @@ void V_DrawFadeConsBack(INT32 plines) // Gets string colormap, used for 0x80 color codes // -const UINT8 *V_GetStringColormap(INT32 colorflags) +UINT8 *V_GetStringColormap(INT32 colorflags) { switch ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT) { - case 1: // 0x81, purple + case 1: // 0x81, purple return purplemap; - case 2: // 0x82, yellow + case 2: // 0x82, yellow return yellowmap; - case 3: // 0x83, lgreen + case 3: // 0x83, green return greenmap; - case 4: // 0x84, blue + case 4: // 0x84, blue return bluemap; - case 5: // 0x85, red + case 5: // 0x85, red return redmap; - case 6: // 0x86, gray + case 6: // 0x86, gray return graymap; - case 7: // 0x87, orange + case 7: // 0x87, orange return orangemap; - case 8: // 0x88, sky + case 8: // 0x88, sky return skymap; + case 9: // 0x89, lavender + return lavendermap; + case 10: // 0x8A, gold + return goldmap; + case 11: // 0x8B, tea-green + return teamap; + case 12: // 0x8C, steel + return steelmap; + case 13: // 0x8D, pink + return pinkmap; + case 14: // 0x8E, teal + return tealmap; + case 15: // 0x8F, peach + return peachmap; default: // reset return NULL; } @@ -1359,7 +1373,7 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) for (i = 0; i < slen; ++i) { c = newstring[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09 continue; if (c == '\n') @@ -1424,6 +1438,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) } charflags = (option & V_CHARCOLORMASK); + colormap = V_GetStringColormap(charflags); switch (option & V_SPACINGMASK) { @@ -1447,7 +1462,10 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) { // manually set flags override color codes if (!(option & V_CHARCOLORMASK)) + { charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK; + colormap = V_GetStringColormap(charflags); + } continue; } if (*ch == '\n') @@ -1490,7 +1508,6 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) continue; } - colormap = V_GetStringColormap(charflags); V_DrawFixedPatch((cx + center)<= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09 continue; c = toupper(c) - HU_FONTSTART; @@ -2192,7 +2218,7 @@ INT32 V_SmallStringWidth(const char *string, INT32 option) for (i = 0; i < strlen(string); i++) { c = string[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09 continue; c = toupper(c) - HU_FONTSTART; @@ -2232,7 +2258,7 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) for (i = 0; i < strlen(string); i++) { c = string[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09 continue; c = toupper(c) - HU_FONTSTART; diff --git a/src/v_video.h b/src/v_video.h index e118d5cf..f6826cf7 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -66,8 +66,6 @@ extern UINT8 hudtrans; #define V_MONOSPACE 0x00000C00 // Don't do width checks on characters, all characters 8 width // use bits 13-16 for colors -// though we only have 7 colors now, perhaps we can introduce -// more as needed later #define V_CHARCOLORSHIFT 12 #define V_CHARCOLORMASK 0x0000F000 // for simplicity's sake, shortcuts to specific colors @@ -79,6 +77,13 @@ extern UINT8 hudtrans; #define V_GRAYMAP 0x00006000 #define V_ORANGEMAP 0x00007000 #define V_SKYMAP 0x00008000 +#define V_LAVENDERMAP 0x00009000 +#define V_GOLDMAP 0x0000A000 +#define V_TEAMAP 0x0000B000 +#define V_STEELMAP 0x0000C000 +#define V_PINKMAP 0x0000D000 +#define V_TEALMAP 0x0000E000 +#define V_PEACHMAP 0x0000F000 // use bits 17-20 for alpha transparency #define V_ALPHASHIFT 16 @@ -157,7 +162,7 @@ void V_DrawFadeConsBack(INT32 plines); void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); // draw a single character, but for the chat void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap); -const UINT8 *V_GetStringColormap(INT32 colorflags); +UINT8 *V_GetStringColormap(INT32 colorflags); void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string); From 81c04480f91b43ddc78e761eaaeb2113b9ca9231 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Sep 2018 20:56:44 +0100 Subject: [PATCH 72/84] List update as requested by Sal --- src/hu_stuff.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 33d4f2aa..ab427b48 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -725,13 +725,13 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) else { const UINT8 color = players[playernum].skincolor; - if (color <= SKINCOLOR_SILVER) + if (color <= SKINCOLOR_SILVER || color == SKINCOLOR_SLATE) cstart = "\x80"; // white else if (color <= SKINCOLOR_BEIGE || color == SKINCOLOR_JET) cstart = "\x86"; // V_GRAYMAP else if (color <= SKINCOLOR_LEATHER) cstart = "\x8A"; // V_GOLDMAP - else if (color <= SKINCOLOR_ROSE || color == SKINCOLOR_RUBY || color == SKINCOLOR_DAWN || color == SKINCOLOR_LILAC) + else if (color <= SKINCOLOR_ROSE || color == SKINCOLOR_LILAC) cstart = "\x8d"; // V_PINKMAP else if (color <= SKINCOLOR_KETCHUP) cstart = "\x85"; // V_REDMAP @@ -741,11 +741,11 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) cstart = "\x8f"; // V_PEACHMAP else if (color <= SKINCOLOR_BRONZE) cstart = "\x8A"; // V_GOLDMAP - else if (color <= SKINCOLOR_MUSTARD || color == SKINCOLOR_LIME) + else if (color <= SKINCOLOR_MUSTARD) cstart = "\x82"; // V_YELLOWMAP else if (color <= SKINCOLOR_PISTACHIO) cstart = "\x8b"; // V_TEAMAP - else if (color <= SKINCOLOR_SWAMP) + else if (color <= SKINCOLOR_SWAMP || color == SKINCOLOR_LIME) cstart = "\x83"; // V_GREENMAP else if (color <= SKINCOLOR_TEAL) cstart = "\x8e"; // V_TEALMAP From f20710fbb470c5be2fc5764ca2921a4536d47ff7 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Sep 2018 21:05:20 +0100 Subject: [PATCH 73/84] Turns out I actually forgot to push this when I did the GL fade colour thing earlier, woops. --- src/hardware/hw_bsp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 38a6026f..e0e4abb4 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -29,6 +29,7 @@ #include "../m_argv.h" #include "../i_video.h" #include "../w_wad.h" +#include "../p_setup.h" // levelfadecol // -------------------------------------------------------------------------- // This is global data for planes rendering From 487e114fee73f4ee4624f5635c7c65a923b40d17 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 22 Sep 2018 18:59:26 -0400 Subject: [PATCH 74/84] raceexittime var --- src/doomstat.h | 2 ++ src/g_game.c | 2 ++ src/p_inter.c | 2 +- src/p_tick.c | 4 ++-- src/p_user.c | 18 +++++++++--------- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index f54abebc..fc13b0e8 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -413,6 +413,8 @@ extern UINT16 extralifetics; // SRB2kart extern tic_t introtime; extern tic_t starttime; +extern tic_t raceexittime; +extern tic_t battleexittime; extern INT32 hyudorotime; extern INT32 stealtime; extern INT32 sneakertime; diff --git a/src/g_game.c b/src/g_game.c index 73d20bfd..e501fa56 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -209,6 +209,8 @@ UINT16 extralifetics = 4*TICRATE; // SRB2kart tic_t introtime = 108+5; // plus 5 for white fade tic_t starttime = 6*TICRATE + (3*TICRATE/4); +tic_t raceexittime = 5*TICRATE + (2*TICRATE/3); +tic_t battleexittime = 8*TICRATE; INT32 hyudorotime = 7*TICRATE; INT32 stealtime = TICRATE/2; INT32 sneakertime = TICRATE + (TICRATE/3); diff --git a/src/p_inter.c b/src/p_inter.c index 74612949..7a148464 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -694,7 +694,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!playeringame[i] || players[i].spectator) continue; - players[i].exiting = (28*TICRATE)/5 + 1; + players[i].exiting = raceexittime+1; } S_StartSound(NULL, sfx_lvpass); } diff --git a/src/p_tick.c b/src/p_tick.c index 3bdc9884..3a55353d 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -448,7 +448,7 @@ static inline void P_DoSpecialStageStuff(void) { if (playeringame[i]) { - players[i].exiting = (28*TICRATE)/5 + 1; + players[i].exiting = raceexittime+1; players[i].pflags &= ~PF_GLIDING; } @@ -485,7 +485,7 @@ static inline void P_DoSpecialStageStuff(void) if (playeringame[i]) { players[i].mo->momx = players[i].mo->momy = 0; - players[i].exiting = (28*TICRATE)/5 + 1; + players[i].exiting = raceexittime+1; } sstimer = 0; diff --git a/src/p_user.c b/src/p_user.c index 165008b7..688e0f7d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -673,7 +673,7 @@ static void P_DeNightserizePlayer(player_t *player) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) players[i].nightstime = 1; // force everyone else to fall too. - player->exiting = 6*TICRATE; + player->exiting = raceexittime+2; stagefailed = true; // NIGHT OVER } @@ -1744,7 +1744,7 @@ void P_DoPlayerExit(player_t *player) S_StartSound(player->mo, sfx_kwin); } - player->exiting = 6*TICRATE; + player->exiting = raceexittime+2; if (cv_inttime.value > 0) P_EndingMusic(player); @@ -1754,15 +1754,15 @@ void P_DoPlayerExit(player_t *player) //countdown2 = countdown + 8*TICRATE; if (P_CheckRacers()) - player->exiting = (28*TICRATE)/5 + 1; + player->exiting = raceexittime+1; } else if (G_BattleGametype()) // Battle Mode exiting { - player->exiting = 8*TICRATE + 1; + player->exiting = battleexittime+1; P_EndingMusic(player); } else - player->exiting = (28*TICRATE)/5 + 2; // Accidental death safeguard??? + player->exiting = raceexittime+2; // Accidental death safeguard??? //player->pflags &= ~PF_GLIDING; /* // SRB2kart - don't need @@ -6572,7 +6572,7 @@ static void P_MovePlayer(player_t *player) S_StartSound(NULL, sfx_s3k6a); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) - players[i].exiting = (28*TICRATE)/5 + 1; + players[i].exiting = raceexittime+1; } else if (player->health > 1) P_DamageMobj(player->mo, NULL, NULL, 1); @@ -9040,8 +9040,8 @@ void P_PlayerThink(player_t *player) } } - if (i == MAXPLAYERS && player->exiting == 6*TICRATE) // finished - player->exiting = (28*TICRATE)/5 + 1; + if (i == MAXPLAYERS && player->exiting == raceexittime+2) // finished + player->exiting = raceexittime+1; // If 10 seconds are left on the timer, // begin the drown music for countdown! @@ -9066,7 +9066,7 @@ void P_PlayerThink(player_t *player) // If it is set, start subtracting // Don't allow it to go back to 0 - if (player->exiting > 1 && (player->exiting < 6*TICRATE || !G_RaceGametype())) // SRB2kart - "&& player->exiting > 1" + if (player->exiting > 1 && (player->exiting < raceexittime+2 || !G_RaceGametype())) // SRB2kart - "&& player->exiting > 1" player->exiting--; if (player->exiting && countdown2) From a3b40c75771b3f4b146ed35a233d8ccc9bf2703e Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 22 Sep 2018 19:00:30 -0400 Subject: [PATCH 75/84] Better particle spread --- src/p_mobj.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 847ae031..9dee0bef 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8303,9 +8303,9 @@ void P_MobjThinker(mobj_t *mobj) } else { - P_SpawnMobj(mobj->x + (P_RandomRange(-32,32)<y + (P_RandomRange(-32,32)<z + (24<x + (P_RandomRange(-48,48)<y + (P_RandomRange(-48,48)<z + (24<flags &= ~MF_NOGRAVITY; if (abs(mobj->z - mobj->movefactor) <= 512<cvmem) From ad8d674e5efd1f66e4d8139e00bdb359db2a67e2 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 22 Sep 2018 19:03:38 -0400 Subject: [PATCH 76/84] Set nogravity on landing Means you can't have a finishline that moves up and down, but eh, thinking this might help the fallback measure disappearing --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 9dee0bef..97cd57f0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8296,9 +8296,9 @@ void P_MobjThinker(mobj_t *mobj) P_SetMobjState(mobj, S_SIGN_END); if (mobj->info->attacksound) S_StartSound(mobj, mobj->info->attacksound); - mobj->z = mobj->movefactor; - //mobj->flags |= MF_NOGRAVITY; // ? + mobj->flags |= MF_NOGRAVITY; // ? mobj->flags &= ~MF_NOCLIPHEIGHT; + mobj->z = mobj->movefactor; mobj->movecount = 0; } else From bb1aaf9d54dc4715d676d3ae027526cc54ed8f4a Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 22 Sep 2018 19:55:26 -0400 Subject: [PATCH 77/84] New sparkles --- src/dehacked.c | 15 ++++++++++++++- src/info.c | 28 ++++++++++++++++++++-------- src/info.h | 16 +++++++++++++++- src/p_mobj.c | 2 +- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index f394a742..037795d2 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6205,6 +6205,19 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RANDOMITEMPOP4", //} + // Signpost sparkles + "S_SIGNSPARK1", + "S_SIGNSPARK2", + "S_SIGNSPARK3", + "S_SIGNSPARK4", + "S_SIGNSPARK5", + "S_SIGNSPARK6", + "S_SIGNSPARK7", + "S_SIGNSPARK8", + "S_SIGNSPARK9", + "S_SIGNSPARK10", + "S_SIGNSPARK11", + // Drift Sparks "S_DRIFTSPARK_A1", "S_DRIFTSPARK_A2", @@ -7206,7 +7219,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BLUEDIAG", "MT_RANDOMITEM", "MT_RANDOMITEMPOP", - "MT_RINGSPARKLE", + "MT_SIGNSPARKLE", "MT_FASTLINE", "MT_FASTDUST", diff --git a/src/info.c b/src/info.c index 58d25b07..91e4020c 100644 --- a/src/info.c +++ b/src/info.c @@ -55,12 +55,12 @@ char sprnames[NUMSPRITES + 1][5] = "GWLR","SRBA","SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI", "SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO", //SRB2kart Sprites - "SPRG","BSPR","RNDM","RPOP","FAST","DSHR","BOST","BOSM","KFRE","KINV", - "KINF","WIPD","DRIF","DUST","FITM","BANA","ORBN","JAWZ","SSMN","KRBM", - "BHOG","BHBM","BLIG","LIGH","THNS","SINK","SITR","KBLN","DEZL","POKE", - "AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO","CRAB", - "SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM", - "ITMO","ITMI","ITMN","WANT","PBOM","RETI","VIEW" + "SPRG","BSPR","RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE", + "KINV","KINF","WIPD","DRIF","DUST","FITM","BANA","ORBN","JAWZ","SSMN", + "KRBM","BHOG","BHBM","BLIG","LIGH","THNS","SINK","SITR","KBLN","DEZL", + "POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO", + "CRAB","SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO", + "ITEM","ITMO","ITMI","ITMN","WANT","PBOM","RETI","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -2535,6 +2535,18 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3 {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 + {SPR_SGNS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 + {SPR_SGNS, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 + {SPR_SGNS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 + {SPR_SGNS, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_SIGNSPARK5}, // S_SIGNSPARK4 + {SPR_SGNS, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_SIGNSPARK6}, // S_SIGNSPARK5 + {SPR_SGNS, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_SIGNSPARK7}, // S_SIGNSPARK6 + {SPR_SGNS, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_SIGNSPARK8}, // S_SIGNSPARK7 + {SPR_SGNS, FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_SIGNSPARK9}, // S_SIGNSPARK8 + {SPR_SGNS, FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_SIGNSPARK10}, // S_SIGNSPARK9 + {SPR_SGNS, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_SIGNSPARK11}, // S_SIGNSPARK10 + {SPR_SGNS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_NULL}, // S_SIGNSPARK11 + {SPR_DRIF, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DRIFTSPARK_A2}, // S_DRIFTSPARK_A1 {SPR_DRIF, FF_FULLBRIGHT|FF_TRANS20|1, 1, {NULL}, 0, 0, S_DRIFTSPARK_A3}, // S_DRIFTSPARK_A2 {SPR_DRIF, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_NULL}, // S_DRIFTSPARK_A3 @@ -14385,9 +14397,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_RINGSPARKLE + { // MT_SIGNSPARKLE -1, // doomednum - S_SPRK1, // spawnstate + S_SIGNSPARK1, // spawnstate 1, // spawnhealth S_NULL, // seestate sfx_None, // seesound diff --git a/src/info.h b/src/info.h index 1891b481..ccbcc51d 100644 --- a/src/info.h +++ b/src/info.h @@ -582,6 +582,7 @@ typedef enum sprite SPR_RNDM, // Random Item Box SPR_RPOP, // Random Item Box Pop + SPR_SGNS, // Signpost sparkle SPR_FAST, // Speed boost trail SPR_DSHR, // Speed boost dust release SPR_BOST, // Sneaker booster flame @@ -3050,6 +3051,19 @@ typedef enum state S_RANDOMITEMPOP4, //} + // Signpost sparkles + S_SIGNSPARK1, + S_SIGNSPARK2, + S_SIGNSPARK3, + S_SIGNSPARK4, + S_SIGNSPARK5, + S_SIGNSPARK6, + S_SIGNSPARK7, + S_SIGNSPARK8, + S_SIGNSPARK9, + S_SIGNSPARK10, + S_SIGNSPARK11, + // Drift Sparks S_DRIFTSPARK_A1, S_DRIFTSPARK_A2, @@ -4068,7 +4082,7 @@ typedef enum mobj_type MT_BLUEDIAG, MT_RANDOMITEM, MT_RANDOMITEMPOP, - MT_RINGSPARKLE, + MT_SIGNSPARKLE, MT_FASTLINE, MT_FASTDUST, diff --git a/src/p_mobj.c b/src/p_mobj.c index 97cd57f0..d39e3876 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8306,7 +8306,7 @@ void P_MobjThinker(mobj_t *mobj) P_SpawnMobj(mobj->x + (P_RandomRange(-48,48)<y + (P_RandomRange(-48,48)<z + (24<flags &= ~MF_NOGRAVITY; if (abs(mobj->z - mobj->movefactor) <= 512<cvmem) { From 8a06e78ab64d440215e4ab28f39d6d0abb3424d4 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 22 Sep 2018 20:14:32 -0400 Subject: [PATCH 78/84] Quick fix for other player's win/lose not playing --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 6fd8e634..2d36e207 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1728,7 +1728,7 @@ void P_DoPlayerExit(player_t *player) else if (!countdown) countdown = cv_countdowntime.value*TICRATE + 1; // Use cv_countdowntime - if (cv_kartvoices.value && P_IsLocalPlayer(player)) + if (cv_kartvoices.value) { if (P_IsLocalPlayer(player)) { From c63518e0b2e2c08b9e783660bef67219405faa60 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 22 Sep 2018 20:15:12 -0400 Subject: [PATCH 79/84] Doing this looks more appealing to me --- src/p_user.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 2d36e207..9ac131b4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1734,15 +1734,10 @@ void P_DoPlayerExit(player_t *player) { sfxenum_t sfx_id; if (K_IsPlayerLosing(player)) - { sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound]; - S_StartSound(NULL, sfx_id); - } else - { sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound]; - S_StartSound(NULL, sfx_id); - } + S_StartSound(NULL, sfx_id); } else { From 2e158f2c2144d910ddf9906d921e1804e87d7e7d Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Sep 2018 13:22:00 +0100 Subject: [PATCH 80/84] Add a scroll bar to the addons menu. Should hopefully make the temperature gauge a little less problematic... --- src/m_menu.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index cbcd44dd..055eab80 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4530,8 +4530,9 @@ static boolean M_AddonsRefresh(void) static void M_DrawAddons(void) { INT32 x, y; - ssize_t i, max; + ssize_t i, m; const UINT8 *flashcol = NULL; + UINT8 hilicol; // hack - need to refresh at end of frame to handle addfile... if (refreshdirmenu & M_AddonsRefresh()) @@ -4565,26 +4566,45 @@ static void M_DrawAddons(void) x = currentMenu->x; y = currentMenu->y + 1; + hilicol = V_GetStringColormap(highlightflags)[120]; + V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath()); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), (MAXSTRINGLENGTH*8+6 - 1), 1, V_GetStringColormap(highlightflags)[120]); - V_DrawFill(x-21 + (MAXSTRINGLENGTH*8+6 - 1), (y - 16) + (lsheadingheight - 3), 1, 1, 30); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), MAXSTRINGLENGTH*8+6, 1, hilicol); V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30); - V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1), 239); + m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1); + V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 239); + + // scrollbar! + if (sizedirmenu <= (2*numaddonsshown + 1)) + i = 0; + else + { + ssize_t q = m; + m = ((2*numaddonsshown + 1) * m)/sizedirmenu; + if (dir_on[menudepthleft] <= numaddonsshown) // all the way up + i = 0; + else if (sizedirmenu <= (dir_on[menudepthleft] + numaddonsshown + 1)) // all the way down + i = q-m; + else + i = ((dir_on[menudepthleft] - numaddonsshown) * (q-m))/(sizedirmenu - (2*numaddonsshown + 1)); + } + + V_DrawFill(x + MAXSTRINGLENGTH*8+5 - 21, (y - 1) + i, 1, m, hilicol); // get bottom... - max = dir_on[menudepthleft] + numaddonsshown + 1; - if (max > (ssize_t)sizedirmenu) - max = sizedirmenu; + m = dir_on[menudepthleft] + numaddonsshown + 1; + if (m > (ssize_t)sizedirmenu) + m = sizedirmenu; // then top... - i = max - (2*numaddonsshown + 1); + i = m - (2*numaddonsshown + 1); // then adjust! if (i < 0) { - if ((max -= i) > (ssize_t)sizedirmenu) - max = sizedirmenu; + if ((m -= i) > (ssize_t)sizedirmenu) + m = sizedirmenu; i = 0; } @@ -4594,7 +4614,7 @@ static void M_DrawAddons(void) if (skullAnimCounter < 4) flashcol = V_GetStringColormap(highlightflags); - for (; i < max; i++) + for (; i < m; i++) { UINT32 flags = V_ALLOWLOWERCASE; if (y > BASEVIDHEIGHT) break; @@ -4626,7 +4646,7 @@ static void M_DrawAddons(void) y += 16; } - if (max != (ssize_t)sizedirmenu) + if (m != (ssize_t)sizedirmenu) V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B"); y = BASEVIDHEIGHT - currentMenu->y + 1; From c5e16f183eb06e772996ab1445883ff597d4adf5 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Sep 2018 13:23:03 +0100 Subject: [PATCH 81/84] Fix Sryder's crash (incorrect setting of dir_on when searching in subfolders). Also, correct a minor copypaste failure in one of the I_Errors' messages. --- src/filesrch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/filesrch.c b/src/filesrch.c index e1e2b39d..98be1f39 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -701,7 +701,7 @@ void searchfilemenu(char *tempname) if (tempname) { - dir_on[menudepthleft] = first; + dir_on[menudepthleft] = 0; //first; -- can't be first, causes problems Z_Free(tempname); } } @@ -886,7 +886,7 @@ boolean preparefilemenu(boolean samedepth) if ((menudepthleft != menudepth-1) // now for UP... entry && !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP)))) - I_Error("searchfilemenu(): could not create \"UP...\"."); + I_Error("preparefilemenu(): could not create \"UP...\"."); menupath[menupathindex[menudepthleft]] = 0; sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind From fa65cbb43efb7a07e38fa5425bc2bc60633720ee Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Sep 2018 13:34:49 +0100 Subject: [PATCH 82/84] Somehow butchered the code cleanliness (indentation/not taking advantage of a macro I defined specifically for this) here a little by accident - tidied up. --- src/m_menu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 055eab80..6199ecf3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4622,12 +4622,13 @@ static void M_DrawAddons(void) #define type (UINT8)(dirmenu[i][DIR_TYPE]) { if (type & EXT_LOADED) - flags |= V_TRANSLUCENT; - - V_DrawSmallScaledPatch(x-(16+4), y, (flags & V_TRANSLUCENT), addonsp[((UINT8)(dirmenu[i][DIR_TYPE]) & ~EXT_LOADED)]); - - if (type & EXT_LOADED) + { + flags |= V_TRANSLUCENT; + V_DrawSmallScaledPatch(x-(16+4), y, V_TRANSLUCENT, addonsp[(type & ~EXT_LOADED)]); V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+2]); + } + else + V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[(type & ~EXT_LOADED)]); if ((size_t)i == dir_on[menudepthleft]) { From 73116f2b6009dd1d4ce2aea120a1fff5fbd9c872 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Sep 2018 16:13:58 +0100 Subject: [PATCH 83/84] The pipeline halted for some reason, so here's the smallest possible legitimate change to bump it back into action: Replacing commenting-out with `#ifdef`ing. --- src/m_menu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 6199ecf3..5d0448ce 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4731,12 +4731,15 @@ static void M_HandleAddons(INT32 choice) char *tempname = NULL; if (dirmenu && dirmenu[dir_on[menudepthleft]]) tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL - searchfilemenu(tempname); - /*if (!preparefilemenu(true)) +#if 0 // much slower + if (!preparefilemenu(true)) { UNEXIST; return; - }*/ + } +#else // streamlined + searchfilemenu(tempname); +#endif } switch (choice) From d2d6e67f48c1a246f107dc4db6d5a39b63523e84 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 23 Sep 2018 16:39:07 +0100 Subject: [PATCH 84/84] Forgot I did this optimisation! Updated for the new colours. --- src/v_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v_video.c b/src/v_video.c index f8842cda..46d34acc 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1291,7 +1291,7 @@ UINT8 *V_GetStringColormap(INT32 colorflags) } #else // optimised colorflags = ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT); - if (!colorflags || colorflags > 8) // INT32 is signed, but V_CHARCOLORMASK is a very restrictive mask. + if (!colorflags || colorflags > 15) // INT32 is signed, but V_CHARCOLORMASK is a very restrictive mask. return NULL; return (purplemap+((colorflags-1)<<8)); #endif