void Init() { var visible = world.ActorsHavingTrait <StrategicVictoryConditions>().Any() && world.ActorsHavingTrait <StrategicPoint>().Any(); IsVisible = () => visible; initialised = true; }
internal Actor FindClosestEnemyBuilding(WPos pos) { var enemy = World.ActorsHavingTrait <Building>().Where(IsEnemyUnit).ClosestTo(pos); if (enemy != null) { return(enemy); } return(World.Actors.Where(IsEnemyUnit).ClosestTo(pos)); }
// TODO: Possibly give this a more generic name when terrain type is unhardcoded public bool EnoughWaterToBuildNaval() { var baseProviders = World.ActorsHavingTrait <BaseProvider>() .Where(a => a.Owner == Player && !a.Info.HasTraitInfo <MobileInfo>()); foreach (var b in baseProviders) { // TODO: Unhardcode terrain type // TODO2: Properly check building foundation rather than 3x3 area var playerWorld = Player.World; var countWaterCells = Map.FindTilesInCircle(b.Location, Info.MaxBaseRadius) .Where(c => playerWorld.Map.Contains(c) && playerWorld.Map.GetTerrainInfo(c).IsWater && Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c)) .All(a => playerWorld.Map.GetTerrainInfo(a).IsWater)) .Count(); if (countWaterCells > 0) { return(true); } } return(false); }
public int CountPotentialFreeBeds() { var housactors = world.ActorsHavingTrait <Building>() .Where(a => a.Owner == Player && hackyAIInfo.BuildingCommonNames.Houses.Contains(a.Info.Name)); var potentialpop = 0; if (housactors.Any() && housactors != null) { foreach (var hous in housactors) { var preserv = Player.World.Map.Rules.Actors[hous.Info.Name.Replace(".scaff", string.Empty).ToLower()]; if (preserv != null && preserv.HasTraitInfo <ProvidesLivingspaceInfo>()) { potentialpop += preserv.TraitInfo <ProvidesLivingspaceInfo>().Ammount; } if (hous != null && hous.Info.HasTraitInfo <ProvidesLivingspaceInfo>()) { potentialpop += hous.Info.TraitInfo <ProvidesLivingspaceInfo>().Ammount; } } } return(potentialpop); }
public IngameRadarDisplayLogic(Widget widget, World world) { var radarEnabled = false; var cachedRadarEnabled = false; var blockColor = Color.Transparent; var radar = widget.Get <RadarWidget>("RADAR_MINIMAP"); radar.IsEnabled = () => radarEnabled; var ticker = widget.Get <LogicTickerWidget>("RADAR_TICKER"); ticker.OnTick = () => { radarEnabled = world.ActorsHavingTrait <ProvidesRadar>(r => !r.IsTraitDisabled).Any(a => a.Owner == world.LocalPlayer); if (radarEnabled != cachedRadarEnabled) { //WarGame.Sound.playno } cachedRadarEnabled = radarEnabled; }; var block = widget.GetOrNull <ColorBlockWidget>("RADAR_FADETOBLACK"); if (block != null) { radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black); block.IsVisible = () => blockColor.A != 0; block.GetColor = () => blockColor; } }
protected override bool OnHotkeyActivated(KeyInput e) { var player = world.RenderPlayer ?? world.LocalPlayer; var harvesters = world.ActorsHavingTrait <Harvester>() .Where(a => a.IsInWorld && a.Owner == player) .ToList(); if (!harvesters.Any()) { return(true); } var next = harvesters .SkipWhile(b => !selection.Contains(b)) .Skip(1) .FirstOrDefault(); if (next == null) { next = harvesters.First(); } selection.Combine(world, new Actor[] { next }, false, true); viewport.Center(selection.Actors); return(true); }
public IngameRadarDisplayLogic(Widget widget, World world) { var radarEnabled = false; var cachedRadarEnabled = false; var blockColor = Color.Transparent; var radar = widget.Get<RadarWidget>("RADAR_MINIMAP"); radar.IsEnabled = () => radarEnabled; var devMode = world.LocalPlayer.PlayerActor.Trait<DeveloperMode>(); var ticker = widget.Get<LogicTickerWidget>("RADAR_TICKER"); ticker.OnTick = () => { radarEnabled = devMode.DisableShroud || world.ActorsHavingTrait<ProvidesRadar>(r => r.IsActive) .Any(a => a.Owner == world.LocalPlayer); if (radarEnabled != cachedRadarEnabled) Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", radarEnabled ? "RadarUp" : "RadarDown", null); cachedRadarEnabled = radarEnabled; }; var block = widget.GetOrNull<ColorBlockWidget>("RADAR_FADETOBLACK"); if (block != null) { radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black); block.IsVisible = () => blockColor.A != 0; block.GetColor = () => blockColor; } }
protected override bool OnHotkeyActivated(KeyInput e) { var player = world.RenderPlayer ?? world.LocalPlayer; var facilities = world.ActorsHavingTrait <Production>() .Where(a => a.Owner == player && a.OccupiesSpace != null && !a.Info.HasTraitInfo <BaseBuildingInfo>() && a.TraitsImplementing <Production>().Any(t => !t.IsTraitDisabled)) .OrderBy(f => f.TraitsImplementing <Production>().First(t => !t.IsTraitDisabled).Info.Produces.First()) .ToList(); if (!facilities.Any()) { return(true); } var next = facilities .SkipWhile(b => !selection.Contains(b)) .Skip(1) .FirstOrDefault(); if (next == null) { next = facilities.First(); } Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", clickSound, null); selection.Combine(world, new Actor[] { next }, false, true); viewport.Center(selection.Actors); return(true); }
/// <summary>Detail scans an area, evaluating positions.</summary> CPos?FindAttackLocationToSupportPower(SupportPowerInstance readyPower) { CPos?bestLocation = null; var bestAttractiveness = 0; var powerDecision = powerDecisions[readyPower.Info.OrderName]; if (powerDecision == null) { AIUtils.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName); return(null); } var availableTargets = world.ActorsHavingTrait <IOccupySpace>().Where(x => x.IsInWorld && !x.IsDead && (powerDecision.IgnoreVisibility || x.CanBeViewedByPlayer(player)) && powerDecision.Against.HasRelationship(player.RelationshipWith(x.Owner)) && powerDecision.Types.Overlaps(x.GetEnabledTargetTypes())); foreach (var a in availableTargets) { var pos = a.CenterPosition; var consideredAttractiveness = 0; consideredAttractiveness += powerDecision.GetAttractiveness(pos, player); if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness) { continue; } bestAttractiveness = consideredAttractiveness; bestLocation = world.Map.CellContaining(pos); } return(bestLocation); }
void IBotTick.BotTick(IBot bot) { if (world.WorldTick % tickEvery != 0) { return; } var miners = world.ActorsHavingTrait <Transforms>() .Where(a => a.Owner == player && a.IsIdle && Info.MinerTypes.Contains(a.Info.Name)); foreach (var miner in miners) { var closestMine = ClosestHarvestablePos(miner); if (!closestMine.HasValue) { continue; } var claimedOk = claimLayer.TryClaimCell(miner, closestMine.Value); if (!claimedOk) { continue; } bot.QueueOrder(new Order("Move", miner, Target.FromCell(world, closestMine.Value), true)); bot.QueueOrder(new Order("DeployTransform", miner, true)); } }
public IngameRadarDisplayLogic(Widget widget, World world) { var radarEnabled = false; var cachedRadarEnabled = false; var blockColor = Color.Transparent; var radar = widget.Get <RadarWidget>("RADAR_MINIMAP"); radar.IsEnabled = () => radarEnabled; var devMode = world.LocalPlayer.PlayerActor.Trait <DeveloperMode>(); var ticker = widget.Get <LogicTickerWidget>("RADAR_TICKER"); ticker.OnTick = () => { radarEnabled = devMode.DisableShroud || world.ActorsHavingTrait <ProvidesRadar>(r => !r.IsTraitDisabled) .Any(a => a.Owner == world.LocalPlayer); if (radarEnabled != cachedRadarEnabled) { Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", radarEnabled ? "RadarUp" : "RadarDown", null); } cachedRadarEnabled = radarEnabled; }; var block = widget.GetOrNull <ColorBlockWidget>("RADAR_FADETOBLACK"); if (block != null) { radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black); block.IsVisible = () => blockColor.A != 0; block.GetColor = () => blockColor; } }
void ITick.Tick(Actor self) { if (IsTraitDisabled) { return; } if (resLayer == null || resLayer.IsResourceLayerEmpty) { return; } if (--scanForIdleHarvestersTicks > 0) { return; } harvesters.RemoveAll(unitCannotBeOrdered); scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval; // Find new harvesters // TODO: Look for a more performance-friendly way to update this list var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.Contains(a)); foreach (var a in newHarvesters) { harvesters.Add(a); } // Find idle harvesters and give them orders: foreach (var harvester in harvesters) { var harv = harvester.Trait <Harvester>(); if (!harv.IsEmpty) { continue; } if (!harvester.IsIdle) { var act = harvester.CurrentActivity; if (!harv.LastSearchFailed || act.NextActivity == null || act.NextActivity.GetType() != typeof(FindResources)) { continue; } } var para = harvester.TraitOrDefault <Parachutable>(); if (para != null && para.IsInAir) { continue; } // Tell the idle harvester to quit slacking: var newSafeResourcePatch = FindNextResource(harvester, harv); AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(harvester, newSafeResourcePatch)); botOrderManager.QueueOrder(new Order("Harvest", harvester, Target.FromCell(world, newSafeResourcePatch), false)); } }
public CPos GetRandomBaseCenter() { var randomBaseBuilding = World.ActorsHavingTrait <BaseBuilding>() .Where(a => a.Owner == Player && !a.Info.HasTraitInfo <MobileInfo>()) .RandomOrDefault(Random); return(randomBaseBuilding != null ? randomBaseBuilding.Location : initialBaseCenter); }
public override void Tick(World world) { this.researchActors = world.ActorsHavingTrait <Researches>().Where(e => e.Owner == world.LocalPlayer); if (!this.researchActors.Any()) { world.CancelInputMode(); } }
public override void Tick(World world) { technicians = world.ActorsHavingTrait <Technician>().Where(e => e.Owner == world.LocalPlayer && e.IsIdle); if (!technicians.Any()) { world.CancelInputMode(); } }
void DeployMcvs(IBot bot, bool chooseLocation) { var newMCVs = world.ActorsHavingTrait <Transforms>() .Where(a => a.Owner == player && a.IsIdle && Info.McvTypes.Contains(a.Info.Name)); foreach (var mcv in newMCVs) { DeployMcv(bot, mcv, chooseLocation); } }
public static bool IsAreaAvailable <T>(World world, Player player, Map map, int radius, HashSet <string> terrainTypes) { var cells = world.ActorsHavingTrait <T>().Where(a => a.Owner == player); // TODO: Properly check building foundation rather than 3x3 area. return(cells.Select(a => map.FindTilesInCircle(a.Location, radius) .Count(c => map.Contains(c) && terrainTypes.Contains(map.GetTerrainInfo(c).Type) && Util.AdjacentCells(world, Target.FromCell(world, c)) .All(ac => terrainTypes.Contains(map.GetTerrainInfo(ac).Type)))) .Any(availableCells => availableCells > 0)); }
protected override bool OnHotkeyActivated(KeyInput e) { var player = world.RenderPlayer ?? world.LocalPlayer; var bases = world.ActorsHavingTrait <BaseBuilding>() .Where(a => a.Owner == player) .ToList(); // If no BaseBuilding exist pick the first selectable Building. if (!bases.Any()) { var building = world.ActorsHavingTrait <Building>() .FirstOrDefault(a => a.Owner == player && a.Info.HasTraitInfo <SelectableInfo>()); // No buildings left if (building == null) { return(true); } selection.Combine(world, new Actor[] { building }, false, true); viewport.Center(selection.Actors); return(true); } var next = bases .SkipWhile(b => !selection.Contains(b)) .Skip(1) .FirstOrDefault(); if (next == null) { next = bases.First(); } selection.Combine(world, new Actor[] { next }, false, true); viewport.Center(selection.Actors); return(true); }
public static IEnumerable <CPos> GetLineBuildCells(World world, CPos location, string name, BuildingInfo bi) { var lbi = world.Map.Rules.Actors[name].TraitInfo <LineBuildInfo>(); var topLeft = location; // 1x1 assumption! if (world.IsCellBuildable(topLeft, bi)) { yield return(topLeft); } // Start at place location, search outwards // TODO: First make it work, then make it nice var vecs = new[] { new CVec(1, 0), new CVec(0, 1), new CVec(-1, 0), new CVec(0, -1) }; int[] dirs = { 0, 0, 0, 0 }; for (var d = 0; d < 4; d++) { for (var i = 1; i < lbi.Range; i++) { if (dirs[d] != 0) { continue; } var cell = topLeft + i * vecs[d]; if (world.IsCellBuildable(cell, bi)) { continue; // Cell is empty; continue search } // Cell contains an actor. Is it the type we want? if (world.ActorsHavingTrait <LineBuildNode>() .Any(a => a.Location == cell && a.Info.TraitInfo <LineBuildNodeInfo>().Types.Overlaps(lbi.NodeTypes))) { dirs[d] = i; // Cell contains actor of correct type } else { dirs[d] = -1; // Cell is blocked by another actor type } } // Place intermediate-line sections if (dirs[d] > 0) { for (var i = 1; i < dirs[d]; i++) { yield return(topLeft + i * vecs[d]); } } } }
void IBotTick.BotTick(IBot bot) { if (!initialized) { var baseBuildings = world.ActorsHavingTrait <BaseBuilding>().Where(a => a.Owner == player); foreach (var baseBuilding in baseBuildings) { SetCenter(baseBuilding.Location); } initialized = true; } }
bool CycleBases() { var player = world.RenderPlayer ?? world.LocalPlayer; var bases = world.ActorsHavingTrait <BaseBuilding>() .Where(a => a.Owner == player) .ToList(); // If no BaseBuilding exist pick the first selectable Building. if (!bases.Any()) { var building = world.ActorsHavingTrait <Building>() .FirstOrDefault(a => a.Owner == player && a.Info.HasTraitInfo <SelectableInfo>()); // No buildings left if (building == null) { return(true); } world.Selection.Combine(world, new Actor[] { building }, false, true); return(ToSelection()); } var next = bases .SkipWhile(b => !world.Selection.Contains(b)) .Skip(1) .FirstOrDefault(); if (next == null) { next = bases.First(); } world.Selection.Combine(world, new Actor[] { next }, false, true); return(ToSelection()); }
void FindNewUnits(IBot bot) { var newUnits = World.ActorsHavingTrait <IPositionable>() .Where(a => a.Owner == Player && !Info.ExcludeFromSquadsTypes.Contains(a.Info.Name) && !activeUnits.Contains(a)); foreach (var a in newUnits) { if (a.Info.HasTraitInfo <AircraftInfo>() && a.Info.HasTraitInfo <AttackBaseInfo>()) { var air = GetSquadOfType(SquadType.Air); if (air == null) { air = RegisterNewSquad(bot, SquadType.Air); } air.Units.Add(a); } else if (Info.NavalUnitsTypes.Contains(a.Info.Name)) { var ships = GetSquadOfType(SquadType.Naval); if (ships == null) { ships = RegisterNewSquad(bot, SquadType.Naval); } ships.Units.Add(a); } else { unitsHangingAroundTheBase.Add(a); } activeUnits.Add(a); } // Notifying here rather than inside the loop, should be fine and saves a bunch of notification calls foreach (var n in notifyIdleBaseUnits) { n.UpdatedIdleBaseUnits(unitsHangingAroundTheBase); } }
void DeployMcvs(IBot bot, bool chooseLocation) { activeMCVs.RemoveAll(unitCannotBeOrdered); var newMCVs = world.ActorsHavingTrait <Transforms>() .Where(a => a.Owner == player && a.IsIdle && Info.McvTypes.Contains(a.Info.Name) && !activeMCVs.Contains(a)); foreach (var a in newMCVs) { activeMCVs.Add(a); } foreach (var mcv in activeMCVs) { DeployMcv(bot, mcv, chooseLocation); } }
protected void OrderHarvesters(IBot bot) { var toRemove = harvesters.Keys.Where(unitCannotBeOrdered).ToList(); foreach (var a in toRemove) { harvesters.Remove(a); } // Find new harvesters // TODO: Look for a more performance-friendly way to update this list var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.ContainsKey(a)); foreach (var a in newHarvesters) { harvesters[a] = new HarvesterTraitWrapper(a); } // Find idle harvesters and give them orders: foreach (var h in harvesters) { if (!h.Key.IsIdle) { var act = h.Key.CurrentActivity as FindAndDeliverResources; // Ignore this actor if FindAndDeliverResources is working fine or it is performing a different activity if (act == null || !act.LastSearchFailed) { continue; } } // Tell the idle harvester to quit slacking: var newSafeResourcePatch = FindNextResource(h.Key, h.Value); AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(h.Key, newSafeResourcePatch)); bot.QueueOrder(new Order("Harvest", h.Key, newSafeResourcePatch, false)); } }
public bool EnoughWaterToBuildNaval() { var baseProviders = World.ActorsHavingTrait <BaseProvider>() .Where(a => a.Owner == Player); foreach (var b in baseProviders) { var playerWorld = Player.World; var countWaterCells = Map.FindTilesInCircle(b.Location, Info.MaxBaseRadius) .Where(c => playerWorld.Map.Contains(c) && Info.WaterTerrainTypes.Contains(playerWorld.Map.GetTerrainInfo(c).Type) && Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c)) .All(a => Info.WaterTerrainTypes.Contains(playerWorld.Map.GetTerrainInfo(a).Type))).Count(); if (countWaterCells > 0) { return(true); } } return(false); }
public static IEnumerable <Actor> GetActorsWithTrait <T>(World world) { return(world.ActorsHavingTrait <T>()); }
public ObserverStatsLogic(World world, ModData modData, WorldRenderer worldRenderer, Widget widget, Action onExit, ObserverStatsPanel activePanel, Dictionary <string, MiniYaml> logicArgs) { this.world = world; this.worldRenderer = worldRenderer; MiniYaml yaml; string[] keyNames = Enum.GetNames(typeof(ObserverStatsPanel)); var statsHotkeys = new HotkeyReference[keyNames.Length]; for (var i = 0; i < keyNames.Length; i++) { statsHotkeys[i] = logicArgs.TryGetValue("Statistics" + keyNames[i] + "Key", out yaml) ? modData.Hotkeys[yaml.Value] : new HotkeyReference(); } players = world.Players.Where(p => !p.NonCombatant); basicStatsHeaders = widget.Get <ContainerWidget>("BASIC_STATS_HEADERS"); economyStatsHeaders = widget.Get <ContainerWidget>("ECONOMY_STATS_HEADERS"); productionStatsHeaders = widget.Get <ContainerWidget>("PRODUCTION_STATS_HEADERS"); combatStatsHeaders = widget.Get <ContainerWidget>("COMBAT_STATS_HEADERS"); earnedThisMinuteGraphHeaders = widget.Get <ContainerWidget>("EARNED_THIS_MIN_GRAPH_HEADERS"); playerStatsPanel = widget.Get <ScrollPanelWidget>("PLAYER_STATS_PANEL"); playerStatsPanel.Layout = new GridLayout(playerStatsPanel); basicPlayerTemplate = playerStatsPanel.Get <ScrollItemWidget>("BASIC_PLAYER_TEMPLATE"); economyPlayerTemplate = playerStatsPanel.Get <ScrollItemWidget>("ECONOMY_PLAYER_TEMPLATE"); productionPlayerTemplate = playerStatsPanel.Get <ScrollItemWidget>("PRODUCTION_PLAYER_TEMPLATE"); combatPlayerTemplate = playerStatsPanel.Get <ScrollItemWidget>("COMBAT_PLAYER_TEMPLATE"); earnedThisMinuteGraphTemplate = playerStatsPanel.Get <ContainerWidget>("EARNED_THIS_MIN_GRAPH_TEMPLATE"); teamTemplate = playerStatsPanel.Get <ScrollItemWidget>("TEAM_TEMPLATE"); var statsDropDown = widget.Get <DropDownButtonWidget>("STATS_DROPDOWN"); Func <string, ContainerWidget, Action, StatsDropDownOption> createStatsOption = (title, headers, a) => { return(new StatsDropDownOption { Title = title, IsSelected = () => headers.Visible, OnClick = () => { ClearStats(); statsDropDown.GetText = () => title; a(); } }); }; var statsDropDownOptions = new StatsDropDownOption[] { createStatsOption("Basic", basicStatsHeaders, () => DisplayStats(BasicStats)), createStatsOption("Economy", economyStatsHeaders, () => DisplayStats(EconomyStats)), createStatsOption("Production", productionStatsHeaders, () => DisplayStats(ProductionStats)), createStatsOption("Combat", combatStatsHeaders, () => DisplayStats(CombatStats)), createStatsOption("Earnings (graph)", earnedThisMinuteGraphHeaders, () => EarnedThisMinuteGraph()) }; Func <StatsDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick); item.Get <LabelWidget>("LABEL").GetText = () => option.Title; return(item); }; statsDropDown.OnMouseDown = _ => statsDropDown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 150, statsDropDownOptions, setupItem); statsDropDownOptions[(int)activePanel].OnClick(); var close = widget.GetOrNull <ButtonWidget>("CLOSE"); if (close != null) { close.OnClick = () => { Ui.CloseWindow(); Ui.Root.RemoveChild(widget); onExit(); } } ; var keyListener = statsDropDown.Get <LogicKeyListenerWidget>("STATS_DROPDOWN_KEYHANDLER"); keyListener.AddHandler(e => { if (e.Event == KeyInputEvent.Down && !e.IsRepeat) { for (var i = 0; i < statsHotkeys.Length; i++) { if (statsHotkeys[i].IsActivatedBy(e)) { Game.Sound.PlayNotification(modData.DefaultRules, null, "Sounds", "ClickSound", null); statsDropDownOptions[i].OnClick(); return(true); } } } return(false); }); } void ClearStats() { playerStatsPanel.Children.Clear(); basicStatsHeaders.Visible = false; economyStatsHeaders.Visible = false; productionStatsHeaders.Visible = false; combatStatsHeaders.Visible = false; earnedThisMinuteGraphHeaders.Visible = false; } void EarnedThisMinuteGraph() { earnedThisMinuteGraphHeaders.Visible = true; var template = earnedThisMinuteGraphTemplate.Clone(); var graph = template.Get <LineGraphWidget>("EARNED_THIS_MIN_GRAPH"); graph.GetSeries = () => players.Select(p => new LineGraphSeries( p.PlayerName, p.Color.RGB, (p.PlayerActor.TraitOrDefault <PlayerStatistics>() ?? new PlayerStatistics(p.PlayerActor)).EarnedSamples.Select(s => (float)s))); playerStatsPanel.AddChild(template); playerStatsPanel.ScrollToTop(); } void DisplayStats(Func <Player, ScrollItemWidget> createItem) { var teams = players.GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.ClientIndex) ?? new Session.Client()).Team).OrderBy(g => g.Key); foreach (var t in teams) { var team = t; var tt = ScrollItemWidget.Setup(teamTemplate, () => false, () => { }); tt.IgnoreMouseOver = true; tt.Get <LabelWidget>("TEAM").GetText = () => team.Key == 0 ? "No Team" : "Team " + team.Key; playerStatsPanel.AddChild(tt); foreach (var p in team) { var player = p; playerStatsPanel.AddChild(createItem(player)); } } } ScrollItemWidget CombatStats(Player player) { combatStatsHeaders.Visible = true; var template = SetupPlayerScrollItemWidget(combatPlayerTemplate, player); LobbyUtils.AddPlayerFlagAndName(template, player); var stats = player.PlayerActor.TraitOrDefault <PlayerStatistics>(); if (stats == null) { return(template); } template.Get <LabelWidget>("ASSETS_DESTROYED").GetText = () => "$" + stats.KillsCost; template.Get <LabelWidget>("ASSETS_LOST").GetText = () => "$" + stats.DeathsCost; template.Get <LabelWidget>("UNITS_KILLED").GetText = () => stats.UnitsKilled.ToString(); template.Get <LabelWidget>("UNITS_DEAD").GetText = () => stats.UnitsDead.ToString(); template.Get <LabelWidget>("BUILDINGS_KILLED").GetText = () => stats.BuildingsKilled.ToString(); template.Get <LabelWidget>("BUILDINGS_DEAD").GetText = () => stats.BuildingsDead.ToString(); return(template); } ScrollItemWidget ProductionStats(Player player) { productionStatsHeaders.Visible = true; var template = SetupPlayerScrollItemWidget(productionPlayerTemplate, player); LobbyUtils.AddPlayerFlagAndName(template, player); template.Get <ObserverProductionIconsWidget>("PRODUCTION_ICONS").GetPlayer = () => player; template.Get <ObserverSupportPowerIconsWidget>("SUPPORT_POWER_ICONS").GetPlayer = () => player; template.IgnoreChildMouseOver = false; return(template); } ScrollItemWidget EconomyStats(Player player) { economyStatsHeaders.Visible = true; var template = SetupPlayerScrollItemWidget(economyPlayerTemplate, player); LobbyUtils.AddPlayerFlagAndName(template, player); var res = player.PlayerActor.Trait <PlayerResources>(); var stats = player.PlayerActor.TraitOrDefault <PlayerStatistics>(); if (stats == null) { return(template); } template.Get <LabelWidget>("CASH").GetText = () => "$" + (res.Cash + res.Resources); template.Get <LabelWidget>("EARNED_MIN").GetText = () => AverageEarnedPerMinute(res.Earned); template.Get <LabelWidget>("EARNED_THIS_MIN").GetText = () => "$" + stats.EarnedThisMinute; template.Get <LabelWidget>("EARNED").GetText = () => "$" + res.Earned; template.Get <LabelWidget>("SPENT").GetText = () => "$" + res.Spent; var assets = template.Get <LabelWidget>("ASSETS"); assets.GetText = () => "$" + world.ActorsHavingTrait <Valued>() .Where(a => a.Owner == player && !a.IsDead) .Sum(a => a.Info.TraitInfos <ValuedInfo>().First().Cost); var harvesters = template.Get <LabelWidget>("HARVESTERS"); harvesters.GetText = () => world.ActorsHavingTrait <Harvester>().Count(a => a.Owner == player && !a.IsDead).ToString(); return(template); } ScrollItemWidget BasicStats(Player player) { basicStatsHeaders.Visible = true; var template = SetupPlayerScrollItemWidget(basicPlayerTemplate, player); LobbyUtils.AddPlayerFlagAndName(template, player); var res = player.PlayerActor.Trait <PlayerResources>(); template.Get <LabelWidget>("CASH").GetText = () => "$" + (res.Cash + res.Resources); template.Get <LabelWidget>("EARNED_MIN").GetText = () => AverageEarnedPerMinute(res.Earned); var powerRes = player.PlayerActor.Trait <PowerManager>(); var power = template.Get <LabelWidget>("POWER"); power.GetText = () => powerRes.PowerDrained + "/" + powerRes.PowerProvided; power.GetColor = () => GetPowerColor(powerRes.PowerState); var stats = player.PlayerActor.TraitOrDefault <PlayerStatistics>(); if (stats == null) { return(template); } template.Get <LabelWidget>("KILLS").GetText = () => (stats.UnitsKilled + stats.BuildingsKilled).ToString(); template.Get <LabelWidget>("DEATHS").GetText = () => (stats.UnitsDead + stats.BuildingsDead).ToString(); template.Get <LabelWidget>("ASSETS_DESTROYED").GetText = () => "$" + stats.KillsCost; template.Get <LabelWidget>("ASSETS_LOST").GetText = () => "$" + stats.DeathsCost; template.Get <LabelWidget>("EXPERIENCE").GetText = () => stats.Experience.ToString(); template.Get <LabelWidget>("ACTIONS_MIN").GetText = () => AverageOrdersPerMinute(stats.OrderCount); return(template); } ScrollItemWidget SetupPlayerScrollItemWidget(ScrollItemWidget template, Player player) { return(ScrollItemWidget.Setup(template, () => false, () => { var playerBase = world.ActorsHavingTrait <BaseBuilding>().FirstOrDefault(a => !a.IsDead && a.Owner == player); if (playerBase != null) { worldRenderer.Viewport.Center(playerBase.CenterPosition); } })); }
void IBotTick.BotTick(IBot bot) { if (resourceLayer == null || resourceLayer.IsEmpty) { return; } if (--scanForIdleHarvestersTicks > 0) { return; } var toRemove = harvesters.Keys.Where(unitCannotBeOrdered).ToList(); foreach (var a in toRemove) { harvesters.Remove(a); } scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval; // Find new harvesters // TODO: Look for a more performance-friendly way to update this list var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.ContainsKey(a)); foreach (var a in newHarvesters) { harvesters[a] = new HarvesterTraitWrapper(a); } // Find idle harvesters and give them orders: foreach (var h in harvesters) { if (!h.Key.IsIdle) { // Ignore this actor if FindAndDeliverResources is working fine or it is performing a different activity if (!(h.Key.CurrentActivity is FindAndDeliverResources act) || !act.LastSearchFailed) { continue; } } if (h.Value.Parachutable != null && h.Value.Parachutable.IsInAir) { continue; } // Tell the idle harvester to quit slacking: var newSafeResourcePatch = FindNextResource(h.Key, h.Value); AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(h.Key, newSafeResourcePatch)); bot.QueueOrder(new Order("Harvest", h.Key, newSafeResourcePatch, false)); } // Less harvesters than refineries - build a new harvester var unitBuilder = requestUnitProduction.FirstOrDefault(Exts.IsTraitEnabled); if (unitBuilder != null && Info.HarvesterTypes.Any()) { var harvInfo = AIUtils.GetInfoByCommonName(Info.HarvesterTypes, player); var harvCountTooLow = AIUtils.CountActorByCommonName(Info.HarvesterTypes, player) < AIUtils.CountBuildingByCommonName(Info.RefineryTypes, player); if (harvCountTooLow && unitBuilder.RequestedProductionCount(bot, harvInfo.Name) == 0) { unitBuilder.RequestUnitProduction(bot, harvInfo.Name); } } }
void QueueCaptureOrders(IBot bot) { if (!Info.CapturingActorTypes.Any() || player.WinState != WinState.Undefined) { return; } activeCapturers.RemoveAll(unitCannotBeOrderedOrIsIdle); var newUnits = world.ActorsHavingTrait <IPositionable>() .Where(a => a.Owner == player && !activeCapturers.Contains(a)); var capturers = newUnits .Where(a => a.IsIdle && Info.CapturingActorTypes.Contains(a.Info.Name) && a.Info.HasTraitInfo <CapturesInfo>()) .Select(a => new TraitPair <CaptureManager>(a, a.TraitOrDefault <CaptureManager>())) .Where(tp => tp.Trait != null) .ToArray(); if (capturers.Length == 0) { return; } var randPlayer = world.Players.Where(p => !p.Spectating && Info.CapturableStances.HasStance(player.Stances[p])).Random(world.LocalRandom); var targetOptions = Info.CheckCaptureTargetsForVisibility ? GetVisibleActorsBelongingToPlayer(randPlayer) : GetActorsThatCanBeOrderedByPlayer(randPlayer); var capturableTargetOptions = targetOptions .Where(target => { var captureManager = target.TraitOrDefault <CaptureManager>(); if (captureManager == null) { return(false); } return(capturers.Any(tp => captureManager.CanBeTargetedBy(target, tp.Actor, tp.Trait))); }) .OrderByDescending(target => target.GetSellValue()) .Take(maximumCaptureTargetOptions); if (Info.CapturableActorTypes.Any()) { capturableTargetOptions = capturableTargetOptions.Where(target => Info.CapturableActorTypes.Contains(target.Info.Name.ToLowerInvariant())); } if (!capturableTargetOptions.Any()) { return; } var failedAttempts = captureHistory.Where(a => a.Key.IsDead).Select(a => a.Value); foreach (var capturer in capturers) { var targetActor = capturableTargetOptions.MinByOrDefault(t => (t.CenterPosition - capturer.Actor.CenterPosition).LengthSquared); if (targetActor == null) { continue; } if (failedAttempts.Any(f => f.Actor == targetActor)) { AIUtils.BotDebug("AI ({0}): skipping capture of {1} as there was a previously failed attempt.", player.ClientIndex, targetActor); continue; } var target = Target.FromActor(targetActor); bot.QueueOrder(new Order("CaptureActor", capturer.Actor, target, true)); AIUtils.BotDebug("AI ({0}): Ordered {1} to capture {2}", player.ClientIndex, capturer.Actor, targetActor); activeCapturers.Add(capturer.Actor); if (!captureHistory.ContainsKey(capturer.Actor)) { captureHistory.Add(capturer.Actor, target); } } }
public void Tick(IBot bot) { // If failed to place something N consecutive times, wait M ticks until resuming building production if (failCount >= baseBuilder.Info.MaximumFailedPlacementAttempts && --failRetryTicks <= 0) { var currentBuildings = world.ActorsHavingTrait <Building>().Count(a => a.Owner == player); var baseProviders = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player); // Only bother resetting failCount if either a) the number of buildings has decreased since last failure M ticks ago, // or b) number of BaseProviders (construction yard or similar) has increased since then. // Otherwise reset failRetryTicks instead to wait again. if (currentBuildings < cachedBuildings || baseProviders > cachedBases) { failCount = 0; } else { failRetryTicks = baseBuilder.Info.StructureProductionResumeDelay; } } if (waterState == WaterCheck.NotChecked) { if (AIUtils.IsAreaAvailable <BaseProvider>(world, player, world.Map, baseBuilder.Info.MaxBaseRadius, baseBuilder.Info.WaterTerrainTypes)) { waterState = WaterCheck.EnoughWater; } else { waterState = WaterCheck.NotEnoughWater; checkForBasesTicks = baseBuilder.Info.CheckForNewBasesDelay; } } if (waterState == WaterCheck.NotEnoughWater && --checkForBasesTicks <= 0) { var currentBases = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player); if (currentBases > cachedBases) { cachedBases = currentBases; waterState = WaterCheck.NotChecked; } } // Only update once per second or so if (--waitTicks > 0) { return; } playerBuildings = world.ActorsHavingTrait <Building>().Where(a => a.Owner == player).ToArray(); var excessPowerBonus = baseBuilder.Info.ExcessPowerIncrement * (playerBuildings.Count() / baseBuilder.Info.ExcessPowerIncreaseThreshold.Clamp(1, int.MaxValue)); minimumExcessPower = (baseBuilder.Info.MinimumExcessPower + excessPowerBonus).Clamp(baseBuilder.Info.MinimumExcessPower, baseBuilder.Info.MaximumExcessPower); var active = false; foreach (var queue in AIUtils.FindQueues(player, category)) { if (TickQueue(bot, queue)) { active = true; } } // Add a random factor so not every AI produces at the same tick early in the game. // Minimum should not be negative as delays in HackyAI could be zero. var randomFactor = world.LocalRandom.Next(0, baseBuilder.Info.StructureProductionRandomBonusDelay); // Needs to be at least 4 * OrderLatency because otherwise the AI frequently duplicates build orders (i.e. makes the same build decision twice) waitTicks = active ? 4 * world.OrderLatency + baseBuilder.Info.StructureProductionActiveDelay + randomFactor : baseBuilder.Info.StructureProductionInactiveDelay + randomFactor; }
IEnumerable <Actor> GetActorsWithTrait <T>() { return(World.ActorsHavingTrait <T>()); }