Skip to content

Commit

Permalink
Added client-side item pick ups
Browse files Browse the repository at this point in the history
Includes feature to disable Actor rendering locally (this cannot be checked from the playsim) and options for disabling co-op only things.
  • Loading branch information
Boondorl authored and madame-rachelle committed Feb 1, 2024
1 parent c3ca564 commit c1539c2
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 13 deletions.
4 changes: 4 additions & 0 deletions src/d_main.cpp
Expand Up @@ -575,6 +575,10 @@ CUSTOM_CVAR(Int, dmflags3, 0, CVAR_SERVERINFO | CVAR_NOINITCALL)

CVAR(Flag, sv_noplayerclip, dmflags3, DF3_NO_PLAYER_CLIP);
CVAR(Flag, sv_coopsharekeys, dmflags3, DF3_COOP_SHARE_KEYS);
CVAR(Flag, sv_localitems, dmflags3, DF3_LOCAL_ITEMS);
CVAR(Flag, sv_nolocaldrops, dmflags3, DF3_NO_LOCAL_DROPS);
CVAR(Flag, sv_nocoopitems, dmflags3, DF3_NO_COOP_ONLY_ITEMS);
CVAR(Flag, sv_nocoopthings, dmflags3, DF3_NO_COOP_ONLY_THINGS);

//==========================================================================
//
Expand Down
6 changes: 5 additions & 1 deletion src/doomdef.h
Expand Up @@ -180,7 +180,11 @@ enum : unsigned
enum : unsigned
{
DF3_NO_PLAYER_CLIP = 1 << 0, // Players can walk through and shoot through each other
DF3_COOP_SHARE_KEYS = 1 << 1, // Keys will be given to all players in coop
DF3_COOP_SHARE_KEYS = 1 << 1, // Keys and other core items will be given to all players in coop
DF3_LOCAL_ITEMS = 1 << 2, // Items are picked up client-side rather than fully taken by the client who picked it up
DF3_NO_LOCAL_DROPS = 1 << 3, // Drops from Actors aren't picked up locally
DF3_NO_COOP_ONLY_ITEMS = 1 << 4, // Items that only appear in co-op are disabled
DF3_NO_COOP_ONLY_THINGS = 1 << 5, // Any Actor that only appears in co-op is disabled
};

// [RH] Compatibility flags.
Expand Down
4 changes: 4 additions & 0 deletions src/playsim/actor.h
Expand Up @@ -904,6 +904,9 @@ class AActor final : public DThinker

// Returns true if this view is considered "local" for the player.
bool CheckLocalView() const;
// Allows for enabling/disabling client-side rendering in a way the playsim can't access.
void DisableLocalRendering(const unsigned int pNum, const bool disable);
bool ShouldRenderLocally() const;

// Finds the first item of a particular type.
AActor *FindInventory (PClassActor *type, bool subclass=false);
Expand Down Expand Up @@ -1125,6 +1128,7 @@ class AActor final : public DThinker
uint32_t RenderRequired; // current renderer must have this feature set
uint32_t RenderHidden; // current renderer must *not* have any of these features

bool NoLocalRender; // DO NOT EXPORT THIS! This is a way to disable rendering such that the playsim cannot access it.
ActorRenderFlags renderflags; // Different rendering flags
ActorRenderFlags2 renderflags2; // More rendering flags...
ActorFlags flags;
Expand Down
65 changes: 58 additions & 7 deletions src/playsim/p_mobj.cpp
Expand Up @@ -970,6 +970,43 @@ DEFINE_ACTION_FUNCTION(AActor, CheckLocalView)
ACTION_RETURN_BOOL(self->CheckLocalView());
}

void AActor::DisableLocalRendering(const unsigned int pNum, const bool disable)
{
if (pNum == consoleplayer)
NoLocalRender = disable;
}

static void DisableLocalRendering(AActor* const self, const unsigned int pNum, const int disable)
{
self->DisableLocalRendering(pNum, disable);
}

DEFINE_ACTION_FUNCTION_NATIVE(AActor, DisableLocalRendering, DisableLocalRendering)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_UINT(pNum);
PARAM_INT(disable);

DisableLocalRendering(self, pNum, disable);
}

bool AActor::ShouldRenderLocally() const
{
return !NoLocalRender;
}

