diff --git a/src/doomdata.h b/src/doomdata.h index 767e47383..f42b13889 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -215,4 +215,11 @@ typedef struct #define NUMMAPS 1035 +/* slope thing types */ +enum +{ + FLOOR_SLOPE_THING = 777, + CEILING_SLOPE_THING = 778, +}; + #endif // __DOOMDATA__ diff --git a/src/p_mobj.c b/src/p_mobj.c index d58772f5c..c309b6a4f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12072,6 +12072,8 @@ void P_SpawnMapThing(mapthing_t *mthing) else if (mthing->type == 750) // Slope vertex point (formerly chaos spawn) return; + else if (mthing->type == 777 || mthing->type == 778) // Slope anchors + return; else if (mthing->type == 300 // Ring || mthing->type == 308 || mthing->type == 309 // Team Rings diff --git a/src/p_setup.c b/src/p_setup.c index c2af9b3b2..6b92a405f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3206,19 +3206,24 @@ boolean P_SetupLevel(boolean skipprecip) // anything that P_ResetDynamicSlopes/P_LoadThings needs to know P_InitSpecials(); + // set up world state + // jart: needs to be done here so anchored slopes know the attached list + P_SpawnSpecials(fromnetsave); + P_ResetDynamicSlopes(); P_LoadThings(); + P_RaiseThings(); + + P_SpawnSpecialsThatRequireObjects(); + P_SpawnSecretItems(loademblems); for (numcoopstarts = 0; numcoopstarts < MAXPLAYERS; numcoopstarts++) if (!playerstarts[numcoopstarts]) break; - // set up world state - P_SpawnSpecials(fromnetsave); - K_AdjustWaypointsParameters(); if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) diff --git a/src/p_slopes.c b/src/p_slopes.c index d90b583c5..2102dd7b2 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -24,6 +24,9 @@ #include "w_wad.h" #include "k_kart.h" // K_PlayerEBrake +static void P_BuildSlopeAnchorList (void); +static void P_SetupAnchoredSlopes (void); + static pslope_t *slopelist = NULL; static UINT16 slopecount = 0; @@ -731,6 +734,14 @@ void P_ResetDynamicSlopes(void) { } } + // jart + + /// Build list of slope anchors--faster searching. + P_BuildSlopeAnchorList(); + + /// Setup anchor based slopes. + P_SetupAnchoredSlopes(); + /// Copies slopes from tagged sectors via line specials. /// \note Doesn't actually copy, but instead they share the same pointers. for (i = 0; i < numlines; i++) @@ -920,5 +931,8 @@ void P_ButteredSlope(mobj_t *mo) P_Thrust(mo, mo->standingslope->xydirection, thrust); } +// jart +#include "slope_anchors.c" + // EOF #endif // #ifdef ESLOPE diff --git a/src/p_spec.c b/src/p_spec.c index 4c86714eb..84b4a7dd1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5358,6 +5358,26 @@ P_RaiseTaggedThingsToFakeFloor ( } } +void +P_RaiseThings (void) +{ + size_t i; + + for (i = 0; i < numlines; ++i) + { + switch (lines[i].special) + { + case 80: // Raise tagged things by type to this FOF + P_RaiseTaggedThingsToFakeFloor( + ( sides[lines[i].sidenum[0]].textureoffset >> FRACBITS ), + lines[i].tag, + lines[i].frontsector + ); + break; + } + } +} + // // SPECIAL SPAWNING // @@ -6822,28 +6842,19 @@ void P_SpawnSpecials(INT32 fromnetsave) } } - /* some things have to be done after FOF spawn */ - - for (i = 0; i < numlines; ++i) - { - switch (lines[i].special) - { - case 80: // Raise tagged things by type to this FOF - P_RaiseTaggedThingsToFakeFloor( - ( sides[lines[i].sidenum[0]].textureoffset >> FRACBITS ), - lines[i].tag, - lines[i].frontsector - ); - break; - } - } - // Allocate each list for (i = 0; i < numsectors; i++) if(secthinkers[i].thinkers) Z_Free(secthinkers[i].thinkers); Z_Free(secthinkers); +} + +/** Fuck polyobjects + */ +void P_SpawnSpecialsThatRequireObjects(void) +{ + size_t i; // haleyjd 02/20/06: spawn polyobjects Polyobj_InitLevel(); diff --git a/src/p_spec.h b/src/p_spec.h index 6c918ef11..24bbfadd9 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -38,6 +38,8 @@ void P_SetupLevelFlatAnims(void); // at map load void P_InitSpecials(void); void P_SpawnSpecials(INT32 fromnetsave); +void P_RaiseThings(void); +void P_SpawnSpecialsThatRequireObjects(void); // every tic void P_UpdateSpecials(void); @@ -461,4 +463,12 @@ void P_CalcHeight(player_t *player); sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo); +/* line specials */ +enum +{ + LT_SLOPE_ANCHORS_FLOOR = 777, + LT_SLOPE_ANCHORS_CEILING = 778, + LT_SLOPE_ANCHORS = 779, +}; + #endif diff --git a/src/slope_anchors.c b/src/slope_anchors.c new file mode 100644 index 000000000..d66c9d9dd --- /dev/null +++ b/src/slope_anchors.c @@ -0,0 +1,491 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \brief Charyb's vertex slope anchors. +/// This file is self contained to avoid a Big Large merge conflict. + +/* +FIXME +FIXME +FIXME +FIXME WHEN 2.2 MERGE IS OVER, REFACTOR A LOT OF THE CODE IN P_SLOPES.C AND +FIXME MAKE THIS NOT REDUNDANT. +FIXME +FIXME +FIXME +*/ + +struct anchor_list +{ + mapthing_t ** anchors; + const vertex_t ** points; + fixed_t * closeness; + size_t count; +}; + +struct anchor_list floor_anchors; +struct anchor_list ceiling_anchors; + +static void * new_list (size_t n) { + return Z_Malloc(n, PU_LEVEL, NULL); +} + +static void make_new_anchor_list (struct anchor_list * list) { + list->anchors = new_list(list->count * sizeof *list->anchors); + list->points = new_list(list->count * sizeof *list->points); + list->closeness = new_list(list->count * sizeof *list->closeness); +} + +static void allocate_anchors (void) { + size_t i; + + floor_anchors.count = 0; + ceiling_anchors.count = 0; + + for (i = 0; i < nummapthings; ++i) + { + switch (mapthings[i].type) + { + case FLOOR_SLOPE_THING: + floor_anchors.count++; + break; + + case CEILING_SLOPE_THING: + ceiling_anchors.count++; + break; + } + } + + make_new_anchor_list(&floor_anchors); + make_new_anchor_list(&ceiling_anchors); +} + +static void +compare_vertex_distance +( + const vertex_t ** nearest, + fixed_t * nearest_distance, + const fixed_t origin_x, + const fixed_t origin_y, + const vertex_t * v +){ + const fixed_t distance = abs(P_AproxDistance + ( + origin_x - v->x, + origin_y - v->y + )); + + if (distance < (*nearest_distance)) + { + (*nearest) = v; + (*nearest_distance) = distance; + } +} + +static const vertex_t * +nearest_point +( + fixed_t * closeness, + mapthing_t * a, + const sector_t * sector +){ + const fixed_t x = a->x << FRACBITS; + const fixed_t y = a->y << FRACBITS; + + const vertex_t * v = NULL;/* shut compiler up, should never be NULL */ + + size_t i; + + (*closeness) = INT32_MAX; + + for (i = 0; i < sector->linecount; ++i) + { + compare_vertex_distance(&v, closeness, x, y, sector->lines[i]->v1); + compare_vertex_distance(&v, closeness, x, y, sector->lines[i]->v2); + } + + return v; +} + +static INT16 +anchor_height +( + const mapthing_t * a, + const sector_t * s +){ + { + INT16 z = ( a->options >> ZSHIFT ); + + if (a->options & MTF_OBJECTFLIP) + { + return ( s->ceilingheight >> FRACBITS ) - z; + } + else + { + return ( s->floorheight >> FRACBITS ) + z; + } + } +} + +static void +set_anchor +( + struct anchor_list * list, + mapthing_t * a +){ + const subsector_t * sub = R_PointInSubsector + ( + a->x << FRACBITS, + a->y << FRACBITS + ); + + const vertex_t * v; + + fixed_t closeness; + + a->z = anchor_height(a, sub->sector); + + v = nearest_point(&closeness, a, sub->sector); + + a->x = ( v->x >> FRACBITS ); + a->y = ( v->y >> FRACBITS ); + + list->anchors [list->count] = a; + list->points [list->count] = v; + list->closeness[list->count] = closeness; + + list->count++; +} + +static void build_anchors (void) { + size_t i; + + floor_anchors.count = 0; + ceiling_anchors.count = 0; + + for (i = 0; i < nummapthings; ++i) + { + switch (mapthings[i].type) + { + case FLOOR_SLOPE_THING: + set_anchor(&floor_anchors, &mapthings[i]); + break; + + case CEILING_SLOPE_THING: + set_anchor(&ceiling_anchors, &mapthings[i]); + break; + } + } +} + +static void +get_anchor +( + mapthing_t ** anchors, + fixed_t distances[3], + const struct anchor_list * list, + const INT16 tag, + const vertex_t * v +){ + size_t i; + + int k; + + for (i = 0; i < list->count; ++i) + { + if (list->points[i] == v && list->anchors[i]->extrainfo == tag) + { + for (k = 0; k < 3; ++k) + { + if (list->closeness[i] < distances[k]) + { + if (k == 0) + { + distances[2] = distances[1]; + distances[1] = distances[0]; + + anchors [2] = anchors [1]; + anchors [1] = anchors [0]; + } + else if (k == 1) + { + distances[2] = distances[1]; + anchors [2] = anchors [1]; + } + + distances[k] = list->closeness[i]; + + anchors[k] = list->anchors[i]; + + break; + } + else if (list->anchors[i] == anchors[k]) + { + break; + } + } + } + } +} + +static void +get_sector_anchors +( + mapthing_t ** anchors, + fixed_t distances[3], + const struct anchor_list * list, + const INT16 tag, + const sector_t * sector +){ + size_t i; + + for (i = 0; i < sector->linecount; ++i) + { + get_anchor(anchors, distances, list, tag, sector->lines[i]->v1); + get_anchor(anchors, distances, list, tag, sector->lines[i]->v2); + } +} + +static mapthing_t ** +find_closest_anchors +( + const sector_t * sector, + const struct anchor_list * list, + const INT16 tag +){ + fixed_t distances[3] = { INT32_MAX, INT32_MAX, INT32_MAX }; + + mapthing_t ** anchors; + + int last = 0; + + size_t i; + + if (list->count < 3) + { + I_Error("At least three slope anchors are required to make a slope."); + } + + anchors = Z_Malloc(3 * sizeof *anchors, PU_LEVEL, NULL); + + if (sector->numattached > 0) + { + for (i = 0; i < sector->numattached; ++i) + { + get_sector_anchors + (anchors, distances, list, tag, §ors[sector->attached[i]]); + } + } + else + { + get_sector_anchors(anchors, distances, list, tag, sector); + } + + if (distances[2] < INT32_MAX) + { + return anchors; + } + + if (distances[1] < INT32_MAX) + last = 2; + else if (distances[0] < INT32_MAX) + last = 1; + else + last = 0; + + if (sector->numattached > 0) + { + CONS_Printf("\nSearched for anchors in sectors...\n\n"); + + for (i = 0; i < sector->numattached; ++i) + { + CONS_Printf("#%s\n", sizeu1 (sector->attached[i])); + } + + I_Error( + "(Control Sector #%s)" + " Slope requires anchors (with Parameter %d)" + " near 3 of its target sectors' vertices (%d found)" + + "\n\nCheck the log to see which sectors were searched.", + + sizeu1 (sector - sectors), + tag, + last + ); + } + else + { + I_Error( + "(Sector #%s)" + " Slope requires anchors (with Parameter %d)" + " near 3 of its vertices (%d found)", + + sizeu1 (sector - sectors), + tag, + last + ); + } +} + +static pslope_t * +new_vertex_slope +( + mapthing_t ** anchors, + const INT16 flags +){ + pslope_t * slope = Z_Calloc(sizeof (pslope_t), PU_LEVEL, NULL); + + slope->flags = SL_VERTEXSLOPE; + + if (flags & ML_NOSONIC) + { + slope->flags |= SL_NOPHYSICS; + } + + if (( flags & ML_NOTAILS ) == 0) + { + slope->flags |= SL_NODYNAMIC; + } + + slope->vertices = anchors; + + P_ReconfigureVertexSlope(slope); + slope->refpos = 5; + + // Add to the slope list + slope->next = slopelist; + slopelist = slope; + + slopecount++; + slope->id = slopecount; + + return slope; +} + +static mapthing_t ** +flip_slope +( + mapthing_t ** origin, + const sector_t * sector +){ + mapthing_t * copy = Z_Malloc(3 * sizeof (mapthing_t), PU_LEVEL, NULL); + mapthing_t ** anchors = Z_Malloc(3 * sizeof (mapthing_t *), PU_LEVEL, NULL); + + size_t i; + + for (i = 0; i < 3; ++i) + { + memcpy(©[i], origin[i], sizeof copy[i]); + + copy[i].options ^= MTF_OBJECTFLIP; + copy[i].z = anchor_height(©[i], sector); + + anchors[i] = ©[i]; + } + + return anchors; +} + +static void +slope_sector +( + pslope_t ** slope, + pslope_t ** alt, + sector_t * sector, + const INT16 flags, + const struct anchor_list * list, + const INT16 tag +){ + mapthing_t ** anchors = find_closest_anchors(sector, list, tag); + + if (anchors != NULL) + { + (*slope) = new_vertex_slope(anchors, flags); + + /* No Knuckles - invert slope to opposite side */ + if (flags & ML_NOKNUX) + { + (*alt) = new_vertex_slope(flip_slope(anchors, sector), flags); + } + + sector->hasslope = true; + } +} + +static void +make_anchored_slope +( + const line_t * line, + const int plane +){ + enum + { + FLOOR = 0x1, + CEILING = 0x2, + }; + + INT16 flags = line->flags; + + const int side = ( flags & ML_NOCLIMB ) != 0; + + sector_t * s; + + if (side == 0 || flags & ML_TWOSIDED) + { + s = sides[line->sidenum[side]].sector; + + if (plane == (FLOOR|CEILING)) + { + flags &= ~ML_NOKNUX; + } + + if (plane & FLOOR) + { + slope_sector + (&s->f_slope, &s->c_slope, s, flags, &floor_anchors, line->tag); + } + + if (plane & CEILING) + { + slope_sector + (&s->c_slope, &s->f_slope, s, flags, &ceiling_anchors, line->tag); + } + } +} + +static void P_BuildSlopeAnchorList (void) { + allocate_anchors(); + build_anchors(); +} + +static void P_SetupAnchoredSlopes (void) { + enum + { + FLOOR = 0x1, + CEILING = 0x2, + }; + + size_t i; + + for (i = 0; i < numlines; ++i) + { + if (lines[i].special == LT_SLOPE_ANCHORS_FLOOR) + { + make_anchored_slope(&lines[i], FLOOR); + } + else if (lines[i].special == LT_SLOPE_ANCHORS_CEILING) + { + make_anchored_slope(&lines[i], CEILING); + } + else if (lines[i].special == LT_SLOPE_ANCHORS) + { + make_anchored_slope(&lines[i], FLOOR|CEILING); + } + } +}