Merge branch 'hyu'

This commit is contained in:
James R 2022-05-25 00:43:32 -07:00
commit dac2f4495e
18 changed files with 669 additions and 33 deletions

View file

@ -302,6 +302,7 @@ target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG)
#)
add_subdirectory(sdl)
add_subdirectory(objects)
if(${CMAKE_SYSTEM} MATCHES Windows)
add_subdirectory(win32)

View file

@ -208,6 +208,7 @@ objdir:=$(makedir)/objs
sources+=\
$(call List,Sourcefile)\
$(call List,blua/Sourcefile)\
$(call List,objects/Sourcefile)\
depends:=$(basename $(filter %.c %.s,$(sources)))
objects:=$(basename $(filter %.c %.s %.nas,$(sources)))

View file

@ -469,6 +469,7 @@ typedef struct player_s
UINT16 hyudorotimer; // Duration of the Hyudoro offroad effect itself
SINT8 stealingtimer; // if >0 you are stealing, if <0 you are being stolen from
mobj_t *hoverhyudoro; // First hyudoro hovering next to player
UINT16 sneakertimer; // Duration of a Sneaker Boost (from Sneakers or level boosters)
UINT8 numsneakers; // Number of stacked sneaker effects

View file

@ -368,8 +368,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_XDEATHSTATE",
"S_RAISESTATE",
// Thok
"S_THOK",
"S_SHADOW",
// SRB2kart Frames
"S_KART_STILL",
@ -3745,6 +3745,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_FLAMESHIELDLINE3",
"S_FLAMESHIELDFLASH",
// Caked-Up Booty-Sheet Ghost
"S_HYUDORO",
// The legend
"S_SINK",
"S_SINK_SHIELD",
@ -4493,6 +4496,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_UNKNOWN",
"MT_THOK", // Thok! mobj
"MT_SHADOW", // Linkdraw Shadow (for invisible objects)
"MT_PLAYER",
"MT_KART_LEFTOVER",
"MT_KART_TIRE",
@ -5315,6 +5319,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_FLAMESHIELDPAPER",
"MT_BUBBLESHIELDTRAP",
"MT_HYUDORO",
"MT_HYUDORO_CENTER",
"MT_SINK", // Kitchen Sink Stuff
"MT_SINK_SHIELD",
"MT_SINKTRAIL",

View file

@ -685,7 +685,6 @@ extern boolean comeback;
extern SINT8 battlewanted[4];
extern tic_t wantedcalcdelay;
extern tic_t indirectitemcooldown;
extern tic_t hyubgone;
extern tic_t mapreset;
extern boolean thwompsactive;
extern UINT8 lastLowestLap;

View file

@ -314,7 +314,6 @@ SINT8 pickedvote; // What vote the host rolls
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
tic_t wantedcalcdelay; // Time before it recalculates WANTED
tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded
tic_t hyubgone; // Cooldown before hyudoro is allowed to be rerolled
tic_t mapreset; // Map reset delay when enough players have joined an empty game
boolean thwompsactive; // Thwomps activate on lap 2
UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors

View file

