diff --git a/packages/documentation/docs/sections/bonfire.md b/packages/documentation/docs/sections/bonfire.md index bd07b67c4..e4c0aa9eb 100644 --- a/packages/documentation/docs/sections/bonfire.md +++ b/packages/documentation/docs/sections/bonfire.md @@ -5,7 +5,9 @@ When you enable a building, this building will be built if all of these are true: 1. Less than **Max** buildings have already been built. + 1. _All_ of the resources required for the building to built are filled to **Trigger** of their stock capacity. + 1. _All_ of the resources required for the building to built are sufficiently available after considering configured **Stock** and **Consume**. ### Upgrades diff --git a/packages/documentation/docs/sections/village.md b/packages/documentation/docs/sections/village.md index 86011df09..66ceea8ea 100644 --- a/packages/documentation/docs/sections/village.md +++ b/packages/documentation/docs/sections/village.md @@ -26,4 +26,4 @@ Promotes your leader, as soon as possible. ### Elect leader -Elects a kittens with the given attributes as a leader. +Elects a kitten with the given attributes as a leader. diff --git a/packages/documentation/docs/sections/workshop.md b/packages/documentation/docs/sections/workshop.md index e58e637ca..51d593660 100644 --- a/packages/documentation/docs/sections/workshop.md +++ b/packages/documentation/docs/sections/workshop.md @@ -1 +1,45 @@ # Workshop + +## Resource Crafting + +In general, resources are crafted if they are enabled and less than **Max** resources are already in stock. + +Additionally, if crafting a resource requires one or more materials that have a capacity, those materials need to be filled to **Trigger** of their stock capacity. + +!!! example + + **Wood** has a capacity. If you want to craft **Beams**, and you set a trigger of `0.5`, then beams would be crafted if wood is filled to half of its stock capacity. + + When you want to craft **Megaliths**, they are built from **Beams**, **Slabs**, and **Plates**. All of which have _no capacity_. So the trigger value does not apply to this craft. + +### Unlimited Crafting + +Just craft as many items as possible, respecting your [Resource Control configuration](./resource-control.md). + +### Limited Crafting + +For a limited item to be crafted, we first look at all the materials that are required for the item to be crafted, and at our current stock for the item. We then calculate how much of our materials would be required to build all the items _we already have in stock_. If we have more materials than _that_, then we allow the additional materials to be crafted into more of the craftable item. + +!!! example + + Let's assume you want to craft **Beams**. A beam costs 175 **Wood**, and you have 1 beam in stock. KS would then craft the next beam when you have 350 wood available. + +### Force Ships to 243 + +When enabled, **Trade Ships** will be handled as _unlimited_, regardless of the actual configuration, until you have at least 243 ships in stock. + +!!! quote + + Having 243 or more ships will guarantee that you get titanium from a trade. The exact number is `1700/7` ships, which rounds up to 243. + + + +## Research Upgrades + +Selected upgrades will automatically be researched as soon as possible. + + +*[KG]: Kittens Game +*[KS]: Kitten Scientists +*[UI]: User interface + diff --git a/packages/documentation/mkdocs.yml b/packages/documentation/mkdocs.yml index 3e3568b78..cb02d4ae4 100644 --- a/packages/documentation/mkdocs.yml +++ b/packages/documentation/mkdocs.yml @@ -1,4 +1,4 @@ -copyright: Oliver Salzburg +copyright: Oliver Salzburg and Kitten Science Contributors dev_addr: 0.0.0.0:8000 docs_dir: docs extra: diff --git a/packages/userscript/source/WorkshopManager.ts b/packages/userscript/source/WorkshopManager.ts index 4aa8fe4fd..b4f718b94 100644 --- a/packages/userscript/source/WorkshopManager.ts +++ b/packages/userscript/source/WorkshopManager.ts @@ -90,38 +90,38 @@ export class WorkshopManager extends UpgradeManager implements Automation { autoCraft( crafts: Partial> = this.settings.resources ) { - // TODO: One of the core limitations here is that only a single resource - // is taken into account, the one set as `require` in the definition. const trigger = this.settings.trigger; for (const craft of Object.values(crafts)) { - // This will always be `false` while `max` is hardcoded to `0`. - // Otherwise, it would contain the current resource information. const current = !craft.max ? false : this.getResource(craft.resource); - // The resource information for the requirement of this craft, if any. - const require = !craft.require ? false : this.getResource(craft.require); + const max = craft.max === -1 ? Number.POSITIVE_INFINITY : craft.max; - let amount = 0; - // Ensure that we have reached our cap - if (current && current.value > max) continue; + if (current && max < current.value) { + continue; + } // If we can't even craft a single item of the resource, skip it. if (!this.singleCraftPossible(craft.resource)) { continue; } - // Craft the resource if it doesn't require anything or we hit the requirement trigger. - if (!require || trigger <= require.value / require.maxValue) { - amount = this.getLowestCraftAmount(craft.resource, craft.limited, true); + const materials = Object.keys(this.getMaterials(craft.resource)) as Array; + // The resource information for the requirement of this craft which have a capacity. + const require = materials + .map(material => this.getResource(material)) + .filter(material => 0 < material.maxValue); - // If a resource DOES "require" another resource AND its trigger value has NOT been hit - // yet AND it is limited... What? - } else if (craft.limited) { - amount = this.getLowestCraftAmount(craft.resource, craft.limited, false); + const allMaterialsAboveTrigger = + require.filter(material => material.value / material.maxValue < trigger).length === 0; + + if (!allMaterialsAboveTrigger) { + continue; } + const amount = this.getLowestCraftAmount(craft.resource, craft.limited, 0 < require.length); + // If we can craft any of this item, do it. - if (amount > 0) { + if (0 < amount) { this.craft(craft.resource, amount); } } @@ -227,81 +227,18 @@ export class WorkshopManager extends UpgradeManager implements Automation { * * @param name The resource to craft. * @param limited Is the crafting of the resource currently limited? - * @param requiredResourceAboveTrigger Is the resource that is required for - * this craft currently above the trigger value? - * @returns ? + * @param capacityControlled Is this craft dependant on materials that have a stock capacity? + * @returns The amount of resources to craft. */ getLowestCraftAmount( name: ResourceCraftable, limited: boolean, - requiredResourceAboveTrigger: boolean + capacityControlled = false ): number { const materials = this.getMaterials(name); const craft = this.getCraft(name); const ratio = this._host.gamePage.getResCraftRatio(craft.name); - const trigger = this.settings.trigger; - - // Safeguard if materials for craft cannot be determined. - if (!materials) { - return 0; - } - - // This seems to be a (hopefully) finely balanced act to distribute iron - // between plates and steel. - // One resource will probably be preferred for periods of time, then the - // other resource will take over. - if (name === "steel" && limited) { - // Under some condition, we don't want to craft any steel. - const plateRatio = this._host.gamePage.getResCraftRatio("plate"); - // The left term will be larger than 1 if we have more plates than steel. - // The right term is basically 1.25, the relation of iron costs between - // plates and steel. Plates require 125 iron, steel 100. - // This term is weighed in regards to the craft ratio of each resource. - // If we get twice as many plates out of a craft than we would steel, the - // right term is increased above 1.25. - // What this all implies is, only craft steel if a reasonable amount of - // plates are also already crafted. - if ( - this.getValueAvailable("plate") / this.getValueAvailable("steel") < - (plateRatio + 1) / 125 / ((ratio + 1) / 100) - ) { - return 0; - } - } - - // It's not clear *how* this is supposed to work. - // What it tries to do is, if we have coal production, under some condition, - // calculate an appropriate max value for plates to be crafted. - // This amount would be lower than the max plates that could be crafted otherwise. - let plateMax = Number.MAX_VALUE; - if (name === "plate" && limited) { - const steelRatio = this._host.gamePage.getResCraftRatio("steel"); - // If we're producing coal, then we could also make steel, and don't want - // to use up all the iron. - const coalPerTick = this._host.gamePage.getResourcePerTick("coal", true); - if (coalPerTick > 0) { - // Here we have the same check as above, but reversed. - // So this would be the case where steel is preferred. - if ( - this.getValueAvailable("plate") / this.getValueAvailable("steel") > - (ratio + 1) / 125 / ((steelRatio + 1) / 100) - ) { - // The absolute trigger value for coal. - const coalTriggerAmount = this.getResource("coal").maxValue * trigger; - // How many units of coal are we away from the trigger. - const distanceToCoalTrigger = coalTriggerAmount - this.getValue("coal"); - // How many ticks until we hit the trigger for coal. - const ticksToCoalTrigger = distanceToCoalTrigger / coalPerTick; - // How much iron will be produce in the time until we hit the trigger for coal. - const ironInTime = - ticksToCoalTrigger * Math.max(this._host.gamePage.getResourcePerTick("iron", true), 0); - // This is some weird voodoo... - plateMax = - (this.getValueAvailable("iron") - Math.max(coalTriggerAmount - ironInTime, 0)) / 125; - } - } - } // The ship override allows the user to treat ships as "unlimited" while there's less than 243. const shipOverride = this.settings.shipOverride.enabled; @@ -315,11 +252,10 @@ export class WorkshopManager extends UpgradeManager implements Automation { // The delta is the smallest craft amount based on the current material. let delta = undefined; - // Either if the build isn't limited, OR we're above the trigger value and have not hit - // our storage limit, OR we're handling the ship override. + // Either if the build isn't limited, or we're handling the ship override. if ( !limited || - (requiredResourceAboveTrigger && 0 < this.getResource(resource).maxValue) || + capacityControlled || (name === "ship" && shipOverride && this.getResource("ship").value < 243) ) { // If there is a storage limit, we can just use everything returned by getValueAvailable, @@ -355,14 +291,16 @@ export class WorkshopManager extends UpgradeManager implements Automation { } } - amount = Math.min(delta, amount, plateMax); + amount = Math.min(delta, amount); } // If we have a maximum value, ensure that we don't produce more than // this value. This should currently only impact wood crafting, but is // written generically to ensure it works for any craft that produces a // good with a maximum value. - if (res.maxValue > 0 && amount > res.maxValue - res.value) amount = res.maxValue - res.value; + if (0 < res.maxValue && res.maxValue - res.value < amount) { + amount = res.maxValue - res.value; + } return Math.floor(amount); } diff --git a/packages/userscript/source/settings/WorkshopSettings.ts b/packages/userscript/source/settings/WorkshopSettings.ts index 50e861f2a..27acad835 100644 --- a/packages/userscript/source/settings/WorkshopSettings.ts +++ b/packages/userscript/source/settings/WorkshopSettings.ts @@ -1,22 +1,15 @@ import { consumeEntriesPedantic } from "../tools/Entries"; import { isNil, Maybe } from "../tools/Maybe"; import { GamePage, ResourceCraftable } from "../types"; -import { Requirement, Setting, SettingLimitedMax, SettingTrigger } from "./Settings"; +import { Setting, SettingLimitedMax, SettingTrigger } from "./Settings"; import { UpgradeSettings } from "./UpgradeSettings"; export class CraftSettingsItem extends SettingLimitedMax { readonly resource: ResourceCraftable; - require: Requirement; - constructor( - resource: ResourceCraftable, - require: Requirement = false, - enabled = true, - limited = true - ) { + constructor(resource: ResourceCraftable, enabled = true, limited = true) { super(enabled, limited); this.resource = resource; - this.require = require; } } @@ -32,25 +25,25 @@ export class WorkshopSettings extends SettingTrigger { enabled = false, trigger = 0.95, resources: WorkshopResourceSettings = { - alloy: new CraftSettingsItem("alloy", "titanium"), - beam: new CraftSettingsItem("beam", "wood"), - blueprint: new CraftSettingsItem("blueprint", "science"), - compedium: new CraftSettingsItem("compedium", "science"), - concrate: new CraftSettingsItem("concrate", false), - eludium: new CraftSettingsItem("eludium", "unobtainium"), - gear: new CraftSettingsItem("gear", false), - kerosene: new CraftSettingsItem("kerosene", "oil"), - manuscript: new CraftSettingsItem("manuscript", "culture"), - megalith: new CraftSettingsItem("megalith", false), - parchment: new CraftSettingsItem("parchment", false, true, false), - plate: new CraftSettingsItem("plate", "iron"), - scaffold: new CraftSettingsItem("scaffold", false), - ship: new CraftSettingsItem("ship", false), - slab: new CraftSettingsItem("slab", "minerals"), - steel: new CraftSettingsItem("steel", "coal"), - tanker: new CraftSettingsItem("tanker", false), - thorium: new CraftSettingsItem("thorium", "uranium"), - wood: new CraftSettingsItem("wood", "catnip"), + alloy: new CraftSettingsItem("alloy"), + beam: new CraftSettingsItem("beam"), + blueprint: new CraftSettingsItem("blueprint"), + compedium: new CraftSettingsItem("compedium"), + concrate: new CraftSettingsItem("concrate"), + eludium: new CraftSettingsItem("eludium"), + gear: new CraftSettingsItem("gear"), + kerosene: new CraftSettingsItem("kerosene"), + manuscript: new CraftSettingsItem("manuscript"), + megalith: new CraftSettingsItem("megalith"), + parchment: new CraftSettingsItem("parchment", true, false), + plate: new CraftSettingsItem("plate"), + scaffold: new CraftSettingsItem("scaffold"), + ship: new CraftSettingsItem("ship"), + slab: new CraftSettingsItem("slab"), + steel: new CraftSettingsItem("steel"), + tanker: new CraftSettingsItem("tanker"), + thorium: new CraftSettingsItem("thorium"), + wood: new CraftSettingsItem("wood"), }, unlockUpgrades = new UpgradeSettings(), shipOverride = new Setting(true) diff --git a/packages/userscript/source/ui/WorkshopSettingsUi.ts b/packages/userscript/source/ui/WorkshopSettingsUi.ts index c7fe9b1da..7e5eeef95 100644 --- a/packages/userscript/source/ui/WorkshopSettingsUi.ts +++ b/packages/userscript/source/ui/WorkshopSettingsUi.ts @@ -1,7 +1,6 @@ import { CraftSettingsItem, WorkshopSettings } from "../settings/WorkshopSettings"; import { UserScript } from "../UserScript"; import { TriggerButton } from "./components/buttons-icon/TriggerButton"; -import { HeaderListItem } from "./components/HeaderListItem"; import { SettingLimitedMaxListItem } from "./components/SettingLimitedMaxListItem"; import { SettingListItem } from "./components/SettingListItem"; import { SettingsList } from "./components/SettingsList"; @@ -10,8 +9,6 @@ import { UpgradeSettingsUi } from "./UpgradeSettingsUi"; export class WorkshopSettingsUi extends SettingsSectionUi { private readonly _trigger: TriggerButton; - private readonly _upgradeUi: UpgradeSettingsUi; - private readonly _shipOverride: SettingListItem; constructor(host: UserScript, settings: WorkshopSettings) { const label = host.engine.i18n("ui.craft"); @@ -63,6 +60,22 @@ export class WorkshopSettingsUi extends SettingsSectionUi { this.setting.resources.ship, this._host.engine.i18n("$workshop.crafts.ship.label") ), + new SettingListItem( + this._host, + this._host.engine.i18n("option.shipOverride"), + this.setting.shipOverride, + { + onCheck: () => + this._host.engine.imessage("status.sub.enable", [ + this._host.engine.i18n("option.shipOverride"), + ]), + onUnCheck: () => + this._host.engine.imessage("status.sub.disable", [ + this._host.engine.i18n("option.shipOverride"), + ]), + upgradeIndicator: true, + } + ), this._getCraftOption( this.setting.resources.tanker, this._host.engine.i18n("$workshop.crafts.tanker.label"), @@ -111,32 +124,13 @@ export class WorkshopSettingsUi extends SettingsSectionUi { }); this.addChild(listCrafts); - const listAdditional = new SettingsList(this._host, { - hasDisableAll: false, - hasEnableAll: false, - }); - listAdditional.addChild(new HeaderListItem(this._host, "Additional options")); - - this._upgradeUi = new UpgradeSettingsUi(this._host, this.setting.unlockUpgrades); - listAdditional.addChild(this._upgradeUi); - - this._shipOverride = new SettingListItem( - this._host, - this._host.engine.i18n("option.shipOverride"), - this.setting.shipOverride, - { - onCheck: () => - this._host.engine.imessage("status.sub.enable", [ - this._host.engine.i18n("option.shipOverride"), - ]), - onUnCheck: () => - this._host.engine.imessage("status.sub.disable", [ - this._host.engine.i18n("option.shipOverride"), - ]), - } + this.addChild( + new SettingsList(this._host, { + children: [new UpgradeSettingsUi(this._host, this.setting.unlockUpgrades)], + hasDisableAll: false, + hasEnableAll: false, + }) ); - listAdditional.addChild(this._shipOverride); - this.addChild(listAdditional); } private _getCraftOption(