# Ambitions

> What an adult townsperson wants out of life, drawn from who they are and pursued step by step over months and years. Data files any mod can extend.

Source: https://underlives.com/docs/gameplay/ambitions

An **ambition** is a lifetime aim: become rich, find love, be looked up to, get out of a life that is crushing them. Every adult of the town draws one or two from who they are (their facets and traits) and holds them for months and years; the Life sheet shows what they are after and how far along they are, and the chronicle says when they set out, got there or gave up. The player never draws one: the player stays free.

The ambition says **what** they want; their traits say **how** they go about it. "Become rich" is one ambition: a diligent person saves and climbs, a cruel one extorts. Which action they take for it is the work of the means and the planner (the next step of the person-first rework); nothing in an ambition names an action, a scene or a crime.

## Files

`Ambitions/*.ulambition`, JSON, discovered in every mod in load order. `ul_Base` ships `base.ulambition` (twelve groups) and `dark.ulambition` (the dark group). A later file redefines an ambition or a group **by id** (the whole object is replaced, and the override is logged); a new id adds one. Prefix your ids with your mod's prefix (`ul_Fame_be_a_star`); the `ul_Base` ids are the base vocabulary.

```json
{
  "version": 1,
  "draw": { "atAge": 18, "count": 1, "secondChance": 0.35, "noise": 0.35, "redrawAfterDays": 30 },
  "groups": [ { "id": "fortune", "name": "Fortune", "description": "Money: enough of it, then more." } ],
  "ambitions": [
    { "id": "own_business", "text": "Own a business of my own", "group": "fortune",
      "score": { "ambition": 0.4, "autonomy": 0.4, "risk_tolerance": 0.3 },
      "traits": { "ambitious": 0.4, "resourceful": 0.4, "cautious": -0.3 },
      "age": [18, 65], "tone": { "peaceful": 1, "balanced": 1, "dark": 1 },
      "state": ["owns_business >= 1", "business_days >= 180"],
      "steps": [
        { "text": "Save the money to start", "state": ["wealth >= 15000"], "windowDays": 365, "failBudget": 2 },
        { "text": "Open the doors", "state": ["owns_business >= 1"], "windowDays": 180, "failBudget": 2 } ],
      "next": "grow_business",
      "onFail": [ { "do": "abandon" } ] }
  ]
}
```

`Tools/ModLint/ambitions_check.py` checks every file against the personality data, lists the readers the engine does not provide yet, and `--simulate N` estimates what a town of N adults would draw. The full field list is in `Content/Modules/ul_Base/Ambitions/README.md`.

## The draw

The first midnight a person spends as an adult (their eighteenth birthday, or the day they are created when they are created older) draws their ambitions, deterministically from their id. Each candidate weighs

```
weight × tone[world] × exp(Σ (facet − 0.5) × score[facet] × 4 + Σ traits held) × noise
```

the same affinity the traits themselves are generated with. A candidate is skipped when it is outside the person's age band, forbidden by one of their traits (`forbidTraits`), already achieved (`state` holds), exclusive with or in the same group as one they hold, when a `requires` condition fails, or when its `target` finds nobody. `draw.count` ambitions are always drawn, plus one more with `secondChance` (raised by the `ambition` facet). A life whose ambitions have all ended draws again after `redrawAfterDays`.

## Conditions and readers

`requires`, `state`, `steps[].state` and `onFail[].if` are lists of strings that must all hold: `wealth >= 25000`, `!has_home` (zero), `has_partner` (above zero), `@target:friends <= 1` (read on the target). A reader is one of the life readers (`wealth`, `career_rank`, `owns_business`, `married`, `children`, `friends`, `feared_by`, `has_partner`, `has_job`, `has_home`, `homeless_days`, `rent_debt`, `social_debt`, `social_pressure`, `temperature`…), `stat:<id>` for any stat, `opinion:<dimension>:<id>`, `grudge_against:<id>`, `memories:<kind>`, `facet:<id>` and `trait:<id>` for the personality, or the bare name of a defined stat. A reader the engine does not know reads as **false**, never as zero, and is logged once: a catalogue written ahead of its readers never completes by accident.

