Skip to content

Commit

Permalink
stash
Browse files Browse the repository at this point in the history
  • Loading branch information
charredUtensil committed Sep 21, 2024
1 parent 774f961 commit e793918
Show file tree
Hide file tree
Showing 17 changed files with 374 additions and 181 deletions.
254 changes: 154 additions & 100 deletions src/core/architects/build_and_power.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { BUILD_POWER_GC_FIRST, BUILD_POWER_GC_LAST, BUILD_POWER_GC_PENULTIMATE } from "../lore/graphs/build_and_power";
import {
BUILD_POWER_GC_FIRST,
BUILD_POWER_GC_LAST,
BUILD_POWER_GC_PENULTIMATE,
} from "../lore/graphs/build_and_power";
import { LoreDie, spellNumber } from "../lore/lore";
import { Architect } from "../models/architect";
import { Building, GEOLOGICAL_CENTER } from "../models/building";
Expand All @@ -7,12 +11,19 @@ import { OrderedOrEstablishedPlan } from "../transformers/01_planning/05_establi
import { DefaultCaveArchitect, PartialArchitect } from "./default";
import { intersectsOnly } from "./utils/intersects";
import { Rough, mkRough } from "./utils/rough";
import { declareStringFromLore, eventChain, eventChainSynchronized, mkVars, scriptFragment, transformPoint } from "./utils/script";
import {
declareStringFromLore,
eventChain,
eventChainSynchronized,
mkVars,
scriptFragment,
transformPoint,
} from "./utils/script";

const TAG = 'buildAndPower' as const;
const TAG = "buildAndPower" as const;
export type BuildAndPowerMetadata = {
readonly tag: typeof TAG;
readonly template: Building['template'];
readonly template: Building["template"];
};

