// KAnimal Ver.1.2 rev.200206171 using System; using System.Drawing; using System.Collections; using System.IO; public class DistComparer : IComparer { Animal parent; public DistComparer(Animal parent) { this.parent = parent; } public int Compare(object a,object b) { double da = parent.DistanceTo(a as OrganismState); double db = parent.DistanceTo(b as OrganismState); return Math.Sign(da - db); } } abstract public class KAnimal : Animal { // //////////////////////////////////////////////////////////////////////////// protected double chaseAlpha = 0.03; protected int distToThreat1 = 150; protected int distToThreat2 = 100; protected int scanCount = 10; protected ArrayList foundCreatures = new ArrayList(); protected AnimalState chase = null; protected int moveCount = 0; // //////////////////////////////////////////////////////////////////////////// IComparer foodComp; IComparer bruntComp; IComparer threatComp; protected IComparer FoodComp { set { if(value != null) { foodComp = value; } } get { return foodComp; } } protected IComparer BruntComp { set { if(value != null) { bruntComp = value; } } get { return bruntComp; } } protected IComparer ThreatComp { set { if(value != null) { threatComp = value; } } get { return threatComp; } } // //////////////////////////////////////////////////////////////////////////// ArrayList foodList = new ArrayList(); ArrayList bruntList = new ArrayList(); ArrayList threatList = new ArrayList(); protected OrganismState Food { set { foodList.Insert(0,value); } get { if(foodList.Count == 0) { return null; } return foodList[0] as OrganismState; } } protected AnimalState Brunt { set { bruntList.Insert(0,value); } get { if(bruntList.Count == 0) { return null; } return bruntList[0] as AnimalState; } } protected AnimalState Threat { set { threatList.Insert(0,value); } get { if(threatList.Count == 0) { return null; } return threatList[0] as AnimalState; } } protected ArrayList FoodList { get { return ArrayList.ReadOnly(foodList); } } protected ArrayList BruntList { get { return ArrayList.ReadOnly(bruntList); } } protected ArrayList ThreatList { get { return ArrayList.ReadOnly(threatList); } } // //////////////////////////////////////////////////////////////////////////// protected virtual int FavSpeed { get { switch(State.EnergyState) { case EnergyState.Full: return (int)(Species.MaximumSpeed * .7); case EnergyState.Normal: return (int)(Species.MaximumSpeed * .5); case EnergyState.Hungry: return (int)(Species.MaximumSpeed * .4); default: return (int)(Species.MaximumSpeed * .25); } } } // //////////////////////////////////////////////////////////////////////////// protected override void Initialize() { foodComp = new DistComparer(this); bruntComp = new DistComparer(this); threatComp = new DistComparer(this); Load += new LoadEventHandler(LoadEvent); MoveCompleted += new MoveCompletedEventHandler(MoveCompletedEvent); AttackCompleted += new AttackCompletedEventHandler(AttackCompletedEvent); EatCompleted += new EatCompletedEventHandler(EatCompletedEvent); Attacked += new AttackedEventHandler(AttackedEvent); DefendCompleted += new DefendCompletedEventHandler(DefendCompletedEvent); Idle += new IdleEventHandler(IdleEvent); } // //////////////////////////////////////////////////////////////////////////// protected int SpeedCheck(int speed) { return (speed > Species.MaximumSpeed) ? Species.MaximumSpeed : (speed < 2) ? 2 : speed; } protected Point RangeCheck(Point o) { int nx = o.X; int ny = o.Y; nx = (nx < 0 ? 0 : nx); nx = (WorldWidth <= nx ? WorldWidth-1 : nx); ny = (ny < 0 ? 0 : ny); ny = (WorldHeight <= ny ? WorldHeight-1 : ny); return new Point(nx,ny); } static private double LeftTicks(AnimalState d,AnimalState a) { double dHitpoint = EngineSettings.DamageToKillPerUnitOfRadius * d.Radius - d.Damage; double aAttackpoint = a.AnimalSpecies.MaximumAttackDamagePerUnitRadius * a.Radius; double dDefendpoint = d.AnimalSpecies.MaximumDefendDamagePerUnitRadius * d.Radius; return dHitpoint / Math.Max(1,aAttackpoint - dDefendpoint); } protected bool CanWin(AnimalState target) { if(target == null) return false; return 0.8*LeftTicks(State,target) > LeftTicks(target,State); } protected new bool CanAttack(AnimalState target) { if(target == null) return false; return base.CanAttack(target); } protected new bool CanEat(OrganismState target) { if(target == null) return false; return base.CanEat && WithinEatingRange(target); } protected Point GetBypass(OrganismState target) { if(target == null) { return new Point(OrganismRandom.Next()); } int dx = target.GridX - State.GridX; int dy = target.GridY - State.GridY; int size = State.CellRadius + target.CellRadius + 2; if(Math.Abs(dx) > Math.Abs(dy)) { if(OrganismRandom.Next(2) == 1) { return new Point(Position.X,(target.GridY + size) << 3); } else { return new Point(Position.X,(target.GridY - size) << 3); } } else { if(OrganismRandom.Next(2) == 1) { return new Point((target.GridX + size) << 3,Position.Y); } else { return new Point((target.GridX - size) << 3,Position.Y); } } } // //////////////////////////////////////////////////////////////////////////// protected void Wander(int speed) { if(IsMoving) return; int RandomX = OrganismRandom.Next(0, WorldWidth - 1); int RandomY = OrganismRandom.Next(0, WorldHeight - 1); BeginMoving(new Point(RandomX,RandomY), speed); } protected void Wander() { Wander(FavSpeed); } protected void BeginChase(AnimalState target) { if(target == null) { return; } WriteTrace("chase",target.Position); chase = target; double dist = DistanceTo(target); Point P = target.Position; if(target.CurrentMoveToAction != null) { MovementVector mv = target.CurrentMoveToAction.MovementVector; Point D = mv.Destination; Vector vector = Vector.Subtract(target.Position,D); vector = vector.GetUnitVector().Scale(dist * chaseAlpha * mv.Speed); P = Vector.Add(P,vector); } int speed = Math.Max(target.Speed * 2 + 1,FavSpeed); BeginMoving(P,speed); } protected void RunAway(AnimalState target) { Vector vector = Vector.Subtract(target.Position,Position).GetUnitVector().Scale(300); int speed = FavSpeed; if(DistanceTo(target) < distToThreat2) { speed = Species.MaximumSpeed; } else if(DistanceTo(target) < distToThreat1) { speed = target.Speed+2; } BeginMoving(Vector.Add(Position,vector) ,speed); } virtual protected void BeginMoving(Point point,int speed) { if(moveCount > 0) { return; } speed = SpeedCheck(speed); point = RangeCheck(point); base.BeginMoving(new MovementVector(point,speed)); } virtual protected void BeginMoving(Point point) { BeginMoving(point,FavSpeed); } virtual protected void BeginMoving(OrganismState target,int speed) { BeginMoving(target.Position,speed); } virtual protected void BeginMoving(OrganismState target) { BeginMoving(target.Position,FavSpeed); } protected new void BeginAttacking(AnimalState target) { if(target == null) return; if(CanAttack(target)) { base.BeginAttacking(target); } } protected new void BeginDefending(AnimalState target) { if(target == null) return; base.BeginDefending(target); } protected new void BeginEating(OrganismState target) { if(target == null) return; try { if(CanEat(target)) { base.BeginEating(target); } } catch(NotVisibleException) { RemoveTarget(target); } } protected bool WithinViewRange(OrganismState target) { return DistanceTo(target) < (Species.EyesightRadius << 3); } // //////////////////////////////////////////////////////////////////////////// protected void UpdateViewState() { ArrayList newfoundCreatures = base.Scan(); foreach(OrganismState oos in foundCreatures) { bool exist = false; foreach(OrganismState nos in newfoundCreatures) { if(oos.ID == nos.ID) { exist = true; break; } } if(!exist) { OrganismState os = LookFor(oos); if(os != null) { newfoundCreatures.Add(os); } else { if(!WithinViewRange(oos)) { newfoundCreatures.Add(oos); } } } } foundCreatures = newfoundCreatures; } protected void RemoveTarget(OrganismState target) { foundCreatures.Remove(target); } protected void UpdateTarget() { foodList.Clear(); bruntList.Clear(); threatList.Clear(); foreach(OrganismState target in foundCreatures) { OrganismState t = LookFor(target); if(t == null) continue; if(IsFood (t)) foodList .Add(t); if(IsBrunt (t)) bruntList .Add(t); if(IsThreat(t)) threatList.Add(t); } foodList.Sort(foodComp); bruntList.Sort(bruntComp); threatList.Sort(threatComp); } // //////////////////////////////////////////////////////////////////////////// protected virtual void LoadEvent(object sender, LoadEventArgs e) { try { moveCount--; if(chase != null) { chase = LookFor(chase) as AnimalState; } for(int i = 0 ; i < scanCount ; i++) { UpdateViewState(); } UpdateTarget(); if(CanReproduce && WannaReproduce()) { BeginReproduction(DNA); } } catch(Exception exc) { WriteTrace(exc); } } protected virtual void MoveCompletedEvent(object sender, MoveCompletedEventArgs e) { try { moveCount = 0; if(e.Reason == ReasonForStop.Blocked) { OrganismState os = LookFor(e.BlockingOrganism); if(os != null) { if(IsBrunt(os) && CanAttack(os as AnimalState)) { Brunt = os as AnimalState; if(WannaAttack(Brunt)) { BeginAttacking(Brunt); } return; } if(IsFood(os) && WithinEatingRange(os)) { Food = os; if(WannaEat(os)) { BeginEating(os); } return; } } BeginMoving(GetBypass(os),e.MoveToAction.MovementVector.Speed); moveCount = 80 / e.MoveToAction.MovementVector.Speed; } else if(chase != null) { if(WithinAttackingRange(chase)) { chase = null; } else { BeginChase(chase); } } } catch(Exception exc) { WriteTrace(exc); } } protected virtual void AttackedEvent(object sender, AttackedEventArgs e) { try { AnimalState target = LookFor(e.Attacker) as AnimalState; if(target == null) return; if(WannaDefend(target)) { BeginDefending(target); } if(IsBrunt(target) && WannaAttack(target)) { BeginAttacking(target); } else { RunAway(target); } } catch(Exception exc) { WriteTrace(exc); } } protected virtual void DefendCompletedEvent(object sender, DefendCompletedEventArgs e) { try { AnimalState target = LookFor(e.DefendAction.TargetAnimal) as AnimalState; if(target == null) return; if(WannaDefend(target)) { BeginDefending(target); } } catch(Exception exc) { WriteTrace(exc); } } protected virtual void AttackCompletedEvent(object sender, AttackCompletedEventArgs e) { try { AnimalState target = LookFor(e.AttackAction.TargetAnimal) as AnimalState; if(target == null) return; if(e.Killed && IsFood(target)) { if(!WithinEatingRange(target)) { BeginMoving(target); } else if(WannaEat(target)) { BeginEating(target); } } if(!e.Killed && IsBrunt(target)) { if(e.Escaped) { BeginChase(target); } else if(target.IsAlive && WannaAttack(target)) { BeginAttacking(target); } } } catch(Exception exc) { WriteTrace(exc); } } protected virtual void EatCompletedEvent(object sender, EatCompletedEventArgs e) { try { OrganismState target = LookFor(e.EatAction.TargetOrganism); if(target == null) return; if(WannaEat(target)) { BeginEating(target); } } catch(Exception exc) { WriteTrace(exc); } } protected abstract void IdleEvent(object sender, IdleEventArgs e); // //////////////////////////////////////////////////////////////////////////// protected virtual bool WannaReproduce() { return true; } protected virtual bool WannaEat(OrganismState target) { return target != null; } protected virtual bool WannaAttack(AnimalState target) { if(target == null) return false; return target.IsAlive; } protected virtual bool WannaDefend(AnimalState target) { if(target == null) return false; return target.IsAlive; } // //////////////////////////////////////////////////////////////////////////// protected abstract bool IsBrunt(OrganismState target); protected abstract bool IsFood(OrganismState target); protected abstract bool IsThreat(OrganismState target); // //////////////////////////////////////////////////////////////////////////// protected virtual byte[] DNA { get { return null; } } public override void SerializeAnimal(MemoryStream m) { } public override void DeserializeAnimal(MemoryStream m) { } // //////////////////////////////////////////////////////////////////////////// }