/* * Factory.cs * Authors: August Zinsser * * Copyright Matthew Belmonte 2007 */ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using tAC_Engine; using Pina3D; namespace Astropolis.ColonySimulator { /// /// A structure that (optinally) inputs commodities and outputs other commodities. /// public class Factory : Building { public override Dictionary InputInventory { get { return ((FactoryState)mState).InputInventory; } } public override Dictionary OutputInventory { get { return ((FactoryState)mState).OutputInventory; } } /// /// Returns true if production has stopped because there is no more room to store its products /// public bool IsOutputInventoryFull { get { return !HaveEnoughSpace(); } } /// /// Create a new Building /// public Factory(FactoryType type, StructureState state) { mType = type; mState = new FactoryState(state); Pina.AddRenderable(type.Model); // Flesh out the inventories foreach (KeyValuePair kvp in ((FactoryType)mType).Inputs) { ((FactoryState)mState).InputInventory.Add(kvp.Key, 0); } foreach (KeyValuePair kvp in ((FactoryType)mType).Outputs) { ((FactoryState)mState).OutputInventory.Add(kvp.Key, 0); } } /// /// Attempts to add some quantity of a commodity to this building's input inventory /// /// True if successfully added, false otherwise public override bool Deliver(string commodity, int quantity) { // Must be enough space in the input inventory if (((FactoryState)mState).InputInventory.ContainsKey(commodity) && ((FactoryState)mState).InputInventory[commodity] + quantity <= ((FactoryType)mType).Inputs[commodity] * ((FactoryType)mType).InventorySize) { ((FactoryState)mState).InputInventory[commodity] += quantity; return true; } return false; } /// /// Attempts to subtract the specified quantity of the specified commodity from this building's output inventory /// /// True if successfully removed, false otherwise public override bool Ship(string commodity, int quantity) { if (((FactoryState)mState).OutputInventory.ContainsKey(commodity) && ((FactoryState)mState).OutputInventory[commodity] >= quantity) { ((FactoryState)mState).OutputInventory[commodity] -= quantity; return true; } return false; } /// /// Return true if there is enough space in the internal output inventory to store products /// /// protected bool HaveEnoughSpace() { foreach (KeyValuePair kvp in ((FactoryType)mType).Outputs) { if ((((FactoryState)mState).OutputInventory[kvp.Key] + ((FactoryType)mType).Outputs[kvp.Key]) > (((FactoryType)mType).Outputs[kvp.Key] * ((FactoryType)mType).InventorySize)) return false; } return true; } /// /// Current quantity / max capacity /// /// 0 if the building does not store the given commodity public float PercentageOutputInventory(string commodity) { if (!((FactoryState)mState).OutputInventory.ContainsKey(commodity)) return 0; return (float)((FactoryState)mState).OutputInventory[commodity] / ((float)(((FactoryType)mType).Outputs[commodity] * ((FactoryType)mType).InventorySize)); } /// /// Current quantity / max capacity /// /// 0 if the building does not store the given commodity public float PercentageInputInventory(string commodity) { if (!((FactoryState)mState).InputInventory.ContainsKey(commodity)) return 0; return (float)((FactoryState)mState).InputInventory[commodity] / ((float)(((FactoryType)mType).Inputs[commodity] * ((FactoryType)mType).InventorySize)); } /// /// Produces if possible /// /// public override void Update(float dT) { base.Update(dT); ((FactoryState)mState).ProductionTimer -= dT; // Produce as many times as possible bool haveEnoughInputs = true; bool haveEnoughSpace = true; bool enoughTimeHasPassed = true; while (haveEnoughInputs && haveEnoughSpace && enoughTimeHasPassed) { // Check inventory foreach (KeyValuePair kvp in ((FactoryType)mType).Inputs) { if (((FactoryState)mState).InputInventory[kvp.Key] < kvp.Value) haveEnoughInputs = false; } haveEnoughSpace = HaveEnoughSpace(); // See if enough time has passed to make another one if (((FactoryState)mState).ProductionTimer > 0) enoughTimeHasPassed = false; // Produce if (haveEnoughInputs && haveEnoughSpace && enoughTimeHasPassed) { // Remove inputs foreach (KeyValuePair kvp in ((FactoryType)mType).Inputs) { ((FactoryState)mState).InputInventory[kvp.Key] -= kvp.Value; } // Create outputs foreach (KeyValuePair kvp in ((FactoryType)mType).Outputs) { ((FactoryState)mState).OutputInventory[kvp.Key] += kvp.Value; } // Account for the production time spent ((FactoryState)mState).ProductionTimer += ((FactoryType)mType).ProductionTime; } } // If the building is not currently producing something, then reset the production timer if (!haveEnoughInputs || !haveEnoughSpace) ((FactoryState)mState).ProductionTimer = ((FactoryType)mType).ProductionTime; } protected class FactoryState : StructureState { /// /// The commodities this building must accumulate before producing outputs /// public Dictionary InputInventory = new Dictionary(); /// /// The commodities this building produces once all inputs have been satisfied and enough time has passed /// public Dictionary OutputInventory = new Dictionary(); /// /// Counts down the time remaining to produce an output /// public float ProductionTimer = 0f; public FactoryState(StructureState state) : base(state.Matrix, state.BoundingBox) { } } } public class FactoryType : BuildingType { /// /// Number of gamedays it takes to produce outputs (once all inputs are received) /// public float ProductionTime; /// /// The size of a Factory's internal input/output inventory relative to BuildingType's input/output quantity /// public float InventorySize = 2f; public FactoryType( PinaModel model, int footprintWidth, int footprintHeight, Dictionary inputs, Dictionary outputs, float productionTime) : base(model, footprintWidth, footprintHeight, inputs, outputs) { this.ProductionTime = productionTime; } } }