Skip to content

Commit edc9695

Browse files
committed
Merge remote-tracking branch 'darkademic/dev'
2 parents f132c92 + 2d854cb commit edc9695

File tree

1,052 files changed

+230071
-7547
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,052 files changed

+230071
-7547
lines changed

.github/workflows/packaging.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
5555
macos:
5656
name: macOS Disk Image
57-
runs-on: macos-13
57+
runs-on: macos-14
5858
needs: create-release
5959
steps:
6060
- name: Clone Repository

OpenRA.Mods.CA/AIUtils.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ public static IEnumerable<ProductionQueue> FindQueues(Player player, string cate
4141
.Select(a => a.Trait);
4242
}
4343

44+
public static ILookup<string, ProductionQueue> FindQueuesByCategory(Player player)
45+
{
46+
return player.World.ActorsWithTrait<ProductionQueue>()
47+
.Where(a => a.Actor.Owner == player && a.Trait.Enabled)
48+
.Select(a => a.Trait)
49+
.ToLookup(pq => pq.Info.Type);
50+
}
51+
4452
public static IEnumerable<Actor> GetActorsWithTrait<T>(World world)
4553
{
4654
return world.ActorsHavingTrait<T>();
@@ -57,6 +65,12 @@ public static int CountActorByCommonName(HashSet<string> commonNames, Player own
5765
commonNames.Contains(a.Info.Name));
5866
}
5967

68+
public static int CountActorByCommonName<TTraitInfo>(
69+
ActorIndex.OwnerAndNamesAndTrait<TTraitInfo> actorIndex) where TTraitInfo : ITraitInfoInterface
70+
{
71+
return actorIndex.Actors.Count(a => !a.IsDead);
72+
}
73+
6074
public static int CountBuildingByCommonName(HashSet<string> buildings, Player owner)
6175
{
6276
return GetActorsWithTrait<Building>(owner.World)

OpenRA.Mods.CA/Activities/Attach.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ void CompleteAttachment(Actor a)
121121
if (attachable == null)
122122
return;
123123

124-
var attached = attachableTo.Attach(attachable, true);
124+
var attached = attachableTo.Attach(a, attachable, true);
125125

126-
if (attached && attachable.Info.AttachSound != null)
126+
if (attached && attachable.Info.AttachSound != null && !a.World.FogObscures(a.CenterPosition))
127127
Game.Sound.Play(SoundType.World, attachable.Info.AttachSound, a.CenterPosition);
128128
}
129129

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#region Copyright & License Information
2+
/**
3+
* Copyright (c) The OpenRA Combined Arms Developers (see CREDITS).
4+
* This file is part of OpenRA Combined Arms, which is free software.
5+
* It is made available to you under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of the License,
7+
* or (at your option) any later version. For more information, see COPYING.
8+
*/
9+
#endregion
10+
11+
using System.Collections.Generic;
12+
using System.Linq;
13+
using OpenRA.Activities;
14+
using OpenRA.Mods.Common;
15+
using OpenRA.Mods.Common.Activities;
16+
using OpenRA.Mods.Common.Traits;
17+
using OpenRA.Traits;
18+
19+
namespace OpenRA.Mods.CA.Activities
20+
{
21+
public class HuntCA : Activity
22+
{
23+
readonly IEnumerable<Actor> targets;
24+
readonly IMove move;
25+
int ticks;
26+
int scanInterval;
27+
28+
public HuntCA(Actor self)
29+
{
30+
ticks = 0;
31+
scanInterval = self.World.SharedRandom.Next(20, 40);
32+
move = self.Trait<IMove>();
33+
var attack = self.Trait<AttackBase>();
34+
targets = self.World.ActorsHavingTrait<Huntable>().Where(
35+
a => self != a && !a.IsDead && a.IsInWorld && a.AppearsHostileTo(self)
36+
&& a.IsTargetableBy(self) && attack.HasAnyValidWeapons(Target.FromActor(a)));
37+
}
38+
39+
public override bool Tick(Actor self)
40+
{
41+
if (IsCanceling)
42+
return true;
43+
44+
ticks++;
45+
46+
var targetActor = ticks % scanInterval == 0 ? targets.ClosestToWithPathFrom(self) : null;
47+
48+
if (targetActor != null)
49+
{
50+
scanInterval = self.World.SharedRandom.Next(20, 40);
51+
52+
// We want to keep 2 cells of distance from the target to prevent the pathfinder from thinking the target position is blocked.
53+
QueueChild(new AttackMoveActivity(self, () => move.MoveWithinRange(Target.FromCell(self.World, targetActor.Location), WDist.FromCells(2))));
54+
QueueChild(new Wait(25));
55+
}
56+
else if (ticks > 375)
57+
scanInterval = self.World.SharedRandom.Next(250, 500);
58+
59+
return false;
60+
}
61+
}
62+
}

