ScriptedEffect experimental builds

Discussion about the experimental SVN builds

Moderators: Enjay, Dev Builds Team

User avatar
Gez
Developer
Developer
Posts: 1393
Joined: Mon Oct 22, 2007 16:47

ScriptedEffect experimental builds

Post by Gez » Mon Jun 08, 2009 18:43

What is it about? It's a new type of powerups which let you define their effects through DECORATE, to the extent of what you can do with DECORATE anyway.

Here is how it works: you define a powerup that inherits from PowerScriptedEffect. The script then takes place in four base states:

ScriptInit:
Similarly to the Pickup: or Use: states of a CustomInventory, the calls from a ScriptInit: are executed in just one tic. This can be used to set up things that the PowerUp does from the start.

ScriptReInit:
Same as above, but this state is instead executed if you pick up another scripted powerup of the same type.

ScriptExit:
The same thing as ScriptInit, but on the other end of the chain: those are executed when the powerup expires or is otherwise removed.

Script:
The meat and bone of this new type of Powerup. While the powerup is in a player's inventory, it will iterate through its states at the normal speed (be sure to make this state last at least one tic!). Very powerful effects are possible: you can use the various A_Checks and A_Jumps, you can A_Give/TakeInventory, you can A_SpawnWhatever things, you can A_Set and A_Unset, and so on.


With this, you can do a lot of types of powerups. They can be pretty simple, or quite elaborate.

Here is a pretty simple example. This powerup generates rockets. You'll get a total of 12 rockets: one every five seconds for one minute.

Code: Select all

Actor PowerRocketGenerator : PowerScriptedEffect
{
	Powerup.Duration -60
	States
	{
	Script:
		// 35 * 5 = 175, so one rocket every 5 seconds
		TNT1 A 175 A_GiveInventory("RocketAmmo")
		Loop
	}
	
}

Actor RocketGenerator : PowerupGiver
{
	+INVENTORY.ALWAYSPICKUP
	+INVENTORY.AUTOACTIVATE
	Inventory.MaxAmount 0
	Inventory.PickupMessage "Picked-up a portable rocket generator"
	Powerup.Type "RocketGenerator"
	States
	{
	Spawn:
		BPAK A -1
		Stop
	}
}

Now here is a more complicated powerup. You can see how it uses many custom states, several inventory tokens, and a lot of A_Jump* checks to achieve its effects.

These combat stims will make you fast and strong, and give you a healing factor. You'll even regenerate above 100% health! However, if you're hurt, your metabolism will no longer sustain some of these effects. If your health goes below 90, you lose the "rage rune" effect. If it falls below 80, you will no longer regenerate above 100. If it falls below 50, you will lose the berserk effect. And if it falls below 25, you will lose all of these boosts entirely, but instead you get speed so that you can run away very quickly! After 30 seconds, the speed boost goes away too. If during your flight you pickup another of these powerups, the stims are back in full force but you lose the speed boost.

Code: Select all

// Special effects
Actor PowerBerserkFiringSpeed : PowerDoubleFiringSpeed { Powerup.Duration 0x7FFFFFFF }
Actor PowerBerserkSpeed : PowerSpeed { Powerup.Duration 0x7FFFFFFF }
Actor BerserkDepletionToken : Inventory {}
Actor BerserkResetToken : Inventory {}
Actor BerserkTicToken : Inventory { Inventory.MaxAmount 1050 }

