Effects schema reference
effects.xml is the file inside a job directory that defines which stats, skills, and brothel properties change at the end of each shift. This page covers every element in the schema.
If you are new to job data files, start with docs/jobs-as-data/authoring-checklist.md for the per-port procedure and directory layout. For the <When> condition grammar used inside <Group>, see reference/when-conditions.md.
<Effects>: root element
Section titled “<Effects>: root element”The root of effects.xml. Contains any mix of <SetStat>, <SetSkill>, <SetBrothel>, <RandomChoice>, <Group>, <Bind>, and <Mod> entries. All top-level entries that are not inside a <Group> fire unconditionally every shift.
<?xml version="1.0" encoding="UTF-8"?><Effects> <!-- entries here --></Effects>Entries are executed in document order. There is no short-circuit evaluation between top-level entries. Every entry runs independently.
<SetStat>: apply a stat delta
Section titled “<SetStat>: apply a stat delta”Adjusts a girl’s stat by a fixed or random amount.
<SetStat target="self" stat="Tiredness" delta="5"/><SetStat target="self" stat="Happiness" delta_min="1" delta_max="3"/>| Attribute | Required | Notes |
|---|---|---|
target | Yes | Who receives the change. See “Targets” below. |
stat | Yes | Stat name. See “Stat names” below. |
delta | One of delta or delta_min+delta_max | Fixed integer delta. May be negative. |
delta_min | With delta_max | Minimum of a uniform random range (inclusive). |
delta_max | With delta_min | Maximum of a uniform random range (inclusive). |
If delta_min > delta_max the engine swaps them silently, so delta_min="-3" delta_max="-1" and delta_min="-1" delta_max="-3" are equivalent. This is intentional for readability when expressing “lose between 1 and 3 points.”
Targets for <SetStat>
Section titled “Targets for <SetStat>”| Target | Meaning |
|---|---|
self | The girl performing the job. |
brothel.girls | All girls currently assigned to the same brothel. Useful for morale/training auras. |
Stat names
Section titled “Stat names”Charisma, Happiness, Libido, Constitution, Intelligence, Confidence, Mana, Agility, Fame, Level, AskPrice, House, Exp, Age, Obedience, Spirit, Beauty, Tiredness, Health, PCFear, PCLove, PCHate.
<SetSkill>: apply a skill delta
Section titled “<SetSkill>: apply a skill delta”Adjusts a girl’s skill by a fixed or random amount.
<SetSkill target="self" skill="Service" delta="1"/><SetSkill target="self" skill="NormalSex" delta_min="2" delta_max="4"/><SetSkill target="self" skill="Lesbian" delta_min="-3" delta_max="-1"/>| Attribute | Required | Notes |
|---|---|---|
target | Yes | Who receives the change. Only self is supported in v1.13. |
skill | Yes | Skill name. See “Skill names” below. |
delta | One of delta or delta_min+delta_max | Fixed integer delta. May be negative. |
delta_min | With delta_max | Minimum of a uniform random range (inclusive). |
delta_max | With delta_min | Maximum of a uniform random range (inclusive). |
Skill names
Section titled “Skill names”Anal, Magic, BDSM, NormalSex, Beastiality, Group, Lesbian, Service, Strip, Combat, Performance.
<SetBrothel>: apply a brothel property delta
Section titled “<SetBrothel>: apply a brothel property delta”Adjusts a numeric property on one or more brothels.
<SetBrothel target="player.brothels" key="Fame" delta="3" clamp_max="100"/><SetBrothel target="brothel" key="Filthiness" delta="2"/>| Attribute | Required | Notes |
|---|---|---|
target | Yes | Which brothel(s) to update. See “Targets” below. |
key | Yes | Property name. See “Key names” below. |
delta | Yes | Integer delta. May be a literal or a bind reference ($bindname). See <Bind> below. |
clamp_max | No | If present, the result is clamped to this maximum after the delta is applied. |
Targets for <SetBrothel>
Section titled “Targets for <SetBrothel>”| Target | Meaning |
|---|---|
brothel | The brothel the girl is currently assigned to. |
player.brothels | Every brothel the player owns. Used by jobs that promote the player’s business city-wide (for example, a recruiter who raises Fame everywhere at once). |
Key names
Section titled “Key names”| Key | Notes |
|---|---|
Fame | How well-known the brothel is (0-100). Affects customer traffic. |
Filthiness | Cleanliness level of the building. High values reduce happiness and income. |
Happiness | Aggregate morale of girls in the brothel (0-100). |
<RandomChoice>: pick exactly one option
Section titled “<RandomChoice>: pick exactly one option”Selects exactly one <Option> at random, weighted by the weight attribute. Only the selected option’s children execute.
<RandomChoice> <Option weight="6"><SetStat target="self" stat="Exp" delta="0"/></Option> <Option weight="2"><SetSkill target="self" skill="Service" delta="1"/></Option> <Option weight="2"><SetSkill target="self" skill="Strip" delta="1"/></Option></RandomChoice><Option weight="N">
Section titled “<Option weight="N">”| Attribute | Notes |
|---|---|
weight | Positive integer. Selection probability is weight / sum_of_all_weights. |
An <Option> may contain any mix of <SetStat>, <SetSkill>, <SetBrothel>, and nested <RandomChoice> entries. An empty <Option> is not supported; use a <SetStat delta="0"> as a no-op placeholder when you want a probability sink (a branch that intentionally does nothing).
There is no minimum number of options, but a <RandomChoice> with a single option is equivalent to an unconditional entry and should be simplified.
<Group>: conditional block
Section titled “<Group>: conditional block”Groups one or more entries under an optional <When> gate. All entries inside the group execute if the <When> condition passes (or if no <When> is present). Groups do not short-circuit each other: if two groups are present, both are evaluated independently every shift.
<Group> <When> <Stat name="Tiredness" lt="50"/> </When> <SetStat target="self" stat="Happiness" delta="1"/> <SetStat target="self" stat="Tiredness" delta="3"/></Group>A <Group> may also contain <Bind> declarations (see below). Binds declared inside a group are scoped to that group and visible to the group’s <When> check and all entries inside it.
Complementary-pair pattern
Section titled “Complementary-pair pattern”Effects that depend on a threshold condition (such as “fire penalty if perf < 20, fire bonus if perf >= 20”) must use two separate groups with complementary <When> clauses. Do not assume the absence of one group’s <When> implies the other ran; the two groups are independent:
<Group> <When><Bind name="perf" lt="20"/></When> <SetStat target="self" stat="Tiredness" delta="2"/></Group><Group> <When><Bind name="perf" ge="20"/></When> <SetStat target="self" stat="Happiness" delta="1"/> <SetStat target="self" stat="Tiredness" delta="4"/></Group>Both groups are always evaluated. The first fires when the condition is true; the second fires when its own condition is true. Together they cover the full range.
<Bind>: derived integer
Section titled “<Bind>: derived integer”Computes an integer value from a formula and assigns it a name. The name can then be referenced in <When><Bind name="..." ge="N"/></When> and in delta="$name" on <SetBrothel>.
<Bind name="perf" expr="(Charisma + Intelligence + Service) / 3"/>| Attribute | Notes |
|---|---|
name | Identifier used to reference the value. Lowercase, no spaces. |
expr | Arithmetic expression over girl stats and skills. Integer arithmetic; division truncates toward zero. |
Evaluable identifiers in expr
Section titled “Evaluable identifiers in expr”All stat names and skill names listed under <SetStat> and <SetSkill> above are valid. For example: Charisma, Intelligence, Service, Happiness, Tiredness.
Referencing earlier binds (1.13.0+)
Section titled “Referencing earlier binds (1.13.0+)”A <Bind> may reference any bind declared earlier in the same <Group>, by name, anywhere its identifier could appear in expr. Binds are evaluated in declaration order, so a later bind sees the value of every bind above it.
<!-- Two-step bind: tier reads perf --><Bind name="perf" expr="(Charisma + Intelligence + Service) / 3"/><Bind name="tier" expr="perf / 20"/>The inline-formula workaround still works for packs that target older engine versions:
<!-- Inline form, equivalent and back-compatible --><Bind name="perf" expr="(Charisma + Intelligence + Service) / 3"/><Bind name="delta" expr="(Charisma + Intelligence + Service) / 60"/>A bind cannot reference a sibling declared later, and binds in one group are not visible from a different group.
A <Bind> may be declared at the top level of <Effects> (visible everywhere) or inside a <Group> (scoped to that group). The group-scoped form is preferred when the value is only used inside that group.
<Mod>: C++ pipeline bridge (legacy <RunHelper> accepted)
Section titled “<Mod>: C++ pipeline bridge (legacy <RunHelper> accepted)”Triggers a named C++ sub-pipeline from inside the data-driven executor. The element is registry-based: any name parses successfully, and the engine looks the name up at apply time. The legacy spelling <RunHelper name="..."/> is still accepted as a synonym.
<Mod name="whore_act"/><Mod> may appear inside <Effects> or, since 1.13.1, inside <Performance>. The latter is the right surface when the hook is producing a synergy multiplier the performance score should consume.
| Attribute | Notes |
|---|---|
name | Name of the registered helper to invoke. Looked up in the engine’s mod registry at apply time. |
Built-in registered names
Section titled “Built-in registered names”| Name | What it does | Direction |
|---|---|---|
whore_act | Runs the full per-customer loop for whore-archetype jobs: customer selection, refusal check, act performance, side effects. | (none; pipeline) |
work.barcook | Bar food synergy producer; publishes a per-Brothel food-quality scalar BarMaid + BarWaitress + BarWhore consume. | publisher (headcount/scalar) |
work.barmaid | Reads bar-staff headcount (Cook + Waitress) to scale tip income. | consumer (headcount) |
work.waitress | Reads BarMaid + BarCook presence to scale service multiplier. | consumer (headcount) |
work.barsinger | Reads piano_present to apply doubled-performance bonus when a Pianist is on shift. | consumer (presence flag) |
work.piano | Publishes piano_present binary flag the Singer reads. | publisher (presence flag) |
work.barwhore | Reads bar-staff headcount to scale income. | consumer (headcount) |
work.barstripper | Reads sleazybarmaid_present. | consumer (presence flag) |
work.sleazybarmaid | Reads barstripper_present (mutual cross-consumer pair). | consumer (presence flag) |
work.sleazywaitress | Reads barstripper_present. | consumer (presence flag) |
work.advertising | Hook stub; the actual m_AdvertisingLevel mutation lives in C++ until Wave 3 promotes double-typed brothel scalars into <Effects>. | bifurcated |
work.security | Hook stub; the actual m_SecurityLevel decay/recompute + threat-deterrence-from-headcount lives in C++ until Wave 3. | bifurcated |
work.masseuse | Hook stub; happy-ending-probability scaling against per-customer satisfaction lands in Wave 3+ via <JobState scope=customer>. | bifurcated (future) |
Most of the per-job hooks above are placeholders today: they fire mod_fired=true so the registry round-trip is observable, but the actual synergy transport (per-brothel scratch slots like piano_present / bar_staff_count / advertising_budget) ships in a future engine version. Today the synergy effect is whatever the engine’s job code computes; the data-side hook is a placeholder for the eventual transport hand-off.
For details on writing synergy-aware message variants that consume these hooks (and the four partner-direction shapes they come in) see visible-synergies.md.
Unknown <Mod> names parse successfully but silently no-op at apply time. This is intentional for forward-compat with future engine versions that may register the name; packs authored against a newer engine load cleanly on an older one rather than failing at parse time.
Common patterns
Section titled “Common patterns”1. Fixed stat penalty + optional skill gain
Section titled “1. Fixed stat penalty + optional skill gain”A simple job that always costs tiredness and has a 40% chance of gaining one of two skills:
<Effects> <SetStat target="self" stat="Tiredness" delta="5"/> <SetStat target="self" stat="Exp" delta="2"/> <RandomChoice> <Option weight="6"><SetStat target="self" stat="Exp" delta="0"/></Option> <Option weight="2"><SetSkill target="self" skill="Service" delta="1"/></Option> <Option weight="2"><SetSkill target="self" skill="Strip" delta="1"/></Option> </RandomChoice></Effects>Six out of ten shifts are no-ops on the <RandomChoice>; two out of ten gain Service; two out of ten gain Strip. The total weight is 10, matching the percent(40) then percent(50) pattern from legacy C++ (see resources/Jobs/houserecruiter/effects.xml for the full worked example with a derived performance bind).
2. Orientation-gated training (single file, multiple job slots)
Section titled “2. Orientation-gated training (single file, multiple job slots)”Three job slots that share one data directory but gate different effects on a <JobParam>:
<Effects> <Group> <When><JobParam name="orientation" value="straight"/></When> <SetSkill target="self" skill="NormalSex" delta_min="2" delta_max="4"/> <SetSkill target="self" skill="Anal" delta_min="1" delta_max="2"/> <SetSkill target="self" skill="Lesbian" delta_min="-1" delta_max="-3"/> <SetStat target="self" stat="Tiredness" delta="5"/> <SetStat target="self" stat="Exp" delta="2"/> </Group> <Group> <When><JobParam name="orientation" value="bi"/></When> <!-- ... --> </Group> <Group> <When><JobParam name="orientation" value="lesbian"/></When> <!-- ... --> </Group></Effects>The three groups are all evaluated every shift; only the one whose <JobParam> matches the registered slot parameter fires. See resources/Jobs/houseso/effects.xml for the full file.
3. Random skill pick from a pool (two independent draws)
Section titled “3. Random skill pick from a pool (two independent draws)”Two consecutive <RandomChoice> blocks to pick two skills from a pool of seven, each with equal probability. The same skill may be picked twice; the executor accumulates deltas correctly:
<Effects> <SetStat target="self" stat="Exp" delta="2"/> <SetStat target="self" stat="Tiredness" delta="4"/> <RandomChoice> <Option weight="1"><SetSkill target="self" skill="NormalSex" delta_min="1" delta_max="1"/></Option> <Option weight="1"><SetSkill target="self" skill="Anal" delta_min="1" delta_max="1"/></Option> <Option weight="1"><SetSkill target="self" skill="BDSM" delta_min="1" delta_max="1"/></Option> <Option weight="1"><SetSkill target="self" skill="Group" delta_min="1" delta_max="1"/></Option> <Option weight="1"><SetSkill target="self" skill="Lesbian" delta_min="1" delta_max="1"/></Option> <Option weight="1"><SetSkill target="self" skill="Service" delta_min="1" delta_max="1"/></Option> <Option weight="1"><SetSkill target="self" skill="Strip" delta_min="1" delta_max="1"/></Option> </RandomChoice> <RandomChoice> <!-- identical block; each draw is independent --> ... </RandomChoice></Effects>See resources/Jobs/basictraining/effects.xml for the full file.
4. Performance-gated brothel fame bump
Section titled “4. Performance-gated brothel fame bump”Compute a derived performance value with <Bind>, gate two complementary groups on it, and use a bind reference in delta="$delta":
<Effects> <Group> <Bind name="perf" expr="(Charisma + Intelligence + Service) / 3"/> <When><Bind name="perf" lt="20"/></When> <SetStat target="self" stat="Tiredness" delta="2"/> </Group> <Group> <Bind name="perf" expr="(Charisma + Intelligence + Service) / 3"/> <Bind name="delta" expr="(Charisma + Intelligence + Service) / 60"/> <When><Bind name="perf" ge="20"/></When> <SetBrothel target="player.brothels" key="Fame" delta="$delta" clamp_max="100"/> <SetStat target="self" stat="Happiness" delta="1"/> <SetStat target="self" stat="Tiredness" delta="4"/> <SetStat target="self" stat="Exp" delta="2"/> </Group></Effects>The perf bind is declared in both groups independently because binds in one group are not visible from another. Inside a single group a later bind may reference earlier ones (1.13.0+); the example above keeps both forms inline so it loads on every supported engine version.
See also
Section titled “See also”reference/when-conditions.md: full grammar for<When>conditions used inside<Group>reference/jobs-reference.md: full schema for all other job files (performance, wage, gains, messages)docs/jobs-as-data/authoring-checklist.md: per-port procedure and status flag caveats