# Outdated description
This document is now historic and a more descriptive version can be found here:
https://github.com/space-wizards/docs/blob/076d601f5fcbe88e2e8c38e0e3464f3c617e3796/src/en/proposals/game-director.md
# Game Director / Dynamic Event Scheduler
Chooses events with intent, rather than randomly. Does this towards a narrative purpose, either to endanger the station or to return order.
## What is our story?
Player experience in SS14 should have both its highs and lows. A peaceful extended shift can become boring with no challenges to overcome together. An overly intense battle might kill half the crew and leave the station in disorder that we cannot recover from. What we want is a middle ground with some variation.
The ideal story has a mix of both, with order followed by disorder and then a chance to recover and rebuild.
### Example story (aspirational)
- Traitors arrive on the station, but cause minor chaos and are rounded up
- A number of minor occurences happen, anomolies, gas leaks and whatnot
- There is an attack by a band of nukies who kill sec and are threating to destroy the station
- A band of security reinforcements arrive (powered by the ghosts of sec and others)
- Enemies are killed but the station is in tatters
- Engineering staff and supplies arrive and begin repairing the station
- Pizza is delivered
- Peace resumes (for now?)
Broken into "story beats", the above story had these goals:
**Traitors -> Peace -> Attackers -> RestoreOrder -> RepairStation -> Peace**
We want a round to follow stories we can understand, with each story beat automatically triggering relevant events that follow our goals at that time. The goal might be to bring order to the station, or it might be to sow a very specific sort of Chaos.
## How do we describe what an event does?
Events have a metric called "Chaos" which describes different types of negative effects they bring to the station. Good events cause negative chaos.
### Negative events increase chaos
```yml
- type: entity
id: SpiderSpawn
parent: BaseGameRule
noSpawn: true
components:
- type: StationEvent
earliestStart: 20
minimumPlayers: 15
weight: 5
duration: 60
chaos:
CombatHostiles: 40 # New hostiles are introduced
CombatFriends: 20 # Friends are likely to die
Medical: 150 # Medical will have wounds to heal
- type: VentCrittersRule
entries:
- id: MobGiantSpiderAngry
amount: 4
maxAmount: 8
```
### Positive events reduce chaos
```yml
- type: entity
id: PizzaPartySmall
parent: BaseGameRule
noSpawn: true
components:
- type: StationEvent
weight: 10
startDelay: 10
duration: 120
chaos:
Hunger: -80 # The pizza party satisfies hunger
Thirst: -40 # And also thirst
- type: CargoGiftsRule
descr: A small pizza party
sender: NanoTrasen
careof: The Bar
gifts:
FoodPizzaLarge: 1 # 16 pizzas
FoodBarSupply: 1
FoodSoftdrinks: 1
CrateVendingMachineRestockRobustSoftdrinks: 1
```
## How do we know how bad things are on the station?
We want to measure how bad the Chaos is right now. If the station is doing well, the lights are on and the floor is clean, we expect a low chaos score. If the lights are out, the place is spaced and enemies are roaming the station, we want a high chaos score.
Because we went events tailored to story requirements and sensitive to the exact situation on the station, chaos is measured on several axes. The solution to hunger is pizzas. The solution to enemies might be a squad of reinforcements.
### Code to measure Chaos
A number of systems called "Metrics" are used to infrequently (perhaps every 30 seconds to 4 minutes) summarize the chaos levels. Metrics each stand alone and so it will be easy to add or remove them as the game matures.
Each metric is set up like a gamerule - it has a system, a component and an invisible entity. These prototypes are instantiated by the dynamic system when needed.
Metrics could subscribe to relevant events and dynamically adjust their scores as events occur on the station. Or they can do a single pass through the component system when run. The single pass approach has been preferred in favor of its stability and simplicity for now.
#### Metrics at the moment
- **AnomalyMetric** - Are there many? Are they out of control? Writes to "Anomaly"
- **CombatMetric** - Who is on the station? How injured are our friends? Writes to "Hostiles", "Friendlies", "Combat", "Death" and "Medical"
- **DoorMetric** - Uses doors as a proxy to surveying the ship for danger. Writes to "Emag", "Atmos" and "Power"
- **FoodMetric** - How hungry are the friendly crew? Writes to "Hunger" and "Thirst"
- **JaniMetric** - How messy is the station (partially as a proxy for safety). Writes to "Jani"
I expect that as we describe a situation we want the Director to react to we will introduce further metrics to give us richer insight into the station. We might want trust metrics based on how many traitors there are. Or staff / department metrics based on staffing issues and role deaths.
## How bad do we want things to be?
Each of the **story beats** from above has a matching chaos level, specifying factors that we care about at that point in the story along with target values for those **Chaos factors**.
**Traitors -> Peace -> Attackers -> RestoreOrder -> RepairStation -> Peace**
While each Story beat will stay around for a certian amount of time, it can end early if certian Chaos levels are met, so called `endIfAnyWorse` and `endIfAllBetter`. These are useful if there is too much war, or perhaps too much peace.
```yml
- type: entity
id: GameDirector
parent: BaseGameRule
noSpawn: true
abstract: true
components:
- type: GameDirectorSystem
storyBeats:
Traitors:
description: Traitors have infiltrated the station
goal: # Some
Traitors: 40
Hostile: 60 # Some hostiles (includes traitors)
endIfAnyWorse:
Atmos: 400 # Severe atmos, power or medical issues should end this beat.
Power: 400
Medical: 400
Death: 200
Combat: -100 # Friendly forces should retain the upper hand
Peace:
description: Life returns to usual, but how usual?
goal: # Try to achieve a wide range of different moderate values.
Combat: -200 # Friendly forces should have the upper hand
Anomaly: 100
Atmos: 200
Power: 100
Jani: 100
Hunger: 100
Thirst: 100
Medical: 100
Attackers:
description: Hostiles are attacking the station.
goal:
Hostile: 100 # Quite a few hostiles
endIfAnyWorse:
Atmos: 800 # Severe atmos, power or medical issues should end this beat.
Power: 800
Medical: 600
Death: 400
Combat: -50 # Friendly forces should just retain the upper hand
RestoreOrder:
description: Send help to quell disorder on the station
# ...
- type: entity
id: CombatDynamic
parent: GameDirector
noSpawn: true
components:
- type: GameDirectorStories
Combat:
Description: After traitors invade, the station descends into combat and rises from the ashes.
MinPlayers: 40
Beats:
- Traitors
- Peace
- Attackers
- RestoreOrder
- RepairStation
- Peace
```
## Picking the best event
Once we know what **Chaos metrics** we currently attempting to achieve, we have a chance to select the correct event.
- The **Story Beat** has told us what chaos we want.
- The **Metrics** tell us what chaos the station currently has.
- Each **StationEvent** has a Chaos field predicting that event's impact
So we iterate through all the possible events, choose the one which moves the station chaos nearest to our goal and set that event into action. Simple!
The whole process is richly logged into the admin log (under GameDirector) so the admins have insight into what the director is attempting to achieve.
# Conclusion
The Game Director system will allow us to author specific experiences that are gated on how chaotic the station has become.
The more events we introduce to the game with clear chaos outcomes, the better the system will be at guiding the station through a specific narrative experience.
The data driven nature of the metrics and story data means that a wide variety of narrative outcomes and station-specific events can all be achieved through the same system.