// The Super Berserk!
Actor PowerSuperBerserk : PowerScriptedEffect
{
	States
	{
	ScriptReInit:
		TNT1 A 0 A_GiveInventory("BerserkResetToken")
		// Fall through to ScriptInit
	ScriptInit:
		TNT1 A 0 A_TakeInventory("BerserkDepletionToken", 255)
		TNT1 A 0 A_GiveInventory("PowerStrength")
		TNT1 A 0 A_GiveInventory("PowerBerserkFiringSpeed")
		TNT1 A 0 HealThing(100, 0)
		TNT1 A 0 A_SelectWeapon("Fist")
		Stop
	ScriptReset:
		TNT1 A 0 A_TakeInventory("BerserkResetToken", 255)
		TNT1 A 0 A_TakeInventory("PowerBerserkSpeed", 255)
		// Fall through to Script
	Script:
		TNT1 A 1 A_GiveInventory("BerserkTicToken")
		TNT1 A 0 A_JumpIfHealthLower(25, "Yipe")
		TNT1 A 0 A_JumpIfInventory("PowerStrength", 1, "StrengthHealthCheck")
		TNT1 A 0 A_JumpIfHealthLower(80, "RegenTokenCheck")
		TNT1 A 0 A_JumpIfInventory("PowerBerserkFiringSpeed", 1, "SpeedHealthCheck")
		TNT1 A 0 A_JumpIfInventory("BerserkTicToken", 105, "RegenCheck")
		Loop
	RegenCheck:
		TNT1 A 0 A_TakeInventory("BerserkTicToken", 1050)
		TNT1 A 0 A_JumpIfHealthLower(100, "LesserRegen")
		TNT1 A 0 A_JumpIfHealthLower(120, "GreaterRegen")
		Goto Script
	GreaterRegen:
		TNT1 A 0 A_JumpIfInventory("BerserkDepletionToken", 1, "Script") // No regen for you!
		TNT1 A 0 A_GiveInventory("HealthBonus") // Gain +1 health to a maximum of 120
		Goto Script
	LesserRegen:
		TNT1 A 0 A_GiveInventory("HealthBonus") // Gain +1 health to a maximum of 100
		Goto Script
	SpeedHealthCheck:
		TNT1 A 0 A_JumpIfHealthLower(90, "SpeedLoss")
		Goto Script +5
	SpeedLoss: // Sorry, you took too much damage to sustain your super attack speed!
		TNT1 A 0 A_Print("Your attacks are no longer accelerated")
		TNT1 A 0 A_TakeInventory("PowerBerserkFiringSpeed", 255)
		Goto Script +5
	RegenTokenCheck:
		TNT1 A 0 A_JumpIfInventory("BerserkDepletionToken", 1, "RegenLoss")
		Goto Script+4
	RegenLoss: // Sorry, but you are hurt and can no longer regen above human limits
		TNT1 A 0 A_Print("Your regen is weakened")
		TNT1 A 0 A_GiveInventory("BerserkDepletionToken")
		Goto Script+4
	StrengthHealthCheck:
		TNT1 A 0 A_JumpIfHealthLower(50, "StrengthLoss")
		Goto Script +3
	StrengthLoss: // Sorry, you took too much damage to sustain your super strength!
		TNT1 A 0 A_Print("Your punches are no longer superhumanly strong")
		TNT1 A 0 A_TakeInventory("PowerStrength", 255)
		Goto Script +3
	Yipe: // A last adrenalin surge that helps running away very quickly!
		TNT1 A 0 A_Print("Run away!")
		TNT1 A 0 A_GiveInventory("PowerBerserkSpeed")
		TNT1 A 0 A_TakeInventory("BerserkTicToken", 1050)
		// fall through to YipeLoop
	YipeLoop:
		TNT1 A 1 A_GiveInventory("BerserkTicToken")
		TNT1 A 0 A_JumpIfInventory("BerserkResetToken", 1, "ScriptReset")
		TNT1 A 0 A_JumpIfInventory("BerserkTicToken", 1050, "YipeEnd")
		Loop		
	YipeEnd:
		TNT1 A 0 A_Print("Adrenalin fading out!")
		Stop // This removes the powerup
	ScriptExit: // Cleanup!
		TNT1 A 0 A_TakeInventory("BerserkTicToken", 1050)
		TNT1 A 0 A_TakeInventory("PowerBerserkFiringSpeed", 255)
		TNT1 A 0 A_TakeInventory("BerserkDepletionToken", 255)
		TNT1 A 0 A_TakeInventory("BerserkResetToken", 255)
		TNT1 A 0 A_TakeInventory("PowerBerserkSpeed", 255)
		TNT1 A 0 A_TakeInventory("PowerStrength", 255)
		Stop
	}
}

Actor SuperBerserk : PowerupGiver replaces Berserk
{
	Game Doom
	SpawnID 134
	+COUNTITEM
	+INVENTORY.ALWAYSPICKUP
	+INVENTORY.AUTOACTIVATE
	Inventory.MaxAmount 0
	Inventory.PickupMessage "Combat stims!"
	Inventory.PickupSound "misc/p_pkup"
	Powerup.Type "SuperBerserk"
	States
	{
	Spawn:
		PSTR A -1
		Stop
	}
}

Now, try those, use them and abuse them to see if you can get them to break. I'd like to be sure they work flawlessly when I'll move them to Code Submission. Oh, and as always, a patch is included in the zip.

User avatar
DoomRater
I wanna get stuck in with da code
Posts: 397
Joined: Tue Jul 19, 2005 4:14
Location: Programmer's Room, talking to Will Harvey
Contact:

Re: ScriptedEffect experimental builds

