Add follower bubbles with the BUBBLESCALE field

This commit is contained in:
Latapostrophe 2020-05-11 00:16:13 +02:00
parent 3f43107eea
commit 2bee969c6a
7 changed files with 153 additions and 5 deletions

View file

@ -719,6 +719,7 @@ static void readfollower(MYFILE *f)
// Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead.
followers[numfollowers].scale = FRACUNIT;
followers[numfollowers].bubblescale = 0; // No bubble by default
followers[numfollowers].atangle = 230;
followers[numfollowers].dist = 32; // changed from 16 to 32 to better account for ogl models
followers[numfollowers].height = 16;
@ -774,6 +775,11 @@ static void readfollower(MYFILE *f)
DEH_WriteUndoline(word, va("%d", followers[numfollowers].scale), UNDO_NONE);
followers[numfollowers].scale = get_number(word2);
}
else if (fastcmp(word, "BUBBLESCALE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bubblescale), UNDO_NONE);
followers[numfollowers].bubblescale = get_number(word2);
}
else if (fastcmp(word, "ATANGLE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].atangle), UNDO_NONE);
@ -917,6 +923,8 @@ if (followers[numfollowers].field < threshold) \
FALLBACK(bobamp, "BOBAMP", 0, 0);
FALLBACK(bobspeed, "BOBSPEED", 0, 0);
FALLBACK(hitconfirmtime, "HITCONFIRMTIME", 1, 1);
FALLBACK(scale, "SCALE", 1, 1); // No null/negative scale
FALLBACK(bubblescale, "BUBBLESCALE", 0, 0); // No negative scale
// Special case for color I suppose
if (followers[numfollowers].defaultcolor < 0 || followers[numfollowers].defaultcolor > MAXSKINCOLORS-1)
@ -7546,6 +7554,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_GCHAOHAPPY3",
"S_GCHAOHAPPY4",
"S_FOLLOWERBUBBLE_FRONT",
"S_FOLLOWERBUBBLE_BACK",
"S_CHEESEIDLE",
"S_CHEESEFLY",
"S_CHEESESAD1",
@ -8404,6 +8415,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BATTLECAPSULE_PIECE",
"MT_FOLLOWER",
"MT_FOLLOWERBUBBLE_FRONT",
"MT_FOLLOWERBUBBLE_BACK",
#ifdef SEENAMES
"MT_NAMECHECK",

View file

@ -73,8 +73,8 @@ char sprnames[NUMSPRITES + 1][5] =
"ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS",
"ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH",
"BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN",
"FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","XMS4","XMS5","GCHA",
"CHEZ","VIEW"
"FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","XMS4","XMS5","FBUB",
"GCHA","CHEZ","VIEW"
};
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)
@ -3513,6 +3513,10 @@ state_t states[NUMSTATES] =
// followers:
// bubble
{SPR_FBUB, 11|FF_ANIMATE|FF_TRANS70|FF_FULLBRIGHT, -1, {NULL}, 10, 3, S_FOLLOWERBUBBLE_FRONT}, // S_FOLLOWERBUBBLE_FRONT
{SPR_FBUB, FF_ANIMATE|0|FF_FULLBRIGHT, -1, {NULL}, 10, 3, S_FOLLOWERBUBBLE_BACK}, // S_FOLLOWERBUBBLE_BACK
// generic chao:
{SPR_GCHA, FF_ANIMATE, -1, {NULL}, 1, 4, S_GCHAOIDLE}, //S_GCHAOIDLE
{SPR_GCHA, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_GCHAOFLY}, //S_GCHAOFLY
@ -20854,6 +20858,62 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // raisestate
},
{ // MT_FOLLOWERBUBBLE_FRONT
-1, // doomednum
S_FOLLOWERBUBBLE_FRONT, // 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
8<<FRACBITS, // radius
16<<FRACBITS, // height
2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_FOLLOWERBUBBLE_BACK
-1, // doomednum
S_FOLLOWERBUBBLE_BACK, // 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
8<<FRACBITS, // radius
16<<FRACBITS, // height
-2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
// ============================================================================================================================//
#ifdef SEENAMES

View file

@ -800,6 +800,7 @@ typedef enum sprite
SPR_XMS4,
SPR_XMS5,
SPR_FBUB, // follower bubble
SPR_GCHA, // follower: generic chao
SPR_CHEZ, // follower: cheese
@ -4189,6 +4190,10 @@ typedef enum state
// followers:
// bubble:
S_FOLLOWERBUBBLE_FRONT,
S_FOLLOWERBUBBLE_BACK,
// generic chao:
S_GCHAOIDLE,
S_GCHAOFLY,
@ -5077,6 +5082,8 @@ typedef enum mobj_type
MT_BATTLECAPSULE_PIECE,
MT_FOLLOWER,
MT_FOLLOWERBUBBLE_FRONT,
MT_FOLLOWERBUBBLE_BACK,
#ifdef SEENAMES
MT_NAMECHECK,

View file

@ -6476,9 +6476,23 @@ void P_MobjThinker(mobj_t *mobj)
// small thinker for follower:
// We cleanse ourselves from existence if our target player doesn't exist for whatever reason. (generally players leaving)
if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->player || mobj->target->player->spectator || mobj->target->player->followerskin < 0)
{
// Remove possible hnext list (bubble)
mobj_t *bub = mobj->hnext;
mobj_t *tmp;
while (bub && !P_MobjWasRemoved(bub))
{
tmp = bub->hnext;
P_RemoveMobj(bub);
bub = tmp;
}
P_RemoveMobj(mobj);
}
return;
case MT_HOOP:
if (mobj->fuse > 1)
P_MoveHoop(mobj);
@ -8798,7 +8812,7 @@ void P_MobjThinker(mobj_t *mobj)
if (curstate >= S_FLAMESHIELD1 && curstate < S_FLAMESHIELDDASH1 && ((curstate-S_FLAMESHIELD1) & 1))
viewingangle += ANGLE_180;
destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4);
desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4);
}
@ -11847,7 +11861,7 @@ void P_SpawnPlayer(INT32 playernum)
//awayview stuff
p->awayviewmobj = NULL;
p->awayviewtics = 0;
p->follower = NULL; // cleanse follower from existence
// set the scale to the mobj's destscale so settings get correctly set. if we don't, they sometimes don't.

