Skip to content

Commit

Permalink
lots o updates
Browse files Browse the repository at this point in the history
  • Loading branch information
charredUtensil committed Nov 29, 2024
1 parent ecdaafc commit 5594ee2
Show file tree
Hide file tree
Showing 42 changed files with 421 additions and 99 deletions.
9 changes: 6 additions & 3 deletions src/core/architects/build_and_power.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { OrderedOrEstablishedPlan } from "../transformers/01_planning/05_establi
import { DefaultCaveArchitect, PartialArchitect } from "./default";
import { intersectsOnly } from "./utils/intersects";
import { gObjectives } from "./utils/objectives";
import { getPlaceRechargeSeams } from "./utils/resources";
import { Rough, mkRough } from "./utils/rough";
import { EventChainLine, mkVars, transformPoint } from "./utils/script";

Expand Down Expand Up @@ -47,10 +48,10 @@ function buildAndPower(
pgFirst: PhraseGraph<State, Format & {remainingCount: number}>,
pgPenultimate: PhraseGraph<State, Format>,
pgLast: PhraseGraph<State, Format>,
minLevel: Building["level"] = 1,
minLevel: Building["level"],
): Pick<
Architect<BuildAndPowerMetadata>,
"prime" | "objectives" | "script" | "scriptGlobals"
"prime" | "placeRechargeSeam" | "objectives" | "script" | "scriptGlobals"
> {
const g = mkVars(`gBuPw${template.inspectAbbrev}`, [
"built",
Expand All @@ -70,6 +71,7 @@ function buildAndPower(
]);
return {
prime: () => metadata,
placeRechargeSeam: getPlaceRechargeSeams(3),
objectives({ cavern }) {
const count = cavern.plans.filter(
(plan) =>
Expand Down Expand Up @@ -270,7 +272,7 @@ export const BUILD_AND_POWER = [
...buildAndPower(SUPPORT_STATION,
BUILD_POWER_SS_FIRST,
BUILD_POWER_SS_PENULTIMATE,
BUILD_POWER_SS_LAST, 5),
BUILD_POWER_SS_LAST, 1),
...mkRough(
{ of: Rough.ALWAYS_FLOOR, width: 2 },
{ of: Rough.LAVA, width: 2, grow: 1 },
Expand All @@ -283,6 +285,7 @@ export const BUILD_AND_POWER = [
return (
plan.fluid === Tile.LAVA &&
!plan.hasErosion &&
!plan.intersects.some((_, pi) => cavern.plans[pi].hasErosion) &&
plan.pearlRadius > 3 &&
plan.path.baseplates.length === 1 &&
amd?.tag === "hq" &&
Expand Down
1 change: 0 additions & 1 deletion src/core/architects/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export const [DefaultCaveArchitect, DefaultHallArchitect] = (
},
placeErosion: (args) => placeErosion(30, 10, args),
placeEntities: () => ({}),
objectives: () => undefined,
maxSlope: undefined,
claimEventOnDiscover: () => [],
}) as PartialArchitect<any>,
Expand Down
2 changes: 1 addition & 1 deletion src/core/architects/established_hq/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export function getPlaceBuildings({
const building = buildings[i];
let fTile: Tile;
if ("placeRubbleInstead" in building) {
fTile = Tile.RUBBLE_4;
fTile = Tile.RUBBLE_1;
} else {
fTile = Tile.FOUNDATION;
if (dependencies.has(building.template)) {
Expand Down
48 changes: 43 additions & 5 deletions src/core/architects/established_hq/gas_leak.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { inferContextDefaults } from "../../common";
import { GAS_LEAK_NO_AIR } from "../../lore/graphs/events";
import { Architect } from "../../models/architect";
import {
TOOL_STORE,
Expand All @@ -6,6 +8,9 @@ import {
TELEPORT_PAD,
ELECTRIC_FENCE_ID,
} from "../../models/building";
import { gCreatures } from "../utils/creature_spawners";
import { gObjectives } from "../utils/objectives";
import { mkVars } from "../utils/script";
import { BASE, HqMetadata, getPlaceBuildings } from "./base";

const T0_BUILDINGS = [TOOL_STORE, TELEPORT_PAD, POWER_STATION, SUPPORT_STATION] as const;
Expand All @@ -15,11 +20,19 @@ const STARTING_BONUS_CRYSTALS = 2;
const GAS_LEAK_BASE: Pick<
Architect<HqMetadata>,
| "crystalsFromMetadata"
| "mod"
| "prime"
| "placeBuildings"
| "scriptGlobals"
| "holdCreatures"
| "script"
> = {
crystalsFromMetadata: (metadata) => STARTING_BONUS_CRYSTALS + metadata.crystalsInBuildings,
mod(cavern) {
const context = inferContextDefaults({
globalHostilesCap: 4,
...cavern.initialContext,
});
return {...cavern, context, oxygen: [500, 500]}
},
prime: () => {
return {
crystalsInBuildings: T0_CRYSTALS,
Expand All @@ -28,16 +41,41 @@ const GAS_LEAK_BASE: Pick<
tag: "hq",
};
},
crystalsFromMetadata: (metadata) => STARTING_BONUS_CRYSTALS + metadata.crystalsInBuildings,
placeBuildings: getPlaceBuildings({
discovered: true,
from: 2,
templates: () => T0_BUILDINGS,
}),
scriptGlobals({sb}) {
holdCreatures: () => true,
script({cavern, plan, sb}) {
const v = mkVars(`p${plan.id}GlHq`, ['msgNoAir', 'holdLoop']);
const rng = cavern.dice.script(plan.id);
sb.onInit(
`disable:${ELECTRIC_FENCE_ID};`,
`crystals=${STARTING_BONUS_CRYSTALS};`
)
`crystals=${STARTING_BONUS_CRYSTALS};`,
`${v.holdLoop};`,
);
sb.declareString(
v.msgNoAir, {pg: GAS_LEAK_NO_AIR, rng}
);
sb.if(
`${gCreatures.airMiners}==0`,
`((${gObjectives.won}>0))return;`,
`wait:5;`,
`msg:${v.msgNoAir};`,
);
sb.event(
v.holdLoop,
// 5-10 minutes of peace
`wait:random(${5 * 60})(${10 * 60});`,
`${gCreatures.anchorHold}=0;`,
// 5-10 minutes of monsters
`wait:random(${5 * 60})(${10 * 60});`,
`${gCreatures.anchorHold}=1;`,
// Loop
`${v.holdLoop};`,
);
},
};

Expand Down
2 changes: 1 addition & 1 deletion src/core/architects/mob_farm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import { getPlaceRechargeSeams, sprinkleCrystals } from "./utils/resources";
import { inferContextDefaults } from "../common";
import { mkVars } from "./utils/script";
import {
HINT_SELECT_LASER_GROUP,
MOB_FARM_NO_LONGER_BLOCKING,
} from "../lore/graphs/events";
import { HINT_SELECT_LASER_GROUP } from "../lore/graphs/hints";
import { gObjectives } from "./utils/objectives";

const BANLIST = [
Expand Down
2 changes: 1 addition & 1 deletion src/core/architects/ore_waste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const BASE: PartialArchitect<typeof METADATA> = {
// ore. No reason to prolong this with an additional ore objective.
return undefined;
}
const studs = (getTotalOre(cavern) - ORE_OVERHEAD) * cavern.context.crystalGoalRatio / 2;
const studs = (getTotalOre(cavern) - ORE_OVERHEAD) * 0.12 / 2;
return {
studs: Math.floor(studs / 5) * 5,
sufficient: false,
Expand Down
11 changes: 8 additions & 3 deletions src/core/architects/utils/objectives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ export function objectiveGlobals({
sb.declareInt(gObjectives.met, 0);
sb.declareInt(gObjectives.won, 0);
if (!resources.length) {
// skip
// No resource goals. Skip.
} else if (resources.length === 1) {
sb.if(`${resources[0]}>=${objectives[resources[0]]}`, `${gObjectives.met}+=1;`)
// One resource goal. When met, mark objective as completed.
sb.if(
`${resources[0]}>=${objectives[resources[0]]}`,
`${gObjectives.met}+=1;`,
);
} else {
sb.declareInt(gObjectives.res, 1);
// Multiple resource goals. Must check all are satisfied simultaneously.
sb.declareInt(gObjectives.res, 0);
resources.forEach((resource) =>
sb.when(
`${resource}>=${objectives[resource]}`,
Expand Down
2 changes: 1 addition & 1 deletion src/core/architects/utils/tile_scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { EventChainLine, ScriptBuilder, transformPoint } from "./script";

const TRIGGERS = {
flood: (cavern, x, y) => `place:${transformPoint(cavern, [x, y])},${Tile.WATER.id};`,
waste: (cavern, x, y) => `place:${transformPoint(cavern, [x, y])},${Tile.WASTE_RUBBLE_4.id};`,
waste: (cavern, x, y) => `place:${transformPoint(cavern, [x, y])},${Tile.WASTE_RUBBLE_3.id};`,
} as const satisfies {[key: string]: (cavern: PreprogrammedCavern, x: number, y: number) => EventChainLine};

export function tileScript({cavern, sb}: {
Expand Down
5 changes: 5 additions & 0 deletions src/core/common/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ export type CavernContext = {
* Does this cavern have limited air?
*/
readonly hasAirLimit: boolean;
/**
* Bias toward (or against) the anchor being in the center.
*/
readonly anchorGravity: number;
/**
* How blobby and jagged caves should be.
* 0 results in perfectly squashed octagons.
Expand Down Expand Up @@ -295,6 +299,7 @@ const STANDARD_DEFAULTS = {
optimalAuxiliaryPathCount: 2,
randomAuxiliaryPathCount: 3,
auxiliaryPathMinAngle: Math.PI / 4,
anchorGravity: 0,
caveBaroqueness: 0.16,
hallBaroqueness: 0.07,
caveCrystalRichness: { base: 0.16, hops: 0.32, order: 0.32 },
Expand Down
11 changes: 11 additions & 0 deletions src/core/lore/graphs/build_and_power.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { BUILD_POWER_GC_FIRST, BUILD_POWER_GC_LAST, BUILD_POWER_GC_PENULTIMATE, BUILD_POWER_SS_FIRST, BUILD_POWER_SS_LAST, BUILD_POWER_SS_PENULTIMATE } from "./build_and_power";
import testCompleteness from "./completeness";

testCompleteness(
BUILD_POWER_GC_FIRST,
BUILD_POWER_GC_LAST,
BUILD_POWER_GC_PENULTIMATE,
BUILD_POWER_SS_FIRST,
BUILD_POWER_SS_LAST,
BUILD_POWER_SS_PENULTIMATE,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import ALL_GRAPHS from ".";
import phraseGraph, { PhraseGraph } from "../utils/builder";
import { FoundLostMinersState, State } from "../lore";

Expand Down Expand Up @@ -86,10 +85,12 @@ function expectCompletion(actual: PhraseGraph<any, any>) {
expect(missing).toEqual([]);
}

describe(`Graph is complete`, () => {
ALL_GRAPHS.forEach((pg) => {
test(`for ${pg.name}`, () => {
expectCompletion(pg);
export default function testCompleteness(...graphs: PhraseGraph<any, any>[]) {
describe(`Graph is complete`, () => {
graphs.forEach((pg) => {
test(`for ${pg.name}`, () => {
expectCompletion(pg);
});
});
});
});
})
};
7 changes: 7 additions & 0 deletions src/core/lore/graphs/conclusions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import testCompleteness from "./completeness";
import { FAILURE, SUCCESS } from "./conclusions";

testCompleteness(
SUCCESS,
FAILURE,
)
26 changes: 23 additions & 3 deletions src/core/lore/graphs/conclusions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ const COMMENDATIONS = [
export const SUCCESS = phraseGraph<State & { readonly commend: boolean }, Format>(
"Conclusion - Success",
({ pg, state, start, end, cut, skip }) => {
const coda = pg();
(() => {
const head = (() => {
const commend = state("commend").then("Wow!", ...COMMENDATIONS);
const hasMonsters = state("hasMonsters").then(
({format: {enemies}}) => `Those ${enemies} were no match for you!`,
Expand All @@ -67,7 +66,9 @@ export const SUCCESS = phraseGraph<State & { readonly commend: boolean }, Format
skip,
state("hasMonsters", "spawnHasErosion", "spawnIsGasLeak").then(despiteTheOdds),
);
})()
})();
const coda = pg();
head
.then("you")
.then(
pg("managed to", "were able to")
Expand Down Expand Up @@ -133,6 +134,25 @@ export const SUCCESS = phraseGraph<State & { readonly commend: boolean }, Format
.then(skip, state("hasMonsters"))
.then(skip, state("spawnHasErosion"))
.then(end);

head.then(
pg(
state("buildAndPowerGcOne").then(
"That Geological Center you built will be very useful to decide " +
"where we can mine next."),
state("buildAndPowerGcMultiple").then(
"Those Geological Centers you built are already helping us far " +
"beyond the reaches of this cavern."),
).then(
skip,
"We already have a promising lead!",
({format: {buildAndPowerGcCount}}) => `\
With ${buildAndPowerGcCount === 1 ? 'this' : 'these'} built, we can safely \
make our way further into the planet.`,
),
).then(
skip, state("hasMonsters")
).then(coda);
},
);

Expand Down
17 changes: 17 additions & 0 deletions src/core/lore/graphs/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import testCompleteness from "./completeness";
import { BLACKOUT_END, BLACKOUT_START, BOSS_ENEMY_DEFEATED, FAILURE_BASE_DESTROYED, FOUND_ALL_LOST_MINERS, FOUND_HOARD, FOUND_HQ, FOUND_LM_BREADCRUMB, FOUND_LOST_MINERS, FOUND_SLUG_NEST, GAS_LEAK_NO_AIR, MOB_FARM_NO_LONGER_BLOCKING } from "./events";

testCompleteness(
FOUND_ALL_LOST_MINERS,
FOUND_HOARD,
FOUND_HQ,
FOUND_LM_BREADCRUMB,
FOUND_LOST_MINERS,
FOUND_SLUG_NEST,
FAILURE_BASE_DESTROYED,
BOSS_ENEMY_DEFEATED,
BLACKOUT_START,
BLACKOUT_END,
MOB_FARM_NO_LONGER_BLOCKING,
GAS_LEAK_NO_AIR,
)
19 changes: 16 additions & 3 deletions src/core/lore/graphs/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,19 @@ export const MOB_FARM_NO_LONGER_BLOCKING = phraseGraph<State, Format>(
},
);

export const HINT_SELECT_LASER_GROUP = `Hint: Hold SHIFT+click to select multiple units.
CTRL+[0-9] assigns a group of units that you can recall with [0-9].
X activates laser mode.`;
export const GAS_LEAK_NO_AIR = phraseGraph<State, Format>(
"Gas Leak - All Support Stations offline",
({ pg, state, start, end, cut, skip }) => {
start.then(
skip,
"Careful there!",
).then(
"Without even one Support Station online, this cavern will be " +
"uninhabitable very quickly.",
).then(
"Fix it NOW or we will need to abort!"
).then(end);
}
)


5 changes: 5 additions & 0 deletions src/core/lore/graphs/hints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export const HINT_SELECT_LASER_GROUP = `\
Hint: Hold SHIFT+click to select multiple units.\
CTRL+[0-9] assigns a group of units that you can recall with [0-9].\
X activates laser mode.`;
2 changes: 2 additions & 0 deletions src/core/lore/graphs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
FOUND_HQ,
FOUND_LOST_MINERS,
FOUND_SLUG_NEST,
GAS_LEAK_NO_AIR,
NOMADS_SETTLED,
} from "./events";
import { NAME } from "./names";
Expand All @@ -41,6 +42,7 @@ const ALL_GRAPHS = [
FOUND_HQ,
FOUND_LOST_MINERS,
FOUND_SLUG_NEST,
GAS_LEAK_NO_AIR,
NAME,
NOMADS_SETTLED,
ORDERS,
Expand Down
4 changes: 4 additions & 0 deletions src/core/lore/graphs/names.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import testCompleteness from "./completeness";
import { NAME } from "./names";

testCompleteness(NAME);
Loading

0 comments on commit 5594ee2

Please sign in to comment.