Determining if inventory was dropped from a player (death or tossed)

Discussions about Coding and Scripting
1337GameDev
Skilled
Posts: 198
Joined: Thu Apr 16, 2020 3:23 pm
Personal rank: GameDev

Determining if inventory was dropped from a player (death or tossed)

Post by 1337GameDev »

I've been trying to detect of a particular inventory item was held by a player since it was spawned. Is there any way to do this?

Looking at Inventory class, I did see PlayerLastTouched, but searching the ut99 codebase, I found no usage (seems to be an incomplete part of the engine, like other things).

Any ideas?

My only idea is to look at it's ammo, and the ammo it's supposed to spawn with, but that's not foolproof.... Obviously bTossedOut works, but that's only when a player explicitly tosses out an item.... For weapon stay shenanigan avoiding.
User avatar
sektor2111
Godlike
Posts: 6133
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Determining if inventory was dropped from a player (death or tossed)

Post by sektor2111 »

1337GameDev wrote: Sat May 08, 2021 7:28 pm Any ideas?
Perhaps a clumsy one.
Mark all inventories from level with something (KeyPoint whatever) which will have as variable weapon located there.
All future weapons appearing in a timed check not having said attached Marker are dropped.

Extra: Adding something for decorations having content and marker tagged similar to their event. If no event is assigned, assign one. When decoration spawns weapon, Marker is triggered for capturing any weapon in next tick, this way weapons never held ever won't be in account, with other words all marked weapons are not dropped but those dropped in any format are not having any marker.

A similar stuff might be added for Pawns having a weapon as "DropWhenKilled" variable.

Main timed cycle can walk through Markers for figuring if whatever weapon is marked or not marked and then... dropped. It might be needed some owner check if a fresh weapon should be unlinked from marker because it's having an owner. These needs tests with logs first. If had an owner but now it's not having one perhaps is dropped - and then all new weapons need to be marked, etc. It's all time consuming for tests. I don't know if weapon can be held multiple times and it's not a copy - I have never been interested about this sort of problems.
Perhaps it's not needed a master check but letting each marker to work in a state code and counting or changing something in their common master controller if such a weapon was owned and held and now it's not longer held, but in state "pickup".

Perhaps this way it's expensive and me one I don't think I need such a toy.
User avatar
Barbie
Godlike
Posts: 2536
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Determining if inventory was dropped from a player (death or tossed)

Post by Barbie »

What's about "Actor.Owner"? Maybe 'misuse' this when weapons are scattered on death?
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
1337GameDev
Skilled
Posts: 198
Joined: Thu Apr 16, 2020 3:23 pm
Personal rank: GameDev

Re: Determining if inventory was dropped from a player (death or tossed)

Post by 1337GameDev »

Hmm, what do you mean by marking them weigh a key point?

Also, what would be different about weapons spawned or created later, so I can differentiate when a weapon has been dropped?

Inventory items routinely use "BecomePickup" and "BecomeItem" when picked up, so they aren't destroyed.

Also, what can be abused about Actor.Owner?

I thought about that, but figured in odd cases that an inventory could be "parented" to another object (eg: a mover / attached to a pawn for special purposes but not in their inventory).

I want to ensure that any usage of parenting to somebody isn't mistaken as it being picked up.
User avatar
sektor2111
Godlike
Posts: 6133
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Determining if inventory was dropped from a player (death or tossed)

Post by sektor2111 »

In these UE1 assets you can have connected actors such as Pawn-Weapon - FlagBase-Flag - Inventory-InventorySpot and so on. You are authorized to link custom things too. A KeyPoint or whatever actor can have a variable MyItem. Right there, in a state code code, you can track what's going on with item and do some logging first for understanding item's life in level - like a diary of item. Then you can take your own decision how to do the rest. Me one, like I said, I did not pay attention at items story, I only removed some errors from weapons or writing small combat codes here and there, but if I want to track an actor suspect by a crime or such I simply install a guard tracking when this actors does whatever change or it changes itself - including when it does an Event.
1337GameDev
Skilled
Posts: 198
Joined: Thu Apr 16, 2020 3:23 pm
Personal rank: GameDev

Re: Determining if inventory was dropped from a player (death or tossed)

Post by 1337GameDev »

Hmm, do you have a code example?

I understand the idea, but unsure of how that works in code. If there's file, item, etc that uses it, I can look in the ut99 UC sources as I have those files all extracted.
Buggie
Godlike
Posts: 1921
Joined: Sat Mar 21, 2020 5:32 am

Re: Determining if inventory was dropped from a player (death or tossed)

Post by Buggie »

If you throw weapon then
https://github.com/Slipyx/UT99/blob/f2e ... n.uc#L1818
Weapon.bTossedOut = true;
TossWeapon();

