mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
483 lines
9.3 KiB
C
483 lines
9.3 KiB
C
// 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.
|
|
|
|
#include "taglist.h"
|
|
|
|
/*
|
|
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
|
|
){
|
|
const fixed_t x = a->x << FRACBITS;
|
|
const fixed_t y = a->y << FRACBITS;
|
|
|
|
if (a->options & MTF_OBJECTFLIP)
|
|
{
|
|
return ( P_GetSectorCeilingZAt(s, x, y) >> FRACBITS ) - a->z;
|
|
}
|
|
else
|
|
{
|
|
return ( P_GetSectorFloorZAt(s, x, y) >> FRACBITS ) + a->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;
|
|
|
|
v = nearest_point(&closeness, a, sub->sector);
|
|
|
|
a->x = ( v->x >> FRACBITS );
|
|
a->y = ( v->y >> FRACBITS );
|
|
|
|
a->z = anchor_height(a, sub->sector);
|
|
|
|
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 mtag_t tag,
|
|
const vertex_t * v
|
|
){
|
|
size_t i;
|
|
|
|
int k;
|
|
|
|
for (i = 0; i < list->count; ++i)
|
|
{
|
|
if (list->points[i] == v && Tag_FGet(&list->anchors[i]->tags) == 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 mtag_t 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 mtag_t 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);
|
|
const vector3_t anchorVertices[3] = {
|
|
{anchors[0]->x << FRACBITS, anchors[0]->y << FRACBITS, anchors[0]->z << FRACBITS},
|
|
{anchors[1]->x << FRACBITS, anchors[1]->y << FRACBITS, anchors[1]->z << FRACBITS},
|
|
{anchors[2]->x << FRACBITS, anchors[2]->y << FRACBITS, anchors[2]->z << FRACBITS}
|
|
};
|
|
|
|
if (flags & TMSAF_NOPHYSICS)
|
|
{
|
|
slope->flags |= SL_NOPHYSICS;
|
|
}
|
|
|
|
if (flags & TMSAF_DYNAMIC)
|
|
{
|
|
slope->flags |= SL_DYNAMIC;
|
|
}
|
|
|
|
P_ReconfigureViaVertexes(slope, anchorVertices[0], anchorVertices[1], anchorVertices[2]);
|
|
//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 mtag_t tag
|
|
){
|
|
mapthing_t ** anchors = find_closest_anchors(sector, list, tag);
|
|
|
|
if (anchors != NULL)
|
|
{
|
|
(*slope) = new_vertex_slope(anchors, flags);
|
|
|
|
/* invert slope to opposite side */
|
|
if (flags & TMSAF_MIRROR)
|
|
{
|
|
(*alt) = new_vertex_slope(flip_slope(anchors, sector), flags);
|
|
}
|
|
|
|
sector->hasslope = true;
|
|
}
|
|
}
|
|
|
|
static void
|
|
make_anchored_slope
|
|
(
|
|
const line_t * line,
|
|
const int plane
|
|
){
|
|
INT16 flags = line->args[1];
|
|
|
|
const int side = ( flags & TMSAF_BACKSIDE ) != 0;
|
|
|
|
sector_t * s;
|
|
|
|
mtag_t tag = Tag_FGet(&line->tags);
|
|
|
|
if (side == 0 || (line->flags & ML_TWOSIDED))
|
|
{
|
|
s = sides[line->sidenum[side]].sector;
|
|
|
|
if (plane == (TMSA_FLOOR|TMSA_CEILING))
|
|
{
|
|
flags &= ~TMSAF_MIRROR;
|
|
}
|
|
|
|
if (plane & TMSA_FLOOR)
|
|
{
|
|
slope_sector
|
|
(&s->f_slope, &s->c_slope, s, flags, &floor_anchors, tag);
|
|
}
|
|
|
|
if (plane & TMSA_CEILING)
|
|
{
|
|
slope_sector
|
|
(&s->c_slope, &s->f_slope, s, flags, &ceiling_anchors, tag);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void P_BuildSlopeAnchorList (void) {
|
|
allocate_anchors();
|
|
build_anchors();
|
|
}
|
|
|
|
static void P_SetupAnchoredSlopes (void) {
|
|
size_t i;
|
|
|
|
for (i = 0; i < numlines; ++i)
|
|
{
|
|
if (lines[i].special == LT_SLOPE_ANCHORS)
|
|
{
|
|
int plane = (lines[i].args[0] & (TMSA_FLOOR|TMSA_CEILING));
|
|
|
|
if (plane == 0)
|
|
{
|
|
CONS_Alert(CONS_WARNING, "Slope anchor linedef %s has no planes set.\n", sizeu1(i));
|
|
continue;
|
|
}
|
|
|
|
make_anchored_slope(&lines[i], plane);
|
|
}
|
|
}
|
|
}
|