const BASE: PartialArchitect<BuildAndPowerMetadata> = {
Expand All @@ -21,42 +32,62 @@ const BASE: PartialArchitect<BuildAndPowerMetadata> = {
};

function buildAndPower(
template: Building['template'],
minLevel: Building['level'] = 1,
): Pick<Architect<BuildAndPowerMetadata>, "prime" | "objectives" | "script" | "scriptGlobals"> {
const g = mkVars(
`gBp${template.inspectAbbrev}`,
[ 'onBuild', 'built', 'onPower', 'doneCount', 'done', 'msgA', 'msgB', 'msgC', 'onComplete' ]
);
template: Building["template"],
minLevel: Building["level"] = 1,
): Pick<
Architect<BuildAndPowerMetadata>,
"prime" | "objectives" | "script" | "scriptGlobals"
> {
const g = mkVars(`gBp${template.inspectAbbrev}`, [
"onBuild",
"built",
"onPower",
"doneCount",
"done",
"msgA",
"msgB",
"msgC",
"onComplete",
]);
const metadata: BuildAndPowerMetadata = { tag: TAG, template };
const mv = (plan: Plan<any>) => mkVars(
`p${plan.id}Bp${template.inspectAbbrev}`,
['arrow', 'building', 'onInit', 'onBuild'],
);
const mv = (plan: Plan<any>) =>
mkVars(`p${plan.id}Bp${template.inspectAbbrev}`, [
"arrow",
"building",
"onInit",
"onBuild",
]);
return {
prime: () => metadata,
objectives({cavern}) {
const count = cavern.plans
.filter(plan => plan.metadata?.tag === TAG && plan.metadata.template === template).length;
objectives({ cavern }) {
const count = cavern.plans.filter(
(plan) =>
plan.metadata?.tag === TAG && plan.metadata.template === template,
).length;
return {
variables: [{
condition: `${g.done}>0`,
description: [
'Build and power a ',
minLevel > 1 ? `Level ${minLevel} ` : '',
template.name,
' in ',
count > 1 ? 'each' : 'the',
' marked cave.',
].join('')
}],
variables: [
{
condition: `${g.done}>0`,
description: [
"Build and power a ",
minLevel > 1 ? `Level ${minLevel} ` : "",
template.name,
" in ",
count > 1 ? "each" : "the",
" marked cave.",
].join(""),
},
],
sufficient: true,
}
};
},
scriptGlobals({cavern}) {
scriptGlobals({ cavern }) {
const pvs = cavern.plans
.filter(plan => plan.metadata?.tag === TAG && plan.metadata.template === template)
.map(plan => mv(plan));
.filter(
(plan) =>
plan.metadata?.tag === TAG && plan.metadata.template === template,
)
.map((plan) => mv(plan));
return scriptFragment(
`# Globals: Build and Power ${template.name}`,

Expand All @@ -65,76 +96,96 @@ function buildAndPower(
// have collisions. In theory, it shouldn't be possible to level up
// multiple buildings at the same time.
`building ${g.built}`,
`when(${template.id}.${minLevel > 1 ? 'levelup' : 'new'})[${g.onBuild}]`,
`when(${template.id}.${minLevel > 1 ? "levelup" : "new"})[${g.onBuild}]`,
eventChain(
g.onBuild,
`savebuilding:${g.built};`,
minLevel > 1 && `((${g.built}.level<${minLevel}))return;`,
...pvs.map(v => `${v.onBuild};` satisfies `${string};`),
...pvs.map((v) => `${v.onBuild};` satisfies `${string};`),
),

// Second trigger: power state changes.
`int ${g.doneCount}=0`,
...pvs.map(v => `arrow ${v.arrow}`),
...pvs.map(v => `building ${v.building}`),
...pvs.map((v) => `arrow ${v.arrow}`),
...pvs.map((v) => `building ${v.building}`),
`when(${template.id}.poweron)[${g.onPower}]`,
`when(${template.id}.poweroff)[${g.onPower}]`,
eventChainSynchronized(
g.onPower,
`${g.doneCount}=0;`,
...pvs.flatMap(v => [
`((${v.building}.powered>0))[hidearrow:${v.arrow}][showarrow:${v.building}.row,${v.building}.column,${v.arrow}];`,
`((${v.building}.powered>0))${g.doneCount}+=1;`,
] satisfies `${string};`[]),
...pvs.flatMap(
(v) =>
[
`((${v.building}.powered>0))[hidearrow:${v.arrow}][showarrow:${v.building}.row,${v.building}.column,${v.arrow}];`,
`((${v.building}.powered>0))${g.doneCount}+=1;`,
] satisfies `${string};`[],
),
),

// Messages & done trigger
pvs.length > 1 && scriptFragment(
declareStringFromLore(cavern, LoreDie.buildAndPower, g.msgA, BUILD_POWER_GC_FIRST, {}, {
buildingName: template.name,
remainingCount: spellNumber(pvs.length - 1)}),
`if(${g.doneCount}==1)[msg:${g.msgA}]`,
),
pvs.length > 2 && scriptFragment(
declareStringFromLore(cavern, LoreDie.buildAndPower, g.msgB, BUILD_POWER_GC_PENULTIMATE, {}, {
pvs.length > 1 &&
scriptFragment(
declareStringFromLore(
cavern,
LoreDie.buildAndPower,
g.msgA,
BUILD_POWER_GC_FIRST,
{},
{
buildingName: template.name,
remainingCount: spellNumber(pvs.length - 1),
},
),
`if(${g.doneCount}==1)[msg:${g.msgA}]`,
),
pvs.length > 2 &&
scriptFragment(
declareStringFromLore(
cavern,
LoreDie.buildAndPower,
g.msgB,
BUILD_POWER_GC_PENULTIMATE,
{},
{
buildingName: template.name,
},
),
`if(${g.doneCount}==${pvs.length - 1})[msg:${g.msgB}]`,
),
`int ${g.done}=0`,
declareStringFromLore(
cavern,
LoreDie.buildAndPower,
g.msgC,
BUILD_POWER_GC_LAST,
{},
{
buildingName: template.name,
}),
`if(${g.doneCount}==${pvs.length - 1})[msg:${g.msgB}]`,
},
),
`int ${g.done}=0`,
declareStringFromLore(cavern, LoreDie.buildAndPower, g.msgC, BUILD_POWER_GC_LAST, {}, {
buildingName: template.name,
}),
`if(${g.doneCount}>=${pvs.length})[${g.onComplete}]`,
eventChain(
g.onComplete,
`msg:${g.msgC};`,
'wait:2;',
`${g.done}=1;`,
),
eventChain(g.onComplete, `msg:${g.msgC};`, "wait:2;", `${g.done}=1;`),
);
},
script({cavern, plan}) {
script({ cavern, plan }) {
const v = mv(plan);
if (plan.path.baseplates.length > 1) {
throw new Error('Plan must have one baseplate.');
throw new Error("Plan must have one baseplate.");
}
const bp = plan.path.baseplates[0];
const arrowPos = plan.innerPearl.flatMap(ly => ly)
.find(pos => cavern.tiles.get(...pos)?.isWall === false);
const arrowPos = plan.innerPearl
.flatMap((ly) => ly)
.find((pos) => cavern.tiles.get(...pos)?.isWall === false);
if (!arrowPos) {
throw new Error('No non-wall points found');
throw new Error("No non-wall points found");
}
const atp = transformPoint(cavern, arrowPos);
const openOnSpawn = cavern.discoveryZones.get(...arrowPos)!.openOnSpawn;

return scriptFragment(
`# P${plan.id}: Build and Power ${template.name}`,
`if(${openOnSpawn ? `time:0` : `change:${atp}`})[${v.onInit}]`,
eventChain(
v.onInit,
`showarrow:${atp},${v.arrow};`,
),
eventChain(v.onInit, `showarrow:${atp},${v.arrow};`),
eventChain(
v.onBuild,
// Filter out buildings outside the baseplate rectangle
Expand All @@ -146,21 +197,21 @@ function buildAndPower(
`${g.onPower};`,
),
);
}
}
},
};
}

function bidHelper(
plans: readonly OrderedOrEstablishedPlan[],
template: Building['template'],
template: Building["template"],
max: number,
dormant: number,
active: number,
): number | false {
let extantCount = 0;
let unestablishedCount = 0;
for (const p of plans) {
if (p.kind === 'cave' && !p.architect) {
if (p.kind === "cave" && !p.architect) {
unestablishedCount++;
} else if (p.metadata?.tag === TAG) {
if (p.metadata.template !== template) {
Expand All @@ -186,35 +237,38 @@ export const BUILD_AND_POWER = [
...buildAndPower(GEOLOGICAL_CENTER, 5),
...mkRough(
{ of: Rough.FLOOR, width: 2, grow: 1 },
{ of: Rough.MIX_DIRT_LOOSE_ROCK, grow: 1, },
{ of: Rough.MIX_DIRT_LOOSE_ROCK, grow: 1 },
{ of: Rough.MIX_LOOSE_HARD_ROCK, grow: 0.5 },
{ of: Rough.VOID, width: 0, grow: 0.5 },
),
placeBuildings({ cavern, plan, openCaveFlags }) {
plan.innerPearl.some(ly => ly.some(pos => {
if (cavern.tiles.get(...pos)?.isWall === false) {
openCaveFlags.set(...pos, true);
return true;
}
return false;
}))
plan.innerPearl.some((ly) =>
ly.some((pos) => {
if (cavern.tiles.get(...pos)?.isWall === false) {
openCaveFlags.set(...pos, true);
return true;
}
return false;
}),
);
return {};
},
caveBid: ({ cavern, plans, plan, hops }) =>
{
const amd = plans[cavern.anchor].metadata;
return !plan.fluid &&
plan.pearlRadius > 2 &&
plan.pearlRadius < 10 &&
plan.path.baseplates.length === 1 &&
!(amd?.tag === 'hq' && amd.fixedComplete) &&
intersectsOnly(plans, plan, null) &&
hops.length > 5 &&
!hops.some(h => {
const m = plans[h].metadata;
return m?.tag === TAG && m.template === GEOLOGICAL_CENTER;
}) &&
bidHelper(plans, GEOLOGICAL_CENTER, 3, 0.04, 10);
},
}
] as const satisfies readonly Architect<BuildAndPowerMetadata>[]
caveBid: ({ cavern, plans, plan, hops }) => {
const amd = plans[cavern.anchor].metadata;
return (
!plan.fluid &&
plan.pearlRadius > 2 &&
plan.pearlRadius < 10 &&
plan.path.baseplates.length === 1 &&
!(amd?.tag === "hq" && amd.fixedComplete) &&
intersectsOnly(plans, plan, null) &&
hops.length > 5 &&
!hops.some((h) => {
const m = plans[h].metadata;
return m?.tag === TAG && m.template === GEOLOGICAL_CENTER;
}) &&
bidHelper(plans, GEOLOGICAL_CENTER, 3, 0.04, 10)
);
},
},
] as const satisfies readonly Architect<BuildAndPowerMetadata>[];
9 changes: 8 additions & 1 deletion src/core/architects/established_hq/fixed_complete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ export const FC_BASE: Pick<
// nobody wants that.
...ALL_BUILDINGS.map((bt) => `disable:${bt.id};` as `${string};`),
),
declareStringFromLore(cavern, LoreDie.failureBaseDestroyed, gFCHQ.msgBaseDestroyed, FAILURE_BASE_DESTROYED, {}, {}),
declareStringFromLore(
cavern,
LoreDie.failureBaseDestroyed,
gFCHQ.msgBaseDestroyed,
FAILURE_BASE_DESTROYED,
{},
{},
),
`int ${gFCHQ.wasBaseDestroyed}=0`,
`if(${TOOL_STORE.id}<=0)[${gFCHQ.onBaseDestroyed}]`,
`if(${POWER_STATION.id}<=0)[${gFCHQ.onBaseDestroyed}]`,
Expand Down
10 changes: 9 additions & 1 deletion src/core/architects/established_hq/lost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,15 @@ const LOST_BASE: Pick<

return scriptFragment(
`# P${plan.id}: Lost HQ`,
shouldPanMessage && declareStringFromLore(cavern, LoreDie.foundHq, v.messageDiscover, FOUND_HQ, {}, {}),
shouldPanMessage &&
declareStringFromLore(
cavern,
LoreDie.foundHq,
v.messageDiscover,
FOUND_HQ,
{},
{},
),
`if(change:${transformPoint(cavern, discoPoint)})[${v.onDiscover}]`,
eventChain(
v.onDiscover,
Expand Down
Loading

0 comments on commit e793918

Please sign in to comment.