/*
* 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;
}
}
}