Post by DoomRater » Mon Jun 08, 2009 19:09

I haven't even tried this and I can already see a bug- the lesser health regen not only produces the same effect as greater health regen, but your check to stop at a maximum of 100 is defeated because it then checks to see if the life is under 120... and then does the greater health regen check! Thus the health regen never actually stops at 100.

baghead
Hosted
Posts: 37
Joined: Tue Dec 16, 2008 3:26
Contact:

Re: ScriptedEffect experimental builds

Post by baghead » Mon Jun 08, 2009 19:18

DR: I'm pretty sure that's intentional.

Gez: Who is the activator when these things execute ACS scripts? Is it the player or the powerup itself? It might be useful to call scripts with the powerup as activator, and have the powerup target the player so the activator can be switched if needed... Just a thought.

User avatar
Gez
Developer
Developer
Posts: 1393
Joined: Mon Oct 22, 2007 16:47

Re: ScriptedEffect experimental builds

Post by Gez » Mon Jun 08, 2009 19:48

DoomRater wrote:I haven't even tried this and I can already see a bug- the lesser health regen not only produces the same effect as greater health regen, but your check to stop at a maximum of 100 is defeated because it then checks to see if the life is under 120... and then does the greater health regen check! Thus the health regen never actually stops at 100.
What are you talking about. If you have less than 100 health, you go to LesserRegen, which gives you one health bonus, and then you go back to script. If you have 100 health or more, you don't go to LesserRegen, instead you go to the next state, which checks if you have less than 120 health. If so, you go to GreaterRegen. And in GreaterRegen, if you don't have the depletion token, you get a health bonus. Then you go back to script.

The way it's done, if you have a depletion token you can only regen up to 100. Otherwise, you can regen up to 120.
baghead wrote:DR: I'm pretty sure that's intentional.

Gez: Who is the activator when these things execute ACS scripts? Is it the player or the powerup itself? It might be useful to call scripts with the powerup as activator, and have the powerup target the player so the activator can be switched if needed... Just a thought.
ACS_Execute is one thing I haven't tested, but the activator would be player. The core of the logic is the same as for the CustomInventory items, using this code to execute functions:

Code: Select all

state->CallAction(Owner, this, &statecall)
So the effects affect Owner (the player), but the states belong to this (the powerup).

The thing is that if the powerup were its own thing (necessary to have it not be the activator of scripts), then any A_SpawnWhatever/A_SomethingMissile/A_RandomAttack function would not work, because they would use the powerup as their point of reference to know where to spawn whatever they have to spawn, and an object in an inventory is unlinked from the world...

baghead
Hosted
Posts: 37
Joined: Tue Dec 16, 2008 3:26
Contact:

Re: ScriptedEffect experimental builds

Post by baghead » Mon Jun 08, 2009 19:59

That's too bad, I could think of some good uses for it.

So, do the inventory items in these examples belong to the powerup or the player?

User avatar
Gez
Developer
Developer
Posts: 1393
Joined: Mon Oct 22, 2007 16:47

Re: ScriptedEffect experimental builds

Post by Gez » Mon Jun 08, 2009 20:32

The player. Just use the very useful "printinv" console command to check.


But really, that's the same thing. :P An actor has one inventory pointer. Just one. But it serves as a linked chain. Every other thing in the actor's inventory are actually in the inventory's inventory, and the inventory's inventory's inventory, and so on.


And I'm not sure which kind of effect would be possible if it were otherwise that aren't possible as it is now. As the elaborate example shows, you can use a scripted powerup to switch on and off other powerups.

User avatar
Graf Zahl
GZDoom Developer
GZDoom Developer
Posts: 7148
Joined: Wed Jul 20, 2005 9:48
Location: Germany
Contact:

Re: ScriptedEffect experimental builds

Post by Graf Zahl » Mon Jun 08, 2009 21:02

And this inventory linking obviously means that inventory items cannot have their own inventory.

baghead
Hosted
Posts: 37
Joined: Tue Dec 16, 2008 3:26
Contact:

Re: ScriptedEffect experimental builds

Post by baghead » Mon Jun 08, 2009 22:56

An actor has one inventory pointer. Just one. But it serves as a linked chain. Every other thing in the actor's inventory are actually in the inventory's inventory, and the inventory's inventory's inventory, and so on.
So the inventory is a linked list, and every actor gets a pointer to the first item in his list? Makes sense.
And this inventory linking obviously means that inventory items cannot have their own inventory.
It would be great if they could... I'm sure you two could figure out a way ;) In actor form, CustomInventory and Weapon items do have an inventory. That's the real use I had in mind for this. I've always wished there was a way to transfer a CustomInventory item's inventory to the player when it is picked up, or do other things based on the CI's properties or inventory during the pickup state.

