Add "drawonlyforplayer" and "dontdrawforviewmobj"

This commit is contained in:
Zwip-Zwap Zapony 2023-06-30 00:09:20 +02:00 committed by Sally Coolatta
parent 1a209146d6
commit 0e2682d590
9 changed files with 188 additions and 70 deletions

View file

@ -631,7 +631,8 @@ void B_HandleFlightIndicator(player_t *player)
}
// otherwise, update its visibility
if (P_IsLocalPlayer(player->botleader))
tails->hnext->drawonlyforplayer = player->botleader; // Hide it from the other player in splitscreen, and yourself when spectating
if (P_IsLocalPlayer(player->botleader)) // Only display it on your own view. Don't display it for spectators
tails->hnext->flags2 &= ~MF2_DONTDRAW;
else
tails->hnext->flags2 |= MF2_DONTDRAW;

View file

@ -1441,6 +1441,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// I assume this is netgame-safe because gunslinger spawns this for only the local player...... *sweats intensely*
newtarget = P_SpawnMobj(ticcmd_ztargetfocus[forplayer]->x, ticcmd_ztargetfocus[forplayer]->y, ticcmd_ztargetfocus[forplayer]->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]);
newtarget->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
if (player->mo && P_AproxDistance(
player->mo->x - ticcmd_ztargetfocus[forplayer]->x,

View file

@ -689,11 +689,12 @@ static int lib_pSpawnLockOn(lua_State *L)
return LUA_ErrInvalid(L, "player_t");
if (state >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1);
if (P_IsLocalPlayer(player)) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
P_SetTarget(&visual->target, lockon);
visual->flags2 |= MF2_DONTDRAW;
visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
P_SetMobjStateNF(visual, state);
}
return 0;

View file

@ -44,6 +44,8 @@ enum mobj_e {
mobj_spritexoffset,
mobj_spriteyoffset,
mobj_floorspriteslope,
mobj_drawonlyforplayer,
mobj_dontdrawforviewmobj,
mobj_touching_sectorlist,
mobj_subsector,
mobj_floorz,
@ -122,6 +124,8 @@ static const char *const mobj_opt[] = {
"spritexoffset",
"spriteyoffset",
"floorspriteslope",
"drawonlyforplayer",
"dontdrawforviewmobj",
"touching_sectorlist",
"subsector",
"floorz",
@ -262,6 +266,17 @@ static int mobj_get(lua_State *L)
case mobj_floorspriteslope:
LUA_PushUserdata(L, mo->floorspriteslope, META_SLOPE);
break;
case mobj_drawonlyforplayer:
LUA_PushUserdata(L, mo->drawonlyforplayer, META_PLAYER);
break;
case mobj_dontdrawforviewmobj:
if (mo->dontdrawforviewmobj && P_MobjWasRemoved(mo->dontdrawforviewmobj))
{ // don't put invalid mobj back into Lua.
P_SetTarget(&mo->dontdrawforviewmobj, NULL);
return 0;
}
LUA_PushUserdata(L, mo->dontdrawforviewmobj, META_MOBJ);
break;
case mobj_touching_sectorlist:
return UNIMPLEMENTED;
case mobj_subsector:
@ -551,6 +566,24 @@ static int mobj_set(lua_State *L)
break;
case mobj_floorspriteslope:
return NOSET;
case mobj_drawonlyforplayer:
if (lua_isnil(L, 3))
mo->drawonlyforplayer = NULL;
else
{
player_t *drawonlyforplayer = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
mo->drawonlyforplayer = drawonlyforplayer;
}
break;
case mobj_dontdrawforviewmobj:
if (lua_isnil(L, 3))
P_SetTarget(&mo->dontdrawforviewmobj, NULL);
else
{
mobj_t *dontdrawforviewmobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&mo->dontdrawforviewmobj, dontdrawforviewmobj);
}
break;
case mobj_touching_sectorlist:
return UNIMPLEMENTED;
case mobj_subsector:

View file

@ -6882,6 +6882,7 @@ void P_RunOverlays(void)
mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP);
mo->scale = mo->destscale = mo->target->scale;
mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir;
P_SetTarget(&mo->dontdrawforviewmobj, mo->target->dontdrawforviewmobj); // Hide the overlay from the view that its target is hidden from - But don't copy drawonlyforplayer!
if (!(mo->state->frame & FF_ANIMATE))
zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale);
@ -7951,11 +7952,6 @@ static void P_MobjSceneryThink(mobj_t *mobj)
return;
}
if (!camera.chase)
mobj->flags2 |= MF2_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
P_UnsetThingPosition(mobj);
{
fixed_t radius = FixedMul(10*mobj->info->speed, mobj->target->scale);

View file

@ -334,6 +334,8 @@ typedef struct mobj_s
// Player and mobj sprites in multiplayer modes are modified
// using an internal color lookup table for re-indexing.
UINT16 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation).
struct player_s *drawonlyforplayer; // If set, hides the mobj for everyone except this player and their spectators
struct mobj_s *dontdrawforviewmobj; // If set, hides the mobj if dontdrawforviewmobj is the current camera (first-person player or awayviewmobj)
// Interaction info, by BLOCKMAP.
// Links in blocks (if needed).

