Skip to content

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.


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.


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.”

Target Meaning
self The girl performing the job.
brothel.girls All girls currently assigned to the same brothel. Useful for morale/training auras.

Charisma, Happiness, Libido, Constitution, Intelligence, Confidence, Mana, Agility, Fame, Level, AskPrice, House, Exp, Age, Obedience, Spirit, Beauty, Tiredness, Health, PCFear, PCLove, PCHate.


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.
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).

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_min No If present, the result is clamped to this minimum after the delta is applied.
clamp_max No If present, the result is clamped to this maximum after the delta is applied. clamp_min > clamp_max on one entry is a load error.
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 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).

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>
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.


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.

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.


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.

All stat names and skill names listed under <SetStat> and <SetSkill> above are valid. For example: Charisma, Intelligence, Service, Happiness, Tiredness.

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 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.
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.


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.

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.


The elements above (<SetStat>, <SetSkill>, <SetBrothel>, etc.) are specific to effects.xml inside job directories. Consumable items use a parallel but distinct <effect type="..."> syntax inside their <use> block. The full table lives in reference/items-reference.md. For convenience the trait-related types are listed here:

Grants the named trait to the consumer.

<effect type="grant_trait" name="Caffeine Addict"/>

With weeks="N": the trait is temporary and removed after N weeks.

Removes the named trait from the consumer. Used by cures and condition-fix items.

<effect type="remove_trait" name="Chlamydia"/>

value= and weeks= are ignored. There is no timed-removal semantics — if the trait re-applies later (e.g. the girl re-catches the disease), that is the disease loop’s job, not the cure’s.


  • 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