NEO Scavenger Modding Documentation
The NEO Scavenger XML file is pretty daunting, so I will start adding some documentation here to explain the various fields.
How IDs Work
- AA - The ID of the data set we're loading from
- BB - The ID of the thing we want in that data set
- CC - The optional subgroup ID of the thing we want (for items that have IDs like BB.CC)
Most data within NEO Scavenger is referred to by an ID. The condition for "Hungry" is condition ID 5, the "dogman" is creature ID 1, and the opening cryo encounter is encounter ID 2. There are even a few complex IDs, such as items. E.g. the "medium branch" item is ID 13.0, 13 for the group ID, and 0 for the subgroup ID.
Everything in the game uses these IDs when referring to other things. So if a dogman has "strong" as a starting condition, the creature data for the dogman specifies "60" as a starting condition.
However, these IDs can become a problem if other mods or the base game use the same ID for something different. For example, what if you have a mod that includes a car tire with ID "13.0"? The base game has "13.0" set to a medium branch, so if you mention "13.0" in your mod, the game needs to know which "13.0" you want. Base game version or the mod version?
That's where prefixes come in (the AA: above). You can specify which data set you mean before the ID by prefixing the ID with the data set's ID and a colon. If no prefix is specified, the game will assume you mean the version in the current mod you're editing. Otherwise, it will assume you mean the version in the mod you specify.
E.g. itemID=13.0 will reference this mod's copy of 13.0
If a mod wants to reference the base game data, it must specify mod "0".
E.g. itemID=0:13.0 will reference base data's copy of 13.0
And if a modder wants to reference another mod, just replace "0" with that mod's name.
E.g. itemID=DeFactoMod:13.0 will reference DeFactoMod's copy of 13.0
The benefit to a system like this is that modders can each use whatever IDs they want without worrying about whether another mod will conflict. The game will just sort everything out behind the scenes, as long as the AA: prefix is there when needed.
Conceptually, it's easiest to think of encounters as nodes connected by arrows. Like a flowchart. This is an example of what the encounter editor looks like:
Before anyone asks, the editor won't do you any good. It doesn't read XML files. Instead, it reads data from a mySQL database running on a local server. I just export the database into XML format because most modders don't have a database running on a server they can use.
Though, if tech-savvy modders are able to setup a database...
Anyway, as you can see above, encounters are gray "nodes" connected by colored arrows. In the XML file, an encounter consists of one of those gray boxes, and all outgoing arrows.
All encounters have the following fields (* are required):
- id* - The unique ID for this encounter (easiest to just add 1 to the previous highest number)
- strName* - Shows up as yellow text if the player has a choice of inputs. Invisible if not.
- strDesc* - The main text. The longest text I've got in one encounter panel is about 130 words. Probably 150 is the limit that will fit on-screen in the game. Longer text needs to be split into subsequent panels (no-choice arrows), so it's better to break them up if they're getting long.
- strImg - The image to display for the panel. Not specifying a picture defaults to a snapshot of the current hex (like battle).
- nItemsID - The special encounter items available in this panel. This is stuff like the broken cryo window or control panel, which only exist in the context of the encounter. Regular items and skills in the player's possession are added automatically in-game based on the possible outcomes, and only if the player has them.
- nTreasureID - Loot to give to the player in this panel. Used for quest items, rewards, etc. Indexes into the treasuretables.
- nRemoveTreasureID - Items to remove from the player in this panel (usually turning in quest items, but could be lost/broken items, etc.). Indexes into the treasuretables.
- aPreConditions - Player conditions that must be present for this encounter to be valid. If the player is missing the requisite condition, this panel will not appear. This is often used in conversations to separate initial conversations from follow-up conversations. It can also be used to hide/show certain panels based on skills or present items. E.g. player must have cholera to see this node, or player must not have visited DMC yet to see this node, etc. Comma-separated list of IDs of conditions. Putting a "-" before a condition ID means this condition must not be on the player to trigger.
- aConditions - Player conditions this panel applies or removes when done. (E.g. injury, flags denoting a conversation was had, etc.) Comma-separated list of IDs of conditions. Putting a "-" before a condition ID means this condition will be removed.
- fPrice - The amount of money deducted when reaching this node. If player does not have enough money, node is not shown.
- nCreatureID - The ID of the creature spawn group this panel spawns. E.g. spawn dogman when exiting cryo. (Currently, these IDs are hidden in code. I need to break them out of code at some point.)
- ptCreatureHex - The hex coordinates where the creature will appear, if applicable. E.g. "40,0" is (radius, direction), and spawns the creature 40 hex rows (radius) due north (direction). Direction is 0-based hexes clockwise from north in the destination hex ring. So hex ring radius 0 is the current hex, radius 1 is the 6 hexes around that, 2 is the 12 around that, etc.
- ptTeleport - The hex coordinates (radius, direction) where the player will be teleported to. Specifying X-only will randomly teleport the player in a ring of radius X. Uses same radius/direction spec as ptCreatureHex, above.
- aMinimapHexes - The coordinates (map x,y) of a hex to reveal, with optional text label for map. Used in the Hatter urn quest, and the glow reveal. E.g. "20x164=Gyges Cryo Facility" reveals hex (20,164) with label "Gyges Cryo Facility."
- bRemoveCreatures - Whether this panel removes creatures from the current hex or not. Useful for guaranteeing current hex is empty. 0 = false, 1 = true.
- bRemoveUsed - Removes from player whichever item was used to reach this node. Useful when generic item types are used to reach a node, rather than specific items (e.g. any light source) 0 = false, 1 = true.
- nType - Whether this is a normal encounter or not. Encounter types include normal (0), scavenge (1), battle (2), and hacking (3).
- fLootChance - The change in loot chance this panel creates, if chosen in a scavenge encounter. 0.0 = 0%, 1.0 = 100%.
- fAccidentChance - The change in accident chance this panel creates, if chosen in a scavenge encounter. 0.0 = 0%, 1.0 = 100%.
- fCreatureChance - The change in creature chance this panel creates, if chosen in a scavenge encounter. 0.0 = 0%, 1.0 = 100%.
- vAccidents - A list of accidents to choose from if this scavenge encounter produces an accident. Comma-separated IDs for encounters.
- vLoot - Additional loot added to regular scavenge loot if this option is chosen in a scavenge encounter. Comma-separated IDs which are indices for the treasuretables.
- ptEditor - The in-editor coordinates of the node. Ignored by game.
aResponses warrant special mention, since they are pretty complicated and also important. These are basically the arrows seen in the image above, and control which encounters one can reach from here, and how.
The format is a series of formulae separated by commas. A formula looks like this:
- AA - The nGroupID of the required item
- BB - The nSubGroupID of the required item
- CC - The number of AA.BB items required.
- DD - The ID of the encounter this choice results in.
- EE - The chance of this outcome happening. 1.0 = 100%, 0.0 = 0%. (Used in cases where more than one outcome is possible at the same time. The total chance of all valid outcomes for a set of input items must be 1.0.)
- FF - The number of "per-use" charges consumed.
- GG - The number of "per-hour" charges consumed.
- HH - The number of "per-hex" charges consumed.
- =1x1x0x0x0 - If no inputs are specified, go to encounter 1 (blank, which ends the encounter), 100% chance, 0 charges used.
- =16x1x0x0x0,=3x1x0x0x0 - If no inputs are specified, go to encounter 16 or 3, depending on which one is valid. 100% chance and 0 charges used, either way.
- 90.3x1=20x1x0x0x0,90.4x1=1320x1x0x0x0,=7x1x0x0x0 - If one item 90.3 is used, go to encounter 20. If one 90.4 is used, go to encounter 1320. If nothing is used, go to 7.
- 86.0x5+46.0x1=1037x1x0x0x0 - If five 86.0s and one 46.0 are used, go to encounter 1037.
- 49x1=930x1x0x1x0 - If you omit the ".BB" in the formula, the game will think you're asking for an ingredient rather than a specific item. In this case, #49 is "handheld lightsource," and will result in encounter 930 with 1 "per-hour" charge deducted.
There are lots of tricks that I've learned in this system, and too much for me to get into right now. But you can do things like =AAx1x0x0x0 where AA is the ID of the current encounter, and this will cause the encounter to point back to itself. This is useful for forcing the player to make a choice, as the encounter will end if no choice is valid.
BattleMoves are the data type that control what combatants can do during any given combat turn. They include not only attacking with the wielded weapon, but also movement, surrender, exiting battle, talking, and special moves. If it happens during battle, it needs a BattleMove.
- id - unique ID
- strID - item ID used to display this move (e.g. 90.33 = green crosshair icon)
- strName - name of battle move
- strNotes - unused in-game. notes to myself.
- strSuccess - message displayed if succeeded. <us> gets auto-replaced with actor's name, <them> is recipient
- strFail - message displayed if failed. <us> gets auto-replaced with actor's name, <them> is recipient
- strPopUp - pop-up/tooltip text
- vChanceType - type of random check (see below) to make when checking if the overall move succeeds
- vUsConditions - list of conditions and random checks (see below) this applies to us if we succeed
- vThemConditions - list of conditions and random checks (see below) this applies to them if we succeed
- vPairConditions - list of conditions and random checks (see below) this applies to the pair if we succeed (e.g. range changes require a pair to operate on, as "us" is meaningless without someone to change range against)
- vUsFailConditions - same as vUsConditions above, except this is for the fail case
- vThemFailConditions - same as vThemFailConditions above, except this is for the fail case
- vPairFailConditions - same as vPairFailConditions above, except this is for the fail case
- vUsPreConditions - list of conditions we must have (or not have) for this move to be available
- vThemPreConditions - list of conditions they must have (or not have) for this move to be available
- nSeeThem - 0=can only do this if they are unseen, 1=seen, 2=doesn't matter
- nSeeUs - 0=can only do this if we are unseen, 1=seen, 2=doesn't matter
- bAllOutOfRange - 1=can only do this if all hostiles are beyond their attack ranges, 0=doesn't matter
- bInAttackRange - 1=can only do this if we are in our attack range, 0=doesn't matter
- nMinCharges - minimum # charges we must have for current attack mode (if any)
- nMinRange - minimum range we can use this move
- nMaxRange - maximum range we can use this move
- nAttackModeType - 0=melee, 1=ranged, -1=any
- vHexTypes - list of hex types in which this move is available. empty=all
- fChance - chance of this move appearing if above conditions are met. 1.0 = 100%
- fPriority - priority of this move compared to other moves. AI will prefer higher priorities over lower.
- fDetect - chance of this move revealing us (multiplier against normal chance)
- fOrder - order in which this move is executed in a turn. 0.0 happens sooner than 1.0
- fFatigue - amount of fatigue this move costs
- bApproach - used by AI to tell if this move will approach target. 0=no, 1=yes
- bOffense - used by AI to tell if this move will attack target. 0=no, 1=yes
- bFallBack - used by AI to tell if this move will fall back from target. 0=no, 1=yes
- bRetreat - used by AI to tell if this move will retreat battle. 0=no, 1=yes
- bPosition - used by AI to tell if this move will stay put/prepare. 0=no, 1=yes
- bPassive - used by AI to tell if this move is passive/non-combat (e.g. talking). 0=no, 1=yes
A random check can be one of several types, but they all follow the same format:
or if the field supports a list of more than one type:
- nCondition is the condition ID that gets applied if chance passes
- nCheckType is the ID for the type of check to make (see below)
- fChance is a parameter passed into the check type specified (usually a chance or chance modifier)
and the nCheckType IDs are:
- =happens no matter what
- =requires a melee attack roll to happen
- =requires a ranged attack roll to happen
- =requires a terrain trip roll to happen
- =requires a terrain trip roll to happen (modified by next term, e.g. 2.0 is double chance)
- =requires a morale check to happen
- =requires a flat probability to happen (specified in next parameter)
- =requires an escape check to happen
Item Group IDs
An item's nGroupID can be important for some item types, but most can be anything. The nGroupIDs to watch out for are:
9, //recipe scrap
20, //crippled (e.g. blocks hands if arm crippled)
25, //terrain resource (e.g. forest, lake, power tap)
26, //camp fixture (e.g. HVAC, light)
90, //encounter item (e.g. cryo console, cryo window)
103 //scavenge location
weapons can be anything, as can clothes.
Item Slot Info - Complete list of slot IDs and properties. Also includes wound slot IDs and props. Covers things like aPossessConditions, aUseConditions, vEquipSlots, vUseSlots, and maybe some others. Especially wounds.
Condensed List of properties - Complete lists of ingredient, item property, container IDs, aFieldNames, and aEffects for reference.
Complete List of Item nGroupIDs - Complete list of nGroupIDs for items.
Item Field and Misc Info - Includes some creature field and attackmode talk.
Creature Fields - Details the complete list of creature fields and functions, for AI, player, and shared fields.
There are also a few fields there which can be used to control conditions on creatures. In particular:
SetPlayerCondition (for AI creatures.)
TriggerEncounter AI can have encounters trigger on them, too.)
SetImmunity (prevent certain conditions on a creature)
Condition durations/removal are controlled primarily by:
fDuration - duration in hours (if > 0 condition disappears when expired, if 0 condition remains until removed manually)
bResetTimer - condition duration reset if stacked
bRemoveAll - removing one from stack removes all
bRemovePostCombat - stripped when exiting battle
bStackable - controls whether effects increment when more than one copy applied. a condition's stack must reach 0 before disappearing from creature, unless timer or bRemoveAll say otherwise
bPermanent - this one's tricky, as it actually means the effects are permanent, not the condition. I.e. the condition's effects are applied, and then no record of the condition is maintained (so it can never be removed without applying an opposite effect later).
Understanding Hex Map Coordinates
Note that the y values increase by 2 each full hex height, with each column having either odd or even y values, not both. And the x coordinate is shared by two staggered columns.
In game terms, the distance between two hexes is usually calculated as the number of moves to reach the new hex from the old one, not the x and y coordinate differences.
In the above image, a radius of 2 hexes from the player would include:
...and all hexes within that.
An important note to remember is that triggers are only added at the beginning of a game. If you add new encountertriggers to your mod, you will not see them in old save games!
More info soon!
Dan Fedor - Founder, Blue Bottle Games