@kitten-science/kitten-scientists
Version:
Add-on for the wonderful incremental browser game: https://kittensgame.com/web/
294 lines • 14.5 kB
JavaScript
import { isNil, mustExist } from "@oliversalzburg/js-utils/data/nil.js";
import { BulkPurchaseHelper } from "./helper/BulkPurchaseHelper.js";
import { BonfireSettings, } from "./settings/BonfireSettings.js";
import { cl } from "./tools/Log.js";
export class BonfireManager {
_host;
settings;
_bulkManager;
_workshopManager;
constructor(host, workshopManager, settings = new BonfireSettings()) {
this._host = host;
this.settings = settings;
this._workshopManager = workshopManager;
this._bulkManager = new BulkPurchaseHelper(this._host, this._workshopManager);
}
tick(context) {
if (!this.settings.enabled) {
return;
}
this._bulkManager.resetPriceCache();
this.autoBuild(context);
this.autoMisc(context);
}
/**
* Try to build as many of the passed buildings as possible.
* Usually, this is called at each iteration of the automation engine to
* handle the building of items on the Bonfire tab.
*
* @param builds The buildings to build.
*/
autoBuild(context, builds = this.settings.buildings) {
// Get the current metadata for all the referenced buildings.
const metaData = {};
for (const build of Object.values(builds)) {
metaData[build.building] = this._host.game.bld.getBuildingExt((build.baseBuilding ?? build.building)).meta;
}
const sectionTrigger = this.settings.trigger;
const builder = (build) => {
this.build((build.name || build.id), build.stage ?? undefined, build.count);
};
context.purchaseOrders.push({ builder, builds, metaData, sectionTrigger });
}
autoUpgrade(context) {
// Get current count of pastures.
const pastures = this._host.game.bld.getBuildingExt("pasture").meta.stage === 0
? this._host.game.bld.getBuildingExt("pasture").meta.val
: 0;
// Get current count of aqueducts.
const aqueducts = this._host.game.bld.getBuildingExt("aqueduct").meta.stage === 0
? this._host.game.bld.getBuildingExt("aqueduct").meta.val
: 0;
const pastureMeta = this._host.game.bld.getBuildingExt("pasture").meta;
// If pastures haven't been upgraded to solar farms yet...
if (this.settings.upgradeBuildings.buildings.solarfarm.enabled &&
pastureMeta.unlocked &&
pastureMeta.stage === 0 &&
mustExist(pastureMeta.stages)[1].stageUnlocked) {
// If we would reduce our pastures to 0, by upgrading them, would we lose any catnip?
if (this._workshopManager.getPotentialCatnip(true, 0, aqueducts) > 0) {
if (this._bulkManager.singleBuildPossible("pasture")) {
const button = this.getBuild("pasture", 0);
if (!isNil(button?.model)) {
// We need to perform the process like this to avoid UI confirmations
// for selling items.
// Sell all pastures (to regain the resources).
button.controller.sellInternal(button.model, 0, false);
// Manually update the metadata, as we bypassed the full selling logic.
pastureMeta.on = 0;
pastureMeta.val = 0;
pastureMeta.stage = 1;
this._host.engine.iactivity("upgrade.building.pasture", [], "ks-upgrade");
// Upgrade the pasture.
this._host.game.ui?.render();
this.build("pasture", 1, 1);
context.requestGameUiRefresh = true;
}
}
}
}
const aqueductMeta = this._host.game.bld.getBuildingExt("aqueduct").meta;
// If aqueducts haven't been upgraded to hydro plants yet...
if (this.settings.upgradeBuildings.buildings.hydroplant.enabled &&
aqueductMeta.unlocked &&
aqueductMeta.stage === 0 &&
mustExist(aqueductMeta.stages)[1].stageUnlocked) {
// If we would reduce our aqueducts to 0, by upgrading them, would we lose any catnip?
if (this._workshopManager.getPotentialCatnip(true, pastures, 0) > 0) {
if (this._bulkManager.singleBuildPossible("aqueduct")) {
const button = this.getBuild("aqueduct", 0);
if (!isNil(button?.model)) {
button.controller.sellInternal(button.model, 0, false);
aqueductMeta.on = 0;
aqueductMeta.val = 0;
aqueductMeta.stage = 1;
// TODO: Why do we do this for the aqueduct and not for the pasture?
aqueductMeta.calculateEffects?.(aqueductMeta, this._host.game);
this._host.engine.iactivity("upgrade.building.aqueduct", [], "ks-upgrade");
this._host.game.ui?.render();
this.build("aqueduct", 1, 1);
context.requestGameUiRefresh = true;
}
}
}
}
const libraryMeta = this._host.game.bld.getBuildingExt("library").meta;
if (this.settings.upgradeBuildings.buildings.dataCenter.enabled &&
libraryMeta.unlocked &&
libraryMeta.stage === 0 &&
mustExist(libraryMeta.stages)[1].stageUnlocked) {
let energyConsumptionRate = this._host.game.workshop.get("cryocomputing").researched ? 1 : 2;
if (this._host.game.challenges.currentChallenge === "energy") {
energyConsumptionRate *= 2;
}
// This indicates how valuable a data center is, compared to a single library.
// We check for possible upgrades, that would make them more valuable.
let libToDat = 3;
if (this._host.game.workshop.get("uplink").researched) {
libToDat *=
1 +
this._host.game.bld.getBuildingExt("biolab").meta.val *
this._host.game.getEffect("uplinkDCRatio");
}
if (this._host.game.workshop.get("machineLearning").researched) {
libToDat *=
1 +
this._host.game.bld.getBuildingExt("aiCore").meta.on *
this._host.game.getEffect("dataCenterAIRatio");
}
// We now have the energy consumption of data centers and the value of data centers.
// Assuming, we would upgrade to data centers and buy as many as we need to have value
// equal to our current libraries, and that wouldn't cap our energy, upgrade them.
if (this._host.game.resPool.energyProd >=
this._host.game.resPool.energyCons + (energyConsumptionRate * libraryMeta.val) / libToDat) {
if (this._bulkManager.singleBuildPossible("library")) {
const button = mustExist(this.getBuild("library", 0));
if (isNil(button.model)) {
return;
}
button.controller.sellInternal(button.model, 0, false);
libraryMeta.on = 0;
libraryMeta.val = 0;
libraryMeta.stage = 1;
libraryMeta.calculateEffects?.(libraryMeta, this._host.game);
this._host.engine.iactivity("upgrade.building.library", [], "ks-upgrade");
this._host.game.ui?.render();
this.build("library", 1, 1);
context.requestGameUiRefresh = true;
return;
}
}
}
const warehouseMeta = this._host.game.bld.getBuildingExt("warehouse").meta;
if (this.settings.upgradeBuildings.buildings.spaceport.enabled &&
warehouseMeta.unlocked &&
warehouseMeta.stage === 0 &&
mustExist(warehouseMeta.stages)[1].stageUnlocked) {
if (this._bulkManager.singleBuildPossible("warehouse")) {
const button = this.getBuild("warehouse", 0);
if (!isNil(button?.model)) {
button.controller.sellInternal(button.model, 0, false);
warehouseMeta.on = 0;
warehouseMeta.val = 0;
warehouseMeta.stage = 1;
this._host.engine.iactivity("upgrade.building.warehouse", [], "ks-upgrade");
this._host.game.ui?.render();
this.build("warehouse", 1, 1);
context.requestGameUiRefresh = true;
return;
}
}
}
const amphitheatreMeta = this._host.game.bld.getBuildingExt("amphitheatre").meta;
// If amphitheathres haven't been upgraded to broadcast towers yet...
// This seems to be identical to the pasture upgrade.
if (this.settings.upgradeBuildings.buildings.broadcasttower.enabled &&
amphitheatreMeta.unlocked &&
amphitheatreMeta.stage === 0 &&
mustExist(amphitheatreMeta.stages)[1].stageUnlocked) {
// TODO: This is problematic. Upgrading from 50 amphitheatres to 1 broadcast tower sucks
// if you don't have enough resources to build several more.
if (this._bulkManager.singleBuildPossible("amphitheatre")) {
const button = this.getBuild("amphitheatre", 0);
if (!isNil(button?.model)) {
button.controller.sellInternal(button.model, 0, false);
amphitheatreMeta.on = 0;
amphitheatreMeta.val = 0;
amphitheatreMeta.stage = 1;
this._host.engine.iactivity("upgrade.building.amphitheatre", [], "ks-upgrade");
this._host.game.ui?.render();
this.build("amphitheatre", 1, 1);
context.requestGameUiRefresh = true;
}
}
}
}
autoMisc(context) {
// Auto turn on steamworks
if (this.settings.turnOnSteamworks.enabled) {
const steamworks = this._host.game.bld.getBuildingExt("steamworks");
if (steamworks.meta.val && steamworks.meta.on === 0) {
const button = this.getBuild("steamworks");
button.controller.onAll(button.model);
}
}
// Auto turn on magnetos
if (this.settings.turnOnMagnetos.enabled) {
const magnetos = this._host.game.bld.getBuildingExt("magneto");
if (magnetos.meta.val && magnetos.meta.on < magnetos.meta.val) {
const button = this.getBuild("magneto");
button.controller.onAll(button.model);
}
}
// Auto turn on reactors
if (this.settings.turnOnReactors.enabled) {
const reactors = this._host.game.bld.getBuildingExt("reactor");
if (reactors.meta.val && reactors.meta.on < reactors.meta.val) {
const button = this.getBuild("reactor");
button.controller.onAll(button.model);
}
}
// If buildings (upgrades of bonfire items) are enabled...
if (this.settings.upgradeBuildings.enabled) {
this.autoUpgrade(context);
}
if (this.settings.gatherCatnip.enabled) {
this.autoGather();
}
}
autoGather() {
for (let clicks = 0; clicks < Math.floor(this._host.engine.settings.interval / 20); ++clicks) {
this._host.game.bld.gatherCatnip();
}
}
build(name, _stage, amount) {
let amountConstructed = 0;
let label;
const itemMetaRaw = game.getUnlockByName(name, "buildings");
const meta = new classes.BuildingMeta(itemMetaRaw).getMeta();
if ("stages" in meta) {
const controller = new classes.ui.btn.StagingBldBtnController(this._host.game);
const model = controller.fetchModel({
building: name,
controller,
description: mustExist(meta.description),
name: mustExist(meta.label),
twoRow: false,
});
amountConstructed = this._bulkManager.construct(model, controller, amount);
label = meta.label ?? "";
}
else {
const controller = new classes.ui.btn.BuildingBtnModernController(this._host.game);
const model = controller.fetchModel({
building: name,
controller,
description: mustExist(meta.description),
name: mustExist(meta.label),
twoRow: false,
});
amountConstructed = this._bulkManager.construct(model, controller, amount);
label = meta.label ?? "";
}
if (amount !== amountConstructed) {
console.warn(...cl(`${label} Amount ordered: ${amount} Amount Constructed: ${amountConstructed}`));
// Bail out to not flood the log with garbage.
if (amountConstructed === 0) {
return;
}
}
this._host.engine.storeForSummary(label, amountConstructed, "build");
if (amountConstructed === 1) {
this._host.engine.iactivity("act.build", [label], "ks-build");
}
else {
this._host.engine.iactivity("act.builds", [label, this._host.renderAbsolute(amountConstructed)], "ks-build");
}
}
getBuild(name, stage = 0) {
const metaRaw = game.bld.get(name);
const buildingMeta = new classes.BuildingMeta(metaRaw).getMeta();
const meta = !isNil(buildingMeta.stages) ? buildingMeta.stages[stage] : metaRaw;
const controller = "stages" in meta
? new classes.ui.btn.StagingBldBtnController(this._host.game)
: new classes.ui.btn.BuildingBtnModernController(this._host.game);
const model = controller.fetchModel({
building: name,
description: meta.description,
key: name,
name: meta.label,
});
return { controller, model };
}
}
//# sourceMappingURL=BonfireManager.js.map