As of 28-02-18, SNPCs have been removed from /tg/station. This page is maintained as a historical archive.
See the Pull Request here: #36016
See the Pull Request here: #36016
Writing a SNPC module
Writing a module for an SNPC is easy, but several things need to be kept in mind for optimum process:
- Modules are processed in a linear, but staggered fashion (from left to right in the /list/functions).
- Modules use sleep(1) to run them, and thus they are queued behind each other in the execution time.
- Modules that interrupt normal function, or edit NPC vars, should use isNotFunc() as the first proc, else strange problems will occur.
Item Handling
Item handling (such as keeping hands free, putting in bags etc) should be mostly done by the main loop, so it is safe to just call take_to_slot(/obj/item), and the NPC does the rest.
Existing Modules
It has several pre-made modules, which are as follows:
- Nearbyscan: keeps a list of nearby mobs.
- Combat: handles all the default combat actions.
- Doorscan: keeps a list of nearby doors.
- Shitcurity: handles using handcuffs on people.
- Chatter: handles bot responses and random chatter.
NPC traits
NPCs can be "varied" from each other in several ways:
- The five "trait" vars, which are set from 1 - 100, used as prob(trait):
- Robustness: Determines how often they should perform a robust action (hit right, break things)
- Smartness: Usually used as a negative (!prob(smartness)), indicates how often they should do "smart" things, like use an object or speak.
- Attitude: Determines how often they will retaliate and/or fight things.
- Slyness: Determines how often they will do "illegal" actions, ie stealing.
- Greytide: A 1/0 bool, Overrides most behaviour and causes the NPC to act like a "greytider", breaking things and hurting people.
NPC base functions
Accessing NPC base functions and controlling them:
- Overall, the NPC uses the var "interest" to determine how long they have been doing something, if interest peaks under certain amounts, the NPC will shift to doing something else. Interest goes up while the "doing" var is not equal 0 (has bitflags assigned).
- NPCs keep track of their ID and their PDA using the MYID and MYPDA variables. These are direct references to the items, and can be used to activate, unlock/lock, and do all things both would do in general.
- NPCs also keep track of what is their hands in a "smart" way. The variables "main_hand" and "other_hand" reference the l_hand and r_hand of the NPC, but are shifted (and can be forced using enforce_hands()) when then NPC drops items, changes items etc, to make sure there is always something in the main_hand. The var "update_hands" can be set to 1 to force a recheck of hands (such as when picking items up)
- NPCs have two variables, TARGET and LAST_TARGET, which are used primarly for combat recognition. Setting TARGET to anything other than null will cause the Combat module to attempt to fight that target. LAST_TARGET is the last var TARGET has been set to. Additionally, the var "retal_target" refers to the last person to attack the NPC.
- NPCs have a custom travel proc, tryWalk(var/turf), which will attempt to walk them to the target. In cases where you want to force them to walk (such as sidestepping in combat, dancing etc), use walk2derpless(var/target) directly.
- Most interaction that NPCs do with the world should use target_filter(var/target) and denied_filter(var/denied) to check if they are valid targets.
Doing Var
- The "doing" var has three distinct flags that are checked and changed for what the NPC is doing.
- INTERACTING: defines that an NPC is interacting with something.
- FIGHTING: defines that an NPC is in combat.
- TRAVEL: defines that an NPC is moving from one location to another.
- "doing" is a bitflag and can be changed with doing |= flag to add a flag, or doing = ~doing&flag to remove one.
Designing a module
- Modules should not interrupt the flow of other modules, nor should they try to take precidence. Treat modules as an extra "task" for the NPC, Like crafting an item or opening a door.
- Modules handling Inventory items should make use of take_to_slot(var/obj) and insert_into_backpack() to do automated handling of item and hands.
- Once a module is created, add it to the var/list/functions and it will be automatically executed.
Misc variable
- Several Variables exist for ease of use, these include:
- MAX_RANGE_FIND and MIN_RANGE_FIND are the Max/Min range an NPC searches for things.
- FUZZY_CHANCE_HIGH and FUZZY_CHANCE LOW are the high and low for a lot of NPC probability that isn't trait related roll.
- CHANCE_TALK is the probability the NPC will say things.
- TRAIT_* are bitflags that can be used to give the NPC special checks, such as always stealing things (TRAIT_THIEVING) or never fighting (TRAIT_FRIENDLY)