static int ShouldRenderLocally(const AActor* const self)
{
return self->ShouldRenderLocally();
}

DEFINE_ACTION_FUNCTION_NATIVE(AActor, ShouldRenderLocally, ShouldRenderLocally)
{
PARAM_SELF_PROLOGUE(AActor);

ACTION_RETURN_INT(ShouldRenderLocally(self));
}

//============================================================================
//
// AActor :: IsInsideVisibleAngles
Expand Down Expand Up @@ -1049,6 +1086,9 @@ bool AActor::IsVisibleToPlayer() const
// [BB] Safety check. This should never be NULL. Nevertheless, we return true to leave the default ZDoom behavior unaltered.
if (p == nullptr || p->camera == nullptr )
return true;

if (!ShouldRenderLocally())
return false;

if (VisibleToTeam != 0 && teamplay &&
(signed)(VisibleToTeam-1) != p->userinfo.GetTeam() )
Expand Down Expand Up @@ -5701,15 +5741,26 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position)

const AActor *info = GetDefaultByType (i);

// don't spawn keycards and players in deathmatch
if (deathmatch && info->flags & MF_NOTDMATCH)
return NULL;
// Don't spawn keycards and players in deathmatch.
if (deathmatch && (info->flags & MF_NOTDMATCH))
return nullptr;

// don't spawn extra things in coop if so desired
if (multiplayer && !deathmatch && (dmflags2 & DF2_NO_COOP_THING_SPAWN))
// Don't spawn extra things in co-op if desired.
if (multiplayer && !deathmatch)
{
if ((mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH)
return NULL;
// Don't spawn DM-only things in co-op.
if ((dmflags2 & DF2_NO_COOP_THING_SPAWN) && (mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH)
return nullptr;
// Having co-op only functionality is a bit odd, but you never know.
if (!mthing->special && !mthing->thingid && (mthing->flags & (MTF_COOPERATIVE | MTF_SINGLE)) == MTF_COOPERATIVE)
{
// Don't spawn co-op only things in general.
if (dmflags3 & DF3_NO_COOP_ONLY_THINGS)
return nullptr;
// Don't spawn co-op only items.
if ((dmflags3 & DF3_NO_COOP_ONLY_ITEMS) && i->IsDescendantOf(NAME_Inventory))
return nullptr;
}
}

// [RH] don't spawn extra weapons in coop if so desired
Expand Down
4 changes: 4 additions & 0 deletions wadsrc/static/menudef.txt
Expand Up @@ -1688,6 +1688,8 @@ OptionMenu CoopOptions protected
Title "$GMPLYMNU_COOPERATIVE"

Option "$GMPLYMNU_MULTIPLAYERTHINGS", "sv_nothingspawn", "NoYes"
Option "$GMPLYMNU_COOPTHINGS", "sv_nocoopthings", "NoYes"
Option "$GMPLYMNU_COOPITEMS", "sv_nocoopitems", "NoYes"
Option "$GMPLYMNU_MULTIPLAYERWEAPONS", "sv_noweaponspawn", "NoYes"
Option "$GMPLYMNU_LOSEINVENTORY", "sv_cooploseinventory", "YesNo"
Option "$GMPLYMNU_KEEPKEYS", "sv_cooplosekeys", "NoYes"
Expand All @@ -1699,6 +1701,8 @@ OptionMenu CoopOptions protected
Option "$GMPLYMNU_SPAWNWHEREDIED", "sv_samespawnspot", "YesNo"
Option "$GMPLYMNU_NOPLAYERCLIP", "sv_noplayerclip", "YesNo"
Option "$GMPLYMNU_SHAREKEYS", "sv_coopsharekeys", "YesNo"
Option "$GMPLYMNU_LOCALITEMS", "sv_localitems", "YesNo"
Option "$GMPLYMNU_NOLOCALDROP", "sv_nolocaldrops", "YesNo"
Class "GameplayMenu"
}

Expand Down
2 changes: 2 additions & 0 deletions wadsrc/static/zscript/actors/actor.zs
Expand Up @@ -503,6 +503,8 @@ class Actor : Thinker native
virtual native void FallAndSink(double grav, double oldfloorz);
private native void Substitute(Actor replacement);
native ui void DisplayNameTag();
native clearscope void DisableLocalRendering(uint playerNum, bool disable);
native ui bool ShouldRenderLocally(); // Only clients get to check this, never the playsim.

// Called by inventory items to see if this actor is capable of touching them.
// If true, the item will attempt to be picked up. Useful for things like
Expand Down
66 changes: 61 additions & 5 deletions wadsrc/static/zscript/actors/inventory/inventory.zs
Expand Up @@ -10,6 +10,8 @@ class Inventory : Actor
const BLINKTHRESHOLD = (4*32);
const BONUSADD = 6;

private bool pickedUp[MAXPLAYERS]; // If items are set to local, track who already picked it up.

deprecated("3.7") private int ItemFlags;
Actor Owner; // Who owns this item? NULL if it's still a pickup.
int Amount; // Amount of item this instance has
Expand Down Expand Up @@ -65,6 +67,7 @@ class Inventory : Actor
flagdef IsHealth: ItemFlags, 22;
flagdef AlwaysPickup: ItemFlags, 23;
flagdef Unclearable: ItemFlags, 24;
flagdef NeverLocal: ItemFlags, 25;

flagdef ForceRespawnInSurvival: none, 0;
flagdef PickupFlash: none, 6;
Expand Down Expand Up @@ -768,22 +771,41 @@ class Inventory : Actor

override void Touch (Actor toucher)
{
bool localPickUp;
let player = toucher.player;

// If a voodoo doll touches something, pretend the real player touched it instead.
if (player != NULL)
if (player)
{
// If a voodoo doll touches something, pretend the real player touched it instead.
toucher = player.mo;
// Client already picked this up, so ignore them.
if (HasPickedUpLocally(toucher))
return;

localPickUp = CanPickUpLocally(toucher);
}

bool localview = toucher.CheckLocalView();

if (!toucher.CanTouchItem(self))
return;

Inventory give = self;
if (localPickUp)
{
give = Inventory(Spawn(GetClass()));
if (!give)
return;
}

bool res;
[res, toucher] = CallTryPickup(toucher);
if (!res) return;
[res, toucher] = give.CallTryPickup(toucher);
if (!res)
{
if (give != self)
give.Destroy();

return;
}

// This is the only situation when a pickup flash should ever play.
if (PickupFlash != NULL && !ShouldStay())
Expand Down Expand Up @@ -829,6 +851,9 @@ class Inventory : Actor
ac.GiveSecret(true, true);
}

if (localPickUp)
PickUpLocally(toucher);

//Added by MC: Check if item taken was the roam destination of any bot
for (int i = 0; i < MAXPLAYERS; i++)
{
Expand Down Expand Up @@ -1014,6 +1039,37 @@ class Inventory : Actor
SetStateLabel("HoldAndDestroy");
}
}