OpenRA.Mods.CA/Activities/InstantTransform.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ public InstantTransform(Actor self, string toActor)
3838
}
3939

4040
protected override void OnFirstRun(Actor self)
41-
{
42-
}
41+
{
42+
IsInterruptible = false;
43+
}
4344

4445
public override bool Tick(Actor self)
4546
{
@@ -57,9 +58,6 @@ public override bool Tick(Actor self)
5758
var makeAnimation = self.TraitOrDefault<WithMakeAnimation>();
5859
if (!SkipMakeAnims && makeAnimation != null)
5960
{
60-
// Once the make animation starts the activity must not be stopped anymore.
61-
IsInterruptible = false;
62-
6361
// Wait forever
6462
QueueChild(new WaitFor(() => false));
6563
makeAnimation.Reverse(self, () => DoTransform(self));

OpenRA.Mods.CA/Activities/Upgrade.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,19 @@ void UpgradeInProgressTick(Actor self)
143143
var expectedRemainingCost = upgradeTicksRemaining == 1 ? 0 : upgradeable.UpgradeInfo.Cost * upgradeTicksRemaining / Math.Max(1, upgradeable.UpgradeInfo.BuildDuration);
144144
var costThisFrame = upgradeCostRemaining - expectedRemainingCost;
145145

146-
/* Insufficient funds. */
147-
if (costThisFrame != 0 && !playerResources.TakeCash(costThisFrame, true))
148-
return;
146+
if (costThisFrame > 0)
147+
{
148+
/* Insufficient funds. */
149+
if (!playerResources.TakeCash(costThisFrame, true))
150+
return;
149151

150-
upgradeCostRemaining -= costThisFrame;
152+
upgradeCostRemaining -= costThisFrame;
153+
}
154+
else if (costThisFrame < 0)
155+
{
156+
playerResources.GiveCash(-costThisFrame);
157+
upgradeCostRemaining -= costThisFrame;
158+
}
151159

152160
foreach (var notifyResupply in notifyResupplies)
153161
notifyResupply.ResupplyTick(host.Actor, self, ResupplyType.Rearm);

OpenRA.Mods.CA/Effects/LinkedProducerSourceIndicator.cs renamed to OpenRA.Mods.CA/Effects/LinkedProducerIndicator.cs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,43 @@
1717

1818
namespace OpenRA.Mods.Common.Effects
1919
{
20-
public class LinkedProducerSourceIndicator : IEffect, IEffectAboveShroud, IEffectAnnotation
20+
public class LinkedProducerIndicator : IEffect, IEffectAboveShroud, IEffectAnnotation
2121
{
2222
readonly Actor building;
2323
readonly LinkedProducerTarget lpt;
24+
readonly LinkedProducerSource lps;
2425

2526
readonly List<WPos> targetLineNodes = new() { };
2627
List<WPos> cachedNodes;
2728

28-
public LinkedProducerSourceIndicator(Actor building, LinkedProducerTarget lpt)
29+
public LinkedProducerIndicator(Actor building, LinkedProducerTarget lpt)
2930
{
3031
this.building = building;
3132
this.lpt = lpt;
33+
this.lps = null;
34+
UpdateTargetLineNodes(building.World);
35+
}
36+
37+
public LinkedProducerIndicator(Actor building, LinkedProducerSource lps)
38+
{
39+
this.building = building;
40+
this.lpt = null;
41+
this.lps = lps;
3242
UpdateTargetLineNodes(building.World);
3343
}
3444

3545
void IEffect.Tick(World world)
3646
{
37-
if (cachedNodes == null || !cachedNodes.SequenceEqual(lpt.LinkNodes))
47+
if (lpt != null)
3848
{
49+
if (cachedNodes == null || !cachedNodes.SequenceEqual(lpt.LinkNodes))
50+
{
51+
UpdateTargetLineNodes(world);
52+
}
53+
}
54+
else if (lps != null)
55+
{
56+
// For sources, we need to update if the target changes
3957
UpdateTargetLineNodes(world);
4058
}
4159

@@ -45,15 +63,30 @@ void IEffect.Tick(World world)
4563

4664
void UpdateTargetLineNodes(World world)
4765
{
48-
cachedNodes = new List<WPos>(lpt.LinkNodes);
4966
targetLineNodes.Clear();
50-
foreach (var n in cachedNodes)
51-
targetLineNodes.Add(n);
5267

53-
if (targetLineNodes.Count == 0)
54-
return;
68+
if (lpt != null)
69+
{
70+
// Target mode: show connections to all sources
71+
cachedNodes = new List<WPos>(lpt.LinkNodes);
5572

56-
targetLineNodes.Insert(0, building.CenterPosition);
73+
// Add the building position first
74+
targetLineNodes.Add(building.CenterPosition);
75+
76+
// Add all source positions
77+
foreach (var n in cachedNodes)
78+
targetLineNodes.Add(n);
79+
}
80+
else if (lps != null)
81+
{
82+
// Source mode: show connection to target
83+
targetLineNodes.Add(building.CenterPosition);
84+
85+
if (lps.HasTarget)
86+
{
87+
targetLineNodes.Add(lps.Target.Actor.CenterPosition);
88+
}
89+
}
5790
}
5891

5992
IEnumerable<IRenderable> IEffect.Render(WorldRenderer wr) { return SpriteRenderable.None; }
@@ -66,9 +99,7 @@ IEnumerable<IRenderable> IEffectAboveShroud.RenderAboveShroud(WorldRenderer wr)
6699
if (!building.World.Selection.Contains(building))
67100
return SpriteRenderable.None;
68101

69-
var renderables = SpriteRenderable.None;
70-
71-
return renderables;
102+
return SpriteRenderable.None;
72103
}
73104

74105
IEnumerable<IRenderable> IEffectAnnotation.RenderAnnotation(WorldRenderer wr)
@@ -90,11 +121,15 @@ IEnumerable<IRenderable> IEffectAnnotation.RenderAnnotation(WorldRenderer wr)
90121

91122
IEnumerable<IRenderable> RenderInner()
92123
{
93-
var prev = targetLineNodes[0];
94-
foreach (var pos in targetLineNodes.Skip(1))
124+
if (targetLineNodes.Count < 2)
125+
yield break;
126+
127+
var targetPos = targetLineNodes[0]; // Building position
128+
129+
// Draw lines from target to each source
130+
foreach (var sourcePos in targetLineNodes.Skip(1))
95131
{
96-
var targetLine = new[] { prev, pos };
97-
prev = pos;
132+
var targetLine = new[] { targetPos, sourcePos };
98133
yield return new TargetLineRenderable(targetLine, Color.DarkGreen, 4, 7);
99134
yield return new TargetLineRenderable(targetLine, Color.Lime, 2, 5);
100135
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#region Copyright & License Information
2+
/*
3+
* Copyright (c) The OpenRA Combined Arms Developers (see CREDITS).
4+
* This file is part of OpenRA Combined Arms, which is free software.
5+
* It is made available to you under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of the License,
7+
* or (at your option) any later version. For more information, see COPYING.
8+
*/
9+
#endregion
10+
11+
using System.Collections.Generic;
12+
using OpenRA.Graphics;
13+
using OpenRA.Mods.Common.Graphics;
14+
using OpenRA.Primitives;
15+
16+
namespace OpenRA.Mods.CA.Graphics
17+
{
18+
/// <summary>
19+
/// Renders a capsule shape using the same pattern as Capsule HitShape:
20+
/// Two circles connected by parallel lines. Much simpler and crash-safe.
21+
/// </summary>
22+
public static class CapsuleAnnotationRenderable
23+
{
24+
public static IEnumerable<IRenderable> Create(WPos capsuleStart, WPos capsuleEnd, WDist radius, int width, Color color)
25+
{
26+
// Render two circles at the ends
27+
yield return new CircleAnnotationRenderable(capsuleStart, radius, width, color);
28+
yield return new CircleAnnotationRenderable(capsuleEnd, radius, width, color);
29+
30+
if (capsuleStart != capsuleEnd)
31+
{
32+
// Calculate perpendicular offset for the connecting lines (like Capsule HitShape does)
33+
var capsuleVec = capsuleEnd - capsuleStart;
34+
var perpVec = new WVec(-capsuleVec.Y, capsuleVec.X, 0);
35+
if (perpVec.Length > 0)
36+
{
37+
var radiusVec = perpVec * radius.Length / perpVec.Length;
38+
39+
var topStart = capsuleStart + radiusVec;
40+
var topEnd = capsuleEnd + radiusVec;
41+
var bottomStart = capsuleStart - radiusVec;
42+
var bottomEnd = capsuleEnd - radiusVec;
43+
44+
yield return new LineAnnotationRenderable(topStart, topEnd, width, color);
45+
yield return new LineAnnotationRenderable(bottomStart, bottomEnd, width, color);
46+
}
47+
}
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)