If you die:
https://github.com/Slipyx/UT99/blob/f2e ... fo.uc#L272
TossWeapon();

TossWeapon:
https://github.com/Slipyx/UT99/blob/f2e ... wn.uc#L563
Weapon.DropFrom(Location + 0.8 * CollisionRadius * X + - 0.5 * CollisionRadius * Y);

DropFrom implemented in some places:
https://github.com/Slipyx/UT99/search?q=DropFrom
I think you need TournamentWeapon
https://github.com/Slipyx/UT99/blob/f2e ... pon.uc#L94
RespawnTime = 0.0; //don't respawn
NetPriority = 2.5;

By default NetPriority = 1.4 for Inventory.
https://github.com/Slipyx/UT99/blob/f2e ... ry.uc#L856

So you can use this for determine. if (NetPriority == 2.5 && RespawnTime == 0.0) // then this TournamentWeapon tossed out.
1337GameDev
Skilled
Posts: 198
Joined: Thu Apr 16, 2020 3:23 pm
Personal rank: GameDev

Re: Determining if inventory was dropped from a player (death or tossed)

Post by 1337GameDev »

Buggie wrote: Sun May 16, 2021 6:52 pm If you throw weapon then
https://github.com/Slipyx/UT99/blob/f2e ... n.uc#L1818
Weapon.bTossedOut = true;
TossWeapon();

If you die:
https://github.com/Slipyx/UT99/blob/f2e ... fo.uc#L272
TossWeapon();

TossWeapon:
https://github.com/Slipyx/UT99/blob/f2e ... wn.uc#L563
Weapon.DropFrom(Location + 0.8 * CollisionRadius * X + - 0.5 * CollisionRadius * Y);

DropFrom implemented in some places:
https://github.com/Slipyx/UT99/search?q=DropFrom
I think you need TournamentWeapon
https://github.com/Slipyx/UT99/blob/f2e ... pon.uc#L94
RespawnTime = 0.0; //don't respawn
NetPriority = 2.5;

By default NetPriority = 1.4 for Inventory.
https://github.com/Slipyx/UT99/blob/f2e ... ry.uc#L856

So you can use this for determine. if (NetPriority == 2.5 && RespawnTime == 0.0) // then this TournamentWeapon tossed out.
I was thinking of going this route too. Is there any way to know for an INVENTORY? I could probably settle for a TournamentWeapon, but curious about base class of Inventory (eg: for custom inventory / pickup class).

Looking again: I see in Inventory that NetPriority is ALSO set to 2.5 there, so this works. Awesome! This should work for me.

Edit:

Just tested this code:

Code: Select all

Log("Checking dropped actors");
ForEach AllActors(class'Inventory', invTest) {
  if(invTest.IsA('Enforcer')){
	 Log("Checking enforcer:"$invTest.Name);
  }

  if(invTest.bTossedOut || ((invTest.RespawnTime == 0.0) && (invTest.NetPriority == 2.5))){
	   Log("Inventory item is considered dropped:"$invTest.Name);
  }
}
In a local game instance, on a test map, with 1 bot, and I killed them. I saw their enforcer on the ground, but saw NO log entries that stated it was considered dropped. I see it being checked, but it didn't pass that check.

Any idea?
Buggie
Godlike
Posts: 1921
Joined: Sat Mar 21, 2020 5:32 am

Re: Determining if inventory was dropped from a player (death or tossed)

Post by Buggie »

1. Inventory != Weapon.
Inventory is all of carried things. Include Ammo and other stuff, like Flare, Translator, Seeds and so on.
Go to Actor Browser in UnrealEd and open in tree Inventory for see full list of standard classes.

2. Your assumption about Inventory in general can be wrong.
Exist only one usage of DropFrom in stock code - Pawn.Weapon. So it must be at least Weapon. no Inventory.
Custom code can use any variant of make item pickup. Or even destroy old and spawn new.
So we talk only about stock code here.

3. Instead of log passed weapon your condition or no, log fields values for understand what happen there.
Log(invtest @ invTest.bTossedOut @ invTest.RespawnTime @ invTest.NetPriority);

--- EDIT ---

Code: Select all

class MyActor expands Actor;

function Tick(float delta) {
	local Inventory invTest;

	ForEach AllActors(class'Inventory', invTest) {
		if (invTest.Owner != None) continue;
		if(invTest.IsA('Enforcer')){
			Log(invtest @ invTest.bTossedOut @ invTest.RespawnTime @ invTest.NetPriority);
		}
	}
}
https://github.com/Slipyx/UT99/blob/f2e ... ry.uc#L261
function BecomePickup()
NetPriority = 1.4;