// Check if the Actor can recieve a local copy of the item instead of outright taking it.
clearscope bool CanPickUpLocally(Actor other) const
{
return other && other.player
&& multiplayer && !deathmatch && sv_localitems
&& !bNeverLocal && (!bDropped || !sv_nolocaldrops);
}

// Check if a client has already picked up this item locally.
clearscope bool HasPickedUpLocally(Actor client) const
{
return pickedUp[client.PlayerNumber()];
}

// When items are dropped, clear their local pick ups.
void ClearLocalPickUps()
{
DisableLocalRendering(consoleplayer, false);
for (int i; i < MAXPLAYERS; ++i)
pickedUp[i] = false;
}

// Client picked up this item. Mark it as invisible to that specific player and
// prevent them from picking it up again.
protected void PickUpLocally(Actor client)
{
int pNum = client.PlayerNumber();
pickedUp[pNum] = true;
DisableLocalRendering(pNum, true);
}

//===========================================================================
//
Expand Down
2 changes: 2 additions & 0 deletions wadsrc/static/zscript/actors/inventory_util.zs
Expand Up @@ -291,6 +291,8 @@ extend class Actor
{
Inventory drop = item.CreateTossable(amt);
if (drop == null) return NULL;
drop.ClearLocalPickUps();
drop.bNeverLocal = true;
drop.SetOrigin(Pos + (0, 0, 10.), false);
drop.Angle = Angle;
drop.VelFromAngle(5.);
Expand Down

0 comments on commit c1539c2

Please sign in to comment.