UNPKG

@kitten-science/kitten-scientists

Version:

Add-on for the wonderful incremental browser game: https://kittensgame.com/web/

299 lines 15 kB
import { isNil, mustExist } from "@oliversalzburg/js-utils/data/nil.js"; import { TabManager } from "./TabManager.js"; import { BulkPurchaseHelper } from "./helper/BulkPurchaseHelper.js"; import { BonfireSettings, } from "./settings/BonfireSettings.js"; import { cwarn } from "./tools/Log.js"; export class BonfireManager { _host; settings; manager; _bulkManager; _workshopManager; constructor(host, workshopManager, settings = new BonfireSettings()) { this._host = host; this.settings = settings; this.manager = new TabManager(this._host, "Bonfire"); this._workshopManager = workshopManager; this._bulkManager = new BulkPurchaseHelper(this._host, this._workshopManager); } tick(context) { if (!this.settings.enabled) { return; } // We must call `.render()` here, because evaluation of availability of our options // is only performed when the game renders the contents of that tab. this.manager.render(); 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) { const bulkManager = this._bulkManager; // Get the current metadata for all the referenced buildings. const metaData = {}; for (const build of Object.values(builds)) { metaData[build.building] = this.getBuild((build.baseBuilding ?? build.building)).meta; } const sectionTrigger = this.settings.trigger; // Let the bulkmanager determine the builds we can make. const buildList = bulkManager.bulk(builds, metaData, sectionTrigger, "Bonfire"); // Build all entries in the build list, where we can build any items. for (const build of buildList.filter(item => 0 < item.count)) { this.build((build.name || build.id), build.stage, build.count); context.requestGameUiRefresh = true; } } 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) { const prices = mustExist(pastureMeta.stages)[1].prices; if (this._bulkManager.singleBuildPossible(pastureMeta, prices, 1)) { const button = this.getBuildButton("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); // 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) { const prices = mustExist(aqueductMeta.stages)[1].prices; if (this._bulkManager.singleBuildPossible(aqueductMeta, prices, 1)) { const button = this.getBuildButton("aqueduct", 0); if (!isNil(button?.model)) { button.controller.sellInternal(button.model, 0); aqueductMeta.on = 0; aqueductMeta.val = 0; aqueductMeta.stage = 1; // TODO: Why do we do this for the aqueduct and not for the pasture? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 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) { const prices = mustExist(libraryMeta.stages)[1].prices; if (this._bulkManager.singleBuildPossible(libraryMeta, prices, 1)) { const button = mustExist(this.getBuildButton("library", 0)); if (isNil(button.model)) { return; } button.controller.sellInternal(button.model, 0); libraryMeta.on = 0; libraryMeta.val = 0; libraryMeta.stage = 1; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 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) { const prices = mustExist(warehouseMeta.stages)[1].prices; if (this._bulkManager.singleBuildPossible(warehouseMeta, prices, 1)) { const button = this.getBuildButton("warehouse", 0); if (!isNil(button?.model)) { button.controller.sellInternal(button.model, 0); 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. const prices = mustExist(amphitheatreMeta.stages)[1].prices; if (this._bulkManager.singleBuildPossible(amphitheatreMeta, prices, 1)) { const button = this.getBuildButton("amphitheatre", 0); if (!isNil(button?.model)) { button.controller.sellInternal(button.model, 0); 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 = mustExist(this.getBuildButton("steamworks")); if (isNil(button.model)) { return; } 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 = mustExist(this.getBuildButton("magneto")); if (isNil(button.model)) { return; } 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 = mustExist(this.getBuildButton("reactor")); if (isNil(button.model)) { return; } 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() { const controller = new classes.game.ui.GatherCatnipButtonController(this._host.game); for (let clicks = 0; clicks < Math.floor(this._host.engine.settings.interval / 20); ++clicks) { controller.buyItem(null, null, () => { /* intentionally left blank */ }); } } build(name, stage, amount) { let amountCalculated = amount; const build = this.getBuild(name); const button = this.getBuildButton(name, stage); if (!button?.model) { return; } if (!button.model.enabled) { return; } const amountTemp = amountCalculated; const label = this._getBuildLabel(build.meta, stage); amountCalculated = this._bulkManager.construct(button.model, button, amountCalculated); if (amountCalculated !== amountTemp) { cwarn(`${label} Amount ordered: ${amountTemp} Amount Constructed: ${amountCalculated}`); } this._host.engine.storeForSummary(label, amountCalculated, "build"); if (amountCalculated === 1) { this._host.engine.iactivity("act.build", [label], "ks-build"); } else { this._host.engine.iactivity("act.builds", [label, this._host.renderAbsolute(amountCalculated)], "ks-build"); } } _getBuildLabel(meta, stage) { return meta.stages && !isNil(stage) ? meta.stages[stage].label : mustExist(meta.label); } getBuild(name) { return this._host.game.bld.getBuildingExt(name); } getBuildButton(name, stage) { const buttons = this.manager.tab.children; const build = this.getBuild(name); const label = this._getBuildLabel(build.meta, stage); return (buttons.find(button => button.model?.name.startsWith(label)) ?? null); } } //# sourceMappingURL=BonfireManager.js.map