Examples:

- Player 1 tosses a sack containing 500 gold coins, 30 iron bolts and a light crossbow to Player 2.
- Player drops plasma cannon loaded with 520 cells to lighten his load. Later he returns for it.
- Player encounters a soft leather armor and casts enchant on it, giving it some Enchanted counters. Player picks up the armor; armor gives player extra armor points per Enchanted counter in the pickup state (can't be done because CI actor is already destroyed?)

If inventory items (and scripted effects) could have their own separate inventory, all kinds of stuff could be done. Just one example:

- Player encounters a robe and throws a potion of Resist Poison at it, giving it some PoisonResistant items. Player picks up and equips the robe; robe gives player same number of PoisonResistant items while worn (as a scripted effect).
The player. Just use the very useful "printinv" console command to check.
I would, but you didn't include a patch ;)

User avatar
Gez
Developer
Developer
Posts: 1393
Joined: Mon Oct 22, 2007 16:47

Re: ScriptedEffect experimental builds

Post by Gez » Mon Jun 08, 2009 23:53

baghead wrote:I would, but you didn't include a patch ;)
Unless the file "scriptedeffect.patch" was deleted by FTP gremlins, it should be there because it is present in the zip I uploaded.

Example 1: how could the player choose what goes in the sack? It'd require a complete redesign of the inventory system to obtain something Ultima-like.

Example 2: a design decision has been made that when dropping weapons or backpacks, you drop them without ammo. It could be changed, but again, how would the player choose how much stuff is in the weapon or backpack?

Example 3: to make this work, it would require much, much more than a change in the way inventories are handled.

baghead
Hosted
Posts: 37
Joined: Tue Dec 16, 2008 3:26
Contact:

Re: ScriptedEffect experimental builds

Post by baghead » Tue Jun 09, 2009 1:06

Gez wrote: Unless the file "scriptedeffect.patch" was deleted by FTP gremlins, it should be there because it is present in the zip I uploaded.
Oops, I assumed those were just binaries.
Example 1: how could the player choose what goes in the sack? It'd require a complete redesign of the inventory system to obtain something Ultima-like.
Well, here's one possible way: Allow sack actors to pick up items. Drop the sack on the ground. Drop some items "into" the sack. There you go, items in a sack. All that's needed is a way for the pickup to transfer inventory to the picker-upper so whoever gets the sack will get the original items.
Example 2: a design decision has been made that when dropping weapons or backpacks, you drop them without ammo. It could be changed, but again, how would the player choose how much stuff is in the weapon or backpack?
I don't want to change it. The normal drop command would still act the same, the modder would have to do his own drop routine and put the ammo in the dropped weapon himself. The modder would decide how much ammo is dropped with each weapon... energy weapons could leave all the ammo with the weapon, clip weapons could just leave the rest of the loaded clip, etc.
Example 3: to make this work, it would require much, much more than a change in the way inventories are handled.
As far as I can tell it would require that the pickup actor is not removed until after the pickup state runs, and that both actors (not just the picker-upper) could be accessed from the pickup's state block. Is there something I'm missing? I'm not talking about changing the current pickup behavior, of course... maybe just adding a flag or something to allow them to behave like this.

So with the flag, pickups could work like this:

Pickup actor's target is set to the picker-upper immediately before pickup state runs (for ActivateTarget).
Pickup actor is not removed from play until immediately after pickup state runs.
Pickup state is activated as the pickup actor.

Then it would be up to the modder to transfer items or whatever in the pickup state; the important thing is you've got access to the pickup actor during the pickup event. The more I think about it, actually, the more it seems like this doesn't apply as much to scripted effects as it does to pickups, since the item's inventory ceases to exist after it's been picked up, and since powerups have to be given by another actor anyway. So yeah, for it to work with scripted effects I guess inventory items would need to have their own inventories... But I don't see why it would be necessary for simple CustomInventory pickups (although it would certainly be useful).

/hijack

User avatar
Gez
Developer
Developer
Posts: 1393
Joined: Mon Oct 22, 2007 16:47

Re: ScriptedEffect experimental builds

Post by Gez » Tue Jun 09, 2009 15:00

For these things to work, you'd need to make pickups shootable at the very least -- otherwise, you can't target them with enchantment effects. This means they have to be solid, so they'll block the players unless they're picked up.

To make pickups pick up other pickups, you need to give them Brownian motion, because picking things up is managed by the collision system. Which can lead to unpredictable results. You'll see bags randomly creeping left and right, and sometimes eating other bags.

Urgh.


I'd rather you forget it. :P Hey, look at the ST compat builds. I've introduced BUMPSPECIAL, and I've left the scripted effect code in. You could use obstacles (not pickups) which manage their inventory through DECORATE scripting and execute a "I'm being picked up" ACS script when the player collides with them, making them disappear and instead spawn an appropriate predetermined CustomInventory. That's about as far as that's gonna go.

baghead
Hosted
Posts: 37
Joined: Tue Dec 16, 2008 3:26
Contact:

Re: ScriptedEffect experimental builds

Post by baghead » Tue Jun 09, 2009 20:07

you need to give them Brownian motion
Yeah, I was hoping you wouldn't catch that ;p but I'd do it in a pattern, not at random, so there'd be no creep. Still an awful hack though.

The having to be solid to be shootable thing I didn't think of... I'll have to see what happens when the player runs over solid pickups, now I'm curious.

The BUMPSPECIAL thing sounds good, but if it works anything like USESPECIAL, the player will be the activator of a script rather than the actor being bumped. Back to the same problem again, how do we reference the actor that got bumped (unless the activator is actually the thing getting bumped, which would make a hell of a lot more sense to me but would be less consistent I guess)?

User avatar
Gez
Developer
Developer
Posts: 1393
Joined: Mon Oct 22, 2007 16:47

Re: ScriptedEffect experimental builds

Post by Gez » Tue Jun 09, 2009 20:35

baghead wrote:Yeah, I was hoping you wouldn't catch that ;p
Problems don't go away when they're not noticed; to the contrary they tend to multiply in these conditions. :P
baghead wrote:The BUMPSPECIAL thing sounds good, but if it works anything like USESPECIAL, the player will be the activator of a script rather than the actor being bumped. Back to the same problem again, how do we reference the actor that got bumped (unless the activator is actually the thing getting bumped, which would make a hell of a lot more sense to me but would be less consistent I guess)?
Yeah. That's why I said you could use it to script the pickup: each fake pickup item has a different script (or, more simply, a different script parameter) and they know who picked them up because they're the activator. It wouldn't allow pickups to pick up other pickups ( :blergh: ugh) but it would let you target them with crazy effects.

baghead
Hosted
Posts: 37
Joined: Tue Dec 16, 2008 3:26
Contact:

Re: ScriptedEffect experimental builds

Post by baghead » Tue Jun 09, 2009 21:19

Ok, sorry to bring this thread so far off-topic... for the record the bag thing was just an example, I really have no intention of doing anything like it, it was just an example of one way the player could get items into a pickup actor's inventory.

About the spell casting thing, my idea was that the spells would leave their effect on the item in the form of inventory items... user-made counters to track Charmed, Cursed, +Damage, +Accuracy, FooResistant, etc. So now you have a pickup (or bumpable, or scripted effect giver, or whatever) with a inventory representing some special properties that this item acquired "in the field."

I just can't for the life of me figure out a good way to access that inventory when the player gets the item, and it seems like it would make sense from a modding standpoint if I could. It's not so much that I want items to pick up other items; I really just want a way to access an item's inventory when it's picked up. Obviously scripted effects are not going to help, so I won't continue to derail your thread. Sorry about that.

Hey, actually, maybe this would work with bumpables and a script parameter like you said (that's what I used for the barrels in zokoban) if I can make sure every pickup is assigned a unique tid and the script parameter matches the tid. Messy, but it ought to work. I might look into trying to add a flag to change pickup behavior as I described earlier... I guess you see what I'm trying to do now anyway ;)

User avatar
Graf Zahl
GZDoom Developer
GZDoom Developer
Posts: 7148
Joined: Wed Jul 20, 2005 9:48
Location: Germany
Contact:

Re: ScriptedEffect experimental builds

Post by Graf Zahl » Tue Jun 09, 2009 21:19

baghead wrote: The BUMPSPECIAL thing sounds good, but if it works anything like USESPECIAL, the player will be the activator of a script rather than the actor being bumped. Back to the same problem again, how do we reference the actor that got bumped (unless the activator is actually the thing getting bumped, which would make a hell of a lot more sense to me but would be less consistent I guess)?

... and now take a guess why I haven't implemented it myself when I did USESPECIAL. Right! Because it's more or less useless in the way Skulltag implemented it!

Locked

Return to “Experimental Builds”