A_SetAffector + properties

Moderator: GZDoom Developers

Post Reply
User avatar
Major Cooke
Posts: 8215
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: GZBoomer Town
Contact:

A_SetAffector + properties

Post by Major Cooke »

A_SetAffector(int whoItAffects, float multiplier, int immunity, int flags)

Using codepointers, this function would basically cause the property controlled by the flags to be affecting the actor pointed at with whoItAffects.

whoItAffects accepts TARGET, MASTER, TRACER, and the customized ones such as AAPTR_PLAYER1, AAPTR_LINE_GETTARGET, etc.

Multiplier sets how much damage it takes and multiplies it before giving it to the linked actor.

Immunities:
These are only set on the calling actor, no one else.
0- No immunities.
1- Immune to linking, and cannot link to others.
2- Immune to linking, but allows linking to others.

Note, the flags are all for the same flag field, it's just separated to make it easier to read and for organization.
Flags:
  • EFO_DONTDAMAGE - By default, the pointed actor takes the same amount of damage (unless specified otherwise via the multiplier, and the calling/pointed actor's resistance to said damagetype). If specified, then only pain (flinching) is condsidered for triggering on the linked actor.
  • EFO_OVERKILL - By default, the actor will not deal any overkill damage done to it (negative health), only what took it to 0. This flag inverses that rule so the affected actor is dealt the overkill damage (except if it's telefrag damage to a player) mixed by the multiplier value.
  • EFO_ABSOLUTEDEALT - The damage will always be the exact same as the calling actor takes, and the multiplier is ignored. (Exceptions are with invulnerability, immunity and/or cheats)
  • EFO_ABSOLUTEFACTOR - The affected actor's current resistances/immunities are not taken into account.
  • EFO_NODAMAGE - The calling actor will essentially transfer all damage done to it to the pointed actor, while taking none itself unless the affected actor dies.

    Pain flags:
    (By default, the actor being affected AND the calling actor both enter the pain states based upon their own individual painchance properties.)
  • EFO_DONTTAKEPAIN - The calling actor doesnt take pain while linked to another actor.
  • EFO_DONTGIVEPAIN - The affected actor doesnt take pain from transferred damage.
  • EFO_SYNCPAIN - The affected actor enters the same pain reaction state as the calling actor for the damagetype if it exists upon the calling actor's reaction. If it doesn't exist, it just goes to a normal pain state. If the affected actor has no pain state or +NOPAIN, this flag is ignored.

    Status flags:
    (By default, nothing happens if, for example, the calling actor dies and the affected one survives.)
  • EFO_KILLACTOR - Upon dying, the calling actor kills the affected actor with the same damagetype. Note that master/minion functions won't always be able to cover what this can! (i.e. there is no A_KillTracer/Target etc, this basically acts like that)
  • EFO_DONTCHECKIMMUNE - Requires the KillActor flag above, else it has no effect. Doesn't check to see if that actor is currently protected from the killing damagetype, so they will die by it regardless/be dealt a different damagetype.
  • EFO_DONTCHECKINVUL - This can be used without EFO_KILLACTOR. Much like DontCheckImmune, only this flag checks invulnerabiliy instead of immunities. It basically acts like +FOILINVUL, so the player won't be hurt by this at all.

    Linking:
    (By default, the calling actor usually establishes a one-way link to the affected actor in the codepointer.)
  • EFO_INVERSE - This basically causes the function to act as if the affected actor had called the function.
  • EFO_DUALLINK - Both of the actors set links on each other, thus both will take damage based upon their resistances and damage taking flags.
  • EFO_SEVER - Severs the links going to the pointer actor affected.
  • EFO_SEVERFROM - Severs any links the code pointer actor may have on the calling actor.
  • EFO_SEVERALL - Severs all links incoming and outgoing.
-----
Properties

Affector takes a code pointer to whom it will usually set a default link on.
AffectFlags takes the above flags and can be combined with the "|" ability.
AffectFactor will set the default multiplier value.

Examples:

Code: Select all

Actor ThornMonster
{
	Monster
	+QUICKTORETALIATE	//With this flag, anything that hurts it will be hurt back.
	Affector "AAPTR_TARGET"
	AffectFactor 0.1
}

//=============================================

Actor PowerElectricProtector : PowerProtection
{
	DamageFactor "Normal", 0.2
}

Actor ElectricalShield
{
	var int user_warp;
	Monster
	+NOINTERACTION
	+NOBLOOD
	+NONSHOOTABLE
	-SHOOTABLE
	Radius 32
	Height 32
	Health 20000
	DamageFactor "Normal", 0.0
	States
	{
	Spawn:
		TNT1 A 0
		TNT1 A 0 A_GiveInventory("PowerElectricProtector",1,AAPTR_MASTER)
		//Causes the master to only take 20% damage.
		SHLD A 0 A_SetAffector(AAPTR_MASTER,0.8,0,EFO_INVERSE|EFO_ABSOLUTE)
		//The shield takes the rest of the brunt.
	Idling:
		SHLD A 1 A_Warp(AAPTR_MASTER,0,0,128,0,WARPF_NOCHECKPOSITION|WARPF_INTERPOLATE)
		SHLD A 0 A_SetUserVar("user_warp",user_warp+1)
		SHLD A 0 A_JumpIf(user_warp>=500,"EndProtection")
		Loop
	Death:
	EndProtection:
		TNT1 A 0 A_TakeInventory("PowerElectricProtector",1,AAPTR_MASTER)
		TNT1 A 0 A_SetAffector(AAPTR_MASTER,0,0,EFO_SEVERALL)
		Stop
	}
}
User avatar
FDARI
Posts: 1097
Joined: Tue Nov 03, 2009 9:19 am

Re: A_SetAffector + properties

Post by FDARI »

I said a lot in my latest PM. I missed the apparent notion of having multiple links to and from each actor at any given time. I think my latter PM might discourage you; it would discourage me somewhat, although I could probably do it. I don't think the result would be all that nice. Maybe you should try to make the A_Damage function from the first PM just as an exercise, and see what you think.

As mentioned, what takes this from "demanding" to entirely "non-trivial" (which in my dictionary is much worse) is the possibility of maintaining links between multiple actors. You have to allocate and save/load these links, and you have to decide how to manage duplicate links.

Concept: a links to b, a calls the function again, linking to b again: do you prevent duplicates in zdoom.exe or do you allow it, making it decorate's job to restrict this?

And there's always that loop-issue. If you don't intend to let damage replication cascade at all, there is no issue. If you intend to let damage cascade, perhaps you must maintain a list of actors that have already received forwarded damage during this damage-processing and omit them from further damage. But with multiple links to the same actor, there may be different specifications so that the amount of damage varies depending on which source in the chain gets to hand it to you.

I think it is basically too complex, and not well suited to zdoom. Perhaps you will be able to cut it down to something manageable.

I've got a WFDS-idea that might work (I don't really think we can put it in zdoom.exe):

A_HandleEvent(int event[, state handler[, str specifier[, str event_data_container]]])

Idea: Call a state whenever a specific event occurs. Execute the state in the same manner you would execute a custominventory function.
Requirement: DoJump() needs another special case, or perhaps we can design a statecall that manages it; dunno.

handler: statename to be executed; if unspecified, clear the handler (remove event handler)
specifier: optional specification. For damage, this specifies a damage type.

Ok... you know what? That's no action function; that's a property.

event damage.[type...] "state" (map an event with or without specifier to a state)
event damage.* "state.*" [exact] (map an event to a corresponding state, with optional exact-requirement, as in SetActorState)

There'd be a new decorate expression with that, called eventdata, which would contain the amount of damage taken for the damage event.

Again: This is unfeasible, but it would allow a more explicit and manageable decorate-based damage-forwarding system. Not quite as flexible and generic as the suggested feature (which can forward a not-predefined damagetype) but still a powerful feature. You would have an even harder time avoiding damage loops though.
User avatar
Major Cooke
Posts: 8215
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: GZBoomer Town
Contact:

Re: A_SetAffector + properties

Post by Major Cooke »

Okay, well, let's forget the multi-actor handling then and leave it as only links for the code pointers the actor currently has. Originally I had thought of having it capable of being placed on multiple targets after switching targets, but thinking about that alone makes my head hurt, actually.

So how about just setting it up with the ability to affect the specified actor with only the damage flags, pain flags, and sever capabilities? The previous target won't be able to keep a severing link on the first target if it switches targets.

For the whole mirroring process, that can be handled by giving a custom inventory item that fetches the first target's inventory (thanks to your owner decorate patch), then the target themselves. We can safely leave that out.

If we go the property route, let's at least include a function that allows us to change it if at all possible.
Post Reply

Return to “Closed Feature Suggestions [GZDoom]”