So this not help.

So you can not exactly know in general way.

if you need work only for Ammo - you can try use PickupAmmoCount

Code: Select all

			Log(invtest @ invTest.bTossedOut @ invTest.RespawnTime @ invTest.NetPriority @ 
				weapon(invTest).PickupAmmoCount @ weapon(invTest).Default.PickupAmmoCount);
--- EDIT ---

Also you do not need kill bot.
Enough fall from high and die self.

So condition look like that:
weap.RespawnTime == 0.0 && weap.PickupAmmoCount != weap.Default.PickupAmmoCount
Obviously you can even use just
weap.RespawnTime == 0.0
if in your game type no place where can appear weapon with zero RespawnTime.

If you need bullet proof solution - you need use polling.
Add all carried weapon (Owner != None) to linked list with two field - weapon and his owner.
When need check presence item without owner in the list. If not - fresh item.

There can be variants of implementation depends of desired targets and other things.

--- EDIT ---

Also you can collect list of all weapons on map on game start.
If weapon without owner not in that list, then it appear from different source. If possible sources only throw or die - you get answer.

If you only use properly built maps you can look at
var InventorySpot MyMarker;
If None - then not from map originally.
But not all maps built properly.

You can try add InventorySpot at runtime. IDK which consequence can be here. Possible not good idea.

I not see fields which can be safely used for mark weapons inside. So you need mark it outside, for example, from your own list, as I write above.

--- EDIT ---

You can use Actor properties.
On start map set bHiddenEd = true for all weapon on map.
By default Weapon not hidden in UnrealEd so there must be false.
https://github.com/Slipyx/UT99/search?q=bHiddenEd
Field not used in game, so you can change it in runtime.
All additionally spawned weapon be bHiddenEd == false;

because of pickup weapon is not really pickup - you get copy and original weapon is hidden for next "respawn":
https://github.com/Slipyx/UT99/blob/f2e ... on.uc#L390
function inventory SpawnCopy( pawn Other )

Of course if( Level.Game.ShouldRespawn(self) )

If not you can carry item which be on map initially. Not just copy of it.

So you need understand what you need, for what and in which condition.

Look like complete common answer will be overkill for you.

If you only need use it for DM where Level.Game.ShouldRespawn(WEAPON) always true, then you can mark all initially weapons with bHiddenEd = True.

Or if you only try detect cheat with Ammo count you can use only: weap.PickupAmmoCount != weap.Default.PickupAmmoCount.

And so on.
1337GameDev
Skilled
Posts: 198
Joined: Thu Apr 16, 2020 3:23 pm
Personal rank: GameDev

Re: Determining if inventory was dropped from a player (death or tossed)

Post by 1337GameDev »

I found a reasonable solution. I noticed the game engine doesn't use: Inventory.PlayerLastTouched name property.

I created a mutator, hooking to HandlePickupQuery and PreventDeath to tag items when a player dies (they'll be tossed, discarded via DropFrom, or destroyed).

Code: Select all

class DroppedInventoryMarkerMutator extends Mutator nousercreate;

static function DroppedInventoryMarkerMutator RegisterMutator(Actor context) {
    local DroppedInventoryMarkerMutator mut;

    mut = context.Spawn(class'DroppedInventoryMarkerMutator');
    context.Level.Game.BaseMutator.AddMutator(mut);
    return mut;
}

//ensure any items we marked as dropped get their special tag reset (if it was set by us)
function bool HandlePickupQuery(Pawn Other, Inventory item, out byte bAllowPickup) {
	local bool DenyPickup;
	DenyPickup = Super.HandlePickupQuery(Other, item, bAllowPickup);
	if(!DenyPickup && item.PlayerLastTouched == 'Dropped'){
	     item.PlayerLastTouched = '';
	}

	return DenyPickup;
}

function bool PreventDeath(Pawn Killed, Pawn Killer, name damageType, vector HitLocation) {
    local Inventory Inv;
    local bool DeathPrevented;

    DeathPrevented = Super.PreventDeath(Killed, Killer, damageType, HitLocation);
    if(!DeathPrevented){
        for(Inv=Killed.Inventory; Inv!=None; Inv=Inv.Inventory) {
            Inv.PlayerLastTouched = 'Dropped';
	    }
    }

    return DeathPrevented;
}
In any class, in the PreBeginPlay function, i look through the Actor.Level.Game.BaseMutator chain and if I don't find the above mutator, I register it using:

Code: Select all

class'DroppedInventoryMarkerMutator '.static.RegisterMutator(self);
In any following code, i check objects using this:

Code: Select all

if((invObject.bTossedOut) || (invObject.PlayerLastTouched == 'Dropped') )