From 861d0d0b0a59e5a0151e2355fe971437a844e71b Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jun 2019 13:33:35 +0100 Subject: [PATCH 01/34] Improve rain/weather. * Like Kart, remove cv_precipdensity. * Like Kart, replace "Infinite" draw distance value with "None". * Better thinker with more return optimisation. * Better placement of thinking in rendering, to avoid ceiling-mounted sprite glitches. --- src/hardware/hw_main.c | 29 +++++++++++------------------ src/m_menu.c | 11 +++++------ src/p_mobj.c | 23 ++++++++++++----------- src/r_main.c | 14 ++++++++++---- src/r_main.h | 2 +- src/r_things.c | 32 +++++++++++++------------------- 6 files changed, 52 insertions(+), 59 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c79452bb5..cb0009da7 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5431,7 +5431,7 @@ static void HWR_AddSprites(sector_t *sec) } #ifdef HWPRECIP - // Someone seriously wants infinite draw distance for precipitation? + // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS)) { for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) @@ -5447,13 +5447,6 @@ static void HWR_AddSprites(sector_t *sec) HWR_ProjectPrecipitationSprite(precipthing); } } - else - { - // Draw everything in sector, no checks - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) - if (!(precipthing->precipflags & PCF_INVISIBLE)) - HWR_ProjectPrecipitationSprite(precipthing); - } #endif } @@ -5774,16 +5767,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) x1 = tr_x + x1 * rightcos; x2 = tr_x - x2 * rightcos; - // okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok - if (!(thing->precipflags & PCF_THUNK)) - { - if (thing->precipflags & PCF_RAIN) - P_RainThinker(thing); - else - P_SnowThinker(thing); - thing->precipflags |= PCF_THUNK; - } - // // store information in a vissprite // @@ -5804,6 +5787,16 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); vis->precip = true; + + // okay... this is a hack, but weather isn't networked, so it should be ok + if (!(thing->precipflags & PCF_THUNK)) + { + if (thing->precipflags & PCF_RAIN) + P_RainThinker(thing); + else + P_SnowThinker(thing); + thing->precipflags |= PCF_THUNK; + } } #endif diff --git a/src/m_menu.c b/src/m_menu.c index 4f78d0adc..6fea99046 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1193,13 +1193,12 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_HEADER, NULL, "Level", NULL, 155}, {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 161}, - {IT_STRING | IT_CVAR, NULL, "NiGHTS Draw Dist.", &cv_drawdist_nights, 166}, - {IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 171}, - {IT_STRING | IT_CVAR, NULL, "Weather Density", &cv_precipdensity, 176}, + {IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 166}, + {IT_STRING | IT_CVAR, NULL, "NiGHTS mode Draw Dist.", &cv_drawdist_nights, 171}, - {IT_HEADER, NULL, "Diagnostic", NULL, 185}, - {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 191}, - {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 196}, + {IT_HEADER, NULL, "Diagnostic", NULL, 180}, + {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 186}, + {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 191}, }; static menuitem_t OP_VideoModeMenu[] = diff --git a/src/p_mobj.c b/src/p_mobj.c index bc43fbe1e..e9c4d12cf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4101,17 +4101,18 @@ void P_RainThinker(precipmobj_t *mobj) } // adjust height - if ((mobj->z += mobj->momz) <= mobj->floorz) + if ((mobj->z += mobj->momz) > mobj->floorz) + return; + + // no splashes on sky or bottomless pits + if (mobj->precipflags & PCF_PIT) { - // no splashes on sky or bottomless pits - if (mobj->precipflags & PCF_PIT) - mobj->z = mobj->ceilingz; - else - { - mobj->z = mobj->floorz; - P_SetPrecipMobjState(mobj, S_SPLASH1); - } + mobj->z = mobj->ceilingz; + return; } + + mobj->z = mobj->floorz; + P_SetPrecipMobjState(mobj, S_SPLASH1); } static void P_RingThinker(mobj_t *mobj) @@ -9431,7 +9432,7 @@ void P_SpawnPrecipitation(void) subsector_t *precipsector = NULL; precipmobj_t *rainmo = NULL; - if (dedicated || !cv_precipdensity.value || curWeather == PRECIP_NONE) + if (dedicated || /*!cv_precipdensity*/!cv_drawdist_precip.value || curWeather == PRECIP_NONE) return; // Use the blockmap to narrow down our placing patterns @@ -9440,7 +9441,7 @@ void P_SpawnPrecipitation(void) basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE; basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE; - for (j = 0; j < cv_precipdensity.value; ++j) + //for (j = 0; j < cv_precipdensity.value; ++j) -- density is 1 for us always { x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); diff --git a/src/r_main.c b/src/r_main.c index 273d13a56..db351e991 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -98,7 +98,14 @@ static CV_PossibleValue_t drawdist_cons_t[] = { {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, {3072, "3072"}, {4096, "4096"}, {6144, "6144"}, {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; -static CV_PossibleValue_t precipdensity_cons_t[] = {{0, "None"}, {1, "Light"}, {2, "Moderate"}, {4, "Heavy"}, {6, "Thick"}, {8, "V.Thick"}, {0, NULL}}; + +//static CV_PossibleValue_t precipdensity_cons_t[] = {{0, "None"}, {1, "Light"}, {2, "Moderate"}, {4, "Heavy"}, {6, "Thick"}, {8, "V.Thick"}, {0, NULL}}; + +static CV_PossibleValue_t drawdist_precip_cons_t[] = { + {256, "256"}, {512, "512"}, {768, "768"}, + {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, + {0, "None"}, {0, NULL}}; + static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}}; @@ -126,8 +133,8 @@ consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_c consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +//consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // Okay, whoever said homremoval causes a performance hit should be shot. consvar_t cv_homremoval = {"homremoval", "No", CV_SAVE, homremoval_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -1158,7 +1165,6 @@ void R_RegisterEngineStuff(void) if (dedicated) return; - CV_RegisterVar(&cv_precipdensity); CV_RegisterVar(&cv_translucency); CV_RegisterVar(&cv_drawdist); CV_RegisterVar(&cv_drawdist_nights); diff --git a/src/r_main.h b/src/r_main.h index 1d82a01b9..2c9b5cc3d 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -78,7 +78,7 @@ extern consvar_t cv_chasecam, cv_chasecam2; extern consvar_t cv_flipcam, cv_flipcam2; extern consvar_t cv_shadow, cv_shadowoffs; extern consvar_t cv_translucency; -extern consvar_t cv_precipdensity, cv_drawdist, cv_drawdist_nights, cv_drawdist_precip; +extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip; extern consvar_t cv_skybox; extern consvar_t cv_tailspickup; diff --git a/src/r_things.c b/src/r_things.c index f5482683f..50ee8e6ef 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1527,16 +1527,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; } - // okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok - if (!(thing->precipflags & PCF_THUNK)) - { - if (thing->precipflags & PCF_RAIN) - P_RainThinker(thing); - else - P_SnowThinker(thing); - thing->precipflags |= PCF_THUNK; - } - //SoM: 3/17/2000: Disregard sprites that are out of view.. gzt = thing->z + spritecachedinfo[lump].topoffset; @@ -1545,7 +1535,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) if (thing->subsector->sector->cullheight) { if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) - return; + goto weatherthink; } // store information in a vissprite @@ -1605,6 +1595,17 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // Fullbright vis->colormap = colormaps; + +weatherthink: + // okay... this is a hack, but weather isn't networked, so it should be ok + if (!(thing->precipflags & PCF_THUNK)) + { + if (thing->precipflags & PCF_RAIN) + P_RainThinker(thing); + else + P_SnowThinker(thing); + thing->precipflags |= PCF_THUNK; + } } // R_AddSprites @@ -1669,7 +1670,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) R_ProjectSprite(thing); } - // Someone seriously wants infinite draw distance for precipitation? + // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS)) { for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) @@ -1685,13 +1686,6 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) R_ProjectPrecipitationSprite(precipthing); } } - else - { - // Draw everything in sector, no checks - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) - if (!(precipthing->precipflags & PCF_INVISIBLE)) - R_ProjectPrecipitationSprite(precipthing); - } } // From 96d6cea569c646d48039d693a745ab4a80a31d07 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jun 2019 14:36:06 +0100 Subject: [PATCH 02/34] Support backspace for resetting various menu values, just like Kart. --- src/m_menu.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 6fea99046..f5b82d297 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2668,20 +2668,35 @@ static void M_ChangeCvar(INT32 choice) { consvar_t *cv = (consvar_t *)currentMenu->menuitems[itemOn].itemaction; + if (choice == -1) + { + if (cv == &cv_playercolor) + { + SINT8 skinno = R_SkinAvailable(cv_chooseskin.string); + if (skinno != -1) + CV_SetValue(cv,skins[skinno].prefcolor); + return; + } + CV_Set(cv,cv->defaultvalue); + return; + } + + choice = (choice<<1) - 1; + if (((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_SLIDER) ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_NOMOD)) { - CV_SetValue(cv,cv->value+(choice*2-1)); + CV_SetValue(cv,cv->value+(choice)); } else if (cv->flags & CV_FLOAT) { char s[20]; - sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice*2-1)*(1.0f/16.0f)); + sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); CV_Set(cv,s); } else - CV_AddValue(cv,choice*2-1); + CV_AddValue(cv,choice); } static boolean M_ChangeStringCvar(INT32 choice) @@ -3117,6 +3132,23 @@ boolean M_Responder(event_t *ev) S_StartSound(NULL, sfx_shldls); return true; } + + if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS + || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) + { + consvar_t *cv = (consvar_t *)currentMenu->menuitems[itemOn].itemaction; + + if (cv == &cv_chooseskin + || cv == &cv_nextmap + || cv == &cv_newgametype) + return true; + + if (currentMenu != &OP_SoundOptionsDef || itemOn > 3) + S_StartSound(NULL, sfx_menu1); + routine(-1); + return true; + } + // Why _does_ backspace go back anyway? //currentMenu->lastOn = itemOn; //if (currentMenu->prevMenu) @@ -9557,6 +9589,16 @@ static void M_HandleSetupMultiPlayer(INT32 choice) S_StartSound(NULL,sfx_menu1); // Tails setupm_name[l-1] = 0; } + else if (itemOn == 2) + { + UINT8 col = skins[setupm_fakeskin].prefcolor; + if (setupm_fakecolor != col) + { + S_StartSound(NULL,sfx_menu1); // Tails + setupm_fakecolor = col; + } + } + break; break; case KEY_DEL: From 1d65caa250a0231bee8efffe9f6e354f9191b5d6 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jun 2019 17:55:57 +0100 Subject: [PATCH 03/34] With permission from Kart Krew (Sal and Sryder specifically - they don't know WHY vanilla's using it): * Port across the additional colour translation maps, including mobj-level support for "colorized" objects. * Make Fangboss and both Metal Sonic objects greyscale if, on spawn, there is a player in the game who is not a spectator whose skin is that character. * Allow bosses with MF_GRENADEBOUNCE to opt out of the MF2_FRET colour-flashing tomfoolery, and give this flag to Fang. --- src/dehacked.c | 9 +++ src/hardware/hw_main.c | 6 +- src/hardware/hw_md2.c | 166 ++++++++++++++++++++++++++++++++--------- src/info.c | 2 +- src/lua_hudlib.c | 4 +- src/lua_mobjlib.c | 14 +++- src/p_mobj.c | 27 ++++++- src/p_mobj.h | 2 + src/p_saveg.c | 14 ++-- src/r_draw.c | 87 +++++++++++++++++++-- src/r_draw.h | 2 + src/r_things.c | 10 ++- 12 files changed, 286 insertions(+), 57 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 6d1f58990..b8417ea59 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -28,6 +28,7 @@ #include "p_local.h" // for var1 and var2, and some constants #include "p_setup.h" #include "r_data.h" +#include "r_draw.h" #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" @@ -8728,6 +8729,14 @@ struct { {"KR_TIMEOUT",KR_TIMEOUT}, {"KR_BAN",KR_BAN}, {"KR_LEAVE",KR_LEAVE}, + + // translation colormaps + {"TC_DEFAULT",TC_DEFAULT}, + {"TC_BOSS",TC_BOSS}, + {"TC_METALSONIC",TC_METALSONIC}, + {"TC_ALLWHITE",TC_ALLWHITE}, + {"TC_RAINBOW",TC_RAINBOW}, + {"TC_BLINK",TC_BLINK}, #endif {NULL,0} diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index cb0009da7..a76c9e1c8 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5660,7 +5660,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->z2 = z2; //Hurdler: 25/04/2000: now support colormap in hardware mode - if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" + if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { if (vis->mobj->type == MT_CYBRAKDEMON) vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); @@ -5672,7 +5672,9 @@ static void HWR_ProjectSprite(mobj_t *thing) else if (thing->color) { // New colormap stuff for skins Tails 06-07-2002 - if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player! + if (thing->colorized) + vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE); + else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player! { size_t skinnum = (skin_t*)thing->skin-skins; vis->colormap = R_GetTranslationColormap((INT32)skinnum, thing->color, GTC_CACHE); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index d69233a9b..6db5d5f08 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -40,6 +40,8 @@ #include "../w_wad.h" #include "../z_zone.h" #include "../r_things.h" +#include "../r_draw.h" +#include "../p_tick.h" #include "hw_main.h" #include "../v_video.h" @@ -978,8 +980,18 @@ spritemd2found: fclose(f); } -static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, skincolors_t color) +// Define for getting accurate color brightness readings according to how the human eye sees them. +// https://en.wikipedia.org/wiki/Relative_luminance +// 0.2126 to red +// 0.7152 to green +// 0.0722 to blue +// (See this same define in k_kart.c!) +#define SETBRIGHTNESS(brightness,r,g,b) \ + brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3) + +static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color) { + UINT8 i; UINT16 w = gpatch->width, h = gpatch->height; UINT32 size = w*h; RGBA_t *image, *blendimage, *cur, blendcolor; @@ -1005,50 +1017,112 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, image = gpatch->mipmap.grInfo.data; blendimage = blendgpatch->mipmap.grInfo.data; + // Average all of the translation's colors if (color == SKINCOLOR_NONE || color >= MAXTRANSLATIONS) blendcolor = V_GetColor(0xff); else - blendcolor = V_GetColor(Color_Index[color-1][4]); - - while (size--) { - if (blendimage->s.alpha == 0) - { - // Don't bother with blending the pixel if the alpha of the blend pixel is 0 - cur->rgba = image->rgba; - } - else - { - INT32 tempcolor; - INT16 tempmult, tempalpha; - tempalpha = -(abs(blendimage->s.red-127)-127)*2; - if (tempalpha > 255) - tempalpha = 255; - else if (tempalpha < 0) - tempalpha = 0; + const UINT8 div = 6; + const UINT8 start = 4; + UINT32 r, g, b; - tempmult = (blendimage->s.red-127)*2; - if (tempmult > 255) - tempmult = 255; - else if (tempmult < 0) - tempmult = 0; + blendcolor = V_GetColor(Color_Index[color-1][start]); + r = (UINT32)(blendcolor.s.red*blendcolor.s.red); + g = (UINT32)(blendcolor.s.green*blendcolor.s.green); + b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue); - tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255; - cur->s.red = (UINT8)tempcolor; - tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255; - cur->s.green = (UINT8)tempcolor; - tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255; - cur->s.blue = (UINT8)tempcolor; - cur->s.alpha = image->s.alpha; + for (i = 1; i < div; i++) + { + RGBA_t nextcolor = V_GetColor(Color_Index[color-1][start+i]); + r += (UINT32)(nextcolor.s.red*nextcolor.s.red); + g += (UINT32)(nextcolor.s.green*nextcolor.s.green); + b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue); } - cur++; image++; blendimage++; + blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<>FRACBITS); + blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<>FRACBITS); + blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<>FRACBITS); + } + + // rainbow support, could theoretically support boss ones too + if (skinnum == TC_RAINBOW) + { + while (size--) + { + if (image->s.alpha == 0 && blendimage->s.alpha == 0) + { + // Don't bother with blending the pixel if the alpha of the blend pixel is 0 + cur->rgba = image->rgba; + } + else + { + UINT32 tempcolor; + UINT16 imagebright, blendbright, finalbright, colorbright; + SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue); + SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue); + // slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway + finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255; + SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue); + + tempcolor = (finalbright*blendcolor.s.red)/colorbright; + tempcolor = min(255, tempcolor); + cur->s.red = (UINT8)tempcolor; + tempcolor = (finalbright*blendcolor.s.green)/colorbright; + tempcolor = min(255, tempcolor); + cur->s.green = (UINT8)tempcolor; + tempcolor = (finalbright*blendcolor.s.blue)/colorbright; + tempcolor = min(255, tempcolor); + cur->s.blue = (UINT8)tempcolor; + cur->s.alpha = image->s.alpha; + } + + cur++; image++; blendimage++; + } + } + else + { + while (size--) + { + if (blendimage->s.alpha == 0) + { + // Don't bother with blending the pixel if the alpha of the blend pixel is 0 + cur->rgba = image->rgba; + } + else + { + INT32 tempcolor; + INT16 tempmult, tempalpha; + tempalpha = -(abs(blendimage->s.red-127)-127)*2; + if (tempalpha > 255) + tempalpha = 255; + else if (tempalpha < 0) + tempalpha = 0; + + tempmult = (blendimage->s.red-127)*2; + if (tempmult > 255) + tempmult = 255; + else if (tempmult < 0) + tempmult = 0; + + tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255; + cur->s.red = (UINT8)tempcolor; + tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255; + cur->s.green = (UINT8)tempcolor; + tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255; + cur->s.blue = (UINT8)tempcolor; + cur->s.alpha = image->s.alpha; + } + + cur++; image++; blendimage++; + } } return; } -static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, const UINT8 *colormap, skincolors_t color) +#undef SETBRIGHTNESS + +static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolors_t color) { // mostly copied from HWR_GetMappedPatch, hence the similarities and comment GLMipmap_t *grmip, *newmip; @@ -1089,13 +1163,14 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, con grmip->nextcolormap = newmip; newmip->colormap = colormap; - HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, color); + HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color); HWD.pfnSetTexture(newmip); Z_ChangeTag(newmip->grInfo.data, PU_HWRCACHE_UNLOCKED); } + // -----------------+ // HWR_DrawMD2 : Draw MD2 // : (monsters, bonuses, weapons, lights, ...) @@ -1285,7 +1360,30 @@ void HWR_DrawMD2(gr_vissprite_t *spr) md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format && gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height) { - HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, spr->colormap, (skincolors_t)spr->mobj->color); + INT32 skinnum = TC_DEFAULT; + if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" + { + if (spr->mobj->type == MT_CYBRAKDEMON) + skinnum = TC_ALLWHITE; + else if (spr->mobj->type == MT_METALSONIC_BATTLE) + skinnum = TC_METALSONIC; + else + skinnum = TC_BOSS; + } + else if (spr->mobj->color) + { + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + { + if (spr->mobj->colorized) + skinnum = TC_RAINBOW; + else + { + skinnum = (INT32)((skin_t*)spr->mobj->skin-skins); + } + } + else skinnum = TC_DEFAULT; + } + HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color); } else { diff --git a/src/info.c b/src/info.c index e03b63a65..f1d570fa0 100644 --- a/src/info.c +++ b/src/info.c @@ -5397,7 +5397,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 3, // damage sfx_boingf, // activesound - MF_SPECIAL|MF_BOSS|MF_SHOOTABLE, // flags + MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE, // flags S_NULL // raisestate }, diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index f3a1ba210..8c1134bca 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -670,8 +670,8 @@ static int libd_getColormap(lua_State *L) else if (lua_type(L, 1) == LUA_TNUMBER) // skin number { skinnum = (INT32)luaL_checkinteger(L, 1); - if (skinnum < TC_ALLWHITE || skinnum >= MAXSKINS) - return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_ALLWHITE, MAXSKINS-1); + if (skinnum < TC_BLINK || skinnum >= MAXSKINS) + return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_BLINK, MAXSKINS-1); } else // skin name { diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 0835e5cc0..0a3d356c9 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -83,12 +83,11 @@ enum mobj_e { mobj_extravalue1, mobj_extravalue2, mobj_cusval, -#ifdef ESLOPE mobj_cvmem, - mobj_standingslope -#else - mobj_cvmem +#ifdef ESLOPE + mobj_standingslope, #endif + mobj_colorized }; static const char *const mobj_opt[] = { @@ -154,6 +153,7 @@ static const char *const mobj_opt[] = { #ifdef ESLOPE "standingslope", #endif + "colorized", NULL}; #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) @@ -371,6 +371,9 @@ static int mobj_get(lua_State *L) LUA_PushUserdata(L, mo->standingslope, META_SLOPE); break; #endif + case mobj_colorized: + lua_pushboolean(L, mo->colorized); + break; default: // extra custom variables in Lua memory lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); @@ -692,6 +695,9 @@ static int mobj_set(lua_State *L) case mobj_standingslope: return NOSET; #endif + case mobj_colorized: + mo->colorized = luaL_checkboolean(L, 3); + break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); diff --git a/src/p_mobj.c b/src/p_mobj.c index e9c4d12cf..fd679857e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8894,6 +8894,7 @@ void P_SceneryThinker(mobj_t *mobj) mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { const mobjinfo_t *info = &mobjinfo[type]; + UINT8 sc = -1; state_t *st; mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); @@ -9150,6 +9151,13 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (nummaprings >= 0) nummaprings++; break; + case MT_METALSONIC_BATTLE: + case MT_METALSONIC_RACE: + sc = 3; + break; + case MT_FANG: + sc = 4; + break; case MT_FBOMB: mobj->flags2 |= MF2_EXPLOSION; break; @@ -9157,6 +9165,23 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; } + if (sc != -1) + { + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (players[i].skin == sc) + { + mobj->color = SKINCOLOR_SILVER; + mobj->colorized = true; + break; + } + } + } + if (!(mobj->flags & MF_NOTHINK)) P_AddThinker(&mobj->thinker); @@ -9427,7 +9452,7 @@ consvar_t cv_flagtime = {"flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, void P_SpawnPrecipitation(void) { - INT32 i, j, mrand; + INT32 i, /*j,*/ mrand; fixed_t basex, basey, x, y, height; subsector_t *precipsector = NULL; precipmobj_t *rainmo = NULL; diff --git a/src/p_mobj.h b/src/p_mobj.h index 936be3bb0..bfcb09210 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -371,6 +371,8 @@ typedef struct mobj_s struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) #endif + boolean colorized; // Whether the mobj uses the rainbow colormap + // WARNING: New fields must be added separately to savegame and Lua. } mobj_t; diff --git a/src/p_saveg.c b/src/p_saveg.c index 0d58387b9..d587cba17 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1262,12 +1262,11 @@ typedef enum MD2_HNEXT = 1<<7, MD2_HPREV = 1<<8, MD2_FLOORROVER = 1<<9, -#ifdef ESLOPE MD2_CEILINGROVER = 1<<10, - MD2_SLOPE = 1<<11 -#else - MD2_CEILINGROVER = 1<<10 +#ifdef ESLOPE + MD2_SLOPE = 1<<11, #endif + MD2_COLORIZED = 1<<12, } mobj_diff2_t; typedef enum @@ -1473,6 +1472,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) if (mobj->standingslope) diff2 |= MD2_SLOPE; #endif + if (mobj->colorized) + diff2 |= MD2_COLORIZED; if (diff2 != 0) diff |= MD_MORE; @@ -1635,6 +1636,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) if (diff2 & MD2_SLOPE) WRITEUINT16(save_p, mobj->standingslope->id); #endif + if (diff2 & MD2_COLORIZED) + WRITEUINT8(save_p, mobj->colorized); WRITEUINT32(save_p, mobj->mobjnum); } @@ -2660,7 +2663,8 @@ static void LoadMobjThinker(actionf_p1 thinker) if (diff2 & MD2_SLOPE) mobj->standingslope = P_SlopeById(READUINT16(save_p)); #endif - + if (diff2 & MD2_COLORIZED) + mobj->colorized = READUINT8(save_p); if (diff & MD_REDFLAG) { diff --git a/src/r_draw.c b/src/r_draw.c index 13ac691d5..77bb1b6e7 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -126,10 +126,12 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; #define BOSS_TT_CACHE_INDEX (MAXSKINS + 1) #define METALSONIC_TT_CACHE_INDEX (MAXSKINS + 2) #define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3) +#define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4) +#define BLINK_TT_CACHE_INDEX (MAXSKINS + 5) #define DEFAULT_STARTTRANSCOLOR 96 #define NUM_PALETTE_ENTRIES 256 -static UINT8** translationtablecache[MAXSKINS + 4] = {NULL}; +static UINT8** translationtablecache[MAXSKINS + 6] = {NULL}; const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = { // {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // SKINCOLOR_NONE @@ -457,17 +459,85 @@ void R_InitTranslationTables(void) \return void */ + +// Define for getting accurate color brightness readings according to how the human eye sees them. +// https://en.wikipedia.org/wiki/Relative_luminance +// 0.2126 to red +// 0.7152 to green +// 0.0722 to blue +// (See this same define in hw_md2.c!) +#define SETBRIGHTNESS(brightness,r,g,b) \ + brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3) + +/** \brief Generates the rainbow colourmaps that are used when a player has the invincibility power... stolen from kart, with permission + + \param dest_colormap colormap to populate + \param skincolor translation color +*/ +static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) +{ + INT32 i; + RGBA_t color; + UINT8 brightness; + INT32 j; + UINT8 colorbrightnesses[16]; + UINT16 brightdif; + INT32 temp; + + // first generate the brightness of all the colours of that skincolour + for (i = 0; i < 16; i++) + { + color = V_GetColor(Color_Index[skincolor-1][i]); + SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue); + } + + // next, for every colour in the palette, choose the transcolor that has the closest brightness + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + { + if (i == 0 || i == 31) // pure black and pure white don't change + { + dest_colormap[i] = (UINT8)i; + continue; + } + color = V_GetColor(i); + SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue); + brightdif = 256; + for (j = 0; j < 16; j++) + { + temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]); + if (temp < brightdif) + { + brightdif = (UINT16)temp; + dest_colormap[i] = Color_Index[skincolor-1][j]; + } + } + } +} + +#undef SETBRIGHTNESS + static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) { INT32 i, starttranscolor, skinramplength; // Handle a couple of simple special cases - if (skinnum == TC_BOSS || skinnum == TC_ALLWHITE || skinnum == TC_METALSONIC || color == SKINCOLOR_NONE) + if (skinnum == TC_BOSS + || skinnum == TC_ALLWHITE + || skinnum == TC_METALSONIC + || skinnum == TC_BLINK + || color == SKINCOLOR_NONE) { - for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + if (skinnum == TC_ALLWHITE) + memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8**)); + else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE) { - if (skinnum == TC_ALLWHITE) dest_colormap[i] = 0; - else dest_colormap[i] = (UINT8)i; + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + dest_colormap[i] = Color_Index[color-1][3]; + } + else + { + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + dest_colormap[i] = (UINT8)i; } // White! @@ -478,6 +548,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U return; } + else if (skinnum == TC_RAINBOW) + { + R_RainbowColormap(dest_colormap, color); + return; + } if (color >= MAXTRANSLATIONS) I_Error("Invalid skin color #%hu.", (UINT16)color); @@ -522,6 +597,8 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) else if (skinnum == TC_BOSS) skintableindex = BOSS_TT_CACHE_INDEX; else if (skinnum == TC_METALSONIC) skintableindex = METALSONIC_TT_CACHE_INDEX; else if (skinnum == TC_ALLWHITE) skintableindex = ALLWHITE_TT_CACHE_INDEX; + else if (skinnum == TC_RAINBOW) skintableindex = RAINBOW_TT_CACHE_INDEX; + else if (skinnum == TC_BLINK) skintableindex = BLINK_TT_CACHE_INDEX; else skintableindex = skinnum; if (flags & GTC_CACHE) diff --git a/src/r_draw.h b/src/r_draw.h index 0c04fee2a..82498eb11 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -105,6 +105,8 @@ extern lumpnum_t viewborderlump[8]; #define TC_BOSS -2 #define TC_METALSONIC -3 // For Metal Sonic battle #define TC_ALLWHITE -4 // For Cy-Brak-demon +#define TC_RAINBOW -5 // For single colour +#define TC_BLINK -6 // For item blinking, according to kart // Initialize color translation tables, for player rendering etc. void R_InitTranslationTables(void); diff --git a/src/r_things.c b/src/r_things.c index 50ee8e6ef..115e49600 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -719,7 +719,7 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; - if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" + if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { // translate certain pixels to white colfunc = transcolfunc; @@ -734,7 +734,9 @@ static void R_DrawVisSprite(vissprite_t *vis) { colfunc = transtransfunc; dc_transmap = vis->transmap; - if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> + if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) + dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> { size_t skinnum = (skin_t*)vis->mobj->skin-skins; dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); @@ -753,7 +755,9 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = transcolfunc; // New colormap stuff for skins Tails 06-07-2002 - if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! + if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) + dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! { size_t skinnum = (skin_t*)vis->mobj->skin-skins; dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); From b0326b6dec5065f90f9798ae4fb3801f8f03c920 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 18 Jun 2019 18:51:24 +0100 Subject: [PATCH 04/34] Do some minor HUD fixes. * Move HUD text's anchoring to underneath STR instead of above Lives. * Adjust chat position slightly, to take advantage of SRB2's HUD layout having less content towards the bottom (unlike Kart, where it has roughly equal). * Fix Match emeralds not displaying while in tab rankings with all-seven invuln/shoes bonus active. --- src/hu_stuff.c | 25 ++++++++++---- src/st_stuff.c | 94 +++++++++++++++++++++++++++++--------------------- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index cec0cfe1f..1a77774c8 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1327,7 +1327,7 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) // 30/7/18: chaty is now the distance at which the lowest point of the chat will be drawn if that makes any sense. -INT16 chatx = 13, chaty = 169; // let's use this as our coordinates, shh +INT16 chatx = 14, chaty = 180; // let's use this as our coordinates // chat stuff by VincyTM LOL XD! @@ -1502,8 +1502,8 @@ static void HU_drawChatLog(INT32 offset) if (splitscreen) { y -= BASEVIDHEIGHT/2; - if (splitscreen > 1) - y += 16; + //if (splitscreen > 1) + //y += 16; } #endif y -= (G_RingSlingerGametype() ? 16 : 0); @@ -2302,7 +2302,9 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I | V_ALLOWLOWERCASE, tab[i].name); // Draw emeralds - if (!players[tab[i].num].powers[pw_super] + if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) + HU_DrawEmeralds(x-12,y+2,255); + else if (!players[tab[i].num].powers[pw_super] || ((leveltime/7) & 1)) { HU_DrawEmeralds(x-12,y+2,tab[i].emeralds); @@ -2574,7 +2576,9 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) } // Draw emeralds - if (!players[tab[i].num].powers[pw_super] + if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) + HU_DrawEmeralds(x-12,y+2,255); + else if (!players[tab[i].num].powers[pw_super] || ((leveltime/7) & 1)) { HU_DrawEmeralds(x-12,y+2,tab[i].emeralds); @@ -2646,7 +2650,9 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon); // Draw emeralds - if (!players[tab[i].num].powers[pw_super] + if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) + HU_DrawEmeralds(x-12,y+2,255); + else if (!players[tab[i].num].powers[pw_super] || ((leveltime/7) & 1)) { HU_DrawEmeralds(x-12,y+2,tab[i].emeralds); @@ -2746,7 +2752,12 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, tagico, 0); // Draw emeralds - if (!players[tab[i].num].powers[pw_super] + if (players[tab[i].num].powers[pw_invulnerability] && players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) + { + HU_Draw32Emeralds(x+60, y+2, 255); + //HU_DrawEmeralds(x-12,y+2,255); + } + else if (!players[tab[i].num].powers[pw_super] || ((leveltime/7) & 1)) { HU_Draw32Emeralds(x+60, y+2, tab[i].emeralds); diff --git a/src/st_stuff.c b/src/st_stuff.c index 4509ed849..f0f40ed32 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1968,37 +1968,27 @@ static void ST_drawMatchHUD(void) static void ST_drawTextHUD(void) { - INT32 y = 176 - 16; // HUD_LIVES - boolean dof12 = false, dospecheader = false; + INT32 y = 42 + 16; // HUD_RINGS + boolean donef12 = false; #define textHUDdraw(str) \ {\ V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, str);\ - y -= 8;\ + y += 8;\ } if (F_GetPromptHideHud(y)) return; - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) + if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) + textHUDdraw(M_GetText("\x86""Spectator mode:")) + + if (circuitmap) { - if (leveltime < hidetime * TICRATE) - { - if (stplyr->pflags & PF_TAGIT) - { - textHUDdraw(M_GetText("Waiting for players to hide...")) - textHUDdraw(M_GetText("\x82""You are blindfolded!")) - } - else if (gametype == GT_HIDEANDSEEK) - textHUDdraw(M_GetText("Hide before time runs out!")) - else - textHUDdraw(M_GetText("Flee before you are hunted!")) - } - else if (gametype == GT_HIDEANDSEEK && !(stplyr->pflags & PF_TAGIT)) - { - textHUDdraw(M_GetText("You cannot move while hiding.")) - dof12 = true; - } + if (stplyr->exiting) + textHUDdraw(M_GetText("\x82""FINISHED!")) + else + textHUDdraw(va("Lap:""\x82 %u/%d", stplyr->laps+1, cv_numlaps.value)) } if (!stplyr->spectator && stplyr->exiting && cv_playersforexit.value && gametype == GT_COOP) @@ -2027,13 +2017,23 @@ static void ST_drawTextHUD(void) if (exiting < total) { + if (!splitscreen && !donef12) + { + textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) + donef12 = true; + } total -= exiting; textHUDdraw(va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))) - dof12 = true; } } else if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) - dof12 = true; + { + if (!splitscreen && !donef12) + { + textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) + donef12 = true; + } + } else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; @@ -2045,6 +2045,15 @@ static void ST_drawTextHUD(void) } else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) { + if (!splitscreen && !donef12) + { + textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) + donef12 = true; + } + + textHUDdraw(M_GetText("\x82""JUMP:""\x80 Rise")) + textHUDdraw(M_GetText("\x82""SPIN:""\x80 Lower")) + if (G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) else if (gametype == GT_COOP) @@ -2076,28 +2085,33 @@ static void ST_drawTextHUD(void) } else textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) - - textHUDdraw(M_GetText("\x82""SPIN:""\x80 Lower")) - textHUDdraw(M_GetText("\x82""JUMP:""\x80 Rise")) - - dof12 = true; - dospecheader = true; } - if (!splitscreen && dof12) - textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) - - if (circuitmap) + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) { - if (stplyr->exiting) - textHUDdraw(M_GetText("\x82""FINISHED!")) - else - textHUDdraw(va("Lap:""\x82 %u/%d", stplyr->laps+1, cv_numlaps.value)) + if (leveltime < hidetime * TICRATE) + { + if (stplyr->pflags & PF_TAGIT) + { + textHUDdraw(M_GetText("\x82""You are blindfolded!")) + textHUDdraw(M_GetText("Waiting for players to hide...")) + } + else if (gametype == GT_HIDEANDSEEK) + textHUDdraw(M_GetText("Hide before time runs out!")) + else + textHUDdraw(M_GetText("Flee before you are hunted!")) + } + else if (gametype == GT_HIDEANDSEEK && !(stplyr->pflags & PF_TAGIT)) + { + if (!splitscreen && !donef12) + { + textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) + donef12 = true; + } + textHUDdraw(M_GetText("You cannot move while hiding.")) + } } - if (dospecheader) - textHUDdraw(M_GetText("\x86""Spectator mode:")) - #undef textHUDdraw } From ef6e00e8a28a7f8a471b871e2c0fe485a9f6d4df Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 12:09:02 +0100 Subject: [PATCH 05/34] P_PlayerCanDamage(player_t*, mobj_t*), ported from the abandoned project_birthday because GOD the code looks awful with those huge monolith conditions in it. Available to Lua. (Also, minor fixes to lib_pSpawnLockOn, and removing the SH_OP fuckery.) --- src/lua_baselib.c | 17 ++++++++++++ src/p_inter.c | 19 +++++-------- src/p_local.h | 1 + src/p_map.c | 70 ++++++++++++++++++++--------------------------- src/p_mobj.c | 9 +++--- src/p_user.c | 36 ++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 57 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 755b76835..192e2b6cb 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -540,6 +540,7 @@ static int lib_pSpawnLockOn(lua_State *L) { mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker visual->target = lockon; + visual->flags2 |= MF2_DONTDRAW; P_SetMobjStateNF(visual, state); } return 0; @@ -951,6 +952,21 @@ static int lib_pResetPlayer(lua_State *L) return 0; } +static int lib_pPlayerCanDamage(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + //HUDSAFE + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + if (!thing) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_PlayerCanDamage(player, thing)); + return 1; +} + + static int lib_pIsObjectInGoop(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -2774,6 +2790,7 @@ static luaL_Reg lib[] = { {"P_PlayerInPain",lib_pPlayerInPain}, {"P_DoPlayerPain",lib_pDoPlayerPain}, {"P_ResetPlayer",lib_pResetPlayer}, + {"P_PlayerCanDamage",lib_pPlayerCanDamage}, {"P_IsObjectInGoop",lib_pIsObjectInGoop}, {"P_IsObjectOnGround",lib_pIsObjectOnGround}, {"P_InSpaceSector",lib_pInSpaceSector}, diff --git a/src/p_inter.c b/src/p_inter.c index 68f1782c5..42722e6d1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -453,13 +453,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) break; } - if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) - || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) - || (player->pflags & (PF_SPINNING|PF_GLIDING)) - || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) - || ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0)) - || player->powers[pw_invulnerability] || player->powers[pw_super] - || elementalpierce) // Do you possess the ability to subdue the object? + if (player->powers[pw_invulnerability] || player->powers[pw_super] + || P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object? { if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) { @@ -1750,6 +1745,10 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour deadtarget = (player->mo->health <= 0); + // Don't log every hazard hit if they don't want us to. + if (!deadtarget && !cv_hazardlog.value) + return; + // Target's name snprintf(targetname, sizeof(targetname), "%s%s%s", CTFTEAMCODE(player), @@ -1853,7 +1852,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour switch (damagetype) { case DMG_WATER: - str = M_GetText("%s was %s by chemical water.\n"); + str = M_GetText("%s was %s by dangerous water.\n"); break; case DMG_FIRE: str = M_GetText("%s was %s by molten lava.\n"); @@ -1901,10 +1900,6 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour if (!str) // Should not happen! Unless we missed catching something above. return; - // Don't log every hazard hit if they don't want us to. - if (!deadtarget && !cv_hazardlog.value) - return; - if (deathonly) { if (!deadtarget) diff --git a/src/p_local.h b/src/p_local.h index b686b9f09..f93ea7147 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -128,6 +128,7 @@ pflags_t P_GetJumpFlags(player_t *player); boolean P_PlayerInPain(player_t *player); void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor); void P_ResetPlayer(player_t *player); +boolean P_PlayerCanDamage(player_t *player, mobj_t *thing); boolean P_IsLocalPlayer(player_t *player); boolean P_IsObjectInGoop(mobj_t *mo); diff --git a/src/p_map.c b/src/p_map.c index ffe6cf916..3db3db4e3 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1405,51 +1405,41 @@ static boolean PIT_CheckThing(mobj_t *thing) } // Monitor? else if (thing->flags & MF_MONITOR - && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))) + && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2)) + && (!(thing->flags & MF_SOLID) || P_PlayerCanDamage(tmthing->player, thing))) { - // 0 = none, 1 = elemental pierce, 2 = bubble bounce - UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY) - ? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2) - : 0); - if (!(thing->flags & MF_SOLID) - || tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) - || ((tmthing->player->pflags & PF_JUMPED) - && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) - || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) - || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) - || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) - && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) - || elementalpierce) + if (thing->z - thing->scale <= tmthing->z + tmthing->height + && thing->z + thing->height + thing->scale >= tmthing->z) { - if (thing->z - thing->scale <= tmthing->z + tmthing->height - && thing->z + thing->height + thing->scale >= tmthing->z) + player_t *player = tmthing->player; + // 0 = none, 1 = elemental pierce, 2 = bubble bounce + UINT8 elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY) + ? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2) + : 0); + SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. + fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;; + fixed_t *z = &tmthing->z; // aau. + // Going down? Then bounce back up. + if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor + && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up + && (elementalpierce != 1)) // you're not piercing through the monitor... { - player_t *player = tmthing->player; - SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. - fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;; - fixed_t *z = &tmthing->z; // aau. - // Going down? Then bounce back up. - if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor - && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up - && (elementalpierce != 1)) // you're not piercing through the monitor... - { - if (elementalpierce == 2) - P_DoBubbleBounce(player); - else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) - *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. - } - if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. - { - if (player->pflags & PF_BOUNCING) - P_DoAbilityBounce(player, false); - return false; - } - else - *z -= *momz; // to ensure proper collision. + if (elementalpierce == 2) + P_DoBubbleBounce(player); + else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. } - - return true; + if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. + { + if (player->pflags & PF_BOUNCING) + P_DoAbilityBounce(player, false); + return false; + } + else + *z -= *momz; // to ensure proper collision. } + + return true; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index fd679857e..70a40592d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3396,11 +3396,7 @@ void P_MobjCheckWater(mobj_t *mobj) if (!((p->powers[pw_super]) || (p->powers[pw_invulnerability]))) { boolean electric = !!(p->powers[pw_shield] & SH_PROTECTELECTRIC); -#define SH_OP (SH_PROTECTFIRE|SH_PROTECTWATER|SH_PROTECTELECTRIC) - if ((p->powers[pw_shield] & SH_OP) == SH_OP) // No. - P_KillMobj(mobj, NULL, NULL, DMG_INSTAKILL); -#undef SH_OP - else if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER))) + if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER))) { // Water removes electric and non-water fire shields... P_FlashPal(p, electric @@ -7109,6 +7105,9 @@ void P_MobjThinker(mobj_t *mobj) P_RemoveMobj(mobj); return; } + + mobj->flags2 &= ~MF2_DONTDRAW; + mobj->x = mobj->target->x; mobj->y = mobj->target->y; diff --git a/src/p_user.c b/src/p_user.c index ca14c64d4..b1b755204 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -977,6 +977,42 @@ void P_ResetPlayer(player_t *player) CV_SetValue(&cv_analog2, true); } +// P_PlayerCanDamage +// +// Can player do damage? +// Doesn't count invincibility or super, for the sake of monitors. +// +boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) +{ + if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing)) + return false; + + if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) + return true; + + if ((player->pflags & PF_JUMPED) + && (!(player->pflags & PF_NOJUMPDAMAGE) + || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) + return true; + + if (player->pflags & (PF_SPINNING|PF_GLIDING)) + return true; + + if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + return true; + + if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) + && (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) + return true; + + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)) + return true; + + return false; +} + + + // // P_GivePlayerRings // From 28dfeb344b5955345e8319286065d8e134cc1d80 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 12:28:57 +0100 Subject: [PATCH 06/34] Instead of only performing a hook if the Lua Hook loop determines its type to be the one we want, actively continue through the loop if it's NOT. This optimisation was performed while preparing the following commit; I have generously split them out for less shitty commit-by-commit review. --- src/lua_hooklib.c | 1135 ++++++++++++++++++++++++--------------------- 1 file changed, 594 insertions(+), 541 deletions(-) diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index d605499e2..de8d29be4 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -250,44 +250,48 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) // Look for all generic mobj hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == which) - { - if (lua_gettop(gL) == 0) - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + LUA_PushUserdata(gL, mo, META_MOBJ); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - if (hookp->type == which) - { - if (lua_gettop(gL) == 0) - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + LUA_PushUserdata(gL, mo, META_MOBJ); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -303,24 +307,26 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) lua_settop(gL, 0); for (hookp = playerhooks; hookp; hookp = hookp->next) - if (hookp->type == which) - { - if (lua_gettop(gL) == 0) - LUA_PushUserdata(gL, plr, META_PLAYER); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + LUA_PushUserdata(gL, plr, META_PLAYER); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -337,13 +343,15 @@ void LUAh_MapChange(INT16 mapnumber) lua_pushinteger(gL, mapnumber); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MapChange) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_MapChange) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } lua_settop(gL, 0); } @@ -359,13 +367,15 @@ void LUAh_MapLoad(void) lua_pushinteger(gL, gamemap); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MapLoad) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_MapLoad) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } lua_settop(gL, 0); } @@ -381,13 +391,15 @@ void LUAh_PlayerJoin(int playernum) lua_pushinteger(gL, playernum); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerJoin) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_PlayerJoin) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } lua_settop(gL, 0); } @@ -400,17 +412,19 @@ void LUAh_ThinkFrame(void) return; for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_ThinkFrame) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + { + if (hookp->type != hook_ThinkFrame) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; } + } } // Hook for mobj collisions @@ -427,62 +441,66 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) // Look for all generic mobj collision hooks for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == which) + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, thing1, META_MOBJ); + LUA_PushUserdata(gL, thing2, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next) - if (hookp->type == which) + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, thing1, META_MOBJ); + LUA_PushUserdata(gL, thing2, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldCollide; @@ -557,52 +575,56 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) // Look for all generic touch special hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_TouchSpecial) + { + if (hookp->type != hook_TouchSpecial) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_TouchSpecial) + { + if (hookp->type != hook_TouchSpecial) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -622,72 +644,75 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 // Look for all generic should damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldDamage) + { + if (hookp->type != hook_ShouldDamage) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldDamage) + { + if (hookp->type != hook_ShouldDamage) + continue; + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldDamage; @@ -707,62 +732,66 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 // Look for all generic mobj damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDamage) + { + if (hookp->type != hook_MobjDamage) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDamage) + { + if (hookp->type != hook_MobjDamage) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -782,58 +811,62 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 // Look for all generic mobj death hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDeath) + { + if (hookp->type != hook_MobjDeath) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDeath) + { + if (hookp->type != hook_MobjDeath) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -850,28 +883,30 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_BotTiccmd) + { + if (hookp->type != hook_BotTiccmd) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, bot, META_PLAYER); - LUA_PushUserdata(gL, cmd, META_TICCMD); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, bot, META_PLAYER); + LUA_PushUserdata(gL, cmd, META_TICCMD); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -888,51 +923,53 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_BotAI - && (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + { + if (hookp->type != hook_BotAI + || (hookp->s.skinname && strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, sonic, META_MOBJ); - LUA_PushUserdata(gL, tails, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 8, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - - // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. - if (lua_istable(gL, 2+1)) { - boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; -#define CHECKFIELD(field) \ - lua_getfield(gL, 2+1, #field);\ - if (lua_toboolean(gL, -1))\ - field = true;\ - lua_pop(gL, 1); - - CHECKFIELD(forward) - CHECKFIELD(backward) - CHECKFIELD(left) - CHECKFIELD(right) - CHECKFIELD(strafeleft) - CHECKFIELD(straferight) - CHECKFIELD(jump) - CHECKFIELD(spin) -#undef CHECKFIELD - B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); - } else - B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); - - lua_pop(gL, 8); - hooked = true; + LUA_PushUserdata(gL, sonic, META_MOBJ); + LUA_PushUserdata(gL, tails, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 8, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + + // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. + if (lua_istable(gL, 2+1)) { + boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; +#define CHECKFIELD(field) \ + lua_getfield(gL, 2+1, #field);\ + if (lua_toboolean(gL, -1))\ + field = true;\ + lua_pop(gL, 1); + + CHECKFIELD(forward) + CHECKFIELD(backward) + CHECKFIELD(left) + CHECKFIELD(right) + CHECKFIELD(strafeleft) + CHECKFIELD(straferight) + CHECKFIELD(jump) + CHECKFIELD(spin) +#undef CHECKFIELD + B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); + } else + B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); + + lua_pop(gL, 8); + hooked = true; + } lua_settop(gL, 0); return hooked; @@ -949,22 +986,24 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) lua_settop(gL, 0); for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next) - if (!strcmp(hookp->s.funcname, line->text)) + { + if (strcmp(hookp->s.funcname, line->text)) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, line, META_LINE); - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, sector, META_SECTOR); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - LUA_Call(gL, 3); - hooked = true; + LUA_PushUserdata(gL, line, META_LINE); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, sector, META_SECTOR); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + LUA_Call(gL, 3); + hooked = true; + } lua_settop(gL, 0); return hooked; @@ -981,43 +1020,45 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerMsg) + { + if (hookp->type != hook_PlayerMsg) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player - if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c - lua_pushinteger(gL, 3); // type - lua_pushnil(gL); // target - } else if (target == -1) { // sayteam - lua_pushinteger(gL, 1); // type - lua_pushnil(gL); // target - } else if (target == 0) { // say - lua_pushinteger(gL, 0); // type - lua_pushnil(gL); // target - } else { // sayto - lua_pushinteger(gL, 2); // type - LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target - } - lua_pushstring(gL, msg); // msg + LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player + if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c + lua_pushinteger(gL, 3); // type + lua_pushnil(gL); // target + } else if (target == -1) { // sayteam + lua_pushinteger(gL, 1); // type + lua_pushnil(gL); // target + } else if (target == 0) { // say + lua_pushinteger(gL, 0); // type + lua_pushnil(gL); // target + } else { // sayto + lua_pushinteger(gL, 2); // type + LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + lua_pushstring(gL, msg); // msg } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1035,33 +1076,35 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_HurtMsg - && (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type))) + { + if (hookp->type != hook_HurtMsg + || (hookp->s.mt && !(inflictor && hookp->s.mt == inflictor->type))) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1084,13 +1127,15 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc) // stack: tables, archFunc for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_NetVars) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); // archFunc - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_NetVars) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); // archFunc + LUA_Call(gL, 1); + } lua_pop(gL, 1); // pop archFunc // stack: tables @@ -1107,52 +1152,56 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing) // Look for all generic mobj map thing spawn hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MapThingSpawn) + { + if (hookp->type != hook_MapThingSpawn) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, mthing, META_MAPTHING); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, mthing, META_MAPTHING); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MapThingSpawn) + { + if (hookp->type != hook_MapThingSpawn) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, mthing, META_MAPTHING); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, mthing, META_MAPTHING); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1169,28 +1218,30 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj) lua_settop(gL, 0); for (hookp = playerhooks; hookp; hookp = hookp->next) - if (hookp->type == hook_FollowMobj) + { + if (hookp->type != hook_FollowMobj) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, mobj, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1205,19 +1256,21 @@ void LUAh_PlayerQuit(player_t *plr, int reason) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerQuit) - { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit - lua_pushinteger(gL, reason); // Reason for quitting - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - LUA_Call(gL, 2); - } + { + if (hookp->type != hook_PlayerQuit) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit + lua_pushinteger(gL, reason); // Reason for quitting + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + LUA_Call(gL, 2); + } lua_settop(gL, 0); } From 3eb9b85fd4d3bbf43d5f1cf9f53e47367fcece11 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 12:55:05 +0100 Subject: [PATCH 07/34] "PlayerCanDamage" hook! * Takes function(player, mo) input. * Return TRUE for stating that yes, the player is in a state that can cause contact damage, do with that what you will. * Return FALSE for stating that no, the player is weak and vulnerable and cannot cause contact damage, do with that what you will. * Return NIL for allowing the function to continue regular operation. Fills a different ideological niche than ShouldDamage - that's for determining whether damage dished between two objects should happen, this is for determining which way around damage should be dished when considering a player-object interaction. Or, in other words, think of it as "ShouldDamage is whether damage that has been requested should be granted, for object-object interaction, while PlayerCanDamage is for whether global player properties should cause damage to enemies and monitors in the first place, like spinning, hammering or stomping." --- src/lua_baselib.c | 2 +- src/lua_hook.h | 4 +++- src/lua_hooklib.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/p_user.c | 12 ++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 192e2b6cb..e6119cd6c 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -956,7 +956,7 @@ static int lib_pPlayerCanDamage(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - //HUDSAFE + NOHUD // was hud safe but then i added a lua hook INLEVEL if (!player) return LUA_ErrInvalid(L, "player_t"); diff --git a/src/lua_hook.h b/src/lua_hook.h index 9fcc36594..45e116c34 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -48,6 +48,7 @@ enum hook { hook_MobjMoveBlocked, hook_MapThingSpawn, hook_FollowMobj, + hook_PlayerCanDamage, hook_PlayerQuit, hook_MAX // last hook @@ -87,7 +88,8 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 #define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities #define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked) boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type -boolean LUAh_FollowMobj(player_t *player, mobj_t *mo); // Hook for P_PlayerAfterThink Smiles mobj-following +boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following +UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index de8d29be4..7f7e8adc6 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -59,6 +59,7 @@ const char *const hookNames[hook_MAX+1] = { "MobjMoveBlocked", "MapThingSpawn", "FollowMobj", + "PlayerCanDamage", "PlayerQuit", NULL }; @@ -200,6 +201,7 @@ static int lib_addHook(lua_State *L) case hook_JumpSpinSpecial: case hook_PlayerSpawn: case hook_FollowMobj: + case hook_PlayerCanDamage: case hook_ShieldSpawn: case hook_ShieldSpecial: lastp = &playerhooks; @@ -1247,6 +1249,51 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj) return hooked; } +// Hook for P_PlayerCanDamage +UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj) +{ + hook_p hookp; + UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_PlayerCanDamage/8] & (1<<(hook_PlayerCanDamage%8)))) + return 0; + + lua_settop(gL, 0); + + for (hookp = playerhooks; hookp; hookp = hookp->next) + { + if (hookp->type != hook_PlayerCanDamage) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldCollide; +} + void LUAh_PlayerQuit(player_t *plr, int reason) { hook_p hookp; diff --git a/src/p_user.c b/src/p_user.c index b1b755204..9a5d315a3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -987,6 +987,18 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing)) return false; +#ifdef HAVE_BLUA + { + UINT8 shouldCollide = LUAh_PlayerCanDamage(player, thing); + if (P_MobjWasRemoved(thing)) + return false; // removed??? + if (shouldCollide == 1) + return true; // force yes + else if (shouldCollide == 2) + return false; // force no + } +#endif + if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) return true; From 6a58ae34d1498d86e0b3b7155505a3f67c2010f3 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 13:20:34 +0100 Subject: [PATCH 08/34] In order to make P_PlayerCanDamage more flexible, I ended up bundling the invincibility/super checks into there. Also, the start of my improvements to CA2_MELEE. Users of that abiliy can only damage enemies/monitors if they touch the front of the player object, but to make up for it, the player is no longer forced away from the direction of the screen at bigger movement speeds. --- src/p_inter.c | 3 +-- src/p_user.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 42722e6d1..4cbd9185c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -453,8 +453,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) break; } - if (player->powers[pw_invulnerability] || player->powers[pw_super] - || P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object? + if (P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object? { if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) { diff --git a/src/p_user.c b/src/p_user.c index 9a5d315a3..b879df48a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -980,7 +980,6 @@ void P_ResetPlayer(player_t *player) // P_PlayerCanDamage // // Can player do damage? -// Doesn't count invincibility or super, for the sake of monitors. // boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) { @@ -999,24 +998,35 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) } #endif + // Invinc/super. Not for Monitors. + if (!(thing->flags & MF_MONITOR) && (player->powers[pw_invulnerability] || player->powers[pw_super])) + return true; + + // NiGHTS drill. Wasn't originally for monitors, but that's more an oversight being corrected than anything else. if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) return true; + // Jumping. if ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) return true; - if (player->pflags & (PF_SPINNING|PF_GLIDING)) + // Spinning. + if (player->pflags & PF_SPINNING) return true; - if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + // From the front. + if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + && (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) < ANGLE_180) return true; + // From the top. if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) return true; + // Shield stomp. if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)) return true; @@ -4336,7 +4346,11 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) P_SetObjectMomZ(player->mo, player->mindash, false); if (player->mo->eflags & MFE_UNDERWATER) player->mo->momz >>= 1; +#if 0 if (FixedMul(player->speed, FINECOSINE(((player->mo->angle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT) & FINEMASK)) < FixedMul(player->maxdash, player->mo->scale)) +#else + if (player->speed < FixedMul(player->maxdash, player->mo->scale)) +#endif { player->drawangle = player->mo->angle; P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale)); From 2e6898f29ed312b940ac1bbcce1fc6162c0ccf15 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 23:20:24 +0100 Subject: [PATCH 09/34] PITY IN PINK! * Smoothen Pity Shield animation to go with sphere's updates to Nev3r's sprites. * Added LHRT object, designed to be summoned with CA2_MELEE. * Gives a pink Pity Shield (SH_PINK) on same-team player contact. * Deals damage to non-player enemies. * Harmlessly fades into nothing when touching an enemy player, players with SH_PINK already, and players capable of applying SH_PINK to others (through non-Lua methods). * Basically, you-know-who is the Healer of the party whenever they're around. Fun consequences for the Co-op and CTF metas. --- src/d_player.h | 1 + src/dehacked.c | 9 +++++++ src/hardware/hw_light.c | 1 + src/info.c | 49 ++++++++++++++++++++++++++++++------ src/info.h | 9 +++++++ src/p_inter.c | 56 +++++++++++++++++++++++++++++++++++------ src/p_map.c | 2 +- src/p_mobj.c | 7 ++++++ src/p_user.c | 51 ++++++++++++++++++++++++++++++++++--- src/r_things.c | 3 +++ 10 files changed, 170 insertions(+), 18 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e68992e15..15cb14e80 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -196,6 +196,7 @@ typedef enum SH_PITY = 1, // the world's most basic shield ever, given to players who suck at Match SH_WHIRLWIND, SH_ARMAGEDDON, + SH_PINK, // PITY IN PINK! // Normal shields that use flags SH_ATTRACT = SH_PITY|SH_PROTECTELECTRIC, diff --git a/src/dehacked.c b/src/dehacked.c index b8417ea59..0fbdfbc31 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6027,6 +6027,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PITY4", "S_PITY5", "S_PITY6", + "S_PITY7", + "S_PITY8", + "S_PITY9", + "S_PITY10", + "S_PITY11", + "S_PITY12", "S_FIRS1", "S_FIRS2", @@ -6519,6 +6525,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_GOTFLAG", "S_CORK", + "S_LHRT", // Red Ring "S_RRNG1", @@ -7579,6 +7586,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_MACHINEAMBIENCE", "MT_CORK", + "MT_LHRT", // Ring Weapons "MT_REDRING", @@ -8342,6 +8350,7 @@ struct { {"SH_PITY",SH_PITY}, {"SH_WHIRLWIND",SH_WHIRLWIND}, {"SH_ARMAGEDDON",SH_ARMAGEDDON}, + {"SH_PINK",SH_PINK}, // normal shields that use flags {"SH_ATTRACT",SH_ATTRACT}, {"SH_ELEMENTAL",SH_ELEMENTAL}, diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 90d02fdf8..7efbc11d7 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -469,6 +469,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_GFLG &lspr[NOLIGHT], // SPR_CORK + &lspr[NOLIGHT], // SPR_LHRT // Ring Weapons &lspr[RINGLIGHT_L], // SPR_RRNG diff --git a/src/info.c b/src/info.c index f1d570fa0..4dbe2c31f 100644 --- a/src/info.c +++ b/src/info.c @@ -364,6 +364,7 @@ char sprnames[NUMSPRITES + 1][5] = "GFLG", // Got Flag sign "CORK", + "LHRT", // Ring Weapons "RRNG", // Red Ring @@ -2664,12 +2665,18 @@ state_t states[NUMSTATES] = {SPR_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10}, // S_ELEMF9 {SPR_NULL, 0, 1, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF10 - {SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1 - {SPR_PITY, FF_TRANS30|1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2 - {SPR_PITY, FF_TRANS30|2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3 - {SPR_PITY, FF_TRANS20|3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4 - {SPR_PITY, FF_TRANS30|4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5 - {SPR_PITY, FF_TRANS20|5, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY6 + {SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1 + {SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2 + {SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3 + {SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4 + {SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5 + {SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7}, // S_PITY6 + {SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8}, // S_PITY7 + {SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9}, // S_PITY8 + {SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10}, // S_PITY9 + {SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11}, // S_PITY10 + {SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12}, // S_PITY11 + {SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY12 {SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40 , 2, {NULL}, 0, 0, S_FIRS2}, // S_FIRS1 {SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3}, // S_FIRS2 @@ -3165,7 +3172,8 @@ state_t states[NUMSTATES] = // CTF Sign {SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG - {SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK + {SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK + {SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LHRT // Red Rings (thrown) {SPR_RRNG, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_RRNG2}, // S_RRNG1 @@ -16099,6 +16107,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_LHRT + -1, // doomednum + S_LHRT, // spawnstate + 1000, // 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_SPRK1, // deathstate + S_SPRK1, // xdeathstate + sfx_None, // deathsound + 60*FRACUNIT, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 0, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE, // flags + S_NULL // raisestate + }, + { // MT_REDRING -1, // doomednum S_RRNG1, // spawnstate diff --git a/src/info.h b/src/info.h index 5482af60b..84b1a7ce1 100644 --- a/src/info.h +++ b/src/info.h @@ -595,6 +595,7 @@ typedef enum sprite SPR_GFLG, // Got Flag sign SPR_CORK, + SPR_LHRT, // Ring Weapons SPR_RRNG, // Red Ring @@ -2771,6 +2772,12 @@ typedef enum state S_PITY4, S_PITY5, S_PITY6, + S_PITY7, + S_PITY8, + S_PITY9, + S_PITY10, + S_PITY11, + S_PITY12, S_FIRS1, S_FIRS2, @@ -3263,6 +3270,7 @@ typedef enum state S_GOTFLAG, S_CORK, + S_LHRT, // Red Ring S_RRNG1, @@ -4343,6 +4351,7 @@ typedef enum mobj_type MT_MACHINEAMBIENCE, MT_CORK, + MT_LHRT, // Ring Weapons MT_REDRING, diff --git a/src/p_inter.c b/src/p_inter.c index 4cbd9185c..5a841807a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2813,26 +2813,47 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou if (player->powers[pw_flashing] || player->powers[pw_invulnerability]) return false; - // Ignore IT players shooting each other, unless friendlyfire is on. - if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && - source && source->player && source->player->pflags & PF_TAGIT))) - return false; - // Don't allow any damage before the round starts. if (leveltime <= hidetime * TICRATE) return false; + // Ignore IT players shooting each other, unless friendlyfire is on. + if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && + source && source->player && source->player->pflags & PF_TAGIT))) + { + if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) + { + if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + { + P_SwitchShield(player, SH_PINK); + S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); + } + } + return false; + } + // Don't allow players on the same team to hurt one another, // unless cv_friendlyfire is on. if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT)) { - if (!(inflictor->flags & MF_FIRE)) + if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) + { + if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + { + P_SwitchShield(player, SH_PINK); + S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); + } + } + else if (!(inflictor->flags & MF_FIRE)) P_GivePlayerRings(player, 1); if (inflictor->flags2 & MF2_BOUNCERING) inflictor->fuse = 0; // bounce ring disappears at -1 not 0 return false; } + if (inflictor->type == MT_LHRT) + return false; + // The tag occurs so long as you aren't shooting another tagger with friendlyfire on. if (source->player->pflags & PF_TAGIT && !(player->pflags & PF_TAGIT)) { @@ -2899,7 +2920,17 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj // In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on if (!cv_friendlyfire.value && (G_PlatformGametype())) + { + if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) + { + if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + { + P_SwitchShield(player, SH_PINK); + S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); + } + } return false; + } } // Tag handling @@ -2913,7 +2944,15 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj // unless cv_friendlyfire is on. if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam) { - if (!(inflictor->flags & MF_FIRE)) + if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) + { + if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + { + P_SwitchShield(player, SH_PINK); + S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); + } + } + else if (!(inflictor->flags & MF_FIRE)) P_GivePlayerRings(target->player, 1); if (inflictor->flags2 & MF2_BOUNCERING) inflictor->fuse = 0; // bounce ring disappears at -1 not 0 @@ -2922,6 +2961,9 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj } } + if (inflictor->type == MT_LHRT) + return false; + // Add pity. if (!player->powers[pw_flashing] && !player->powers[pw_invulnerability] && !player->powers[pw_super] && source->player->score > player->score) diff --git a/src/p_map.c b/src/p_map.c index 3db3db4e3..97f7712f3 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1076,7 +1076,7 @@ static boolean PIT_CheckThing(mobj_t *thing) tmthing->y = thing->y; P_SetThingPosition(tmthing); } - else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial + else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial for shell { UINT8 damagetype = tmthing->info->mass; if (!damagetype && tmthing->flags & MF_FIRE) // BURN! diff --git a/src/p_mobj.c b/src/p_mobj.c index 70a40592d..f29da4ec5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7861,6 +7861,10 @@ void P_MobjThinker(mobj_t *mobj) } } break; + case MT_LHRT: + mobj->momx = FixedMul(mobj->momx, (48*FRACUNIT)/50); + mobj->momy = FixedMul(mobj->momy, (48*FRACUNIT)/50); + break; case MT_EGGCAPSULE: if (!mobj->reactiontime) { @@ -8547,6 +8551,9 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: P_SetMobjState(mobj, mobj->info->deathstate); break; + case MT_LHRT: + P_KillMobj(mobj, NULL, NULL, 0); + break; case MT_BLUEFLAG: case MT_REDFLAG: if (mobj->spawnpoint) diff --git a/src/p_user.c b/src/p_user.c index b879df48a..534f281ff 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1609,6 +1609,7 @@ void P_SpawnShieldOrb(player_t *player) orbtype = MT_ARMAGEDDON_ORB; break; case SH_PITY: + case SH_PINK: // PITY IN PINK orbtype = MT_PITY_ORB; break; case SH_FLAMEAURA: @@ -1639,7 +1640,13 @@ void P_SpawnShieldOrb(player_t *player) shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype); shieldobj->flags2 |= MF2_SHIELD; P_SetTarget(&shieldobj->target, player->mo); - shieldobj->color = (UINT8)shieldobj->info->painchance; + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) + { + shieldobj->color = SKINCOLOR_PINK; + shieldobj->colorized = true; + } + else + shieldobj->color = (UINT8)shieldobj->info->painchance; shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK); if (shieldobj->info->seestate) @@ -1787,6 +1794,9 @@ void P_SpawnThokMobj(player_t *player) if (player->spectator) return; + if (!type) + return; + if (type == MT_GHOST) mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us else @@ -1847,6 +1857,9 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type) if (player->spectator) return; + if (!type) + return; + if (type == MT_GHOST) mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us else @@ -2002,10 +2015,42 @@ boolean P_PlayerHitFloor(player_t *player) } else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING)) { + mobjtype_t type = player->spinitem; P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; S_StartSound(player->mo, sfx_s3k8b); player->pflags |= PF_FULLSTASIS; + + // hearticles + if (type) + { + UINT8 i = 0; + angle_t throwang = -(2*ANG30); + fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t zo = 6*player->mo->scale; + fixed_t mu = FixedMul(player->maxdash, player->mo->scale); + fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + mobj_t *missile; + if (mu2 < mu) + mu2 = mu; + while (i < 5) + { + missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); + P_SetTarget(&missile->target, player->mo); + missile->angle = throwang + player->drawangle; + P_Thrust(missile, player->drawangle + ANGLE_90, + P_ReturnThrustY(missile, throwang, mu)); // side to side component + P_Thrust(missile, player->drawangle, mu2); // forward component + P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->fuse = TICRATE/2; + + i++; + throwang += ANG30; + } + if (mobjinfo[type].seesound) + S_StartSound(missile, missile->info->seesound); + } } else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING) || player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED) @@ -9806,12 +9851,12 @@ void P_DoPityCheck(player_t *player) // Apply pity shield if available. if ((player->pity >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE) { + P_SwitchShield(player, SH_PITY); + if (player->pity > 0) S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound); player->pity = 0; - player->powers[pw_shield] = SH_PITY; - P_SpawnShieldOrb(player); } } diff --git a/src/r_things.c b/src/r_things.c index 115e49600..9b5cbc09a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2704,6 +2704,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; player->followitem = skin->followitem; + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->spinitem == MT_LHRT)) // Healers can't keep their buff. + player->powers[pw_shield] &= SH_STACK; + player->actionspd = skin->actionspd; player->mindash = skin->mindash; player->maxdash = skin->maxdash; From 84ff2a57a177c16718ef2314a98aee5cea429f40 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 23:29:39 +0100 Subject: [PATCH 10/34] As I wanted MI to do but he was too exhausted at the time from hardcoding, make the Fang bullet knockback less hardcoded and instead give it MF2_SUPERFIRE. --- src/p_inter.c | 8 ++------ src/p_mobj.c | 3 +++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 5a841807a..abe3a9061 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3423,14 +3423,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } } - else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] // ignore bouncing & such in invulnerability - || player->powers[pw_super]) + else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) // ignore bouncing & such in invulnerability { if (force - || (player->powers[pw_super] - && inflictor && inflictor->flags & MF_MISSILE && inflictor->flags2 & MF2_SUPERFIRE) // Super Sonic is stunned! - || (player->powers[pw_flashing] - && source && source->type == MT_FANG && inflictor && inflictor->type == MT_CORK)) // Fang's cork bullets knock you back even when flashing + || (inflictor && inflictor->flags & MF_MISSILE && inflictor->flags2 & MF2_SUPERFIRE)) // Super Sonic is stunned! { #ifdef HAVE_BLUA if (!LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) diff --git a/src/p_mobj.c b/src/p_mobj.c index f29da4ec5..c4211be85 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9164,6 +9164,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_FANG: sc = 4; break; + case MT_CORK: + mobj->flags2 |= MF2_SUPERFIRE; + break; case MT_FBOMB: mobj->flags2 |= MF2_EXPLOSION; break; From f9e09ec31fe70efa7dab0e1ecb0205dd87bc4256 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 19 Jun 2019 23:35:18 +0100 Subject: [PATCH 11/34] Tweak Boss5MakeItRain's bomb launch angles to properly smash the ceiling in the new arena. --- src/p_enemy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 664e3b9b0..46669ad94 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -12414,7 +12414,7 @@ void A_Boss5MakeItRain(mobj_t *actor) actor->angle += ANGLE_45; var1 = locvar1; - var2 = offset + (i & 1) ? 55 : 70; + var2 = offset + (i & 1) ? 80 : 85; A_TrapShot(actor); } From 460632ad3b315e0e28edaf4c16b6d315d3c010b2 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 20 Jun 2019 00:24:13 +0100 Subject: [PATCH 12/34] Some preliminary work to make multiple bosses in the same map work nicely together, by allowing parameter to alter the linedef executor tag to call in increments of 100. Also: Making sure every single reserved tag is recorded as an LE_ constant. --- src/dehacked.c | 8 ++++++++ src/doomdef.h | 18 +++++++++++++----- src/info.c | 4 ++-- src/p_enemy.c | 40 +++++++++++++++++++++++++--------------- src/p_inter.c | 13 +++++++------ 5 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 0fbdfbc31..a3752ece5 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8228,6 +8228,14 @@ struct { {"LE_BOSSDEAD",LE_BOSSDEAD}, // A boss in the map died (Chaos mode boss tally) {"LE_BOSS4DROP",LE_BOSS4DROP}, // CEZ boss dropped its cage {"LE_BRAKVILEATACK",LE_BRAKVILEATACK}, // Brak's doing his LOS attack, oh noes + {"LE_TURRET",LE_TURRET}, // THZ turret + {"LE_BRAKPLATFORM",LE_BRAKPLATFORM}, // v2.0 Black Eggman destroys platform + {"LE_CAPSULE2",LE_CAPSULE2}, // Egg Capsule + {"LE_CAPSULE1",LE_CAPSULE1}, // Egg Capsule + {"LE_CAPSULE0",LE_CAPSULE0}, // Egg Capsule + {"LE_KOOPA",LE_KOOPA}, // Distant cousin to Gay Bowser + {"LE_AXE",LE_AXE}, // MKB Axe object + {"LE_PARAMWIDTH",LE_PARAMWIDTH}, // If an object that calls LinedefExecute has a nonzero parameter value, this times the parameter will be subtracted. (Mostly for the purpose of coexisting bosses...) /// \todo Get all this stuff into its own sections, maybe. Maybe. diff --git a/src/doomdef.h b/src/doomdef.h index 512c90f86..475328918 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -381,11 +381,19 @@ typedef enum // Special linedef executor tag numbers! enum { - LE_PINCHPHASE = -2, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) - LE_ALLBOSSESDEAD = -3, // All bosses in the map are dead (Egg capsule raise) - LE_BOSSDEAD = -4, // A boss in the map died (Chaos mode boss tally) - LE_BOSS4DROP = -5, // CEZ boss dropped its cage - LE_BRAKVILEATACK = -6 // Brak's doing his LOS attack, oh noes + LE_PINCHPHASE = -2, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) + LE_ALLBOSSESDEAD = -3, // All bosses in the map are dead (Egg capsule raise) + LE_BOSSDEAD = -4, // A boss in the map died (Chaos mode boss tally) + LE_BOSS4DROP = -5, // CEZ boss dropped its cage + LE_BRAKVILEATACK = -6, // Brak's doing his LOS attack, oh noes + LE_TURRET = 32000, // THZ turret + LE_BRAKPLATFORM = 4200, // v2.0 Black Eggman destroys platform + LE_CAPSULE2 = 682, // Egg Capsule + LE_CAPSULE1 = 681, // Egg Capsule + LE_CAPSULE0 = 680, // Egg Capsule + LE_KOOPA = 650, // Distant cousin to Gay Bowser + LE_AXE = 649, // MKB Axe object + LE_PARAMWIDTH = -100 // If an object that calls LinedefExecute has a nonzero parameter value, this times the parameter will be subtracted. (Mostly for the purpose of coexisting bosses...) }; // Name of local directory for config files and savegames diff --git a/src/info.c b/src/info.c index 4dbe2c31f..5a8633233 100644 --- a/src/info.c +++ b/src/info.c @@ -898,7 +898,7 @@ state_t states[NUMSTATES] = {SPR_TRET, FF_FULLBRIGHT|2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7}, // S_TURRETSHOCK6 {SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK8}, // S_TURRETSHOCK7 {SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK9}, // S_TURRETSHOCK8 - {SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecute}, 32000, 0, S_XPLD1}, // S_TURRETSHOCK9 + {SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecute}, LE_TURRET, 0, S_XPLD1}, // S_TURRETSHOCK9 {SPR_TURR, 0, 1, {A_Look}, 1, 0, S_TURRETPOPDOWN8}, // S_TURRETLOOK {SPR_TURR, 0, 0, {A_FaceTarget}, 0, 0, S_TURRETPOPUP1}, // S_TURRETSEE @@ -1501,7 +1501,7 @@ state_t states[NUMSTATES] = {SPR_BRAK, 21, 3*TICRATE, {NULL}, 0, 0, S_BLACKEGG_DESTROYPLAT2}, // S_BLACKEGG_DESTROYPLAT1 {SPR_BRAK, 21, 1, {A_PlaySound}, sfx_s3k54, 0, S_BLACKEGG_DESTROYPLAT3}, // S_BLACKEGG_DESTROYPLAT2 - {SPR_BRAK, 21, 14, {A_LinedefExecute}, 4200, 0, S_BLACKEGG_STND}, // S_BLACKEGG_DESTROYPLAT3 + {SPR_BRAK, 21, 14, {A_LinedefExecute}, LE_BRAKPLATFORM, 0, S_BLACKEGG_STND}, // S_BLACKEGG_DESTROYPLAT3 {SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER}, // S_BLACKEGG_HELPER diff --git a/src/p_enemy.c b/src/p_enemy.c index 46669ad94..5de14e0a7 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3510,7 +3510,10 @@ void A_BossDeath(mobj_t *mo) return; #endif - P_LinedefExecute(LE_BOSSDEAD, mo, NULL); + if (mo->spawnpoint && mo->spawnpoint->extrainfo) + P_LinedefExecute(LE_BOSSDEAD+(mo->spawnpoint->extrainfo*LE_PARAMWIDTH), mo, NULL); + else + P_LinedefExecute(LE_BOSSDEAD, mo, NULL); mo->health = 0; // Boss is dead (but not necessarily fleeing...) @@ -3548,11 +3551,11 @@ void A_BossDeath(mobj_t *mo) else { // Bring the egg trap up to the surface - junk.tag = 680; + junk.tag = LE_CAPSULE0; EV_DoElevator(&junk, elevateHighest, false); - junk.tag = 681; + junk.tag = LE_CAPSULE1; EV_DoElevator(&junk, elevateUp, false); - junk.tag = 682; + junk.tag = LE_CAPSULE2; EV_DoElevator(&junk, elevateHighest, false); } @@ -3576,7 +3579,7 @@ bossjustdie: } case MT_KOOPA: { - junk.tag = 650; + junk.tag = LE_KOOPA; EV_DoCeiling(&junk, raiseToHighest); return; } @@ -3636,15 +3639,17 @@ bossjustdie: mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSSFLYPOINT) - { - // If this one's closer then the last one, go for it. - if (!mo->target || - P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) < - P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z)) - P_SetTarget(&mo->target, mo2); - // Otherwise... Don't! - } + if (mo2->type != MT_BOSSFLYPOINT) + continue; + + // If this one's further then the last one, don't go for it. + if (mo->target && + P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) > + P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z)) + continue; + + // Otherwise... Do! + P_SetTarget(&mo->target, mo2); } mo->flags |= MF_NOGRAVITY|MF_NOCLIP; @@ -6390,7 +6395,10 @@ void A_Boss1Chase(mobj_t *actor) } else { - P_LinedefExecute(LE_PINCHPHASE, actor, NULL); + if (actor->spawnpoint && actor->spawnpoint->extrainfo) + P_LinedefExecute(LE_PINCHPHASE+(actor->spawnpoint->extrainfo*LE_PARAMWIDTH), actor, NULL); + else + P_LinedefExecute(LE_PINCHPHASE, actor, NULL); P_SetMobjState(actor, actor->info->raisestate); } @@ -7595,6 +7603,8 @@ void A_LinedefExecute(mobj_t *actor) if (locvar2) tagnum += locvar2*(AngleFixed(actor->angle)>>FRACBITS); + else if (actor->spawnpoint && actor->spawnpoint->extrainfo) + tagnum += (actor->spawnpoint->extrainfo*LE_PARAMWIDTH); CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecute: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum); diff --git a/src/p_inter.c b/src/p_inter.c index abe3a9061..a8e716123 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1353,7 +1353,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->bot) return; - junk.tag = 649; + junk.tag = LE_AXE; EV_DoElevator(&junk, bridgeFall, false); // scan the remaining thinkers to find koopa @@ -1363,11 +1363,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_KOOPA) - { - mo2->momz = 5*FRACUNIT; - break; - } + + if (mo2->type != MT_KOOPA) + continue; + + mo2->momz = 5*FRACUNIT; + break; } } break; From eac36e73a3a2199b7dcf917dc95396628013f1d0 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 20 Jun 2019 00:28:45 +0100 Subject: [PATCH 13/34] Correct some oversights where drawangle was incorrectly ignored. --- src/p_enemy.c | 18 +++++++++++++----- src/p_spec.c | 2 +- src/p_telept.c | 34 ++++++++++++++++++---------------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 5de14e0a7..995635b3f 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5977,7 +5977,7 @@ void A_MixUp(mobj_t *actor) else if (numplayers == 2) // Special case -- simple swap { fixed_t x, y, z; - angle_t angle; + angle_t angle, drawangle; INT32 one = -1, two = 0; // default value 0 to make the compiler shut up // Zoom tube stuff @@ -6027,6 +6027,7 @@ void A_MixUp(mobj_t *actor) y = players[one].mo->y; z = players[one].mo->z; angle = players[one].mo->angle; + drawangle = players[one].drawangle; starpostx = players[one].starpostx; starposty = players[one].starposty; @@ -6042,10 +6043,14 @@ void A_MixUp(mobj_t *actor) players[two].starpostnum, players[two].starposttime, players[two].starpostangle, players[two].mo->flags2); + players[one].drawangle = players[two].drawangle; + P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz, starpostnum, starposttime, starpostangle, mflags2); + players[two].drawangle = drawangle; + //carry set after mixup. Stupid P_ResetPlayer() takes away some of the stuff we look for... //but not all of it! So we need to make sure they aren't set wrong or anything. players[one].powers[pw_carry] = carry2; @@ -6057,7 +6062,7 @@ void A_MixUp(mobj_t *actor) else { fixed_t position[MAXPLAYERS][3]; - angle_t anglepos[MAXPLAYERS]; + angle_t anglepos[MAXPLAYERS][2]; INT32 pindex[MAXPLAYERS], counter = 0, teleportfrom = 0; // Zoom tube stuff @@ -6076,7 +6081,7 @@ void A_MixUp(mobj_t *actor) for (i = 0; i < MAXPLAYERS; i++) { - position[i][0] = position[i][1] = position[i][2] = anglepos[i] = pindex[i] = -1; + position[i][0] = position[i][1] = position[i][2] = anglepos[i][0] = anglepos[i][1] = pindex[i] = -1; teleported[i] = false; } @@ -6092,7 +6097,8 @@ void A_MixUp(mobj_t *actor) position[counter][1] = players[i].mo->y; position[counter][2] = players[i].mo->z; pindex[counter] = i; - anglepos[counter] = players[i].mo->angle; + anglepos[counter][0] = players[i].mo->angle; + anglepos[counter][1] = players[i].drawangle; players[i].mo->momx = players[i].mo->momy = players[i].mo->momz = players[i].rmomx = players[i].rmomy = 1; players[i].cmomx = players[i].cmomy = 0; @@ -6144,11 +6150,13 @@ void A_MixUp(mobj_t *actor) players[i].speed = transspeed[teleportfrom]; P_SetTarget(&players[i].mo->tracer, transtracer[teleportfrom]); - P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom], + P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom][0], spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2], starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom], flags2[teleportfrom]); + players[i].drawangle = anglepos[teleportfrom][1]; + //...carry after. same reasoning. players[i].powers[pw_carry] = transcarry[teleportfrom]; diff --git a/src/p_spec.c b/src/p_spec.c index e47b5cc03..1ec97a2f9 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4514,7 +4514,7 @@ DoneSection2: break; } - player->mo->angle = lineangle; + player->mo->angle = player->drawangle = lineangle; if (!demoplayback || P_AnalogMove(player)) { diff --git a/src/p_telept.c b/src/p_telept.c index 2e070d14b..3e135aee7 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -130,7 +130,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle if (!dontstopmove) thing->momx = thing->momy = thing->momz = 0; else // Change speed to match direction - P_InstaThrust(thing, thing->angle, P_AproxDistance(thing->momx, thing->momy)); + P_InstaThrust(thing, angle, FixedHypot(thing->momx, thing->momy)); if (thing->player) { @@ -139,21 +139,6 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle else thing->player->viewz = thing->z + thing->player->viewheight; - if (!dontstopmove) - thing->reactiontime = TICRATE/2; // don't move for about half a second - - // absolute angle position - if (thing->player == &players[consoleplayer]) - localangle = angle; - if (thing->player == &players[secondarydisplayplayer]) - localangle2 = angle; - - // move chasecam at new player location - if (splitscreen && camera2.chase && thing->player == &players[secondarydisplayplayer]) - P_ResetCamera(thing->player, &camera2); - else if (camera.chase && thing->player == &players[displayplayer]) - P_ResetCamera(thing->player, &camera); - // don't run in place after a teleport if (!dontstopmove) { @@ -171,7 +156,24 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle thing->player->speed = 0; P_ResetPlayer(thing->player); P_SetPlayerMobjState(thing, S_PLAY_STND); + + thing->reactiontime = TICRATE/2; // don't move for about half a second + thing->player->drawangle = angle; } + else + thing->player->drawangle += (angle - thing->angle); + + // absolute angle position + if (thing->player == &players[consoleplayer]) + localangle = angle; + if (thing->player == &players[secondarydisplayplayer]) + localangle2 = angle; + + // move chasecam at new player location + if (splitscreen && camera2.chase && thing->player == &players[secondarydisplayplayer]) + P_ResetCamera(thing->player, &camera2); + else if (camera.chase && thing->player == &players[displayplayer]) + P_ResetCamera(thing->player, &camera); if (flash) P_FlashPal(thing->player, PAL_MIXUP, 10); From f182bb867f30c4c4e58e14cf2cae06479ec94101 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 20 Jun 2019 15:34:27 +0100 Subject: [PATCH 14/34] HUD stuff. * Re-fix chat HUD position, and make it not move in match (which it needed to do in 2.1). * Fix HU_drawPing for the new palette. * Change the condition for greying out players, since the current one was buggy. * Allow for tokens on the coop MP HUD, and use the small emeralds so there's space for them. * Fix the mapping between skincolours and name colours in new chat, specifically to take into account every possible text colour (as opposed to the port previously done, which only used the 2.1 text colours and looked like ass as a result). --- src/dehacked.c | 2 + src/hu_stuff.c | 200 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 146 insertions(+), 56 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index a3752ece5..e90329417 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8688,6 +8688,7 @@ struct { {"V_6WIDTHSPACE",V_6WIDTHSPACE}, {"V_OLDSPACING",V_OLDSPACING}, {"V_MONOSPACE",V_MONOSPACE}, + {"V_MAGENTAMAP",V_MAGENTAMAP}, {"V_YELLOWMAP",V_YELLOWMAP}, {"V_GREENMAP",V_GREENMAP}, @@ -8703,6 +8704,7 @@ struct { {"V_BROWNMAP",V_BROWNMAP}, {"V_ROSYMAP",V_ROSYMAP}, {"V_INVERTMAP",V_INVERTMAP}, + {"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 1a77774c8..a4eeafc6c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -751,40 +751,102 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) cstart = "\x83"; // Follow palette order at r_draw.c Color_Names - if (color <= SKINCOLOR_SILVER - || color == SKINCOLOR_AETHER) - cstart = "\x80"; // White - else if (color <= SKINCOLOR_BLACK - || color == SKINCOLOR_SLATE) - cstart = "\x86"; // Grey - else if (color <= SKINCOLOR_YOGURT) - cstart = "\x85"; // Red - else if (color <= SKINCOLOR_BEIGE) - cstart = "\x86"; // Grey - else if (color <= SKINCOLOR_LAVENDER) - cstart = "\x81"; // Purple - else if (color <= SKINCOLOR_PEACHY) - cstart = "\x85"; // Red - else if (color <= SKINCOLOR_RUST) - cstart = "\x87"; // Orange - else if (color == SKINCOLOR_GOLD - || color == SKINCOLOR_YELLOW) - cstart = "\x82"; // Yellow - else if (color == SKINCOLOR_SANDY - || color == SKINCOLOR_OLIVE) - cstart = "\x81"; // Purple - else if (color <= SKINCOLOR_MINT) - cstart = "\x83"; // Green - else if (color <= SKINCOLOR_DUSK) - cstart = "\x84"; // Blue - else if (color == SKINCOLOR_PINK - || color == SKINCOLOR_PASTEL - || color == SKINCOLOR_BUBBLEGUM - || color == SKINCOLOR_MAGENTA - || color == SKINCOLOR_ROSY) - cstart = "\x85"; // Red - else if (color <= SKINCOLOR_PLUM) - cstart = "\x81"; // Purple + switch (color) + { + default: + case SKINCOLOR_WHITE: + case SKINCOLOR_BONE: + case SKINCOLOR_CLOUDY: + case SKINCOLOR_GREY: + case SKINCOLOR_SILVER: + case SKINCOLOR_AETHER: + case SKINCOLOR_SLATE: + cstart = "\x80"; // white + break; + case SKINCOLOR_CARBON: + case SKINCOLOR_JET: + case SKINCOLOR_BLACK: + cstart = "\x86"; // V_GRAYMAP + break; + case SKINCOLOR_PINK: + case SKINCOLOR_RUBY: + case SKINCOLOR_SALMON: + case SKINCOLOR_RED: + case SKINCOLOR_CRIMSON: + case SKINCOLOR_FLAME: + cstart = "\x85"; // V_REDMAP + break; + case SKINCOLOR_YOGURT: + case SKINCOLOR_BROWN: + case SKINCOLOR_TAN: + case SKINCOLOR_BEIGE: + case SKINCOLOR_QUAIL: + cstart = "\x8d"; // V_BROWNMAP + break; + case SKINCOLOR_MOSS: + case SKINCOLOR_GREEN: + case SKINCOLOR_FOREST: + case SKINCOLOR_EMERALD: + case SKINCOLOR_MINT: + cstart = "\x83"; // V_GREENMAP + break; + case SKINCOLOR_AZURE: + cstart = "\x8c"; // V_AZUREMAP + break; + case SKINCOLOR_LAVENDER: + case SKINCOLOR_PASTEL: + case SKINCOLOR_PURPLE: + cstart = "\x89"; // V_PURPLEMAP + break; + case SKINCOLOR_PEACHY: + case SKINCOLOR_LILAC: + case SKINCOLOR_PLUM: + case SKINCOLOR_ROSY: + cstart = "\x8e"; // V_ROSYMAP + break; + case SKINCOLOR_SUNSET: + case SKINCOLOR_APRICOT: + case SKINCOLOR_ORANGE: + case SKINCOLOR_RUST: + cstart = "\x87"; // V_ORANGEMAP + break; + case SKINCOLOR_GOLD: + case SKINCOLOR_SANDY: + case SKINCOLOR_YELLOW: + case SKINCOLOR_OLIVE: + cstart = "\x82"; // V_YELLOWMAP + break; + case SKINCOLOR_LIME: + case SKINCOLOR_PERIDOT: + cstart = "\x8b"; // V_PERIDOTMAP + break; + case SKINCOLOR_SEAFOAM: + case SKINCOLOR_AQUA: + cstart = "\x8a"; // V_AQUAMAP + break; + case SKINCOLOR_TEAL: + case SKINCOLOR_WAVE: + case SKINCOLOR_CYAN: + case SKINCOLOR_SKY: + case SKINCOLOR_CERULEAN: + case SKINCOLOR_ICY: + case SKINCOLOR_SAPPHIRE: + case SKINCOLOR_VAPOR: + cstart = "\x88"; // V_SKYMAP + break; + case SKINCOLOR_CORNFLOWER: + case SKINCOLOR_BLUE: + case SKINCOLOR_COBALT: + case SKINCOLOR_DUSK: + cstart = "\x84"; // V_BLUEMAP + break; + case SKINCOLOR_BUBBLEGUM: + case SKINCOLOR_MAGENTA: + case SKINCOLOR_NEON: + case SKINCOLOR_VIOLET: + cstart = "\x81"; // V_MAGENTAMAP + break; + } } prefix = cstart; @@ -1327,7 +1389,7 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) // 30/7/18: chaty is now the distance at which the lowest point of the chat will be drawn if that makes any sense. -INT16 chatx = 14, chaty = 180; // let's use this as our coordinates +INT16 chatx = 13, chaty = 169; // let's use this as our coordinates // chat stuff by VincyTM LOL XD! @@ -1506,7 +1568,6 @@ static void HU_drawChatLog(INT32 offset) //y += 16; } #endif - y -= (G_RingSlingerGametype() ? 16 : 0); chat_topy = y + chat_scroll*charheight; chat_bottomy = chat_topy + boxh*charheight; @@ -2229,7 +2290,7 @@ void HU_Erase(void) //====================================================================== #define supercheckdef ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS1] || players[tab[i].num].mo->state >= &states[S_PLAY_SUPER_TRANS6])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin].flags & SF_SUPER)) -#define greycheckdef ((players[tab[i].num].mo && ((players[tab[i].num].rings <= 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres <= 0 && (maptol & TOL_NIGHTS)))) || players[tab[i].num].spectator) +#define greycheckdef (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD || (G_IsSpecialStage(gamemap) && players[tab[i].num].exiting)) // // HU_drawPing @@ -2237,7 +2298,7 @@ void HU_Erase(void) void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext) { UINT8 numbars = 1; // how many ping bars do we draw? - UINT8 barcolor = 128; // color we use for the bars (green, yellow or red) + UINT8 barcolor = 35; // color we use for the bars (green, yellow or red) SINT8 i = 0; SINT8 yoffset = 6; INT32 dx = x+1 - (V_SmallStringWidth(va("%dms", ping), V_ALLOWLOWERCASE)/2); @@ -2245,12 +2306,12 @@ void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext) if (ping < 128) { numbars = 3; - barcolor = 184; + barcolor = 112; } else if (ping < 256) { numbars = 2; // Apparently ternaries w/ multiple statements don't look good in C so I decided against it. - barcolor = 103; + barcolor = 73; } if (!notext || vid.width >= 640) // how sad, we're using a shit resolution. @@ -2414,6 +2475,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) INT32 redplayers = 0, blueplayers = 0; const UINT8 *colormap; char name[MAXPLAYERNAME+1]; + boolean greycheck, supercheck; V_DrawFill(160, 26, 1, 154, 0); //Draw a vertical line to separate the two teams. V_DrawFill(1, 26, 318, 1, 0); //And a horizontal line to make a T. @@ -2424,6 +2486,9 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) if (players[tab[i].num].spectator) continue; //ignore them. + greycheck = greycheckdef; + supercheck = supercheckdef; + if (tab[i].color == skincolor_redteam) //red { redplayers++; @@ -2439,10 +2504,13 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) else //er? not on red or blue, so ignore them continue; + greycheck = greycheckdef; + supercheck = supercheckdef; + strlcpy(name, tab[i].name, 8); V_DrawString(x + 10, y, ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (((players[tab[i].num].rings > 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres > 0 && (maptol & TOL_NIGHTS))) ? 0 : V_TRANSLUCENT) + | (greycheck ? 0 : V_TRANSLUCENT) | V_ALLOWLOWERCASE, name); if (gametype == GT_CTF) @@ -2454,13 +2522,19 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) } // Draw emeralds - if (!players[tab[i].num].powers[pw_super] + if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) + { + HU_Draw32Emeralds(x+60, y+2, 255); + //HU_DrawEmeralds(x-12,y+2,255); + } + else if (!players[tab[i].num].powers[pw_super] || ((leveltime/7) & 1)) { HU_Draw32Emeralds(x+60, y+2, tab[i].emeralds); + //HU_DrawEmeralds(x-12,y+2,tab[i].emeralds); } - if (players[tab[i].num].powers[pw_super]) + if (supercheck) { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], colormap); @@ -2468,12 +2542,12 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - if ((players[tab[i].num].rings <= 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres <= 0 && (maptol & TOL_NIGHTS))) + if (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, V_HUDTRANSHALF, faceprefix[players[tab[i].num].skin], colormap); else V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, faceprefix[players[tab[i].num].skin], colormap); } - V_DrawRightAlignedThinString(x+128, y, (((players[tab[i].num].rings > 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres > 0 && (maptol & TOL_NIGHTS))) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+128, y, ((players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); if (!splitscreen) { if (!(tab[i].num == serverplayer)) @@ -2722,6 +2796,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor INT32 i; const UINT8 *colormap; char name[MAXPLAYERNAME+1]; + boolean greycheck, supercheck; V_DrawFill(160, 26, 1, 154, 0); //Draw a vertical line to separate the two sides. V_DrawFill(1, 26, 318, 1, 0); //And a horizontal line to make a T. @@ -2729,9 +2804,12 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor for (i = 0; i < scorelines; i++) { - if (players[tab[i].num].spectator) + if (players[tab[i].num].spectator && gametype != GT_COOP) continue; //ignore them. + greycheck = greycheckdef; + supercheck = supercheckdef; + strlcpy(name, tab[i].name, 7); if (!splitscreen) // don't draw it on splitscreen, { @@ -2743,7 +2821,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor V_DrawString(x + 10, y, ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (((players[tab[i].num].rings > 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres > 0 && (maptol & TOL_NIGHTS))) ? 0 : V_TRANSLUCENT) + | (greycheck ? 0 : V_TRANSLUCENT) | V_ALLOWLOWERCASE, name); if (G_GametypeUsesLives()) //show lives @@ -2752,7 +2830,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, tagico, 0); // Draw emeralds - if (players[tab[i].num].powers[pw_invulnerability] && players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) + if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) { HU_Draw32Emeralds(x+60, y+2, 255); //HU_DrawEmeralds(x-12,y+2,255); @@ -2772,7 +2850,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], 0); else { - if ((players[tab[i].num].rings <= 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres <= 0 && (maptol & TOL_NIGHTS))) + if (greycheck) V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, V_HUDTRANSHALF, faceprefix[players[tab[i].num].skin], 0); else V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, faceprefix[players[tab[i].num].skin], 0); @@ -2780,7 +2858,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor } else { - if (players[tab[i].num].powers[pw_super]) + if (supercheck) { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], colormap); @@ -2788,7 +2866,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - if ((players[tab[i].num].rings <= 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres <= 0 && (maptol & TOL_NIGHTS))) + if (greycheck) V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, V_HUDTRANSHALF, faceprefix[players[tab[i].num].skin], colormap); else V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, faceprefix[players[tab[i].num].skin], colormap); @@ -2803,13 +2881,13 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor if (players[tab[i].num].exiting) V_DrawRightAlignedThinString(x+128, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); else - V_DrawRightAlignedThinString(x+128, y, (((players[tab[i].num].rings > 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres > 0 && (maptol & TOL_NIGHTS))) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); } else - V_DrawRightAlignedThinString(x+128, y, (((players[tab[i].num].rings > 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres > 0 && (maptol & TOL_NIGHTS))) ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); + V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); } else - V_DrawRightAlignedThinString(x+128, y, (((players[tab[i].num].rings > 0 && !(maptol & TOL_NIGHTS)) || (players[tab[i].num].spheres > 0 && (maptol & TOL_NIGHTS))) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); y += 9; if (i == 16) @@ -3045,7 +3123,7 @@ static void HU_DrawRankings(void) // shush, we'll do it anyway. if (G_GametypeHasTeams()) - HU_DrawTeamTabRankings(tab, whiteplayer); //separate function for Spazzo's silly request + HU_DrawTeamTabRankings(tab, whiteplayer); else if (scorelines <= 9 && !cv_compactscoreboard.value) HU_DrawTabRankings(40, 32, tab, scorelines, whiteplayer); else if (scorelines <= 20 && !cv_compactscoreboard.value) @@ -3104,6 +3182,16 @@ static void HU_DrawNetplayCoopOverlay(void) { int i; + if (token +#ifdef HAVE_BLUA + && LUA_HudEnabled(hud_tokens) +#endif + ) + { + V_DrawString(168, 10, 0, va("- %d", token)); + V_DrawSmallScaledPatch(148, 6, 0, tokenicon); + } + #ifdef HAVE_BLUA if (!LUA_HudEnabled(hud_coopemeralds)) return; @@ -3112,7 +3200,7 @@ static void HU_DrawNetplayCoopOverlay(void) for (i = 0; i < 7; ++i) { if (emeralds & (1 << i)) - V_DrawScaledPatch(20 + (i * 20), 6, 0, emeraldpics[0][i]); + V_DrawScaledPatch(20 + (i * 10), 9, 0, emeraldpics[1][i]); } } From f7fe418f7c6819897a287a1ad5f0d3cb4ecec568 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 20 Jun 2019 23:43:05 +0100 Subject: [PATCH 15/34] Slight buff to MT_LHRT. --- 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 c4211be85..9b25ba473 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7862,8 +7862,8 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_LHRT: - mobj->momx = FixedMul(mobj->momx, (48*FRACUNIT)/50); - mobj->momy = FixedMul(mobj->momy, (48*FRACUNIT)/50); + mobj->momx = FixedMul(mobj->momx, (49*FRACUNIT)/50); + mobj->momy = FixedMul(mobj->momy, (49*FRACUNIT)/50); break; case MT_EGGCAPSULE: if (!mobj->reactiontime) From 3597b1c4857c0e74289f01f132c7e9aab45a348a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 21 Jun 2019 00:43:03 +0100 Subject: [PATCH 16/34] Make minor adjustments to the CA2_MELEE and CA_TWINSPIN stuff. --- src/info.c | 4 ++-- src/p_user.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/info.c b/src/info.c index 5a8633233..0dc0797c9 100644 --- a/src/info.c +++ b/src/info.c @@ -724,10 +724,10 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_FIRE, 15, {NULL}, S_PLAY_STND, 0, S_PLAY_STND}, // S_PLAY_FIRE_FINISH // CA_TWINSPIN - {SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN + {SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN // CA2_MELEE - {SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE + {SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE {SPR_PLAY, SPR2_MLEE, 70, {NULL}, 0, 0, S_PLAY_FALL}, // S_PLAY_MELEE_FINISH {SPR_PLAY, SPR2_MLEL, 35, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_MELEE_LANDING diff --git a/src/p_user.c b/src/p_user.c index 534f281ff..ae4876221 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2015,7 +2015,7 @@ boolean P_PlayerHitFloor(player_t *player) } else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING)) { - mobjtype_t type = player->spinitem; + mobjtype_t type = player->revitem; P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; S_StartSound(player->mo, sfx_s3k8b); From d5e91ed8d77277fd355c15ab62d37193205fb5ea Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 21 Jun 2019 12:35:37 +0100 Subject: [PATCH 17/34] Don't give SH_PINK in Race/Competition. They're your opponents! --- src/p_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index a8e716123..49916c858 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2922,7 +2922,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj // In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on if (!cv_friendlyfire.value && (G_PlatformGametype())) { - if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) + if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only { if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { From 50e4a65f99f8ae57dcb453f791ec1c3352eafce0 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 21 Jun 2019 12:51:55 +0100 Subject: [PATCH 18/34] Correct some more oversights of switching to revitem for CA2_MELEE's particles. --- src/p_enemy.c | 3 +++ src/p_inter.c | 8 ++++---- src/r_things.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 995635b3f..07d1b9746 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -6329,6 +6329,9 @@ void A_RecyclePowers(mobj_t *actor) players[recv_pl].ringweapons = weapons[send_pl]; players[recv_pl].currentweapon = weaponheld[send_pl]; + if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT)) // Healers can't keep their buff. + players[recv_pl].powers[pw_shield] &= SH_STACK; + P_SpawnShieldOrb(&players[recv_pl]); if (P_IsLocalPlayer(&players[recv_pl])) P_RestoreMusic(&players[recv_pl]); diff --git a/src/p_inter.c b/src/p_inter.c index 49916c858..81f046e2e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2824,7 +2824,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2839,7 +2839,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2924,7 +2924,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only { - if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2947,7 +2947,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); diff --git a/src/r_things.c b/src/r_things.c index 9b5cbc09a..22c3d96c9 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2704,7 +2704,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; player->followitem = skin->followitem; - if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->spinitem == MT_LHRT)) // Healers can't keep their buff. + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT)) // Healers can't keep their buff. player->powers[pw_shield] &= SH_STACK; player->actionspd = skin->actionspd; From 02e315a4ee83b3a10e049d56ab7dbdd47f35c8b0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Jun 2019 16:44:32 +0100 Subject: [PATCH 19/34] Add HUD icon for Pink shield. (Don't worry, this is my last expected commit in this branch. Gonna cherry pick everything unrelated to the Pink shield into a bunch of other branches now.) --- src/st_stuff.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/st_stuff.c b/src/st_stuff.c index f0f40ed32..1cf221bc9 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -95,6 +95,7 @@ static patch_t *ringshield; static patch_t *watershield; static patch_t *bombshield; static patch_t *pityshield; +static patch_t *pinkshield; static patch_t *flameshield; static patch_t *bubbleshield; static patch_t *thundershield; @@ -285,6 +286,7 @@ void ST_LoadGraphics(void) watershield = W_CachePatchName("TVELICON", PU_HUDGFX); bombshield = W_CachePatchName("TVARICON", PU_HUDGFX); pityshield = W_CachePatchName("TVPIICON", PU_HUDGFX); + pinkshield = W_CachePatchName("TVPPICON", PU_HUDGFX); flameshield = W_CachePatchName("TVFLICON", PU_HUDGFX); bubbleshield = W_CachePatchName("TVBBICON", PU_HUDGFX); thundershield = W_CachePatchName("TVZPICON", PU_HUDGFX); @@ -1250,6 +1252,7 @@ static void ST_drawPowerupHUD(void) case SH_ARMAGEDDON: p = bombshield; break; case SH_ATTRACT: p = ringshield; break; case SH_PITY: p = pityshield; break; + case SH_PINK: p = pinkshield; break; case SH_FLAMEAURA: p = flameshield; break; case SH_BUBBLEWRAP: p = bubbleshield; break; case SH_THUNDERCOIN: p = thundershield; break; From 29c4fa306ac79546fa78621548bacc84ff37dc62 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Jun 2019 17:23:04 +0100 Subject: [PATCH 20/34] Realised I forgot to do this. Without this commit, the drawangle update stuff is useless :V --- src/p_telept.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_telept.c b/src/p_telept.c index 3e135aee7..e80dd0428 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -125,8 +125,6 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle if (!P_TeleportMove(thing, x, y, z)) return false; - thing->angle = angle; - if (!dontstopmove) thing->momx = thing->momy = thing->momz = 0; else // Change speed to match direction @@ -179,5 +177,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle P_FlashPal(thing->player, PAL_MIXUP, 10); } + thing->angle = angle; + return true; } From b02c21b818bf61c003ed66cfd7ab69d118196ee1 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 22 Jun 2019 20:15:48 +0100 Subject: [PATCH 21/34] Remove some more 2.1-related ringslinger offsets to the chat. --- src/hu_stuff.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a4eeafc6c..f86100e27 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1468,7 +1468,6 @@ static void HU_drawMiniChat(void) if (splitscreen > 1) y += 16; }*/ - y -= (G_RingSlingerGametype() ? 16 : 0); dx = 0; dy = 0; @@ -1677,7 +1676,6 @@ static void HU_DrawChat(void) } } #endif - y -= (G_RingSlingerGametype() ? 16 : 0); if (teamtalk) { @@ -1770,7 +1768,6 @@ static void HU_DrawChat(void) p_dispy += 16; } #endif - p_dispy -= (G_RingSlingerGametype() ? 16 : 0); i = 0; for(i=0; (i Date: Wed, 26 Jun 2019 23:26:05 +0100 Subject: [PATCH 22/34] Now it's CA_TWINSPIN's turn to get the improvements! * Remove PF_THOKKED every time a successful damage bounce occours. * When this happens, spawn a number of particles based on thokitem at half scale! (Optimised, again, for MT_LHRT.) * Also spawn these particles when a successful spring boost occours, as well as playing a twisted spring sound. Also, some other related tweaks: * Optimisations to A_VultureBlast, which was used as a base for the particle creation. * Make the Metal Sonic boss use P_PlayerCanDamage instead of a custom, somewhat broken player damage detection mechanism. * P_SpawnGhostMobj takes colorized into account. * Fold Tails propeller damage into P_PlayerCanDamage. * When performing an Attraction Blast, place the player in roll frames. * Update all conditions preventing SH_PINK to incorporate thokitem and spinitem as well. * Buff MT_LHRT travel distance at slow speeds. --- src/p_enemy.c | 15 ++++++++---- src/p_inter.c | 22 ++++++----------- src/p_local.h | 1 + src/p_map.c | 27 ++++++++++++++++++--- src/p_mobj.c | 40 ++++++++++++++---------------- src/p_user.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++--- src/r_things.c | 2 +- src/sounds.c | 1 + src/sounds.h | 1 + 9 files changed, 126 insertions(+), 49 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 95138a3fa..23c9b88fc 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2411,6 +2411,8 @@ void A_VultureBlast(mobj_t *actor) { mobj_t *dust; UINT8 i; + angle_t faa; + fixed_t faacos, faasin; #ifdef HAVE_BLUA if (LUA_CallAction("A_VultureBlast", actor)) @@ -2419,18 +2421,21 @@ void A_VultureBlast(mobj_t *actor) S_StartSound(actor, actor->info->attacksound); + faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + faacos = FINECOSINE(faa); + faasin = FINESINE(faa); + for (i = 0; i <= 7; i++) { angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK; - angle_t faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; - dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -FINESINE(faa)), actor->y + 48*FixedMul(FINECOSINE(fa), FINECOSINE(faa)), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); + dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -faasin), actor->y + 48*FixedMul(FINECOSINE(fa), faacos), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); P_SetScale(dust, 4*FRACUNIT); dust->destscale = FRACUNIT; dust->scalespeed = 4*FRACUNIT/TICRATE; dust->fuse = TICRATE; - dust->momx = FixedMul(FINECOSINE(fa), -FINESINE(faa))*3; - dust->momy = FixedMul(FINECOSINE(fa), FINECOSINE(faa))*3; + dust->momx = FixedMul(FINECOSINE(fa), -faasin)*3; + dust->momy = FixedMul(FINECOSINE(fa), faacos)*3; dust->momz = FINESINE(fa)*6; } } @@ -6631,7 +6636,7 @@ void A_RecyclePowers(mobj_t *actor) players[recv_pl].ringweapons = weapons[send_pl]; players[recv_pl].currentweapon = weaponheld[send_pl]; - if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT)) // Healers can't keep their buff. + if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT || players[recv_pl].spinitem == MT_LHRT || players[recv_pl].thokitem == MT_LHRT)) // Healers can't keep their buff. players[recv_pl].powers[pw_shield] &= SH_STACK; P_SpawnShieldOrb(&players[recv_pl]); diff --git a/src/p_inter.c b/src/p_inter.c index 42809c66b..3348696c0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -468,18 +468,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { toucher->momx = -toucher->momx; toucher->momy = -toucher->momy; + if (player->charability == CA_FLY && player->panim == PA_ABILITY) + toucher->momz = -toucher->momz/2; } P_DamageMobj(special, toucher, toucher, 1, 0); - } - else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) - || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) - && player->charability == CA_FLY - && (player->powers[pw_tailsfly] - || toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with her propeller. - { - toucher->momz = -toucher->momz/2; - - P_DamageMobj(special, toucher, toucher, 1, 0); + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + P_TwinSpinRejuvenate(player, player->thokitem); } else P_DamageMobj(toucher, special, special, 1, 0); @@ -2898,7 +2892,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2913,7 +2907,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2998,7 +2992,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -3021,7 +3015,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); diff --git a/src/p_local.h b/src/p_local.h index d6f9d7648..8aeddf162 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -159,6 +159,7 @@ boolean P_AutoPause(void); void P_DoJumpShield(player_t *player); void P_DoBubbleBounce(player_t *player); void P_DoAbilityBounce(player_t *player, boolean changemomz); +void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type); void P_BlackOw(player_t *player); void P_ElementalFire(player_t *player, boolean cropcircle); diff --git a/src/p_map.c b/src/p_map.c index 4d4d30356..76b6535b5 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -135,6 +135,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; boolean final = false; + UINT8 strong = 0; // Object was already sprung this tic if (object->eflags & MFE_SPRUNG) @@ -148,6 +149,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (!spring->health || !object->health) return false; + if (object->player) + { + if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) + strong = 1; + else if (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2) + strong = 2; + } + if (spring->info->painchance == -1) // Pinball bumper mode. { // The first of the entirely different spring modes! @@ -188,6 +197,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { fixed_t playervelocity; + if (strong) + vertispeed <<= 1; + if (!(object->player->pflags & PF_THOKKED) && !(object->player->homing) && ((playervelocity = FixedDiv(9*FixedHypot(object->player->speed, object->momz), 10< vertispeed)) vertispeed = playervelocity; @@ -260,11 +272,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) return false; } - if (object->player - && ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) - || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2))) + if (strong) { - S_StartSound(object, sfx_s3k8b); if (horizspeed) horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3); if (vertispeed) @@ -399,6 +408,12 @@ springstate: P_AddPlayerScore(object->player, 10); spring->reactiontime--; } + + if (strong) + { + P_TwinSpinRejuvenate(object->player, (strong == 1 ? object->player->thokitem : object->player->revitem)); + S_StartSound(object, sfx_sprong); // strong spring. sprong. + } } return final; @@ -1504,7 +1519,11 @@ static boolean PIT_CheckThing(mobj_t *thing) if (elementalpierce == 2) P_DoBubbleBounce(player); else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + { *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + P_TwinSpinRejuvenate(player, player->thokitem); + } } if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. { diff --git a/src/p_mobj.c b/src/p_mobj.c index a78a83da1..70017546c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -281,6 +281,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) player->panim = PA_FALL; break; case S_PLAY_FLY: + case S_PLAY_FLY_TIRED: case S_PLAY_SWIM: case S_PLAY_GLIDE: case S_PLAY_BOUNCE: @@ -1509,8 +1510,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (mo->player) { if ((mo->player->pflags & PF_GLIDING) - || (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly] - || mo->state-states == S_PLAY_FLY_TIRED))) + || (mo->player->charability == CA_FLY && mo->player->panim == PA_ABILITY)) gravityadd = gravityadd/3; // less gravity while flying/gliding if (mo->player->climbing || (mo->player->powers[pw_carry] == CR_NIGHTSMODE)) gravityadd = 0; @@ -5484,7 +5484,6 @@ static void P_Boss9Thinker(mobj_t *mobj) // AI goes here. { - boolean danger = true; angle_t angle; if (mobj->threshold) mobj->momz = (mobj->watertop-mobj->z)/16; // Float to your desired position FASTER @@ -5837,29 +5836,26 @@ static void P_Boss9Thinker(mobj_t *mobj) //A_FaceTarget(mobj); // Check if we're being attacked - if (!(mobj->target->player->pflags & (PF_JUMPED|PF_SPINNING) - || mobj->target->player->powers[pw_tailsfly] - || mobj->target->player->powers[pw_invulnerability] - || mobj->target->player->powers[pw_super])) - danger = false; + if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) + goto nodanger; if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) - danger = false; + goto nodanger; if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) - danger = false; + goto nodanger; if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) - danger = false; + goto nodanger; if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) - danger = false; + goto nodanger; if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) - danger = false; + goto nodanger; if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) - danger = false; - if (danger) { - // An incoming attack is detected! What should we do?! - // Go into vector form! - vectorise; - return; - } + goto nodanger; + + // An incoming attack is detected! What should we do?! + // Go into vector form! + vectorise; + return; +nodanger: // Move normally: Approach the player using normal thrust and simulated friction. dist = P_AproxDistance(mobj->x-mobj->target->x, mobj->y-mobj->target->y); @@ -7920,8 +7916,8 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_LHRT: - mobj->momx = FixedMul(mobj->momx, (49*FRACUNIT)/50); - mobj->momy = FixedMul(mobj->momy, (49*FRACUNIT)/50); + mobj->momx = FixedMul(mobj->momx, mobj->extravalue2); + mobj->momy = FixedMul(mobj->momy, mobj->extravalue2); break; case MT_EGGCAPSULE: if (!mobj->reactiontime) diff --git a/src/p_user.c b/src/p_user.c index 9961d55dc..ac951a8fa 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1021,9 +1021,13 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) && (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) < ANGLE_180) return true; - // From the top. - if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) - && (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) + // From the top/bottom. + if (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) + { + if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) + return true; + } + else if (player->charability == CA_FLY && player->panim == PA_ABILITY) return true; // Shield stomp. @@ -1752,6 +1756,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) } ghost->color = mobj->color; + ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); ghost->sprite = mobj->sprite; @@ -2031,9 +2036,11 @@ boolean P_PlayerHitFloor(player_t *player) fixed_t zo = 6*player->mo->scale; fixed_t mu = FixedMul(player->maxdash, player->mo->scale); fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t ev; mobj_t *missile; if (mu2 < mu) mu2 = mu; + ev = (50*FRACUNIT - (mu/25))/50; while (i < 5) { missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); @@ -2044,6 +2051,7 @@ boolean P_PlayerHitFloor(player_t *player) P_Thrust(missile, player->drawangle, mu2); // forward component P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); missile->fuse = TICRATE/2; + missile->extravalue2 = ev; i++; throwang += ANG30; @@ -4529,6 +4537,57 @@ void P_DoAbilityBounce(player_t *player, boolean changemomz) player->pflags |= PF_BOUNCING|PF_THOKKED; } +// +// P_TwinSpinRejuvenate +// +// CA_TWINSPIN landing handling +// +void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type) +{ + fixed_t actionspd; + angle_t movang, ang, fa; + fixed_t v, h; + UINT8 i; + + if (!player->mo || !type) + return; + + actionspd = FixedMul(player->actionspd, player->mo->scale); + + fa = (R_PointToAngle2(0, 0, player->mo->momz, FixedHypot(player->mo->momx, player->mo->momy))>>ANGLETOFINESHIFT) & FINEMASK; + movang = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + ang = 0; + + v = FixedMul(actionspd, FINESINE(fa)); + h = actionspd - FixedMul(actionspd, FINECOSINE(fa)); + + // hearticles + for (i = 0; i <= 7; i++) + { + fixed_t side = actionspd - FixedMul(h, abs(FINESINE((ang>>ANGLETOFINESHIFT) & FINEMASK))); + fixed_t xo = P_ReturnThrustX(NULL, ang + movang, side); + fixed_t yo = P_ReturnThrustY(NULL, ang + movang, side); + fixed_t zo = -FixedMul(FINECOSINE(((ang>>ANGLETOFINESHIFT) & FINEMASK)), v); + mobj_t *missile = P_SpawnMobjFromMobj(player->mo, + xo, + yo, + player->mo->height/2 + zo, + type); + P_SetTarget(&missile->target, player->mo); + P_SetScale(missile, (missile->destscale >>= 1)); + missile->angle = ang + movang; + missile->fuse = TICRATE/2; + missile->extravalue2 = (99*FRACUNIT)/100; + missile->momx = xo; + missile->momy = yo; + missile->momz = zo; + + ang += ANGLE_45; + } + + player->pflags &= ~PF_THOKKED; +} + // // P_Telekinesis // @@ -7899,6 +7958,7 @@ static void P_MovePlayer(player_t *player) { player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); S_StartSound(player->mo, sfx_s3k40); player->homing = 3*TICRATE; } diff --git a/src/r_things.c b/src/r_things.c index 22c3d96c9..9fe1e96e4 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2704,7 +2704,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; player->followitem = skin->followitem; - if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT)) // Healers can't keep their buff. + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff. player->powers[pw_shield] &= SH_STACK; player->actionspd = skin->actionspd; diff --git a/src/sounds.c b/src/sounds.c index 56de4a9c5..52dbee341 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -197,6 +197,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, {"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"}, {"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"}, + {"sprong", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power spring"}, // Menu, interface {"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"}, diff --git a/src/sounds.h b/src/sounds.h index 475309121..742febbba 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -263,6 +263,7 @@ typedef enum sfx_corkh, sfx_bowl, sfx_chuchu, + sfx_sprong, // Menu, interface sfx_chchng, From faebe0f9aff3dc2d803d45f4f9f66529bcfd05c3 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 28 Jun 2019 20:48:14 +0100 Subject: [PATCH 23/34] Metal Sonic fixes! * Add more context clues to his fight, including an indicator for which laser attack is being used after chargeup. * Make missiles able to vectorise him. * Add another laser orb attack - vertical slice - and change the laser orb sequence to accurately reflect that horizontal is the hardest of the ones in 2.1. * Optimise TC_BLINK, and fix an issue with TC_ALLWHITE that somehow avoided coming up in testing. * Fix colorized bosses losing their colorization when flashing, by forcing TC_ALLWHITE. --- src/dehacked.c | 5 +- src/hardware/hw_main.c | 2 +- src/hardware/hw_md2.c | 2 +- src/info.c | 27 ++-- src/info.h | 5 +- src/lua_baselib.c | 4 +- src/p_local.h | 2 +- src/p_map.c | 21 +++ src/p_mobj.c | 360 +++++++++++++++++++++++++++++++---------- src/p_user.c | 45 +++--- src/r_draw.c | 7 +- src/r_things.c | 2 +- src/sounds.c | 4 +- 13 files changed, 351 insertions(+), 135 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index f532bde68..7935c474f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5125,7 +5125,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_METALSONIC_BADBOUNCE", "S_METALSONIC_SHOOT", "S_METALSONIC_PAIN", - "S_METALSONIC_DEATH", + "S_METALSONIC_DEATH1", + "S_METALSONIC_DEATH2", + "S_METALSONIC_DEATH3", + "S_METALSONIC_DEATH4", "S_METALSONIC_FLEE1", "S_METALSONIC_FLEE2", "S_METALSONIC_FLEE3", diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a76c9e1c8..d649eeb8e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5662,7 +5662,7 @@ static void HWR_ProjectSprite(mobj_t *thing) //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { - if (vis->mobj->type == MT_CYBRAKDEMON) + if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 6db5d5f08..e26aa98ff 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1363,7 +1363,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) INT32 skinnum = TC_DEFAULT; if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { - if (spr->mobj->type == MT_CYBRAKDEMON) + if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized) skinnum = TC_ALLWHITE; else if (spr->mobj->type == MT_METALSONIC_BATTLE) skinnum = TC_METALSONIC; diff --git a/src/info.c b/src/info.c index 477c3f372..a58b2313c 100644 --- a/src/info.c +++ b/src/info.c @@ -1747,20 +1747,23 @@ state_t states[NUMSTATES] = {SPR_METL, 9, 2, {NULL}, 0, 0, S_METALSONIC_RUN1}, // S_METALSONIC_RUN4 {SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT - {SPR_METL, 12, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR - {SPR_METL, 0, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN - {SPR_METL, 13, 40, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE + {SPR_METL, 12|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR + {SPR_METL, 11, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN + {SPR_METL, 13, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER {SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BOUNCE {SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE {SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT {SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN - {SPR_METL, 11, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH - {SPR_METL, 3, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 - {SPR_METL, 4, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 - {SPR_METL, 5, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3 - {SPR_METL, 4, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4 + {SPR_METL, 13, 8, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1 + {SPR_METL, 13, 8, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2 + {SPR_METL, 13, 0, {A_Repeat}, 11, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3 + {SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4 + {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 + {SPR_METL, 11, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 + {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3 + {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2 @@ -6259,13 +6262,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_METALSONIC_DASH, // seestate sfx_s3k54, // seesound 0, // reactiontime - sfx_trpowr, // attacksound + sfx_bechrg, // attacksound S_METALSONIC_PAIN, // painstate S_METALSONIC_VECTOR,// painchance sfx_dmpain, // painsound S_METALSONIC_BADBOUNCE, // meleestate S_METALSONIC_SHOOT, // missilestate - S_METALSONIC_DEATH, // deathstate + S_METALSONIC_DEATH1,// deathstate S_METALSONIC_FLEE1, // xdeathstate sfx_s3k6e, // deathsound MT_ENERGYBALL, // speed @@ -6297,7 +6300,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 32*FRACUNIT, // radius - 64*FRACUNIT, // height + 52*FRACUNIT, // height 0, // display offset 0, // mass 0, // damage @@ -9140,7 +9143,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_ENERGYBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_s3k54, // seesound + sfx_bexpld, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate diff --git a/src/info.h b/src/info.h index a7f5d775a..c1891a766 100644 --- a/src/info.h +++ b/src/info.h @@ -1888,7 +1888,10 @@ typedef enum state S_METALSONIC_BADBOUNCE, S_METALSONIC_SHOOT, S_METALSONIC_PAIN, - S_METALSONIC_DEATH, + S_METALSONIC_DEATH1, + S_METALSONIC_DEATH2, + S_METALSONIC_DEATH3, + S_METALSONIC_DEATH4, S_METALSONIC_FLEE1, S_METALSONIC_FLEE2, S_METALSONIC_FLEE3, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index e6119cd6c..81a17ef20 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1235,8 +1235,8 @@ static int lib_pHomingAttack(lua_State *L) INLEVEL if (!source || !enemy) return LUA_ErrInvalid(L, "mobj_t"); - P_HomingAttack(source, enemy); - return 0; + lua_pushboolean(L, P_HomingAttack(source, enemy)); + return 1; } static int lib_pSuperReady(lua_State *L) diff --git a/src/p_local.h b/src/p_local.h index 8aeddf162..479994079 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -176,7 +176,7 @@ void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move); mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet); void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius); -void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user +boolean P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user boolean P_SuperReady(player_t *player); void P_DoJump(player_t *player, boolean soundandstate); #if 0 diff --git a/src/p_map.c b/src/p_map.c index 76b6535b5..a852a3933 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -725,6 +725,27 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + // vectorise metal - done in a special case as at this point neither has the right flags for touching + if (thing->type == MT_METALSONIC_BATTLE + && (tmthing->flags & MF_MISSILE) + && tmthing->target != thing + && thing->state == &states[thing->info->spawnstate]) + { + blockdist = thing->radius + tmthing->radius; + + if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + thing->flags2 |= MF2_CLASSICPUSH; + + return true; + } + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index 70017546c..ff2bcc77f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5395,7 +5395,8 @@ static void P_Boss7Thinker(mobj_t *mobj) if (mobj->info->activesound)\ S_StartSound(mobj, mobj->info->activesound);\ if (mobj->info->painchance)\ - P_SetMobjState(mobj, mobj->info->painchance) + P_SetMobjState(mobj, mobj->info->painchance);\ + mobj->flags2 &= ~MF2_INVERTAIMABLE;\ // Metal Sonic battle boss // You CAN put multiple Metal Sonics in a single map @@ -5485,25 +5486,16 @@ static void P_Boss9Thinker(mobj_t *mobj) // AI goes here. { angle_t angle; - if (mobj->threshold) + if (mobj->threshold || mobj->movecount) mobj->momz = (mobj->watertop-mobj->z)/16; // Float to your desired position FASTER else mobj->momz = (mobj->watertop-mobj->z)/40; // Float to your desired position - if (mobj->movecount == 2) { + if (mobj->movecount == 2) + { mobj_t *spawner; fixed_t dist = 0; - angle = 0x06000000*leveltime; - - // Alter your energy bubble's size/position - if (mobj->health > 3) { - mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); - P_SetScale(mobj->tracer, mobj->tracer->destscale); - P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); - mobj->tracer->momx = mobj->momx; - mobj->tracer->momy = mobj->momy; - mobj->tracer->momz = mobj->momz; - } + angle = 0x06000000*leveltime; // wtf? // Face your target P_BossTargetPlayer(mobj, true); @@ -5514,27 +5506,150 @@ static void P_Boss9Thinker(mobj_t *mobj) else mobj->angle -= InvAngle(angle)/8; + // Alter your energy bubble's size/position + if (mobj->health > 3) + { + mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); + P_SetScale(mobj->tracer, mobj->tracer->destscale); + } + else + mobj->tracer->frame &= ~FF_TRANSMASK; // this causes a flicker but honestly i like it this way + P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); + mobj->tracer->momx = mobj->momx; + mobj->tracer->momy = mobj->momy; + mobj->tracer->momz = mobj->momz; + + // Firin' mah lazors - INDICATOR + if (mobj->fuse > TICRATE/2) + { + tic_t shoottime, worktime, calctime; + shoottime = (TICRATE/((mobj->extravalue1 == 3) ? 8 : 4)); + shoottime += (shoottime>>1); + worktime = shoottime*(mobj->threshold/2); + calctime = mobj->fuse-(TICRATE/2); + + if (calctime <= worktime && (calctime % shoottime == 0)) + { + mobj_t *missile; + + missile = P_SpawnMissile(mobj, mobj->target, MT_MSGATHER); + S_StopSound(missile); + if (mobj->extravalue1 >= 2) + P_SetScale(missile, FRACUNIT>>1); + missile->destscale = missile->scale>>1; + missile->fuse = TICRATE/2; + missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse; + missile->z -= missile->height/2; + missile->momx *= -1; + missile->momy *= -1; + missile->momz *= -1; + + if (mobj->extravalue1 == 2) + { + UINT8 i; + mobj_t *spread; + for (i = 0; i < 5; i++) + { + if (i == 2) + continue; + spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); + spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); + P_InstaThrust(spread,spread->angle,-spread->info->speed); + spread->momz = missile->momz; + P_SetScale(spread, missile->scale); + spread->destscale = missile->destscale; + spread->scalespeed = missile->scalespeed; + spread->fuse = missile->fuse; + P_UnsetThingPosition(spread); + spread->x -= spread->fuse*spread->momx; + spread->y -= spread->fuse*spread->momy; + spread->z -= spread->fuse*spread->momz; + P_SetThingPosition(spread); + } + P_InstaThrust(missile,missile->angle,-missile->info->speed); + } + else if (mobj->extravalue1 >= 3) + { + UINT8 i; + mobj_t *spread; + mobj->target->z -= (4*missile->height); + for (i = 0; i < 5; i++) + { + if (i != 2) + { + spread = P_SpawnMissile(mobj, mobj->target, missile->type); + P_SetScale(spread, missile->scale); + spread->destscale = missile->destscale; + spread->fuse = missile->fuse; + spread->z -= spread->height/2; + spread->momx *= -1; + spread->momy *= -1; + spread->momz *= -1; + P_UnsetThingPosition(spread); + spread->x -= spread->fuse*spread->momx; + spread->y -= spread->fuse*spread->momy; + spread->z -= spread->fuse*spread->momz; + P_SetThingPosition(spread); + } + mobj->target->z += missile->height*2; + } + mobj->target->z -= (6*missile->height); + } + + P_UnsetThingPosition(missile); + missile->x -= missile->fuse*missile->momx; + missile->y -= missile->fuse*missile->momy; + missile->z -= missile->fuse*missile->momz; + P_SetThingPosition(missile); + + S_StartSound(mobj, sfx_s3kb3); + } + } + + // up... + mobj->z += mobj->height/2; + // Spawn energy particles - for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) { + for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) + { dist = P_AproxDistance(spawner->x - mobj->x, spawner->y - mobj->y); if (P_RandomRange(1,(dist>>FRACBITS)/16) == 1) break; } - if (spawner) { + if (spawner) + { mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER); - if (mobj->health > mobj->info->damage) - missile->momz = FixedDiv(missile->momz, 7*FRACUNIT/5); + if (dist == 0) missile->fuse = 0; else missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy)); + if (missile->fuse > mobj->fuse) P_RemoveMobj(missile); + + if (mobj->health > mobj->info->damage) + { + P_SetScale(missile, FRACUNIT/2); + missile->color = SKINCOLOR_GOLD; // sonic cd electric power + } + else + { + P_SetScale(missile, FRACUNIT/4); + missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power + } + missile->destscale = missile->scale*2; + missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse; + missile->colorized = true; } + + // ...then down. easier than changing the missile's momz after-the-fact + mobj->z -= mobj->height/2; } // Pre-threshold reactiontime stuff for attack phases - if (mobj->reactiontime && mobj->movecount == 3) { + if (mobj->reactiontime && mobj->movecount == 3) + { mobj->reactiontime--; if (mobj->movedir == 0 || mobj->movedir == 2) { // Pausing between bounces in the pinball phase @@ -5555,13 +5670,15 @@ static void P_Boss9Thinker(mobj_t *mobj) } // threshold is used for attacks/maneuvers. - if (mobj->threshold) { + if (mobj->threshold && mobj->movecount != 2) { fixed_t speed = 20*FRACUNIT + FixedMul(40*FRACUNIT, FixedDiv((mobj->info->spawnhealth - mobj->health)<info->spawnhealth<movecount == 3 && mobj->movedir == 1) { - if (!(mobj->threshold&1)) { + if (mobj->movecount == 3 && mobj->movedir == 1) + { + if (!(mobj->threshold & 1)) + { mobj_t *missile; if (mobj->info->seesound) S_StartSound(mobj, mobj->info->seesound); @@ -5573,18 +5690,20 @@ static void P_Boss9Thinker(mobj_t *mobj) A_FaceTarget(mobj); missile = P_SpawnMissile(mobj, mobj->target, mobj->info->speed); - if (mobj->extravalue1 == 2 || mobj->extravalue1 == 3) { + if (mobj->extravalue1 >= 2) + { missile->destscale = FRACUNIT>>1; P_SetScale(missile, missile->destscale); } missile->fuse = 3*TICRATE; missile->z -= missile->height/2; - if (mobj->extravalue1 == 2) { - int i; + if (mobj->extravalue1 == 2) + { + UINT8 i; mobj_t *spread; - missile->flags |= MF_MISSILE; - for (i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) + { if (i == 2) continue; spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); @@ -5593,11 +5712,32 @@ static void P_Boss9Thinker(mobj_t *mobj) spread->momz = missile->momz; spread->destscale = FRACUNIT>>1; P_SetScale(spread, spread->destscale); - spread->fuse = 3*TICRATE; + spread->fuse = missile->fuse; } - missile->flags &= ~MF_MISSILE; + P_InstaThrust(missile,missile->angle,missile->info->speed); } - } else { + else if (mobj->extravalue1 >= 3) + { + UINT8 i; + mobj_t *spread; + mobj->target->z -= (2*missile->height); + for (i = 0; i < 5; i++) + { + if (i != 2) + { + spread = P_SpawnMissile(mobj, mobj->target, missile->type); + spread->destscale = FRACUNIT>>1; + P_SetScale(spread, spread->destscale); + spread->fuse = missile->fuse; + spread->z -= spread->height/2; + } + mobj->target->z += missile->height; + } + mobj->target->z -= (3*missile->height); + } + } + else + { P_SetMobjState(mobj, mobj->state->nextstate); if (mobj->extravalue1 == 3) mobj->reactiontime = TICRATE/8; @@ -5611,7 +5751,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_SpawnGhostMobj(mobj); // Pinball attack! - if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) { + if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) + { if ((statenum_t)(mobj->state-states) != mobj->info->seestate) P_SetMobjState(mobj, mobj->info->seestate); if (mobj->movedir == 0) // mobj health == 1 @@ -5620,7 +5761,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_InstaThrust(mobj, mobj->angle, 22*FRACUNIT); else // mobj health == 2 P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT); - if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) { // Hit a wall? Find a direction to bounce + if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) + { // Hit a wall? Find a direction to bounce mobj->threshold--; P_SetMobjState(mobj, mobj->state->nextstate); if (!mobj->threshold) { // failed bounce! @@ -5633,11 +5775,15 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->movecount = 0; P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION); P_SetMobjState(mobj, mobj->info->meleestate); - } else if (!(mobj->threshold%4)) { // We've decided to lock onto the player this bounce. + } + else if (!(mobj->threshold%4)) + { // We've decided to lock onto the player this bounce. S_StartSound(mobj, sfx_s3k5a); mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx*4, mobj->target->y + mobj->target->momy*4); mobj->reactiontime = TICRATE - 5*(mobj->info->damage - mobj->health); // targetting time - } else { // No homing, just use P_BounceMove + } + else + { // No homing, just use P_BounceMove S_StartSound(mobj, sfx_s3kaa); // make the bounces distinct... P_BounceMove(mobj); mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); @@ -5651,7 +5797,8 @@ static void P_Boss9Thinker(mobj_t *mobj) // Vector form dodge! mobj->angle += mobj->movedir; P_InstaThrust(mobj, mobj->angle, -speed); - while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) { + while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) + { S_StartSound(mobj, sfx_mspogo); P_BounceMove(mobj); mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0); @@ -5708,7 +5855,7 @@ static void P_Boss9Thinker(mobj_t *mobj) if (mobj->flags2 & MF2_FRET) return; - if (mobj->state == &states[mobj->info->raisestate]) + if (mobj->movecount == 1 || mobj->movecount == 2) { // Charging energy if (mobj->momx != 0 || mobj->momy != 0) { // Apply the air breaks if (abs(mobj->momx)+abs(mobj->momy) < FRACUNIT) @@ -5716,11 +5863,13 @@ static void P_Boss9Thinker(mobj_t *mobj) else P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -6*FRACUNIT/8); } - return; + if (mobj->state == states+mobj->info->raisestate) + return; } if (mobj->fuse == 0) { + mobj->flags2 &= ~MF2_INVERTAIMABLE; // It's time to attack! What are we gonna do?! switch(mobj->movecount) { @@ -5728,6 +5877,7 @@ static void P_Boss9Thinker(mobj_t *mobj) default: // Fly up and prepare for an attack! // We have to charge up first, so let's go up into the air + S_StartSound(mobj, sfx_beflap); P_SetMobjState(mobj, mobj->info->raisestate); if (mobj->floorz >= mobj->target->floorz) mobj->watertop = mobj->floorz + 256*FRACUNIT; @@ -5735,33 +5885,69 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->watertop = mobj->target->floorz + 256*FRACUNIT; break; - case 1: { + case 1: // Okay, we're up? Good, time to gather energy... if (mobj->health > mobj->info->damage) { // No more bubble if we're broken (pinch phase) mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); P_SetTarget(&mobj->tracer, shield); P_SetTarget(&shield->target, mobj); + + // Attack 2: Energy shot! + switch (mobj->health) + { + case 8: // shoot once + default: + mobj->extravalue1 = 0; + mobj->threshold = 2; + break; + case 7: // spread shot (vertical) + mobj->extravalue1 = 4; + mobj->threshold = 2; + break; + case 6: // three shots + mobj->extravalue1 = 1; + mobj->threshold = 3*2; + break; + case 5: // spread shot (horizontal) + mobj->extravalue1 = 2; + mobj->threshold = 2; + break; + case 4: // machine gun + mobj->extravalue1 = 3; + mobj->threshold = 5*2; + break; + } } else - P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); + { + mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); + P_SetTarget(&mobj->tracer, shield); + P_SetTarget(&shield->target, mobj); + shield->height -= 20*FRACUNIT; // different offset... + shield->color = SKINCOLOR_MAGENTA; + shield->colorized = true; + P_SetMobjState(shield, S_FIRS1); + //P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); -- why does this happen twice? see case 2... + } mobj->fuse = 4*TICRATE; mobj->flags |= MF_PAIN; if (mobj->info->attacksound) S_StartSound(mobj, mobj->info->attacksound); A_FaceTarget(mobj); + break; - } case 2: // We're all charged and ready now! Unleash the fury!! - if (mobj->health > mobj->info->damage) + S_StopSound(mobj); + mobj_t *removemobj = mobj->tracer; + P_SetTarget(&mobj->tracer, mobj->hnext); + P_RemoveMobj(removemobj); + if (mobj->health <= mobj->info->damage) { - mobj_t *removemobj = mobj->tracer; - P_SetTarget(&mobj->tracer, mobj->hnext); - P_RemoveMobj(removemobj); - } - if (mobj->health <= mobj->info->damage) { + mobj_t *whoosh; + // Attack 1: Pinball dash! if (mobj->health == 1) mobj->movedir = 0; @@ -5776,32 +5962,23 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->threshold = 24; // bounce 24 times mobj->watertop = mobj->target->floorz + 16*FRACUNIT; P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); - } else { + + whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct + whoosh->frame = FF_FULLBRIGHT; + whoosh->sprite = SPR_ARMA; + whoosh->destscale = whoosh->scale<<1; + whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); + whoosh->height = 38*whoosh->scale; + whoosh->fuse = 10; + whoosh->color = SKINCOLOR_MAGENTA; + whoosh->colorized = true; + whoosh->flags |= MF_NOCLIPHEIGHT; + } + else + { // Attack 2: Energy shot! mobj->movedir = 1; - - if (mobj->health >= 8) - mobj->extravalue1 = 0; - else if (mobj->health >= 5) - mobj->extravalue1 = 2; - else if (mobj->health >= 4) - mobj->extravalue1 = 1; - else - mobj->extravalue1 = 3; - - switch(mobj->extravalue1) { - case 0: // shoot once - case 2: // spread-shot - default: - mobj->threshold = 2; - break; - case 1: // shoot 3 times - mobj->threshold = 3*2; - break; - case 3: // shoot like a goddamn machinegun - mobj->threshold = 8*2; - break; - } + // looking for the number of things to fire? that's done in case 1 now } break; @@ -5835,21 +6012,26 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->angle -= InvAngle(angle)/8; //A_FaceTarget(mobj); - // Check if we're being attacked - if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) - goto nodanger; - if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) - goto nodanger; - if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) - goto nodanger; - if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) - goto nodanger; - if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) - goto nodanger; - if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) - goto nodanger; - if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) - goto nodanger; + if (mobj->flags2 & MF2_CLASSICPUSH) + mobj->flags2 &= ~MF2_CLASSICPUSH; // a missile caught us in PIT_CheckThing! + else + { + // Check if we're being attacked + if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) + goto nodanger; + if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) + goto nodanger; + if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) + goto nodanger; + if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) + goto nodanger; + if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) + goto nodanger; + if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) + goto nodanger; + if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) + goto nodanger; + } // An incoming attack is detected! What should we do?! // Go into vector form! @@ -5857,13 +6039,17 @@ static void P_Boss9Thinker(mobj_t *mobj) return; nodanger: + mobj->flags2 |= MF2_INVERTAIMABLE; + // Move normally: Approach the player using normal thrust and simulated friction. dist = P_AproxDistance(mobj->x-mobj->target->x, mobj->y-mobj->target->y); P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -3*FRACUNIT/8); - if (dist < 64*FRACUNIT) + if (dist < 64*FRACUNIT && !(mobj->target->player && mobj->target->player->homing)) P_Thrust(mobj, mobj->angle, -4*FRACUNIT); else if (dist > 180*FRACUNIT) P_Thrust(mobj, mobj->angle, FRACUNIT); + else + P_Thrust(mobj, mobj->angle + ANGLE_90, FINECOSINE((((angle_t)(leveltime*ANG1))>>ANGLETOFINESHIFT) & FINEMASK)>>1); mobj->momz += P_AproxDistance(mobj->momx, mobj->momy)/12; // Move up higher the faster you're going. } } diff --git a/src/p_user.c b/src/p_user.c index ac951a8fa..0d38fd876 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4803,10 +4803,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->mo->momx /= 2; player->mo->momy /= 2; } - else if (player->charability == CA_HOMINGTHOK) + if (player->charability == CA_HOMINGTHOK) { - player->mo->momx /= 3; - player->mo->momy /= 3; + player->mo->momx /= 2; + player->mo->momy /= 2; } if (player->charability == CA_HOMINGTHOK) @@ -7923,7 +7923,7 @@ static void P_MovePlayer(player_t *player) if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super { - // Force shield activation + // Force stop if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) { player->pflags |= PF_THOKKED|PF_SHIELDABILITY; @@ -7939,17 +7939,17 @@ static void P_MovePlayer(player_t *player) if (P_SuperReady(player)) P_DoSuperTransformation(player, false); break; - // Whirlwind/Thundercoin shield activation + // Whirlwind jump/Thunder jump case SH_WHIRLWIND: case SH_THUNDERCOIN: P_DoJumpShield(player); break; - // Armageddon shield activation + // Armageddon pow case SH_ARMAGEDDON: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_BlackOw(player); break; - // Attract shield activation + // Attraction blast case SH_ATTRACT: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; player->homing = 2; @@ -7965,7 +7965,7 @@ static void P_MovePlayer(player_t *player) else S_StartSound(player->mo, sfx_s3ka6); break; - // Elemental/Bubblewrap shield activation + // Elemental stomp/Bubble bounce case SH_ELEMENTAL: case SH_BUBBLEWRAP: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; @@ -7979,7 +7979,7 @@ static void P_MovePlayer(player_t *player) ? sfx_s3k43 : sfx_s3k44); break; - // Flame shield activation + // Flame burst case SH_FLAMEAURA: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); @@ -8000,8 +8000,7 @@ static void P_MovePlayer(player_t *player) { if (player->homing && player->mo->tracer) { - P_HomingAttack(player->mo, player->mo->tracer); - if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET)) + if (!P_HomingAttack(player->mo, player->mo->tracer)) { P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); if (player->mo->eflags & MFE_UNDERWATER) @@ -8020,10 +8019,9 @@ static void P_MovePlayer(player_t *player) if (player->homing && player->mo->tracer) { P_SpawnThokMobj(player); - P_HomingAttack(player->mo, player->mo->tracer); // But if you don't, then stop homing. - if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET)) + if (!P_HomingAttack(player->mo, player->mo->tracer)) { if (player->mo->eflags & MFE_UNDERWATER) P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); @@ -8621,7 +8619,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; // not a mobj thinker mo = (mobj_t *)think; - if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag continue; // not a valid target if (mo->health <= 0) // dead @@ -8633,9 +8631,6 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) if (mo->flags2 & MF2_FRET) continue; - if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) - continue; - if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING)) continue; @@ -8689,17 +8684,23 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) return closestmo; } -void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target +boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target { fixed_t zdist; fixed_t dist; fixed_t ns = 0; if (!enemy) - return; + return false; - if (!(enemy->health)) - return; + if (!enemy->health) + return false; + + if (enemy->flags2 & MF2_FRET) + return false; + + if (!(enemy->flags & (MF_SHOOTABLE|MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + return false; // change angle source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y); @@ -8742,6 +8743,8 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns); source->momz = FixedMul(FixedDiv(zdist, dist), ns); + + return true; } // Search for emeralds diff --git a/src/r_draw.c b/src/r_draw.c index 77bb1b6e7..f8e435624 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -528,12 +528,9 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U || color == SKINCOLOR_NONE) { if (skinnum == TC_ALLWHITE) - memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8**)); + memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8)); else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE) - { - for (i = 0; i < NUM_PALETTE_ENTRIES; i++) - dest_colormap[i] = Color_Index[color-1][3]; - } + memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8)); else { for (i = 0; i < NUM_PALETTE_ENTRIES; i++) diff --git a/src/r_things.c b/src/r_things.c index 9fe1e96e4..155d0f83f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -723,7 +723,7 @@ static void R_DrawVisSprite(vissprite_t *vis) { // translate certain pixels to white colfunc = transcolfunc; - if (vis->mobj->type == MT_CYBRAKDEMON) + if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); diff --git a/src/sounds.c b/src/sounds.c index 52dbee341..aa1c841d6 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -137,7 +137,7 @@ sfxinfo_t S_sfx[NUMSFX] = // Game objects, etc {"appear", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Appearing platform"}, - {"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon explosion"}, + {"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon pow"}, {"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing! {"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing! {"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"}, @@ -304,7 +304,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"}, {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"}, {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"}, - {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"}, + {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder Shield"}, {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"}, {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"}, {"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble bounce"}, From 5cec737985765a825595dc3fe8914183c8f3bb90 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 3 Jul 2019 00:10:22 +0200 Subject: [PATCH 24/34] Remove character-specific flags, replace them with net-only/no-net flags --- src/dehacked.c | 5 ----- src/doomdata.h | 8 +++----- src/p_slopes.c | 10 +++++----- src/p_spec.c | 36 ++++++++++++------------------------ 4 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index d86161390..ac1709cbf 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9573,11 +9573,6 @@ static inline int lib_getenum(lua_State *L) lua_pushinteger(L, ((lua_Integer)1<flags & ML_NOSONIC) + if (line->flags & ML_NETONLY) flags |= SL_NOPHYSICS; - if (line->flags & ML_NOTAILS) + if (line->flags & ML_NONET) flags |= SL_DYNAMIC; if(!frontfloor && !backfloor && !frontceil && !backceil) @@ -468,9 +468,9 @@ static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker) UINT16 tag1, tag2, tag3; UINT8 flags = 0; - if (line->flags & ML_NOSONIC) + if (line->flags & ML_NETONLY) flags |= SL_NOPHYSICS; - if (line->flags & ML_NOTAILS) + if (line->flags & ML_NONET) flags |= SL_DYNAMIC; switch(line->special) @@ -494,7 +494,7 @@ static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker) return; } - if (line->flags & ML_NOKNUX) + if (line->flags & ML_EFFECT6) { tag1 = line->tag; tag2 = side->textureoffset >> FRACBITS; diff --git a/src/p_spec.c b/src/p_spec.c index c6679e190..ae63e53bf 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6322,7 +6322,7 @@ void P_InitSpecials(void) static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs) { - if (!(master->flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set + if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set { sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle; sector->floor_xoffs += xoffs; @@ -6332,7 +6332,7 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata sector->spawn_flr_yoffs = sector->floor_yoffs; } - if (!(master->flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set + if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set { sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle; sector->ceiling_xoffs += xoffs; @@ -6463,28 +6463,22 @@ void P_SpawnSpecials(INT32 fromnetsave) // Init line EFFECTs for (i = 0; i < numlines; i++) { - if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups... + if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment in netgames... { // set line specials to 0 here too, same reason as above if (netgame || multiplayer) { - // future: nonet flag? + if ((lines[i].flags & ML_NONET) == ML_NONET) + { + lines[i].special = 0; + continue; + } } else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) { lines[i].special = 0; continue; } - else - { - if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) - || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) - || (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))) - { - lines[i].special = 0; - continue; - } - } } switch (lines[i].special) @@ -6530,13 +6524,13 @@ void P_SpawnSpecials(INT32 fromnetsave) #endif case 7: // Flat alignment - redone by toast - if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something... + if ((lines[i].flags & (ML_NETONLY|ML_NONET)) != (ML_NETONLY|ML_NONET)) // If you can do something... { angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)); fixed_t xoffs; fixed_t yoffs; - if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set + if (lines[i].flags & ML_EFFECT6) // Set offset through x and y texture offsets if ML_EFFECT6 flag is set { xoffs = sides[lines[i].sidenum[0]].textureoffset; yoffs = sides[lines[i].sidenum[0]].rowoffset; @@ -9194,19 +9188,13 @@ static void P_SearchForDisableLinedefs(void) // that P_InitTagLists literally just created! lines[i].special = 0; - // Ability flags can disable disable linedefs now, lol if (netgame || multiplayer) { - // future: nonet flag? + if ((lines[i].flags & ML_NONET) == ML_NONET) + continue; } else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) continue; // Net-only never triggers in single player - else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) - continue; - else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) - continue; - else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) - continue; // Disable any linedef specials with our tag. for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;) From c04b560e9260ae1f57834cd2e68e3f3bfca19c18 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 2 Jul 2019 23:49:10 +0000 Subject: [PATCH 25/34] Revert "Merge branch 'metalfixes' into 'toast_cleanup'" This reverts merge request !239 --- src/dehacked.c | 5 +- src/hardware/hw_main.c | 2 +- src/hardware/hw_md2.c | 2 +- src/info.c | 27 ++-- src/info.h | 5 +- src/lua_baselib.c | 4 +- src/p_local.h | 2 +- src/p_map.c | 21 --- src/p_mobj.c | 360 ++++++++++------------------------------- src/p_user.c | 45 +++--- src/r_draw.c | 7 +- src/r_things.c | 2 +- src/sounds.c | 4 +- 13 files changed, 135 insertions(+), 351 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 7935c474f..f532bde68 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5125,10 +5125,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_METALSONIC_BADBOUNCE", "S_METALSONIC_SHOOT", "S_METALSONIC_PAIN", - "S_METALSONIC_DEATH1", - "S_METALSONIC_DEATH2", - "S_METALSONIC_DEATH3", - "S_METALSONIC_DEATH4", + "S_METALSONIC_DEATH", "S_METALSONIC_FLEE1", "S_METALSONIC_FLEE2", "S_METALSONIC_FLEE3", diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d649eeb8e..a76c9e1c8 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5662,7 +5662,7 @@ static void HWR_ProjectSprite(mobj_t *thing) //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { - if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) + if (vis->mobj->type == MT_CYBRAKDEMON) vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index e26aa98ff..6db5d5f08 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1363,7 +1363,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) INT32 skinnum = TC_DEFAULT; if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { - if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized) + if (spr->mobj->type == MT_CYBRAKDEMON) skinnum = TC_ALLWHITE; else if (spr->mobj->type == MT_METALSONIC_BATTLE) skinnum = TC_METALSONIC; diff --git a/src/info.c b/src/info.c index a58b2313c..477c3f372 100644 --- a/src/info.c +++ b/src/info.c @@ -1747,23 +1747,20 @@ state_t states[NUMSTATES] = {SPR_METL, 9, 2, {NULL}, 0, 0, S_METALSONIC_RUN1}, // S_METALSONIC_RUN4 {SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT - {SPR_METL, 12|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR - {SPR_METL, 11, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN - {SPR_METL, 13, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE + {SPR_METL, 12, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR + {SPR_METL, 0, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN + {SPR_METL, 13, 40, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER {SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BOUNCE {SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE {SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT {SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN - {SPR_METL, 13, 8, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1 - {SPR_METL, 13, 8, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2 - {SPR_METL, 13, 0, {A_Repeat}, 11, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3 - {SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4 - {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 - {SPR_METL, 11, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 - {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3 - {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4 + {SPR_METL, 11, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH + {SPR_METL, 3, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 + {SPR_METL, 4, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 + {SPR_METL, 5, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3 + {SPR_METL, 4, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2 @@ -6262,13 +6259,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_METALSONIC_DASH, // seestate sfx_s3k54, // seesound 0, // reactiontime - sfx_bechrg, // attacksound + sfx_trpowr, // attacksound S_METALSONIC_PAIN, // painstate S_METALSONIC_VECTOR,// painchance sfx_dmpain, // painsound S_METALSONIC_BADBOUNCE, // meleestate S_METALSONIC_SHOOT, // missilestate - S_METALSONIC_DEATH1,// deathstate + S_METALSONIC_DEATH, // deathstate S_METALSONIC_FLEE1, // xdeathstate sfx_s3k6e, // deathsound MT_ENERGYBALL, // speed @@ -6300,7 +6297,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 32*FRACUNIT, // radius - 52*FRACUNIT, // height + 64*FRACUNIT, // height 0, // display offset 0, // mass 0, // damage @@ -9143,7 +9140,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_ENERGYBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_bexpld, // seesound + sfx_s3k54, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate diff --git a/src/info.h b/src/info.h index c1891a766..a7f5d775a 100644 --- a/src/info.h +++ b/src/info.h @@ -1888,10 +1888,7 @@ typedef enum state S_METALSONIC_BADBOUNCE, S_METALSONIC_SHOOT, S_METALSONIC_PAIN, - S_METALSONIC_DEATH1, - S_METALSONIC_DEATH2, - S_METALSONIC_DEATH3, - S_METALSONIC_DEATH4, + S_METALSONIC_DEATH, S_METALSONIC_FLEE1, S_METALSONIC_FLEE2, S_METALSONIC_FLEE3, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 81a17ef20..e6119cd6c 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1235,8 +1235,8 @@ static int lib_pHomingAttack(lua_State *L) INLEVEL if (!source || !enemy) return LUA_ErrInvalid(L, "mobj_t"); - lua_pushboolean(L, P_HomingAttack(source, enemy)); - return 1; + P_HomingAttack(source, enemy); + return 0; } static int lib_pSuperReady(lua_State *L) diff --git a/src/p_local.h b/src/p_local.h index 479994079..8aeddf162 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -176,7 +176,7 @@ void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move); mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet); void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius); -boolean P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user +void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user boolean P_SuperReady(player_t *player); void P_DoJump(player_t *player, boolean soundandstate); #if 0 diff --git a/src/p_map.c b/src/p_map.c index a852a3933..76b6535b5 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -725,27 +725,6 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - // vectorise metal - done in a special case as at this point neither has the right flags for touching - if (thing->type == MT_METALSONIC_BATTLE - && (tmthing->flags & MF_MISSILE) - && tmthing->target != thing - && thing->state == &states[thing->info->spawnstate]) - { - blockdist = thing->radius + tmthing->radius; - - if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) - return true; // didn't hit it - - if (tmthing->z > thing->z + thing->height) - return true; // overhead - if (tmthing->z + tmthing->height < thing->z) - return true; // underneath - - thing->flags2 |= MF2_CLASSICPUSH; - - return true; - } - if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index ff2bcc77f..70017546c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5395,8 +5395,7 @@ static void P_Boss7Thinker(mobj_t *mobj) if (mobj->info->activesound)\ S_StartSound(mobj, mobj->info->activesound);\ if (mobj->info->painchance)\ - P_SetMobjState(mobj, mobj->info->painchance);\ - mobj->flags2 &= ~MF2_INVERTAIMABLE;\ + P_SetMobjState(mobj, mobj->info->painchance) // Metal Sonic battle boss // You CAN put multiple Metal Sonics in a single map @@ -5486,16 +5485,25 @@ static void P_Boss9Thinker(mobj_t *mobj) // AI goes here. { angle_t angle; - if (mobj->threshold || mobj->movecount) + if (mobj->threshold) mobj->momz = (mobj->watertop-mobj->z)/16; // Float to your desired position FASTER else mobj->momz = (mobj->watertop-mobj->z)/40; // Float to your desired position - if (mobj->movecount == 2) - { + if (mobj->movecount == 2) { mobj_t *spawner; fixed_t dist = 0; - angle = 0x06000000*leveltime; // wtf? + angle = 0x06000000*leveltime; + + // Alter your energy bubble's size/position + if (mobj->health > 3) { + mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); + P_SetScale(mobj->tracer, mobj->tracer->destscale); + P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); + mobj->tracer->momx = mobj->momx; + mobj->tracer->momy = mobj->momy; + mobj->tracer->momz = mobj->momz; + } // Face your target P_BossTargetPlayer(mobj, true); @@ -5506,150 +5514,27 @@ static void P_Boss9Thinker(mobj_t *mobj) else mobj->angle -= InvAngle(angle)/8; - // Alter your energy bubble's size/position - if (mobj->health > 3) - { - mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); - P_SetScale(mobj->tracer, mobj->tracer->destscale); - } - else - mobj->tracer->frame &= ~FF_TRANSMASK; // this causes a flicker but honestly i like it this way - P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); - mobj->tracer->momx = mobj->momx; - mobj->tracer->momy = mobj->momy; - mobj->tracer->momz = mobj->momz; - - // Firin' mah lazors - INDICATOR - if (mobj->fuse > TICRATE/2) - { - tic_t shoottime, worktime, calctime; - shoottime = (TICRATE/((mobj->extravalue1 == 3) ? 8 : 4)); - shoottime += (shoottime>>1); - worktime = shoottime*(mobj->threshold/2); - calctime = mobj->fuse-(TICRATE/2); - - if (calctime <= worktime && (calctime % shoottime == 0)) - { - mobj_t *missile; - - missile = P_SpawnMissile(mobj, mobj->target, MT_MSGATHER); - S_StopSound(missile); - if (mobj->extravalue1 >= 2) - P_SetScale(missile, FRACUNIT>>1); - missile->destscale = missile->scale>>1; - missile->fuse = TICRATE/2; - missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse; - missile->z -= missile->height/2; - missile->momx *= -1; - missile->momy *= -1; - missile->momz *= -1; - - if (mobj->extravalue1 == 2) - { - UINT8 i; - mobj_t *spread; - for (i = 0; i < 5; i++) - { - if (i == 2) - continue; - spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); - spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); - P_InstaThrust(spread,spread->angle,-spread->info->speed); - spread->momz = missile->momz; - P_SetScale(spread, missile->scale); - spread->destscale = missile->destscale; - spread->scalespeed = missile->scalespeed; - spread->fuse = missile->fuse; - P_UnsetThingPosition(spread); - spread->x -= spread->fuse*spread->momx; - spread->y -= spread->fuse*spread->momy; - spread->z -= spread->fuse*spread->momz; - P_SetThingPosition(spread); - } - P_InstaThrust(missile,missile->angle,-missile->info->speed); - } - else if (mobj->extravalue1 >= 3) - { - UINT8 i; - mobj_t *spread; - mobj->target->z -= (4*missile->height); - for (i = 0; i < 5; i++) - { - if (i != 2) - { - spread = P_SpawnMissile(mobj, mobj->target, missile->type); - P_SetScale(spread, missile->scale); - spread->destscale = missile->destscale; - spread->fuse = missile->fuse; - spread->z -= spread->height/2; - spread->momx *= -1; - spread->momy *= -1; - spread->momz *= -1; - P_UnsetThingPosition(spread); - spread->x -= spread->fuse*spread->momx; - spread->y -= spread->fuse*spread->momy; - spread->z -= spread->fuse*spread->momz; - P_SetThingPosition(spread); - } - mobj->target->z += missile->height*2; - } - mobj->target->z -= (6*missile->height); - } - - P_UnsetThingPosition(missile); - missile->x -= missile->fuse*missile->momx; - missile->y -= missile->fuse*missile->momy; - missile->z -= missile->fuse*missile->momz; - P_SetThingPosition(missile); - - S_StartSound(mobj, sfx_s3kb3); - } - } - - // up... - mobj->z += mobj->height/2; - // Spawn energy particles - for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) - { + for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) { dist = P_AproxDistance(spawner->x - mobj->x, spawner->y - mobj->y); if (P_RandomRange(1,(dist>>FRACBITS)/16) == 1) break; } - if (spawner) - { + if (spawner) { mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER); - + if (mobj->health > mobj->info->damage) + missile->momz = FixedDiv(missile->momz, 7*FRACUNIT/5); if (dist == 0) missile->fuse = 0; else missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy)); - if (missile->fuse > mobj->fuse) P_RemoveMobj(missile); - - if (mobj->health > mobj->info->damage) - { - P_SetScale(missile, FRACUNIT/2); - missile->color = SKINCOLOR_GOLD; // sonic cd electric power - } - else - { - P_SetScale(missile, FRACUNIT/4); - missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power - } - missile->destscale = missile->scale*2; - missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse; - missile->colorized = true; } - - // ...then down. easier than changing the missile's momz after-the-fact - mobj->z -= mobj->height/2; } // Pre-threshold reactiontime stuff for attack phases - if (mobj->reactiontime && mobj->movecount == 3) - { + if (mobj->reactiontime && mobj->movecount == 3) { mobj->reactiontime--; if (mobj->movedir == 0 || mobj->movedir == 2) { // Pausing between bounces in the pinball phase @@ -5670,15 +5555,13 @@ static void P_Boss9Thinker(mobj_t *mobj) } // threshold is used for attacks/maneuvers. - if (mobj->threshold && mobj->movecount != 2) { + if (mobj->threshold) { fixed_t speed = 20*FRACUNIT + FixedMul(40*FRACUNIT, FixedDiv((mobj->info->spawnhealth - mobj->health)<info->spawnhealth<movecount == 3 && mobj->movedir == 1) - { - if (!(mobj->threshold & 1)) - { + if (mobj->movecount == 3 && mobj->movedir == 1) { + if (!(mobj->threshold&1)) { mobj_t *missile; if (mobj->info->seesound) S_StartSound(mobj, mobj->info->seesound); @@ -5690,20 +5573,18 @@ static void P_Boss9Thinker(mobj_t *mobj) A_FaceTarget(mobj); missile = P_SpawnMissile(mobj, mobj->target, mobj->info->speed); - if (mobj->extravalue1 >= 2) - { + if (mobj->extravalue1 == 2 || mobj->extravalue1 == 3) { missile->destscale = FRACUNIT>>1; P_SetScale(missile, missile->destscale); } missile->fuse = 3*TICRATE; missile->z -= missile->height/2; - if (mobj->extravalue1 == 2) - { - UINT8 i; + if (mobj->extravalue1 == 2) { + int i; mobj_t *spread; - for (i = 0; i < 5; i++) - { + missile->flags |= MF_MISSILE; + for (i = 0; i < 5; i++) { if (i == 2) continue; spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); @@ -5712,32 +5593,11 @@ static void P_Boss9Thinker(mobj_t *mobj) spread->momz = missile->momz; spread->destscale = FRACUNIT>>1; P_SetScale(spread, spread->destscale); - spread->fuse = missile->fuse; + spread->fuse = 3*TICRATE; } - P_InstaThrust(missile,missile->angle,missile->info->speed); + missile->flags &= ~MF_MISSILE; } - else if (mobj->extravalue1 >= 3) - { - UINT8 i; - mobj_t *spread; - mobj->target->z -= (2*missile->height); - for (i = 0; i < 5; i++) - { - if (i != 2) - { - spread = P_SpawnMissile(mobj, mobj->target, missile->type); - spread->destscale = FRACUNIT>>1; - P_SetScale(spread, spread->destscale); - spread->fuse = missile->fuse; - spread->z -= spread->height/2; - } - mobj->target->z += missile->height; - } - mobj->target->z -= (3*missile->height); - } - } - else - { + } else { P_SetMobjState(mobj, mobj->state->nextstate); if (mobj->extravalue1 == 3) mobj->reactiontime = TICRATE/8; @@ -5751,8 +5611,7 @@ static void P_Boss9Thinker(mobj_t *mobj) P_SpawnGhostMobj(mobj); // Pinball attack! - if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) - { + if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) { if ((statenum_t)(mobj->state-states) != mobj->info->seestate) P_SetMobjState(mobj, mobj->info->seestate); if (mobj->movedir == 0) // mobj health == 1 @@ -5761,8 +5620,7 @@ static void P_Boss9Thinker(mobj_t *mobj) P_InstaThrust(mobj, mobj->angle, 22*FRACUNIT); else // mobj health == 2 P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT); - if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) - { // Hit a wall? Find a direction to bounce + if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) { // Hit a wall? Find a direction to bounce mobj->threshold--; P_SetMobjState(mobj, mobj->state->nextstate); if (!mobj->threshold) { // failed bounce! @@ -5775,15 +5633,11 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->movecount = 0; P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION); P_SetMobjState(mobj, mobj->info->meleestate); - } - else if (!(mobj->threshold%4)) - { // We've decided to lock onto the player this bounce. + } else if (!(mobj->threshold%4)) { // We've decided to lock onto the player this bounce. S_StartSound(mobj, sfx_s3k5a); mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx*4, mobj->target->y + mobj->target->momy*4); mobj->reactiontime = TICRATE - 5*(mobj->info->damage - mobj->health); // targetting time - } - else - { // No homing, just use P_BounceMove + } else { // No homing, just use P_BounceMove S_StartSound(mobj, sfx_s3kaa); // make the bounces distinct... P_BounceMove(mobj); mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); @@ -5797,8 +5651,7 @@ static void P_Boss9Thinker(mobj_t *mobj) // Vector form dodge! mobj->angle += mobj->movedir; P_InstaThrust(mobj, mobj->angle, -speed); - while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) - { + while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) { S_StartSound(mobj, sfx_mspogo); P_BounceMove(mobj); mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0); @@ -5855,7 +5708,7 @@ static void P_Boss9Thinker(mobj_t *mobj) if (mobj->flags2 & MF2_FRET) return; - if (mobj->movecount == 1 || mobj->movecount == 2) + if (mobj->state == &states[mobj->info->raisestate]) { // Charging energy if (mobj->momx != 0 || mobj->momy != 0) { // Apply the air breaks if (abs(mobj->momx)+abs(mobj->momy) < FRACUNIT) @@ -5863,13 +5716,11 @@ static void P_Boss9Thinker(mobj_t *mobj) else P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -6*FRACUNIT/8); } - if (mobj->state == states+mobj->info->raisestate) - return; + return; } if (mobj->fuse == 0) { - mobj->flags2 &= ~MF2_INVERTAIMABLE; // It's time to attack! What are we gonna do?! switch(mobj->movecount) { @@ -5877,7 +5728,6 @@ static void P_Boss9Thinker(mobj_t *mobj) default: // Fly up and prepare for an attack! // We have to charge up first, so let's go up into the air - S_StartSound(mobj, sfx_beflap); P_SetMobjState(mobj, mobj->info->raisestate); if (mobj->floorz >= mobj->target->floorz) mobj->watertop = mobj->floorz + 256*FRACUNIT; @@ -5885,69 +5735,33 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->watertop = mobj->target->floorz + 256*FRACUNIT; break; - case 1: + case 1: { // Okay, we're up? Good, time to gather energy... if (mobj->health > mobj->info->damage) { // No more bubble if we're broken (pinch phase) mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); P_SetTarget(&mobj->tracer, shield); P_SetTarget(&shield->target, mobj); - - // Attack 2: Energy shot! - switch (mobj->health) - { - case 8: // shoot once - default: - mobj->extravalue1 = 0; - mobj->threshold = 2; - break; - case 7: // spread shot (vertical) - mobj->extravalue1 = 4; - mobj->threshold = 2; - break; - case 6: // three shots - mobj->extravalue1 = 1; - mobj->threshold = 3*2; - break; - case 5: // spread shot (horizontal) - mobj->extravalue1 = 2; - mobj->threshold = 2; - break; - case 4: // machine gun - mobj->extravalue1 = 3; - mobj->threshold = 5*2; - break; - } } else - { - mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); - P_SetTarget(&mobj->tracer, shield); - P_SetTarget(&shield->target, mobj); - shield->height -= 20*FRACUNIT; // different offset... - shield->color = SKINCOLOR_MAGENTA; - shield->colorized = true; - P_SetMobjState(shield, S_FIRS1); - //P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); -- why does this happen twice? see case 2... - } + P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); mobj->fuse = 4*TICRATE; mobj->flags |= MF_PAIN; if (mobj->info->attacksound) S_StartSound(mobj, mobj->info->attacksound); A_FaceTarget(mobj); - break; + } case 2: // We're all charged and ready now! Unleash the fury!! - S_StopSound(mobj); - mobj_t *removemobj = mobj->tracer; - P_SetTarget(&mobj->tracer, mobj->hnext); - P_RemoveMobj(removemobj); - if (mobj->health <= mobj->info->damage) + if (mobj->health > mobj->info->damage) { - mobj_t *whoosh; - + mobj_t *removemobj = mobj->tracer; + P_SetTarget(&mobj->tracer, mobj->hnext); + P_RemoveMobj(removemobj); + } + if (mobj->health <= mobj->info->damage) { // Attack 1: Pinball dash! if (mobj->health == 1) mobj->movedir = 0; @@ -5962,23 +5776,32 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->threshold = 24; // bounce 24 times mobj->watertop = mobj->target->floorz + 16*FRACUNIT; P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); - - whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct - whoosh->frame = FF_FULLBRIGHT; - whoosh->sprite = SPR_ARMA; - whoosh->destscale = whoosh->scale<<1; - whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); - whoosh->height = 38*whoosh->scale; - whoosh->fuse = 10; - whoosh->color = SKINCOLOR_MAGENTA; - whoosh->colorized = true; - whoosh->flags |= MF_NOCLIPHEIGHT; - } - else - { + } else { // Attack 2: Energy shot! mobj->movedir = 1; - // looking for the number of things to fire? that's done in case 1 now + + if (mobj->health >= 8) + mobj->extravalue1 = 0; + else if (mobj->health >= 5) + mobj->extravalue1 = 2; + else if (mobj->health >= 4) + mobj->extravalue1 = 1; + else + mobj->extravalue1 = 3; + + switch(mobj->extravalue1) { + case 0: // shoot once + case 2: // spread-shot + default: + mobj->threshold = 2; + break; + case 1: // shoot 3 times + mobj->threshold = 3*2; + break; + case 3: // shoot like a goddamn machinegun + mobj->threshold = 8*2; + break; + } } break; @@ -6012,26 +5835,21 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->angle -= InvAngle(angle)/8; //A_FaceTarget(mobj); - if (mobj->flags2 & MF2_CLASSICPUSH) - mobj->flags2 &= ~MF2_CLASSICPUSH; // a missile caught us in PIT_CheckThing! - else - { - // Check if we're being attacked - if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) - goto nodanger; - if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) - goto nodanger; - if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) - goto nodanger; - if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) - goto nodanger; - if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) - goto nodanger; - if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) - goto nodanger; - if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) - goto nodanger; - } + // Check if we're being attacked + if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) + goto nodanger; + if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) + goto nodanger; + if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) + goto nodanger; + if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) + goto nodanger; + if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) + goto nodanger; + if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) + goto nodanger; + if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) + goto nodanger; // An incoming attack is detected! What should we do?! // Go into vector form! @@ -6039,17 +5857,13 @@ static void P_Boss9Thinker(mobj_t *mobj) return; nodanger: - mobj->flags2 |= MF2_INVERTAIMABLE; - // Move normally: Approach the player using normal thrust and simulated friction. dist = P_AproxDistance(mobj->x-mobj->target->x, mobj->y-mobj->target->y); P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -3*FRACUNIT/8); - if (dist < 64*FRACUNIT && !(mobj->target->player && mobj->target->player->homing)) + if (dist < 64*FRACUNIT) P_Thrust(mobj, mobj->angle, -4*FRACUNIT); else if (dist > 180*FRACUNIT) P_Thrust(mobj, mobj->angle, FRACUNIT); - else - P_Thrust(mobj, mobj->angle + ANGLE_90, FINECOSINE((((angle_t)(leveltime*ANG1))>>ANGLETOFINESHIFT) & FINEMASK)>>1); mobj->momz += P_AproxDistance(mobj->momx, mobj->momy)/12; // Move up higher the faster you're going. } } diff --git a/src/p_user.c b/src/p_user.c index 0d38fd876..ac951a8fa 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4803,10 +4803,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->mo->momx /= 2; player->mo->momy /= 2; } - if (player->charability == CA_HOMINGTHOK) + else if (player->charability == CA_HOMINGTHOK) { - player->mo->momx /= 2; - player->mo->momy /= 2; + player->mo->momx /= 3; + player->mo->momy /= 3; } if (player->charability == CA_HOMINGTHOK) @@ -7923,7 +7923,7 @@ static void P_MovePlayer(player_t *player) if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super { - // Force stop + // Force shield activation if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) { player->pflags |= PF_THOKKED|PF_SHIELDABILITY; @@ -7939,17 +7939,17 @@ static void P_MovePlayer(player_t *player) if (P_SuperReady(player)) P_DoSuperTransformation(player, false); break; - // Whirlwind jump/Thunder jump + // Whirlwind/Thundercoin shield activation case SH_WHIRLWIND: case SH_THUNDERCOIN: P_DoJumpShield(player); break; - // Armageddon pow + // Armageddon shield activation case SH_ARMAGEDDON: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_BlackOw(player); break; - // Attraction blast + // Attract shield activation case SH_ATTRACT: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; player->homing = 2; @@ -7965,7 +7965,7 @@ static void P_MovePlayer(player_t *player) else S_StartSound(player->mo, sfx_s3ka6); break; - // Elemental stomp/Bubble bounce + // Elemental/Bubblewrap shield activation case SH_ELEMENTAL: case SH_BUBBLEWRAP: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; @@ -7979,7 +7979,7 @@ static void P_MovePlayer(player_t *player) ? sfx_s3k43 : sfx_s3k44); break; - // Flame burst + // Flame shield activation case SH_FLAMEAURA: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); @@ -8000,7 +8000,8 @@ static void P_MovePlayer(player_t *player) { if (player->homing && player->mo->tracer) { - if (!P_HomingAttack(player->mo, player->mo->tracer)) + P_HomingAttack(player->mo, player->mo->tracer); + if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET)) { P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); if (player->mo->eflags & MFE_UNDERWATER) @@ -8019,9 +8020,10 @@ static void P_MovePlayer(player_t *player) if (player->homing && player->mo->tracer) { P_SpawnThokMobj(player); + P_HomingAttack(player->mo, player->mo->tracer); // But if you don't, then stop homing. - if (!P_HomingAttack(player->mo, player->mo->tracer)) + if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET)) { if (player->mo->eflags & MFE_UNDERWATER) P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); @@ -8619,7 +8621,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; // not a mobj thinker mo = (mobj_t *)think; - if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag continue; // not a valid target if (mo->health <= 0) // dead @@ -8631,6 +8633,9 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) if (mo->flags2 & MF2_FRET) continue; + if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) + continue; + if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING)) continue; @@ -8684,23 +8689,17 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) return closestmo; } -boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target +void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target { fixed_t zdist; fixed_t dist; fixed_t ns = 0; if (!enemy) - return false; + return; - if (!enemy->health) - return false; - - if (enemy->flags2 & MF2_FRET) - return false; - - if (!(enemy->flags & (MF_SHOOTABLE|MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag - return false; + if (!(enemy->health)) + return; // change angle source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y); @@ -8743,8 +8742,6 @@ boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns); source->momz = FixedMul(FixedDiv(zdist, dist), ns); - - return true; } // Search for emeralds diff --git a/src/r_draw.c b/src/r_draw.c index f8e435624..77bb1b6e7 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -528,9 +528,12 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U || color == SKINCOLOR_NONE) { if (skinnum == TC_ALLWHITE) - memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8)); + memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8**)); else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE) - memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8)); + { + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + dest_colormap[i] = Color_Index[color-1][3]; + } else { for (i = 0; i < NUM_PALETTE_ENTRIES; i++) diff --git a/src/r_things.c b/src/r_things.c index 155d0f83f..9fe1e96e4 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -723,7 +723,7 @@ static void R_DrawVisSprite(vissprite_t *vis) { // translate certain pixels to white colfunc = transcolfunc; - if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) + if (vis->mobj->type == MT_CYBRAKDEMON) dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); diff --git a/src/sounds.c b/src/sounds.c index aa1c841d6..52dbee341 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -137,7 +137,7 @@ sfxinfo_t S_sfx[NUMSFX] = // Game objects, etc {"appear", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Appearing platform"}, - {"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon pow"}, + {"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon explosion"}, {"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing! {"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing! {"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"}, @@ -304,7 +304,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"}, {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"}, {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"}, - {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder Shield"}, + {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"}, {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"}, {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"}, {"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble bounce"}, From 4ad1703ae34d3d76fca1455a365f41edee055f25 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 3 Jul 2019 00:58:02 +0100 Subject: [PATCH 26/34] Revert "Revert "Merge branch 'metalfixes' into 'toast_cleanup'"" This reverts commit c04b560e9260ae1f57834cd2e68e3f3bfca19c18. --- src/dehacked.c | 5 +- src/hardware/hw_main.c | 2 +- src/hardware/hw_md2.c | 2 +- src/info.c | 27 ++-- src/info.h | 5 +- src/lua_baselib.c | 4 +- src/p_local.h | 2 +- src/p_map.c | 21 +++ src/p_mobj.c | 360 +++++++++++++++++++++++++++++++---------- src/p_user.c | 45 +++--- src/r_draw.c | 7 +- src/r_things.c | 2 +- src/sounds.c | 4 +- 13 files changed, 351 insertions(+), 135 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index f532bde68..7935c474f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5125,7 +5125,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_METALSONIC_BADBOUNCE", "S_METALSONIC_SHOOT", "S_METALSONIC_PAIN", - "S_METALSONIC_DEATH", + "S_METALSONIC_DEATH1", + "S_METALSONIC_DEATH2", + "S_METALSONIC_DEATH3", + "S_METALSONIC_DEATH4", "S_METALSONIC_FLEE1", "S_METALSONIC_FLEE2", "S_METALSONIC_FLEE3", diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a76c9e1c8..d649eeb8e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5662,7 +5662,7 @@ static void HWR_ProjectSprite(mobj_t *thing) //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { - if (vis->mobj->type == MT_CYBRAKDEMON) + if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 6db5d5f08..e26aa98ff 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1363,7 +1363,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) INT32 skinnum = TC_DEFAULT; if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" { - if (spr->mobj->type == MT_CYBRAKDEMON) + if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized) skinnum = TC_ALLWHITE; else if (spr->mobj->type == MT_METALSONIC_BATTLE) skinnum = TC_METALSONIC; diff --git a/src/info.c b/src/info.c index 477c3f372..a58b2313c 100644 --- a/src/info.c +++ b/src/info.c @@ -1747,20 +1747,23 @@ state_t states[NUMSTATES] = {SPR_METL, 9, 2, {NULL}, 0, 0, S_METALSONIC_RUN1}, // S_METALSONIC_RUN4 {SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT - {SPR_METL, 12, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR - {SPR_METL, 0, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN - {SPR_METL, 13, 40, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE + {SPR_METL, 12|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR + {SPR_METL, 11, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN + {SPR_METL, 13, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER {SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BOUNCE {SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE {SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT {SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN - {SPR_METL, 11, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH - {SPR_METL, 3, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 - {SPR_METL, 4, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 - {SPR_METL, 5, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3 - {SPR_METL, 4, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4 + {SPR_METL, 13, 8, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1 + {SPR_METL, 13, 8, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2 + {SPR_METL, 13, 0, {A_Repeat}, 11, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3 + {SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4 + {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 + {SPR_METL, 11, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 + {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3 + {SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2 @@ -6259,13 +6262,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_METALSONIC_DASH, // seestate sfx_s3k54, // seesound 0, // reactiontime - sfx_trpowr, // attacksound + sfx_bechrg, // attacksound S_METALSONIC_PAIN, // painstate S_METALSONIC_VECTOR,// painchance sfx_dmpain, // painsound S_METALSONIC_BADBOUNCE, // meleestate S_METALSONIC_SHOOT, // missilestate - S_METALSONIC_DEATH, // deathstate + S_METALSONIC_DEATH1,// deathstate S_METALSONIC_FLEE1, // xdeathstate sfx_s3k6e, // deathsound MT_ENERGYBALL, // speed @@ -6297,7 +6300,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 32*FRACUNIT, // radius - 64*FRACUNIT, // height + 52*FRACUNIT, // height 0, // display offset 0, // mass 0, // damage @@ -9140,7 +9143,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_ENERGYBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_s3k54, // seesound + sfx_bexpld, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate diff --git a/src/info.h b/src/info.h index a7f5d775a..c1891a766 100644 --- a/src/info.h +++ b/src/info.h @@ -1888,7 +1888,10 @@ typedef enum state S_METALSONIC_BADBOUNCE, S_METALSONIC_SHOOT, S_METALSONIC_PAIN, - S_METALSONIC_DEATH, + S_METALSONIC_DEATH1, + S_METALSONIC_DEATH2, + S_METALSONIC_DEATH3, + S_METALSONIC_DEATH4, S_METALSONIC_FLEE1, S_METALSONIC_FLEE2, S_METALSONIC_FLEE3, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index e6119cd6c..81a17ef20 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1235,8 +1235,8 @@ static int lib_pHomingAttack(lua_State *L) INLEVEL if (!source || !enemy) return LUA_ErrInvalid(L, "mobj_t"); - P_HomingAttack(source, enemy); - return 0; + lua_pushboolean(L, P_HomingAttack(source, enemy)); + return 1; } static int lib_pSuperReady(lua_State *L) diff --git a/src/p_local.h b/src/p_local.h index 8aeddf162..479994079 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -176,7 +176,7 @@ void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move); mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet); void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius); -void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user +boolean P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user boolean P_SuperReady(player_t *player); void P_DoJump(player_t *player, boolean soundandstate); #if 0 diff --git a/src/p_map.c b/src/p_map.c index 76b6535b5..a852a3933 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -725,6 +725,27 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + // vectorise metal - done in a special case as at this point neither has the right flags for touching + if (thing->type == MT_METALSONIC_BATTLE + && (tmthing->flags & MF_MISSILE) + && tmthing->target != thing + && thing->state == &states[thing->info->spawnstate]) + { + blockdist = thing->radius + tmthing->radius; + + if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + thing->flags2 |= MF2_CLASSICPUSH; + + return true; + } + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index 70017546c..ff2bcc77f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5395,7 +5395,8 @@ static void P_Boss7Thinker(mobj_t *mobj) if (mobj->info->activesound)\ S_StartSound(mobj, mobj->info->activesound);\ if (mobj->info->painchance)\ - P_SetMobjState(mobj, mobj->info->painchance) + P_SetMobjState(mobj, mobj->info->painchance);\ + mobj->flags2 &= ~MF2_INVERTAIMABLE;\ // Metal Sonic battle boss // You CAN put multiple Metal Sonics in a single map @@ -5485,25 +5486,16 @@ static void P_Boss9Thinker(mobj_t *mobj) // AI goes here. { angle_t angle; - if (mobj->threshold) + if (mobj->threshold || mobj->movecount) mobj->momz = (mobj->watertop-mobj->z)/16; // Float to your desired position FASTER else mobj->momz = (mobj->watertop-mobj->z)/40; // Float to your desired position - if (mobj->movecount == 2) { + if (mobj->movecount == 2) + { mobj_t *spawner; fixed_t dist = 0; - angle = 0x06000000*leveltime; - - // Alter your energy bubble's size/position - if (mobj->health > 3) { - mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); - P_SetScale(mobj->tracer, mobj->tracer->destscale); - P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); - mobj->tracer->momx = mobj->momx; - mobj->tracer->momy = mobj->momy; - mobj->tracer->momz = mobj->momz; - } + angle = 0x06000000*leveltime; // wtf? // Face your target P_BossTargetPlayer(mobj, true); @@ -5514,27 +5506,150 @@ static void P_Boss9Thinker(mobj_t *mobj) else mobj->angle -= InvAngle(angle)/8; + // Alter your energy bubble's size/position + if (mobj->health > 3) + { + mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); + P_SetScale(mobj->tracer, mobj->tracer->destscale); + } + else + mobj->tracer->frame &= ~FF_TRANSMASK; // this causes a flicker but honestly i like it this way + P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); + mobj->tracer->momx = mobj->momx; + mobj->tracer->momy = mobj->momy; + mobj->tracer->momz = mobj->momz; + + // Firin' mah lazors - INDICATOR + if (mobj->fuse > TICRATE/2) + { + tic_t shoottime, worktime, calctime; + shoottime = (TICRATE/((mobj->extravalue1 == 3) ? 8 : 4)); + shoottime += (shoottime>>1); + worktime = shoottime*(mobj->threshold/2); + calctime = mobj->fuse-(TICRATE/2); + + if (calctime <= worktime && (calctime % shoottime == 0)) + { + mobj_t *missile; + + missile = P_SpawnMissile(mobj, mobj->target, MT_MSGATHER); + S_StopSound(missile); + if (mobj->extravalue1 >= 2) + P_SetScale(missile, FRACUNIT>>1); + missile->destscale = missile->scale>>1; + missile->fuse = TICRATE/2; + missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse; + missile->z -= missile->height/2; + missile->momx *= -1; + missile->momy *= -1; + missile->momz *= -1; + + if (mobj->extravalue1 == 2) + { + UINT8 i; + mobj_t *spread; + for (i = 0; i < 5; i++) + { + if (i == 2) + continue; + spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); + spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); + P_InstaThrust(spread,spread->angle,-spread->info->speed); + spread->momz = missile->momz; + P_SetScale(spread, missile->scale); + spread->destscale = missile->destscale; + spread->scalespeed = missile->scalespeed; + spread->fuse = missile->fuse; + P_UnsetThingPosition(spread); + spread->x -= spread->fuse*spread->momx; + spread->y -= spread->fuse*spread->momy; + spread->z -= spread->fuse*spread->momz; + P_SetThingPosition(spread); + } + P_InstaThrust(missile,missile->angle,-missile->info->speed); + } + else if (mobj->extravalue1 >= 3) + { + UINT8 i; + mobj_t *spread; + mobj->target->z -= (4*missile->height); + for (i = 0; i < 5; i++) + { + if (i != 2) + { + spread = P_SpawnMissile(mobj, mobj->target, missile->type); + P_SetScale(spread, missile->scale); + spread->destscale = missile->destscale; + spread->fuse = missile->fuse; + spread->z -= spread->height/2; + spread->momx *= -1; + spread->momy *= -1; + spread->momz *= -1; + P_UnsetThingPosition(spread); + spread->x -= spread->fuse*spread->momx; + spread->y -= spread->fuse*spread->momy; + spread->z -= spread->fuse*spread->momz; + P_SetThingPosition(spread); + } + mobj->target->z += missile->height*2; + } + mobj->target->z -= (6*missile->height); + } + + P_UnsetThingPosition(missile); + missile->x -= missile->fuse*missile->momx; + missile->y -= missile->fuse*missile->momy; + missile->z -= missile->fuse*missile->momz; + P_SetThingPosition(missile); + + S_StartSound(mobj, sfx_s3kb3); + } + } + + // up... + mobj->z += mobj->height/2; + // Spawn energy particles - for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) { + for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) + { dist = P_AproxDistance(spawner->x - mobj->x, spawner->y - mobj->y); if (P_RandomRange(1,(dist>>FRACBITS)/16) == 1) break; } - if (spawner) { + if (spawner) + { mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER); - if (mobj->health > mobj->info->damage) - missile->momz = FixedDiv(missile->momz, 7*FRACUNIT/5); + if (dist == 0) missile->fuse = 0; else missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy)); + if (missile->fuse > mobj->fuse) P_RemoveMobj(missile); + + if (mobj->health > mobj->info->damage) + { + P_SetScale(missile, FRACUNIT/2); + missile->color = SKINCOLOR_GOLD; // sonic cd electric power + } + else + { + P_SetScale(missile, FRACUNIT/4); + missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power + } + missile->destscale = missile->scale*2; + missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse; + missile->colorized = true; } + + // ...then down. easier than changing the missile's momz after-the-fact + mobj->z -= mobj->height/2; } // Pre-threshold reactiontime stuff for attack phases - if (mobj->reactiontime && mobj->movecount == 3) { + if (mobj->reactiontime && mobj->movecount == 3) + { mobj->reactiontime--; if (mobj->movedir == 0 || mobj->movedir == 2) { // Pausing between bounces in the pinball phase @@ -5555,13 +5670,15 @@ static void P_Boss9Thinker(mobj_t *mobj) } // threshold is used for attacks/maneuvers. - if (mobj->threshold) { + if (mobj->threshold && mobj->movecount != 2) { fixed_t speed = 20*FRACUNIT + FixedMul(40*FRACUNIT, FixedDiv((mobj->info->spawnhealth - mobj->health)<info->spawnhealth<movecount == 3 && mobj->movedir == 1) { - if (!(mobj->threshold&1)) { + if (mobj->movecount == 3 && mobj->movedir == 1) + { + if (!(mobj->threshold & 1)) + { mobj_t *missile; if (mobj->info->seesound) S_StartSound(mobj, mobj->info->seesound); @@ -5573,18 +5690,20 @@ static void P_Boss9Thinker(mobj_t *mobj) A_FaceTarget(mobj); missile = P_SpawnMissile(mobj, mobj->target, mobj->info->speed); - if (mobj->extravalue1 == 2 || mobj->extravalue1 == 3) { + if (mobj->extravalue1 >= 2) + { missile->destscale = FRACUNIT>>1; P_SetScale(missile, missile->destscale); } missile->fuse = 3*TICRATE; missile->z -= missile->height/2; - if (mobj->extravalue1 == 2) { - int i; + if (mobj->extravalue1 == 2) + { + UINT8 i; mobj_t *spread; - missile->flags |= MF_MISSILE; - for (i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) + { if (i == 2) continue; spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); @@ -5593,11 +5712,32 @@ static void P_Boss9Thinker(mobj_t *mobj) spread->momz = missile->momz; spread->destscale = FRACUNIT>>1; P_SetScale(spread, spread->destscale); - spread->fuse = 3*TICRATE; + spread->fuse = missile->fuse; } - missile->flags &= ~MF_MISSILE; + P_InstaThrust(missile,missile->angle,missile->info->speed); } - } else { + else if (mobj->extravalue1 >= 3) + { + UINT8 i; + mobj_t *spread; + mobj->target->z -= (2*missile->height); + for (i = 0; i < 5; i++) + { + if (i != 2) + { + spread = P_SpawnMissile(mobj, mobj->target, missile->type); + spread->destscale = FRACUNIT>>1; + P_SetScale(spread, spread->destscale); + spread->fuse = missile->fuse; + spread->z -= spread->height/2; + } + mobj->target->z += missile->height; + } + mobj->target->z -= (3*missile->height); + } + } + else + { P_SetMobjState(mobj, mobj->state->nextstate); if (mobj->extravalue1 == 3) mobj->reactiontime = TICRATE/8; @@ -5611,7 +5751,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_SpawnGhostMobj(mobj); // Pinball attack! - if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) { + if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) + { if ((statenum_t)(mobj->state-states) != mobj->info->seestate) P_SetMobjState(mobj, mobj->info->seestate); if (mobj->movedir == 0) // mobj health == 1 @@ -5620,7 +5761,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_InstaThrust(mobj, mobj->angle, 22*FRACUNIT); else // mobj health == 2 P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT); - if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) { // Hit a wall? Find a direction to bounce + if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) + { // Hit a wall? Find a direction to bounce mobj->threshold--; P_SetMobjState(mobj, mobj->state->nextstate); if (!mobj->threshold) { // failed bounce! @@ -5633,11 +5775,15 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->movecount = 0; P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION); P_SetMobjState(mobj, mobj->info->meleestate); - } else if (!(mobj->threshold%4)) { // We've decided to lock onto the player this bounce. + } + else if (!(mobj->threshold%4)) + { // We've decided to lock onto the player this bounce. S_StartSound(mobj, sfx_s3k5a); mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx*4, mobj->target->y + mobj->target->momy*4); mobj->reactiontime = TICRATE - 5*(mobj->info->damage - mobj->health); // targetting time - } else { // No homing, just use P_BounceMove + } + else + { // No homing, just use P_BounceMove S_StartSound(mobj, sfx_s3kaa); // make the bounces distinct... P_BounceMove(mobj); mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); @@ -5651,7 +5797,8 @@ static void P_Boss9Thinker(mobj_t *mobj) // Vector form dodge! mobj->angle += mobj->movedir; P_InstaThrust(mobj, mobj->angle, -speed); - while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) { + while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) + { S_StartSound(mobj, sfx_mspogo); P_BounceMove(mobj); mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0); @@ -5708,7 +5855,7 @@ static void P_Boss9Thinker(mobj_t *mobj) if (mobj->flags2 & MF2_FRET) return; - if (mobj->state == &states[mobj->info->raisestate]) + if (mobj->movecount == 1 || mobj->movecount == 2) { // Charging energy if (mobj->momx != 0 || mobj->momy != 0) { // Apply the air breaks if (abs(mobj->momx)+abs(mobj->momy) < FRACUNIT) @@ -5716,11 +5863,13 @@ static void P_Boss9Thinker(mobj_t *mobj) else P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -6*FRACUNIT/8); } - return; + if (mobj->state == states+mobj->info->raisestate) + return; } if (mobj->fuse == 0) { + mobj->flags2 &= ~MF2_INVERTAIMABLE; // It's time to attack! What are we gonna do?! switch(mobj->movecount) { @@ -5728,6 +5877,7 @@ static void P_Boss9Thinker(mobj_t *mobj) default: // Fly up and prepare for an attack! // We have to charge up first, so let's go up into the air + S_StartSound(mobj, sfx_beflap); P_SetMobjState(mobj, mobj->info->raisestate); if (mobj->floorz >= mobj->target->floorz) mobj->watertop = mobj->floorz + 256*FRACUNIT; @@ -5735,33 +5885,69 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->watertop = mobj->target->floorz + 256*FRACUNIT; break; - case 1: { + case 1: // Okay, we're up? Good, time to gather energy... if (mobj->health > mobj->info->damage) { // No more bubble if we're broken (pinch phase) mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); P_SetTarget(&mobj->tracer, shield); P_SetTarget(&shield->target, mobj); + + // Attack 2: Energy shot! + switch (mobj->health) + { + case 8: // shoot once + default: + mobj->extravalue1 = 0; + mobj->threshold = 2; + break; + case 7: // spread shot (vertical) + mobj->extravalue1 = 4; + mobj->threshold = 2; + break; + case 6: // three shots + mobj->extravalue1 = 1; + mobj->threshold = 3*2; + break; + case 5: // spread shot (horizontal) + mobj->extravalue1 = 2; + mobj->threshold = 2; + break; + case 4: // machine gun + mobj->extravalue1 = 3; + mobj->threshold = 5*2; + break; + } } else - P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); + { + mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); + P_SetTarget(&mobj->tracer, shield); + P_SetTarget(&shield->target, mobj); + shield->height -= 20*FRACUNIT; // different offset... + shield->color = SKINCOLOR_MAGENTA; + shield->colorized = true; + P_SetMobjState(shield, S_FIRS1); + //P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); -- why does this happen twice? see case 2... + } mobj->fuse = 4*TICRATE; mobj->flags |= MF_PAIN; if (mobj->info->attacksound) S_StartSound(mobj, mobj->info->attacksound); A_FaceTarget(mobj); + break; - } case 2: // We're all charged and ready now! Unleash the fury!! - if (mobj->health > mobj->info->damage) + S_StopSound(mobj); + mobj_t *removemobj = mobj->tracer; + P_SetTarget(&mobj->tracer, mobj->hnext); + P_RemoveMobj(removemobj); + if (mobj->health <= mobj->info->damage) { - mobj_t *removemobj = mobj->tracer; - P_SetTarget(&mobj->tracer, mobj->hnext); - P_RemoveMobj(removemobj); - } - if (mobj->health <= mobj->info->damage) { + mobj_t *whoosh; + // Attack 1: Pinball dash! if (mobj->health == 1) mobj->movedir = 0; @@ -5776,32 +5962,23 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->threshold = 24; // bounce 24 times mobj->watertop = mobj->target->floorz + 16*FRACUNIT; P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); - } else { + + whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct + whoosh->frame = FF_FULLBRIGHT; + whoosh->sprite = SPR_ARMA; + whoosh->destscale = whoosh->scale<<1; + whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); + whoosh->height = 38*whoosh->scale; + whoosh->fuse = 10; + whoosh->color = SKINCOLOR_MAGENTA; + whoosh->colorized = true; + whoosh->flags |= MF_NOCLIPHEIGHT; + } + else + { // Attack 2: Energy shot! mobj->movedir = 1; - - if (mobj->health >= 8) - mobj->extravalue1 = 0; - else if (mobj->health >= 5) - mobj->extravalue1 = 2; - else if (mobj->health >= 4) - mobj->extravalue1 = 1; - else - mobj->extravalue1 = 3; - - switch(mobj->extravalue1) { - case 0: // shoot once - case 2: // spread-shot - default: - mobj->threshold = 2; - break; - case 1: // shoot 3 times - mobj->threshold = 3*2; - break; - case 3: // shoot like a goddamn machinegun - mobj->threshold = 8*2; - break; - } + // looking for the number of things to fire? that's done in case 1 now } break; @@ -5835,21 +6012,26 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->angle -= InvAngle(angle)/8; //A_FaceTarget(mobj); - // Check if we're being attacked - if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) - goto nodanger; - if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) - goto nodanger; - if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) - goto nodanger; - if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) - goto nodanger; - if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) - goto nodanger; - if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) - goto nodanger; - if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) - goto nodanger; + if (mobj->flags2 & MF2_CLASSICPUSH) + mobj->flags2 &= ~MF2_CLASSICPUSH; // a missile caught us in PIT_CheckThing! + else + { + // Check if we're being attacked + if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) + goto nodanger; + if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) + goto nodanger; + if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) + goto nodanger; + if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) + goto nodanger; + if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) + goto nodanger; + if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) + goto nodanger; + if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) + goto nodanger; + } // An incoming attack is detected! What should we do?! // Go into vector form! @@ -5857,13 +6039,17 @@ static void P_Boss9Thinker(mobj_t *mobj) return; nodanger: + mobj->flags2 |= MF2_INVERTAIMABLE; + // Move normally: Approach the player using normal thrust and simulated friction. dist = P_AproxDistance(mobj->x-mobj->target->x, mobj->y-mobj->target->y); P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -3*FRACUNIT/8); - if (dist < 64*FRACUNIT) + if (dist < 64*FRACUNIT && !(mobj->target->player && mobj->target->player->homing)) P_Thrust(mobj, mobj->angle, -4*FRACUNIT); else if (dist > 180*FRACUNIT) P_Thrust(mobj, mobj->angle, FRACUNIT); + else + P_Thrust(mobj, mobj->angle + ANGLE_90, FINECOSINE((((angle_t)(leveltime*ANG1))>>ANGLETOFINESHIFT) & FINEMASK)>>1); mobj->momz += P_AproxDistance(mobj->momx, mobj->momy)/12; // Move up higher the faster you're going. } } diff --git a/src/p_user.c b/src/p_user.c index ac951a8fa..0d38fd876 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4803,10 +4803,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->mo->momx /= 2; player->mo->momy /= 2; } - else if (player->charability == CA_HOMINGTHOK) + if (player->charability == CA_HOMINGTHOK) { - player->mo->momx /= 3; - player->mo->momy /= 3; + player->mo->momx /= 2; + player->mo->momy /= 2; } if (player->charability == CA_HOMINGTHOK) @@ -7923,7 +7923,7 @@ static void P_MovePlayer(player_t *player) if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super { - // Force shield activation + // Force stop if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) { player->pflags |= PF_THOKKED|PF_SHIELDABILITY; @@ -7939,17 +7939,17 @@ static void P_MovePlayer(player_t *player) if (P_SuperReady(player)) P_DoSuperTransformation(player, false); break; - // Whirlwind/Thundercoin shield activation + // Whirlwind jump/Thunder jump case SH_WHIRLWIND: case SH_THUNDERCOIN: P_DoJumpShield(player); break; - // Armageddon shield activation + // Armageddon pow case SH_ARMAGEDDON: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_BlackOw(player); break; - // Attract shield activation + // Attraction blast case SH_ATTRACT: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; player->homing = 2; @@ -7965,7 +7965,7 @@ static void P_MovePlayer(player_t *player) else S_StartSound(player->mo, sfx_s3ka6); break; - // Elemental/Bubblewrap shield activation + // Elemental stomp/Bubble bounce case SH_ELEMENTAL: case SH_BUBBLEWRAP: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; @@ -7979,7 +7979,7 @@ static void P_MovePlayer(player_t *player) ? sfx_s3k43 : sfx_s3k44); break; - // Flame shield activation + // Flame burst case SH_FLAMEAURA: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); @@ -8000,8 +8000,7 @@ static void P_MovePlayer(player_t *player) { if (player->homing && player->mo->tracer) { - P_HomingAttack(player->mo, player->mo->tracer); - if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET)) + if (!P_HomingAttack(player->mo, player->mo->tracer)) { P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); if (player->mo->eflags & MFE_UNDERWATER) @@ -8020,10 +8019,9 @@ static void P_MovePlayer(player_t *player) if (player->homing && player->mo->tracer) { P_SpawnThokMobj(player); - P_HomingAttack(player->mo, player->mo->tracer); // But if you don't, then stop homing. - if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET)) + if (!P_HomingAttack(player->mo, player->mo->tracer)) { if (player->mo->eflags & MFE_UNDERWATER) P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); @@ -8621,7 +8619,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; // not a mobj thinker mo = (mobj_t *)think; - if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag continue; // not a valid target if (mo->health <= 0) // dead @@ -8633,9 +8631,6 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) if (mo->flags2 & MF2_FRET) continue; - if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) - continue; - if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING)) continue; @@ -8689,17 +8684,23 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) return closestmo; } -void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target +boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target { fixed_t zdist; fixed_t dist; fixed_t ns = 0; if (!enemy) - return; + return false; - if (!(enemy->health)) - return; + if (!enemy->health) + return false; + + if (enemy->flags2 & MF2_FRET) + return false; + + if (!(enemy->flags & (MF_SHOOTABLE|MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + return false; // change angle source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y); @@ -8742,6 +8743,8 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns); source->momz = FixedMul(FixedDiv(zdist, dist), ns); + + return true; } // Search for emeralds diff --git a/src/r_draw.c b/src/r_draw.c index 77bb1b6e7..f8e435624 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -528,12 +528,9 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U || color == SKINCOLOR_NONE) { if (skinnum == TC_ALLWHITE) - memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8**)); + memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8)); else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE) - { - for (i = 0; i < NUM_PALETTE_ENTRIES; i++) - dest_colormap[i] = Color_Index[color-1][3]; - } + memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8)); else { for (i = 0; i < NUM_PALETTE_ENTRIES; i++) diff --git a/src/r_things.c b/src/r_things.c index 9fe1e96e4..155d0f83f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -723,7 +723,7 @@ static void R_DrawVisSprite(vissprite_t *vis) { // translate certain pixels to white colfunc = transcolfunc; - if (vis->mobj->type == MT_CYBRAKDEMON) + if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); else if (vis->mobj->type == MT_METALSONIC_BATTLE) dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); diff --git a/src/sounds.c b/src/sounds.c index 52dbee341..aa1c841d6 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -137,7 +137,7 @@ sfxinfo_t S_sfx[NUMSFX] = // Game objects, etc {"appear", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Appearing platform"}, - {"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon explosion"}, + {"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon pow"}, {"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing! {"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing! {"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"}, @@ -304,7 +304,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"}, {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"}, {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"}, - {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"}, + {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder Shield"}, {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"}, {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"}, {"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble bounce"}, From a5074a846be7391fc9bf90f27f5556643e5ac5c3 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 3 Jul 2019 09:19:29 +0200 Subject: [PATCH 27/34] Implemented a skin-based linedef executor trigger --- src/p_setup.c | 6 ++++++ src/p_spec.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index e7dc271a4..7aaad233d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1282,6 +1282,9 @@ static void P_LoadLineDefs2(void) // Compile linedef 'text' from both sidedefs 'text' for appropriate specials. switch(ld->special) { + case 331: // Trigger linedef executor: Skin - Continuous + case 332: // Trigger linedef executor: Skin - Each time + case 333: // Trigger linedef executor: Skin - Once case 443: // Calls a named Lua function if (sides[ld->sidenum[0]].text) { @@ -1492,6 +1495,9 @@ static void P_LoadRawSideDefs2(void *data) break; } + case 331: // Trigger linedef executor: Skin - Continuous + case 332: // Trigger linedef executor: Skin - Each time + case 333: // Trigger linedef executor: Skin - Once case 443: // Calls a named Lua function case 459: // Control text prompt (named tag) { diff --git a/src/p_spec.c b/src/p_spec.c index ae63e53bf..68bdf0c82 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -36,6 +36,7 @@ #include "m_cond.h" //unlock triggers #include "lua_hook.h" // LUAh_LinedefExecute #include "f_finale.h" // control text prompt +#include "r_things.h" // skins #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -2008,7 +2009,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!P_CheckNightsTriggerLine(triggerline, actor)) return false; break; - + case 331: // continuous + case 332: // each time + case 333: // once + if (!(actor && actor->player && ((stricmp(triggerline->text, skins[actor->player->skin].name) == 0) ^ ((triggerline->flags & ML_NOCLIMB) == ML_NOCLIMB)))) + return false; + break; default: break; } @@ -2141,6 +2147,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller || specialtype == 326 // DeNightserize - Once || specialtype == 328 // Nights lap - Once || specialtype == 330 // Nights Bonus Time - Once + || specialtype == 333 // Skin - Once || specialtype == 399) // Level Load triggerline->special = 0; // Clear it out @@ -2181,7 +2188,8 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) || lines[masterline].special == 306 // Character ability - Each time || lines[masterline].special == 310 // CTF Red team - Each time || lines[masterline].special == 312 // CTF Blue team - Each time - || lines[masterline].special == 322) // Trigger on X calls - Each Time + || lines[masterline].special == 322 // Trigger on X calls - Each Time + || lines[masterline].special == 332)// Skin - Each time continue; if (lines[masterline].special < 300 @@ -7169,6 +7177,7 @@ void P_SpawnSpecials(INT32 fromnetsave) case 301: case 310: case 312: + case 332: sec = sides[*lines[i].sidenum].sector - sectors; P_AddEachTimeThinker(§ors[sec], &lines[i]); break; @@ -7217,6 +7226,11 @@ void P_SpawnSpecials(INT32 fromnetsave) case 330: break; + // Skin trigger executors + case 331: + case 333: + break; + case 399: // Linedef execute on map load // This is handled in P_RunLevelLoadExecutors. break; From ec8f64100eef29843c85488faa9bd3983e3955d8 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 6 Jul 2019 00:31:02 -0400 Subject: [PATCH 28/34] Hardcode brick debris --- src/dehacked.c | 2 ++ src/hardware/hw_light.c | 3 +++ src/info.c | 32 ++++++++++++++++++++++++++++++++ src/info.h | 6 ++++++ 4 files changed, 43 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index d86161390..f851f4963 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7167,6 +7167,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ROCKCRUMBLEN", "S_ROCKCRUMBLEO", "S_ROCKCRUMBLEP", + "S_BRICKDEBRIS", #ifdef SEENAMES "S_NAMECHECK", @@ -7881,6 +7882,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_ROCKCRUMBLE14", "MT_ROCKCRUMBLE15", "MT_ROCKCRUMBLE16", + "MT_BRICKDEBRIS", #ifdef SEENAMES "MT_NAMECHECK", diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 949f38064..2feda1f1f 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -580,6 +580,9 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_ROIO &lspr[NOLIGHT], // SPR_ROIP + // Bricks + &lspr[NOLIGHT], // SPR_BRIC + // Gravity Well Objects &lspr[NOLIGHT], // SPR_GWLG &lspr[NOLIGHT], // SPR_GWLR diff --git a/src/info.c b/src/info.c index 074e31ba2..0dee208f8 100644 --- a/src/info.c +++ b/src/info.c @@ -475,6 +475,9 @@ char sprnames[NUMSPRITES + 1][5] = "ROIO", "ROIP", + // Bricks + "BRIC", + // Gravity Well Objects "GWLG", "GWLR", @@ -3861,6 +3864,8 @@ state_t states[NUMSTATES] = {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEO {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEP + {SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS + #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK #endif @@ -19970,6 +19975,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BRICKDEBRIS + -1, // doomednum + S_BRICKDEBRIS, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 255, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + #ifdef SEENAMES { // MT_NAMECHECK -1, // doomednum diff --git a/src/info.h b/src/info.h index 13abfa5f6..75cb00906 100644 --- a/src/info.h +++ b/src/info.h @@ -720,6 +720,9 @@ typedef enum sprite SPR_ROIO, SPR_ROIP, + // Bricks + SPR_BRIC, + // Gravity Well Objects SPR_GWLG, SPR_GWLR, @@ -3923,6 +3926,9 @@ typedef enum state S_ROCKCRUMBLEO, S_ROCKCRUMBLEP, + // Bricks + S_BRICKDEBRIS, + #ifdef SEENAMES S_NAMECHECK, #endif From ef05d81a4c7efcf4bec0eddbc7aa366bc9e8b2d3 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 6 Jul 2019 00:39:36 -0400 Subject: [PATCH 29/34] Change this, not that it really matters but --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 0dee208f8..49f6d4c8f 100644 --- a/src/info.c +++ b/src/info.c @@ -19984,7 +19984,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 255, // painchance + 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate From d2adb5e829cce48fad6952aa4f7ff6784568e224 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 6 Jul 2019 18:11:49 -0400 Subject: [PATCH 30/34] Update info.h Also add a case for MT_BRICKDEBRIS to P_MobjThinker --- src/info.h | 3 +++ src/p_mobj.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/info.h b/src/info.h index 75cb00906..4af76907f 100644 --- a/src/info.h +++ b/src/info.h @@ -4663,6 +4663,9 @@ typedef enum mobj_type MT_ROCKCRUMBLE15, MT_ROCKCRUMBLE16, + // Bricks + MT_BRICKDEBRIS, + #ifdef SEENAMES MT_NAMECHECK, #endif diff --git a/src/p_mobj.c b/src/p_mobj.c index 69550fa73..46f3ef49f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7309,6 +7309,7 @@ void P_MobjThinker(mobj_t *mobj) case MT_ROCKCRUMBLE15: case MT_ROCKCRUMBLE16: case MT_WOODDEBRIS: + case MT_BRICKDEBRIS: if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) && mobj->state != &states[mobj->info->deathstate]) { From a65925aeca428939e03506302ccbda670e090ce7 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 4 Jul 2019 14:43:18 +0100 Subject: [PATCH 31/34] Realised I accidentially broke rain in the rainfixes branch (oh, the irony!), realised it needed a few additional P_RecalcPrecipInSector calls to properly work with the new arena, and increased its speed. If you must, I can cherrypick this into another branch - but it's required for this one, at least. --- src/info.c | 6 ++-- src/p_floor.c | 2 +- src/p_mobj.c | 81 +++++++++++++++++++++++++-------------------------- src/p_spec.c | 4 +++ 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/info.c b/src/info.c index 074e31ba2..8a699f91a 100644 --- a/src/info.c +++ b/src/info.c @@ -3187,8 +3187,8 @@ state_t states[NUMSTATES] = {SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1}, // S_BHORIZ8 // Rain - {SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1 - {SPR_RAIN, FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN + {SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1 + {SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN // Snowflake {SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1 @@ -16113,7 +16113,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - -24*FRACUNIT, // speed + -72*FRACUNIT, // speed 1*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset diff --git a/src/p_floor.c b/src/p_floor.c index 4a03f70c0..ed2afd13d 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -3130,7 +3130,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) // no longer exists (can't collide with again) rover->flags &= ~FF_EXISTS; rover->master->frontsector->moved = true; - sec->moved = true; + P_RecalcPrecipInSector(sec); } // Used for bobbing platforms on the water diff --git a/src/p_mobj.c b/src/p_mobj.c index 69550fa73..187766dcb 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9600,12 +9600,12 @@ consvar_t cv_flagtime = {"flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, void P_SpawnPrecipitation(void) { - INT32 i /*, j*/, mrand; + INT32 i, mrand; fixed_t basex, basey, x, y, height; subsector_t *precipsector = NULL; precipmobj_t *rainmo = NULL; - if (dedicated || /*!cv_precipdensity*/!cv_drawdist_precip.value || curWeather == PRECIP_NONE) + if (dedicated || !(cv_drawdist_precip.value) || curWeather == PRECIP_NONE) return; // Use the blockmap to narrow down our placing patterns @@ -9614,50 +9614,47 @@ void P_SpawnPrecipitation(void) basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE; basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE; - //for (j = 0; j < cv_precipdensity.value; ++j) -- density is 1 for us always + x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); + y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); + + precipsector = R_IsPointInSubsector(x, y); + + // No sector? Stop wasting time, + // move on to the next entry in the blockmap + if (!precipsector) + continue; + + // Exists, but is too small for reasonable precipitation. + if (!(precipsector->sector->floorheight <= precipsector->sector->ceilingheight - (32<sector->ceilingheight; + + if (curWeather == PRECIP_SNOW) { - x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); - y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); - - precipsector = R_IsPointInSubsector(x, y); - - // No sector? Stop wasting time, - // move on to the next entry in the blockmap - if (!precipsector) - break; - - // Exists, but is too small for reasonable precipitation. - if (!(precipsector->sector->floorheight <= precipsector->sector->ceilingheight - (32<sector->ceilingpic != skyflatnum) continue; - // Don't set height yet... - height = precipsector->sector->ceilingheight; - - if (curWeather == PRECIP_SNOW) - { - // Not in a sector with visible sky -- exception for NiGHTS. - if (!(maptol & TOL_NIGHTS) && precipsector->sector->ceilingpic != skyflatnum) - continue; - - rainmo = P_SpawnSnowMobj(x, y, height, MT_SNOWFLAKE); - mrand = M_RandomByte(); - if (mrand < 64) - P_SetPrecipMobjState(rainmo, S_SNOW3); - else if (mrand < 144) - P_SetPrecipMobjState(rainmo, S_SNOW2); - } - else // everything else. - { - // Not in a sector with visible sky. - if (precipsector->sector->ceilingpic != skyflatnum) - continue; - - rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN); - } - - // Randomly assign a height, now that floorz is set. - rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<sector->ceilingpic != skyflatnum) + continue; + + rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN); + } + + // Randomly assign a height, now that floorz is set. + rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<flags != oldflags) + { sec->moved = true; + P_RecalcPrecipInSector(sec); + } } } @@ -7879,6 +7882,7 @@ void T_Disappear(disappear_t *d) } } sectors[s].moved = true; + P_RecalcPrecipInSector(§ors[s]); } if (d->exists) From 4da108748b4823b458104388953f5ea99f800b7d Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 8 Jul 2019 21:17:40 +0100 Subject: [PATCH 32/34] Use M_SetupNextMenu to actually set up the Sound Options menu "properly" instead of the old hacks. If you wanted the game to reset the item selected to the top option like before though, I left a line commented out that would do that for you. Unlike the old item = 0 way, it would automatically be corrected for headers and other spaces (thus kind of future-proofing this code) --- src/m_menu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index cebdd1bbd..dca2e552d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2953,8 +2953,9 @@ boolean M_Responder(event_t *ev) return true; M_StartControlPanel(); M_Options(0); - currentMenu = &OP_SoundOptionsDef; - itemOn = 0; + // Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically. + //OP_SoundOptionsDef.lastOn = 0; + M_SetupNextMenu(&OP_SoundOptionsDef); return true; case KEY_F5: // Video Mode From 5b741d823292d987c7c333bb541acc1af0bc8df4 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 8 Jul 2019 22:56:00 +0200 Subject: [PATCH 33/34] Simplified checks for ML_NETONLY and ML_NONET --- src/p_spec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 68bdf0c82..d67d5e035 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6476,13 +6476,13 @@ void P_SpawnSpecials(INT32 fromnetsave) // set line specials to 0 here too, same reason as above if (netgame || multiplayer) { - if ((lines[i].flags & ML_NONET) == ML_NONET) + if (lines[i].flags & ML_NONET) { lines[i].special = 0; continue; } } - else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) + else if (lines[i].flags & ML_NETONLY) { lines[i].special = 0; continue; @@ -9204,10 +9204,10 @@ static void P_SearchForDisableLinedefs(void) if (netgame || multiplayer) { - if ((lines[i].flags & ML_NONET) == ML_NONET) + if (lines[i].flags & ML_NONET) continue; } - else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) + else if (lines[i].flags & ML_NETONLY) continue; // Net-only never triggers in single player // Disable any linedef specials with our tag. From d3d24bc0bde6f0c1fcd719ac6546ad1fcf22dc94 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 8 Jul 2019 22:58:31 +0200 Subject: [PATCH 34/34] Removed the "disable" linedef effect, since it's useless now that the character flags are gone --- src/p_spec.c | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index d67d5e035..3c81552d8 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -99,7 +99,6 @@ typedef struct thinker_t **thinkers; } thinkerlist_t; -static void P_SearchForDisableLinedefs(void); static void P_SpawnScrollers(void); static void P_SpawnFriction(void); static void P_SpawnPushers(void); @@ -6421,8 +6420,6 @@ void P_SpawnSpecials(INT32 fromnetsave) } } - P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line - P_SpawnScrollers(); // Add generalized scrollers P_SpawnFriction(); // Friction model using linedefs P_SpawnPushers(); // Pusher model using linedefs @@ -6525,12 +6522,6 @@ void P_SpawnSpecials(INT32 fromnetsave) P_AddCameraScanner(§ors[sec], §ors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)); break; -#ifdef PARANOIA - case 6: // Disable tags if level not cleared - I_Error("Failed to catch a disable linedef"); - break; -#endif - case 7: // Flat alignment - redone by toast if ((lines[i].flags & (ML_NETONLY|ML_NONET)) != (ML_NETONLY|ML_NONET)) // If you can do something... { @@ -9185,34 +9176,4 @@ static void P_SpawnPushers(void) Add_Pusher(p_downwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; } -} - -static void P_SearchForDisableLinedefs(void) -{ - size_t i; - INT32 j; - - // Look for disable linedefs - for (i = 0; i < numlines; i++) - { - if (lines[i].special == 6) - { - // Remove special - // Do *not* remove tag. That would mess with the tag lists - // that P_InitTagLists literally just created! - lines[i].special = 0; - - if (netgame || multiplayer) - { - if (lines[i].flags & ML_NONET) - continue; - } - else if (lines[i].flags & ML_NETONLY) - continue; // Net-only never triggers in single player - - // Disable any linedef specials with our tag. - for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;) - lines[j].special = 0; - } - } -} +} \ No newline at end of file