From 93dce12fceda1f2e1d942b0dc04c8050fa10190b Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 25 Jun 2017 20:46:30 +0100 Subject: [PATCH 01/14] Seriously improves the reliability of the linkdraw system (in Software, the only rendering engine which actually does anything with this information), reducing the number of visual errors it produces significantly. Of particular note: Standing in shallow pools of water as Smiles will now reliably associate the bottom half of the tails following mobj with the underwater portion of Smiles' body, and the flicking ends with his un-submerged head. Deliberately engineered to only affect objects with MF2_LINKDRAW applied. --- src/r_things.c | 114 +++++++++++++++++++++++++++++++++++++------------ src/r_things.h | 6 ++- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index d71a7e7a1..ad1ac1362 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1049,6 +1049,8 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) // adjust the heights. newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t)); + newsprite->cut |= (sprite->cut & SC_LINKDRAW); + sprite->cut |= SC_BOTTOM; sprite->gz = testheight; @@ -1109,6 +1111,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) // static void R_ProjectSprite(mobj_t *thing) { + mobj_t *oldthing = thing; fixed_t tr_x, tr_y; fixed_t gxt, gyt; fixed_t tx, tz; @@ -1128,6 +1131,8 @@ static void R_ProjectSprite(mobj_t *thing) vissprite_t *vis; + spritecut_e cut = SC_NONE; + angle_t ang = 0; // compiler complaints fixed_t iscale; fixed_t scalestep; @@ -1326,24 +1331,10 @@ static void R_ProjectSprite(mobj_t *thing) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) { fixed_t linkscale; -#if 0 // support for chains of linkdraw - probably not network safe to modify mobjs during rendering - mobj_t *link, *link2; - for (link = thing->tracer; (link->tracer && (link->flags2 & MF2_LINKDRAW)); link = link->tracer) - link->flags2 &= ~MF2_LINKDRAW; // to prevent infinite loops, otherwise would just be a ; - - for (link2 = thing->tracer; (link2->tracer && (link2 != link)); link2 = link2->tracer) - link->flags2 |= MF2_LINKDRAW; // only needed for correction of the above - - if (link->flags2 & MF2_LINKDRAW) - link->flags2 &= ~MF2_LINKDRAW; // let's try and make sure this doesn't happen again... - - tr_x = link->x - viewx; - tr_y = link->y - viewy; -#else - tr_x = thing->tracer->x - viewx; - tr_y = thing->tracer->y - viewy; -#endif + thing = thing->tracer; + tr_x = thing->x - viewx; + tr_y = thing->y - viewy; gxt = FixedMul(tr_x, viewcos); gyt = -FixedMul(tr_y, viewsin); tz = gxt-gyt; @@ -1356,6 +1347,7 @@ static void R_ProjectSprite(mobj_t *thing) dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0) sortscale = linkscale; // now make sure it's linked + cut = SC_LINKDRAW; } // PORTAL SPRITE CLIPPING @@ -1374,18 +1366,18 @@ static void R_ProjectSprite(mobj_t *thing) // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! - gz = thing->z + thing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale); + gz = oldthing->z + oldthing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale); gzt = gz + FixedMul(spritecachedinfo[lump].height, this_scale); } else { - gzt = thing->z + FixedMul(spritecachedinfo[lump].topoffset, this_scale); + gzt = oldthing->z + FixedMul(spritecachedinfo[lump].topoffset, this_scale); gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale); } if (thing->subsector->sector->cullheight) { - if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) + if (R_DoCulling(oldthing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) return; } @@ -1469,7 +1461,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); - vis->cut = SC_NONE; + vis->cut = cut; if (thing->subsector->sector->numlights) vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap; else @@ -1506,12 +1498,12 @@ static void R_ProjectSprite(mobj_t *thing) // specific translucency if (!cv_translucency.value) ; // no translucency - else if (thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) + else if (oldthing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) vis->transmap = transtables + ((tr_trans80-1)<frame & FF_TRANSMASK) - vis->transmap = transtables + (thing->frame & FF_TRANSMASK) - 0x10000; + else if (oldthing->frame & FF_TRANSMASK) + vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000; - if (((thing->frame & FF_FULLBRIGHT) || (thing->flags2 & MF2_SHADOW)) + if (((oldthing->frame & FF_FULLBRIGHT) || (oldthing->flags2 & MF2_SHADOW)) && (!vis->extra_colormap || !vis->extra_colormap->fog)) { // full bright: goggles @@ -1535,7 +1527,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->isScaled = false; if (thing->subsector->sector->numlights) - R_SplitSprite(vis, thing); + R_SplitSprite(vis, oldthing); // Debug ++objectsdrawn; @@ -1559,7 +1551,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) fixed_t iscale; //SoM: 3/17/2000 - fixed_t gz ,gzt; + fixed_t gz, gzt; // transform the origin point tr_x = thing->x - viewx; @@ -1821,13 +1813,17 @@ void R_SortVisSprites(void) ds->next = dsnext; ds->prev = dsprev; + ds->linkdraw = NULL; } // Fix first and last. ds still points to the last one after the loop dsfirst->prev = &unsorted; unsorted.next = dsfirst; if (ds) + { ds->next = &unsorted; + ds->linkdraw = NULL; + } unsorted.prev = ds; // pull the vissprites out by scale @@ -1857,6 +1853,47 @@ void R_SortVisSprites(void) vsprsortedhead.prev->next = best; vsprsortedhead.prev = best; } + + // bundle linkdraw + for (ds = vsprsortedhead.prev; ds != &vsprsortedhead; ds = ds->prev) + { + if (!(ds->cut & SC_LINKDRAW)) + continue; + + // reuse dsfirst... + for (dsfirst = vsprsortedhead.prev; dsfirst != &vsprsortedhead; dsfirst = dsfirst->prev) + { + // don't connect if it's also a link + if (dsfirst->cut & SC_LINKDRAW) + continue; + + // don't connect if it's not the tracer + if (dsfirst->mobj != ds->mobj) + continue; + + // don't connect if the tracer's top is cut off, but lower than the link's top + if ((dsfirst->cut & SC_TOP) + && dsfirst->szt > ds->szt) + continue; + + // don't connect if the tracer's bottom is cut off, but higher than the link's bottom + if ((dsfirst->cut & SC_BOTTOM) + && dsfirst->sz < ds->sz) + continue; + + break; + } + + // remove from chain + ds->next->prev = ds->prev; + ds->prev->next = ds->next; + + if (dsfirst != &vsprsortedhead) + { + ds->next = dsfirst->linkdraw; + dsfirst->linkdraw = ds; + } + } } // @@ -2453,8 +2490,29 @@ void R_DrawMasked(void) // Tails 08-18-2002 if (r2->sprite->precip == true) R_DrawPrecipitationSprite(r2->sprite); - else + else if (!r2->sprite->linkdraw) R_DrawSprite(r2->sprite); + else // unbundle linkdraw + { + vissprite_t *ds = ds = r2->sprite->linkdraw; + + if (r2->sprite->dispoffset < ds->dispoffset) + { + r2->sprite->next = r2->sprite->linkdraw; + r2->sprite->linkdraw = r2->sprite; + } + else + { + for (; ds->next != NULL; ds = ds->next) + if (r2->sprite->dispoffset < ds->next->dispoffset) + break; + r2->sprite->next = ds->next; + ds->next = r2->sprite; + } + + for (ds = r2->sprite->linkdraw; ds != NULL; ds = ds->next) + R_DrawSprite(ds); + } R_DoneWithNode(r2); r2 = next; diff --git a/src/r_things.h b/src/r_things.h index 3907fd2ae..7db991bd3 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -129,7 +129,8 @@ typedef enum { SC_NONE = 0, SC_TOP = 1, - SC_BOTTOM = 2 + SC_BOTTOM = 2, + SC_LINKDRAW = 4 } spritecut_e; // A vissprite_t is a thing that will be drawn during a refresh, @@ -140,6 +141,9 @@ typedef struct vissprite_s struct vissprite_s *prev; struct vissprite_s *next; + // Bonus Linkdraw pointer. + struct vissprite_s *linkdraw; + mobj_t *mobj; // for easy access INT32 x1, x2; From 59ea08ee111c89c91b6b986a2d9983f2ccfad302 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 26 Jun 2017 14:44:10 +0100 Subject: [PATCH 02/14] * Change the order of operations such that linkdraw sprites aren't ever used for ordering comparisons with non-linkdraw sprites. * Refactor of the unbundling to not involve modifying the next/prev links. * Make the booleans in vissprite_t use flags stored in sprite->cut instead. * Make the linkdrawn sprites much more linked - ie, same brightness (unless independently fullbright), same colormap, and don't draw if the tracer isn't being drawn. * Other minor corrections. --- src/r_things.c | 163 +++++++++++++++++++++++++------------------------ src/r_things.h | 18 ++++-- 2 files changed, 95 insertions(+), 86 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index ad1ac1362..8c8a35276 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -887,12 +887,12 @@ static void R_DrawVisSprite(vissprite_t *vis) this_scale = 1; if (this_scale != FRACUNIT) { - if (!vis->isScaled) + if (!(vis->cut & SC_ISSCALED)) { vis->scale = FixedMul(vis->scale, this_scale); vis->scalestep = FixedMul(vis->scalestep, this_scale); vis->xiscale = FixedDiv(vis->xiscale,this_scale); - vis->isScaled = true; + vis->cut |= SC_ISSCALED; } dc_texturemid = FixedDiv(dc_texturemid,this_scale); } @@ -934,7 +934,7 @@ static void R_DrawVisSprite(vissprite_t *vis) sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); dc_iscale = (0xffffffffu / (unsigned)spryscale); } - if (vis->vflip) + if (vis->cut & SC_VFLIP) R_DrawFlippedMaskedColumn(column, patch->height); else R_DrawMaskedColumn(column); @@ -1013,7 +1013,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) // // R_SplitSprite // runs through a sector's lightlist and -static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) +static void R_SplitSprite(vissprite_t *sprite) { INT32 i, lightnum, lindex; INT16 cutfrac; @@ -1049,7 +1049,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) // adjust the heights. newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t)); - newsprite->cut |= (sprite->cut & SC_LINKDRAW); + newsprite->cut |= (sprite->cut & SC_FLAGMASK); sprite->cut |= SC_BOTTOM; sprite->gz = testheight; @@ -1083,15 +1083,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) newsprite->extra_colormap = sector->lightlist[i].extra_colormap; -/* - if (thing->frame & FF_TRANSMASK) - ; - else if (thing->flags2 & MF2_SHADOW) - ; - else -*/ - if (!((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK) || thing->flags2 & MF2_SHADOW) - && (!newsprite->extra_colormap || !newsprite->extra_colormap->fog))) + if (!(newsprite->cut & SC_FULLBRIGHT)) { lindex = FixedMul(sprite->xscale, FixedDiv(640, vid.width))>>(LIGHTSCALESHIFT); @@ -1333,6 +1325,10 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t linkscale; thing = thing->tracer; + + if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) + return; + tr_x = thing->x - viewx; tr_y = thing->y - viewy; gxt = FixedMul(tr_x, viewcos); @@ -1377,7 +1373,7 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->cullheight) { - if (R_DoCulling(oldthing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) + if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) return; } @@ -1508,6 +1504,7 @@ static void R_ProjectSprite(mobj_t *thing) { // full bright: goggles vis->colormap = colormaps; + vis->cut |= SC_FULLBRIGHT; } else { @@ -1520,14 +1517,11 @@ static void R_ProjectSprite(mobj_t *thing) vis->colormap = spritelights[lindex]; } - vis->precip = false; - - vis->vflip = vflip; - - vis->isScaled = false; + if (vflip) + vis->cut |= SC_VFLIP; if (thing->subsector->sector->numlights) - R_SplitSprite(vis, oldthing); + R_SplitSprite(vis); // Debug ++objectsdrawn; @@ -1688,15 +1682,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->transmap = NULL; vis->mobjflags = 0; - vis->cut = SC_NONE; + vis->cut = SC_PRECIP; vis->extra_colormap = thing->subsector->sector->extra_colormap; vis->heightsec = thing->subsector->sector->heightsec; // Fullbright vis->colormap = colormaps; - vis->precip = true; - vis->vflip = false; - vis->isScaled = false; } // R_AddSprites @@ -1789,7 +1780,7 @@ static vissprite_t vsprsortedhead; void R_SortVisSprites(void) { - UINT32 i; + UINT32 i, linkedvissprites = 0; vissprite_t *ds, *dsprev, *dsnext, *dsfirst; vissprite_t *best = NULL; vissprite_t unsorted; @@ -1826,42 +1817,14 @@ void R_SortVisSprites(void) } unsorted.prev = ds; - // pull the vissprites out by scale - vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; - for (i = 0; i < visspritecount; i++) - { - bestscale = bestdispoffset = INT32_MAX; - for (ds = unsorted.next; ds != &unsorted; ds = ds->next) - { - if (ds->sortscale < bestscale) - { - bestscale = ds->sortscale; - bestdispoffset = ds->dispoffset; - best = ds; - } - // order visprites of same scale by dispoffset, smallest first - else if (ds->sortscale == bestscale && ds->dispoffset < bestdispoffset) - { - bestdispoffset = ds->dispoffset; - best = ds; - } - } - best->next->prev = best->prev; - best->prev->next = best->next; - best->next = &vsprsortedhead; - best->prev = vsprsortedhead.prev; - vsprsortedhead.prev->next = best; - vsprsortedhead.prev = best; - } - // bundle linkdraw - for (ds = vsprsortedhead.prev; ds != &vsprsortedhead; ds = ds->prev) + for (ds = unsorted.prev; ds != &unsorted; ds = ds->prev) { if (!(ds->cut & SC_LINKDRAW)) continue; // reuse dsfirst... - for (dsfirst = vsprsortedhead.prev; dsfirst != &vsprsortedhead; dsfirst = dsfirst->prev) + for (dsfirst = unsorted.prev; dsfirst != &unsorted; dsfirst = dsfirst->prev) { // don't connect if it's also a link if (dsfirst->cut & SC_LINKDRAW) @@ -1881,18 +1844,65 @@ void R_SortVisSprites(void) && dsfirst->sz < ds->sz) continue; + // remove from chain + ds->next->prev = ds->prev; + ds->prev->next = ds->next; + linkedvissprites++; + + if (!(ds->cut & SC_FULLBRIGHT)) + ds->colormap = dsfirst->colormap; + ds->extra_colormap = dsfirst->extra_colormap; + + // reusing dsnext... + dsnext = dsfirst->linkdraw; + + if (!dsnext || ds->dispoffset < dsnext->dispoffset) + { + ds->next = dsnext; + dsfirst->linkdraw = ds; + } + else + { + for (; dsnext->next != NULL; dsnext = dsnext->next) + if (ds->dispoffset < dsnext->next->dispoffset) + break; + ds->next = dsnext->next; + dsnext->next = ds; + } + break; } + } - // remove from chain - ds->next->prev = ds->prev; - ds->prev->next = ds->next; - - if (dsfirst != &vsprsortedhead) + // pull the vissprites out by scale + vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; + for (i = 0; i < visspritecount-linkedvissprites; i++) + { + bestscale = bestdispoffset = INT32_MAX; + for (ds = unsorted.next; ds != &unsorted; ds = ds->next) { - ds->next = dsfirst->linkdraw; - dsfirst->linkdraw = ds; + if (ds->cut & SC_LINKDRAW) + I_Error("No link made!"); // testing + + if (ds->sortscale < bestscale) + { + bestscale = ds->sortscale; + bestdispoffset = ds->dispoffset; + best = ds; + } + // order visprites of same scale by dispoffset, smallest first + else if (ds->sortscale == bestscale && ds->dispoffset < bestdispoffset) + { + bestdispoffset = ds->dispoffset; + best = ds; + } } + best->next->prev = best->prev; + best->prev->next = best->next; + best->next = &vsprsortedhead; + best->prev = vsprsortedhead.prev; + vsprsortedhead.prev->next = best; + vsprsortedhead.prev = best; } } @@ -2267,7 +2277,7 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr) void R_ClipSprites(void) { vissprite_t *spr; - for (;clippedvissprites < visspritecount; clippedvissprites++) + for (; clippedvissprites < visspritecount; clippedvissprites++) { drawseg_t *ds; INT32 x; @@ -2488,29 +2498,22 @@ void R_DrawMasked(void) next = r2->prev; // Tails 08-18-2002 - if (r2->sprite->precip == true) + if (r2->sprite->cut & SC_PRECIP) R_DrawPrecipitationSprite(r2->sprite); else if (!r2->sprite->linkdraw) R_DrawSprite(r2->sprite); else // unbundle linkdraw { - vissprite_t *ds = ds = r2->sprite->linkdraw; + vissprite_t *ds = r2->sprite->linkdraw; - if (r2->sprite->dispoffset < ds->dispoffset) - { - r2->sprite->next = r2->sprite->linkdraw; - r2->sprite->linkdraw = r2->sprite; - } - else - { - for (; ds->next != NULL; ds = ds->next) - if (r2->sprite->dispoffset < ds->next->dispoffset) - break; - r2->sprite->next = ds->next; - ds->next = r2->sprite; - } + for (; + (ds != NULL && r2->sprite->dispoffset > ds->dispoffset); + ds = ds->next) + R_DrawSprite(ds); - for (ds = r2->sprite->linkdraw; ds != NULL; ds = ds->next) + R_DrawSprite(r2->sprite); + + for (; ds != NULL; ds = ds->next) R_DrawSprite(ds); } diff --git a/src/r_things.h b/src/r_things.h index 7db991bd3..c6eed746d 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -127,10 +127,19 @@ typedef struct // ----------- typedef enum { + // actual cuts SC_NONE = 0, SC_TOP = 1, - SC_BOTTOM = 2, - SC_LINKDRAW = 4 + SC_BOTTOM = 1<<1, + // other flags + SC_PRECIP = 1<<2, + SC_LINKDRAW = 1<<3, + SC_FULLBRIGHT = 1<<4, + SC_VFLIP = 1<<5, + SC_ISSCALED = 1>>6, + // masks + SC_CUTMASK = SC_TOP|SC_BOTTOM, + SC_FLAGMASK = ~SC_CUTMASK } spritecut_e; // A vissprite_t is a thing that will be drawn during a refresh, @@ -141,7 +150,7 @@ typedef struct vissprite_s struct vissprite_s *prev; struct vissprite_s *next; - // Bonus Linkdraw pointer. + // Bonus linkdraw pointer. struct vissprite_s *linkdraw; mobj_t *mobj; // for easy access @@ -182,9 +191,6 @@ typedef struct vissprite_s INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; - boolean precip; - boolean vflip; // Flip vertically - boolean isScaled; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing } vissprite_t; From dda9148e5626b504528be07b221a0602321c2836 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 26 Jun 2017 15:53:20 +0100 Subject: [PATCH 03/14] Fix issue with precipitation not modifying its mobj reference, resulting in Smiles' tails disappearing in CEZ3. Also, as a result, safeguard some stuff against referencing stuff that's outside of *precipmobj_t's domain. --- src/r_things.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 8c8a35276..f4deb1711 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -817,7 +817,7 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; - if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" + if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { // translate certain pixels to white colfunc = transcolfunc; @@ -832,7 +832,7 @@ static void R_DrawVisSprite(vissprite_t *vis) { colfunc = transtransfunc; dc_transmap = vis->transmap; - if (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->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); @@ -851,7 +851,7 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = transcolfunc; // New colormap stuff for skins Tails 06-07-2002 - if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! + 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); @@ -881,7 +881,7 @@ static void R_DrawVisSprite(vissprite_t *vis) frac = vis->startfrac; windowtop = windowbottom = sprbotscreen = INT32_MAX; - if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) + if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale); if (this_scale <= 0) this_scale = 1; @@ -1681,6 +1681,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) else vis->transmap = NULL; + vis->mobj = (mobj_t *)thing; vis->mobjflags = 0; vis->cut = SC_PRECIP; vis->extra_colormap = thing->subsector->sector->extra_colormap; @@ -2137,20 +2138,6 @@ static void R_CreateDrawNodes(void) } else if (r2->seg) { -#if 0 //#ifdef POLYOBJECTS_PLANES - if (r2->seg->curline->polyseg && rover->mobj && P_MobjInsidePolyobj(r2->seg->curline->polyseg, rover->mobj)) { - // Determine if we need to sort in front of the polyobj, based on the planes. This fixes the issue where - // polyobject planes render above the object standing on them. (A bit hacky... but it works.) -Red - mobj_t *mo = rover->mobj; - sector_t *po = r2->seg->curline->backsector; - - if (po->ceilingheight < viewz && mo->z+mo->height > po->ceilingheight) - continue; - - if (po->floorheight > viewz && mo->z < po->floorheight) - continue; - } -#endif if (rover->x1 > r2->seg->x2 || rover->x2 < r2->seg->x1) continue; From b2fc2e03ba6ae28fba112b5512d6dfe918f6b5c7 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 26 Jun 2017 16:11:50 +0100 Subject: [PATCH 04/14] * Always remove linkdraw vissprites from unsorted drawing chain. * Make the related I_Error more descriptive and "#define PARANOIA"'d only. --- src/r_things.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index f4deb1711..406cebdef 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1845,11 +1845,16 @@ void R_SortVisSprites(void) && dsfirst->sz < ds->sz) continue; - // remove from chain - ds->next->prev = ds->prev; - ds->prev->next = ds->next; - linkedvissprites++; + break; + } + // remove from chain + ds->next->prev = ds->prev; + ds->prev->next = ds->next; + linkedvissprites++; + + if (dsfirst != &unsorted) + { if (!(ds->cut & SC_FULLBRIGHT)) ds->colormap = dsfirst->colormap; ds->extra_colormap = dsfirst->extra_colormap; @@ -1870,8 +1875,6 @@ void R_SortVisSprites(void) ds->next = dsnext->next; dsnext->next = ds; } - - break; } } @@ -1882,8 +1885,10 @@ void R_SortVisSprites(void) bestscale = bestdispoffset = INT32_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) { +#ifdef PARANOIA if (ds->cut & SC_LINKDRAW) - I_Error("No link made!"); // testing + I_Error("R_SortVisSprites: no link or discardal made for linkdraw!"); +#endif if (ds->sortscale < bestscale) { From fe4dcee9ad3a99e2c18f95d25d7b3bf5b3dc1044 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 26 Jun 2017 16:30:23 +0100 Subject: [PATCH 05/14] fix inaccurate SC_FULLBRIGHT declarations --- src/r_things.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 406cebdef..53dcc3314 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1083,7 +1083,7 @@ static void R_SplitSprite(vissprite_t *sprite) newsprite->extra_colormap = sector->lightlist[i].extra_colormap; - if (!(newsprite->cut & SC_FULLBRIGHT)) + if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !newsprite->extra_colormap->fog))) { lindex = FixedMul(sprite->xscale, FixedDiv(640, vid.width))>>(LIGHTSCALESHIFT); @@ -1499,12 +1499,14 @@ static void R_ProjectSprite(mobj_t *thing) else if (oldthing->frame & FF_TRANSMASK) vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000; - if (((oldthing->frame & FF_FULLBRIGHT) || (oldthing->flags2 & MF2_SHADOW)) + if ((oldthing->frame & FF_FULLBRIGHT) || (oldthing->flags2 & MF2_SHADOW)) + vis->cut |= SC_FULLBRIGHT; + + if (vis->cut & SC_FULLBRIGHT && (!vis->extra_colormap || !vis->extra_colormap->fog)) { // full bright: goggles vis->colormap = colormaps; - vis->cut |= SC_FULLBRIGHT; } else { From 66d59efddcf8070270bce0603e11853c6ca1500d Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 17 Jul 2017 23:58:54 +0100 Subject: [PATCH 06/14] Sorry, MI. More info in forthcoming merge request. --- src/info.c | 10 +++++----- src/p_mobj.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/info.c b/src/info.c index 4f1a76c73..30f6c082d 100644 --- a/src/info.c +++ b/src/info.c @@ -5992,7 +5992,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_WALLSPIKE 522, // doomednum - S_WALLSPIKE1, // spawnstate + S_WALLSPIKE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -6005,9 +6005,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate - sfx_None, // deathsound + sfx_None, // deathsound 2*TICRATE, // speed - 32*FRACUNIT, // radius + 16*FRACUNIT, // radius 14*FRACUNIT, // height 0, // display offset 4, // mass @@ -6019,7 +6019,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_WALLSPIKEBASE -1, // doomednum - S_WALLSPIKEBASE, // spawnstate + S_WALLSPIKEBASE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -6034,7 +6034,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 7*FRACUNIT, // radius + FRACUNIT/4, // radius 14*FRACUNIT, // height 0, // display offset 4, // mass diff --git a/src/p_mobj.c b/src/p_mobj.c index 2bb370f50..c6847df30 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10146,7 +10146,7 @@ ML_NOCLIMB : Direction not controllable // spawn base { const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so... - const fixed_t baseradius = mobj->radius/2 - FixedMul(FRACUNIT, mobj->scale); + const fixed_t baseradius = mobj->radius - FixedMul(mobjinfo[MT_WALLSPIKEBASE].radius, mobj->scale); mobj_t *base = P_SpawnMobj( mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), From 6d43fad0986b72a5df3c63bcf434e6b03cbe250b Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 18 Jul 2017 12:56:39 +0100 Subject: [PATCH 07/14] Correct the baseradius stuff. (Still doing some other work, though - will let you know when the branch is safe to review.) --- src/info.c | 2 +- src/p_mobj.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/info.c b/src/info.c index 30f6c082d..66e1b64cf 100644 --- a/src/info.c +++ b/src/info.c @@ -6034,7 +6034,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - FRACUNIT/4, // radius + 7*FRACUNIT, // radius 14*FRACUNIT, // height 0, // display offset 4, // mass diff --git a/src/p_mobj.c b/src/p_mobj.c index c6847df30..ddb36afa5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7379,16 +7379,18 @@ void P_MobjThinker(mobj_t *mobj) return; } mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); +#if 0 if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle { mobj_t *target = mobj->target; // shortcut - const fixed_t baseradius = target->radius/2 - FixedMul(FRACUNIT, target->scale); + const fixed_t baseradius = target->radius - (target->scale/4); //FixedMul(FRACUNIT/4, target->scale); P_UnsetThingPosition(mobj); mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); P_SetThingPosition(mobj); mobj->angle = target->angle + ANGLE_90; } +#endif break; case MT_FALLINGROCK: // Despawn rocks here in case zmovement code can't do so (blame slopes) @@ -10146,7 +10148,7 @@ ML_NOCLIMB : Direction not controllable // spawn base { const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so... - const fixed_t baseradius = mobj->radius - FixedMul(mobjinfo[MT_WALLSPIKEBASE].radius, mobj->scale); + const fixed_t baseradius = mobj->radius - (mobj->scale/4); //FixedMul(FRACUNIT/4, mobj->scale); mobj_t *base = P_SpawnMobj( mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), From a5477737d79dce77c3f04eb75cfd27e6710730d6 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 18 Jul 2017 14:17:10 +0100 Subject: [PATCH 08/14] Whooh boy. Probably requires re-review. * Support for MF_PAPERCOLLISION tmhitthing in P_SlideMove. * Knockback for wallspikes is much more consistent. * Optimised away a FixedDiv call when determining the slopetype of a line. * Changed the position of the wallspike base slightly. * Made it so NOTHING can step up onto the player outside of other players, essentially killing a bunch of springs-launch-with-players style bugs. (I was able to recreate that issue with the wallspikes until I added this, which is why I did it in this branch.) --- src/p_map.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++--- src/p_mobj.c | 4 +-- src/p_polyobj.c | 2 +- src/p_setup.c | 2 +- src/p_user.c | 5 ++- 5 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index e1f204a8c..b4fecd614 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -971,15 +971,15 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->z + thing->height > bottomz // above bottom && thing->z < topz) // below top - { // don't check angle, the player was clearly in the way in this case + // don't check angle, the player was clearly in the way in this case P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); - } } else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tmthing->player) { fixed_t bottomz, topz; bottomz = thing->z; topz = thing->z + thing->height; + if (thing->eflags & MFE_VERTICALFLIP) bottomz -= FixedMul(FRACUNIT, thing->scale); else @@ -1151,12 +1151,14 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE)) + if (!(tmthing->player) && (thing->player)) + ; // no solid thing should ever be able to step up onto a player + else if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE)) { if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now... return false; // "cancel" P_TryMove via blocking so you keep your current position } - else if (tmthing->flags & MF_SPRING && (thing->player || thing->flags & MF_PUSHABLE)) + else if (tmthing->flags & MF_SPRING && (thing->flags & MF_PUSHABLE)) ; // Fix a few nasty spring-jumping bugs that happen sometimes. // Monitors are not treated as solid to players who are jumping, spinning or gliding, // unless it's a CTF team monitor and you're on the wrong team @@ -3092,6 +3094,7 @@ void P_SlideMove(mobj_t *mo) fixed_t leadx, leady, trailx, traily, newx, newy; INT16 hitcount = 0; boolean success = false; + boolean papercol = false; if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) { @@ -3099,6 +3102,80 @@ void P_SlideMove(mobj_t *mo) if (tmhitthing->flags & MF_PUSHABLE) return; + if (tmhitthing->flags & MF_PAPERCOLLISION) + { + fixed_t cosradius, sinradius; + vertex_t v1, v2; // fake vertexes + line_t junk; // fake linedef - does this need to be static? toast does not know + + fixed_t num, den; + + // trace along the three leading corners + if (mo->momx > 0) + { + leadx = mo->x + mo->radius; + trailx = mo->x - mo->radius; + } + else + { + leadx = mo->x - mo->radius; + trailx = mo->x + mo->radius; + } + + if (mo->momy > 0) + { + leady = mo->y + mo->radius; + traily = mo->y - mo->radius; + } + else + { + leady = mo->y - mo->radius; + traily = mo->y + mo->radius; + } + + papercol = true; + slidemo = mo; + bestslideline = &junk; + + cosradius = FixedMul(tmhitthing->radius, FINECOSINE(tmhitthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmhitthing->radius, FINESINE(tmhitthing->angle>>ANGLETOFINESHIFT)); + + v1.x = tmhitthing->x - cosradius; + v1.y = tmhitthing->y - sinradius; + v2.x = tmhitthing->x + cosradius; + v2.y = tmhitthing->y + sinradius; + + junk.v1 = &v1; + junk.v2 = &v2; + junk.dx = 2*cosradius; // v2.x - v1.x; + junk.dy = 2*sinradius; // v2.y - v1.y; + + junk.slopetype = !cosradius ? ST_VERTICAL : !sinradius ? ST_HORIZONTAL : + ((sinradius > 0) == (cosradius > 0)) ? ST_POSITIVE : ST_NEGATIVE; + + bestslidefrac = FRACUNIT+1; + + den = FixedMul(junk.dy>>8, mo->momx) - FixedMul(junk.dx>>8, mo->momy); + + if (!den) + bestslidefrac = 0; + else + { + fixed_t frac; +#define P_PaperTraverse(startx, starty) \ + num = FixedMul((v1.x - leadx)>>8, junk.dy) + FixedMul((leady - v1.y)>>8, junk.dx); \ + frac = FixedDiv(num, den); \ + if (frac < bestslidefrac) \ + bestslidefrac = frac + P_PaperTraverse(leadx, leady); + P_PaperTraverse(trailx, leady); + P_PaperTraverse(leadx, traily); +#undef dowork + } + + goto papercollision; + } + // Thankfully box collisions are a lot simpler than arbitrary lines. There's only four possible cases. if (mo->y + mo->radius <= tmhitthing->y - tmhitthing->radius) { @@ -3129,7 +3206,7 @@ void P_SlideMove(mobj_t *mo) bestslideline = NULL; retry: - if (++hitcount == 3) + if ((++hitcount == 3) || papercol) goto stairstep; // don't loop forever // trace along the three leading corners @@ -3171,6 +3248,7 @@ retry: return; } +papercollision: // move up to the wall if (bestslidefrac == FRACUNIT+1) { diff --git a/src/p_mobj.c b/src/p_mobj.c index ddb36afa5..1bb6a2f01 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7383,7 +7383,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle { mobj_t *target = mobj->target; // shortcut - const fixed_t baseradius = target->radius - (target->scale/4); //FixedMul(FRACUNIT/4, target->scale); + const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); P_UnsetThingPosition(mobj); mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); @@ -10148,7 +10148,7 @@ ML_NOCLIMB : Direction not controllable // spawn base { const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so... - const fixed_t baseradius = mobj->radius - (mobj->scale/4); //FixedMul(FRACUNIT/4, mobj->scale); + const fixed_t baseradius = mobj->radius - (mobj->scale/2); //FixedMul(FRACUNIT/2, mobj->scale); mobj_t *base = P_SpawnMobj( mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 7776ab19a..fd3237c9d 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1237,7 +1237,7 @@ static void Polyobj_rotateLine(line_t *ld) // determine slopetype ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL : - FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE; + ((ld->dy > 0) == (ld->dx > 0)) ? ST_POSITIVE : ST_NEGATIVE; // update bounding box if (v1->x < v2->x) diff --git a/src/p_setup.c b/src/p_setup.c index 4f11c10d0..217f087cd 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1212,7 +1212,7 @@ static void P_LoadLineDefs(lumpnum_t lumpnum) ld->slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; - else if (FixedDiv(ld->dy, ld->dx) > 0) + else if ((ld->dy > 0) == (ld->dx > 0)) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; diff --git a/src/p_user.c b/src/p_user.c index 9ae79e5e2..58593eca1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -821,7 +821,10 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) if (inflictor) { - ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy); + if (inflictor->type == MT_WALLSPIKE) + ang = inflictor->angle; + else + ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy); // explosion and rail rings send you farther back, making it more difficult // to recover From d1be22ccf5b6aeabb0acf9a5de67309f6d58d166 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 18 Jul 2017 14:17:10 +0100 Subject: [PATCH 09/14] * Scope tweakin's to prevent having to make some stuff static. * Make wallspikes intangible if you're being thrust away from them in pain. --- src/p_map.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index b4fecd614..20b36fea6 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -990,10 +990,15 @@ static boolean PIT_CheckThing(mobj_t *thing) && !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer { // use base as a reference point to determine what angle you touched the spike at angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); - angle_t diffangle = thing->angle - touchangle; - if (diffangle > ANGLE_180) - diffangle = InvAngle(diffangle); - if (diffangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked! + + if (P_PlayerInPain(tmthing->player) + && (R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle) > ANGLE_180) + return true; + + touchangle = thing->angle - touchangle; + if (touchangle > ANGLE_180) + touchangle = InvAngle(touchangle); + if (touchangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked! P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); } } @@ -3094,7 +3099,10 @@ void P_SlideMove(mobj_t *mo) fixed_t leadx, leady, trailx, traily, newx, newy; INT16 hitcount = 0; boolean success = false; + boolean papercol = false; + vertex_t v1, v2; // fake vertexes + line_t junk; // fake linedef if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) { @@ -3104,11 +3112,7 @@ void P_SlideMove(mobj_t *mo) if (tmhitthing->flags & MF_PAPERCOLLISION) { - fixed_t cosradius, sinradius; - vertex_t v1, v2; // fake vertexes - line_t junk; // fake linedef - does this need to be static? toast does not know - - fixed_t num, den; + fixed_t cosradius, sinradius, num, den; // trace along the three leading corners if (mo->momx > 0) From 2330f1a9c9eddd24af3c72e6796221ebb3668e4b Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 18 Jul 2017 14:17:10 +0100 Subject: [PATCH 10/14] Account for the fact that pointtoangle2 points due weast if there's no dy OR dx, so that's taken care of. --- src/p_map.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_map.c b/src/p_map.c index 20b36fea6..7ea19a249 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -992,6 +992,7 @@ static boolean PIT_CheckThing(mobj_t *thing) angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); if (P_PlayerInPain(tmthing->player) + && (tmthing->momx || tmthing->momy) && (R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle) > ANGLE_180) return true; From ef4dc42c7cba52ce8eac5eec52a90e2377b1e5e5 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 18 Jul 2017 14:17:10 +0100 Subject: [PATCH 11/14] * Bustable wallspikes. * Improve the code for busting vertical spikes. * Improve the frame arrangement for vertical spikes' spriteset. (Requires new patch.dta) * Make all spikes consistently do damage with DMG_SPIKE. * (unrelated) renamed "flame stomp" to "elemental stomp" in P_HitDeathMessages --- src/dehacked.c | 2 + src/info.c | 20 +++-- src/info.h | 2 + src/p_inter.c | 230 ++++++++++++++++++++++++++++++++----------------- src/p_map.c | 31 ++++--- src/p_mobj.c | 5 +- 6 files changed, 188 insertions(+), 102 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 1279d7bd0..3db12d4c0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4681,6 +4681,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_WALLSPIKE5", "S_WALLSPIKE6", "S_WALLSPIKEBASE", + "S_WALLSPIKED1", + "S_WALLSPIKED2", // Starpost "S_STARPOST_IDLE", diff --git a/src/info.c b/src/info.c index 66e1b64cf..191c8ae91 100644 --- a/src/info.c +++ b/src/info.c @@ -1563,13 +1563,13 @@ state_t states[NUMSTATES] = // Floor Spike {SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended - {SPR_USPK, 5, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2 - {SPR_USPK, 4, 2, {NULL}, 0, 0, S_SPIKE4}, // S_SPIKE3 + {SPR_USPK, 1, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2 + {SPR_USPK, 2, 2, {NULL}, 0, 0, S_SPIKE4}, // S_SPIKE3 {SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5}, // S_SPIKE4 -- Fully retracted - {SPR_USPK, 4, 2, {A_Pain}, 0, 0, S_SPIKE6}, // S_SPIKE5 - {SPR_USPK, 5, 2, {NULL}, 0, 0, S_SPIKE1}, // S_SPIKE6 - {SPR_USPK, 1,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles - {SPR_USPK, 2,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2 + {SPR_USPK, 2, 2, {A_Pain}, 0, 0, S_SPIKE6}, // S_SPIKE5 + {SPR_USPK, 1, 2, {NULL}, 0, 0, S_SPIKE1}, // S_SPIKE6 + {SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles + {SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2 // Wall Spike {SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2}, // S_WALLSPIKE1 -- Fully extended @@ -1579,6 +1579,8 @@ state_t states[NUMSTATES] = {SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain}, 0, 0, S_WALLSPIKE6}, // S_WALLSPIKE5 {SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_WALLSPIKE1}, // S_WALLSPIKE6 {SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKEBASE -- Base + {SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED1 -- Busted spike particles + {SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED2 // Starpost {SPR_STPT, 0 , -1, {NULL}, 0, 0, S_NULL}, // S_STARPOST_IDLE @@ -6003,9 +6005,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_s3k64, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound + S_WALLSPIKED1, // deathstate + S_WALLSPIKED2, // xdeathstate + sfx_mspogo, // deathsound 2*TICRATE, // speed 16*FRACUNIT, // radius 14*FRACUNIT, // height diff --git a/src/info.h b/src/info.h index 42fd63dff..735530667 100644 --- a/src/info.h +++ b/src/info.h @@ -1784,6 +1784,8 @@ typedef enum state S_WALLSPIKE5, S_WALLSPIKE6, S_WALLSPIKEBASE, + S_WALLSPIKED1, + S_WALLSPIKED2, // Starpost S_STARPOST_IDLE, diff --git a/src/p_inter.c b/src/p_inter.c index 33ca1eeb5..730fd207b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1665,7 +1665,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour if (damagetype == DMG_NUKE) // SH_ARMAGEDDON, armageddon shield str = M_GetText("%s%s's armageddon blast %s %s.\n"); else if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && (inflictor->player->pflags & PF_SHIELDABILITY)) - str = M_GetText("%s%s's flame stomp %s %s.\n"); + str = M_GetText("%s%s's elemental stomp %s %s.\n"); else if (inflictor->player->powers[pw_invulnerability]) str = M_GetText("%s%s's invincibility aura %s %s.\n"); else if (inflictor->player->powers[pw_super]) @@ -1719,6 +1719,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n"); break; case MT_SPIKE: + case MT_WALLSPIKE: str = M_GetText("%s was %s by spikes.\n"); break; default: @@ -2395,7 +2396,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget else { P_SetObjectMomZ(target, 14*FRACUNIT, false); - if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // Spikes + if (damagetype == DMG_SPIKE) // Spikes S_StartSound(target, sfx_spkdth); else P_PlayDeathSound(target); @@ -2457,90 +2458,159 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } } - if (target->type == MT_SPIKE && inflictor && target->info->deathstate != S_NULL) + if (target->type == MT_SPIKE && target->info->deathstate != S_NULL) { - const fixed_t x=target->x,y=target->y,z=target->z; - const fixed_t scale=target->scale; - const boolean flip=(target->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP; - S_StartSound(target,target->info->deathsound); + const angle_t ang = ((inflictor) ? inflictor->angle : 0) + ANGLE_90; + const fixed_t scale = target->scale; + const fixed_t xoffs = P_ReturnThrustX(target, ang, 8*scale), yoffs = P_ReturnThrustY(target, ang, 8*scale); + const UINT16 flip = (target->eflags & MFE_VERTICALFLIP); + mobj_t *chunk; + fixed_t momz; - P_SetMobjState(target, target->info->deathstate); - target->health = 0; - target->angle = inflictor->angle + ANGLE_90; - P_UnsetThingPosition(target); - target->flags = MF_NOCLIP; - target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - if (flip) - target->z -= FixedMul(12*FRACUNIT, target->scale); - else - target->z += FixedMul(12*FRACUNIT, target->scale); - P_SetThingPosition(target); - P_InstaThrust(target,target->angle,FixedMul(2*FRACUNIT, target->scale)); - target->momz = FixedMul(7*FRACUNIT, target->scale); - if (flip) - target->momz = -target->momz; - - if (flip) - { - target = P_SpawnMobj(x,y,z-FixedMul(12*FRACUNIT, target->scale),MT_SPIKE); - target->eflags |= MFE_VERTICALFLIP; - } - else - target = P_SpawnMobj(x,y,z+FixedMul(12*FRACUNIT, target->scale),MT_SPIKE); - P_SetMobjState(target, target->info->deathstate); - target->health = 0; - target->angle = inflictor->angle - ANGLE_90; - target->destscale = scale; - P_SetScale(target, scale); - P_UnsetThingPosition(target); - target->flags = MF_NOCLIP; - target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - P_SetThingPosition(target); - P_InstaThrust(target,target->angle,FixedMul(2*FRACUNIT, target->scale)); - target->momz = FixedMul(7*FRACUNIT, target->scale); - if (flip) - target->momz = -target->momz; + S_StartSound(target, target->info->deathsound); if (target->info->xdeathstate != S_NULL) { - target = P_SpawnMobj(x,y,z,MT_SPIKE); + momz = 6*scale; if (flip) - target->eflags |= MFE_VERTICALFLIP; - P_SetMobjState(target, target->info->xdeathstate); - target->health = 0; - target->angle = inflictor->angle + ANGLE_90; - target->destscale = scale; - P_SetScale(target, scale); - P_UnsetThingPosition(target); - target->flags = MF_NOCLIP; - target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - P_SetThingPosition(target); - P_InstaThrust(target,target->angle,FixedMul(4*FRACUNIT, target->scale)); - target->momz = FixedMul(6*FRACUNIT, target->scale); - if (flip) - target->momz = -target->momz; + momz *= -1; +#define makechunk(angtweak, xmov, ymov) \ + chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);\ + chunk->eflags |= flip;\ + P_SetMobjState(chunk, target->info->xdeathstate);\ + chunk->health = 0;\ + chunk->angle = angtweak;\ + chunk->destscale = scale;\ + P_SetScale(chunk, scale);\ + P_UnsetThingPosition(chunk);\ + chunk->flags = MF_NOCLIP;\ + chunk->x += xmov;\ + chunk->y += ymov;\ + P_SetThingPosition(chunk);\ + P_InstaThrust(chunk,chunk->angle, 4*scale);\ + chunk->momz = momz - target = P_SpawnMobj(x,y,z,MT_SPIKE); - if (flip) - target->eflags |= MFE_VERTICALFLIP; - P_SetMobjState(target, target->info->xdeathstate); - target->health = 0; - target->angle = inflictor->angle - ANGLE_90; - target->destscale = scale; - P_SetScale(target, scale); - P_UnsetThingPosition(target); - target->flags = MF_NOCLIP; - target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale)); - P_SetThingPosition(target); - P_InstaThrust(target,target->angle,FixedMul(4*FRACUNIT, target->scale)); - target->momz = FixedMul(6*FRACUNIT, target->scale); - if (flip) - target->momz = -target->momz; + makechunk(ang + ANGLE_180, -xoffs, -yoffs); + makechunk(ang, xoffs, yoffs); + +#undef makechunk } + + momz = 7*scale; + if (flip) + momz *= -1; + + chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE); + chunk->eflags |= flip; + + P_SetMobjState(chunk, target->info->deathstate); + chunk->health = 0; + chunk->angle = ang + ANGLE_180; + chunk->destscale = scale; + P_SetScale(chunk, scale); + P_UnsetThingPosition(chunk); + chunk->flags = MF_NOCLIP; + chunk->x -= xoffs; + chunk->y -= yoffs; + if (flip) + chunk->z -= 12*scale; + else + chunk->z += 12*scale; + P_SetThingPosition(chunk); + P_InstaThrust(chunk, chunk->angle, 2*scale); + chunk->momz = momz; + + P_SetMobjState(target, target->info->deathstate); + target->health = 0; + target->angle = ang; + P_UnsetThingPosition(target); + target->flags = MF_NOCLIP; + target->x += xoffs; + target->y += yoffs; + target->z = chunk->z; + P_SetThingPosition(target); + P_InstaThrust(target, target->angle, 2*scale); + target->momz = momz; + } + else if (target->type == MT_WALLSPIKE && target->info->deathstate != S_NULL) + { + const angle_t ang = (/*(inflictor) ? inflictor->angle : */target->angle) + ANGLE_90; + const fixed_t scale = target->scale; + const fixed_t xoffs = P_ReturnThrustX(target, ang, 8*scale), yoffs = P_ReturnThrustY(target, ang, 8*scale), forwardxoffs = P_ReturnThrustX(target, target->angle, 7*scale), forwardyoffs = P_ReturnThrustY(target, target->angle, 7*scale); + const UINT16 flip = (target->eflags & MFE_VERTICALFLIP); + mobj_t *chunk; + boolean sprflip; + + S_StartSound(target, target->info->deathsound); + if (!P_MobjWasRemoved(target->tracer)) + P_RemoveMobj(target->tracer); + + if (target->info->xdeathstate != S_NULL) + { + sprflip = P_RandomChance(FRACUNIT/2); + +#define makechunk(angtweak, xmov, ymov) \ + chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);\ + chunk->eflags |= flip;\ + P_SetMobjState(chunk, target->info->xdeathstate);\ + chunk->health = 0;\ + chunk->angle = target->angle;\ + chunk->destscale = scale;\ + P_SetScale(chunk, scale);\ + P_UnsetThingPosition(chunk);\ + chunk->flags = MF_NOCLIP;\ + chunk->x += xmov - forwardxoffs;\ + chunk->y += ymov - forwardyoffs;\ + P_SetThingPosition(chunk);\ + P_InstaThrust(chunk, angtweak, 4*scale);\ + chunk->momz = P_RandomRange(5, 7)*scale;\ + if (flip)\ + chunk->momz *= -1;\ + if (sprflip)\ + chunk->frame |= FF_VERTICALFLIP + + makechunk(ang + ANGLE_180, -xoffs, -yoffs); + sprflip = !sprflip; + makechunk(ang, xoffs, yoffs); + +#undef makechunk + } + + sprflip = P_RandomChance(FRACUNIT/2); + + chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE); + chunk->eflags |= flip; + + P_SetMobjState(chunk, target->info->deathstate); + chunk->health = 0; + chunk->angle = target->angle; + chunk->destscale = scale; + P_SetScale(chunk, scale); + P_UnsetThingPosition(chunk); + chunk->flags = MF_NOCLIP; + chunk->x += forwardxoffs - xoffs; + chunk->y += forwardyoffs - yoffs; + P_SetThingPosition(chunk); + P_InstaThrust(chunk, ang + ANGLE_180, 2*scale); + chunk->momz = P_RandomRange(5, 7)*scale; + if (flip) + chunk->momz *= -1; + if (sprflip) + chunk->frame |= FF_VERTICALFLIP; + + P_SetMobjState(target, target->info->deathstate); + target->health = 0; + P_UnsetThingPosition(target); + target->flags = MF_NOCLIP; + target->x += forwardxoffs + xoffs; + target->y += forwardyoffs + yoffs; + P_SetThingPosition(target); + P_InstaThrust(target, ang, 2*scale); + target->momz = P_RandomRange(5, 7)*scale; + if (flip) + target->momz *= -1; + if (!sprflip) + target->frame |= FF_VERTICALFLIP; } else if (target->player) { @@ -2876,7 +2946,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes + if (damagetype == DMG_SPIKE) // spikes S_StartSound(player->mo, sfx_spkdth); else S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss. @@ -2905,7 +2975,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes + if (damagetype == DMG_SPIKE) // spikes S_StartSound(player->mo, sfx_spkdth); if (source && source->player && !player->powers[pw_super]) //don't score points against super players diff --git a/src/p_map.c b/src/p_map.c index 7ea19a249..665ebd204 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -439,7 +439,9 @@ static boolean PIT_CheckThing(mobj_t *thing) // Metal Sonic destroys tiny baby objects. if (tmthing->type == MT_METALSONIC_RACE - && (thing->flags & (MF_MISSILE|MF_ENEMY|MF_BOSS) || thing->type == MT_SPIKE)) + && (thing->flags & (MF_MISSILE|MF_ENEMY|MF_BOSS) + || (thing->type == MT_SPIKE + || thing->type == MT_WALLSPIKE))) { if ((thing->flags & (MF_ENEMY|MF_BOSS)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE))) return true; @@ -451,12 +453,14 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // overhead if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (thing->type == MT_SPIKE) + if (thing->type == MT_SPIKE + || thing->type == MT_WALLSPIKE) { + mobjtype_t type = thing->type; if (thing->flags & MF_SOLID) S_StartSound(tmthing, thing->info->deathsound); for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) - if (thing->type == MT_SPIKE && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < FixedMul(56*FRACUNIT, thing->scale)) + if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale)) P_KillMobj(thing, tmthing, tmthing, 0); } else @@ -470,10 +474,13 @@ static boolean PIT_CheckThing(mobj_t *thing) // SF_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes. if ((tmthing->player) && (((tmthing->player->charflags & SF_DASHMODE) && (tmthing->player->dashmode >= 3*TICRATE) - && (thing->flags & (MF_MONITOR) || thing->type == MT_SPIKE)) + && (thing->flags & (MF_MONITOR) + || (thing->type == MT_SPIKE + || thing->type == MT_WALLSPIKE))) || ((((tmthing->player->charability == CA_TWINSPIN) && (tmthing->player->panim == PA_ABILITY)) || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)) - && (thing->type == MT_SPIKE)))) + && (thing->type == MT_SPIKE + || thing->type == MT_WALLSPIKE)))) { if ((thing->flags & (MF_MONITOR)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE))) return true; @@ -485,12 +492,14 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // overhead if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (thing->type == MT_SPIKE) + if (thing->type == MT_SPIKE + || thing->type == MT_WALLSPIKE) { + mobjtype_t type = thing->type; if (thing->flags & MF_SOLID) S_StartSound(tmthing, thing->info->deathsound); for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) - if (thing->type == MT_SPIKE && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < FixedMul(56*FRACUNIT, thing->scale)) + if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale)) P_KillMobj(thing, tmthing, tmthing, 0); } else @@ -937,12 +946,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz && !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && thing->eflags & MFE_VERTICALFLIP)) - P_DamageMobj(thing, tmthing, tmthing, 1, 0); + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); } else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz && !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && !(thing->eflags & MFE_VERTICALFLIP))) - P_DamageMobj(thing, tmthing, tmthing, 1, 0); + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); } else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?! { @@ -951,12 +960,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale) && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && tmthing->eflags & MFE_VERTICALFLIP)) - P_DamageMobj(tmthing, thing, thing, 1, 0); + P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); } else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && !(tmthing->eflags & MFE_VERTICALFLIP))) - P_DamageMobj(tmthing, thing, thing, 1, 0); + P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE); } if (tmthing->type == MT_WALLSPIKE && tmthing->flags & MF_SOLID && thing->player) // wall spike impales player diff --git a/src/p_mobj.c b/src/p_mobj.c index 1bb6a2f01..f01cd4383 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2739,8 +2739,9 @@ static boolean P_ZMovement(mobj_t *mo) return true; break; case MT_SPIKE: + case MT_WALLSPIKE: // Dead spike particles disappear upon ground contact - if ((mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz) && mo->health <= 0) + if (!mo->health && (mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz)) { P_RemoveMobj(mo); return false; @@ -10148,7 +10149,7 @@ ML_NOCLIMB : Direction not controllable // spawn base { const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so... - const fixed_t baseradius = mobj->radius - (mobj->scale/2); //FixedMul(FRACUNIT/2, mobj->scale); + const fixed_t baseradius = mobj->radius - mobj->scale; mobj_t *base = P_SpawnMobj( mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), From b2e92e7a099b741e9a4270d8753cca878d2270e4 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 18 Jul 2017 14:17:10 +0100 Subject: [PATCH 12/14] * Invert solidity flag for vertical spikes and wallspikes. * (unrelated) Per a request by sphere, make the ambush flag stop sounds being made by the gas jet. --- src/p_enemy.c | 19 +++++++++++-------- src/p_mobj.c | 8 ++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 4b8d14170..08c6eb306 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4110,15 +4110,18 @@ void A_SetSolidSteam(mobj_t *actor) #endif actor->flags &= ~MF_NOCLIP; actor->flags |= MF_SOLID; - if (P_RandomChance(FRACUNIT/8)) + if (!(actor->flags2 & MF2_AMBUSH)) { - if (actor->info->deathsound) - S_StartSound(actor, actor->info->deathsound); // Hiss! - } - else - { - if (actor->info->painsound) - S_StartSound(actor, actor->info->painsound); + if (P_RandomChance(FRACUNIT/8)) + { + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); // Hiss! + } + else + { + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); + } } P_SetObjectMomZ (actor, 1, true); diff --git a/src/p_mobj.c b/src/p_mobj.c index f01cd4383..f8d1a4239 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10120,8 +10120,8 @@ ML_NOCLIMB : Direction not controllable mobj->flags &= ~MF_SCENERY; mobj->fuse = mthing->angle + mobj->info->speed; } - // Use per-thing collision for spikes if the deaf flag is checked. - if (mthing->options & MTF_AMBUSH && !metalrecording) + // Use per-thing collision for spikes if the deaf flag isn't checked. + if (!(mthing->options & MTF_AMBUSH) && !metalrecording) { P_UnsetThingPosition(mobj); mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT); @@ -10137,8 +10137,8 @@ ML_NOCLIMB : Direction not controllable mobj->flags &= ~MF_SCENERY; mobj->fuse = mobj->info->speed; } - // Use per-thing collision for spikes if the deaf flag is checked. - if (mthing->options & MTF_AMBUSH && !metalrecording) + // Use per-thing collision for spikes if the deaf flag isn't checked. + if (!(mthing->options & MTF_AMBUSH) && !metalrecording) { P_UnsetThingPosition(mobj); mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIPHEIGHT); From 1e1d191a757c5703e4c6a3f9a890c1e7c7b65ff9 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 30 Jul 2017 16:52:39 +0100 Subject: [PATCH 13/14] Make it so you can't even STAND on spikes if you're flashing and moving away from them. --- src/p_map.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 665ebd204..209df088c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -986,6 +986,13 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tmthing->player) { fixed_t bottomz, topz; + angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); + + if (P_PlayerInPain(tmthing->player) + && (tmthing->momx || tmthing->momy) + && (R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle) > ANGLE_180) + return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. + bottomz = thing->z; topz = thing->z + thing->height; @@ -998,13 +1005,6 @@ static boolean PIT_CheckThing(mobj_t *thing) && tmthing->z < topz // below top && !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer { // use base as a reference point to determine what angle you touched the spike at - angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); - - if (P_PlayerInPain(tmthing->player) - && (tmthing->momx || tmthing->momy) - && (R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle) > ANGLE_180) - return true; - touchangle = thing->angle - touchangle; if (touchangle > ANGLE_180) touchangle = InvAngle(touchangle); From 021e7ed1f0b0eb94420554fb6ec7243eadc32cf4 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 30 Jul 2017 17:45:27 +0100 Subject: [PATCH 14/14] Okay, actually fixed. Thanks, MI, for understanding the maths a little better than I :p --- src/p_map.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 209df088c..d4d8796a2 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -988,10 +988,14 @@ static boolean PIT_CheckThing(mobj_t *thing) fixed_t bottomz, topz; angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); - if (P_PlayerInPain(tmthing->player) - && (tmthing->momx || tmthing->momy) - && (R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle) > ANGLE_180) - return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. + if (P_PlayerInPain(tmthing->player) && (tmthing->momx || tmthing->momy)) + { + angle_t playerangle = R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle; + if (playerangle > ANGLE_180) + playerangle = InvAngle(playerangle); + if (playerangle < ANGLE_90) + return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. + } bottomz = thing->z; topz = thing->z + thing->height;