The means added a second family of readers, computed on the spot from the town's state and never stored. Standing: `fame` (the stat), `respected_by` (people whose respect for them is 30 or more), `afraid_of`, `grudges_held`, `controls` (people who fear them and owe them), `controlled_by`, `crew` (people who both fear and trust them), `best_trust`, `lovers`, `leverage` (people whose acts they know of). Family: `parents_alive`, `family_estranged`, `outdid_parents`, `children_settled`. Work: `career_top`, `job_field:<field>`, `subordinates`, `employees`, `self_employed`, `qualifications`, `clubs`, `best_skill` (the best of the stats a `.ulmeans` lists as `skills`), `owns_home`. About one person: `turned_against:<id>`, `harmed:<id>`, `brought_down:<id>`, `knows_weakness:<id>`, with `{target}` for the id. The ambition's own clock: `held_days`; the person's: `mood_avg30`. And every **life counter** by its bare name (`works_made`, `nights_out`, `trips`, `thrills`, `performances`, `bets_placed`, `helped_others`, `parent_care_days`, `legacy`, `job_days`, `sober_days`…): a counter is known as soon as a `.ulmeans` declares it or an action's `ADVANCES` names it, and reads 0 until something moves it. The reference table is in `Content/Modules/ul_Base/Ambitions/README.md`.

## Steps, success, failure

One step is current at a time, checked every seven days of the person's life. Its `state` holds: the step is done and the next starts with a fresh window; after the last one the ambition's own `state` is tested and the ambition is achieved (and its `next` tier starts, when it has one). `windowDays` pass without the state holding: one failure, the window restarts. Failures over `failBudget`: the ambition fails, and `onFail` says what that does. `abandon` ends it (a new draw comes `redrawAfterDays` later); `mutate` turns it into another ambition, with the person who blocked the step as its target. Mutation and the facet marks (`marks`) are read today and acted on by the next steps of the rework.

## Means

An ambition says what; a **means** says how a step moves. `Ambitions/*.ulmeans` (JSON, discovered like the ambitions, a later `id` replacing an earlier one) declares three things: the daily **counters**, the **skills** `best_skill` reads, and the **means** themselves. `ul_Base/Ambitions/means.ulmeans` is the reference file.

```json
{
  "version": 1,
  "counters": { "job_days": { "daily": ["has_job"], "reset": ["!has_job"] },
                "sober_days": { "daily": ["stat:drug_dependence <= 0"], "reset": ["stat:drug_dependence > 0"] } },
  "skills": ["music", "martial", "fitness", "intelligence", "cooking", "art", "dancing", "charisma", "driving"],
  "means": [
    { "id": "open_business", "advances": { "owns_business": 1, "self_employed": 1 },
      "do": { "engine": "business.open", "kind": "shop", "cost": 10000, "income": 3200, "title": "Owner" },
      "requires": ["wealth >= 12000"], "odds": 0.1, "behaviors": { "ambition": 0.5, "risk_taking": 0.5 } },
    { "id": "perform", "advances": { "performances": 1, "fame": 1 }, "do": { "action": "*" } }
  ]
}
```

A counter gains 1 at midnight while its `daily` conditions hold and drops to 0 when its `reset` conditions do (same syntax as an ambition's conditions). A means has an `id`, what it `advances` (reader to amount), what it does (`do`), what it `requires` first, and how acceptable it is: `odds` (daily chance, default 0.1), `norm` (0 to 1, the share of people who would), `minTemperature` (opens only once the person lacks enough: the bar is a quarter higher in a peaceful world, a quarter lower in a dark one), `risk` (cuts the odds in a peaceful or balanced world), `adultOnly` (default true) and `behaviors` (behaviour id to weight, scaling the odds by the person's bias).

`do` is one of three forms:

