Initialize environment configuration and enhance API logging
- Added a new .env file for environment variables including database and Redis configurations. - Updated CLAUDE.md with hard rules for development practices. - Enhanced package.json with new scripts for development and infrastructure management. - Integrated Pino for structured logging in the API, replacing the default NestJS logger. - Implemented OpenTelemetry for tracing and monitoring in the API. - Added durationMinutes field to the Mission model in Prisma schema and created corresponding migration. - Updated missions controller and service to handle mission duration and abandonment logic. - Introduced new logger module for consistent logging across the application.
This commit is contained in:
@@ -1 +1,2 @@
|
||||
export * from './lib/encounter-library';
|
||||
export { SURVIVOR_NAMES } from './lib/survivors';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import type { EncounterDefinition } from '@fog-explorer/api-interfaces';
|
||||
import { ALLY_FIRST_NAMES } from './survivors';
|
||||
import encountersData from './encounters.json';
|
||||
|
||||
interface RawEncounter {
|
||||
key: string;
|
||||
@@ -13,9 +15,6 @@ interface EncountersFile {
|
||||
encounters: RawEncounter[];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const encountersData = require('./encounters.json') as EncountersFile;
|
||||
|
||||
export interface LibraryEncounter extends EncounterDefinition {
|
||||
tier: 1 | 2 | 3;
|
||||
flavorSuccess: string[];
|
||||
@@ -66,5 +65,12 @@ export function pickFlavor(
|
||||
rng: () => number
|
||||
): string {
|
||||
const pool = ctx.success ? encounter.flavorSuccess : encounter.flavorFailure;
|
||||
return pool[Math.floor(rng() * pool.length)];
|
||||
const raw = pool[Math.floor(rng() * pool.length)];
|
||||
return expandAlly(raw, rng);
|
||||
}
|
||||
|
||||
function expandAlly(text: string, rng: () => number): string {
|
||||
return text.replace(/\{\{ally\}\}/g, () => {
|
||||
return ALLY_FIRST_NAMES[Math.floor(rng() * ALLY_FIRST_NAMES.length)];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"version": "1.2.0",
|
||||
"encounters": [
|
||||
{
|
||||
"key": "generator_repair",
|
||||
@@ -7,28 +7,28 @@
|
||||
"tags": ["generator", "objectives"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The generator sputters to life. Light floods the area.",
|
||||
"Sparks fly, then hum — the generator catches.",
|
||||
"Wires connected. The machine breathes again.",
|
||||
"A deep mechanical thrum. Progress.",
|
||||
"The gauge climbs. Another generator done.",
|
||||
"Hands steady, heart racing. The engine turns over.",
|
||||
"The generator shudders, then roars. One less in the dark.",
|
||||
"Circuit reconnected. The hum is its own small victory.",
|
||||
"It takes longer than expected, but the light comes.",
|
||||
"The generator protests, then yields."
|
||||
"It catches. I step back before I let myself feel anything.",
|
||||
"Sparks, then hum. I keep moving.",
|
||||
"The last wire clicks. One down.",
|
||||
"It's running. I don't stop to celebrate.",
|
||||
"My hands stop shaking when the engine turns over.",
|
||||
"{{ally}} holds the wire steady. It catches.",
|
||||
"The gauge climbs. I'm already looking for the next one.",
|
||||
"Takes too long. But it works.",
|
||||
"Done. The light helps more than I expected.",
|
||||
"{{ally}} calls out. I make the connection. Done."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The generator kicks back. Too many watchers in the dark.",
|
||||
"The mechanism jams. Footsteps echo nearby.",
|
||||
"A noise betrays the position. The generator goes cold.",
|
||||
"Something shifts in the fog. The work abandoned.",
|
||||
"The wiring resists every attempt. No progress tonight.",
|
||||
"A shadow crosses the generator. Not now.",
|
||||
"The tool slips. The noise is too loud.",
|
||||
"The generator sparks wrong. An alarm of sorts.",
|
||||
"Patience runs out before the generator does.",
|
||||
"A nearby sound. The repair will have to wait."
|
||||
"Something moves in the fog. I pull back.",
|
||||
"A sound behind me. I leave the gen and run.",
|
||||
"Too loud. I made it too loud.",
|
||||
"The wiring's wrong. I can't fix it from here.",
|
||||
"I miscalculate. The whole thing sparks wrong.",
|
||||
"{{ally}} had to break away. I lose the progress.",
|
||||
"My hand slips. The noise is too much.",
|
||||
"A shadow on the gen. I'm already gone.",
|
||||
"Not tonight. Not this one.",
|
||||
"{{ally}} pulls back — something's close. I follow."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -37,28 +37,28 @@
|
||||
"tags": ["totem", "altruistic", "objectives"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The totem crumbles. Its curse lifts from the fog.",
|
||||
"Bones scatter. The hex dissolves into smoke.",
|
||||
"The ritual unravels. Something distant screams.",
|
||||
"The totem falls apart like it was never solid.",
|
||||
"Ash and splinter. The hex breaks.",
|
||||
"A soft crack — the bones give way. Something changes.",
|
||||
"The skull shatters. Whatever watched through it is gone.",
|
||||
"The cleansing takes. The fog feels thinner.",
|
||||
"The totem offers no resistance. It was waiting to fall.",
|
||||
"One less curse in the trial."
|
||||
"It breaks. Something screams — not here, but somewhere.",
|
||||
"The bones scatter. I feel the curse lift.",
|
||||
"One hex gone. The fog feels slightly less wrong.",
|
||||
"It comes apart like it was never solid.",
|
||||
"I don't understand what I just broke. I'm glad I broke it.",
|
||||
"{{ally}} spots it first. I make short work of it.",
|
||||
"The skull gives. Whatever watched through it is gone.",
|
||||
"{{ally}} watches my back. The cleanse is fast.",
|
||||
"It was waiting to fall. I let it.",
|
||||
"One less curse."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The totem resists. Its pull is stronger than expected.",
|
||||
"A presence drives the survivor back before the cleanse completes.",
|
||||
"The hex holds. Dread thickens the air.",
|
||||
"Fingers close on the totem — then something warns away.",
|
||||
"The totem hums with malice. Not today.",
|
||||
"The ritual is interrupted. The hex burns brighter.",
|
||||
"The bones refuse to break. Wrong approach.",
|
||||
"The totem feels wrong. Leave it for now.",
|
||||
"Whatever keeps the totem standing isn't done yet.",
|
||||
"The cleanse stalls halfway. The hex endures."
|
||||
"It pulls back. I can't finish this.",
|
||||
"Something drives me away before it's done.",
|
||||
"The hex holds. The air gets thicker.",
|
||||
"I reach for it and stop. Something warns me off.",
|
||||
"The totem hums. I'm not strong enough. Not yet.",
|
||||
"{{ally}} calls wrong. The totem burns brighter.",
|
||||
"The bones won't break. Wrong approach.",
|
||||
"{{ally}} needs me. I leave the totem standing.",
|
||||
"Halfway through. Then something changes. I run.",
|
||||
"The hex endures. I'll find another way."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -67,28 +67,28 @@
|
||||
"tags": ["chest", "item"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The chest yields a worn medkit. Small mercies.",
|
||||
"A flashlight, still charged. The fog recedes slightly.",
|
||||
"A useful tool among the debris.",
|
||||
"Something worth having. The chest wasn't empty after all.",
|
||||
"Buried under detritus — a working toolbox.",
|
||||
"A medkit, half-depleted but still viable.",
|
||||
"The chest creaks open. Something useful inside.",
|
||||
"Luck, this time.",
|
||||
"Not everything in the fog is hostile. The chest provides.",
|
||||
"A find. The supplies won't last, but they'll help."
|
||||
"A medkit. Worn, but real.",
|
||||
"A flashlight, still charged. I pocket it.",
|
||||
"Something useful. I don't ask how it got here.",
|
||||
"Not empty. That's not nothing.",
|
||||
"A toolbox, buried under rot. I'll take it.",
|
||||
"Half a medkit. Better than nothing.",
|
||||
"The chest creaks open. I take what's there.",
|
||||
"Lucky.",
|
||||
"The fog gives sometimes. Not often.",
|
||||
"Supplies. They won't last, but they'll help."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The chest is empty. Only rust and regret.",
|
||||
"The lid splinters — nothing useful inside.",
|
||||
"A noise nearby cuts the search short.",
|
||||
"Someone got here first.",
|
||||
"The chest is locked. No time to force it.",
|
||||
"Debris, nothing more.",
|
||||
"Empty. Just rust and old regret.",
|
||||
"Nothing worth taking.",
|
||||
"A sound cuts the search short.",
|
||||
"Someone else was here first.",
|
||||
"Locked. I don't have time to force it.",
|
||||
"Debris. Nothing more.",
|
||||
"Whatever was here is long gone.",
|
||||
"The chest yields nothing. Time wasted.",
|
||||
"Empty. The trial takes without giving.",
|
||||
"Nothing. Move on."
|
||||
"Nothing. Time I don't have, wasted.",
|
||||
"The trial takes without giving.",
|
||||
"Move on."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -97,28 +97,28 @@
|
||||
"tags": ["hook", "survival"],
|
||||
"tier": 2,
|
||||
"flavorSuccess": [
|
||||
"With grim determination, the survivor slips free.",
|
||||
"Arms aching, the hook releases. Freedom, for now.",
|
||||
"A desperate push — the chains give way.",
|
||||
"The hook yields to persistence.",
|
||||
"I don't know how. I don't care. I'm off.",
|
||||
"Arms burning. The hook releases. Move.",
|
||||
"Every instinct says give up. I don't.",
|
||||
"It gives. I fall. I run.",
|
||||
"Blood and effort. The barb comes free.",
|
||||
"The survivor drops to the ground, gasping.",
|
||||
"Will wins where strength falls short. Free.",
|
||||
"The hook's grip loosens. A precious second of clarity.",
|
||||
"Every instinct says stop. The survivor doesn't.",
|
||||
"The chains snap. Unlikely. Necessary."
|
||||
"{{ally}}'s voice from out there somewhere. I fight harder. I'm free.",
|
||||
"Will wins. I'm off the hook.",
|
||||
"A fraction of movement — and it releases.",
|
||||
"I stop thinking and just push. It works.",
|
||||
"{{ally}} is coming. I hold on long enough. Then I'm free."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The struggle exhausts. The hook holds.",
|
||||
"Every movement drives the barb deeper. Stay still.",
|
||||
"The fog presses in. The hook remains.",
|
||||
"The attempt fails. The chains don't care.",
|
||||
"No leverage. No escape. Not yet.",
|
||||
"The energy spent is wasted. Still trapped.",
|
||||
"The hook was designed for this. It holds.",
|
||||
"Patience isn't a luxury here — but neither is panic.",
|
||||
"The struggle costs everything. The hook doesn't move.",
|
||||
"Every movement makes it worse. I go still.",
|
||||
"The fog presses in. I'm still up here.",
|
||||
"I try. The chains don't.",
|
||||
"No leverage. Not this time.",
|
||||
"{{ally}} can't get to me. Still stuck.",
|
||||
"It's designed for exactly this. It holds.",
|
||||
"Panic and pain in equal measure. Neither helps.",
|
||||
"The barb shifts but doesn't release.",
|
||||
"The struggle ends. The hook wins this round."
|
||||
"I lose this one."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -127,28 +127,28 @@
|
||||
"tags": ["exit", "objectives"],
|
||||
"tier": 2,
|
||||
"flavorSuccess": [
|
||||
"The gate grinds open. Cold air rushes in.",
|
||||
"Generators humming, the lock gives. Almost there.",
|
||||
"The exit yields. Light from outside cuts the fog.",
|
||||
"The switch holds down. The gate obeys.",
|
||||
"A long, agonising second — then the gate opens.",
|
||||
"The exit panel responds. The way out is clear.",
|
||||
"The gate was always going to open. Tonight it does.",
|
||||
"The outside world, briefly visible through iron.",
|
||||
"The switch trips. The gate moves.",
|
||||
"One last obstacle overcome."
|
||||
"The gate grinds open. Cold air. Real air.",
|
||||
"The lock gives. I keep pressure on the switch.",
|
||||
"Light from outside cuts through the fog.",
|
||||
"The gate obeys. I don't let go until it does.",
|
||||
"A long second. Then the mechanism gives.",
|
||||
"The panel responds. I'm almost out.",
|
||||
"It opens. It actually opens.",
|
||||
"Through the iron, I can see outside.",
|
||||
"The switch trips. The gate moves. I move.",
|
||||
"One more thing behind me."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The gate mechanism is jammed. Precious seconds lost.",
|
||||
"A shadow falls across the panel. The attempt abandoned.",
|
||||
"The switch is stuck. The gate stays shut.",
|
||||
"The gate won't cooperate. Not now.",
|
||||
"The panel sparks and resets. Try again.",
|
||||
"Something holds the gate. Not mechanical — worse.",
|
||||
"The generator noise covers the gate's resistance.",
|
||||
"The lock mechanism fails. The gate holds.",
|
||||
"Too slow. The gate doesn't open in time.",
|
||||
"Pressure on the switch, nothing. Wrong timing."
|
||||
"The gate mechanism jams. I burn seconds I don't have.",
|
||||
"A shadow at the panel. I abandon it.",
|
||||
"The switch won't budge.",
|
||||
"The gate refuses. Not now.",
|
||||
"The panel sparks and resets. I try again.",
|
||||
"Something holds it. Nothing mechanical.",
|
||||
"The gate resists. I can't tell why.",
|
||||
"The lock fails. The gate stays shut.",
|
||||
"Too slow. The gate doesn't care.",
|
||||
"Nothing. Wrong timing."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -157,28 +157,28 @@
|
||||
"tags": ["stealth", "survival"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"Still as stone. The threat passes without noticing.",
|
||||
"A breath held long — then silence. Safe.",
|
||||
"The fog swallows the survivor whole. Unseen.",
|
||||
"The patrol route is predictable. Predictable is avoidable.",
|
||||
"Close. Too close. But not close enough to matter.",
|
||||
"The survivor becomes scenery. The patrol sees nothing.",
|
||||
"A narrow gap in the patrol. Taken.",
|
||||
"The killer's attention is elsewhere. Move.",
|
||||
"Footsteps near, then receding. Safe.",
|
||||
"The locker is cold and cramped and perfect."
|
||||
"I don't breathe. I don't think. It passes.",
|
||||
"A long silence — then the footsteps recede.",
|
||||
"I melt into the fog. Unseen.",
|
||||
"Predictable. Predictable is avoidable.",
|
||||
"Close. Too close. But not enough.",
|
||||
"{{ally}} draws the patrol the other way. I slip through.",
|
||||
"A gap in the route. I take it.",
|
||||
"The killer looks elsewhere. I don't waste it.",
|
||||
"Footsteps near. Then far. Then gone.",
|
||||
"The locker is cold and tight and it works."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"A twig snaps. Eye contact — then the chase begins.",
|
||||
"The survivor misjudges the angle. Spotted.",
|
||||
"Heartbeat too loud. Presence too close.",
|
||||
"The patrol's route changed. A fatal assumption.",
|
||||
"No cover. The survivor is seen.",
|
||||
"A shadow where there should be none. Detected.",
|
||||
"The instinct to run is wrong. It happens anyway.",
|
||||
"The fog offers no protection here.",
|
||||
"Spotted. The trial shifts.",
|
||||
"The killer turns at the wrong moment."
|
||||
"A wrong step. Eye contact. The chase starts.",
|
||||
"I misjudge the angle. Spotted.",
|
||||
"My heartbeat is too loud. The presence is too close.",
|
||||
"The route changed. I didn't know.",
|
||||
"No cover. Nowhere to go.",
|
||||
"{{ally}} breaks stealth nearby. We're both compromised.",
|
||||
"Every instinct says run. That instinct is wrong. I run anyway.",
|
||||
"The fog doesn't protect me here.",
|
||||
"Spotted. Everything changes.",
|
||||
"{{ally}}'s noise pulls the killer my way."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -187,28 +187,28 @@
|
||||
"tags": ["healing", "altruistic", "survival"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"Bandages tight, the wound closes. Pain recedes.",
|
||||
"The medkit does its job. The survivor steadies.",
|
||||
"A few tense minutes — injuries tended.",
|
||||
"Not good as new, but functional. Good enough.",
|
||||
"The bleeding stops. The fog feels slightly less hostile.",
|
||||
"Clinical precision in a place with no clinics.",
|
||||
"The medkit is emptied wisely. The injury yields.",
|
||||
"Hands that shake still heal.",
|
||||
"The wound is dressed. One less liability.",
|
||||
"Recovery, however temporary, is still recovery."
|
||||
"The bandages hold. The pain pulls back.",
|
||||
"The medkit does what it's supposed to.",
|
||||
"Not ideal. But the wound closes.",
|
||||
"Not fixed. Functional. That's enough.",
|
||||
"The bleeding stops. I breathe.",
|
||||
"{{ally}}'s hands are steadier than mine. It works.",
|
||||
"I use the supplies right. The wound yields.",
|
||||
"{{ally}} moves fast. The treatment holds.",
|
||||
"One less liability.",
|
||||
"Better than nothing. Better than before."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"Supplies exhausted before the job is done.",
|
||||
"Shaking hands fumble the medkit. Time runs out.",
|
||||
"The wound is worse than it looked. Supplies fall short.",
|
||||
"The medkit can't do what it wasn't built for.",
|
||||
"Partial healing is still an open wound.",
|
||||
"The medkit empties wrong. Wasted.",
|
||||
"The supplies run out before the job is done.",
|
||||
"My hands shake too much. Time runs out.",
|
||||
"Worse than I thought. Supplies fall short.",
|
||||
"The medkit can't do this.",
|
||||
"Half-healed is still injured.",
|
||||
"{{ally}} isn't here. I can't manage it alone.",
|
||||
"Not enough supplies. Not enough time.",
|
||||
"A noise ends the attempt prematurely.",
|
||||
"The injury resists treatment.",
|
||||
"The medkit fails the survivor. Move anyway."
|
||||
"A sound. I have to stop.",
|
||||
"The wound doesn't cooperate.",
|
||||
"The medkit fails me. I move anyway."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -217,28 +217,28 @@
|
||||
"tags": ["survival", "escape"],
|
||||
"tier": 2,
|
||||
"flavorSuccess": [
|
||||
"The pallet crashes down. A moment bought.",
|
||||
"Timber splinters between them. Distance gained.",
|
||||
"The drop lands true. The chase falters.",
|
||||
"A calculated throw. The pallet does its job.",
|
||||
"The killer staggers. A few precious seconds.",
|
||||
"The pallet drops at the right instant.",
|
||||
"An obstacle placed. The chase interrupted.",
|
||||
"The wood holds. That's all it needs to do.",
|
||||
"A roar of frustration behind the pallet. Run.",
|
||||
"The drop lands. The gap widens."
|
||||
"It crashes down between us. A moment bought.",
|
||||
"Wood and impact. I gain distance.",
|
||||
"The drop lands right. The chase falters.",
|
||||
"Timed right. The pallet works.",
|
||||
"They stagger. I use every second.",
|
||||
"The drop lands at the right instant.",
|
||||
"A barrier placed. The chase interrupted.",
|
||||
"It holds. That's all it needs to do.",
|
||||
"A roar behind the pallet. I'm already running.",
|
||||
"The gap widens. Use it."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The pallet drops wide. No gap created.",
|
||||
"Too slow — the obstacle proves useless.",
|
||||
"The throw miscalculated. The pursuit continues.",
|
||||
"The pallet falls too early. Used for nothing.",
|
||||
"The killer vaults before the drop lands.",
|
||||
"The angle was wrong. The pallet wasted.",
|
||||
"The swing comes before the pallet hits.",
|
||||
"Not enough distance to matter.",
|
||||
"The throw panics. The pallet means nothing.",
|
||||
"A wasted pallet. The chase doesn't stop."
|
||||
"The pallet drops wide. No gap.",
|
||||
"Too slow. It means nothing.",
|
||||
"I miscalculate. The chase continues.",
|
||||
"Too early. Wasted.",
|
||||
"They vault before the wood lands.",
|
||||
"Wrong angle. Wrong moment.",
|
||||
"The swing comes first.",
|
||||
"Not enough distance. Never was.",
|
||||
"I panic. The pallet follows.",
|
||||
"Wasted. The chase doesn't stop."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -247,28 +247,28 @@
|
||||
"tags": ["chest", "item", "high-risk"],
|
||||
"tier": 3,
|
||||
"flavorSuccess": [
|
||||
"The basement yields rare supplies. Worth the risk.",
|
||||
"A pristine toolbox — almost worth dying for.",
|
||||
"The gamble paid off. The survivor emerges with something valuable.",
|
||||
"The basement gives up its best. A full medkit.",
|
||||
"Down there and back. The best supplies in the trial.",
|
||||
"The risk calculates out. Everything needed, found.",
|
||||
"Down there and back. Worth it.",
|
||||
"A pristine toolbox. Almost worth dying for.",
|
||||
"The gamble paid. I have what I need.",
|
||||
"A full medkit in the basement. I don't question it.",
|
||||
"The best supplies in the trial. Found.",
|
||||
"I run the numbers. The risk pays out.",
|
||||
"The stairs back up feel like a victory.",
|
||||
"The basement held back something good tonight.",
|
||||
"The basement gives up something good.",
|
||||
"A rare find. The fog occasionally provides.",
|
||||
"Against instinct, into the basement. Worth it."
|
||||
"I go against every instinct. It works."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The basement was a trap. Retreat costs dearly.",
|
||||
"The stairwell offers no escape. A mistake made clear.",
|
||||
"The risk was not worth the reward found — nothing.",
|
||||
"The basement is empty. And now time is lost.",
|
||||
"Going down is easy. Coming back is not.",
|
||||
"The killer knows about the basement.",
|
||||
"The basement was a trap. I pay for it.",
|
||||
"The stairs offer nothing. Getting back costs more.",
|
||||
"The risk wasn't worth it. Nothing down here.",
|
||||
"Empty. And now I'm out of time.",
|
||||
"Going down is easy. Coming back is the problem.",
|
||||
"They know about the basement.",
|
||||
"Nothing down here but dread.",
|
||||
"The search finds nothing. The stairs up feel longer.",
|
||||
"I find nothing. The stairs back feel endless.",
|
||||
"An empty chest in a dangerous room.",
|
||||
"The basement takes more than it gives tonight."
|
||||
"The basement takes more than it gives."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -277,28 +277,28 @@
|
||||
"tags": ["exit", "survival", "high-risk"],
|
||||
"tier": 3,
|
||||
"flavorSuccess": [
|
||||
"The hatch sighs open. One last mercy from the fog.",
|
||||
"A sound — familiar, haunting. The hatch, just ahead.",
|
||||
"Against all odds, the escape route reveals itself.",
|
||||
"The hatch was always here. It waited.",
|
||||
"The hatch opens. One last way out.",
|
||||
"That sound — I know that sound. I run toward it.",
|
||||
"Against everything. The escape route is there.",
|
||||
"It was here all along. Waiting.",
|
||||
"The fog breaks once. That's enough.",
|
||||
"The survivor finds it before the killer does.",
|
||||
"One last door. It opens.",
|
||||
"The hatch glows faintly. Run.",
|
||||
"The sound of it — an invitation.",
|
||||
"Found. The trial ends here."
|
||||
"I find it before they do.",
|
||||
"One door left. It opens.",
|
||||
"The hatch glows. I don't wait.",
|
||||
"I hear it. I go.",
|
||||
"Found. This ends here."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The hatch is nowhere. Only fog and silence.",
|
||||
"Nothing. Only fog.",
|
||||
"Close — so close. Then it closes.",
|
||||
"The sound was something else entirely.",
|
||||
"The hatch stays hidden.",
|
||||
"Searching costs time that isn't there.",
|
||||
"The killer finds the hatch first.",
|
||||
"That sound was something else.",
|
||||
"It stays hidden.",
|
||||
"Searching burns time I don't have.",
|
||||
"They find the hatch first.",
|
||||
"The fog gives nothing freely.",
|
||||
"The sound led nowhere. A trick of the trial.",
|
||||
"No hatch. No escape. Not this way.",
|
||||
"The trial isn't done with the survivor yet."
|
||||
"The sound led nowhere.",
|
||||
"No hatch. No escape this way.",
|
||||
"The trial isn't finished with me yet."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -307,27 +307,27 @@
|
||||
"tags": ["escape", "survival"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The window frame holds. Through and clear.",
|
||||
"A clean vault. Momentum kept.",
|
||||
"The opening is tight but usable.",
|
||||
"Through the gap before the killer closes.",
|
||||
"The vault buys distance. Use it.",
|
||||
"A practiced move. The window yields.",
|
||||
"Landing clean on the other side.",
|
||||
"The window is a door when you need it.",
|
||||
"Fast enough. The gap widens.",
|
||||
"Clean vault. The frame holds.",
|
||||
"Through and clear. Momentum kept.",
|
||||
"Tight, but usable.",
|
||||
"I make it through before they close the gap.",
|
||||
"The vault buys distance. I use it.",
|
||||
"Practiced. The window yields.",
|
||||
"I land clean on the other side.",
|
||||
"The window is a door when I need it.",
|
||||
"Fast enough. The gap opens.",
|
||||
"Through. The chase resets."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The window is boarded shut.",
|
||||
"The vault is too slow. Caught.",
|
||||
"The frame splinters. Not a clean exit.",
|
||||
"Misjudged the height. A costly stumble.",
|
||||
"The window closes the gap but not the killer.",
|
||||
"Too narrow. No good.",
|
||||
"The vault fails at the worst moment.",
|
||||
"The opening was an illusion. Dead end.",
|
||||
"A bad angle kills the attempt.",
|
||||
"Boarded. No exit here.",
|
||||
"Too slow. I'm caught mid-vault.",
|
||||
"The frame splinters wrong.",
|
||||
"I misjudge the height. I pay for it.",
|
||||
"The window doesn't solve the problem.",
|
||||
"Too narrow.",
|
||||
"The worst possible moment for this to fail.",
|
||||
"The opening was an illusion.",
|
||||
"Bad angle. Bad outcome.",
|
||||
"The window doesn't help tonight."
|
||||
]
|
||||
},
|
||||
@@ -337,28 +337,28 @@
|
||||
"tags": ["stealth", "survival"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The locker closes. Footsteps pass. Breathe.",
|
||||
"Darkness and rust — perfect cover.",
|
||||
"The killer walks past the locker without a glance.",
|
||||
"The door closes. Footsteps pass. Breathe.",
|
||||
"Rust and darkness. It works.",
|
||||
"They walk past without a glance.",
|
||||
"Still. Quiet. Safe.",
|
||||
"The locker is old and cold and hiding works.",
|
||||
"In and out before the threat turns around.",
|
||||
"The locker holds its occupant safe.",
|
||||
"A long minute of nothing. Then clear.",
|
||||
"The hiding spot works. The patrol moves on.",
|
||||
"The locker door stays closed. The killer moves on."
|
||||
"Cold metal. Silence. It holds.",
|
||||
"{{ally}} draws them off. The locker stays shut.",
|
||||
"I hold my breath. The footsteps don't stop here.",
|
||||
"One long minute. Then nothing. Clear.",
|
||||
"The hiding spot works. They move on.",
|
||||
"They don't check it. I don't breathe until they're gone."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The locker door rattles. Discovered.",
|
||||
"The killer yanks it open. No hiding here.",
|
||||
"The locker was already checked.",
|
||||
"The sound of breathing gives the position away.",
|
||||
"The killer knows these lockers too well.",
|
||||
"A squeak of the hinge. Fatal.",
|
||||
"The hiding spot chosen is the wrong one.",
|
||||
"The killer's instinct is correct tonight.",
|
||||
"Spotted entering. No time.",
|
||||
"The locker offers nothing. Pulled out."
|
||||
"The door rattles. I'm found.",
|
||||
"It yanks open. No hiding here.",
|
||||
"Already checked. Bad call.",
|
||||
"My breathing gives me away.",
|
||||
"They know these lockers too well.",
|
||||
"{{ally}} makes noise nearby. They look harder. They find me.",
|
||||
"The wrong spot. I know it as soon as I'm inside.",
|
||||
"Their instinct is right tonight.",
|
||||
"Spotted going in. No time.",
|
||||
"Pulled out."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -367,28 +367,28 @@
|
||||
"tags": ["objectives", "altruistic"],
|
||||
"tier": 2,
|
||||
"flavorSuccess": [
|
||||
"The trap clicks disarmed. One less hazard.",
|
||||
"Patient work. The mechanism yields.",
|
||||
"The snap of metal, controlled this time.",
|
||||
"Disarmed without triggering. Clean.",
|
||||
"The trap comes apart safely.",
|
||||
"A moment of focus. The trap poses no more threat.",
|
||||
"It clicks safe. One less hazard.",
|
||||
"Patience. The mechanism yields.",
|
||||
"The snap of metal — controlled this time.",
|
||||
"Clean disarm. No mistakes.",
|
||||
"It comes apart safely. I exhale.",
|
||||
"One moment of focus. The trap is inert.",
|
||||
"The floor is safer now.",
|
||||
"The mechanism was elegant. Now it's inert.",
|
||||
"One trap gone. Onwards.",
|
||||
"The disarm holds. The path is clear."
|
||||
"Elegant mechanism. Now it's nothing.",
|
||||
"One trap down. Keep moving.",
|
||||
"Disarmed. Path clear."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The trap snaps. A brutal reminder.",
|
||||
"It snaps. A brutal reminder of what this place is.",
|
||||
"One wrong move. The trap wins.",
|
||||
"The mechanism was subtler than expected.",
|
||||
"The disarm attempt triggers it.",
|
||||
"Fingers too slow. The trap bites.",
|
||||
"The trap was set with someone capable in mind.",
|
||||
"Miscalculation. The mechanism triggers.",
|
||||
"The trap holds and catches.",
|
||||
"The attempt fails. Pain follows.",
|
||||
"The trap wasn't meant to be disarmed easily."
|
||||
"Subtler than I expected.",
|
||||
"My attempt triggers it.",
|
||||
"Too slow. The trap bites.",
|
||||
"Whoever set this knew what they were doing.",
|
||||
"I miscalculate. The mechanism fires.",
|
||||
"It catches me.",
|
||||
"I fail. Pain follows.",
|
||||
"It wasn't meant to be easy."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -397,26 +397,26 @@
|
||||
"tags": ["altruistic", "hook"],
|
||||
"tier": 2,
|
||||
"flavorSuccess": [
|
||||
"Off the hook. Both survivors run.",
|
||||
"The unhook is clean. No one watching.",
|
||||
"A teammate freed. The trial continues.",
|
||||
"Quick hands, lucky timing. The rescue holds.",
|
||||
"The hook releases. Time to move.",
|
||||
"Pulled free before the killer returns.",
|
||||
"The rescue works. Move fast.",
|
||||
"A window of opportunity, taken.",
|
||||
"The teammate drops free. The trial has two again.",
|
||||
"Freed. Both running now."
|
||||
"{{ally}} gets there first. Both of us run.",
|
||||
"Clean unhook. Nobody watching.",
|
||||
"I get them down. The trial continues.",
|
||||
"Fast hands, right timing.",
|
||||
"They're off the hook. We move.",
|
||||
"{{ally}} pulls them free before the killer returns.",
|
||||
"The rescue works. Don't stop moving.",
|
||||
"The window was there. I took it.",
|
||||
"{{ally}} gets them clear. Two of us running again.",
|
||||
"Free. Both running now."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The killer turns back too soon. Retreat.",
|
||||
"The rescue fails. Both caught.",
|
||||
"The timing was wrong.",
|
||||
"The unhook attempted — the killer was watching.",
|
||||
"No safe window. The rescue abandoned.",
|
||||
"The hook held on.",
|
||||
"The approach was spotted.",
|
||||
"The teammate is hooked again. Worse now.",
|
||||
"{{ally}} pulls back. The killer turns too soon.",
|
||||
"The rescue fails. Both of us in danger.",
|
||||
"Wrong timing.",
|
||||
"{{ally}} reaches for the hook — the killer is already watching.",
|
||||
"No safe window. I leave.",
|
||||
"The hook holds.",
|
||||
"{{ally}}'s approach is spotted.",
|
||||
"They're hooked again. Worse now.",
|
||||
"The rescue was a trap.",
|
||||
"The killer was closer than it looked."
|
||||
]
|
||||
@@ -427,26 +427,26 @@
|
||||
"tags": ["totem", "objectives", "altruistic"],
|
||||
"tier": 2,
|
||||
"flavorSuccess": [
|
||||
"The ruin totem falls. Generator speed returns to normal.",
|
||||
"It falls. Generator speed comes back.",
|
||||
"The hex breaks. The pressure lifts.",
|
||||
"Ruin destroyed. The generators are finally cooperating.",
|
||||
"The totem crumbles. Something screams.",
|
||||
"The ruin is gone. Work can continue properly.",
|
||||
"Ruin is gone. Finally.",
|
||||
"{{ally}} calls out the location. I put it down.",
|
||||
"One less advantage for the fog.",
|
||||
"The corrupting influence ends here.",
|
||||
"Ruin undone. A meaningful contribution.",
|
||||
"The hex shattered. Every generator benefits.",
|
||||
"Ruin falls. The trial shifts.",
|
||||
"The cleansing removes one of the fog's advantages."
|
||||
"Ruin undone. That mattered.",
|
||||
"{{ally}} watches while I cleanse. The hex shatters.",
|
||||
"Ruin falls. The whole trial shifts.",
|
||||
"One of the fog's edges, removed."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"Ruin holds. The generators resist every effort.",
|
||||
"The totem is guarded.",
|
||||
"Ruin endures. Progress is a trickle.",
|
||||
"The hex is stronger than expected.",
|
||||
"The cleanse fails. Ruin stays.",
|
||||
"Guarded or cursed — the totem won't fall.",
|
||||
"The approach to ruin is cut off.",
|
||||
"Ruin watches everything. No safe approach.",
|
||||
"Ruin holds. The generators push back at every touch.",
|
||||
"It's guarded.",
|
||||
"Ruin endures. Progress is slower than it should be.",
|
||||
"The hex is stronger than I am right now.",
|
||||
"I fail. Ruin stays.",
|
||||
"{{ally}} couldn't hold them back. Ruin stands.",
|
||||
"The path to it is cut off.",
|
||||
"Ruin sees everything. I can't get close.",
|
||||
"The hex survives the attempt.",
|
||||
"Ruin stands. The generators punish every mistake."
|
||||
]
|
||||
@@ -457,26 +457,26 @@
|
||||
"tags": ["stealth", "survival", "objectives"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The area is clear. Work continues.",
|
||||
"A careful sweep — nothing here.",
|
||||
"All quiet. Safe to proceed.",
|
||||
"The check takes seconds. Worth every one.",
|
||||
"Nothing threatening nearby. Focus returned.",
|
||||
"The perimeter is clean. Move on.",
|
||||
"A slow look around — all clear.",
|
||||
"The survivor's instincts were right. Safe.",
|
||||
"No danger. The noise was nothing.",
|
||||
"The area is empty. Continue."
|
||||
"All clear. Back to work.",
|
||||
"Nothing here. I was right to check.",
|
||||
"Quiet. Safe to continue.",
|
||||
"Seconds spent checking. Worth it.",
|
||||
"Nothing threatening nearby.",
|
||||
"{{ally}} signals clear. I continue.",
|
||||
"Slow sweep. Nothing. Move.",
|
||||
"My instincts were right. Safe.",
|
||||
"The noise was nothing.",
|
||||
"Empty. Continue."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The check reveals what was feared.",
|
||||
"Not clear. Danger is close.",
|
||||
"The area isn't empty.",
|
||||
"The sound was not nothing.",
|
||||
"A presence, sensed too late.",
|
||||
"The check confirms the worst.",
|
||||
"Not safe. Move now.",
|
||||
"The area is watched.",
|
||||
"The check confirms what I feared.",
|
||||
"Not clear. Move now.",
|
||||
"Not empty.",
|
||||
"That sound was not nothing.",
|
||||
"{{ally}}'s signal cuts out. Something is here.",
|
||||
"Confirmed. Worse than I thought.",
|
||||
"Get out.",
|
||||
"I'm being watched.",
|
||||
"The noise was a warning.",
|
||||
"Something is here."
|
||||
]
|
||||
@@ -487,26 +487,26 @@
|
||||
"tags": ["item", "objectives"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"A map of the trial grounds. The generators are marked.",
|
||||
"Routes, exits — everything useful on one piece of paper.",
|
||||
"The map provides context. Decisions improve.",
|
||||
"A map of the grounds. The generators are marked.",
|
||||
"Routes, exits — all of it on one piece of paper.",
|
||||
"The map helps. Decisions get clearer.",
|
||||
"A schematic of the realm. Useful.",
|
||||
"The map shows what couldn't be known otherwise.",
|
||||
"A rare find. The trial becomes navigable.",
|
||||
"Totem locations, hooks — the map tells all.",
|
||||
"The map is accurate. That's not guaranteed here.",
|
||||
"A clearer picture of the trial grounds.",
|
||||
"The map is old but correct. It will help."
|
||||
"The map tells me things I couldn't know otherwise.",
|
||||
"A rare find. I know where I'm going now.",
|
||||
"Totem locations, hooks — the map knows.",
|
||||
"Accurate. I didn't expect that.",
|
||||
"A clearer picture.",
|
||||
"Old, but correct. I'll take it."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"Nothing useful found.",
|
||||
"The map, if it existed, is gone.",
|
||||
"The search yields no information.",
|
||||
"Fog and confusion. No map here.",
|
||||
"Nothing useful.",
|
||||
"No map. If there was one, it's gone.",
|
||||
"The search gives me nothing.",
|
||||
"Fog and no information.",
|
||||
"The grounds give nothing away.",
|
||||
"The trial keeps its layout to itself.",
|
||||
"No orientation gained.",
|
||||
"Blind as before.",
|
||||
"Still blind.",
|
||||
"The realm offers no guide tonight.",
|
||||
"No map. Trust instinct."
|
||||
]
|
||||
@@ -517,28 +517,28 @@
|
||||
"tags": ["stealth", "altruistic"],
|
||||
"tier": 1,
|
||||
"flavorSuccess": [
|
||||
"The trail read correctly. The survivor is found.",
|
||||
"Scratch marks, followed. Another survivor located.",
|
||||
"The signs in the fog tell a story.",
|
||||
"The trail is fresh. Someone was here recently.",
|
||||
"I read the trail right. Found.",
|
||||
"{{ally}}'s marks, followed. They're close.",
|
||||
"The fog leaves clues if you know how to look.",
|
||||
"{{ally}} was just here. The trail is fresh.",
|
||||
"The marks lead somewhere useful.",
|
||||
"Reading the ground pays off.",
|
||||
"The scratch marks don't lie.",
|
||||
"A teammate's path, followed to its source.",
|
||||
"The signs are legible. The survivor is found.",
|
||||
"The trail ends at something worth finding."
|
||||
"I follow {{ally}}'s path. It ends well.",
|
||||
"Legible. I find what I was looking for.",
|
||||
"The trail ends somewhere worth being."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The trail goes cold.",
|
||||
"The marks lead nowhere useful.",
|
||||
"Misread. The path was wrong.",
|
||||
"The trail circles back. Disorienting.",
|
||||
"The signs in the fog are misleading.",
|
||||
"Too old. The trail is gone.",
|
||||
"The scratch marks weren't recent.",
|
||||
"The trail led somewhere dangerous.",
|
||||
"The signs can't be read clearly.",
|
||||
"The trail ends without resolution."
|
||||
"{{ally}}'s marks lead nowhere useful.",
|
||||
"I read it wrong. Wrong direction.",
|
||||
"The trail circles. I lose time.",
|
||||
"The fog misleads. The signs are wrong.",
|
||||
"Too old. {{ally}}'s trail is gone.",
|
||||
"The marks weren't recent.",
|
||||
"The trail leads somewhere I don't want to be.",
|
||||
"I can't make sense of them.",
|
||||
"No resolution."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -547,26 +547,26 @@
|
||||
"tags": ["high-risk", "survival"],
|
||||
"tier": 3,
|
||||
"flavorSuccess": [
|
||||
"The presence recedes. The survivor is not chosen.",
|
||||
"Whatever stalks the fog passes over.",
|
||||
"The terror subsides. Not tonight.",
|
||||
"The entity considers — then moves on.",
|
||||
"The survivor is overlooked. Lucky.",
|
||||
"The cold lifts. The entity chose elsewhere.",
|
||||
"The fog's attention moves away.",
|
||||
"Stillness. The presence is gone.",
|
||||
"The presence passes over me. Not chosen. Not tonight.",
|
||||
"Whatever stalks the fog — it moves on.",
|
||||
"The terror recedes. I'm still here.",
|
||||
"It considers. Then looks elsewhere.",
|
||||
"I'm overlooked. I don't question it.",
|
||||
"The cold lifts. It chose someone else.",
|
||||
"The fog's attention slides away.",
|
||||
"Stillness. It's gone.",
|
||||
"Not taken. Not yet.",
|
||||
"The chill passes. The trial continues."
|
||||
"The chill passes. I continue."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The fog thickens. Something approaches.",
|
||||
"The presence locks on. There is no outrunning this.",
|
||||
"The entity's attention does not waver.",
|
||||
"Noticed. The trial changes.",
|
||||
"The chill deepens. The entity is here.",
|
||||
"No escape from something this deliberate.",
|
||||
"The fog moves with purpose.",
|
||||
"The survivor is seen by something that doesn't forget.",
|
||||
"The fog thickens around me. Something is coming.",
|
||||
"It locks on. There's no running from this.",
|
||||
"The attention doesn't move.",
|
||||
"Noticed. Everything changes.",
|
||||
"The chill deepens. It's here.",
|
||||
"Nothing escapes something this deliberate.",
|
||||
"The fog moves with intent.",
|
||||
"Something sees me. Something that doesn't forget.",
|
||||
"The presence descends.",
|
||||
"Chosen. The hardest part begins."
|
||||
]
|
||||
@@ -577,28 +577,28 @@
|
||||
"tags": ["high-risk", "stealth"],
|
||||
"tier": 3,
|
||||
"flavorSuccess": [
|
||||
"The instinct passes harmlessly. Not found.",
|
||||
"The killer's sense of where to look is wrong tonight.",
|
||||
"The prediction fails. Safe.",
|
||||
"The killer checks elsewhere.",
|
||||
"Instinct misfires. The survivor is still hidden.",
|
||||
"Wrong corner checked. The survivor breathes.",
|
||||
"The killer's certainty was misplaced.",
|
||||
"The instinct misfires. I'm not found.",
|
||||
"They look in the wrong place.",
|
||||
"The prediction fails. I'm safe.",
|
||||
"They check elsewhere.",
|
||||
"Wrong corner. I breathe.",
|
||||
"They're certain. They're wrong.",
|
||||
"The read was off. I move.",
|
||||
"Not there. Not tonight.",
|
||||
"The instinct was wrong. Move quickly.",
|
||||
"The killer's focus breaks elsewhere."
|
||||
"The instinct fails them.",
|
||||
"Their focus breaks. I use it."
|
||||
],
|
||||
"flavorFailure": [
|
||||
"The killer knows exactly where to look.",
|
||||
"Instinct and experience. The survivor is found.",
|
||||
"No hiding from something this certain.",
|
||||
"The killer's read was correct.",
|
||||
"The position is given away before the search begins.",
|
||||
"Exactly where expected. No luck tonight.",
|
||||
"The killer's certainty was earned.",
|
||||
"Found before the search starts.",
|
||||
"They know exactly where I am.",
|
||||
"Instinct and experience. I'm found.",
|
||||
"There's no hiding from something this certain.",
|
||||
"The read was right.",
|
||||
"My position is given away before the search starts.",
|
||||
"Exactly where expected.",
|
||||
"Their certainty was earned.",
|
||||
"Found before the search begins.",
|
||||
"The instinct is right.",
|
||||
"The killer walks directly to the survivor."
|
||||
"They walk directly to me."
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
63
libs/encounter-library/src/lib/survivors.ts
Normal file
63
libs/encounter-library/src/lib/survivors.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
export const SURVIVOR_NAMES: readonly string[] = [
|
||||
'Dwight Fairfield',
|
||||
'Meg Thomas',
|
||||
'Claudette Morel',
|
||||
'Jake Park',
|
||||
'Nea Karlsson',
|
||||
'Laurie Strode',
|
||||
'Ace Visconti',
|
||||
'Bill Overbeck',
|
||||
'Feng Min',
|
||||
'David King',
|
||||
'Quentin Smith',
|
||||
'David Tapp',
|
||||
'Kate Denson',
|
||||
'Adam Francis',
|
||||
'Jeff Johansen',
|
||||
'Jane Romero',
|
||||
'Ash Williams',
|
||||
'Nancy Wheeler',
|
||||
'Steve Harrington',
|
||||
'Yui Kimura',
|
||||
'Zarina Kassir',
|
||||
'Cheryl Mason',
|
||||
'Felix Richter',
|
||||
'Élodie Rakoto',
|
||||
'Yun-Jin Lee',
|
||||
'Jill Valentine',
|
||||
'Leon S. Kennedy',
|
||||
'Mikaela Reid',
|
||||
'Jonah Vasquez',
|
||||
'Yoichi Asakawa',
|
||||
'Haddie Kaur',
|
||||
'Ada Wong',
|
||||
'Rebecca Chambers',
|
||||
'Vittorio Toscano',
|
||||
'Thalita Lyra',
|
||||
'Renato Lyra',
|
||||
'Gabriel Soma',
|
||||
'Nicolas Cage',
|
||||
'Ellen Ripley',
|
||||
'Alan Wake',
|
||||
'Sable Ward',
|
||||
'Aestri Yazar',
|
||||
'Lara Croft',
|
||||
'Trevor Belmont',
|
||||
'Taurie Cain',
|
||||
'Rick Grimes',
|
||||
'Michonne Grimes',
|
||||
'Vee Boonyasak',
|
||||
];
|
||||
|
||||
export const ALLY_FIRST_NAMES: readonly string[] = [
|
||||
'Dwight', 'Meg', 'Claudette', 'Jake', 'Nea',
|
||||
'Laurie', 'Ace', 'Bill', 'Feng', 'David',
|
||||
'Quentin', 'Tapp', 'Kate', 'Adam', 'Jeff',
|
||||
'Jane', 'Ash', 'Nancy', 'Steve', 'Yui',
|
||||
'Zarina', 'Cheryl', 'Felix', 'Élodie', 'Yun-Jin',
|
||||
'Jill', 'Leon', 'Mikaela', 'Jonah', 'Yoichi',
|
||||
'Haddie', 'Ada', 'Rebecca', 'Vittorio', 'Thalita',
|
||||
'Renato', 'Gabriel', 'Nicolas', 'Ellen', 'Alan',
|
||||
'Sable', 'Aestri', 'Lara', 'Trevor',
|
||||
'Taurie', 'Rick', 'Michonne', 'Vee',
|
||||
];
|
||||
Reference in New Issue
Block a user