/// <summary> /// Refreshes an organism state to the latest available state. Organism /// state objects can be held by an organism for many ticks, and they don't /// automatically update themselves. The reference held is immutable and so /// only represents the creature's state at the time the Scan was made and /// not necessarily the latest state. /// </summary> /// <param name="organismState">The organism state that needs to be updated</param> /// <returns>An updated state if the creature is still visible and alive, else null</returns> public OrganismState LookFor(OrganismState organismState) { if (organismState == null) { throw new ArgumentNullException("organismState", "The argument organismState cannot be null"); } OrganismState targetOrganism = LookForNoCamouflage(organismState); if (targetOrganism != null) { if (targetOrganism is AnimalState) { // See if the camouflage hides it int invisible = Organism.OrganismRandom.Next(1, 100); if (invisible <= ((AnimalSpecies)targetOrganism.Species).InvisibleOdds) { Organism.WriteTrace("#Camouflage hid animal from organism"); return null; } } return targetOrganism; } else { return null; } }
internal void SelectOrganism(OrganismState state) { if (showTraces.Checked) { AddTrace(state); } }
/// <summary> /// Creates a new event relating to a creature being destroyed. /// </summary> /// <param name="organismState">The creature being destroyed.</param> /// <param name="reason">The reason the creature is being destroyed.</param> /// <returns>State change initialized for a creature being destroyed with messages.</returns> public static EngineStateChangedEventArgs AnimalDestroyed(OrganismState organismState, PopulationChangeReason reason) { var reasonDescription = ""; switch (reason) { case PopulationChangeReason.Timeout: reasonDescription = "thought for too long"; break; case PopulationChangeReason.Error: reasonDescription = "had an error"; break; case PopulationChangeReason.SecurityViolation: reasonDescription = "attempted to violate security"; break; case PopulationChangeReason.OrganismBlacklisted: reasonDescription = "is blacklisted due to past bad behavior and won't be loaded"; break; } return new EngineStateChangedEventArgs( EngineStateChangeType.Other, string.Format("A {0} was destroyed because it {1}.", ((Species) organismState.Species).Name, reasonDescription), string.Format("A {0} was destroyed because it {1}.", ((Species) organismState.Species).Name, reasonDescription) ); }
/// <summary> /// Derived classes must override (and call Base.CopyStateInto) /// if they have additional state /// </summary> /// <param name="newInstance">The new state that will hold this state's members</param> /// <internal/> protected virtual void CopyStateInto(OrganismState newInstance) { // OrganismID and species are copied via the constructor newInstance.Radius = Radius; // Safe because they are immutable newInstance.currentMoveToAction = currentMoveToAction; newInstance.currentReproduceAction = currentReproduceAction; // Points aren't immutable, so return a copy newInstance.currentPosition = new Point(currentPosition.X, currentPosition.Y); newInstance.energy = energy; newInstance.currentFoodChunks = currentFoodChunks; newInstance.IncubationTicks = IncubationTicks; newInstance.TickAge = TickAge; newInstance.ReproductionWait = ReproductionWait; newInstance.GrowthWait = GrowthWait; newInstance.DeathReason = DeathReason; newInstance.ActualDirection = ActualDirection; // This object remains mutable because it is information // that the renderer updates after the WorldVector has been // created. Nothing besides the renderer should ever touch this newInstance.RenderInfo = RenderInfo; }
/// <internal/> public MoveCompletedEventArgs(int actionID, Action action, ReasonForStop reason, OrganismState blockingOrganism) : base(actionID, action) { Reason = reason; BlockingOrganism = blockingOrganism; }
/// <summary> /// /// </summary> /// <param name="newInstance"></param> protected override void CopyStateInto(OrganismState newInstance) { base.CopyStateInto(newInstance); ((AnimalState)newInstance).damage = damage; ((AnimalState)newInstance).RotTicks = RotTicks; ((AnimalState)newInstance).state = new AntennaState(state); }
/// <summary> /// Creates a NewOrganism object intialized with the creature's state, some /// DNA information if available. The state object must be immutable for /// this to succeed. /// </summary> /// <param name="state">The state of the organism to be added.</param> /// <param name="dna">The DNA the creature gets initialized with.</param> public NewOrganism(OrganismState state, byte[] dna) { // Must be mutable Debug.Assert(!state.IsImmutable); this.state = state; this.dna = dna; }
/// <summary> /// <para> /// Used to determine if your creature is within range to eat another /// target creature. /// </para> /// <para> /// This method does not attempt to validate the position of the /// organismState with respect to the current world state. If you /// pass a stale object in then you may get stale results. Make sure /// you use the LookFor method to get the most up-to-date results. /// </para> /// </summary> /// <param name="targetOrganism"> /// OrganismState of the creature you're thinking of eating. /// </param> /// <returns> /// True if the creature is within range to eat, False otherwise. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if the targetOrganism parameter is null. /// </exception> public Boolean WithinEatingRange(OrganismState targetOrganism) { if (targetOrganism == null) { throw new ArgumentNullException("targetOrganism", "The argument 'targetOrganism' cannot be null"); } return(State.IsAdjacentOrOverlapping(targetOrganism)); }
/// <summary> /// <para> /// Tries to return an updated OrganismState given a creature's state OrganismState. /// This function may return null if the creature can't be found or was hidden by /// camouflage. You may call this method multiple times and get different results. /// </para> /// </summary> /// <param name="organismState"> /// The stale OrganismState object you want to refresh. /// </param> /// <returns> /// OrganismState representing the creature being looked for or null if not found. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if the organismState parameter is null. /// </exception> public OrganismState LookFor(OrganismState organismState) { if (organismState == null) { throw new ArgumentNullException("organismState", "The argument 'organismState' cannot be null"); } return(World.LookFor(organismState)); }
/// <summary> /// <para> /// Calculates the linear distance between your creature and another using /// various API's defined by the Vector class. /// </para> /// </summary> /// <param name="organismState"> /// The OrganismState object for the creature to /// use when computing linear distance from you're creature. /// </param> /// <returns> /// A System.Double representing the linear distance between your creature and another. /// </returns> public double DistanceTo(OrganismState organismState) { if (organismState == null) { throw new ArgumentNullException("organismState", "The argument 'organismState' cannot be null"); } return(Vector.Subtract(Position, organismState.Position).Magnitude); }
/// <summary> /// Creates a new event relating to a creature arriving. /// </summary> /// <param name="organismState">The creature arriving.</param> /// <returns>State change initialized for a teleporting creature with messages.</returns> public static EngineStateChangedEventArgs AnimalArrived(OrganismState organismState) { return new EngineStateChangedEventArgs( EngineStateChangeType.AnimalTeleported, string.Format("A new {0} arrived at {1}", ((Species) organismState.Species).Name, DateTime.Now.TimeOfDay), string.Format("A new {0} was teleported into your world at {1}", ((Species) organismState.Species).Name, DateTime.Now) ); }
/// <summary> /// <para> /// Allows a creature to determine if the OrganismState of another creature /// represents the same species. This can be used to determine whether you /// should attack/defend against another creature. /// </para> /// <para> /// Creatures of the same species often don't fight one another, defend against /// one another, and kill one another. They often help their own species in /// fights against other species. Carnivores of the same species may sacrifice /// themselves as food once they become too old to members of their species. /// </para> /// </summary> /// <param name="targetState"> /// The OrganismState for the creature to be used in species comparison. /// </param> /// <returns> /// True if the organism owning the state object is of the same species, false otherwise. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if the targetState parameter is null. /// </exception> public Boolean IsMySpecies(OrganismState targetState) { if (targetState == null) { throw new ArgumentNullException("targetState", "The argument 'targetState' cannot be null"); } return(State.Species.IsSameSpecies(targetState.Species)); }
/// <summary> /// Create a new state object to represent an organism. /// </summary> /// <param name="id">The GUID ID representing this organism in the world.</param> /// <param name="species">The species which defines the basic properties of the organism.</param> /// <param name="generation">The familial generation number.</param> /// <param name="initialEnergyState">The initial EnergyState of the organism.</param> /// <param name="initialRadius">The initial Radius of the organism.</param> internal OrganismState(string id, ISpecies species, int generation, EnergyState initialEnergyState, int initialRadius) { DeathReason = PopulationChangeReason.NotDead; ID = id; Species = species; Generation = generation; SetStoredEnergyInternal(OrganismState.UpperBoundaryForEnergyState(species, initialEnergyState, initialRadius)); Radius = initialRadius; events = new OrganismEventResults(); }
internal MovementSegment(MovementSegment previous, OrganismState state, Point startingPoint, int entryTime, int gridX, int gridY) { Debug.Assert((previous == null && entryTime == 0) || (previous != null && entryTime != 0)); this.State = state; this.StartingPoint = startingPoint; this.EntryTime = entryTime; this.GridX = gridX; this.GridY = gridY; this.Previous = previous; }
/// <summary> /// <para> /// Method used to command your creature to start eating another creature. /// You can only eat one target creature per round, and a single call to /// BeginEating will only attack a target creature in the upcoming tick. /// Calling BeginEating multiple times in the same turn will only result /// in your creature eating the target specified in the last call to /// BeginEating. /// </para> /// <para> /// Eating is asynchronous so you'll need to handle the EatCompleted event /// in order to get the status of the bite. A single bite might not /// produce enough energy for your creature so you'll have to make multiple /// bites against the same target until it is completed eaten. /// </para> /// </summary> /// <param name="targetOrganism"> /// OrganismState of the creature you wish to eat. /// </param> /// <exception cref="System.ArgumentNullException"> /// Thrown if the targetOrganism parameter is null. /// </exception> /// <exception cref="AlreadyFullException"> /// Thrown if your creature is not hungry enough to eat. /// </exception> /// <exception cref="NotVisibleException"> /// Thrown if the creature had disappeared from your creature's view. /// </exception> /// <exception cref="NotWithinDistanceException"> /// Thrown if your creature is not within eating distance. /// </exception> /// <exception cref="ImproperFoodException"> /// Thrown if a Carnivore tries to eat a plant or a Herbivore tries to eat an Animal /// </exception> /// <exception cref="NotDeadException"> /// Thrown if a Carnivore tries to eat a creature that isn't dead yet. /// </exception> public void BeginEating(OrganismState targetOrganism) { if (targetOrganism == null) { throw new ArgumentNullException("targetOrganism", "The argument 'targetOrganism' cannot be null"); } if (State.EnergyState > EnergyState.Normal) { throw new AlreadyFullException(); } // Get an up to date state -- this organism may be an old state var currentOrganism = World.LookForNoCamouflage(targetOrganism); if (currentOrganism == null) { throw new NotVisibleException(); } if (!WithinEatingRange(currentOrganism)) { throw new NotWithinDistanceException(); } // Make sure it is edible if (State.AnimalSpecies.IsCarnivore) { if (currentOrganism is PlantState) { throw new ImproperFoodException(); } if (currentOrganism.IsAlive) { throw new NotDeadException(); } } else { if (currentOrganism is AnimalState) { throw new ImproperFoodException(); } } var actionID = GetNextActionID(); var action = new EatAction(ID, actionID, targetOrganism); lock (PendingActions) { PendingActions.SetEatAction(action); InProgressActions.SetEatAction(action); } }
/// <summary> /// Used to compute whether or not a given state object is in an adjacent or /// overlapping grid cell. The extra radius can be used to extend the area /// used for the function to find a match and so can be used for functions /// like visibiliy. /// </summary> /// <param name="state1ExtraRadius">The amount of extra grid cells to add</param> /// <param name="state2">The organism state of the creature to use in the area test.</param> /// <returns>True if the creature is within range, false otherwise.</returns> public Boolean IsWithinRect(int state1ExtraRadius, OrganismState state2) { if (null == state2) { return(false); } var state1Radius = CellRadius + state1ExtraRadius; var state2Radius = state2.CellRadius; var difference = (GridX - state1Radius) - (state2.GridX - state2Radius); if (difference < 0) { // Negative means state1 boundary < state2 boundary if (-difference > (state1Radius * 2) + 1) { // X isn't overlapping or adjacent return(false); } } else { // state2 boundary <= state1 boundary if (difference > (state2Radius * 2) + 1) { // X isn't overlapping or adjacent return(false); } } difference = (GridY - state1Radius) - (state2.GridY - state2Radius); if (difference < 0) { // Negative means state1 boundary < state2 boundary if (-difference > (state1Radius * 2) + 1) { // Y isn't overlapping or adjacent return(false); } } else { // state2 boundary <= state1 boundary if (difference > (state2Radius * 2) + 1) { // Y isn't overlapping or adjacent return(false); } } return(true); }
/// <summary> /// Determines if the given organism state is within teleport zone. /// </summary> /// <param name="state">The state being checked.</param> /// <returns>True if the state is in the zone, false otherwise.</returns> public Boolean Contains(OrganismState state) { var difference = _rectangle.Left - (state.Position.X - state.Radius); if (difference < 0) { // Negative means rectangle boundary < state boundary if (-difference > _rectangle.Width + 1) { // X isn't overlapping or adjacent return false; } } else { // state boundary <= rectangle boundary if (difference > (state.Radius*2) + 1) { // X isn't overlapping or adjacent return false; } } difference = _rectangle.Top - (state.Position.Y - state.Radius); if (difference < 0) { // Negative means rectangle boundary < state boundary if (-difference > _rectangle.Height + 1) { // Y isn't overlapping or adjacent return false; } } else { // state boundary <= rectangle boundary if (difference > (state.Radius*2) + 1) { // Y isn't overlapping or adjacent return false; } } return true; }
/// <summary> /// Should only be called by the GameEngine. /// </summary> /// <param name="state">The state of the organism to add.</param> public void AddOrganism(OrganismState state) { if (IsImmutable) { throw new ApplicationException("WorldState must be mutable to add organisms."); } Debug.Assert(state.GridX >= 0 && state.GridX < _gridWidth && state.GridY >= 0 && state.GridY < _gridHeight); Debug.Assert(_cellOrganisms[state.GridX, state.GridY] == null); if (_organisms.ContainsKey(state.ID)) { throw new OrganismAlreadyExistsException(); } FillCells(state, state.GridX, state.GridY, state.CellRadius, false); // Lock the size and position since we've added it to the index and these shouldn't be changed now state.LockSizeAndPosition(); _organisms.Add(state.ID, state); }
/// <summary> /// Fills in the appropriate grid cells in our CellIndex given the organism state. /// </summary> /// <param name="state">The state of the organism being added.</param> /// <param name="cellX">The location of the organism in cells.</param> /// <param name="cellY">The location of the organism in cells.</param> /// <param name="cellRadius">The radius in cells of the organism.</param> /// <param name="clear">Determines if cells should be cleared or set.</param> public void FillCells(OrganismState state, int cellX, int cellY, int cellRadius, Boolean clear) { Debug.Assert(cellX - cellRadius >= 0 && cellY - cellRadius + 1 >= 0); for (var x = cellX - cellRadius; x <= cellX + cellRadius; x++) { for (var y = cellY - cellRadius; y <= cellY + cellRadius; y++) { if (clear) { // Make sure we are only clearing ourselves, the value may be null because clearindex // may have been called if (!(_cellOrganisms[x, y] == null || _cellOrganisms[x, y].ID == state.ID)) { Debug.Assert(_cellOrganisms[x, y] == null || _cellOrganisms[x, y].ID == state.ID); } _cellOrganisms[x, y] = null; } else { // Make sure there was no one else here if (!(_cellOrganisms[x, y] == null)) { Debug.Assert(_cellOrganisms[x, y] == null); } _cellOrganisms[x, y] = state; } } } }
/// <summary> /// Copies the value of the current state into a new state object. /// Used by the CloneMutable method to make mutable copies of state /// objects. /// </summary> /// <param name="newInstance">The new state object that will hold the values.</param> /// <internal/> protected override void CopyStateInto(OrganismState newInstance) { base.CopyStateInto(newInstance); ((PlantState)newInstance).Height = Height; }
/// <summary> /// Make sure the organism only overlaps itself and not other organisms. /// </summary> /// <param name="state">The state of the organism to check.</param> /// <returns>True if the creature is safe, false otherwise.</returns> public Boolean OnlyOverlapsSelf(OrganismState state) { Debug.Assert(this.IndexBuilt); int minGridX = state.GridX - state.CellRadius; int maxGridX = state.GridX + state.CellRadius; int minGridY = state.GridY - state.CellRadius; int maxGridY = state.GridY + state.CellRadius; // If it would be out of bounds, return false. if (minGridX < 0 || maxGridX > gridWidth - 1 || minGridY < 0 || maxGridY > gridHeight - 1) { return false; } for (int x = minGridX; x <= maxGridX; x++) { for (int y = minGridY; y <= maxGridY; y++) { if (CellOrganisms[x,y] != null) { if (CellOrganisms[x,y].ID != state.ID) { return false; } } } } return true; }
/// <summary> /// <para> /// Used to determine if your creature is within range to eat another /// target creature. /// </para> /// <para> /// This method does not attempt to validate the position of the /// organismState with respect to the current world state. If you /// pass a stale object in then you may get stale results. Make sure /// you use the LookFor method to get the most up-to-date results. /// </para> /// </summary> /// <param name="targetOrganism"> /// OrganismState of the creature you're thinking of eating. /// </param> /// <returns> /// True if the creature is within range to eat, False otherwise. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if the targetOrganism parameter is null. /// </exception> public Boolean WithinEatingRange(OrganismState targetOrganism) { if (targetOrganism == null) { throw new ArgumentNullException("targetOrganism", "The argument 'targetOrganism' cannot be null"); } return State.IsAdjacentOrOverlapping(targetOrganism); }
/// <summary> /// Creates a new KilledOrganism based on information in an OrganismState. /// </summary> /// <param name="state">The state object that ID and death reason will be pulled from.</param> public KilledOrganism(OrganismState state) { this.id = state.ID; this.deathReason = state.DeathReason; }
/// <summary> /// <para> /// Determines if a creature is immediately next to or overlapping /// another creature using grid cells comparisons. /// </para> /// </summary> /// <param name="state2"> /// OrganismState of the creature to check for proximity. /// </param> /// <returns> /// True if the creature is adjacent or overlapping, False otherwise. /// </returns> public Boolean IsAdjacentOrOverlapping(OrganismState state2) { return(IsWithinRect(0, state2)); }
/// <summary> /// Create a new eat action to eat a specific organism. /// </summary> /// <param name="organismID">Eating organism's ID</param> /// <param name="actionID">Unique Organism ID for action.</param> /// <param name="targetOrganism">The state representing the organism to eat.</param> internal EatAction(string organismID, int actionID, OrganismState targetOrganism) : base(organismID, actionID) { TargetOrganism = targetOrganism; }
/// <summary> /// Find a list of organisms within the view of the given organism. /// </summary> /// <param name="state">The state of the organism to check.</param> /// <param name="radius">The radius of vision.</param> /// <returns>A list of found organisms.</returns> public ArrayList FindOrganismsInView(OrganismState state, int radius) { Debug.Assert(IndexBuilt); // Make sure we have enough space in our visibility matrix Debug.Assert((state.CellRadius + radius)*2 + 1 <= _invisible.GetLength(0)); var foundOrganisms = new ArrayList(); var foundHash = new Hashtable(); var originX = state.GridX; var originY = state.GridY; var middleX = -originX + state.CellRadius + radius; var middleY = -originY + state.CellRadius + radius; int xIncrement = 0, yIncrement = 0; // The first ring is all visible var currentRadius = state.CellRadius + 1; var currentX = originX - currentRadius; var currentY = originY - currentRadius; for (var side = 0; side < 4; side++) { switch (side) { case 0: xIncrement = 1; yIncrement = 0; break; case 1: xIncrement = 0; yIncrement = 1; break; case 2: xIncrement = -1; yIncrement = 0; break; case 3: xIncrement = 0; yIncrement = -1; break; } for (var count = 0; count < currentRadius << 1; count++) { if (currentX >= 0 && currentY >= 0 && currentX < _gridWidth && currentY < _gridHeight) { var currentOrganism = _cellOrganisms[currentX, currentY]; if (currentOrganism != null) { if (foundHash[currentOrganism] == null) { foundHash[currentOrganism] = currentOrganism; foundOrganisms.Add(currentOrganism); } } _invisible[currentX + middleX, currentY + middleY] = 0; } currentX += xIncrement; currentY += yIncrement; } } for (currentRadius = state.CellRadius + 2; currentRadius <= state.CellRadius + radius; currentRadius++) { // Look at each point on a square of radius currentRadius // Look at the two points that are between this point and the origin // if they are invisible, this point is invisible // p1 is in the diagonal direction from [x,y] to [originX,originY] and // p2 is in the horizontal/vertical direction from [x,y] to [originX, originY]. // p2 collapses to point_1 if j = 0 or i = 0 currentX = originX - currentRadius; currentY = originY - currentRadius; for (var side = 0; side < 4; side++) { switch (side) { case 0: xIncrement = 1; yIncrement = 0; break; case 1: xIncrement = 0; yIncrement = 1; break; case 2: xIncrement = -1; yIncrement = 0; break; case 3: xIncrement = 0; yIncrement = -1; break; } for (var count = 0; count < currentRadius << 1; count++) { if (currentX >= 0 && currentY >= 0 && currentX < _gridWidth && currentY < _gridHeight) { var i = currentX - originX; var j = currentY - originY; // These actually calculate -1 * sign not just the sign function int signI; if (i < 0) { signI = 1; } else if (i > 0) { signI = -1; } else { signI = 0; } int signJ; if (j < 0) { signJ = 1; } else if (j > 0) { signJ = -1; } else { signJ = 0; } int absI; if (i < 0) { absI = -i; } else { absI = i; } int absJ; if (j < 0) { absJ = -j; } else { absJ = j; } // Check first point which is the diagonal direction from [x,y] to [originX,originY] int p1X; int p1Y; if (absJ > absI) { // We are in the 90 < theta < 45 degrees region of every quadrant p1X = currentX; p1Y = signJ + currentY; } else { p1X = signI + currentX; p1Y = signJ + currentY; } // Check second point // if Abs(j) == Abs(i) then we are on a diagonal, so secondpoint is the same as first point int p2X; int p2Y; if (absJ != absI) { p2X = signI + currentX; p2Y = signJ + currentY; } else { p2X = p1X; p2Y = p1Y; } // if p1 or p2 was invisible or they were something that blocks visibility if (_invisible[p1X + middleX, p1Y + middleY] == 1 || _invisible[p2X + middleX, p2Y + middleY] == 1) { _invisible[currentX + middleX, currentY + middleY] = 1; } else { var currentOrganism = _cellOrganisms[currentX, currentY]; if (currentOrganism != null) { // if there is an organism here, mark this spot as invisible // (even though it really isn't) // so the outer cells will be invisible too _invisible[currentX + middleX, currentY + middleY] = 1; if (foundHash[currentOrganism] == null) { foundHash[currentOrganism] = currentOrganism; foundOrganisms.Add(currentOrganism); } } else { _invisible[currentX + middleX, currentY + middleY] = 0; } } } currentX += xIncrement; currentY += yIncrement; } } } return foundOrganisms; }
/// <summary> /// Can be called with an OrganismState that needs to be teleported. /// Cannot be called during MoveAnimals since it passes true to the clearOld /// argument in RemoveOrganism. /// </summary> /// <param name="state">The state of the creature to be teleported.</param> public void Teleport(OrganismState state) { if (null == state) { throw new Exception("Null object passed into Teleport"); } TeleportState teleportState = new TeleportState(); Organism organism = Scheduler.GetOrganism(state.ID); state.MakeImmutable(); teleportState.OrganismState = state; teleportState.Organism = organism; teleportState.OrganismWrapper = new OrganismWrapper(organism); teleportState.Originator = _newWorldState.StateGuid; teleportState.Country = GameConfig.UserCountry; teleportState.State = GameConfig.UserState; // Remove it from this world removeOrganism(new KilledOrganism(state.ID, PopulationChangeReason.TeleportedFrom)); // Teleport the organism through the network engine if (_usingNetwork) { _networkEngine.Teleport(teleportState); } else { ReceiveTeleportation(teleportState, true); } }
/// <summary> /// Uses the bounding box computation methods to compute a /// box that can be printed within the graphics engine. This /// is used for debugging creature pathing. /// </summary> /// <param name="orgState">The state of the creature to compute a bounding box for.</param> /// <returns>A bounding box.</returns> private Rectangle GetBoundsOfState(OrganismState orgState) { var origin = orgState.Position; var cellRadius = orgState.CellRadius; var p1 = new Point( (origin.X >> 3)*8, (origin.Y >> 3)*8 ); var bounds = new Rectangle( p1.X - (cellRadius*8), p1.Y - (cellRadius*8), (((cellRadius*2 + 1)*8) - 1), (((cellRadius*2 + 1)*8) - 1) ); return bounds; }
/// <summary> /// Provides the same features as LookFor, except does not take camouflage /// into account. /// </summary> /// <param name="organismState">The organism state that needs to be updated.</param> /// <returns>An updated state if the creature is still alive and within range, null otherwise.</returns> /// <internal/> public OrganismState LookForNoCamouflage(OrganismState organismState) { if (organismState != null) { var worldState = AppMgr.CurrentScheduler.CurrentState; organismState = worldState.GetOrganismState(organismState.ID); OrganismState thisOrganism = CurrentAnimalState; if (organismState == null || !thisOrganism.IsWithinRect(((AnimalSpecies) thisOrganism.Species).EyesightRadius, organismState)) { organismState = null; } } return organismState; }
/// <summary> /// Should only be called by the game engine. Should be called if the state /// of the organism changes. /// </summary> /// <param name="state">The state of the organism to refresh.</param> public void RefreshOrganism(OrganismState state) { if (IsImmutable) { throw new ApplicationException("WorldState must be mutable to change."); } var organismID = state.ID; // Clear the index if it's built if (IndexBuilt) { var oldState = GetOrganismState(organismID); FillCells(oldState, oldState.GridX, oldState.GridY, oldState.CellRadius, true); } _organisms.Remove(organismID); AddOrganism(state); }
/// <summary> /// Make sure the organism only overlaps itself and not other organisms. /// </summary> /// <param name="state">The state of the organism to check.</param> /// <returns>True if the creature is safe, false otherwise.</returns> public Boolean OnlyOverlapsSelf(OrganismState state) { Debug.Assert(IndexBuilt); var minGridX = state.GridX - state.CellRadius; var maxGridX = state.GridX + state.CellRadius; var minGridY = state.GridY - state.CellRadius; var maxGridY = state.GridY + state.CellRadius; // If it would be out of bounds, return false. if (minGridX < 0 || maxGridX > _gridWidth - 1 || minGridY < 0 || maxGridY > _gridHeight - 1) { return false; } for (var x = minGridX; x <= maxGridX; x++) { for (var y = minGridY; y <= maxGridY; y++) { if (_cellOrganisms[x, y] == null) continue; if (_cellOrganisms[x, y].ID != state.ID) { return false; } } } return true; }
/// <summary> /// <para> /// Tries to return an updated OrganismState given a creature's state OrganismState. /// This function may return null if the creature can't be found or was hidden by /// camouflage. You may call this method multiple times and get different results. /// </para> /// </summary> /// <param name="organismState"> /// The stale OrganismState object you want to refresh. /// </param> /// <returns> /// OrganismState representing the creature being looked for or null if not found. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if the organismState parameter is null. /// </exception> public OrganismState LookFor(OrganismState organismState) { if (organismState == null) { throw new ArgumentNullException("organismState", "The argument 'organismState' cannot be null"); } return World.LookFor(organismState); }
/// <summary> /// /// </summary> /// <param name="newInstance"></param> protected override void CopyStateInto(OrganismState newInstance) { base.CopyStateInto(newInstance); ((AnimalState) newInstance).damage = damage; ((AnimalState) newInstance).RotTicks = RotTicks; ((AnimalState) newInstance).state = new AntennaState(state); }
/// <summary> /// <para> /// Allows a creature to determine if the OrganismState of another creature /// represents the same species. This can be used to determine whether you /// should attack/defend against another creature. /// </para> /// <para> /// Creatures of the same species often don't fight one another, defend against /// one another, and kill one another. They often help their own species in /// fights against other species. Carnivores of the same species may sacrifice /// themselves as food once they become too old to members of their species. /// </para> /// </summary> /// <param name="targetState"> /// The OrganismState for the creature to be used in species comparison. /// </param> /// <returns> /// True if the organism owning the state object is of the same species, false otherwise. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if the targetState parameter is null. /// </exception> public Boolean IsMySpecies(OrganismState targetState) { if (targetState == null) { throw new ArgumentNullException("targetState", "The argument 'targetState' cannot be null"); } return State.Species.IsSameSpecies(targetState.Species); }
/// <summary> /// Copies the value of the current state into a new state object. /// Used by the CloneMutable method to make mutable copies of state /// objects. /// </summary> /// <param name="newInstance">The new state object that will hold the values.</param> /// <internal/> protected override void CopyStateInto(OrganismState newInstance) { base.CopyStateInto(newInstance); ((PlantState) newInstance).Height = Height; }
internal void SelectObject(OrganismState state) { if (formClosed) { return; } comboBox.Items.Add(new OrganismComboItem(state)); if (comboBox.Items.Count == 1) { comboBox.SelectedIndex = 0; } RefreshGrid(); }
/// <summary> /// Initializes a new organism state by computed and /// attaching a TerrariumSprite class that can be used /// to control on screen movement, animation skins, and /// selection. /// </summary> /// <param name="orgState">The organism state to attach the sprite animation information to.</param> private void InitOrganism(OrganismState orgState) { var tsSprite = new TerrariumSprite(); tsSprite.CurFrame = 0; tsSprite.CurFrameDelta = 1; var species = orgState.Species; if (species is AnimalSpecies) { tsSprite.SpriteKey = ((AnimalSpecies) species).Skin; tsSprite.SkinFamily = ((AnimalSpecies) species).SkinFamily.ToString(); tsSprite.IsPlant = false; if (tsSprite.SpriteKey == null && tsSprite.SkinFamily == null) { tsSprite.SpriteKey = AnimalSkinFamily.Spider.ToString(); // This will be our default } } else { tsSprite.SpriteKey = ((PlantSpecies) species).Skin; tsSprite.SkinFamily = ((PlantSpecies) species).SkinFamily.ToString(); tsSprite.IsPlant = true; if (tsSprite.SpriteKey == null && tsSprite.SkinFamily == null) { tsSprite.SpriteKey = PlantSkinFamily.Plant.ToString(); // This will be our default } } tsSprite.XPosition = orgState.Position.X; tsSprite.YPosition = orgState.Position.Y; tsSprite.PreviousAction = orgState.PreviousDisplayAction; orgState.RenderInfo = tsSprite; }
internal void UnselectObject(OrganismState state) { if (formClosed) { return; } UnselectObject(state.ID); }
/// <summary> /// Subtracts an organism from the count of organisms. Depending on the /// organism type either plants or animals will be decremented. /// </summary> /// <param name="state">The state of the creature.</param> /// <param name="reason">The reason the creature is being removed.</param> private void uncountOrganism(OrganismState state, PopulationChangeReason reason) { Debug.Assert(state != null); _populationData.UncountOrganism(((Species) state.Species).Name, reason); if (state is AnimalState) { _animalCount--; } else { _plantCount--; } }
public OrganismComboItem(OrganismState o) { this.id = o.ID; this.name = ((Species) o.Species).Name; this.text = this.name + " - " + this.id; }