public Boolean ProcessTurn()
{
// shutdownError and invalidPeerError are two errors that get set from
// deep in the system. We process them here because it is a clean place
// to restart the game since we aren't in the middle of any phases.
// This is just a mechanism for cleanly throwing an error from a known good
// location.
if (_shutdownError)
{
_shutdownError = false;
throw new ShutdownFailureException();
}
if (_invalidPeerError)
{
_invalidPeerError = false;
throw new InvalidPeerException();
}
// We break the main processing of the game into 10 phases that have been tuned to each
// take roughly the same amount of time. We paint the screen in between each one. This way
// We can have a constant frame rate and incrementally do the engine processing we need to
// do.
// After we do all 10 phases we've done one game "tick". We can do two ticks a second which means
// we have a frame rate of 20.
switch (_turnPhase)
{
case 0:
// If we are in ecosystem mode, we want to save the game state periodically in case the user
// shuts down the screensaver by pressing ctl-alt-del which just kills the process. This way
// we won't have lost too much processing time.
// We always want to save on the tick after we've reported so we don't get our state messed up
// on the server. For example: never start the game in a state that was before the information
// was sent to the server because the server will think we're corrupted.
if (_logState ||
(_ecosystemMode && _populationData.IsReportingTick(CurrentVector.State.TickNumber - 1)))
{
Debug.WriteLine("Saving state.");
serializeState(_currentStateFileName);
}
// Give 1/5 of the animals a chance to do their processing
Scheduler.Tick();
break;
case 1:
// Give 1/5 of the animals a chance to do their processing
Scheduler.Tick();
break;
case 2:
// Give 1/5 of the animals a chance to do their processing
Scheduler.Tick();
break;
case 3:
// Give 1/5 of the animals a chance to do their processing
Scheduler.Tick();
break;
case 4:
// Give 1/5 of the animals a chance to do their processing
Scheduler.Tick();
break;
case 5:
// Get all the actions that the animals want to perform in this tick.
TickActions act = _scheduler.GatherTickActions();
CurrentVector.Actions = act;
// Create a mutable version of the world state that we'll change to create the next
// world state.
_newWorldState = (WorldState) CurrentVector.State.DuplicateMutable();
_newWorldState.TickNumber = _newWorldState.TickNumber + 1;
_populationData.BeginTick(_newWorldState.TickNumber, CurrentVector.State.StateGuid);
// Remove any organisms queued to be removed
removeOrganismsFromQueue();
// We take a snapshot of the organism IDs since we do several foreach loops
// and change the state, which causes exceptions to occur
_organismIDList = new string[_newWorldState.OrganismIDs.Count];
_newWorldState.OrganismIDs.CopyTo(_organismIDList, 0);
killDiseasedOrganisms2();
break;
case 6:
Debug.Assert(_newWorldState != null, "Worldstate did not get created for this tick");
// Do this first, since it always must happen so that things (like growing)
// won't happen if there isn't enough energy
burnBaseEnergy();
// Do attacks before movement so that when a carnivore asks if it can attack
// they actually get to hit the target before it moves
doAttacks();
doDefends();
changeMovementVectors();
break;
case 7:
moveAnimals();
break;
case 8:
doBites();
growAllOrganisms();
incubate();
startReproduction();
heal();
break;
case 9:
// Do this last so that the plant always starts charged up,
// and has to operate with what it has for the next turn
giveEnergyToPlants();
// Teleport after all actions have been processed so that there are
// no single turn pending actions left for the organism.
teleportOrganisms();
// Insert any new organisms
insertOrganismsFromQueue();
// Set Antenna States
doAntennas();
// We're done changing the state, now make it immutable
_newWorldState.MakeImmutable();
Debug.Assert(_newWorldState.Organisms.Count == Scheduler.Organisms.Count);
WorldVector vector = new WorldVector(_newWorldState);
CurrentVector = vector;
_scheduler.CurrentState = _newWorldState;
_populationData.EndTick(_newWorldState.TickNumber);
_newWorldState = null;
break;
}
_turnPhase++;
if (_turnPhase == 10)
{
_turnPhase = 0;
return true;
}
return false;
}