/*
* Planet.cs
* Authors: Bradley R. Blankenship
* Copyright (c) 2007-2008 Cornell University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
namespace ColonySim.Structures
{
///
/// Represents a planet in the game. Planets are the population centers
/// of the game.
///
class Planet : Structure
{
#region Constants
// Constant for the weight the GOP has for population growth
const float GOP_WEIGHT = 0.90f;
// Constant for the weight the Room has for population growth
const float ROOM_WEIGHT = 0.10f;
// Constant for rarity of a resource based on distance
const float RARITY_DISTANCE = 5.0f;
#endregion
#region Fields
// The current population
int mCurrentPopulation = 0;
// The maxiumum population
int mMaximumPopulation = 100;
// The current GOP factor for the planet
float mGOP = 1.0f;
// The current room factor for the planet
float mRoom = 1.0f;
// The current maximum amount the population can grow by (0 minimum)
int mMaxGrowthPossible = 50;
// The current maximum amount the population can decline by (0 minimum)
int mMaxDeclinePossible = 0;
// List of resources and their values
Dictionary mResourceValues = new Dictionary();
#endregion
#region Properties
///
/// Allow the viewing of the current population of the planet.
///
public int CurrentPopulation
{
get { return mCurrentPopulation; }
set { mCurrentPopulation = value; }
}
///
/// Allow the viewing of the maximum population of the planet.
///
public int MaximumPopulation
{
get { return mMaximumPopulation; }
set { mMaximumPopulation = value; }
}
///
/// Allow the viewing and setting of the GOP for the planet.
///
public float GOP
{
get { return mGOP; }
set { mGOP = value; }
}
#endregion
#region Constructs
///
/// Create the given structure.
///
/// The content manager
/// The name of our model
/// The name of our texture
public Planet(ContentManager pContent, string pModelName,
string pTextureName) : base(pContent,pModelName,pTextureName)
{
// Add each of the current resources possible with a value of 0
foreach (ResourceCode code in Enum.GetValues(typeof(ResourceCode)))
{
// Add the code
mResourceValues.Add(code, 0);
}
}
#endregion
#region Behavior
///
/// Update the population because we just ticked on a turn.
///
public override void Tick()
{
// Grow the population
GrowPopulation();
}
///
/// Grow the population based on the rules for altering the population,
/// using the GOP.
///
protected void GrowPopulation()
{
// Combined the GOP and Room factors into a single factor
float combinedFactor = mGOP * GOP_WEIGHT / 100 + mRoom * ROOM_WEIGHT;
// Now adjust the current population
if (combinedFactor >= 0)
{
// Increment the population
mCurrentPopulation += (int)(combinedFactor * mMaxGrowthPossible);
}
else
{
// Decline the population
mCurrentPopulation += (int)(combinedFactor * mMaxDeclinePossible);
}
// Now adjust based on the current population level
if (mCurrentPopulation > mMaximumPopulation)
{
// Set the max population
mCurrentPopulation = mMaximumPopulation;
}
else if (mCurrentPopulation < 0)
{
// Set the zero population
mCurrentPopulation = 0;
}
// Now reset the room factor
mRoom = (float)(mMaximumPopulation - mCurrentPopulation);
mRoom /= (mMaximumPopulation * 5);
// Calculate the new maximum growth potential
mMaxGrowthPossible = (int)(mRoom * mMaximumPopulation);
// Calculate the new maximum decline potential
mMaxDeclinePossible = (int)(((float)mCurrentPopulation / mMaximumPopulation) / 5 * mCurrentPopulation);
// Add to the reference grids new population
GridReference.StatusInfo.Population += mCurrentPopulation;
}
///
/// Receive the carrier and make it halt.
///
/// the carrier to receive.
/// The carrier.
public override bool ReceiveCarrier(Carrier pCarrier)
{
// Print the value of the carrier received, its resource, and the modifier
Console.Write(pCarrier.Value + ", " + pCarrier.Resource.ResourceCode + ", " + mResourceValues[pCarrier.Resource.ResourceCode] + ", ");
// Modify the value of each of the resource amounts
pCarrier.Resource.CreditsPerUnit = (int)
Math.Round(((mResourceValues[pCarrier.Resource.ResourceCode] *
pCarrier.Resource.CreditsPerUnit)));
// Add to the income for the colony
GridReference.StatusInfo.Money += pCarrier.Value;
// Calculate the GOP
mGOP = pCarrier.Value / mCurrentPopulation;
// Dispose of the Carrier
pCarrier.Dispose();
// Return the base call
return base.ReceiveCarrier(pCarrier);
}
///
/// Generates the value for a resource based on its absolute path and
/// its inherent value.
///
public void GenerateResourceValues()
{
// If we have a grid reference and a position
if (GridReference != null && GridPosition != null)
{
// Get the list of resources to search for
Array types = Enum.GetValues(typeof(ResourceCode));
// The list of mining plants
List plants = GridReference.GetSpecificStructures(typeof(MiningPlant));
// Go through each
foreach (ResourceCode code in types)
{
// Go through each of the plants
foreach (MiningPlant plant in plants)
{
// If the plant has the code
if (plant.OutputResource.ResourceCode == code)
{
// Then get the absolute distance
float value = (float)Math.Sqrt(Math.Pow(plant.GridPosition.X - GridPosition.X, 2) +
Math.Pow(plant.GridPosition.Y - GridPosition.Y, 2));
// Now round the distance to a value
value = (float)Math.Round(value) / RARITY_DISTANCE;
// If the value is less
if (value < mResourceValues[code] || mResourceValues[code] == 0)
{
// Set the value for the code
mResourceValues[code] = value;
}
}
}
}
}
}
#endregion
#region Utility
///
/// Returns a clone of this structure.
///
/// The cloned structure.
public override Structure Clone()
{
// Create the return value
Planet retVal = new Planet(this.Content, this.ModelPath, this.TexturePath);
// Set the values to ours
retVal.Name = this.Name;
retVal.FootPrintSize = this.FootPrintSize;
retVal.Cost = this.Cost;
retVal.MaximumPopulation = this.MaximumPopulation;
retVal.DrawOrder = this.DrawOrder;
retVal.TechniqueName = this.TechniqueName;
// Return the retval
return retVal;
}
#endregion
}
}