States, Patterns, Execute Patterns

States, Patterns, and Execute Patterns are the very main core of Postal3Script, these make up 100% of all scripts, and they are essentially the "AI".

States, Patterns, and Execution Patterns

  • Cannot exist without a behavior, they must be attached to a behavior.
  • Can be inherited, they can be overridden by creating the same state/pattern in the new behavior.

State Group

States have a group, this group can be Neutral, Alert, or Combat.
For non-NPCs these don't mean anything.
For NPCs however, they'll belong in that status group, for example it'll control their view/hear distance, and the game will force them to be in that NPC state.
This is a feature re-used from Half-Life 2/Source Engine.

State

Every State must have a Pattern called pt_default.

Note

All Entities in Postal 3 have an Init State, and Start State,
these are usually always called st_init and st_start.

Patterns

Patterns can be used in two ways, normally, or executed.
When normally used, the State will enter into that pattern, and will execute code normally.
When executed, the State will never enter into that pattern, but will execute the pattern's content.

Execute Pattern

When executing a pattern, some functions will not work.
Wait, Repeat and Pattern will never work, for Pattern you should use State instead.

Like here so:
State st_mystate.pt_mypattern

Naming Convention

Naming Convention

TM used a naming convention for Postal3Script, while it's not a must, it is still highly recommended to follow these to avoid confusion in the future:

  • Behaviors always start with bh_
  • States always start with st_
  • Patterns always start with pt_
  • Execute Patterns always start with xpt_

Inheritance

Postal3Script supports inheritance, states and patterns can be inherited, and they can be overridden when wanted.
In Postal 3 this is heavily used to split the NPC AI in parts.

Here's an example of inheritance:

// Main core
behavior
{
    name bh_core
    States
    {
        st_corestate
        {
            Group Neutral
            Patterns
            {
                pt_default
                {
                    actions
                    {
                        SetAttr "ea_health 0"
                    }
                }
            }
        }
    }
}

// Some behavior
behavior
{
    name bh_myai
    // Inherit from bh_core!
    inherited bh_core
    States
    {
        // Recreate the state to override it!
        st_corestate
        {
            Group Neutral
            Patterns
            {
                pt_default
                {
                    actions
                    {
                        SetAttr "ea_health 100"
                    }
                }

                xpt_coredefault
                {
                    actions
                    {
                        // Entering our core's state! We'll be absolutely dead.
                        State bh_core.st_corestate
                    }
                }
            }
        }
    }
}

In the example above in bh_core behavior we have a state called st_corestate, when entering it the entity will be dead, but the entity with the bh_myai behavior will not, and instead it will just reset it's health back to 100.

However, you can still access the core's state by executing xpt_coredefault pattern, this will jump over the overridden state and will just use the core's state instead.

Example of a Behavior with States and Patterns:

behavior
{
    name bh_mybehavior
    States
    {
        st_init
        {
            Group Neutral
            Patterns
            {
                pt_default
                {
                    actions
                    {
                        // Create a timer that fires an event every 2 seconds..
                        Timer tLoadCheck,2,repeated
                    }
                }
            }
        }

        st_start
        {
            Group Neutral
            Patterns
            {
                pt_default
                {
                    actions
                    {
                        SetAttr "loaded 1"
                    }
                    events
                    {
                        OnHit               "RemoveAttr loaded"
                        OnTimer_tLoadCheck  "ExecutePattern .xpt_check"
                    }
                }

                pt_dead
                {
                    actions
                    {
                        // dead, not big surprise
                    }
                }

                xpt_check
                {
                    actions
                    {
                        // Check if this attribute exist
                        CheckAttr "loaded Return 1"

                        // Well it doesn't exist anymore..
                        SetAttr "ea_health 0"
                        Timer tLoadCheck,0
                        Pattern pt_dead
                    }
                }
            }
        }
    }
}