//***Importing of NameSpaces
using System;
using System.Drawing;
using System.Collections;
using System.IO;
//***end importing
//***Creature Definition
[assembly: OrganismClass("WHOOPER01")] // The class that derives from Creature
[assembly: AuthorInformation("Jeremy C. Wright", "jwright@tacf.org")] // Your Email
[CarnivoreAttribute(false)] // It's an herbivore
// Define what the beast is
[AnimalSkin("Beetle")]
[MarkingColor(KnownColor.Green)]
[MatureSize(26)] // Medium sized so it doesn't get too slow in old age
// Point Based Attributes
// You get 100 points to distribute among these attributes to define
// what your organism can do. Choose them based on the strategy your organism
// will use
[MaximumEnergyPoints(20)] // Needs a little energy to reproduce
[EatingSpeedPoints(0)] // Who cares how long it takes to eat
[AttackDamagePoints(0)] // Doesn't ever attack
[DefendDamagePoints(0)] // Runs too fast to need to defend
[MaximumSpeedPoints(40)] // Sprinter baby!
[CamouflagePoints(0)] // Camo is crap anyways
[EyesightPoints(40)] // Need this to find plants better
//*** end definition
public class WHOOPER01 : Animal
{
//*** global attributes
PlantState targetPlant = null; // The current plant we're going after
AnimalState attackerAnimal = null; // The current attacker we are fleeing
const int cruisingSpeed = 5; // When there's nothing better to do: dawdle
const int fleeingSpeed = 40; // Running from scary crap speed
private Point parentLocation; // For the BornEvent method
int aroundCount=0; // Used to make semi-intelligent "move around"
// decisions (don't change)
// Species counter variables
protected int mcKilled;
protected int mcBorn;
protected int mcTeleported;
//***end global attributes
//***event calls
// Set up any event handlers that we want when first initialized
protected override void Initialize()
{
Load += new LoadEventHandler(LoadEvent);
Idle += new IdleEventHandler(IdleEvent);
Attacked += new AttackedEventHandler(AttackedEvent);
Born += new BornEventHandler(BornEvent);
MoveCompleted += new MoveCompletedEventHandler(MoveCompletedEvent);
Teleported += new TeleportedEventHandler(TeleportedEvent);
AttackCompleted += new AttackCompletedEventHandler(AttackCompletedEvent);
//EatCompleted += new EatCompletedEventHandler(EatCompletedEvent);
ReproduceCompleted += new ReproduceCompletedEventHandler(ReproduceCompletedEvent);
}
//***end event calls
//***event definitions
// Fired if we arrived at our destination or got blocked
void MoveCompletedEvent(object sender, MoveCompletedEventArgs e)
{
if(e.Reason == ReasonForStop.Blocked)
{
if(targetPlant != null || attackerAnimal != null)
{
// If we get blocked, try moving perpendicular 3 times,
// then find other target
if(aroundCount < 3)
{
Point originalDestination = e.MoveToAction.MovementVector.Destination;
Vector originalVector = Vector.Subtract(originalDestination, this.Position);
Vector newVector = originalVector.Rotate(Math.PI / 4);
Vector unitVector = newVector.GetUnitVector();
Vector newPositionVector = unitVector.Scale(20);
Point newPosition = Vector.Add(Position, newPositionVector);
aroundCount += 1;
WriteTrace("Tried going around " + aroundCount + " times.");
if (attackerAnimal != null)
BeginMoving(new MovementVector(newPosition, fleeingSpeed));
else
BeginMoving(new MovementVector(newPosition, cruisingSpeed));
}
else
{
WriteTrace("Going Around failed, getting new target");
BeginMoving(getDestination());
}
}
}
}
private void BornEvent(object sender, BornEventArgs e)
{
byte[] dna = e.Dna;
if ( dna != null )
{
MemoryStream m = new MemoryStream(dna);
BinaryReader b = new BinaryReader(m);
parentLocation = new Point(b.ReadInt32(),b.ReadInt32());
BeginMoving(new MovementVector(parentLocation, getSpeed()));
b.Close();
}
}
// First event fired on an organism each turn
void LoadEvent(object sender, LoadEventArgs e)
{
try
{
if(targetPlant != null)
{
// See if our target plant still exists (it may have died)
// LookFor returns null if it isn't found
targetPlant = (PlantState) LookFor(targetPlant);
if(targetPlant == null)
WriteTrace("Target plant disappeared.");
}
if (Antennas.AntennaValue!=6)
{
Antennas.AntennaValue=6;
}
}
catch(Exception exc)
{
WriteTrace(exc.ToString());
}
}
// Fired if we are being attacked
void AttackedEvent(object sender, AttackedEventArgs e)
{
if(e.Attacker.IsAlive)
{
AnimalState TheAttacker = e.Attacker;
BeginDefending(TheAttacker); //defend against the attacker
WriteTrace("Run away to some random point");
BeginMoving(getDestination());
}
}
// Species Counter function
public void AttackCompletedEvent(object sender, AttackCompletedEventArgs e)
{
if ( e.Killed )
{
mcKilled += 1;
WriteTrace("TO-O-O-O..."); // Doesn't work without this line
}
}
// Species Counter function
public void TeleportedEvent(object sender, TeleportedEventArgs e)
{
mcTeleported += 1;
targetPlant = null;
attackerAnimal = null;
}
// Species Counter function
public void ReproduceCompletedEvent(object sender, ReproduceCompletedEventArgs e)
{
mcBorn += 1;
}
// Fired after all other events are fired during a turn
void IdleEvent(object sender, IdleEventArgs e)
{
try
{
// Reproduce as often as possible
if(CanReproduce)
{
// Writing parents location for child
MemoryStream m = new MemoryStream();
BinaryWriter b = new BinaryWriter(m);
b.Write(Position.X);
b.Write(Position.Y);
BeginReproduction(m.ToArray());
b.Close();
}
// Scan for potential attackers
if (ScanForAttackers())
{
return;
}
// If we can eat and we have a target plant, eat
if(CanEat)
{
WriteTrace("I can eat");
if(!IsEating)
{
WriteTrace("I'm not eating... Target plant?");
if(targetPlant != null)
{
WriteTrace("Target plant found, is healthy?");
// Only accept if plant is healthy (unless we are starving)
if (targetPlant.PercentInjured < 0.7 || State.EnergyState == EnergyState.Deterioration)
{
WriteTrace("Healthy, can I reach it?");
if(WithinEatingRange(targetPlant))
{
WriteTrace("Within Range, Start eating.");
BeginEating(targetPlant);
if(IsMoving)
{
WriteTrace("Stop while eating.");
StopMoving();
}
}
else
{
if(!IsMoving)
{
WriteTrace("Move to Target Plant");
BeginMoving(new MovementVector(targetPlant.Position, 2));
}
}
}
}
else
{
WriteTrace("Don't have target plant.");
if(!ScanForTargetPlant())
if(!IsMoving)
{
WriteTrace("No plant found, so pick a random point and move there");
/*
int RandomX= OrganismRandom.Next(0, WorldWidth - 1);
int RandomY= OrganismRandom.Next(0, WorldHeight - 1);
BeginMoving(new MovementVector(new Point(RandomX,RandomY), 2));
*/
BeginMoving(getDestination());
}
else
{
WriteTrace("Moving and Looking...");
}
}
}
else
{
WriteTrace("Eating.");
if(IsMoving)
{
WriteTrace("Stop moving while eating.");
StopMoving();
}
}
}
else
{
WriteTrace("Full: do nothing.");
if(IsMoving)
StopMoving();
}
}
catch(Exception exc)
{
WriteTrace(exc.ToString());
}
}
//***end event definitions
//***generic functions/methods
// If you ever need to just re-insure your target is valid
void RefreshTarget()
{
if ( targetPlant == null )
{
return;
}
PlantState newState = (PlantState) LookFor(targetPlant);
if(newState != null)
{
targetPlant = newState;
}
else
{
targetPlant = null;
}
}
// Generic "are there attackers around I should run from" method
bool ScanForAttackers()
{
try
{
ArrayList foundAnimals = Scan();
if(foundAnimals.Count > 0)
{
foreach(OrganismState organismState in foundAnimals)
{
if(organismState is AnimalState)
{
IAnimalSpecies iAS = (IAnimalSpecies) organismState.Species;
if (iAS.IsCarnivore)
{
if (WithinAttackingRange ((AnimalState)organismState))
{
WriteTrace("Carnivore in range: fleeing");
attackerAnimal = (AnimalState) organismState;
Vector newVector = Vector.Subtract(organismState.Position, Position);
Vector newPositionVector = newVector.Scale(10);
Point newPosition = Vector.Add(Position, newPositionVector);
BeginMoving(new MovementVector(newPosition, fleeingSpeed));
return true;
}
}
}
}
}
}
catch(Exception exc)
{
WriteTrace(exc.ToString());
}
attackerAnimal = null;
return false;
}
// sets speed based upon current energy level
int getSpeed()
{
int speed = 0;
switch(State.EnergyState)
{
case EnergyState.Full:
speed = Convert.ToInt32(Species.MaximumSpeed * .7); // 70% speed
break;
case EnergyState.Normal:
speed = Convert.ToInt32(Species.MaximumSpeed * .5); // 50% speed
break;
case EnergyState.Hungry:
speed = Convert.ToInt32(Species.MaximumSpeed * .40); // 40% speed
break;
default:
speed = Convert.ToInt32(Species.MaximumSpeed * .25); // 25% speed
break;
}
return speed;
}
// Global 'bit' to set a destination based upon a variety of factors
MovementVector getDestination()
{
// sets destination as a random point
MovementVector destination = new MovementVector(
new Point (
OrganismRandom.Next(0, WorldWidth - 1),
OrganismRandom.Next(0, WorldHeight - 1)
),getSpeed());
return destination;
}
// Used to find closest plant from an array of plants
bool FindClosestPlant(ArrayList plants)
{
// we are assuming that plants is already set to an ArrayList of plants
double minDistance = double.MaxValue;
PlantState target = null;
if ( plants.Count > 0 )
{
foreach(PlantState plant in plants)
{
if (DistanceTo(plant) < minDistance && (plant.PercentInjured < 75 || (State.EnergyState == EnergyState.Deterioration)))
{
target = plant;
minDistance = DistanceTo(plant);
}
}
}
return true;
}
// Looks for target plants, and starts moving towards the first one it finds
bool ScanForTargetPlant()
{
try
{
ArrayList foundCreatures = Scan();
if(foundCreatures.Count > 0)
{
// Always move after closest plant or defend closest creature if there is one
foreach(OrganismState organismState in foundCreatures)
{
if(organismState is PlantState)
{
targetPlant = (PlantState) organismState;
BeginMoving(new MovementVector(organismState.Position, 2));
return true;
}
}
}
}
catch(Exception exc)
{
WriteTrace(exc.ToString());
}
return false;
}
//***end generic functions/methods
//***species counter bits
// Species Counter function output
protected void TraceState()
{
if ( State.IsMature )
{
WriteTrace("+/" + State.IncubationTicks + "/" + State.ReproductionWait);
}
else
{
WriteTrace("-/" + State.Radius + "/" + State.GrowthWait + " == " + GetPercentUsedTicks(State).ToString("n"));
}
WriteTrace(mcKilled + "/" + mcBorn + "/" + mcTeleported + "/" + State.Generation);
WriteTrace(State.PercentLifespanRemaining.ToString("n") + "/" + State.PercentEnergy.ToString("n") + "/" + State.PercentInjured.ToString("n"));
}
// Above uses those functions:
public static double GetPercentUsedTicks (AnimalState animal)
{
return (double)GetUsedTicks(animal) / animal.TickAge;
}
public static int GetUsedTicks (AnimalState animal)
{
int usedTicks = animal.Species.GrowthWait * ( animal.Radius - 11 ) +
animal.Species.GrowthWait - animal.GrowthWait;
return usedTicks;
}
//***end Species Counter bits
//***serialize/deserialize bits
// This gets called whenever your creature is being saved -- either the game is closing
// or you are being teleported. Store anything you want to remember when you are
// instantiated again in the stream.
public override void SerializeAnimal(MemoryStream m)
{
BinaryWriter b = new BinaryWriter(m);
b.Write(mcKilled);
b.Write(mcBorn);
b.Write(mcTeleported);
}
// This gets called when you are instantiated again after being saved. You get a
// chance to pull out any information that you put into the stream when you were saved
public override void DeserializeAnimal(MemoryStream m)
{
BinaryReader b = new BinaryReader(m);
mcKilled = b.ReadInt32();
mcBorn = b.ReadInt32();
mcTeleported = b.ReadInt32();
}
//***end serialize/deserialize bits
}