mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-26 04:31:22 +00:00
Added client-side item pick ups
Includes feature to disable Actor rendering locally (this cannot be checked from the playsim) and options for disabling co-op only things.
This commit is contained in:
parent
c3ca564cfc
commit
c1539c2286
8 changed files with 140 additions and 13 deletions
|
@ -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);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -904,6 +904,9 @@ public:
|
|||
|
||||
// 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);
|
||||
|
@ -1125,6 +1128,7 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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
|
||||
|
@ -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() )
|
||||
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -768,12 +771,17 @@ 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();
|
||||
|
@ -781,9 +789,23 @@ class Inventory : Actor
|
|||
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())
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
|
|
@ -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.);
|
||||
|
|
Loading…
Reference in a new issue