Sometimes, you want monsters, players, or other actors to do a lot of things at once, while it's doing other things. For example, if you wanted to make a standard imp do something interesting in its See state if it's fully submerged underwater, you might do something like this:
See:
TROO A 0 A_JumpIf(waterlevel == 3, 2)
TROO A 0 A_ChangeFlag("NoPain", 0)
Goto See+3
TROO A 0 A_ChangeFlag("NoPain", 1)
TROO A 3 A_Chase
TROO A 0 A_JumpIf(waterlevel == 3, 2)
TROO A 0 A_ChangeFlag("NoPain", 0)
Goto See+7
TROO A 0 A_ChangeFlag("NoPain", 1)
TROO A 3 A_Chase
TROO B 0 A_JumpIf(waterlevel == 3, 2)
TROO B 0 A_ChangeFlag("NoPain", 0)
Goto See+11
TROO B 0 A_ChangeFlag("NoPain", 1)
TROO B 3 A_Chase
TROO B 0 A_JumpIf(waterlevel == 3, 2)
TROO B 0 A_ChangeFlag("NoPain", 0)
Goto See+15
TROO B 0 A_ChangeFlag("NoPain", 1)
TROO B 3 A_Chase
TROO C 0 A_JumpIf(waterlevel == 3, 2)
TROO C 0 A_ChangeFlag("NoPain", 0)
Goto See+19
TROO C 0 A_ChangeFlag("NoPain", 1)
TROO C 3 A_Chase
TROO C 0 A_JumpIf(waterlevel == 3, 2)
TROO C 0 A_ChangeFlag("NoPain", 0)
Goto See+23
TROO C 0 A_ChangeFlag("NoPain", 1)
TROO C 3 A_Chase
TROO D 0 A_JumpIf(waterlevel == 3, 2)
TROO D 0 A_ChangeFlag("NoPain", 0)
Goto See+27
TROO D 0 A_ChangeFlag("NoPain", 1)
TROO D 3 A_Chase
TROO D 0 A_JumpIf(waterlevel == 3, 2)
TROO D 0 A_ChangeFlag("NoPain", 0)
Goto See+31
TROO D 0 A_ChangeFlag("NoPain", 1)
TROO D 3 A_Chase
Loop
//Don't quote me on this, I haven't tested it. Just an example of what it might look like
TROO A 0 A_JumpIf(waterlevel == 3, 2)
TROO A 0 A_ChangeFlag("NoPain", 0)
Goto See+3
TROO A 0 A_ChangeFlag("NoPain", 1)
TROO A 3 A_Chase
TROO A 0 A_JumpIf(waterlevel == 3, 2)
TROO A 0 A_ChangeFlag("NoPain", 0)
Goto See+7
TROO A 0 A_ChangeFlag("NoPain", 1)
TROO A 3 A_Chase
TROO B 0 A_JumpIf(waterlevel == 3, 2)
TROO B 0 A_ChangeFlag("NoPain", 0)
Goto See+11
TROO B 0 A_ChangeFlag("NoPain", 1)
TROO B 3 A_Chase
TROO B 0 A_JumpIf(waterlevel == 3, 2)
TROO B 0 A_ChangeFlag("NoPain", 0)
Goto See+15
TROO B 0 A_ChangeFlag("NoPain", 1)
TROO B 3 A_Chase
TROO C 0 A_JumpIf(waterlevel == 3, 2)
TROO C 0 A_ChangeFlag("NoPain", 0)
Goto See+19
TROO C 0 A_ChangeFlag("NoPain", 1)
TROO C 3 A_Chase
TROO C 0 A_JumpIf(waterlevel == 3, 2)
TROO C 0 A_ChangeFlag("NoPain", 0)
Goto See+23
TROO C 0 A_ChangeFlag("NoPain", 1)
TROO C 3 A_Chase
TROO D 0 A_JumpIf(waterlevel == 3, 2)
TROO D 0 A_ChangeFlag("NoPain", 0)
Goto See+27
TROO D 0 A_ChangeFlag("NoPain", 1)
TROO D 3 A_Chase
TROO D 0 A_JumpIf(waterlevel == 3, 2)
TROO D 0 A_ChangeFlag("NoPain", 0)
Goto See+31
TROO D 0 A_ChangeFlag("NoPain", 1)
TROO D 3 A_Chase
Loop
//Don't quote me on this, I haven't tested it. Just an example of what it might look like
Pretty obviously, this is hilariously ugly, can bug out easily if not done right, and you have to keep close track of your jumps, gotos and etc. THERE IS A BETTER WAY TO DO THIS!
In "real" programming, if you have one function that does the same thing repeatedly in a sequence with other stuff, we outsource that repeated thing to another function and call that, so it looks cleaner and is easier to troubleshoot. This is why, for example, A_MissileAttack has A_FaceTarget built in, instead of calling it with a 0-delay just beforehand. Unfortunately in Decorate, we can't define new functions (the A_ things)... But we have CustomInventory!
CustomInventory, by definition, is an item that allows you to define a Pickup state (or Use, but we want Pickup for this) with existing functions to make a powerup or other item that does anything you want it to do, with a few limitations. These functions in the Pickup and Use states are executed BY THE ACTOR WHO PICKED UP THE ITEM, not the item itself. Thus, we can slap some of those functions we have in a CustomInventory item, and A_GiveInventory it so we can execute those checks and flag changes to one call!
Yes! As the wiki page says, monsters can have items! They have no code for picking up items (for good or ill), so they either have to give it to themselves or it has to be done in ACS.
See:
TROO AABBCCDD 3 A_GiveInventory("ImpWaterCheck", 1) //Execute our new function!
Loop
Actor ImpWaterCheck : CustomInventory
{
Inventory.PickupMessage ""
Inventory.PickupSound ""
-CountItem
states
{
Spawn:
TNT1 A 1
Fail //We don't want this ever spawning.
Pickup:
TNT1 A 0 A_Chase
TNT1 A 0 A_JumpIf(waterlevel == 3, "Underwater")
TNT1 A 0 A_ChangeFlag("NoPain", 0)
Stop
Underwater: //Because new states are just awesome
TNT1 A 0 A_ChangeFlag("NoPain", 1)
Stop
}
}
TROO AABBCCDD 3 A_GiveInventory("ImpWaterCheck", 1) //Execute our new function!
Loop
Actor ImpWaterCheck : CustomInventory
{
Inventory.PickupMessage ""
Inventory.PickupSound ""
-CountItem
states
{
Spawn:
TNT1 A 1
Fail //We don't want this ever spawning.
Pickup:
TNT1 A 0 A_Chase
TNT1 A 0 A_JumpIf(waterlevel == 3, "Underwater")
TNT1 A 0 A_ChangeFlag("NoPain", 0)
Stop
Underwater: //Because new states are just awesome
TNT1 A 0 A_ChangeFlag("NoPain", 1)
Stop
}
}
It requires a new CustomInventory item, but we've just made our See state much easier to follow. Now, keep in mind, CustomInventory items CANNOT have delays! Nor would we want them to in this case because it we want all of this to happen immediately when it's given. Still, CustomInventory items can't have delays, and no matter what number you put in, it'll still execute all of it with 0 delays. Now, I really don't recommend this for just collapsing a few 0-delay things together, but it's ideal for when you have checks, jumps and things like that in a looping state, because that gets difficult to manage how the state flows.
Another thing I like to use this for is when I have a monster that is heavily built in to some ACS scripts. If you want to use an ACS script change a flag on a monster, for example, but don't want to use SetActorState (and risk interrupting an animation), you can give a CustomInventory item that does it.