Touch
virtual void Touch (Actor toucher)
Usage
A virtual function called by actors with the when another actor comes in contact with them. This doesn't handle general collision (see CanCollideWith for that); instead, this function is mainly utilized by Inventory items: when a player actor touches the item, the item will call Touch()
to try and be picked up by that actor.
If the item is picked up, Touch()
also prints its PickupMessage and plays its PickupSound for the toucher. Note, those are handled by separate functions: PrintPickupMessage and PlayPickupSound respectively. The process of the item being placed in the toucher's inventory is also not handled in Touch()
directly, instead it's handled in CallTryPickup.
This function can also be called directly, such as <itempointer>.Touch(<actorpointer>)
, even if the item and the actor are not at the same position. This forces the item to perform its pickup sequence.
This function is also utilized by the SpectralMonster class to let it hurt the player when touching them.
Parameters
- Actor toucher
- The actor who is attempting to pick up this item.
ZScript definition
Note: The ZScript definition below is for reference and may be different in the current version of GZDoom.The most up-to-date version of this code can be found on GZDoom GitHub. |
This function is actually empty in the base Actor class and does nothing. The base Inventory class, however, uses this override:
override void Touch (Actor toucher)
{
bool localPickUp;
let player = toucher.player;
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) && !ShouldStay() && !ShouldRespawn();
}
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] = 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())
{
Spawn(PickupFlash, Pos, ALLOW_REPLACE);
}
if (!bQuiet)
{
PrintPickupMessage(localview, PickupMessage ());
// Special check so voodoo dolls picking up items cause the
// real player to make noise.
if (player != NULL)
{
PlayPickupSound (player.mo);
if (!bNoScreenFlash && player.playerstate != PST_DEAD)
{
player.bonuscount = BONUSADD;
}
}
else
{
PlayPickupSound (toucher);
}
}
// [RH] Execute an attached special (if any)
DoPickupSpecial (toucher);
if (bCountItem)
{
if (player != NULL)
{
player.itemcount++;
}
level.found_items++;
}
if (bCountSecret)
{
Actor ac = player != NULL? Actor(player.mo) : toucher;
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++)
{
if (players[i].Bot != NULL && self == players[i].Bot.dest)
players[i].Bot.dest = NULL;
}
}
Examples
This is an example of calling Touch() directly rather than overriding it. This version of Doom's HealthBonus will be instantly picked up by any player who enters the 256 radius around it:
class HealthBonus_AutoPickup : HealthBonus
{
override void Tick()
{
super.Tick();
// Do nothing if this item is frozen or has the NOSECTOR flag
// (is in the process of being respawned):
if (isFrozen() || bNOSECTOR)
{
return;
}
double dist = 256;
let bti = BlockThingsIterator.Create(self, dist);
while (bti.Next())
{
let act = bti.thing;
if (act.player && act.health > 0 && Distance3D(act) <= dist)
{
Touch(act);
break;
}
}
}
}
Note, in contrast to a similar example using CallTryPickup()
, this example will also print the item's pickupmessage and play its pickupsound.