- `{ "action": "*" }`: any action whose `EFFECTS` or `ADVANCES` move the reader. The planner makes the step a goal on that reader and the ordinary decision loop finds the action. `{ "action": "<id>" }` names one action.
- `{ "lifeChoice": "<id>" }`: one of the [life choices](/docs/gameplay/npc-life#life-choices).
- `{ "engine": "<routine>", ...params }`: a routine of the engine, tried once a day with the means' odds for the person whose ambition goal names it:

| Routine | What it does | Params (default) |
| --- | --- | --- |
| `jobs.apply` | Applies to a catalogue job at its first rank that they qualify for and that pays at least a tenth more than today's (anything when jobless); hired by the town's hiring chance. | — |
| `jobs.promote` | The ordinary promotion check, now. | — |
| `residence.move` | Moves into a vacant home they can afford: a dearer one within a third of their income when `better` is 1 and the rent is paid, a cheaper one when it is 0. Minor children follow. | `better` (1) |
| `residence.buy` | Buys the home they rent at `years` of rent, the money going to its owner. | `years` (10) |
| `business.open` | Registers a business of `kind` to them, at `cost`; their job from now on, paid `income` a month. | `kind` (shop), `cost` (10000), `income` (3000), `title` (Owner) |
| `business.hire` | A jobless adult of the town joins their business, up to `max` staff. | `max` (5), `salary` (1500), `title` (Employee) |
| `partner.seek` | The free adult, not family, they find most attractive and who likes them back; at the same place unless `anywhere`. The pair starts dating. | `anywhere` (1), `minScore` (0) |
| `partner.marry` | Marries the partner after `days` days together, when the partner's rapport is at least `rapport`. | `days` (180), `rapport` (0) |
| `partner.leave` | Leaves the partner or spouse. | — |
| `advance` | Lands the counters in `advances` and nothing else. | — |

**The planner.** Each midnight, for a person with ambitions: the first condition of the current step that does not hold, the means that advances its reader and whose requirements hold (or, when a means needs something first, that requirement, three levels down: save, then open the business, then hire) becomes the goal at the top of the person's goals, with the step's window as its deadline and the group's `drive` (a `.ulambition` group may name one) as what it is scored under. The decision loop pursues it like any goal; an engine means is also tried once a day, more often as the goal escalates.

**`ADVANCES` on actions.** Any action can carry a table of counters it moves when it completes, for the NPC or the player who did it ([Actions](/docs/gameplay/actions#advances)):

```lua
ADVANCES = { performances = 1, nights_out = 1 },
```

Counter names only: a name here becomes a counter and shadows a stat or life reader of the same name, so a stat change stays in `EFFECTS`. An action with `ADVANCES` and no `NPC` block is still player-only (the generic NPC rules only value effects a drive reads): add `NPC = { ENABLED = true, BASE = ... }` when an NPC can do it. The base content carries `ADVANCES` on about eighty actions: gigs, opening nights, streams and karaoke (`performances`), crafts, photo walks, writing and a thesis (`works_made`), bars, clubs, bowling, parties and festivals (`nights_out`), holidays, cruises and camping (`trips`), climbing, surfing, skating and the marathon (`thrills`), gambling (`bets_placed`), volunteering, donations and prison visits (`helped_others`), visiting an ageing parent (`parent_care_days`), the letter to a grown child and the will (`legacy`).

The engine means write their own history: `npc_job_application`, `npc_job_found`, `npc_changed_job`, `npc_promoted`, `npc_moved_home`, `npc_bought_home`, `npc_business_opened` (with `{business}`), `npc_hired_staff`, `npc_started_dating`, `npc_married`, `npc_broke_up`. `Tools/ModLint/ambitions_check.py` lists the readers nothing provides yet, and `modlint.py check` validates `.ulmeans` keys and `ADVANCES` tables.

## Adults only

The loader refuses an ambition whose `age[0]` is under 18, nobody draws before `atAge` (itself never under 18), and every `target` is an adult, whatever the data says. The dark group (`revenge_control`) is weighed by cruelty, domination and grudge, and its share of the adults is measured by the long simulation: at most 8 % in a peaceful world, 20 % in a dark one.

## What the player sees

The Life sheet of a person shows each ambition's text, its tier, the current step and a progress bar: the done steps plus, for the current one, how far its readers went from where they stood when the step began toward their thresholds. The history records `npc_ambition_drawn`, `npc_ambition_step`, `npc_ambition_achieved` and `npc_ambition_abandoned`, with the ambition's text. In Sandbox everything shows; what the player's own character may know of it is the Story-mode filter of a later step.