View file

@ -1576,7 +1576,9 @@ typedef enum
MD2_SPRITEXOFFSET = 1<<20,
MD2_SPRITEYOFFSET = 1<<21,
MD2_FLOORSPRITESLOPE = 1<<22,
MD2_DISPOFFSET = 1<<23
MD2_DISPOFFSET = 1<<23,
MD2_DRAWONLYFORPLAYER = 1<<24,
MD2_DONTDRAWFORVIEWMOBJ = 1<<25
} mobj_diff2_t;
typedef enum
@ -1811,6 +1813,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
|| (slope->normal.z != FRACUNIT))
diff2 |= MD2_FLOORSPRITESLOPE;
}
if (mobj->drawonlyforplayer)
diff2 |= MD2_DRAWONLYFORPLAYER;
if (mobj->dontdrawforviewmobj)
diff2 |= MD2_DONTDRAWFORVIEWMOBJ;
if (mobj->dispoffset != mobj->info->dispoffset)
diff2 |= MD2_DISPOFFSET;
@ -1988,6 +1994,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
WRITEFIXED(save_p, slope->normal.y);
WRITEFIXED(save_p, slope->normal.z);
}
if (diff2 & MD2_DRAWONLYFORPLAYER)
WRITEUINT8(save_p, mobj->drawonlyforplayer-players);
if (diff2 & MD2_DONTDRAWFORVIEWMOBJ)
WRITEUINT32(save_p, mobj->dontdrawforviewmobj->mobjnum);
if (diff2 & MD2_DISPOFFSET)
WRITEINT32(save_p, mobj->dispoffset);
@ -3044,6 +3054,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
slope->normal.y = READFIXED(save_p);
slope->normal.z = READFIXED(save_p);
}
if (diff2 & MD2_DRAWONLYFORPLAYER)
mobj->drawonlyforplayer = &players[READUINT8(save_p)];
if (diff2 & MD2_DONTDRAWFORVIEWMOBJ)
mobj->dontdrawforviewmobj = (mobj_t *)(size_t)READUINT32(save_p);
if (diff2 & MD2_DISPOFFSET)
mobj->dispoffset = READINT32(save_p);
else
@ -4063,6 +4077,13 @@ static void P_RelinkPointers(void)
if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
continue;
if (mobj->dontdrawforviewmobj)
{
temp = (UINT32)(size_t)mobj->dontdrawforviewmobj;
mobj->dontdrawforviewmobj = NULL;
if (!P_SetTarget(&mobj->dontdrawforviewmobj, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "dontdrawforviewmobj not found on %d\n", mobj->type);
}
if (mobj->tracer)
{
temp = (UINT32)(size_t)mobj->tracer;

View file

@ -398,6 +398,7 @@ void P_GiveFinishFlags(player_t *player)
angle += FixedAngle(120*FRACUNIT);
P_SetTarget(&flag->target, player->mo);
P_SetTarget(&flag->dontdrawforviewmobj, player->mo); // Hide the flag in first-person
}
}
@ -1840,6 +1841,7 @@ void P_SpawnShieldOrb(player_t *player)
shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype);
shieldobj->flags2 |= MF2_SHIELD;
P_SetTarget(&shieldobj->target, player->mo);
P_SetTarget(&shieldobj->dontdrawforviewmobj, player->mo); // Hide the shield in first-person
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK)
{
shieldobj->color = SKINCOLOR_PINK;
@ -1964,6 +1966,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
mobj_t *ghost = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_GHOST);
P_SetTarget(&ghost->target, mobj);
P_SetTarget(&ghost->dontdrawforviewmobj, mobj); // Hide the ghost in first-person
P_SetScale(ghost, mobj->scale);
ghost->destscale = mobj->scale;
@ -2009,6 +2012,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
mobj_t *ghost2 = P_SpawnGhostMobj(mobj->player->followmobj);
P_SetTarget(&ghost2->tracer, ghost);
P_SetTarget(&ghost->tracer, ghost2);
P_SetTarget(&ghost2->dontdrawforviewmobj, mobj); // Hide the follow-ghost for the non-follow object
ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW);
}
@ -3123,39 +3127,41 @@ static void P_DoBubbleBreath(player_t *player)
//
static void P_DoPlayerHeadSigns(player_t *player)
{
mobj_t *sign = NULL;
if (G_TagGametype())
{
// If you're "IT", show a big "IT" over your head for others to see.
if (player->pflags & PF_TAGIT && !P_IsLocalPlayer(player))
// If you're "IT", show a big "IT" over your head for others to see, including spectators
// (and even yourself if you spectate someone else).
if (player->pflags & PF_TAGIT && (!P_IsLocalPlayer(player) || consoleplayer != displayplayer || splitscreen))
{
mobj_t* it = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG);
it->x = player->mo->x;
it->y = player->mo->y;
it->z = player->mo->z;
it->old_x = player->mo->old_x;
it->old_y = player->mo->old_y;
it->old_z = player->mo->old_z;
sign = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG);
sign->x = player->mo->x;
sign->y = player->mo->y;
sign->z = player->mo->z;
sign->old_x = player->mo->old_x;
sign->old_y = player->mo->old_y;
sign->old_z = player->mo->old_z;
if (!(player->mo->eflags & MFE_VERTICALFLIP))
{
it->z += player->mo->height;
it->old_z += player->mo->height;
sign->z += player->mo->height;
sign->old_z += player->mo->height;
}
else
{
it->z -= mobjinfo[MT_TAG].height;
it->old_z -= mobjinfo[MT_TAG].height;
sign->z -= mobjinfo[MT_TAG].height;
sign->old_z -= mobjinfo[MT_TAG].height;
}
}
}
else if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) // If you have the flag (duh).
{
// Spawn a got-flag message over the head of the player that
// has it (but not on your own screen if you have the flag).
if (splitscreen || player != &players[consoleplayer])
// Spawn a got-flag message over the head of the player that has it
// (but not on your own screen if you have the flag, unless you're spectating).
if (!P_IsLocalPlayer(player) || consoleplayer != displayplayer || splitscreen)
{
fixed_t zofs;
mobj_t *sign;
boolean player_is_flipped = (player->mo->eflags & MFE_VERTICALFLIP) > 0;
zofs = player->mo->momz;
@ -3187,6 +3193,43 @@ static void P_DoPlayerHeadSigns(player_t *player)
sign->frame = 2|FF_FULLBRIGHT;
}
}
if (!P_MobjWasRemoved(sign) && splitscreen) // Hide the sign from yourself in splitscreen - In single-screen, it wouldn't get spawned if it shouldn't be visible
{
if (player == &players[displayplayer])
sign->drawonlyforplayer = &players[secondarydisplayplayer];
else
sign->drawonlyforplayer = &players[displayplayer];
#ifdef QUADS
if (splitscreen > 1) // Can be seen by at least two local views, so we need an extra copy of the sign
{
UINT32 signframe = sign->frame; // Copy the flag frame
sign = P_SpawnMobjFromMobj(sign, 0, 0, 0, MT_TAG);
if (P_MobjWasRemoved(sign))
return;
sign->frame = signframe;
if (player == &players[displayplayer] || player == &players[secondarydisplayplayer])
sign->drawonlyforplayer = &players[thirddisplayplayer];
else
sign->drawonlyforplayer = &players[secondarydisplayplayer];
if (splitscreen > 2) // Can be seen by three local views
{
sign = P_SpawnMobjFromMobj(sign, 0, 0, 0, MT_TAG);
if (P_MobjWasRemoved(sign))
return;
sign->frame = signframe;
if (player != &players[fourthdisplayplayer])
sign->drawonlyforplayer = &players[fourthdisplayplayer];
else
sign->drawonlyforplayer = &players[thirddisplayplayer];
}
}
#endif
}
}
//
@ -4707,10 +4750,11 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
mobj_t *lockon = P_LookForEnemies(player, false, true);
if (lockon)
{
if (P_IsLocalPlayer(player)) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
P_SetTarget(&visual->target, lockon);
visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
}
}
if ((cmd->buttons & BT_SPIN) && !(player->pflags & PF_SPINDOWN))
@ -5054,7 +5098,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
{
if ((lockonshield = P_LookForEnemies(player, false, false)))
{
if (P_IsLocalPlayer(player)) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators
{
boolean dovis = true;
if (lockonshield == lockonthok)
@ -5068,6 +5112,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
{
visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
P_SetTarget(&visual->target, lockonshield);
visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
P_SetMobjStateNF(visual, visual->info->spawnstate+1);
}
}
@ -5171,10 +5216,11 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockonthok = P_LookForEnemies(player, true, false)))
{
if (P_IsLocalPlayer(player)) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators
{
visual = P_SpawnMobj(lockonthok->x, lockonthok->y, lockonthok->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
P_SetTarget(&visual->target, lockonthok);
visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
}
}
@ -11084,17 +11130,30 @@ static void P_MinecartThink(player_t *player)
// Mark interpolation; the old positions need to be relative to the displacement from the minecart _after_ it's moved.
// This isn't quite correct (it captures the landing wobble) but it works well enough
// Additionally, hide other players' marks
if (detleft)
{
if (P_IsLocalPlayer(player))
{
detleft->old_x = detleft->x - (minecart->old_x - minecart->old_x2);
detleft->old_y = detleft->y - (minecart->old_y - minecart->old_y2);
detleft->old_z = detleft->z - (minecart->old_z - minecart->old_z2);
detleft->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
}
else // Don't see others' marks when spectating others
P_RemoveMobj(detleft); // Lock-on markers are only spawned client-side, so this SHOULD be safe too...
}
if (detright)
{
if (P_IsLocalPlayer(player))
{
detright->old_x = detright->x - (minecart->old_x - minecart->old_x2);
detright->old_y = detright->y - (minecart->old_y - minecart->old_y2);
detright->old_z = detright->z - (minecart->old_z - minecart->old_z2);
detright->drawonlyforplayer = player;
}
else
P_RemoveMobj(detleft);
}
}
else
@ -11386,12 +11445,15 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume)
for (i = -1; i < 2; i += 2)
{
mobj_t *bubble;
offsetH = i*P_ReturnThrustX(fume, fume->movedir, radiusV);
offsetV = i*P_ReturnThrustY(fume, fume->movedir, radiusV);
x = mo->x + radiusX + FixedMul(offsetH, factorX);
y = mo->y + radiusY + FixedMul(offsetH, factorY);
z = mo->z + heightoffset + offsetV;
P_SpawnMobj(x, y, z, MT_SMALLBUBBLE)->scale = mo->scale >> 1;
bubble = P_SpawnMobj(x, y, z, MT_SMALLBUBBLE);
bubble->scale = mo->scale >> 1;
P_SetTarget(&bubble->dontdrawforviewmobj, mo); // Hide the bubble in first-person
}
fume->movefactor = 0;
@ -11460,7 +11522,11 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume)
// If dashmode is high enough, spawn a trail
if (player->normalspeed >= skins[player->skin].normalspeed*2)
P_SpawnGhostMobj(fume);
{
mobj_t *ghost = P_SpawnGhostMobj(fume);
if (!P_MobjWasRemoved(ghost))
P_SetTarget(&ghost->dontdrawforviewmobj, mo); // Hide the trail in first-person
}
}
//
@ -12104,14 +12170,6 @@ void P_PlayerThink(player_t *player)
gmobj->tracer->frame |= tr_trans70<<FF_TRANSSHIFT;
}
}
// Hide the mobj from our sights if we're the displayplayer and chasecam is off,
// or secondarydisplayplayer and chasecam2 is off.
// Why not just not spawn the mobj? Well, I'd rather only flirt with
// consistency so much...
if ((player == &players[displayplayer] && !camera.chase)
|| (splitscreen && player == &players[secondarydisplayplayer] && !camera2.chase))
gmobj->flags2 |= MF2_DONTDRAW;
}
#endif

View file

@ -3322,9 +3322,14 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
boolean R_ThingVisible (mobj_t *thing)
{
return (!(
thing->sprite == SPR_NULL ||
( thing->flags2 & (MF2_DONTDRAW) ) ||
(r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing)))
(thing->sprite == SPR_NULL) || // Don't draw null-sprites
(thing->flags2 & MF2_DONTDRAW) || // Don't draw MF2_LINKDRAW objects
(thing->drawonlyforplayer && thing->drawonlyforplayer != viewplayer) || // Don't draw other players' personal objects
(r_viewmobj && (
(r_viewmobj == thing) || // Don't draw first-person players or awayviewmobj objects
(r_viewmobj->player && r_viewmobj->player->followmobj == thing) || // Don't draw first-person players' followmobj
(r_viewmobj == thing->dontdrawforviewmobj) // Don't draw objects that are hidden for the current view
))
));
}