Merge branch 'loops' into 'master'
Sonic Loops See merge request KartKrew/Kart!991
This commit is contained in:
parent
6927191a24
commit
4c994de722
20 changed files with 714 additions and 4 deletions
|
|
@ -83,6 +83,7 @@ endif()
|
|||
|
||||
add_subdirectory(blua)
|
||||
add_subdirectory(blan)
|
||||
add_subdirectory(objects)
|
||||
|
||||
if(${SRB2_CONFIG_HAVE_GME})
|
||||
if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ sources+=\
|
|||
$(call List,Sourcefile)\
|
||||
$(call List,blua/Sourcefile)\
|
||||
$(call List,blan/Sourcefile)\
|
||||
$(call List,objects/Sourcefile)\
|
||||
|
||||
depends:=$(basename $(filter %.c %.s,$(sources)))
|
||||
objects:=$(basename $(filter %.c %.s %.nas,$(sources)))
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ p_sight.c
|
|||
p_spec.c
|
||||
p_telept.c
|
||||
p_tick.c
|
||||
p_loop.c
|
||||
p_user.c
|
||||
p_slopes.c
|
||||
tables.c
|
||||
|
|
|
|||
|
|
@ -278,6 +278,16 @@ typedef struct botvars_s
|
|||
|
||||
} botvars_t;
|
||||
|
||||
// player_t struct for loop state
|
||||
typedef struct {
|
||||
fixed_t radius;
|
||||
fixed_t revolution, min_revolution, max_revolution;
|
||||
angle_t yaw;
|
||||
vector3_t origin;
|
||||
vector2_t shift;
|
||||
boolean flip;
|
||||
} sonicloopvars_t;
|
||||
|
||||
// ========================================================================
|
||||
// PLAYER STRUCTURE
|
||||
// ========================================================================
|
||||
|
|
@ -543,6 +553,8 @@ typedef struct player_s
|
|||
|
||||
fixed_t outrun; // Milky Way road effect
|
||||
UINT8 outruntime; // Used to bypass the speed cap for fall off
|
||||
|
||||
sonicloopvars_t loop;
|
||||
|
||||
#ifdef HWRENDER
|
||||
fixed_t fovadd; // adjust FOV for hw rendering
|
||||
|
|
|
|||
|
|
@ -5469,6 +5469,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_PAPERITEMSPOT",
|
||||
|
||||
"MT_BEAMPOINT",
|
||||
|
||||
"MT_LOOPENDPOINT",
|
||||
"MT_LOOPCENTERPOINT",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
|
|||
54
src/info.c
54
src/info.c
|
|
@ -28104,6 +28104,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_LOOPENDPOINT
|
||||
2020, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
MAXRADIUS, // radius
|
||||
2*MAXRADIUS, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
1, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_LOOPCENTERPOINT
|
||||
2021, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
48*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
1, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
skincolor_t skincolors[MAXSKINCOLORS] = {
|
||||
|
|
|
|||
|
|
@ -6487,6 +6487,9 @@ typedef enum mobj_type
|
|||
|
||||
MT_BEAMPOINT,
|
||||
|
||||
MT_LOOPENDPOINT,
|
||||
MT_LOOPCENTERPOINT,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
14
src/k_objects.h
Normal file
14
src/k_objects.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* object-specific code */
|
||||
#ifndef k_objects_H
|
||||
#define k_objects_H
|
||||
|
||||
#include "taglist.h"
|
||||
|
||||
/* Loops */
|
||||
mobj_t *Obj_FindLoopCenter(const mtag_t tag);
|
||||
void Obj_InitLoopEndpoint(mobj_t *end, mobj_t *anchor);
|
||||
void Obj_InitLoopCenter(mobj_t *center);
|
||||
void Obj_LinkLoopAnchor(mobj_t *anchor, mobj_t *center, UINT8 type);
|
||||
void Obj_LoopEndpointCollide(mobj_t *special, mobj_t *toucher);
|
||||
|
||||
#endif/*k_objects_H*/
|
||||
1
src/objects/CMakeLists.txt
Normal file
1
src/objects/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
target_sourcefile(c)
|
||||
1
src/objects/Sourcefile
Normal file
1
src/objects/Sourcefile
Normal file
|
|
@ -0,0 +1 @@
|
|||
loops.c
|
||||
281
src/objects/loops.c
Normal file
281
src/objects/loops.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James R.
|
||||
// Copyright (C) 2023 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file loop-endpoint.c
|
||||
/// \brief Sonic loops, start and end points
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../taglist.h"
|
||||
#include "../p_local.h"
|
||||
#include "../p_setup.h"
|
||||
#include "../p_spec.h"
|
||||
#include "../r_main.h"
|
||||
#include "../k_objects.h"
|
||||
|
||||
#define end_anchor(o) ((o)->target)
|
||||
|
||||
#define center_max_revolution(o) ((o)->threshold)
|
||||
#define center_alpha(o) ((o)->target)
|
||||
#define center_beta(o) ((o)->tracer)
|
||||
|
||||
static inline boolean
|
||||
center_has_flip (const mobj_t *center)
|
||||
{
|
||||
return (center->flags2 & MF2_AMBUSH) == MF2_AMBUSH;
|
||||
}
|
||||
|
||||
static inline void
|
||||
center_set_flip
|
||||
( mobj_t * center,
|
||||
boolean mode)
|
||||
{
|
||||
center->flags2 = (center->flags2 & ~(MF2_AMBUSH)) |
|
||||
((mode != false) * MF2_AMBUSH);
|
||||
}
|
||||
|
||||
#define anchor_center(o) ((o)->target)
|
||||
#define anchor_other(o) ((o)->tracer)
|
||||
#define anchor_type(o) ((o)->reactiontime)
|
||||
|
||||
static void
|
||||
set_shiftxy
|
||||
( player_t * player,
|
||||
const mobj_t * a)
|
||||
{
|
||||
const mobj_t *b = anchor_other(a);
|
||||
|
||||
const fixed_t dx = (b->x - a->x);
|
||||
const fixed_t dy = (b->y - a->y);
|
||||
|
||||
const angle_t th =
|
||||
(R_PointToAngle2(0, 0, dx, dy) - a->angle);
|
||||
|
||||
const fixed_t adj = FixedMul(
|
||||
abs(FCOS(AbsAngle(th - ANGLE_90))),
|
||||
FixedHypot(dx, dy)) / 2;
|
||||
|
||||
vector2_t *xy = &player->loop.shift;
|
||||
|
||||
xy->x = FixedMul(FSIN(a->angle), adj);
|
||||
xy->y = FixedMul(FCOS(a->angle), adj);
|
||||
}
|
||||
|
||||
static void
|
||||
measure_clock
|
||||
( const mobj_t * center,
|
||||
const mobj_t * anchor,
|
||||
angle_t * pitch,
|
||||
fixed_t * radius)
|
||||
{
|
||||
const fixed_t dx = (anchor->x - center->x);
|
||||
const fixed_t dy = (anchor->y - center->y);
|
||||
const fixed_t dz = (anchor->z - center->z);
|
||||
|
||||
/* Translate the anchor point to be along a center line.
|
||||
This makes the horizontal position one dimensional
|
||||
relative to the center point. */
|
||||
const fixed_t xy = (
|
||||
FixedMul(dx, FCOS(anchor->angle)) +
|
||||
FixedMul(dy, FSIN(anchor->angle)));
|
||||
|
||||
/* The 3d position of the anchor point is then reduced to
|
||||
two axes and can be measured as an angle. */
|
||||
*pitch = R_PointToAngle2(0, 0, xy, dz) + ANGLE_90;
|
||||
*radius = FixedHypot(xy, dz);
|
||||
}
|
||||
|
||||
static void
|
||||
crisscross
|
||||
( mobj_t * anchor,
|
||||
mobj_t ** target_p,
|
||||
mobj_t ** other_p)
|
||||
{
|
||||
P_SetTarget(target_p, anchor);
|
||||
|
||||
if (!P_MobjWasRemoved(*other_p))
|
||||
{
|
||||
P_SetTarget(&anchor_other(anchor), *other_p);
|
||||
P_SetTarget(&anchor_other(*other_p), anchor);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean
|
||||
moving_toward_gate
|
||||
( const player_t * player,
|
||||
const mobj_t * anchor,
|
||||
angle_t pitch)
|
||||
{
|
||||
const fixed_t
|
||||
x = player->mo->momx,
|
||||
y = player->mo->momy,
|
||||
z = player->mo->momz,
|
||||
|
||||
zx = FixedMul(FCOS(anchor->angle), z),
|
||||
zy = FixedMul(FSIN(anchor->angle), z),
|
||||
|
||||
co = abs(FCOS(pitch)),
|
||||
si = abs(FSIN(pitch)),
|
||||
|
||||
dx = FixedMul(co, x) + FixedMul(si, zx),
|
||||
dy = FixedMul(co, y) + FixedMul(si, zy);
|
||||
|
||||
return AngleDelta(anchor->angle,
|
||||
R_PointToAngle2(0, 0, dx, dy)) < ANG60;
|
||||
}
|
||||
|
||||
static SINT8
|
||||
get_binary_direction
|
||||
( angle_t pitch,
|
||||
mobj_t * toucher)
|
||||
{
|
||||
const fixed_t si = FSIN(pitch);
|
||||
|
||||
if (abs(si) < abs(FCOS(pitch)))
|
||||
{
|
||||
// pitch = 0 points downward so offset 90 degrees
|
||||
// clockwise so 180 occurs at horizon
|
||||
return ((pitch + ANGLE_90) < ANGLE_180) ? 1 : -(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return intsign(si) * P_MobjFlip(toucher);
|
||||
}
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_FindLoopCenter (const mtag_t tag)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
TAG_ITER_THINGS(tag, i)
|
||||
{
|
||||
mapthing_t *mt = &mapthings[i];
|
||||
|
||||
if (mt->type == mobjinfo[MT_LOOPCENTERPOINT].doomednum)
|
||||
{
|
||||
return mt->mobj;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_InitLoopEndpoint
|
||||
( mobj_t * end,
|
||||
mobj_t * anchor)
|
||||
{
|
||||
P_SetTarget(&end_anchor(end), anchor);
|
||||
}
|
||||
|
||||
void
|
||||
Obj_InitLoopCenter (mobj_t *center)
|
||||
{
|
||||
const mapthing_t *mt = center->spawnpoint;
|
||||
|
||||
center_max_revolution(center) = mt->args[1] * FRACUNIT / 360;
|
||||
center_set_flip(center, mt->args[0]);
|
||||
}
|
||||
|
||||
void
|
||||
Obj_LinkLoopAnchor
|
||||
( mobj_t * anchor,
|
||||
mobj_t * center,
|
||||
UINT8 type)
|
||||
{
|
||||
P_SetTarget(&anchor_center(anchor), center);
|
||||
|
||||
anchor_type(anchor) = type;
|
||||
|
||||
if (!P_MobjWasRemoved(center))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TMLOOP_ALPHA:
|
||||
crisscross(anchor,
|
||||
¢er_alpha(center),
|
||||
¢er_beta(center));
|
||||
break;
|
||||
|
||||
case TMLOOP_BETA:
|
||||
crisscross(anchor,
|
||||
¢er_beta(center),
|
||||
¢er_alpha(center));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_LoopEndpointCollide
|
||||
( mobj_t * end,
|
||||
mobj_t * toucher)
|
||||
{
|
||||
player_t *player = toucher->player;
|
||||
sonicloopvars_t *s = &player->loop;
|
||||
|
||||
mobj_t *anchor = end_anchor(end);
|
||||
mobj_t *center = anchor ? anchor_center(anchor) : NULL;
|
||||
|
||||
angle_t pitch;
|
||||
fixed_t radius;
|
||||
|
||||
/* predict movement for a smooth transition */
|
||||
const fixed_t px = toucher->x + toucher->momx;
|
||||
const fixed_t py = toucher->y + toucher->momy;
|
||||
|
||||
SINT8 flip;
|
||||
|
||||
if (P_MobjWasRemoved(center))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->loop.radius != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
measure_clock(center, anchor, &pitch, &radius);
|
||||
|
||||
if (!moving_toward_gate(player, anchor, pitch))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!P_MobjWasRemoved(anchor_other(anchor)))
|
||||
{
|
||||
set_shiftxy(player, anchor);
|
||||
}
|
||||
|
||||
flip = get_binary_direction(pitch, toucher);
|
||||
|
||||
s->yaw = anchor->angle;
|
||||
|
||||
s->origin.x = center->x - (anchor->x - px);
|
||||
s->origin.y = center->y - (anchor->y - py);
|
||||
s->origin.z = center->z;
|
||||
|
||||
s->radius = radius * flip;
|
||||
s->revolution = AngleFixed(pitch) / 360;
|
||||
|
||||
s->min_revolution = s->revolution;
|
||||
s->max_revolution = s->revolution +
|
||||
center_max_revolution(center) * flip;
|
||||
|
||||
s->flip = center_has_flip(center);
|
||||
|
||||
player->speed =
|
||||
3 * (player->speed + toucher->momz) / 2;
|
||||
|
||||
/* cancel the effects of K_Squish */
|
||||
toucher->spritexscale = FRACUNIT;
|
||||
toucher->spriteyscale = FRACUNIT;
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "p_spec.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
// CTF player names
|
||||
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
||||
|
|
@ -584,6 +585,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
return;
|
||||
|
||||
case MT_LOOPENDPOINT:
|
||||
Obj_LoopEndpointCollide(special, toucher);
|
||||
return;
|
||||
|
||||
default: // SOC or script pickup
|
||||
P_SetTarget(&special->target, toucher);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -195,6 +195,10 @@ boolean P_AutoPause(void);
|
|||
void P_ElementalFire(player_t *player, boolean cropcircle);
|
||||
void P_SpawnSkidDust(player_t *player, fixed_t radius, boolean sound);
|
||||
|
||||
void P_HaltPlayerOrbit(player_t *player);
|
||||
void P_ExitPlayerOrbit(player_t *player);
|
||||
boolean P_PlayerOrbit(player_t *player);
|
||||
|
||||
void P_MovePlayer(player_t *player);
|
||||
void P_PlayerThink(player_t *player);
|
||||
void P_PlayerAfterThink(player_t *player);
|
||||
|
|
|
|||
176
src/p_loop.c
Normal file
176
src/p_loop.c
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
// SONIC ROBO BLAST 2 KART
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file p_loop.c
|
||||
/// \brief Sonic loop physics
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "d_player.h"
|
||||
#include "k_kart.h"
|
||||
#include "p_local.h"
|
||||
#include "p_setup.h"
|
||||
#include "p_slopes.h"
|
||||
#include "r_main.h"
|
||||
|
||||
static inline angle_t
|
||||
get_pitch (fixed_t revolution)
|
||||
{
|
||||
return FixedAngle((revolution & FRACMASK) * 360);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
get_shift_curve (const sonicloopvars_t *s)
|
||||
{
|
||||
const angle_t th = get_pitch(FixedDiv(
|
||||
s->revolution - s->min_revolution,
|
||||
s->max_revolution - s->min_revolution));
|
||||
|
||||
// XY shift is transformed on wave scale; less movement
|
||||
// at start and end of rotation, more halfway.
|
||||
return FSIN((th / 2) - ANGLE_90);
|
||||
}
|
||||
|
||||
void P_HaltPlayerOrbit(player_t *player)
|
||||
{
|
||||
// see P_PlayerOrbit
|
||||
player->mo->flags &= ~(MF_NOCLIPHEIGHT);
|
||||
|
||||
player->loop.radius = 0;
|
||||
}
|
||||
|
||||
void P_ExitPlayerOrbit(player_t *player)
|
||||
{
|
||||
sonicloopvars_t *s = &player->loop;
|
||||
|
||||
angle_t pitch = get_pitch(s->revolution);
|
||||
angle_t yaw = s->yaw;
|
||||
|
||||
fixed_t co, si;
|
||||
fixed_t speed;
|
||||
|
||||
if (s->radius < 0)
|
||||
{
|
||||
pitch += ANGLE_180;
|
||||
}
|
||||
|
||||
co = FCOS(pitch);
|
||||
si = FSIN(pitch);
|
||||
|
||||
speed = FixedMul(co, player->speed);
|
||||
|
||||
P_InstaThrust(player->mo, yaw, speed);
|
||||
|
||||
player->mo->momz = FixedMul(si, player->speed);
|
||||
|
||||
if (speed < 0)
|
||||
{
|
||||
yaw += ANGLE_180;
|
||||
}
|
||||
|
||||
// excludes only extremely vertical angles
|
||||
if (abs(co) * 4 > abs(si))
|
||||
{
|
||||
P_SetPlayerAngle(player, yaw);
|
||||
}
|
||||
|
||||
if (s->flip)
|
||||
{
|
||||
player->mo->eflags ^= MFE_VERTICALFLIP;
|
||||
player->mo->flags2 ^= MF2_OBJECTFLIP;
|
||||
|
||||
P_SetPitchRoll(player->mo,
|
||||
pitch + ANGLE_180, s->yaw);
|
||||
}
|
||||
|
||||
P_HaltPlayerOrbit(player);
|
||||
}
|
||||
|
||||
boolean P_PlayerOrbit(player_t *player)
|
||||
{
|
||||
sonicloopvars_t *s = &player->loop;
|
||||
|
||||
angle_t pitch;
|
||||
|
||||
fixed_t xy, z;
|
||||
fixed_t xs, ys;
|
||||
|
||||
fixed_t step, th, left;
|
||||
|
||||
fixed_t grav;
|
||||
|
||||
if (s->radius == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
grav = abs(P_GetMobjGravity(player->mo));
|
||||
|
||||
// Lose speed on the way up. revolution = 0.5 always
|
||||
// points straight up.
|
||||
if (abs(s->revolution & FRACMASK) < FRACUNIT/2)
|
||||
{
|
||||
player->speed -= grav;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->speed += 4 * grav;
|
||||
}
|
||||
|
||||
pitch = get_pitch(s->revolution);
|
||||
|
||||
xy = FixedMul(abs(s->radius), FSIN(pitch));
|
||||
z = FixedMul(abs(s->radius), -(FCOS(pitch)));
|
||||
|
||||
th = get_shift_curve(s);
|
||||
|
||||
xs = FixedMul(s->shift.x, th);
|
||||
ys = FixedMul(s->shift.y, th);
|
||||
|
||||
xs += FixedMul(xy, FCOS(s->yaw));
|
||||
ys += FixedMul(xy, FSIN(s->yaw));
|
||||
|
||||
P_MoveOrigin(player->mo,
|
||||
s->origin.x + xs,
|
||||
s->origin.y + ys,
|
||||
s->origin.z + z);
|
||||
|
||||
// Match rollangle to revolution
|
||||
P_SetPitchRoll(player->mo,
|
||||
s->radius < 0 ? (ANGLE_180 + pitch) : pitch,
|
||||
s->yaw);
|
||||
|
||||
// circumfrence = (2r)PI
|
||||
step = FixedDiv(player->speed,
|
||||
FixedMul(s->radius, M_TAU_FIXED));
|
||||
|
||||
left = (s->max_revolution - s->revolution);
|
||||
|
||||
if (abs(left) < abs(step))
|
||||
{
|
||||
P_ExitPlayerOrbit(player);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If player slows down by too much, throw them out of
|
||||
// the loop
|
||||
if (player->speed < player->mo->scale)
|
||||
{
|
||||
P_HaltPlayerOrbit(player);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
s->revolution += step;
|
||||
|
||||
// We need to not clip the ground. It sucks but setting
|
||||
// this flag is the only way to do that.
|
||||
player->mo->flags |= (MF_NOCLIPHEIGHT);
|
||||
|
||||
return true;
|
||||
}
|
||||
18
src/p_map.c
18
src/p_map.c
|
|
@ -2386,6 +2386,22 @@ fixed_t P_GetThingStepUp(mobj_t *thing, fixed_t destX, fixed_t destY)
|
|||
return maxstep;
|
||||
}
|
||||
|
||||
static boolean P_UsingStepUp(mobj_t *thing)
|
||||
{
|
||||
if (thing->flags & MF_NOCLIP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// orbits have no collision
|
||||
if (thing->player && thing->player->loop.radius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean
|
||||
increment_move
|
||||
( mobj_t * thing,
|
||||
|
|
@ -2438,7 +2454,7 @@ increment_move
|
|||
// copy into the spechitint buffer from spechit
|
||||
spechitint_copyinto();
|
||||
|
||||
if (!(thing->flags & MF_NOCLIP))
|
||||
if (P_UsingStepUp(thing))
|
||||
{
|
||||
//All things are affected by their scale.
|
||||
fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy);
|
||||
|
|
|
|||
40
src/p_mobj.c
40
src/p_mobj.c
|
|
@ -48,6 +48,7 @@
|
|||
#include "k_bot.h"
|
||||
#include "k_terrain.h"
|
||||
#include "k_collide.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
// BlanKart
|
||||
#include "blan/b_soc.h"
|
||||
|
|
@ -3770,7 +3771,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
|
|||
mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN;
|
||||
|
||||
// Zoom tube
|
||||
if ((mobj->player->carry == CR_ZOOMTUBE && mobj->tracer && !P_MobjWasRemoved(mobj->tracer)))
|
||||
if ((mobj->player->carry == CR_ZOOMTUBE && mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
|
||||
|| mobj->player->loop.radius != 0)
|
||||
{
|
||||
P_HitSpecialLines(mobj, mobj->x, mobj->y, mobj->momx, mobj->momy);
|
||||
P_UnsetThingPosition(mobj);
|
||||
|
|
@ -12590,6 +12592,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
|
|||
// Increment no. of capsules on the map counter
|
||||
maptargets++;
|
||||
}
|
||||
case MT_LOOPCENTERPOINT:
|
||||
{
|
||||
Obj_InitLoopCenter(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -12819,6 +12826,11 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi
|
|||
angle_t angle = FixedAngle(fixedangle << FRACBITS);
|
||||
angle_t fineangle = (angle >> ANGLETOFINESHIFT) & FINEMASK;
|
||||
|
||||
boolean isloopend = (mthing->type == mobjinfo[MT_LOOPENDPOINT].doomednum);
|
||||
mobj_t *loopanchor;
|
||||
|
||||
boolean inclusive = isloopend;
|
||||
|
||||
for (r = 0; r < numitemtypes; r++)
|
||||
{
|
||||
dummything = *mthing;
|
||||
|
|
@ -12837,6 +12849,21 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi
|
|||
}
|
||||
z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, mthing->layer, mthing->options & MTF_OBJECTFLIP, mthing->scale);
|
||||
|
||||
if (isloopend)
|
||||
{
|
||||
const fixed_t length = (numitems - 1) * horizontalspacing / 2;
|
||||
|
||||
mobj_t *loopcenter = Obj_FindLoopCenter(Tag_FGet(&mthing->tags));
|
||||
|
||||
// Spawn the anchor at the middle point of the line
|
||||
loopanchor = P_SpawnMobjFromMapThing(&dummything,
|
||||
x + FixedMul(length, FINECOSINE(fineangle)),
|
||||
y + FixedMul(length, FINESINE(fineangle)),
|
||||
z, MT_LOOPCENTERPOINT);
|
||||
|
||||
Obj_LinkLoopAnchor(loopanchor, loopcenter, mthing->args[0]);
|
||||
}
|
||||
|
||||
for (r = 0; r < numitems; r++)
|
||||
{
|
||||
mobjtype_t itemtype = itemtypes[r % numitemtypes];
|
||||
|
|
@ -12844,15 +12871,24 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi
|
|||
continue;
|
||||
dummything.type = mobjinfo[itemtype].doomednum;
|
||||
|
||||
if (inclusive)
|
||||
mobj = P_SpawnMobjFromMapThing(&dummything, x, y, z, itemtype);
|
||||
|
||||
x += FixedMul(horizontalspacing, FINECOSINE(fineangle));
|
||||
y += FixedMul(horizontalspacing, FINESINE(fineangle));
|
||||
z += (mthing->options & MTF_OBJECTFLIP) ? -verticalspacing : verticalspacing;
|
||||
|
||||
mobj = P_SpawnMobjFromMapThing(&dummything, x, y, z, itemtype);
|
||||
if (!inclusive)
|
||||
mobj = P_SpawnMobjFromMapThing(&dummything, x, y, z, itemtype);
|
||||
|
||||
if (!mobj)
|
||||
continue;
|
||||
|
||||
if (isloopend)
|
||||
{
|
||||
Obj_InitLoopEndpoint(mobj, loopanchor);
|
||||
}
|
||||
|
||||
mobj->spawnpoint = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,6 +356,20 @@ static void P_NetArchivePlayers(void)
|
|||
|
||||
WRITEFIXED(save_p, players[i].outrun);
|
||||
WRITEUINT8(save_p, players[i].outruntime);
|
||||
|
||||
// sonicloopsvars_t
|
||||
WRITEFIXED(save_p, players[i].loop.radius);
|
||||
WRITEFIXED(save_p, players[i].loop.revolution);
|
||||
WRITEFIXED(save_p, players[i].loop.min_revolution);
|
||||
WRITEFIXED(save_p, players[i].loop.max_revolution);
|
||||
WRITEANGLE(save_p, players[i].loop.yaw);
|
||||
WRITEFIXED(save_p, players[i].loop.origin.x);
|
||||
WRITEFIXED(save_p, players[i].loop.origin.y);
|
||||
WRITEFIXED(save_p, players[i].loop.origin.z);
|
||||
WRITEFIXED(save_p, players[i].loop.shift.x);
|
||||
WRITEFIXED(save_p, players[i].loop.shift.y);
|
||||
WRITEUINT8(save_p, players[i].loop.flip);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -621,6 +635,19 @@ static void P_NetUnArchivePlayers(void)
|
|||
players[i].outrun = READFIXED(save_p);
|
||||
players[i].outruntime = READUINT8(save_p);
|
||||
|
||||
// sonicloopsvars_t
|
||||
players[i].loop.radius = READFIXED(save_p);
|
||||
players[i].loop.revolution = READFIXED(save_p);
|
||||
players[i].loop.min_revolution = READFIXED(save_p);
|
||||
players[i].loop.max_revolution = READFIXED(save_p);
|
||||
players[i].loop.yaw = READANGLE(save_p);
|
||||
players[i].loop.origin.x = READFIXED(save_p);
|
||||
players[i].loop.origin.y = READFIXED(save_p);
|
||||
players[i].loop.origin.z = READFIXED(save_p);
|
||||
players[i].loop.shift.x = READFIXED(save_p);
|
||||
players[i].loop.shift.y = READFIXED(save_p);
|
||||
players[i].loop.flip = READUINT8(save_p);
|
||||
|
||||
//players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -859,11 +859,26 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int cmp_loopends(const void *a, const void *b)
|
||||
{
|
||||
const mapthing_t
|
||||
*mt1 = *(const mapthing_t*const*)a,
|
||||
*mt2 = *(const mapthing_t*const*)b;
|
||||
|
||||
// weighted sorting; tag takes precedence over type
|
||||
return
|
||||
intsign(Tag_FGet(&mt1->tags) - Tag_FGet(&mt2->tags)) * 2 +
|
||||
intsign(mt1->args[0] - mt2->args[0]);
|
||||
}
|
||||
|
||||
static void P_SpawnMapThings(boolean spawnemblems)
|
||||
{
|
||||
size_t i;
|
||||
mapthing_t *mt;
|
||||
|
||||
mapthing_t **loopends;
|
||||
size_t num_loopends = 0;
|
||||
|
||||
// Spawn axis points first so they are at the front of the list for fast searching.
|
||||
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
|
||||
{
|
||||
|
|
@ -872,14 +887,22 @@ static void P_SpawnMapThings(boolean spawnemblems)
|
|||
case 1700: // MT_AXIS
|
||||
case 1701: // MT_AXISTRANSFER
|
||||
case 1702: // MT_AXISTRANSFERLINE
|
||||
case 2021: // MT_LOOPCENTERPOINT
|
||||
mt->mobj = NULL;
|
||||
P_SpawnMapThing(mt);
|
||||
break;
|
||||
case 2020: // MT_LOOPENDPOINT
|
||||
num_loopends++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Z_Malloc(num_loopends * sizeof *loopends, PU_STATIC,
|
||||
&loopends);
|
||||
num_loopends = 0;
|
||||
|
||||
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
|
||||
{
|
||||
switch (mt->type)
|
||||
|
|
@ -887,6 +910,7 @@ static void P_SpawnMapThings(boolean spawnemblems)
|
|||
case 1700: // MT_AXIS
|
||||
case 1701: // MT_AXISTRANSFER
|
||||
case 1702: // MT_AXISTRANSFERLINE
|
||||
case 2021: // MT_LOOPCENTERPOINT
|
||||
continue; // These were already spawned
|
||||
}
|
||||
|
||||
|
|
@ -898,6 +922,13 @@ static void P_SpawnMapThings(boolean spawnemblems)
|
|||
|
||||
mt->mobj = NULL;
|
||||
|
||||
if (mt->type == mobjinfo[MT_LOOPENDPOINT].doomednum)
|
||||
{
|
||||
loopends[num_loopends] = mt;
|
||||
num_loopends++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mt->type >= 600 && mt->type <= 611) // item patterns
|
||||
P_SpawnItemPattern(mt);
|
||||
else if (mt->type == 1713) // hoops
|
||||
|
|
@ -905,6 +936,25 @@ static void P_SpawnMapThings(boolean spawnemblems)
|
|||
else // Everything else
|
||||
P_SpawnMapThing(mt);
|
||||
}
|
||||
|
||||
qsort(loopends, num_loopends, sizeof *loopends,
|
||||
cmp_loopends);
|
||||
|
||||
for (i = 1; i < num_loopends; ++i)
|
||||
{
|
||||
mapthing_t
|
||||
*mt1 = loopends[i - 1],
|
||||
*mt2 = loopends[i];
|
||||
|
||||
if (Tag_FGet(&mt1->tags) == Tag_FGet(&mt2->tags) &&
|
||||
mt1->args[0] == mt2->args[0])
|
||||
{
|
||||
P_SpawnItemLine(mt1, mt2);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
Z_Free(loopends);
|
||||
}
|
||||
|
||||
// Experimental groovy write function!
|
||||
|
|
@ -4319,6 +4369,8 @@ static void P_AddBinaryMapTags(void)
|
|||
case 292:
|
||||
case 294:
|
||||
case 780:
|
||||
case 2020: // MT_LOOPENDPOINT
|
||||
case 2021: // MT_LOOPCENTERPOINT
|
||||
Tag_FSet(&mapthings[i].tags, mapthings[i].extrainfo);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -7017,6 +7069,17 @@ static void P_ConvertBinaryThingTypes(void)
|
|||
mapthings[i].args[2] |= TMICF_INVERTSIZE;
|
||||
}
|
||||
break;
|
||||
case 2020: // MT_LOOPENDPOINT
|
||||
{
|
||||
mapthings[i].args[0] =
|
||||
mapthings[i].options & MTF_AMBUSH ?
|
||||
TMLOOP_BETA : TMLOOP_ALPHA;
|
||||
break;
|
||||
}
|
||||
case 2021: // MT_LOOPCENTERPOINT
|
||||
mapthings[i].args[0] = (mapthings[i].options & MTF_AMBUSH) == MTF_AMBUSH;
|
||||
mapthings[i].args[1] = mapthings[i].angle;
|
||||
break;
|
||||
case 2050: // MT_DUELBOMB
|
||||
mapthings[i].args[1] = !!(mapthings[i].options & MTF_AMBUSH);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -510,6 +510,12 @@ typedef enum
|
|||
TMBOT_FORCEDIR = 1<<2,
|
||||
} textmapbotcontroller_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TMLOOP_ALPHA = 0,
|
||||
TMLOOP_BETA = 1,
|
||||
} textmaploopendpointtype_t;
|
||||
|
||||
// GETSECSPECIAL (specialval, section)
|
||||
//
|
||||
// Pulls out the special # from a particular section.
|
||||
|
|
|
|||
|
|
@ -4373,6 +4373,11 @@ void P_PlayerThink(player_t *player)
|
|||
P_DoZoomTube(player);
|
||||
player->rmomx = player->rmomy = 0;
|
||||
}
|
||||
else if (player->loop.radius != 0)
|
||||
{
|
||||
P_PlayerOrbit(player);
|
||||
player->rmomx = player->rmomy = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move around.
|
||||
|
|
@ -4506,7 +4511,7 @@ void P_PlayerThink(player_t *player)
|
|||
player->typing_timer = 0;
|
||||
player->typing_duration = 0;
|
||||
}
|
||||
|
||||
|
||||
K_KartPlayerThink(player, cmd); // SRB2kart
|
||||
|
||||
DoABarrelRoll(player);
|
||||
|
|
|
|||
Loading…
Reference in a new issue