@ -29,6 +29,7 @@
char sprnames[NUMSPRITES + 1][5] =
{
"NULL", // invisible object
"NONE", // invisible but still rendered
"UNKN",
"THOK", // Thok! mobj
@ -570,6 +571,7 @@ char sprnames[NUMSPRITES + 1][5] =
"FLMP", // Flame Shield paper sprites
"FLML", // Flame Shield speed lines
"FLMF", // Flame Shield flash
"HYUU", // Hyudoro
"SINK", // Kitchen Sink
"SITR", // Kitchen Sink Trail
"KBLN", // Battle Mode Bumper
@ -856,6 +858,7 @@ state_t states[NUMSTATES] =
{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL}, // S_RAISESTATE
{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_THOK
{SPR_NONE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHADOW
// Player
{SPR_PLAY, SPR2_STIN, 1, {NULL}, 0, 0, S_KART_STILL}, // S_KART_STILL
@ -4300,6 +4303,8 @@ state_t states[NUMSTATES] =
{SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|14, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE3
{SPR_FLMF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDFLASH
{SPR_HYUU, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_HYUDORO
{SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK
{SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD
{SPR_SITR, 0, 1, {NULL}, 0, 0, S_SINKTRAIL2}, // S_SINKTRAIL1
@ -5154,6 +5159,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SHADOW
-1, // doomednum
S_SHADOW, // 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
8, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
-1, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_PLAYER
-1, // doomednum
S_KART_STILL, // spawnstate
@ -23881,6 +23913,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_HYUDORO
-1, // doomednum
S_HYUDORO, // 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
32*FRACUNIT, // radius
24*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_HYUDORO_CENTER
-1, // 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
64*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_SINK
-1, // doomednum
S_SINK, // spawnstate

View file

@ -575,6 +575,7 @@ extern boolean actionsoverridden[NUMACTIONS];
typedef enum sprite
{
SPR_NULL, // invisible object
SPR_NONE, // invisible but still rendered
SPR_UNKN,
SPR_THOK, // Thok! mobj
@ -1116,6 +1117,7 @@ typedef enum sprite
SPR_FLMP, // Flame Shield paper sprites
SPR_FLML, // Flame Shield speed lines
SPR_FLMF, // Flame Shield flash
SPR_HYUU, // Hyudoro
SPR_SINK, // Kitchen Sink
SPR_SITR, // Kitchen Sink Trail
SPR_KBLN, // Battle Mode Bumper
@ -1355,8 +1357,8 @@ typedef enum state
S_XDEATHSTATE,
S_RAISESTATE,
// Thok
S_THOK,
S_SHADOW,
S_KART_STILL,
S_KART_STILL_L,
@ -4731,6 +4733,9 @@ typedef enum state
S_FLAMESHIELDLINE3,
S_FLAMESHIELDFLASH,
// Caked-Up Booty-Sheet Ghost
S_HYUDORO,
// The legend
S_SINK,
S_SINK_SHIELD,
@ -5516,6 +5521,7 @@ typedef enum mobj_type
MT_UNKNOWN,
MT_THOK, // Thok! mobj
MT_SHADOW, // Linkdraw Shadow (for invisible objects)
MT_PLAYER,
MT_KART_LEFTOVER,
MT_KART_TIRE,
@ -6338,6 +6344,9 @@ typedef enum mobj_type
MT_FLAMESHIELDPAPER,
MT_BUBBLESHIELDTRAP,
MT_HYUDORO,
MT_HYUDORO_CENTER,
MT_SINK, // Kitchen Sink Stuff
MT_SINK_SHIELD,
MT_SINKTRAIL,

View file

@ -38,6 +38,7 @@
#include "k_director.h"
#include "k_collide.h"
#include "k_follower.h"
#include "k_objects.h"
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
@ -353,25 +354,25 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
//P-Odds 0 1 2 3 4 5 6 7
/*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker
/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker
/*Invincibility*/ { 0, 0, 0, 0, 2, 4, 6, 9 }, // Invincibility
/*Banana*/ { 4, 3, 1, 0, 0, 0, 0, 0 }, // Banana
/*Invincibility*/ { 0, 0, 0, 0, 3, 4, 6, 9 }, // Invincibility
/*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana
/*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
/*Orbinaut*/ { 5, 4, 2, 2, 0, 0, 0, 0 }, // Orbinaut
/*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz
/*Mine*/ { 0, 2, 3, 1, 0, 0, 0, 0 }, // Mine
/*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
/*Ballhog*/ { 0, 0, 2, 1, 0, 0, 0, 0 }, // Ballhog
/*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
/*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink
/*Lightning Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
/*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield
/*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield
/*Hyudoro*/ { 0, 0, 0, 1, 1, 0, 0, 0 }, // Hyudoro
/*Hyudoro*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro
/*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring
/*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
/*Drop Target*/ { 4, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
/*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
/*Sneaker x2*/ { 0, 0, 2, 2, 1, 0, 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3
/*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
@ -458,9 +459,6 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem)
if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items
indirectitemcooldown = 20*TICRATE;
if (getitem == KITEM_HYUDORO) // Hyudoro cooldown
hyubgone = 5*TICRATE;
player->botvars.itemdelay = TICRATE;
player->botvars.itemconfirm = 0;
@ -682,6 +680,7 @@ INT32 K_KartGetItemOdds(
case KITEM_LANDMINE:
case KITEM_DROPTARGET:
case KITEM_BALLHOG:
case KITEM_HYUDORO:
case KRITEM_TRIPLESNEAKER:
case KRITEM_TRIPLEORBINAUT:
case KRITEM_QUADORBINAUT:
@ -742,13 +741,6 @@ INT32 K_KartGetItemOdds(
if (spbplace != -1)
newodds = 0;
break;
case KITEM_HYUDORO:
cooldownOnStart = true;
notNearEnd = true;
if (hyubgone > 0)
newodds = 0;
break;
default:
break;
}
@ -2917,6 +2909,7 @@ boolean K_TripwirePassConditions(player_t *player)
player->sneakertimer ||
player->growshrinktimer > 0 ||
player->flamedash ||
player->hyudorotimer ||
player->speed > 2 * K_GetKartSpeed(player, false)
)
return true;
@ -5393,6 +5386,7 @@ static void K_FlameDashLeftoverSmoke(mobj_t *src)
}
}
#if 0
static void K_DoHyudoroSteal(player_t *player)
{
INT32 i, numplayers = 0;
@ -5470,6 +5464,7 @@ static void K_DoHyudoroSteal(player_t *player)
S_StartSound(NULL, sfx_s3k92);
}
}
#endif
void K_DoSneaker(player_t *player, INT32 type)
{
@ -10068,7 +10063,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->itemamount--;
K_DoHyudoroSteal(player); // yes. yes they do.
//K_DoHyudoroSteal(player); // yes. yes they do.
Obj_HyudoroDeploy(player->mo);
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_POGOSPRING:

11
src/k_objects.h Normal file
View file

@ -0,0 +1,11 @@
/* object-specific code */
#ifndef k_objects_H
#define k_objects_H
/* Hyudoro */
void Obj_HyudoroDeploy(mobj_t *master);
void Obj_HyudoroThink(mobj_t *actor);
void Obj_HyudoroCenterThink(mobj_t *actor);
void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher);
#endif/*k_objects_H*/

View file

@ -378,9 +378,6 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"indirectitemcooldown")) {
lua_pushinteger(L, indirectitemcooldown);
return 1;
} else if (fastcmp(word,"hyubgone")) {
lua_pushinteger(L, hyubgone);
return 1;
} else if (fastcmp(word,"thwompsactive")) {
lua_pushboolean(L, thwompsactive);
return 1;
@ -468,8 +465,6 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
exitcountdown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"indirectitemcooldown"))
indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"hyubgone"))
hyubgone = (tic_t)luaL_checkinteger(L, 2);
else
return 0;

1
src/objects/Sourcefile Normal file
View file

@ -0,0 +1 @@
hyudoro.c

481
src/objects/hyudoro.c Normal file
View file

@ -0,0 +1,481 @@
#include "../doomdef.h"
#include "../doomstat.h"
#include "../info.h"
#include "../k_kart.h"
#include "../k_objects.h"
#include "../m_random.h"
#include "../p_local.h"
#include "../r_main.h"
#include "../s_sound.h"
enum {
HYU_PATROL,
HYU_RETURN,
HYU_HOVER,
};
// TODO: make these general functions
static fixed_t
K_GetSpeed (mobj_t *mobj)
{
return FixedHypot(mobj->momx, mobj->momy);
}
static void
K_ChangePlayerItem
( player_t * player,
INT32 itemtype,
INT32 itemamount)
{
player->itemtype = itemtype;
player->itemamount = itemamount;
K_UnsetItemOut(player);
}
#define hyudoro_mode(o) ((o)->extravalue1)
#define hyudoro_itemtype(o) ((o)->movefactor)
#define hyudoro_itemcount(o) ((o)->movecount)
#define hyudoro_hover_stack(o) ((o)->threshold)
#define hyudoro_next(o) ((o)->tracer)
#define hyudoro_stackpos(o) ((o)->reactiontime)
// cannot be combined
#define hyudoro_center(o) ((o)->target)
#define hyudoro_target(o) ((o)->target)
#define hyudoro_center_max_radius(o) ((o)->threshold)
#define hyudoro_center_master(o) ((o)->target)
static angle_t
trace_angle (mobj_t *hyu)
{
mobj_t *center = hyu->target;
if (hyu->x != center->x || hyu->y != center->y)
{
return R_PointToAngle2(
center->x, center->y, hyu->x, hyu->y);
}
else
return hyu->angle;
}
static angle_t
get_look_angle (mobj_t *thing)
{
player_t *player = thing->player;
return player ? player->angleturn : thing->angle;
}
static boolean
is_hyudoro (mobj_t *thing)
{
return thing && thing->type == MT_HYUDORO;
}
static mobj_t *
get_hyudoro_master (mobj_t *hyu)
{
mobj_t *center = hyudoro_center(hyu);
return center ? hyudoro_center_master(center) : NULL;
}
static player_t *
get_hyudoro_target_player (mobj_t *hyu)
{
mobj_t *target = hyudoro_target(hyu);
return target ? target->player : NULL;
}
static void
sine_bob
( mobj_t * hyu,
angle_t a,
fixed_t sineofs)
{
hyu->sprzoff = FixedMul(hyu->height,
sineofs + FINESINE(a >> ANGLETOFINESHIFT));
}
static void
project_hyudoro (mobj_t *hyu)
{
mobj_t *center = hyudoro_center(hyu);
angle_t angleStep = FixedMul(5 * ANG1,
FixedDiv(hyudoro_center_max_radius(center),
center->radius));
angle_t angle = trace_angle(hyu) + angleStep;
fixed_t d = center->radius;
fixed_t x = P_ReturnThrustX(center, angle, d);
fixed_t y = P_ReturnThrustY(center, angle, d);
hyu->momx = (center->x + x) - hyu->x;
hyu->momy = (center->y + y) - hyu->y;
hyu->angle = angle + ANGLE_90;
sine_bob(hyu, angle, FRACUNIT);
}
static void
project_hyudoro_hover (mobj_t *hyu)
{
const INT32 bob_speed = 64;
mobj_t *target = hyudoro_target(hyu);
// Turns a bit toward its target
angle_t ang = get_look_angle(target) + ANGLE_67h;
fixed_t rad = (target->radius * 2) + hyu->radius;
fixed_t zofs = hyudoro_stackpos(hyu) *
((target->height / 2) + (hyu->height * 2));
P_MoveOrigin(hyu,
target->x - P_ReturnThrustX(hyu, ang, rad),
target->y - P_ReturnThrustY(hyu, ang, rad),
target->z + (zofs * P_MobjFlip(target)));
// Cancel momentum from HYU_RETURN.
// (And anything else! I don't trust this game!!)
hyu->momx = 0;
hyu->momy = 0;
hyu->angle = ang;
// copies sprite tilting
hyu->pitch = target->pitch;
hyu->roll = target->roll;
sine_bob(hyu,
(leveltime & (bob_speed - 1)) *
(ANGLE_MAX / bob_speed), -(3*FRACUNIT/4));
}
static void
spawn_hyudoro_shadow (mobj_t *hyu)
{
mobj_t *shadow = P_SpawnMobjFromMobj(
hyu, 0, 0, 0, MT_SHADOW);
shadow->whiteshadow = true;
shadow->shadowscale = hyu->shadowscale;
hyu->shadowscale = 0;
P_SetTarget(&shadow->tracer, hyu);
}
static void
move_to_player (mobj_t *hyu)
{
mobj_t *target = hyudoro_target(hyu);
angle_t angle;
if (!target)
return;
angle = R_PointToAngle2(
hyu->x, hyu->y, target->x, target->y);
P_InstaThrust(hyu, angle, (hyu->radius / 2) +
max(hyu->radius, K_GetSpeed(target)));
hyu->z = target->z; // stay level with target
hyu->angle = angle;
}
static void
deliver_item (mobj_t *hyu)
{
mobj_t *target = hyudoro_target(hyu);
player_t *player = target->player;
P_SetTarget(&hyudoro_target(hyu), NULL);
if (player)
{
K_ChangePlayerItem(player,
hyudoro_itemtype(hyu),
player->itemamount + hyudoro_itemcount(hyu));
}
S_StartSound(target, sfx_itpick);
// Stop moving here
hyu->momx = 0;
hyu->momy = 0;
hyu->tics = 4;
hyu->destscale = target->scale / 4;
hyu->scalespeed =
abs(hyu->scale - hyu->destscale) / hyu->tics;
}
static void
append_hyudoro
( mobj_t ** head,
mobj_t * hyu)
{
INT32 lastpos = 0;
while (is_hyudoro(*head))
{
lastpos = hyudoro_stackpos(*head);
head = &hyudoro_next(*head);
}
hyudoro_stackpos(hyu) = lastpos + 1;
*head = hyu;
}
static void
pop_hyudoro (mobj_t **head)
{
mobj_t *hyu = *head;
INT32 lastpos;
INT32 thispos;
if (is_hyudoro(hyu))
{
lastpos = hyudoro_stackpos(hyu);
hyu = hyudoro_next(hyu);
while (is_hyudoro(hyu))
{
thispos = hyudoro_stackpos(hyu);
hyudoro_stackpos(hyu) = lastpos;
lastpos = thispos;
hyu = hyudoro_next(hyu);
}
}
*head = hyu;
}
static boolean
hyudoro_patrol_hit_player
( mobj_t * hyu,
mobj_t * toucher)
{
player_t *player = toucher->player;
mobj_t *center = hyudoro_center(hyu);
if (!player)
return false;
// Cannot hit its master
if (toucher == get_hyudoro_master(hyu))
return false;
// Don't punish a punished player
if (player->hyudorotimer)
return false;
// NO ITEM?
if (!player->itemamount)
return false;
K_AddHitLag(toucher, TICRATE/2, true);
hyudoro_mode(hyu) = HYU_RETURN;
hyudoro_itemtype(hyu) = player->itemtype;
hyudoro_itemcount(hyu) = player->itemamount;
K_StripItems(player);
player->hyudorotimer = hyudorotime;
player->stealingtimer = hyudorotime;
P_SetTarget(&hyudoro_target(hyu),
hyudoro_center_master(center));
if (center)
P_RemoveMobj(center);
hyu->renderflags &= ~(RF_DONTDRAW);
return true;
}
static boolean
award_immediately (mobj_t *hyu)
{
player_t *player = get_hyudoro_target_player(hyu);
if (player)
{
if (player->itemamount &&
player->itemtype != hyudoro_itemtype(hyu))
{
return false;
}
// Same as picking up paper items; get stacks
// immediately
if (!P_CanPickupItem(player, 3))
return false;
}
deliver_item(hyu);
return true;
}
static boolean
hyudoro_return_hit_player
( mobj_t * hyu,
mobj_t * toucher)
{
if (toucher != hyudoro_target(hyu))
return false;
// If the player already has an item, just hover beside
// them until they use/lose it.
if (!award_immediately(hyu))
{
hyudoro_mode(hyu) = HYU_HOVER;
append_hyudoro(&toucher->player->hoverhyudoro, hyu);
}
return true;
}
static boolean
hyudoro_hover_await_stack (mobj_t *hyu)
{
player_t *player = get_hyudoro_target_player(hyu);
if (!player)
return false;
// First in stack goes first
if (hyu != player->hoverhyudoro)
return false;
if (!award_immediately(hyu))
return false;
pop_hyudoro(&player->hoverhyudoro);
return true;
}
void
Obj_HyudoroDeploy (mobj_t *master)
{
mobj_t *center = P_SpawnMobjFromMobj(
master, 0, 0, 0, MT_HYUDORO_CENTER);
mobj_t *hyu = P_SpawnMobjFromMobj(
center, 0, 0, 0, MT_HYUDORO);
// This allows a Lua override
if (!hyudoro_center_max_radius(center))
{
hyudoro_center_max_radius(center) =
128 * center->scale;
}
center->radius = hyu->radius;
P_InitAngle(hyu, master->angle);
P_SetTarget(&hyudoro_center(hyu), center);
P_SetTarget(&hyudoro_center_master(center), master);
hyudoro_mode(hyu) = HYU_PATROL;
// Set splitscreen player visibility
if (master->player)
{
hyu->renderflags |= RF_DONTDRAW &
~(K_GetPlayerDontDrawFlag(master->player));
}
spawn_hyudoro_shadow(hyu); // this sucks btw
S_StartSound(master, sfx_s3k92); // scary ghost noise
}
void
Obj_HyudoroThink (mobj_t *hyu)
{
// Might get set from clipping slopes
hyu->momz = 0;
switch (hyudoro_mode(hyu))
{
case HYU_PATROL:
if (hyudoro_center(hyu))
project_hyudoro(hyu);
if (leveltime & 1)
{
mobj_t *ghost = P_SpawnGhostMobj(hyu);
// Flickers every frame
ghost->extravalue1 = 1;
ghost->extravalue2 = 2;
// copy per-splitscreen-player visibility
ghost->renderflags =
(hyu->renderflags & RF_DONTDRAW);
ghost->tics = 8;
P_SetTarget(&ghost->tracer, hyu);
}
break;
case HYU_RETURN:
move_to_player(hyu);
break;
case HYU_HOVER:
if (hyudoro_target(hyu))
{
project_hyudoro_hover(hyu);
hyudoro_hover_await_stack(hyu);
}
break;
}
}
void
Obj_HyudoroCenterThink (mobj_t *center)
{
fixed_t max_radius = hyudoro_center_max_radius(center);
if (center->radius < max_radius)
center->radius += max_radius / 64;
}
void
Obj_HyudoroCollide
( mobj_t * hyu,
mobj_t * toucher)
{
switch (hyudoro_mode(hyu))
{
case HYU_PATROL:
hyudoro_patrol_hit_player(hyu, toucher);
break;
case HYU_RETURN:
hyudoro_return_hit_player(hyu, toucher);
break;
}
}

View file

@ -37,6 +37,7 @@
#include "k_boss.h"
#include "k_respawn.h"
#include "p_spec.h"
#include "k_objects.h"
// CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -483,6 +484,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
S_StartSound(toucher, sfx_s1b2);
return;
case MT_HYUDORO:
Obj_HyudoroCollide(special, toucher);
return;
case MT_RING:
case MT_FLINGRING:
if (special->extravalue1)

View file

@ -44,6 +44,7 @@
#include "k_bot.h"
#include "k_terrain.h"
#include "k_collide.h"
#include "k_objects.h"
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);
@ -5300,6 +5301,20 @@ static void P_MobjSceneryThink(mobj_t *mobj)
switch (mobj->type)
{
case MT_SHADOW:
if (mobj->tracer)
{
P_MoveOrigin(mobj,
mobj->tracer->x,
mobj->tracer->y,
mobj->tracer->z);
}
else
{
P_RemoveMobj(mobj);
return;
}
break;
case MT_BOSSJUNK:
mobj->renderflags ^= RF_DONTDRAW;
break;
@ -7671,6 +7686,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
break;
}
case MT_HYUDORO:
{
Obj_HyudoroThink(mobj);
break;
}
case MT_HYUDORO_CENTER:
{
Obj_HyudoroCenterThink(mobj);
break;
}
case MT_ROCKETSNEAKER:
if (!mobj->target || !mobj->target->health)
{
@ -9185,14 +9210,19 @@ void P_MobjThinker(mobj_t *mobj)
{
if (mobj->extravalue2 >= 2)
{
UINT32 dontdraw = RF_DONTDRAW;
if (mobj->tracer)
dontdraw &= ~(mobj->tracer->renderflags);
if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this.
mobj->renderflags ^= RF_DONTDRAW;
mobj->renderflags ^= dontdraw;
else
{
if (mobj->fuse == mobj->extravalue2)
mobj->renderflags &= ~RF_DONTDRAW;
mobj->renderflags &= ~(dontdraw);
else
mobj->renderflags |= RF_DONTDRAW;
mobj->renderflags |= dontdraw;
}
}
}
@ -9653,6 +9683,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_SSMINE_SHIELD:
case MT_LANDMINE:
case MT_BALLHOG:
case MT_HYUDORO:
case MT_SINK:
case MT_ROCKETSNEAKER:
case MT_SPB:

View file

@ -63,6 +63,7 @@ typedef enum
FOLLOWER = 0x04,
SKYBOXVIEW = 0x08,
SKYBOXCENTER = 0x10,
HOVERHYUDORO = 0x20,
} player_saveflags;
static inline void P_ArchivePlayer(void)
@ -196,6 +197,9 @@ static void P_NetArchivePlayers(void)
if (players[i].skybox.centerpoint)
flags |= SKYBOXCENTER;
if (players[i].hoverhyudoro)
flags |= HOVERHYUDORO;
WRITEUINT16(save_p, flags);
if (flags & SKYBOXVIEW)
@ -210,6 +214,9 @@ static void P_NetArchivePlayers(void)
if (flags & FOLLOWITEM)
WRITEUINT32(save_p, players[i].followmobj->mobjnum);
if (flags & HOVERHYUDORO)
WRITEUINT32(save_p, players[i].hoverhyudoro->mobjnum);
WRITEUINT32(save_p, (UINT32)players[i].followitem);
WRITEUINT32(save_p, players[i].charflags);
@ -485,6 +492,9 @@ static void P_NetUnArchivePlayers(void)
if (flags & FOLLOWITEM)
players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p);
if (flags & HOVERHYUDORO)
players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save_p);
players[i].followitem = (mobjtype_t)READUINT32(save_p);
//SetPlayerSkinByNum(i, players[i].skin);
@ -4236,6 +4246,13 @@ static void P_RelinkPointers(void)
CONS_Debug(DBG_GAMELOGIC, "respawn.wp not found on %d\n", mobj->type);
}
}
if (mobj->player->hoverhyudoro)
{
temp = (UINT32)(size_t)mobj->player->hoverhyudoro;
mobj->player->hoverhyudoro = NULL;
if (!P_SetTarget(&mobj->player->hoverhyudoro, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on %d\n", mobj->type);
}
}
}
}
@ -4488,7 +4505,6 @@ static void P_NetArchiveMisc(boolean resending)
WRITEUINT32(save_p, wantedcalcdelay);
WRITEUINT32(save_p, indirectitemcooldown);
WRITEUINT32(save_p, hyubgone);
WRITEUINT32(save_p, mapreset);
for (i = 0; i < MAXPLAYERS; i++)
@ -4638,7 +4654,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
wantedcalcdelay = READUINT32(save_p);
indirectitemcooldown = READUINT32(save_p);
hyubgone = READUINT32(save_p);
mapreset = READUINT32(save_p);
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -4405,7 +4405,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
wantedcalcdelay = wantedfrequency*2;
indirectitemcooldown = 0;
hyubgone = 0;
mapreset = 0;
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -685,8 +685,6 @@ void P_Ticker(boolean run)
if (indirectitemcooldown > 0)
indirectitemcooldown--;
if (hyubgone > 0)
hyubgone--;
K_BossInfoTicker();