public List <CPos> FindUnitPath(CPos source, CPos target, Actor self, Actor ignoreActor) { var li = self.Info.TraitInfo <MobileInfo>().LocomotorInfo; if (!cached) { domainIndex = world.WorldActor.TraitOrDefault <DomainIndex>(); cached = true; } // If a water-land transition is required, bail early if (domainIndex != null && !domainIndex.IsPassable(source, target, li)) { return(EmptyPath); } var distance = source - target; if (source.Layer == target.Layer && distance.LengthSquared < 3 && li.CanMoveFreelyInto(world, self, target, null, CellConditions.All)) { return new List <CPos> { target } } ; List <CPos> pb; using (var fromSrc = PathSearch.FromPoint(world, li, self, target, source, true).WithIgnoredActor(ignoreActor)) using (var fromDest = PathSearch.FromPoint(world, li, self, source, target, true).WithIgnoredActor(ignoreActor).Reverse()) pb = FindBidiPath(fromSrc, fromDest); return(pb); }
public List <CPos> FindUnitPath(CPos source, CPos target, Actor self, Actor ignoreActor, BlockedByActor check) { // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. var locomotor = ((Mobile)self.OccupiesSpace).Locomotor; if (!cached) { domainIndex = world.WorldActor.TraitOrDefault <DomainIndex>(); cached = true; } // If a water-land transition is required, bail early if (domainIndex != null && !domainIndex.IsPassable(source, target, locomotor)) { return(EmptyPath); } var distance = source - target; var canMoveFreely = locomotor.CanMoveFreelyInto(self, target, check, null); if (distance.LengthSquared < 3 && !canMoveFreely) { return new List <CPos> { } } ; if (source.Layer == target.Layer && distance.LengthSquared < 3 && canMoveFreely) { return new List <CPos> { target } } ; List <CPos> pb; using (var fromSrc = PathSearch.FromPoint(world, locomotor, self, target, source, check).WithIgnoredActor(ignoreActor)) using (var fromDest = PathSearch.FromPoint(world, locomotor, self, source, target, check).WithIgnoredActor(ignoreActor).Reverse()) pb = FindBidiPath(fromSrc, fromDest); return(pb); }
public List <CPos> FindUnitPath(CPos source, CPos target, Actor self, Actor ignoreActor, BlockedByActor check) { var mobile = self.Trait <Mobile>(); var locomotor = mobile.Locomotor; if (!cached) { domainIndex = world.WorldActor.TraitOrDefault <DomainIndex>(); cached = true; } // If a water-land transition is required, bail early if (domainIndex != null && !domainIndex.IsPassable(source, target, locomotor.Info)) { return(EmptyPath); } var distance = source - target; var canMoveFreely = locomotor.CanMoveFreelyInto(self, target, check, null); if (distance.LengthSquared < 3 && !canMoveFreely) { return new List <CPos> { } } ; if (source.Layer == target.Layer && distance.LengthSquared < 3 && canMoveFreely) { return new List <CPos> { target } } ; List <CPos> pb; using (var fromSrc = PathSearch.FromPoint(world, locomotor, self, target, source, check).WithIgnoredActor(ignoreActor)) using (var fromDest = PathSearch.FromPoint(world, locomotor, self, source, target, check).WithIgnoredActor(ignoreActor).Reverse()) pb = FindBidiPath(fromSrc, fromDest); return(pb); }
Target FindNextResource(Actor actor, HarvesterTraitWrapper harv) { Func <CPos, bool> isValidResource = cell => domainIndex.IsPassable(actor.Location, cell, harv.Locomotor) && harv.Harvester.CanHarvestCell(actor, cell) && claimLayer.CanClaimCell(actor, cell); var path = pathfinder.FindPath( PathSearch.Search(world, harv.Locomotor, actor, BlockedByActor.Stationary, isValidResource) .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius) .Where(u => !u.IsDead && actor.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy) .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length))) .FromPoint(actor.Location)); if (path.Count == 0) { return(Target.Invalid); } return(Target.FromCell(world, path[0])); }
CPos FindNextResource(Actor actor, Harvester harv) { var locomotorInfo = actor.Info.TraitInfo <MobileInfo>().LocomotorInfo; Func <CPos, bool> isValidResource = cell => domainIndex.IsPassable(actor.Location, cell, locomotorInfo) && harv.CanHarvestCell(actor, cell) && claimLayer.CanClaimCell(actor, cell); var path = pathfinder.FindPath( PathSearch.Search(world, locomotorInfo, actor, true, isValidResource) .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius) .Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy) .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length))) .FromPoint(actor.Location)); if (path.Count == 0) { return(CPos.Zero); } return(path[0]); }
public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits) { if (IsTraitDisabled || IsTraitPaused) { return(false); } var aircraftInfo = producee.TraitInfoOrDefault <AircraftInfo>(); var mobileInfo = producee.TraitInfoOrDefault <MobileInfo>(); var destination = rp != null ? rp.Location : self.Location; var location = spawnLocation; if (!location.HasValue) { if (aircraftInfo != null) { location = self.World.Map.ChooseClosestEdgeCell(self.Location); } if (mobileInfo != null) { var locomotorInfo = mobileInfo.LocomotorInfo; location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location, c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destination, locomotorInfo)); } } // No suitable spawn location could be found, so production has failed. if (!location.HasValue) { return(false); } var pos = self.World.Map.CenterOfCell(location.Value); // If aircraft, spawn at cruise altitude if (aircraftInfo != null) { pos += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length); } var initialFacing = self.World.Map.FacingBetween(location.Value, destination, 0); self.World.AddFrameEndTask(w => { var td = new TypeDictionary(); foreach (var init in inits) { td.Add(init); } td.Add(new LocationInit(location.Value)); td.Add(new CenterPositionInit(pos)); td.Add(new FacingInit(initialFacing)); var newUnit = self.World.CreateActor(producee.Name, td); var move = newUnit.TraitOrDefault <IMove>(); if (move != null) { newUnit.QueueActivity(move.MoveTo(destination, 2)); } newUnit.SetTargetLine(Target.FromCell(self.World, destination), Color.Green, false); if (!self.IsDead) { foreach (var t in self.TraitsImplementing <INotifyProduction>()) { t.UnitProduced(self, newUnit, destination); } } var notifyOthers = self.World.ActorsWithTrait <INotifyOtherProduction>(); foreach (var notify in notifyOthers) { notify.Trait.UnitProducedByOther(notify.Actor, self, newUnit, productionType); } foreach (var t in newUnit.TraitsImplementing <INotifyBuildComplete>()) { t.BuildingComplete(newUnit); } }); return(true); }
public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits, int refundableValue) { if (IsTraitDisabled || IsTraitPaused) { return(false); } var aircraftInfo = producee.TraitInfoOrDefault <AircraftInfo>(); var mobileInfo = producee.TraitInfoOrDefault <MobileInfo>(); var destinations = rp != null && rp.Path.Count > 0 ? rp.Path : new List <CPos> { self.Location }; var location = spawnLocation; if (!location.HasValue) { if (aircraftInfo != null) { location = self.World.Map.ChooseClosestEdgeCell(self.Location); } if (mobileInfo != null) { var locomotor = self.World.WorldActor.TraitsImplementing <Locomotor>().First(l => l.Info.Name == mobileInfo.Locomotor); location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location, c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotor)); } } // No suitable spawn location could be found, so production has failed. if (!location.HasValue) { return(false); } var pos = self.World.Map.CenterOfCell(location.Value); // If aircraft, spawn at cruise altitude if (aircraftInfo != null) { pos += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length); } var initialFacing = self.World.Map.FacingBetween(location.Value, destinations[0], WAngle.Zero); self.World.AddFrameEndTask(w => { var td = new TypeDictionary(); foreach (var init in inits) { td.Add(init); } td.Add(new LocationInit(location.Value)); td.Add(new CenterPositionInit(pos)); td.Add(new FacingInit(initialFacing)); var newUnit = self.World.CreateActor(producee.Name, td); var move = newUnit.TraitOrDefault <IMove>(); if (move != null) { foreach (var cell in destinations) { newUnit.QueueActivity(move.MoveTo(cell, 2, evaluateNearestMovableCell: true)); } } if (!self.IsDead) { foreach (var t in self.TraitsImplementing <INotifyProduction>()) { t.UnitProduced(self, newUnit, destinations[0]); } } var notifyOthers = self.World.ActorsWithTrait <INotifyOtherProduction>(); foreach (var notify in notifyOthers) { notify.Trait.UnitProducedByOther(notify.Actor, self, newUnit, productionType, td); } }); return(true); }