View file

@ -8084,6 +8084,10 @@ static void P_HandleFollower(player_t *player)
fixed_t sx, sy, sz;
UINT8 color;
fixed_t bubble; // bubble scale (0 if no bubble)
mobj_t *bmobj; // temp bubble mobj
if (!player->followerready)
return; // we aren't ready to perform anything follower related yet.
@ -8105,6 +8109,7 @@ static void P_HandleFollower(player_t *player)
an = player->mo->angle + (fl.atangle)*ANG1; // it's aproximative but it really doesn't matter in the grand scheme of things...
zoffs = (fl.zoffs)*FRACUNIT;
bubble = fl.bubblescale; // 0 if no bubble to spawn.
// do you like angle maths? I certainly don't...
sx = player->mo->x + FixedMul((player->mo->scale*fl.dist), FINECOSINE((an)>>ANGLETOFINESHIFT));
@ -8151,6 +8156,18 @@ static void P_HandleFollower(player_t *player)
P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear
player->follower->angle = player->mo->angle;
// This is safe to only spawn it here, the follower is removed then respawned when switched.
if (bubble)
{
bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_FRONT);
P_SetTarget(&player->follower->hnext, bmobj);
P_SetTarget(&bmobj->target, player->follower); // Used to know if we have to despawn at some point.
bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_BACK);
P_SetTarget(&player->follower->hnext->hnext, bmobj); // this seems absolutely stupid, I know, but this will make updating the momentums/flags of these a bit easier.
P_SetTarget(&bmobj->target, player->follower); // Ditto
}
player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use.
/*
0 = idle
@ -8205,6 +8222,29 @@ static void P_HandleFollower(player_t *player)
// if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward.
// Make sure the follower itself is also moving however, otherwise we'll be facing angle 0
// Finally, if the follower has bubbles, move them, set their scale, etc....
// This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done!
bmobj = player->follower->hnext; // will be NULL if there's no bubble
while (bmobj && !P_MobjWasRemoved(bmobj))
{
// match follower's momentums and (e)flags(2).
bmobj->momx = player->follower->momx;
bmobj->momy = player->follower->momy;
bmobj->momz = player->follower->momz;
P_SetScale(bmobj, FixedMul(bubble, player->mo->scale));
K_GenericExtraFlagsNoZAdjust(bmobj, player->follower);
bmobj->flags2 = (player->follower->flags2 & ~MF2_SHADOW)|(player->mo->flags2 & MF2_SHADOW);
if (player->follower->threshold) // threshold means the follower was "despawned" with S_NULL (is actually just set to S_INVISIBLE)
P_SetMobjState(bmobj, S_INVISIBLE); // sooooo... let's do the same!
bmobj = bmobj->hnext; // switch to other bubble layer or exit
}
if (player->follower->threshold)
return; // Threshold means the follower was "despanwed" with S_NULL.

View file

@ -3043,6 +3043,8 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
void SetFollower(INT32 playernum, INT32 skinnum)
{
player_t *player = &players[playernum];
mobj_t *bub;
mobj_t *tmp;
player->followerready = true; // we are ready to perform follower related actions in the player thinker, now.
if (skinnum >= -1 && skinnum <= numfollowers) // Make sure it exists!
@ -3053,6 +3055,17 @@ void SetFollower(INT32 playernum, INT32 skinnum)
*/
if (player->follower && skinnum != player->followerskin) // this is also called when we change colour so don't respawn the follower unless we changed skins
{
// Remove follower's possible hnext list (bubble)
bub = player->follower->hnext;
while (bub && !P_MobjWasRemoved(bub))
{
tmp = bub->hnext;
P_RemoveMobj(bub);
bub = tmp;
}
P_RemoveMobj(player->follower);
player->follower = NULL;
}

View file

@ -113,6 +113,7 @@ typedef struct follower_s
UINT8 defaultcolor; // default color for menus.
fixed_t scale; // Scale relative to the player's.
fixed_t bubblescale; // Bubble scale relative to the player scale. If not set, no bubble will spawn (default)
// some position shenanigans:
INT32 atangle; // angle the object will be at around the player. The object itself will always face the same direction as the player.