Compare commits
72 Commits
log_chat_s
...
log_chat_s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50277c59d7 | ||
|
|
2a13752203 | ||
|
|
8ce3ea5f2c | ||
|
|
b4f3d8ae02 | ||
|
|
d70c30763b | ||
|
|
27297a1ba9 | ||
|
|
2890ccf2b1 | ||
|
|
f9f1889112 | ||
|
|
d9c5821329 | ||
|
|
7fc415de19 | ||
|
|
ec01f63317 | ||
|
|
c9ac702217 | ||
|
|
1913c608a6 | ||
|
|
94ac6cc400 | ||
|
|
97d9520bf0 | ||
|
|
e7300cc430 | ||
|
|
677d7e47a4 | ||
|
|
5f287d38ab | ||
|
|
3a00d5a679 | ||
|
|
d5d43ee97c | ||
|
|
fd12ef1535 | ||
|
|
de8317d9b8 | ||
|
|
b953f4a40d | ||
|
|
b565f0903a | ||
|
|
da71a8271d | ||
|
|
54558169e1 | ||
|
|
bcb953309a | ||
|
|
a371826613 | ||
|
|
82ee3d779c | ||
|
|
4ea0e70589 | ||
|
|
3f4e4db836 | ||
|
|
85020bc2af | ||
|
|
70bb01a2c7 | ||
|
|
38d4719073 | ||
|
|
aebb97967d | ||
|
|
97f81d0aa4 | ||
|
|
2030c17a8b | ||
|
|
b6dcd8d9af | ||
|
|
9a78f22e86 | ||
|
|
19ca3d610b | ||
|
|
dd74d3572a | ||
|
|
ad7e5d62cd | ||
|
|
ece7547695 | ||
|
|
944bc7667a | ||
|
|
0ac28e1f5f | ||
|
|
ca3a57289e | ||
|
|
a4641be7e7 | ||
|
|
0651308210 | ||
|
|
cac6aebb6c | ||
|
|
0baddf46e2 | ||
|
|
e0d893b736 | ||
|
|
2ccfa425b2 | ||
|
|
52102da839 | ||
|
|
fc08f18663 | ||
|
|
cc064d0dad | ||
|
|
8b997a5656 | ||
|
|
7d8fff535d | ||
|
|
0855a9e5bf | ||
|
|
3fa2b9fe79 | ||
|
|
c561509c82 | ||
|
|
0566b6f787 | ||
|
|
e2821933a4 | ||
|
|
34c29f872a | ||
|
|
2192a6b4f9 | ||
|
|
68ad9163ff | ||
|
|
5f6eecc1f6 | ||
|
|
5edca87622 | ||
|
|
fa01c24f23 | ||
|
|
593c2735ce | ||
|
|
48e72c62f3 | ||
|
|
f316d4c757 | ||
|
|
d6dba3e545 |
@@ -336,7 +336,7 @@ dotnet_diagnostic.IDE0305.severity = silent # Requires C# 12
|
|||||||
#dotnet_style_readonly_field = true
|
#dotnet_style_readonly_field = true
|
||||||
dotnet_diagnostic.IDE0044.severity = warning
|
dotnet_diagnostic.IDE0044.severity = warning
|
||||||
|
|
||||||
## Language keyword vs. framework types preferences
|
## Language keyword vs framework types preferences
|
||||||
|
|
||||||
# IDE0049 Use language keywords instead of framework type names for type references
|
# IDE0049 Use language keywords instead of framework type names for type references
|
||||||
#dotnet_style_predefined_type_for_locals_parameters_members = true
|
#dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||||
|
|||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Remove System .NET
|
||||||
|
run: sudo apt-get remove -y dotnet*
|
||||||
|
|
||||||
- name: Clone Repository
|
- name: Clone Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|||||||
85
.github/workflows/itch.yml
vendored
85
.github/workflows/itch.yml
vendored
@@ -15,73 +15,56 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
if: github.repository == 'openra/openra'
|
if: github.repository == 'openra/openra'
|
||||||
steps:
|
steps:
|
||||||
- name: Download Packages
|
- name: Download Butler
|
||||||
|
env:
|
||||||
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
run: |
|
run: |
|
||||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}-x64.exe"
|
wget -cq -O butler-linux-amd64.zip https://broth.itch.ovh/butler/linux-amd64/LATEST/archive/default
|
||||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}-x64-winportable.zip" -O "OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip"
|
unzip butler-linux-amd64.zip
|
||||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}.dmg"
|
rm butler-linux-amd64.zip
|
||||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Dune-2000-x86_64.AppImage"
|
chmod +x butler
|
||||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Red-Alert-x86_64.AppImage"
|
./butler -V
|
||||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Tiberian-Dawn-x86_64.AppImage"
|
./butler login
|
||||||
wget -q "https://raw.githubusercontent.com/${{ github.repository }}/${{ github.event.inputs.tag }}/packaging/.itch.toml"
|
|
||||||
zip -u "OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip" .itch.toml
|
|
||||||
|
|
||||||
- name: Publish Windows Installer
|
- name: Publish Windows Installer
|
||||||
uses: josephbmanley/butler-publish-itchio-action@master
|
|
||||||
env:
|
env:
|
||||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
CHANNEL: win
|
run: |
|
||||||
ITCH_GAME: openra
|
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}-x64.exe"
|
||||||
ITCH_USER: openra
|
./butler push "OpenRA-${{ github.event.inputs.tag }}-x64.exe" "openra/openra:win" --userversion ${{ github.event.inputs.tag }}
|
||||||
VERSION: ${{ github.event.inputs.tag }}
|
|
||||||
PACKAGE: OpenRA-${{ github.event.inputs.tag }}-x64.exe
|
|
||||||
|
|
||||||
- name: Publish Windows Itch Bundle
|
- name: Publish Windows Itch Bundle
|
||||||
uses: josephbmanley/butler-publish-itchio-action@master
|
|
||||||
env:
|
env:
|
||||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
CHANNEL: itch
|
run: |
|
||||||
ITCH_GAME: openra
|
wget -q "https://raw.githubusercontent.com/${{ github.repository }}/${{ github.event.inputs.tag }}/packaging/.itch.toml"
|
||||||
ITCH_USER: openra
|
zip -u "OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip" .itch.toml
|
||||||
VERSION: ${{ github.event.inputs.tag }}
|
./butler push "OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip" "openra/openra:itch" --userversion ${{ github.event.inputs.tag }}
|
||||||
PACKAGE: OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip
|
|
||||||
|
|
||||||
- name: Publish macOS Package
|
- name: Publish macOS Package
|
||||||
uses: josephbmanley/butler-publish-itchio-action@master
|
|
||||||
env:
|
env:
|
||||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
CHANNEL: macos
|
run: |
|
||||||
ITCH_GAME: openra
|
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}.dmg"
|
||||||
ITCH_USER: openra
|
./butler push "OpenRA-${{ github.event.inputs.tag }}.dmg" "openra/openra:macos" --userversion ${{ github.event.inputs.tag }}
|
||||||
VERSION: ${{ github.event.inputs.tag }}
|
|
||||||
PACKAGE: OpenRA-${{ github.event.inputs.tag }}.dmg
|
|
||||||
|
|
||||||
- name: Publish RA AppImage
|
- name: Publish RA AppImage
|
||||||
uses: josephbmanley/butler-publish-itchio-action@master
|
|
||||||
env:
|
env:
|
||||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
CHANNEL: linux-ra
|
run: |
|
||||||
ITCH_GAME: openra
|
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Red-Alert-x86_64.AppImage"
|
||||||
ITCH_USER: openra
|
./butler push "OpenRA-Red-Alert-x86_64.AppImage" "openra/openra:linux-ra" --userversion ${{ github.event.inputs.tag }}
|
||||||
VERSION: ${{ github.event.inputs.tag }}
|
|
||||||
PACKAGE: OpenRA-Red-Alert-x86_64.AppImage
|
|
||||||
|
|
||||||
- name: Publish TD AppImage
|
- name: Publish TD AppImage
|
||||||
uses: josephbmanley/butler-publish-itchio-action@master
|
|
||||||
env:
|
env:
|
||||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
CHANNEL: linux-cnc
|
run: |
|
||||||
ITCH_GAME: openra
|
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Tiberian-Dawn-x86_64.AppImage"
|
||||||
ITCH_USER: openra
|
./butler push "OpenRA-Tiberian-Dawn-x86_64.AppImage" "openra/openra:linux-cnc" --userversion ${{ github.event.inputs.tag }}
|
||||||
VERSION: ${{ github.event.inputs.tag }}
|
|
||||||
PACKAGE: OpenRA-Tiberian-Dawn-x86_64.AppImage
|
|
||||||
|
|
||||||
- name: Publish D2k AppImage
|
- name: Publish D2k AppImage
|
||||||
uses: josephbmanley/butler-publish-itchio-action@master
|
|
||||||
env:
|
env:
|
||||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||||
CHANNEL: linux-d2k
|
run: |
|
||||||
ITCH_GAME: openra
|
wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Dune-2000-x86_64.AppImage"
|
||||||
ITCH_USER: openra
|
./butler push "OpenRA-Dune-2000-x86_64.AppImage" "openra/openra:linux-d2k" --userversion ${{ github.event.inputs.tag }}
|
||||||
VERSION: ${{ github.event.inputs.tag }}
|
|
||||||
PACKAGE: OpenRA-Dune-2000-x86_64.AppImage
|
|
||||||
|
|||||||
36
.github/workflows/packaging.yml
vendored
36
.github/workflows/packaging.yml
vendored
@@ -57,13 +57,11 @@ jobs:
|
|||||||
./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux"
|
./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux"
|
||||||
|
|
||||||
- name: Upload Packages
|
- name: Upload Packages
|
||||||
uses: svenstaro/upload-release-action@v2
|
env:
|
||||||
with:
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
shell: bash
|
||||||
tag: ${{ github.ref }}
|
run: |
|
||||||
overwrite: true
|
gh release upload ${{ github.ref_name }} build/linux/*
|
||||||
file_glob: true
|
|
||||||
file: build/linux/*
|
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
name: macOS Disk Image
|
name: macOS Disk Image
|
||||||
@@ -92,13 +90,11 @@ jobs:
|
|||||||
./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos"
|
./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos"
|
||||||
|
|
||||||
- name: Upload Package
|
- name: Upload Package
|
||||||
uses: svenstaro/upload-release-action@v2
|
env:
|
||||||
with:
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
shell: bash
|
||||||
tag: ${{ github.ref }}
|
run: |
|
||||||
overwrite: true
|
gh release upload ${{ github.ref_name }} build/macos/*
|
||||||
file_glob: true
|
|
||||||
file: build/macos/*
|
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: Windows Installers
|
name: Windows Installers
|
||||||
@@ -124,10 +120,8 @@ jobs:
|
|||||||
./packaging/windows/buildpackage.sh "${GIT_TAG}" "${PWD}/build/windows"
|
./packaging/windows/buildpackage.sh "${GIT_TAG}" "${PWD}/build/windows"
|
||||||
|
|
||||||
- name: Upload Packages
|
- name: Upload Packages
|
||||||
uses: svenstaro/upload-release-action@v2
|
env:
|
||||||
with:
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
shell: bash
|
||||||
tag: ${{ github.ref }}
|
run: |
|
||||||
overwrite: true
|
gh release upload ${{ github.ref_name }} build/windows/*
|
||||||
file_glob: true
|
|
||||||
file: build/windows/*
|
|
||||||
|
|||||||
29
Dockerfile
Normal file
29
Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get -y upgrade; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
make \
|
||||||
|
python3 \
|
||||||
|
unzip \
|
||||||
|
mono-complete
|
||||||
|
|
||||||
|
|
||||||
|
RUN useradd -d /home/openra -m -s /sbin/nologin openra
|
||||||
|
|
||||||
|
WORKDIR /home/openra
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN chown -R openra:openra .
|
||||||
|
|
||||||
|
USER openra
|
||||||
|
|
||||||
|
RUN make
|
||||||
|
|
||||||
|
EXPOSE 1234
|
||||||
|
|
||||||
|
ENTRYPOINT ["./launch-dedicated.sh"]
|
||||||
@@ -22,6 +22,7 @@ namespace OpenRA.Graphics
|
|||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
public bool IsDecoration { get; set; }
|
public bool IsDecoration { get; set; }
|
||||||
|
|
||||||
|
readonly Map map;
|
||||||
readonly SequenceSet sequences;
|
readonly SequenceSet sequences;
|
||||||
readonly Func<WAngle> facingFunc;
|
readonly Func<WAngle> facingFunc;
|
||||||
readonly Func<bool> paused;
|
readonly Func<bool> paused;
|
||||||
@@ -43,6 +44,7 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public Animation(World world, string name, Func<WAngle> facingFunc, Func<bool> paused)
|
public Animation(World world, string name, Func<WAngle> facingFunc, Func<bool> paused)
|
||||||
{
|
{
|
||||||
|
map = world.Map;
|
||||||
sequences = world.Map.Sequences;
|
sequences = world.Map.Sequences;
|
||||||
Name = name.ToLowerInvariant();
|
Name = name.ToLowerInvariant();
|
||||||
this.facingFunc = facingFunc;
|
this.facingFunc = facingFunc;
|
||||||
@@ -65,8 +67,10 @@ namespace OpenRA.Graphics
|
|||||||
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
||||||
if (shadow != null)
|
if (shadow != null)
|
||||||
{
|
{
|
||||||
|
var height = map.DistanceAboveTerrain(pos).Length;
|
||||||
|
|
||||||
var shadowRenderable = new SpriteRenderable(
|
var shadowRenderable = new SpriteRenderable(
|
||||||
shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette,
|
shadow, pos, offset - new WVec(0, 0, height), CurrentSequence.ShadowZOffset + zOffset + height, palette,
|
||||||
CurrentSequence.Scale, 1f, float3.Ones, tintModifiers,
|
CurrentSequence.Scale, 1f, float3.Ones, tintModifiers,
|
||||||
true, rotation);
|
true, rotation);
|
||||||
return new IRenderable[] { shadowRenderable, imageRenderable };
|
return new IRenderable[] { shadowRenderable, imageRenderable };
|
||||||
|
|||||||
@@ -149,6 +149,10 @@ namespace OpenRA.Graphics
|
|||||||
var buffer = data;
|
var buffer = data;
|
||||||
ReleaseBuffer();
|
ReleaseBuffer();
|
||||||
|
|
||||||
|
// We aren't commiting data to the GPU, so let's not delete our data.
|
||||||
|
if (Game.Renderer == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Only transfer if the destination has no data that would be lost by overwriting.
|
// Only transfer if the destination has no data that would be lost by overwriting.
|
||||||
if (buffer != null && destination.data == null && destination.texture == null)
|
if (buffer != null && destination.data == null && destination.texture == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
@@ -244,21 +245,42 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
var client = HttpClientFactory.Create();
|
var client = HttpClientFactory.Create();
|
||||||
var stringPool = new HashSet<string>(); // Reuse common strings in YAML
|
var stringPool = new HashSet<string>(); // Reuse common strings in YAML
|
||||||
|
var buffer = new StringBuilder();
|
||||||
|
|
||||||
// Limit each query to 50 maps at a time to avoid request size limits
|
// Limit each query to 50 maps at a time to avoid request size limits
|
||||||
for (var i = 0; i < queryUids.Count; i += 50)
|
for (var i = 0; i < queryUids.Count; i += 50)
|
||||||
{
|
{
|
||||||
var batchUids = queryUids.Skip(i).Take(50).ToList();
|
var batchUids = queryUids.Skip(i).Take(50).ToList();
|
||||||
var url = repositoryUrl + "hash/" + string.Join(",", batchUids) + "/yaml";
|
var url = repositoryUrl + "hash/" + string.Join(",", batchUids) + "/yaml";
|
||||||
|
|
||||||
|
using (new PerfTimer("RemoteMapDetails"))
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var httpResponseMessage = await client.GetAsync(url);
|
await using (var resultStream = await client.GetStreamAsync(url))
|
||||||
var result = await httpResponseMessage.Content.ReadAsStreamAsync();
|
{
|
||||||
|
using (var resultReader = new StreamReader(resultStream))
|
||||||
var yaml = MiniYaml.FromStream(result, url, stringPool: stringPool);
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var line = await resultReader.ReadLineAsync();
|
||||||
|
if (line == null || !line.StartsWith('\t'))
|
||||||
|
{
|
||||||
|
var yaml = MiniYaml.FromString(buffer.ToString(), url, stringPool: stringPool);
|
||||||
|
buffer.Clear();
|
||||||
foreach (var kv in yaml)
|
foreach (var kv in yaml)
|
||||||
previews[kv.Key].UpdateRemoteSearch(MapStatus.DownloadAvailable, kv.Value, modData.Manifest.MapCompatibility, mapDetailsReceived);
|
previews[kv.Key].UpdateRemoteSearch(MapStatus.DownloadAvailable, kv.Value, modData.Manifest.MapCompatibility, mapDetailsReceived);
|
||||||
|
|
||||||
|
if (line == null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Append(line);
|
||||||
|
buffer.Append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var uid in batchUids)
|
foreach (var uid in batchUids)
|
||||||
{
|
{
|
||||||
var p = previews[uid];
|
var p = previews[uid];
|
||||||
@@ -280,6 +302,7 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,11 +249,26 @@ namespace OpenRA
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string GetMessage(string key, object[] args = null)
|
public string GetMessage(string key, object[] args = null)
|
||||||
{
|
{
|
||||||
// PERF: instead of loading mod level strings per each MapPreview, reuse the already loaded one in FluentProvider.
|
if (TryGetMessage(key, out var message, args))
|
||||||
if (FluentProvider.TryGetModMessage(key, out var message, args))
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
return innerData.FluentBundle?.GetMessage(key, args) ?? key;
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Functionality mirrors <see cref="FluentProvider.TryGetMessage"/>, except instead of using
|
||||||
|
/// loaded <see cref="Map"/>'s fluent bundle as backup, we use this <see cref="MapPreview"/>'s.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryGetMessage(string key, out string message, object[] args = null)
|
||||||
|
{
|
||||||
|
// PERF: instead of loading mod level strings per each MapPreview, reuse the already loaded one in FluentProvider.
|
||||||
|
if (FluentProvider.TryGetModMessage(key, out message, args))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (innerData.FluentBundle == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return innerData.FluentBundle.TryGetMessage(key, out message, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite minimap;
|
Sprite minimap;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<RootNamespace>OpenRA</RootNamespace>
|
<RootNamespace>OpenRA</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition="'$(MSBuildRuntimeType)'!='Mono'">
|
<ItemGroup Condition="'$(MSBuildRuntimeType)'!='Mono'">
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="6.0.2" />
|
||||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Mono'">
|
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Mono'">
|
||||||
|
|||||||
@@ -1006,7 +1006,10 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
case "Chat":
|
case "Chat":
|
||||||
{
|
{
|
||||||
if (!IsMultiplayer || !playerMessageTracker.IsPlayerAtFloodLimit(conn))
|
var client = GetClient(conn);
|
||||||
|
Console.WriteLine($"[{DateTime.Now.ToString(Settings.TimestampFormat)}] {client.Name}: {o.TargetString}");
|
||||||
|
|
||||||
|
if (Type == ServerType.Local || !playerMessageTracker.IsPlayerAtFloodLimit(conn))
|
||||||
DispatchOrdersToClients(conn, 0, o.Serialize());
|
DispatchOrdersToClients(conn, 0, o.Serialize());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ namespace OpenRA.Mods.Cnc.Scripting
|
|||||||
public ChronosphereProperties(ScriptContext context, Actor self)
|
public ChronosphereProperties(ScriptContext context, Actor self)
|
||||||
: base(context, self) { }
|
: base(context, self) { }
|
||||||
|
|
||||||
[Desc("Chronoshift a group of actors. A duration of 0 will teleport the actors permanently.")]
|
[Desc("Chronoshift a group of actors. A duration of 0 will teleport the actors permanently. " +
|
||||||
|
"If a given cell is unexplored for this power's owner, the closest valid cell will be used instead.")]
|
||||||
public void Chronoshift([ScriptEmmyTypeOverride("{ [actor]: cpos }")] LuaTable unitLocationPairs, int duration = 0, bool killCargo = false)
|
public void Chronoshift([ScriptEmmyTypeOverride("{ [actor]: cpos }")] LuaTable unitLocationPairs, int duration = 0, bool killCargo = false)
|
||||||
{
|
{
|
||||||
foreach (var kv in unitLocationPairs)
|
foreach (var kv in unitLocationPairs)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
public override object Create(ActorInitializer init) { return new ChronoVortexRenderer(init.Self); }
|
public override object Create(ActorInitializer init) { return new ChronoVortexRenderer(init.Self); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ChronoVortexRenderer : IRenderPostProcessPass
|
public sealed class ChronoVortexRenderer : IRenderPostProcessPass, INotifyActorDisposing
|
||||||
{
|
{
|
||||||
readonly Renderer renderer;
|
readonly Renderer renderer;
|
||||||
readonly IShader shader;
|
readonly IShader shader;
|
||||||
@@ -105,5 +105,11 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
|
|
||||||
vortices.Clear();
|
vortices.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void INotifyActorDisposing.Disposing(Actor self)
|
||||||
|
{
|
||||||
|
vortexSheet.Dispose();
|
||||||
|
vortexBuffer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
|
|
||||||
void CancelCapture()
|
void CancelCapture()
|
||||||
{
|
{
|
||||||
manager.CancelCapture(enterCaptureManager);
|
manager.CancelCapture(enterActor, enterCaptureManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
// Prioritise search by these locations in this order: lastHarvestedCell -> lastLinkedDock -> self.
|
// Prioritise search by these locations in this order: lastHarvestedCell -> lastLinkedDock -> self.
|
||||||
CPos searchFromLoc;
|
CPos searchFromLoc;
|
||||||
int searchRadius;
|
int searchRadius;
|
||||||
WPos? dockPos = null;
|
var dockPos = harv.DockClientManager?.LastReservedHost?.DockPosition;
|
||||||
|
|
||||||
if (lastHarvestedCell.HasValue)
|
if (lastHarvestedCell.HasValue)
|
||||||
{
|
{
|
||||||
searchRadius = harvInfo.SearchFromHarvesterRadius;
|
searchRadius = harvInfo.SearchFromHarvesterRadius;
|
||||||
@@ -182,12 +183,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
searchRadius = harvInfo.SearchFromProcRadius;
|
searchRadius = harvInfo.SearchFromProcRadius;
|
||||||
var dock = harv.DockClientManager?.LastReservedHost;
|
if (dockPos != null)
|
||||||
if (dock != null)
|
|
||||||
{
|
|
||||||
dockPos = dock.DockPosition;
|
|
||||||
searchFromLoc = self.World.Map.CellContaining(dockPos.Value);
|
searchFromLoc = self.World.Map.CellContaining(dockPos.Value);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
searchFromLoc = self.Location;
|
searchFromLoc = self.Location;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
readonly bool forceEnter;
|
readonly bool forceEnter;
|
||||||
readonly bool ignoreOccupancy;
|
readonly bool ignoreOccupancy;
|
||||||
|
|
||||||
|
bool dockingCancelled;
|
||||||
|
|
||||||
public MoveToDock(Actor self, Actor dockHostActor = null, IDockHost dockHost = null,
|
public MoveToDock(Actor self, Actor dockHostActor = null, IDockHost dockHost = null,
|
||||||
bool forceEnter = false, bool ignoreOccupancy = false, Color? dockLineColor = null)
|
bool forceEnter = false, bool ignoreOccupancy = false, Color? dockLineColor = null)
|
||||||
{
|
{
|
||||||
@@ -44,17 +46,25 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
|
|
||||||
protected override void OnFirstRun(Actor self)
|
protected override void OnFirstRun(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceling || dockClient.IsTraitDisabled)
|
if (dockClient.IsTraitDisabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We were ordered to dock to an actor but host was unspecified.
|
// We were ordered to dock to an actor but host was unspecified.
|
||||||
if (dockHostActor != null && dockHost == null)
|
if (dockHostActor != null && dockHost == null)
|
||||||
{
|
{
|
||||||
|
if (dockHostActor.IsDead || !dockHostActor.IsInWorld)
|
||||||
|
{
|
||||||
|
dockingCancelled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var link = dockClient.AvailableDockHosts(dockHostActor, default, forceEnter, ignoreOccupancy)
|
var link = dockClient.AvailableDockHosts(dockHostActor, default, forceEnter, ignoreOccupancy)
|
||||||
.ClosestDock(self, dockClient);
|
.ClosestDock(self, dockClient);
|
||||||
|
|
||||||
if (link.HasValue)
|
if (link.HasValue)
|
||||||
dockHost = link.Value.Trait;
|
dockHost = link.Value.Trait;
|
||||||
|
else
|
||||||
|
dockingCancelled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +73,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
if (IsCanceling)
|
if (IsCanceling)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (dockClient.IsTraitDisabled)
|
if (dockingCancelled || dockClient.IsTraitDisabled)
|
||||||
{
|
{
|
||||||
Cancel(self, true);
|
Cancel(self, true);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Mods.Common.EditorBrushes;
|
||||||
using OpenRA.Mods.Common.Graphics;
|
using OpenRA.Mods.Common.Graphics;
|
||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
@@ -87,6 +89,12 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
return ((long)pixelDistance << 32) + worldZPosition;
|
return ((long)pixelDistance << 32) + worldZPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteSelection(MapBlitFilters filters)
|
||||||
|
{
|
||||||
|
if (Selection.Area != null)
|
||||||
|
editorActionManager.Add(new DeleteAreaAction(world.Map, filters, Selection.Area, resourceLayer, actorLayer));
|
||||||
|
}
|
||||||
|
|
||||||
public void ClearSelection(bool updateSelectedTab = false)
|
public void ClearSelection(bool updateSelectedTab = false)
|
||||||
{
|
{
|
||||||
if (Selection.HasSelection)
|
if (Selection.HasSelection)
|
||||||
@@ -335,6 +343,114 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class DeleteAreaAction : IEditorAction
|
||||||
|
{
|
||||||
|
[FluentReference("x", "y", "width", "height")]
|
||||||
|
const string RemovedArea = "notification-removed-area";
|
||||||
|
|
||||||
|
public string Text { get; }
|
||||||
|
|
||||||
|
readonly EditorBlitSource editorBlitSource;
|
||||||
|
readonly MapBlitFilters blitFilters;
|
||||||
|
readonly IResourceLayer resourceLayer;
|
||||||
|
readonly EditorActorLayer editorActorLayer;
|
||||||
|
readonly CellRegion area;
|
||||||
|
readonly Map map;
|
||||||
|
|
||||||
|
public DeleteAreaAction(Map map, MapBlitFilters blitFilters, CellRegion area, IResourceLayer resourceLayer, EditorActorLayer editorActorLayer)
|
||||||
|
{
|
||||||
|
this.map = map;
|
||||||
|
this.blitFilters = blitFilters;
|
||||||
|
this.resourceLayer = resourceLayer;
|
||||||
|
this.editorActorLayer = editorActorLayer;
|
||||||
|
this.area = area;
|
||||||
|
|
||||||
|
editorBlitSource = EditorBlit.CopyRegionContents(map, editorActorLayer, resourceLayer, area, blitFilters);
|
||||||
|
|
||||||
|
Text = FluentProvider.GetMessage(RemovedArea,
|
||||||
|
"x", area.TopLeft.X,
|
||||||
|
"y", area.TopLeft.Y,
|
||||||
|
"width", area.BottomRight.X - area.TopLeft.X,
|
||||||
|
"height", area.BottomRight.Y - area.TopLeft.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
Do();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Do()
|
||||||
|
{
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Actors))
|
||||||
|
{
|
||||||
|
// Clear any existing actors in the paste cells.
|
||||||
|
foreach (var regionActor in editorActorLayer.PreviewsInCellRegion(area.CellCoords).ToList())
|
||||||
|
editorActorLayer.Remove(regionActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var tileKeyValuePair in editorBlitSource.Tiles)
|
||||||
|
{
|
||||||
|
var position = tileKeyValuePair.Key;
|
||||||
|
if (!map.Tiles.Contains(position))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Clear any existing resources.
|
||||||
|
if (resourceLayer != null && blitFilters.HasFlag(MapBlitFilters.Resources))
|
||||||
|
resourceLayer.ClearResources(position);
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Terrain))
|
||||||
|
{
|
||||||
|
map.Tiles[position] = map.Rules.TerrainInfo.DefaultTerrainTile;
|
||||||
|
map.Height[position] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Undo()
|
||||||
|
{
|
||||||
|
foreach (var tileKeyValuePair in editorBlitSource.Tiles)
|
||||||
|
{
|
||||||
|
var position = tileKeyValuePair.Key;
|
||||||
|
if (!map.Tiles.Contains(position))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var tile = tileKeyValuePair.Value;
|
||||||
|
var resourceLayerContents = tile.ResourceLayerContents;
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Terrain))
|
||||||
|
{
|
||||||
|
map.Tiles[position] = tile.TerrainTile;
|
||||||
|
map.Height[position] = tile.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Resources) &&
|
||||||
|
resourceLayerContents.HasValue &&
|
||||||
|
!string.IsNullOrWhiteSpace(resourceLayerContents.Value.Type))
|
||||||
|
resourceLayer.AddResource(resourceLayerContents.Value.Type, position, resourceLayerContents.Value.Density);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Actors))
|
||||||
|
{
|
||||||
|
// Create copies of the original actors, update their locations, and place.
|
||||||
|
foreach (var actorKeyValuePair in editorBlitSource.Actors)
|
||||||
|
{
|
||||||
|
var copy = actorKeyValuePair.Value.Export();
|
||||||
|
var locationInit = copy.GetOrDefault<LocationInit>();
|
||||||
|
if (locationInit != null)
|
||||||
|
{
|
||||||
|
if (!map.Tiles.Contains(locationInit.Value))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
copy.RemoveAll<LocationInit>();
|
||||||
|
copy.Add(new LocationInit(locationInit.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
editorActorLayer.Add(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed class RemoveSelectedActorAction : IEditorAction
|
sealed class RemoveSelectedActorAction : IEditorAction
|
||||||
{
|
{
|
||||||
[FluentReference("name", "id")]
|
[FluentReference("name", "id")]
|
||||||
|
|||||||
@@ -13,23 +13,28 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.FileSystem
|
namespace OpenRA.Mods.Common.FileSystem
|
||||||
{
|
{
|
||||||
|
[Desc("A file system that loads game assets installed by the user into their support directory.")]
|
||||||
public class ContentInstallerFileSystemLoader : IFileSystemLoader, IFileSystemExternalContent
|
public class ContentInstallerFileSystemLoader : IFileSystemLoader, IFileSystemExternalContent
|
||||||
{
|
{
|
||||||
[FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
|
[Desc("Mod to use for content installation.")]
|
||||||
public readonly string ContentInstallerMod = null;
|
public readonly string ContentInstallerMod = null;
|
||||||
|
|
||||||
[FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
public readonly Dictionary<string, string> Packages = null;
|
[Desc("A list of mod-provided packages. Anything required to display the initial load screen must be listed here.")]
|
||||||
|
public readonly Dictionary<string, string> SystemPackages = null;
|
||||||
|
|
||||||
|
[Desc("A list of user-installed packages. If missing (and not marked as optional), these will trigger the content installer.")]
|
||||||
public readonly Dictionary<string, string> ContentPackages = null;
|
public readonly Dictionary<string, string> ContentPackages = null;
|
||||||
|
|
||||||
public readonly Dictionary<string, string> ContentFiles = null;
|
[Desc("Files that aren't mounted as packages, but still need to trigger the content installer if missing.")]
|
||||||
|
public readonly Dictionary<string, string> RequiredContentFiles = null;
|
||||||
|
|
||||||
bool contentAvailable = true;
|
bool isContentAvailable = true;
|
||||||
|
|
||||||
public void Mount(OpenRA.FileSystem.FileSystem fileSystem, ObjectCreator objectCreator)
|
public void Mount(OpenRA.FileSystem.FileSystem fileSystem, ObjectCreator objectCreator)
|
||||||
{
|
{
|
||||||
foreach (var kv in Packages)
|
foreach (var kv in SystemPackages)
|
||||||
fileSystem.Mount(kv.Key, kv.Value);
|
fileSystem.Mount(kv.Key, kv.Value);
|
||||||
|
|
||||||
if (ContentPackages != null)
|
if (ContentPackages != null)
|
||||||
@@ -42,23 +47,23 @@ namespace OpenRA.Mods.Common.FileSystem
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
contentAvailable = false;
|
isContentAvailable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ContentFiles != null)
|
if (RequiredContentFiles != null)
|
||||||
foreach (var kv in ContentFiles)
|
foreach (var kv in RequiredContentFiles)
|
||||||
if (!fileSystem.Exists(kv.Key))
|
if (!fileSystem.Exists(kv.Key))
|
||||||
contentAvailable = false;
|
isContentAvailable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IFileSystemExternalContent.InstallContentIfRequired(ModData modData)
|
bool IFileSystemExternalContent.InstallContentIfRequired(ModData modData)
|
||||||
{
|
{
|
||||||
if (!contentAvailable)
|
if (!isContentAvailable)
|
||||||
Game.InitializeMod(ContentInstallerMod, new Arguments());
|
Game.InitializeMod(ContentInstallerMod, new Arguments());
|
||||||
|
|
||||||
return !contentAvailable;
|
return !isContentAvailable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
|
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<PackageReference Include="NuGet.CommandLine" Version="6.12.1" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="OpenRA-FuzzyLogicLibrary" Version="1.0.1" />
|
<PackageReference Include="OpenRA-FuzzyLogicLibrary" Version="1.0.1" />
|
||||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
GetScriptTriggers(actor).RegisterCallback(Trigger.OnIdle, func, Context);
|
GetScriptTriggers(actor).RegisterCallback(Trigger.OnIdle, func, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Call a function when the actor is damaged. The callback " +
|
[Desc("Call a function when the actor is damaged. " +
|
||||||
|
"Repairs or other negative damage can activate this trigger. The callback " +
|
||||||
"function will be called as func(self: actor, attacker: actor, damage: integer).")]
|
"function will be called as func(self: actor, attacker: actor, damage: integer).")]
|
||||||
public void OnDamaged(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor, attacker: actor, damage: integer)")] LuaFunction func)
|
public void OnDamaged(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor, attacker: actor, damage: integer)")] LuaFunction func)
|
||||||
{
|
{
|
||||||
@@ -130,7 +131,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
GetScriptTriggers(a).OnKilledInternal += OnMemberKilled;
|
GetScriptTriggers(a).OnKilledInternal += OnMemberKilled;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Call a function when one of the actors in a group is killed. The callback " +
|
[Desc("Call a function when one of the actors in a group is killed. " +
|
||||||
|
"This trigger is only called once. The callback " +
|
||||||
"function will be called as func(killed: actor).")]
|
"function will be called as func(killed: actor).")]
|
||||||
public void OnAnyKilled(Actor[] actors, [ScriptEmmyTypeOverride("fun(killed: actor)")] LuaFunction func)
|
public void OnAnyKilled(Actor[] actors, [ScriptEmmyTypeOverride("fun(killed: actor)")] LuaFunction func)
|
||||||
{
|
{
|
||||||
@@ -164,12 +166,12 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
[Desc("Call a function when this actor produces another actor. " +
|
[Desc("Call a function when this actor produces another actor. " +
|
||||||
"The callback function will be called as func(producer: actor, produced: actor).")]
|
"The callback function will be called as func(producer: actor, produced: actor).")]
|
||||||
public void OnProduction(Actor actors, [ScriptEmmyTypeOverride("fun(producer: actor, produced: actor)")] LuaFunction func)
|
public void OnProduction(Actor actor, [ScriptEmmyTypeOverride("fun(producer: actor, produced: actor)")] LuaFunction func)
|
||||||
{
|
{
|
||||||
if (actors == null)
|
if (actor == null)
|
||||||
throw new NullReferenceException(nameof(actors));
|
throw new NullReferenceException(nameof(actor));
|
||||||
|
|
||||||
GetScriptTriggers(actors).RegisterCallback(Trigger.OnProduction, func, Context);
|
GetScriptTriggers(actor).RegisterCallback(Trigger.OnProduction, func, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Call a function when any actor produces another actor. The callback " +
|
[Desc("Call a function when any actor produces another actor. The callback " +
|
||||||
@@ -304,15 +306,16 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
[Desc("Call a function when this actor is captured. The callback function " +
|
[Desc("Call a function when this actor is captured. The callback function " +
|
||||||
"will be called as func(self: actor, captor: actor, oldOwner: player, newOwner: player).")]
|
"will be called as func(self: actor, captor: actor, oldOwner: player, newOwner: player).")]
|
||||||
public void OnCapture(Actor actors, [ScriptEmmyTypeOverride("fun(self: actor, captor: actor, oldOwner: player, newOwner: player)")] LuaFunction func)
|
public void OnCapture(Actor actor, [ScriptEmmyTypeOverride("fun(self: actor, captor: actor, oldOwner: player, newOwner: player)")] LuaFunction func)
|
||||||
{
|
{
|
||||||
if (actors == null)
|
if (actor == null)
|
||||||
throw new NullReferenceException(nameof(actors));
|
throw new NullReferenceException(nameof(actor));
|
||||||
|
|
||||||
GetScriptTriggers(actors).RegisterCallback(Trigger.OnCapture, func, Context);
|
GetScriptTriggers(actor).RegisterCallback(Trigger.OnCapture, func, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Call a function when this actor is killed or captured. " +
|
[Desc("Call a function when this actor is killed or captured. " +
|
||||||
|
"This trigger is only called once. " +
|
||||||
"The callback function will be called as func().")]
|
"The callback function will be called as func().")]
|
||||||
public void OnKilledOrCaptured(Actor actor, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
public void OnKilledOrCaptured(Actor actor, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||||
{
|
{
|
||||||
@@ -345,6 +348,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Call a function when all of the actors in a group have been killed or captured. " +
|
[Desc("Call a function when all of the actors in a group have been killed or captured. " +
|
||||||
|
"This trigger is only called once. " +
|
||||||
"The callback function will be called as func().")]
|
"The callback function will be called as func().")]
|
||||||
public void OnAllKilledOrCaptured(Actor[] actors, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
public void OnAllKilledOrCaptured(Actor[] actors, [ScriptEmmyTypeOverride("fun()")] LuaFunction func)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
Self.World.Add(new FlashTarget(Self, color, 0.5f, count, interval, delay));
|
Self.World.Add(new FlashTarget(Self, color, 0.5f, count, interval, delay));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("The effective owner of the actor.")]
|
[Desc("The effective (displayed) owner of the actor. " +
|
||||||
|
"This may differ from the true owner in some cases, such as disguised actors.")]
|
||||||
public Player EffectiveOwner
|
public Player EffectiveOwner
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -96,7 +97,6 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[ScriptPropertyGroup("General")]
|
[ScriptPropertyGroup("General")]
|
||||||
public class GeneralProperties : ScriptActorProperties
|
public class GeneralProperties : ScriptActorProperties
|
||||||
{
|
{
|
||||||
readonly IFacing facing;
|
|
||||||
readonly AutoTarget autotarget;
|
readonly AutoTarget autotarget;
|
||||||
readonly ScriptTags scriptTags;
|
readonly ScriptTags scriptTags;
|
||||||
readonly Tooltip[] tooltips;
|
readonly Tooltip[] tooltips;
|
||||||
@@ -104,30 +104,11 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
public GeneralProperties(ScriptContext context, Actor self)
|
public GeneralProperties(ScriptContext context, Actor self)
|
||||||
: base(context, self)
|
: base(context, self)
|
||||||
{
|
{
|
||||||
facing = self.TraitOrDefault<IFacing>();
|
|
||||||
autotarget = self.TraitOrDefault<AutoTarget>();
|
autotarget = self.TraitOrDefault<AutoTarget>();
|
||||||
scriptTags = self.TraitOrDefault<ScriptTags>();
|
scriptTags = self.TraitOrDefault<ScriptTags>();
|
||||||
tooltips = self.TraitsImplementing<Tooltip>().ToArray();
|
tooltips = self.TraitsImplementing<Tooltip>().ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("The actor position in cell coordinates.")]
|
|
||||||
public CPos Location => Self.Location;
|
|
||||||
|
|
||||||
[Desc("The actor position in world coordinates.")]
|
|
||||||
public WPos CenterPosition => Self.CenterPosition;
|
|
||||||
|
|
||||||
[Desc("The direction that the actor is facing.")]
|
|
||||||
public WAngle Facing
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (facing == null)
|
|
||||||
throw new LuaException($"Actor '{Self}' doesn't define a facing");
|
|
||||||
|
|
||||||
return facing.Facing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[ScriptActorPropertyActivity]
|
[ScriptActorPropertyActivity]
|
||||||
[Desc("Instantly moves the actor to the specified cell.")]
|
[Desc("Instantly moves the actor to the specified cell.")]
|
||||||
public void Teleport(CPos cell)
|
public void Teleport(CPos cell)
|
||||||
@@ -213,4 +194,32 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
return IsTaggable && scriptTags.HasTag(tag);
|
return IsTaggable && scriptTags.HasTag(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ScriptPropertyGroup("General")]
|
||||||
|
public class LocationProperties : ScriptActorProperties, Requires<IOccupySpaceInfo>
|
||||||
|
{
|
||||||
|
public LocationProperties(ScriptContext context, Actor self)
|
||||||
|
: base(context, self) { }
|
||||||
|
|
||||||
|
[Desc("The actor position in cell coordinates.")]
|
||||||
|
public CPos Location => Self.Location;
|
||||||
|
|
||||||
|
[Desc("The actor position in world coordinates.")]
|
||||||
|
public WPos CenterPosition => Self.CenterPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ScriptPropertyGroup("General")]
|
||||||
|
public class FacingProperties : ScriptActorProperties, Requires<IFacingInfo>
|
||||||
|
{
|
||||||
|
readonly IFacing facing;
|
||||||
|
|
||||||
|
public FacingProperties(ScriptContext context, Actor self)
|
||||||
|
: base(context, self)
|
||||||
|
{
|
||||||
|
facing = self.Trait<IFacing>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Desc("The direction that the actor is facing.")]
|
||||||
|
public WAngle Facing => facing.Facing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[ScriptActorPropertyActivity]
|
[ScriptActorPropertyActivity]
|
||||||
[Desc("Mark an objective as failed. This needs the objective ID returned " +
|
[Desc("Mark an objective as failed. This needs the objective ID returned " +
|
||||||
"by AddObjective as argument. Secondary objectives do not have any " +
|
"by AddObjective as argument. Secondary objectives do not have any " +
|
||||||
"influence whatsoever on the outcome of the game.")]
|
"influence whatsoever on the outcome of the game. " +
|
||||||
|
"It is possible to mark a completed objective as a failure.")]
|
||||||
public void MarkFailedObjective(int id)
|
public void MarkFailedObjective(int id)
|
||||||
{
|
{
|
||||||
if (id < 0 || id >= mo.Objectives.Count)
|
if (id < 0 || id >= mo.Objectives.Count)
|
||||||
|
|||||||
@@ -87,9 +87,6 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
[FluentReference("faction")]
|
[FluentReference("faction")]
|
||||||
const string InvalidFactionSelected = "notification-invalid-faction-selected";
|
const string InvalidFactionSelected = "notification-invalid-faction-selected";
|
||||||
|
|
||||||
[FluentReference("factions")]
|
|
||||||
const string SupportedFactions = "notification-supported-factions";
|
|
||||||
|
|
||||||
[FluentReference]
|
[FluentReference]
|
||||||
const string RequiresHost = "notification-requires-host";
|
const string RequiresHost = "notification-requires-host";
|
||||||
|
|
||||||
@@ -609,9 +606,8 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
|
|
||||||
foreach (var c in server.LobbyInfo.Clients)
|
foreach (var c in server.LobbyInfo.Clients)
|
||||||
{
|
{
|
||||||
|
c.Faction = SanitizePlayerFaction(server, c.Faction, selectableFactions);
|
||||||
c.State = Session.ClientState.Invalid;
|
c.State = Session.ClientState.Invalid;
|
||||||
if (!selectableFactions.Contains(c.Faction))
|
|
||||||
c.Faction = "Random";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reassign players into new slots based on their old slots:
|
// Reassign players into new slots based on their old slots:
|
||||||
@@ -1055,15 +1051,13 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction)
|
if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var factions = server.Map.WorldActorInfo.TraitInfos<FactionInfo>()
|
|
||||||
.Where(f => f.Selectable).Select(f => f.InternalName)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var faction = parts[1];
|
var faction = parts[1];
|
||||||
if (!factions.Contains(faction))
|
var isValidFaction = server.Map.WorldActorInfo.TraitInfos<FactionInfo>()
|
||||||
|
.Any(f => f.Selectable && f.InternalName == client.Faction);
|
||||||
|
|
||||||
|
if (!isValidFaction)
|
||||||
{
|
{
|
||||||
server.SendFluentMessageTo(conn, InvalidFactionSelected, new object[] { "faction", faction });
|
server.SendFluentMessageTo(conn, InvalidFactionSelected, new object[] { "faction", faction });
|
||||||
server.SendFluentMessageTo(conn, SupportedFactions, new object[] { "factions", factions.JoinWith(", ") });
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1438,6 +1432,11 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string SanitizePlayerFaction(S server, string askedFaction, IEnumerable<string> validFactions)
|
||||||
|
{
|
||||||
|
return !validFactions.Contains(askedFaction) ? "Random" : askedFaction;
|
||||||
|
}
|
||||||
|
|
||||||
static string MissionBriefingOrDefault(S server)
|
static string MissionBriefingOrDefault(S server)
|
||||||
{
|
{
|
||||||
var missionData = server.Map.WorldActorInfo.TraitInfoOrDefault<MissionDataInfo>();
|
var missionData = server.Map.WorldActorInfo.TraitInfoOrDefault<MissionDataInfo>();
|
||||||
|
|||||||
@@ -92,12 +92,18 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var selectableFactions = server.Map.WorldActorInfo.TraitInfos<FactionInfo>()
|
||||||
|
.Where(f => f.Selectable)
|
||||||
|
.Select(f => f.InternalName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var playerNode = nodes.NodeWithKeyOrDefault("Player");
|
var playerNode = nodes.NodeWithKeyOrDefault("Player");
|
||||||
if (playerNode != null)
|
if (playerNode != null)
|
||||||
{
|
{
|
||||||
var client = server.GetClient(conn);
|
var client = server.GetClient(conn);
|
||||||
SkirmishSlot.DeserializeToClient(playerNode.Value, client);
|
SkirmishSlot.DeserializeToClient(playerNode.Value, client);
|
||||||
client.Color = LobbyCommands.SanitizePlayerColor(server, client.Color, client.Index);
|
client.Color = LobbyCommands.SanitizePlayerColor(server, client.Color, client.Index);
|
||||||
|
client.Faction = LobbyCommands.SanitizePlayerFaction(server, client.Faction, selectableFactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
var botsNode = nodes.NodeWithKeyOrDefault("Bots");
|
var botsNode = nodes.NodeWithKeyOrDefault("Bots");
|
||||||
@@ -128,6 +134,8 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
if (client.Slot != null && !server.LobbyInfo.Slots[client.Slot].LockColor)
|
if (client.Slot != null && !server.LobbyInfo.Slots[client.Slot].LockColor)
|
||||||
client.Color = LobbyCommands.SanitizePlayerColor(server, client.Color, client.Index);
|
client.Color = LobbyCommands.SanitizePlayerColor(server, client.Color, client.Index);
|
||||||
|
|
||||||
|
client.Faction = LobbyCommands.SanitizePlayerFaction(server, client.Faction, selectableFactions);
|
||||||
|
|
||||||
server.LobbyInfo.Clients.Add(client);
|
server.LobbyInfo.Clients.Add(client);
|
||||||
S.SyncClientToPlayerReference(client, server.Map.Players.Players[client.Slot]);
|
S.SyncClientToPlayerReference(client, server.Map.Players.Players[client.Slot]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1325,8 +1325,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
||||||
{
|
{
|
||||||
if (ChildActivity != null)
|
var a = ChildActivity;
|
||||||
foreach (var n in ChildActivity.TargetLineNodes(self))
|
for (; a != null; a = a.NextActivity)
|
||||||
|
if (!a.IsCanceling)
|
||||||
|
foreach (var n in a.TargetLineNodes(self))
|
||||||
yield return n;
|
yield return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
for (var i = 0; i < updateCount; i++)
|
for (var i = 0; i < updateCount; i++)
|
||||||
{
|
{
|
||||||
var rp = rallyPoints.Pop();
|
var rp = rallyPoints.Pop();
|
||||||
if (rp.Actor.Owner == player)
|
if (rp.Actor.Owner == player && !rp.Actor.Disposed)
|
||||||
SetRallyPoint(bot, rp);
|
SetRallyPoint(bot, rp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,20 +343,34 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
Locomotor[] LocomotorsForProducibles(Actor producer)
|
Locomotor[] LocomotorsForProducibles(Actor producer)
|
||||||
{
|
{
|
||||||
var buildingInfo = producer.Info.TraitInfoOrDefault<BuildingInfo>();
|
// Per-actor production
|
||||||
var productionInfo = producer.Info.TraitInfoOrDefault<ProductionInfo>();
|
var productions = producer.TraitsImplementing<Production>();
|
||||||
var locomotors = Array.Empty<Locomotor>();
|
|
||||||
|
|
||||||
if (productionInfo != null && productionInfo.Produces.Length > 0)
|
// Player-wide production
|
||||||
|
if (!productions.Any())
|
||||||
|
productions = producer.World.ActorsWithTrait<Production>().Where(x => x.Actor.Owner != producer.Owner).Select(x => x.Trait);
|
||||||
|
|
||||||
|
var produces = productions.SelectMany(p => p.Info.Produces).ToHashSet();
|
||||||
|
var locomotors = Array.Empty<Locomotor>();
|
||||||
|
if (produces.Count > 0)
|
||||||
{
|
{
|
||||||
var productionQueues = producer.Owner.PlayerActor.TraitsImplementing<ProductionQueue>()
|
// Per-actor production
|
||||||
.Where(pq => productionInfo.Produces.Contains(pq.Info.Type));
|
var productionQueues = producer.TraitsImplementing<ProductionQueue>();
|
||||||
|
|
||||||
|
// Player-wide production
|
||||||
|
if (!productionQueues.Any())
|
||||||
|
productionQueues = producer.Owner.PlayerActor.TraitsImplementing<ProductionQueue>();
|
||||||
|
|
||||||
|
productionQueues = productionQueues.Where(pq => produces.Contains(pq.Info.Type));
|
||||||
|
|
||||||
var producibles = productionQueues.SelectMany(pq => pq.BuildableItems());
|
var producibles = productionQueues.SelectMany(pq => pq.BuildableItems());
|
||||||
var locomotorNames = producibles
|
var locomotorNames = producibles
|
||||||
.Select(p => p.TraitInfoOrDefault<MobileInfo>())
|
.Select(p => p.TraitInfoOrDefault<MobileInfo>())
|
||||||
.Where(mi => mi != null)
|
.Where(mi => mi != null)
|
||||||
.Select(mi => mi.Locomotor)
|
.Select(mi => mi.Locomotor)
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
|
|
||||||
|
if (locomotorNames.Count != 0)
|
||||||
locomotors = world.WorldActor.TraitsImplementing<Locomotor>()
|
locomotors = world.WorldActor.TraitsImplementing<Locomotor>()
|
||||||
.Where(l => locomotorNames.Contains(l.Info.Name))
|
.Where(l => locomotorNames.Contains(l.Info.Name))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
// Returns true if FindNextResource was called.
|
// Returns true if FindNextResource was called.
|
||||||
bool HarvestIfAble(IBot bot, HarvesterTraitWrapper h)
|
bool HarvestIfAble(IBot bot, HarvesterTraitWrapper h)
|
||||||
{
|
{
|
||||||
if (h.Mobile == null)
|
if (h.Actor.IsDead || !h.Actor.IsInWorld || h.Mobile == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!h.Actor.IsIdle)
|
if (!h.Actor.IsIdle)
|
||||||
@@ -195,7 +195,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
// Tell the idle harvester to quit slacking:
|
// Tell the idle harvester to quit slacking:
|
||||||
var newSafeResourcePatch = FindNextResource(h.Actor, h);
|
var newSafeResourcePatch = FindNextResource(h.Actor, h);
|
||||||
AIUtils.BotDebug($"AI: Harvester {h.Actor} is idle. Ordering to {newSafeResourcePatch} in search for new resources.");
|
AIUtils.BotDebug($"AI: Harvester {h.Actor} is idle. Ordering to {newSafeResourcePatch} in search for new resources.");
|
||||||
if (newSafeResourcePatch != Target.Invalid)
|
if (newSafeResourcePatch.Type != TargetType.Invalid)
|
||||||
bot.QueueOrder(new Order("Harvest", h.Actor, newSafeResourcePatch, false));
|
bot.QueueOrder(new Order("Harvest", h.Actor, newSafeResourcePatch, false));
|
||||||
else
|
else
|
||||||
h.NoResourcesCooldown = Info.ScanIntervalMultiplerWhenNoResources;
|
h.NoResourcesCooldown = Info.ScanIntervalMultiplerWhenNoResources;
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
|
|||||||
new("Units", FieldSaver.FormatValue(Units.Select(a => a.ActorID).ToArray()))
|
new("Units", FieldSaver.FormatValue(Units.Select(a => a.ActorID).ToArray()))
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Target != Target.Invalid)
|
if (Target.Type != TargetType.Invalid)
|
||||||
{
|
{
|
||||||
nodes.Add(new MiniYamlNode("ActorToTarget", FieldSaver.FormatValue(TargetActor.ActorID)));
|
nodes.Add(new MiniYamlNode("ActorToTarget", FieldSaver.FormatValue(TargetActor.ActorID)));
|
||||||
nodes.Add(new MiniYamlNode("TargetOffset", FieldSaver.FormatValue(Target.CenterPosition - TargetActor.CenterPosition)));
|
nodes.Add(new MiniYamlNode("TargetOffset", FieldSaver.FormatValue(Target.CenterPosition - TargetActor.CenterPosition)));
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
Info.EnterCursor,
|
Info.EnterCursor,
|
||||||
Info.EnterBlockedCursor,
|
Info.EnterBlockedCursor,
|
||||||
() => Info.RequiresForceMove,
|
() => Info.RequiresForceMove,
|
||||||
DockingPossible,
|
CanQueueDockAt,
|
||||||
CanDockAt);
|
CanDockAt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,9 +109,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
string IOrderVoice.VoicePhraseForOrder(Actor self, Order order)
|
string IOrderVoice.VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "Dock" && CanDockAt(order.Target.Actor, false))
|
if (order.Target.Type != TargetType.Actor || IsTraitDisabled)
|
||||||
return Info.Voice;
|
return null;
|
||||||
else if (order.OrderString == "ForceDock" && CanDockAt(order.Target.Actor, true))
|
|
||||||
|
if (order.OrderString != "Dock" && order.OrderString != "ForceDock")
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (CanQueueDockAt(order.Target.Actor, order.OrderString == "ForceDock", order.Queued))
|
||||||
return Info.Voice;
|
return Info.Voice;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -125,12 +129,6 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Clone of <see cref="DockClientManager.DockingPossible(Actor, bool)"/>.</summary>
|
|
||||||
public bool DockingPossible(Actor target, bool forceEnter)
|
|
||||||
{
|
|
||||||
return !IsTraitDisabled && target.TraitsImplementing<DockHost>().Any(host => dockClients.Any(client => client.CanDock(host.GetDockType)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Clone of <see cref="DockClientManager.CanDockAt(Actor, bool, bool)"/>.</summary>
|
/// <summary>Clone of <see cref="DockClientManager.CanDockAt(Actor, bool, bool)"/>.</summary>
|
||||||
public bool CanDockAt(Actor target, bool forceEnter)
|
public bool CanDockAt(Actor target, bool forceEnter)
|
||||||
{
|
{
|
||||||
@@ -140,5 +138,16 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return !IsTraitDisabled && target.TraitsImplementing<DockHost>().Any(
|
return !IsTraitDisabled && target.TraitsImplementing<DockHost>().Any(
|
||||||
host => dockClients.Any(client => client.CanDockAt(target, host, forceEnter, true)));
|
host => dockClients.Any(client => client.CanDockAt(target, host, forceEnter, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Clone of <see cref="DockClientManager.CanQueueDockAt(Actor, bool, bool)"/>.</summary>
|
||||||
|
public bool CanQueueDockAt(Actor target, bool forceEnter, bool isQueued)
|
||||||
|
{
|
||||||
|
if (Info.RequiresForceMove && !forceEnter)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (!IsTraitDisabled)
|
||||||
|
&& target.TraitsImplementing<IDockHost>().Any(
|
||||||
|
host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (target != currentTarget)
|
if (target != currentTarget)
|
||||||
{
|
{
|
||||||
if (currentTargetManager != null)
|
if (currentTargetManager != null)
|
||||||
CancelCapture(currentTargetManager);
|
CancelCapture(currentTarget, currentTargetManager);
|
||||||
|
|
||||||
targetManager.currentCaptors.Add(self);
|
targetManager.currentCaptors.Add(self);
|
||||||
currentTarget = target;
|
currentTarget = target;
|
||||||
@@ -239,12 +239,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
/// This method revokes the capturing conditions on the captor and target
|
/// This method revokes the capturing conditions on the captor and target
|
||||||
/// and resets any capturing progress.
|
/// and resets any capturing progress.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CancelCapture(CaptureManager targetManager)
|
public void CancelCapture(Actor target, CaptureManager targetManager)
|
||||||
{
|
{
|
||||||
if (currentTarget == null)
|
if (currentTarget == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var target = targetManager.self;
|
|
||||||
foreach (var w in progressWatchers)
|
foreach (var w in progressWatchers)
|
||||||
w.Update(self, self, target, 0, 0);
|
w.Update(self, self, target, 0, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Allow deploying on specified charge to grant a condition for a specified duration.")]
|
[Desc("Grant a condition via player orders for a specified amount of time.")]
|
||||||
public class GrantConditionOnDeployWithChargeInfo : PausableConditionalTraitInfo, IRulesetLoaded
|
public class GrantChargedConditionOnToggleInfo : PausableConditionalTraitInfo, IRulesetLoaded
|
||||||
{
|
{
|
||||||
[FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
[GrantedConditionReference]
|
[GrantedConditionReference]
|
||||||
[Desc("The condition to grant after deploying.")]
|
[Desc("The condition to grant when enabled.")]
|
||||||
public readonly string DeployedCondition = null;
|
public readonly string ActivatedCondition = null;
|
||||||
|
|
||||||
[GrantedConditionReference]
|
[GrantedConditionReference]
|
||||||
[Desc("The condition to grant when charge is above " + nameof(ChargeThreshhold) + ".")]
|
[Desc("The condition to grant when charge is above " + nameof(ChargeThreshhold) + ".")]
|
||||||
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("Cooldown (in ticks) to reach full charge.")]
|
[Desc("Cooldown (in ticks) to reach full charge.")]
|
||||||
public readonly int ChargeDuration = 500;
|
public readonly int ChargeDuration = 500;
|
||||||
|
|
||||||
[Desc("The amount of charge that needs to be present for deploy to be issued. " +
|
[Desc("The amount of charge that needs to be present to turn on the condition. " +
|
||||||
"If set to -1, threshold is set to full charge. " +
|
"If set to -1, threshold is set to full charge. " +
|
||||||
"If activated without full charge " + nameof(ConditionDuration) + " is percentally smaller.")]
|
"If activated without full charge " + nameof(ConditionDuration) + " is percentally smaller.")]
|
||||||
public readonly int ChargeThreshhold = -1;
|
public readonly int ChargeThreshhold = -1;
|
||||||
@@ -43,30 +43,39 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("How long (in ticks) should the condition stay active?")]
|
[Desc("How long (in ticks) should the condition stay active?")]
|
||||||
public readonly int ConditionDuration = 1;
|
public readonly int ConditionDuration = 1;
|
||||||
|
|
||||||
[Desc("Can " + nameof(DeployedCondition) + " be canceled by followup deploy order?")]
|
[Desc("Can " + nameof(ActivatedCondition) + " be turned off manually?")]
|
||||||
public readonly bool CanCancelCondition = false;
|
public readonly bool CanCancelCondition = false;
|
||||||
|
|
||||||
[CursorReference]
|
[Desc("Should we interrupt the current activity")]
|
||||||
[Desc("Cursor to display when able to (un)deploy the actor.")]
|
public readonly bool CancelsCurrentActivity = false;
|
||||||
public readonly string DeployCursor = "deploy";
|
|
||||||
|
|
||||||
[CursorReference]
|
[CursorReference]
|
||||||
[Desc("Cursor to display when unable to (un)deploy the actor.")]
|
[Desc("Cursor to display when able to trigger a state change.")]
|
||||||
public readonly string DeployBlockedCursor = "deploy-blocked";
|
public readonly string Cursor = "deploy";
|
||||||
|
|
||||||
[Desc("Play a randomly selected sound from this list when deploying.")]
|
[CursorReference]
|
||||||
public readonly string[] DeploySounds = null;
|
[Desc("Cursor to display when unable to trigger a state change.")]
|
||||||
|
public readonly string BlockedCursor = "deploy-blocked";
|
||||||
|
|
||||||
[Desc("Play a randomly selected sound from this list when undeploying.")]
|
[Desc("Play a randomly selected sound from this list when turning on.")]
|
||||||
public readonly string[] UndeploySounds = null;
|
public readonly string[] ActivationSounds = null;
|
||||||
|
|
||||||
|
[Desc("Play a randomly selected sound from this list when turning off.")]
|
||||||
|
public readonly string[] DeactivattionSounds = null;
|
||||||
|
|
||||||
[VoiceReference]
|
[VoiceReference]
|
||||||
public readonly string Voice = "Action";
|
public readonly string Voice = "Action";
|
||||||
|
|
||||||
public readonly Color ChargingColor = Color.Magenta;
|
[Desc("Color of the charge bar when deactivated.")]
|
||||||
public readonly Color DeployedColor = Color.DarkMagenta;
|
public readonly Color DeactivatedColor = Color.Magenta;
|
||||||
|
|
||||||
public override object Create(ActorInitializer init) { return new GrantConditionOnDeployWithCharge(this); }
|
[Desc("Color of the charge bar when activated.")]
|
||||||
|
public readonly Color ActivatedColor = Color.DarkMagenta;
|
||||||
|
|
||||||
|
[Desc("Should the charge bar be displayed when not charged or the trait is disabled?")]
|
||||||
|
public readonly bool DisplayBarWhenEmpty = true;
|
||||||
|
|
||||||
|
public override object Create(ActorInitializer init) { return new GrantChargedConditionOnToggle(this); }
|
||||||
|
|
||||||
public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
|
public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
|
||||||
{
|
{
|
||||||
@@ -80,37 +89,37 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GrantConditionOnDeployWithCharge : PausableConditionalTrait<GrantConditionOnDeployWithChargeInfo>,
|
public class GrantChargedConditionOnToggle : PausableConditionalTrait<GrantChargedConditionOnToggleInfo>,
|
||||||
IIssueOrder, IResolveOrder, ITick, ISelectionBar, IOrderVoice, ISync, IIssueDeployOrder
|
IIssueOrder, IResolveOrder, ITick, ISelectionBar, IOrderVoice, ISync, IIssueDeployOrder
|
||||||
{
|
{
|
||||||
[Sync]
|
[Sync]
|
||||||
int chargeTick = 0;
|
int chargeTick = 0;
|
||||||
|
|
||||||
bool deployed = false;
|
bool isActive = false;
|
||||||
|
|
||||||
int deployedToken = Actor.InvalidConditionToken;
|
int activatedToken = Actor.InvalidConditionToken;
|
||||||
|
|
||||||
int chargedToken = Actor.InvalidConditionToken;
|
int chargedToken = Actor.InvalidConditionToken;
|
||||||
|
|
||||||
readonly int chargeThreshold;
|
readonly int chargeThreshold;
|
||||||
readonly int deployedChargeThreshold;
|
readonly int activatedChargeThreshold;
|
||||||
|
|
||||||
public GrantConditionOnDeployWithCharge(GrantConditionOnDeployWithChargeInfo info)
|
public GrantChargedConditionOnToggle(GrantChargedConditionOnToggleInfo info)
|
||||||
: base(info)
|
: base(info)
|
||||||
{
|
{
|
||||||
chargeTick = info.InitialCharge < 0 || info.InitialCharge >= info.ChargeDuration ? Info.ChargeDuration : info.InitialCharge;
|
chargeTick = info.InitialCharge < 0 || info.InitialCharge >= info.ChargeDuration ? Info.ChargeDuration : info.InitialCharge;
|
||||||
|
|
||||||
// PERF: Cache the conversions.
|
// PERF: Cache the conversions.
|
||||||
chargeThreshold = Info.ChargeThreshhold < 0 || Info.ChargeThreshhold > Info.ChargeDuration ? Info.ChargeDuration : Info.ChargeThreshhold;
|
chargeThreshold = Info.ChargeThreshhold < 0 || Info.ChargeThreshhold > Info.ChargeDuration ? Info.ChargeDuration : Info.ChargeThreshhold;
|
||||||
deployedChargeThreshold = chargeThreshold * Info.ConditionDuration / Info.ChargeDuration;
|
activatedChargeThreshold = chargeThreshold * Info.ConditionDuration / Info.ChargeDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void TraitDisabled(Actor self)
|
protected override void TraitDisabled(Actor self)
|
||||||
{
|
{
|
||||||
base.TraitDisabled(self);
|
base.TraitDisabled(self);
|
||||||
|
|
||||||
if (deployed)
|
if (isActive)
|
||||||
Undeploy(self);
|
Deactivate(self);
|
||||||
|
|
||||||
// Reset charge.
|
// Reset charge.
|
||||||
chargeTick = Info.InitialCharge < 0 || Info.InitialCharge > Info.ChargeDuration ? Info.ChargeDuration : Info.InitialCharge;
|
chargeTick = Info.InitialCharge < 0 || Info.InitialCharge > Info.ChargeDuration ? Info.ChargeDuration : Info.InitialCharge;
|
||||||
@@ -120,7 +129,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return order.OrderString == "DeployWithCharge" ? Info.Voice : null;
|
return order.OrderString == "ActivateCondition" ? Info.Voice : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
@@ -128,14 +137,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!IsTraitDisabled)
|
if (!IsTraitDisabled)
|
||||||
yield return new DeployOrderTargeter("DeployWithCharge", 5,
|
yield return new DeployOrderTargeter("ActivateCondition", 5,
|
||||||
() => CanDeploy() ? Info.DeployCursor : Info.DeployBlockedCursor);
|
() => CanToggle() ? Info.Cursor : Info.BlockedCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "DeployWithCharge")
|
if (order.OrderID == "ActivateCondition")
|
||||||
return new Order(order.OrderID, self, queued);
|
return new Order(order.OrderID, self, queued);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -143,55 +152,60 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued)
|
Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued)
|
||||||
{
|
{
|
||||||
return new Order("DeployWithCharge", self, queued);
|
return new Order("ActivateCondition", self, queued);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) { return queued || CanDeploy(); }
|
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) { return queued || CanToggle(); }
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "DeployWithCharge")
|
if (order.OrderString != "ActivateCondition")
|
||||||
self.QueueActivity(order.Queued, new DeployForGrantedConditionWithCharge(self, this));
|
return;
|
||||||
|
|
||||||
|
if (order.Queued || Info.CancelsCurrentActivity)
|
||||||
|
self.QueueActivity(order.Queued, new ToggleChargedCondition(self, this));
|
||||||
|
else if (CanToggle())
|
||||||
|
ToggleState(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanDeploy() => !IsTraitDisabled && !IsTraitPaused && ((!deployed && chargeTick >= chargeThreshold) || (deployed && Info.CanCancelCondition));
|
public bool CanToggle() => !IsTraitDisabled && !IsTraitPaused && ((!isActive && chargeTick >= chargeThreshold) || (isActive && Info.CanCancelCondition));
|
||||||
|
|
||||||
public void TriggerDeploy(Actor self)
|
public void ToggleState(Actor self)
|
||||||
{
|
{
|
||||||
if (deployed)
|
if (isActive)
|
||||||
{
|
{
|
||||||
// Keep the percentage of the unused charge.
|
// Keep the percentage of the unused charge.
|
||||||
chargeTick = chargeTick * Info.ChargeDuration / Info.ConditionDuration;
|
chargeTick = chargeTick * Info.ChargeDuration / Info.ConditionDuration;
|
||||||
Undeploy(self);
|
Deactivate(self);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If deployed without full charge, reduce the deploy duration.
|
// If activated without full charge, subtract from the activated duration.
|
||||||
chargeTick = chargeTick * Info.ConditionDuration / Info.ChargeDuration;
|
chargeTick = chargeTick * Info.ConditionDuration / Info.ChargeDuration;
|
||||||
Deploy(self);
|
Activate(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Deploy(Actor self)
|
void Activate(Actor self)
|
||||||
{
|
{
|
||||||
if (Info.DeploySounds != null && Info.DeploySounds.Length > 0)
|
if (Info.ActivationSounds != null && Info.ActivationSounds.Length > 0)
|
||||||
Game.Sound.Play(SoundType.World, Info.DeploySounds, self.World, self.CenterPosition);
|
Game.Sound.Play(SoundType.World, Info.ActivationSounds, self.World, self.CenterPosition);
|
||||||
|
|
||||||
if (deployedToken == Actor.InvalidConditionToken)
|
if (activatedToken == Actor.InvalidConditionToken)
|
||||||
deployedToken = self.GrantCondition(Info.DeployedCondition);
|
activatedToken = self.GrantCondition(Info.ActivatedCondition);
|
||||||
|
|
||||||
deployed = true;
|
isActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Undeploy(Actor self)
|
void Deactivate(Actor self)
|
||||||
{
|
{
|
||||||
if (Info.UndeploySounds != null && Info.UndeploySounds.Length > 0)
|
if (Info.DeactivattionSounds != null && Info.DeactivattionSounds.Length > 0)
|
||||||
Game.Sound.Play(SoundType.World, Info.UndeploySounds, self.World, self.CenterPosition);
|
Game.Sound.Play(SoundType.World, Info.DeactivattionSounds, self.World, self.CenterPosition);
|
||||||
|
|
||||||
if (deployedToken != Actor.InvalidConditionToken)
|
if (activatedToken != Actor.InvalidConditionToken)
|
||||||
deployedToken = self.RevokeCondition(deployedToken);
|
activatedToken = self.RevokeCondition(activatedToken);
|
||||||
|
|
||||||
deployed = false;
|
isActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ITick.Tick(Actor self)
|
void ITick.Tick(Actor self)
|
||||||
@@ -199,12 +213,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (IsTraitDisabled || IsTraitPaused)
|
if (IsTraitDisabled || IsTraitPaused)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (deployed)
|
if (isActive)
|
||||||
{
|
{
|
||||||
if (chargeTick > 0)
|
if (chargeTick > 0)
|
||||||
chargeTick--;
|
chargeTick--;
|
||||||
else
|
else
|
||||||
Undeploy(self);
|
Deactivate(self);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -214,7 +228,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
if (Info.ChargedCondition != null)
|
if (Info.ChargedCondition != null)
|
||||||
{
|
{
|
||||||
if (chargeTick < (deployed ? deployedChargeThreshold : chargeThreshold))
|
if (chargeTick < (isActive ? activatedChargeThreshold : chargeThreshold))
|
||||||
{
|
{
|
||||||
if (chargedToken != Actor.InvalidConditionToken)
|
if (chargedToken != Actor.InvalidConditionToken)
|
||||||
chargedToken = self.RevokeCondition(chargedToken);
|
chargedToken = self.RevokeCondition(chargedToken);
|
||||||
@@ -232,28 +246,28 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (IsTraitDisabled)
|
if (IsTraitDisabled)
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
return deployed
|
return isActive
|
||||||
? (float)chargeTick / Info.ConditionDuration
|
? (float)chargeTick / Info.ConditionDuration
|
||||||
: (float)chargeTick / Info.ChargeDuration;
|
: (float)chargeTick / Info.ChargeDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color ISelectionBar.GetColor() { return deployed ? Info.DeployedColor : Info.ChargingColor; }
|
Color ISelectionBar.GetColor() { return isActive ? Info.ActivatedColor : Info.DeactivatedColor; }
|
||||||
bool ISelectionBar.DisplayWhenEmpty => false;
|
bool ISelectionBar.DisplayWhenEmpty => Info.DisplayBarWhenEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DeployForGrantedConditionWithCharge : Activity
|
public class ToggleChargedCondition : Activity
|
||||||
{
|
{
|
||||||
readonly GrantConditionOnDeployWithCharge deploy;
|
readonly GrantChargedConditionOnToggle toggle;
|
||||||
|
|
||||||
public DeployForGrantedConditionWithCharge(Actor self, GrantConditionOnDeployWithCharge deploy)
|
public ToggleChargedCondition(Actor self, GrantChargedConditionOnToggle toggle)
|
||||||
{
|
{
|
||||||
this.deploy = deploy;
|
this.toggle = toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFirstRun(Actor self)
|
protected override void OnFirstRun(Actor self)
|
||||||
{
|
{
|
||||||
if (deploy.CanDeploy())
|
if (toggle.CanToggle())
|
||||||
deploy.TriggerDeploy(self);
|
toggle.ToggleState(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
||||||
@@ -37,9 +37,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public virtual bool CanDockAt(Actor hostActor, IDockHost host, bool forceEnter = false, bool ignoreOccupancy = false)
|
public virtual bool CanDockAt(Actor hostActor, IDockHost host, bool forceEnter = false, bool ignoreOccupancy = false)
|
||||||
{
|
{
|
||||||
return (forceEnter || self.Owner.IsAlliedWith(hostActor.Owner)) &&
|
return CanDock(host.GetDockType, forceEnter)
|
||||||
CanDock(host.GetDockType, forceEnter) &&
|
&& host.IsDockingPossible(self, this, ignoreOccupancy);
|
||||||
host.IsDockingPossible(self, this, ignoreOccupancy);
|
}
|
||||||
|
|
||||||
|
public virtual bool CanQueueDockAt(Actor hostActor, IDockHost host, bool forceEnter, bool isQueued)
|
||||||
|
{
|
||||||
|
return CanDock(host.GetDockType, true)
|
||||||
|
&& host.IsDockingPossible(self, this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnDockStarted(Actor self, Actor hostActor, IDockHost host) { }
|
public virtual void OnDockStarted(Actor self, Actor hostActor, IDockHost host) { }
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
Info.EnterCursor,
|
Info.EnterCursor,
|
||||||
Info.EnterBlockedCursor,
|
Info.EnterBlockedCursor,
|
||||||
() => requireForceMove,
|
() => requireForceMove,
|
||||||
DockingPossible,
|
CanQueueDockAt,
|
||||||
(target, forceEnter) => CanDockAt(target, forceEnter, true));
|
(target, forceEnter) => CanDockAt(target, forceEnter, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,9 +194,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (order.Target.Type != TargetType.Actor || IsTraitDisabled)
|
if (order.Target.Type != TargetType.Actor || IsTraitDisabled)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (order.OrderString == "Dock" && CanDockAt(order.Target.Actor, false, true))
|
if (order.OrderString != "Dock" && order.OrderString != "ForceDock")
|
||||||
return Info.Voice;
|
return null;
|
||||||
else if (order.OrderString == "ForceDock" && CanDockAt(order.Target.Actor, true, true))
|
|
||||||
|
if (CanQueueDockAt(order.Target.Actor, order.OrderString == "ForceDock", order.Queued))
|
||||||
return Info.Voice;
|
return Info.Voice;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -225,13 +226,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Do we have an enabled client with matching <paramref name="type"/>.</summary>
|
/// <summary>Do we have an enabled client with matching <paramref name="type"/>.</summary>
|
||||||
public bool DockingPossible(BitSet<DockType> type, bool forceEnter = false)
|
public bool CanDock(BitSet<DockType> type, bool forceEnter = false)
|
||||||
{
|
{
|
||||||
return !IsTraitDisabled && dockClients.Any(client => client.CanDock(type, forceEnter));
|
return !IsTraitDisabled && dockClients.Any(client => client.CanDock(type, forceEnter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Does this <paramref name="target"/> contain at least one enabled <see cref="IDockHost"/> with maching <see cref="DockType"/>.</summary>
|
/// <summary>Does this <paramref name="target"/> contain at least one enabled <see cref="IDockHost"/> with maching <see cref="DockType"/>.</summary>
|
||||||
public bool DockingPossible(Actor target, bool forceEnter = false)
|
public bool CanDock(Actor target, bool forceEnter = false)
|
||||||
{
|
{
|
||||||
return !IsTraitDisabled &&
|
return !IsTraitDisabled &&
|
||||||
target.TraitsImplementing<IDockHost>()
|
target.TraitsImplementing<IDockHost>()
|
||||||
@@ -252,6 +253,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
host => dockClients.Any(client => client.CanDockAt(target, host, forceEnter, ignoreOccupancy)));
|
host => dockClients.Any(client => client.CanDockAt(target, host, forceEnter, ignoreOccupancy)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Can we dock to this <paramref name="target"/>.</summary>
|
||||||
|
public bool CanQueueDockAt(Actor target, bool forceEnter, bool isQueued)
|
||||||
|
{
|
||||||
|
return !IsTraitDisabled
|
||||||
|
&& target.TraitsImplementing<IDockHost>()
|
||||||
|
.Any(host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued)));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Find the closest viable <see cref="IDockHost"/>.</summary>
|
/// <summary>Find the closest viable <see cref="IDockHost"/>.</summary>
|
||||||
/// <remarks>If <paramref name="type"/> is not set, scans all clients. Does not check if <see cref="DockClientManager"/> is enabled.</remarks>
|
/// <remarks>If <paramref name="type"/> is not set, scans all clients. Does not check if <see cref="DockClientManager"/> is enabled.</remarks>
|
||||||
public TraitPair<IDockHost>? ClosestDock(IDockHost ignore, BitSet<DockType> type = default, bool forceEnter = false, bool ignoreOccupancy = false)
|
public TraitPair<IDockHost>? ClosestDock(IDockHost ignore, BitSet<DockType> type = default, bool forceEnter = false, bool ignoreOccupancy = false)
|
||||||
@@ -292,11 +301,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
readonly string enterCursor;
|
readonly string enterCursor;
|
||||||
readonly string enterBlockedCursor;
|
readonly string enterBlockedCursor;
|
||||||
readonly Func<bool> requireForceMove;
|
readonly Func<bool> requireForceMove;
|
||||||
readonly Func<Actor, bool, bool> canTarget;
|
readonly Func<Actor, bool, bool, bool> canTarget;
|
||||||
readonly Func<Actor, bool, bool> useEnterCursor;
|
readonly Func<Actor, bool, bool> useEnterCursor;
|
||||||
|
|
||||||
public DockActorTargeter(int priority, string enterCursor, string enterBlockedCursor,
|
public DockActorTargeter(int priority, string enterCursor, string enterBlockedCursor,
|
||||||
Func<bool> requireForceMove, Func<Actor, bool, bool> canTarget, Func<Actor, bool, bool> useEnterCursor)
|
Func<bool> requireForceMove, Func<Actor, bool, bool, bool> canTarget, Func<Actor, bool, bool> useEnterCursor)
|
||||||
{
|
{
|
||||||
OrderID = "Dock";
|
OrderID = "Dock";
|
||||||
OrderPriority = priority;
|
OrderPriority = priority;
|
||||||
@@ -325,10 +334,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (requireForceMove() && !forceEnter)
|
if (requireForceMove() && !forceEnter)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!canTarget(target.Actor, forceEnter))
|
if (!canTarget(target.Actor, forceEnter, IsQueued))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cursor = useEnterCursor(target.Actor, forceEnter) ? enterCursor : enterBlockedCursor;
|
cursor = IsQueued || useEnterCursor(target.Actor, forceEnter)
|
||||||
|
? enterCursor
|
||||||
|
: enterBlockedCursor;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
&& (self.Owner == hostActor.Owner || (ignoreOccupancy && self.Owner.IsAlliedWith(hostActor.Owner)));
|
&& (self.Owner == hostActor.Owner || (ignoreOccupancy && self.Owner.IsAlliedWith(hostActor.Owner)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanQueueDockAt(Actor hostActor, IDockHost host, bool forceEnter, bool isQueued)
|
||||||
|
{
|
||||||
|
return base.CanQueueDockAt(hostActor, host, forceEnter, isQueued)
|
||||||
|
&& self.Owner.IsAlliedWith(hostActor.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateCondition(Actor self)
|
void UpdateCondition(Actor self)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Info.EmptyCondition))
|
if (string.IsNullOrEmpty(Info.EmptyCondition))
|
||||||
|
|||||||
@@ -87,11 +87,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
bool IsValidActor(Actor target)
|
bool IsValidActor(Actor target)
|
||||||
{
|
{
|
||||||
var instantlyRepairable = target.Info.TraitInfoOrDefault<InstantlyRepairableInfo>();
|
var instantlyRepairable = target.TraitOrDefault<InstantlyRepairable>();
|
||||||
if (instantlyRepairable == null)
|
if (instantlyRepairable == null || instantlyRepairable.IsTraitDisabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!instantlyRepairable.Types.IsEmpty && !instantlyRepairable.Types.Overlaps(Info.Types))
|
if (!instantlyRepairable.Info.Types.IsEmpty && !instantlyRepairable.Info.Types.Overlaps(Info.Types))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1000,6 +1000,23 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
foreach (var cell in rallyPoint)
|
foreach (var cell in rallyPoint)
|
||||||
QueueChild(new AttackMoveActivity(self, () => mobile.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed)));
|
QueueChild(new AttackMoveActivity(self, () => mobile.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Target> GetTargets(Actor self)
|
||||||
|
{
|
||||||
|
if (ChildActivity != null)
|
||||||
|
return ChildActivity.GetTargets(self);
|
||||||
|
|
||||||
|
return Target.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
||||||
|
{
|
||||||
|
var a = ChildActivity;
|
||||||
|
for (; a != null; a = a.NextActivity)
|
||||||
|
if (!a.IsCanceling)
|
||||||
|
foreach (var n in a.TargetLineNodes(self))
|
||||||
|
yield return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Activity ICreationActivity.GetCreationActivity()
|
Activity ICreationActivity.GetCreationActivity()
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
protected override void PrepareRender(WorldRenderer wr, IShader shader)
|
protected override void PrepareRender(WorldRenderer wr, IShader shader)
|
||||||
{
|
{
|
||||||
shader.SetVec("Blend", blend);
|
shader.SetVec("Blend", blend);
|
||||||
shader.SetVec("Color", (float)Info.Color.B / 255, (float)Info.Color.G / 255, (float)Info.Color.R / 255);
|
shader.SetVec("Color", (float)Info.Color.R / 255, (float)Info.Color.G / 255, (float)Info.Color.B / 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,12 +174,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
void UpdateNetWorth(string oldResourceType, int oldDensity, string newResourceType, int newDensity)
|
void UpdateNetWorth(string oldResourceType, int oldDensity, string newResourceType, int newDensity)
|
||||||
{
|
{
|
||||||
// Density + 1 as workaround for fixing ResourceLayer.Harvest as it would be very disruptive to balancing
|
|
||||||
if (oldResourceType != null && oldDensity > 0 && resourceValues.TryGetValue(oldResourceType, out var oldResourceValue))
|
if (oldResourceType != null && oldDensity > 0 && resourceValues.TryGetValue(oldResourceType, out var oldResourceValue))
|
||||||
NetWorth -= (oldDensity + 1) * oldResourceValue;
|
NetWorth -= oldDensity * oldResourceValue;
|
||||||
|
|
||||||
if (newResourceType != null && newDensity > 0 && resourceValues.TryGetValue(newResourceType, out var newResourceValue))
|
if (newResourceType != null && newDensity > 0 && resourceValues.TryGetValue(newResourceType, out var newResourceValue))
|
||||||
NetWorth += (newDensity + 1) * newResourceValue;
|
NetWorth += newDensity * newResourceValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CalculateRegionValue(CellRegion sourceRegion)
|
public int CalculateRegionValue(CellRegion sourceRegion)
|
||||||
@@ -188,39 +187,44 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
foreach (var cell in sourceRegion.CellCoords)
|
foreach (var cell in sourceRegion.CellCoords)
|
||||||
{
|
{
|
||||||
var mcell = cell.ToMPos(Map);
|
var mcell = cell.ToMPos(Map);
|
||||||
if (Map.Resources.Contains(mcell) && Map.Resources[mcell].Type != 0)
|
if (!Map.Resources.Contains(mcell))
|
||||||
{
|
continue;
|
||||||
resourceValueInRegion++;
|
|
||||||
var rcell = Map.Resources[mcell];
|
var resource = Map.Resources[mcell].Type;
|
||||||
if (ResourceTypesByIndex.TryGetValue(rcell.Type, out var resourceType) && resourceValues.TryGetValue(resourceType, out var resourceValuePerUnit))
|
if (resource != 0
|
||||||
|
&& ResourceTypesByIndex.TryGetValue(resource, out var resourceType)
|
||||||
|
&& resourceValues.TryGetValue(resourceType, out var resourceValuePerUnit))
|
||||||
resourceValueInRegion += Tiles[mcell].Density * resourceValuePerUnit;
|
resourceValueInRegion += Tiles[mcell].Density * resourceValuePerUnit;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return resourceValueInRegion;
|
return resourceValueInRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual int CalculateCellDensity(ResourceLayerContents contents, CPos c)
|
/// <summary>
|
||||||
|
/// Matches the logic in <see cref="ResourceLayer"/> trait.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual int CalculateCellDensity(ResourceLayerContents contents, CPos cell)
|
||||||
{
|
{
|
||||||
var resources = Map.Resources;
|
var resources = Map.Resources;
|
||||||
if (contents.Type == null || !info.ResourceTypes.TryGetValue(contents.Type, out var resourceInfo) || resources[c].Type != resourceInfo.ResourceIndex)
|
if (contents.Type == null || !info.ResourceTypes.TryGetValue(contents.Type, out var resourceInfo) || resources[cell].Type != resourceInfo.ResourceIndex)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!info.RecalculateResourceDensity)
|
if (!info.RecalculateResourceDensity)
|
||||||
return contents.Density.Clamp(1, resourceInfo.MaxDensity);
|
return contents.Density.Clamp(1, resourceInfo.MaxDensity);
|
||||||
|
|
||||||
// Set density based on the number of neighboring resources
|
// Set density based on the number of neighboring resources.
|
||||||
var adjacent = 0;
|
var adjacent = 0;
|
||||||
for (var u = -1; u < 2; u++)
|
var directions = CVec.Directions;
|
||||||
|
for (var i = 0; i < directions.Length; i++)
|
||||||
{
|
{
|
||||||
for (var v = -1; v < 2; v++)
|
var c = cell + directions[i];
|
||||||
{
|
if (resources.Contains(c) && resources[c].Type == resourceInfo.ResourceIndex)
|
||||||
var cell = c + new CVec(u, v);
|
++adjacent;
|
||||||
if (resources.Contains(cell) && resources[cell].Type == resourceInfo.ResourceIndex)
|
|
||||||
adjacent++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to have at least one resource in the cell.
|
||||||
|
// HACK: we should not be lerping to 9, as maximum adjacent resources is 8.
|
||||||
|
// HACK: it's too disruptive to fix.
|
||||||
return Math.Max(int2.Lerp(0, resourceInfo.MaxDensity, adjacent, 9), 1);
|
return Math.Max(int2.Lerp(0, resourceInfo.MaxDensity, adjacent, 9), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
public abstract class RenderPostProcessPassBase : IRenderPostProcessPass
|
public abstract class RenderPostProcessPassBase : IRenderPostProcessPass, INotifyActorDisposing
|
||||||
{
|
{
|
||||||
readonly Renderer renderer;
|
readonly Renderer renderer;
|
||||||
readonly IShader shader;
|
readonly IShader shader;
|
||||||
@@ -52,5 +52,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
protected abstract bool Enabled { get; }
|
protected abstract bool Enabled { get; }
|
||||||
protected abstract void PrepareRender(WorldRenderer wr, IShader shader);
|
protected abstract void PrepareRender(WorldRenderer wr, IShader shader);
|
||||||
|
|
||||||
|
void INotifyActorDisposing.Disposing(Actor self)
|
||||||
|
{
|
||||||
|
buffer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
++adjacent;
|
++adjacent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjacent includes the current cell, so is always >= 1
|
// We need to have at least one resource in the cell.
|
||||||
|
// HACK: we should not be lerping to 9, as maximum adjacent resources is 8.
|
||||||
|
// HACK: it's too disruptive to fix.
|
||||||
var density = Math.Max(int2.Lerp(0, resourceInfo.MaxDensity, adjacent, 9), 1);
|
var density = Math.Max(int2.Lerp(0, resourceInfo.MaxDensity, adjacent, 9), 1);
|
||||||
Content[cell] = new ResourceLayerContents(resource.Type, density);
|
Content[cell] = new ResourceLayerContents(resource.Type, density);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,19 +220,26 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
bool OnDockTick(Actor self, Actor hostActor, IDockHost dock);
|
bool OnDockTick(Actor self, Actor hostActor, IDockHost dock);
|
||||||
void OnDockCompleted(Actor self, Actor hostActor, IDockHost host);
|
void OnDockCompleted(Actor self, Actor hostActor, IDockHost host);
|
||||||
|
|
||||||
/// <summary>Is this client allowed to dock.</summary>
|
/// <summary>Are we allowed to dock.</summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Does not check if <see cref="Traits.DockClientManager"/> is enabled.
|
/// Does not check if <see cref="Traits.DockClientManager"/> is enabled.
|
||||||
/// Function should only be called from within <see cref="IDockClient"/> or <see cref="Traits.DockClientManager"/>.
|
/// Function should only be called from within <see cref="IDockClient"/> or <see cref="Traits.DockClientManager"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
bool CanDock(BitSet<DockType> type, bool forceEnter = false);
|
bool CanDock(BitSet<DockType> type, bool forceEnter = false);
|
||||||
|
|
||||||
/// <summary>Is this client allowed to dock to <paramref name="host"/>.</summary>
|
/// <summary>Are we allowed to dock to this <paramref name="host"/>.</summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Does not check if <see cref="Traits.DockClientManager"/> is enabled.
|
/// Does not check if <see cref="Traits.DockClientManager"/> is enabled.
|
||||||
/// Function should only be called from within <see cref="IDockClient"/> or <see cref="Traits.DockClientManager"/>.
|
/// Function should only be called from within <see cref="IDockClient"/> or <see cref="Traits.DockClientManager"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
bool CanDockAt(Actor hostActor, IDockHost host, bool forceEnter = false, bool ignoreOccupancy = false);
|
bool CanDockAt(Actor hostActor, IDockHost host, bool forceEnter = false, bool ignoreOccupancy = false);
|
||||||
|
|
||||||
|
/// <summary>Are we allowed to give a docking order for this <paramref name="host"/>.</summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Does not check if <see cref="Traits.DockClientManager"/> is enabled.
|
||||||
|
/// Function should only be called from within <see cref="IDockClient"/> or <see cref="Traits.DockClientManager"/>.
|
||||||
|
/// </remarks>
|
||||||
|
bool CanQueueDockAt(Actor hostActor, IDockHost host, bool forceEnter, bool isQueued);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IDockHostInfo : ITraitInfoInterface { }
|
public interface IDockHostInfo : ITraitInfoInterface { }
|
||||||
|
|||||||
@@ -35,8 +35,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
var palette = new ImmutablePalette(args[1], new[] { 0 }, Array.Empty<int>());
|
var palette = new ImmutablePalette(args[1], new[] { 0 }, Array.Empty<int>());
|
||||||
|
|
||||||
SequenceSet sequences;
|
SequenceSet sequences;
|
||||||
if (modData.DefaultTerrainInfo.ContainsKey(args[2]))
|
var tilesetUpper = args[2].ToUpperInvariant();
|
||||||
sequences = new SequenceSet(modData.ModFiles, modData, args[2], null);
|
if (modData.DefaultTerrainInfo.ContainsKey(tilesetUpper))
|
||||||
|
sequences = new SequenceSet(modData.ModFiles, modData, tilesetUpper, null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var mapPackage = new Folder(Platform.EngineDir).OpenPackage(args[2], modData.ModFiles);
|
var mapPackage = new Folder(Platform.EngineDir).OpenPackage(args[2], modData.ModFiles);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
|
|
||||||
foreach (var layout in chromeLayouts)
|
foreach (var layout in chromeLayouts)
|
||||||
{
|
{
|
||||||
var fluentFolder = layout.Key + "|languages";
|
var fluentFolder = layout.Key + "|fluent";
|
||||||
var fluentPackage = modData.ModFiles.OpenPackage(fluentFolder);
|
var fluentPackage = modData.ModFiles.OpenPackage(fluentFolder);
|
||||||
var fluentPath = Path.Combine(fluentPackage.Name, "chrome.ftl");
|
var fluentPath = Path.Combine(fluentPackage.Name, "chrome.ftl");
|
||||||
|
|
||||||
@@ -262,12 +262,23 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
&& !UpdateUtils.IsAlreadyExtracted(childNode.Value.Value)
|
&& !UpdateUtils.IsAlreadyExtracted(childNode.Value.Value)
|
||||||
&& childNode.Value.Value.Any(char.IsLetterOrDigit))
|
&& childNode.Value.Value.Any(char.IsLetterOrDigit))
|
||||||
{
|
{
|
||||||
var value = childNode.Value.Value
|
var replaced = false;
|
||||||
.Replace("\\n", "\n ")
|
var value = childNode.Value.Value;
|
||||||
|
if (value.Contains("\\n"))
|
||||||
|
{
|
||||||
|
value = value.Replace("\\n", "\n ");
|
||||||
|
replaced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value
|
||||||
.Replace("{", "<")
|
.Replace("{", "<")
|
||||||
.Replace("}", ">")
|
.Replace("}", ">")
|
||||||
.Trim().Trim('\n');
|
.Trim().Trim('\n');
|
||||||
|
|
||||||
|
// Preserve indentation
|
||||||
|
if (replaced)
|
||||||
|
value = "\n " + value;
|
||||||
|
|
||||||
validChildTypes.Add((childNode, childType.ToLowerInvariant(), value));
|
validChildTypes.Add((childNode, childType.ToLowerInvariant(), value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fluentPackage = modData.ModFiles.OpenPackage(modData.Manifest.Id + "|languages");
|
var fluentPackage = modData.ModFiles.OpenPackage(modData.Manifest.Id + "|fluent");
|
||||||
ExtractFromFile(Path.Combine(fluentPackage.Name, "rules.ftl"), modRules, traitInfos);
|
ExtractFromFile(Path.Combine(fluentPackage.Name, "rules.ftl"), modRules, traitInfos);
|
||||||
modRules.Save();
|
modRules.Save();
|
||||||
|
|
||||||
@@ -307,9 +307,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
if (string.IsNullOrEmpty(propertyValue) || UpdateUtils.IsAlreadyExtracted(propertyValue) || !propertyValue.Any(char.IsLetterOrDigit))
|
if (string.IsNullOrEmpty(propertyValue) || UpdateUtils.IsAlreadyExtracted(propertyValue) || !propertyValue.Any(char.IsLetterOrDigit))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var value = propertyValue
|
var replaced = false;
|
||||||
.Replace("\\n", "\n ")
|
var value = propertyValue;
|
||||||
.Trim().Trim('\n');
|
if (value.Contains("\\n"))
|
||||||
|
{
|
||||||
|
value = value.Replace("\\n", "\n ");
|
||||||
|
replaced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve indentation
|
||||||
|
value = (replaced ? "\n " : "") + value.Trim().Trim('\n');
|
||||||
|
|
||||||
var actorName = ToLowerActor(actor.Key);
|
var actorName = ToLowerActor(actor.Key);
|
||||||
var key = traitInfo;
|
var key = traitInfo;
|
||||||
|
|||||||
@@ -179,5 +179,11 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
OnChange();
|
OnChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Removed()
|
||||||
|
{
|
||||||
|
mixerSheet?.Dispose();
|
||||||
|
base.Removed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
{
|
{
|
||||||
Sprite hueSprite;
|
Sprite hueSprite;
|
||||||
Sprite pickerSprite;
|
Sprite pickerSprite;
|
||||||
|
Sheet hueSheet;
|
||||||
|
|
||||||
public HueSliderWidget() { }
|
public HueSliderWidget() { }
|
||||||
public HueSliderWidget(HueSliderWidget other)
|
public HueSliderWidget(HueSliderWidget other)
|
||||||
@@ -28,7 +29,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
{
|
{
|
||||||
base.Initialize(args);
|
base.Initialize(args);
|
||||||
|
|
||||||
var hueSheet = new Sheet(SheetType.BGRA, new Size(256, 1));
|
hueSheet = new Sheet(SheetType.BGRA, new Size(256, 1));
|
||||||
|
|
||||||
var buffer = new byte[4 * 256];
|
var buffer = new byte[4 * 256];
|
||||||
|
|
||||||
@@ -63,5 +64,11 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width - 1) - (int)pickerSprite.Size.X / 2, (rb.Height - (int)pickerSprite.Size.Y) / 2);
|
var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width - 1) - (int)pickerSprite.Size.X / 2, (rb.Height - (int)pickerSprite.Size.Y) / 2);
|
||||||
WidgetUtils.DrawSprite(pickerSprite, pos);
|
WidgetUtils.DrawSprite(pickerSprite, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Removed()
|
||||||
|
{
|
||||||
|
hueSheet?.Dispose();
|
||||||
|
base.Removed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
public LabelWidget DiagonalLabel;
|
public LabelWidget DiagonalLabel;
|
||||||
public LabelWidget ResourceCounterLabel;
|
public LabelWidget ResourceCounterLabel;
|
||||||
|
|
||||||
MapBlitFilters copyFilters = MapBlitFilters.All;
|
MapBlitFilters selectionFilters = MapBlitFilters.All;
|
||||||
EditorBlitSource? clipboard;
|
EditorBlitSource? clipboard;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
@@ -81,12 +81,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
worldRenderer,
|
worldRenderer,
|
||||||
clipboard.Value,
|
clipboard.Value,
|
||||||
resourceLayer,
|
resourceLayer,
|
||||||
() => copyFilters));
|
() => selectionFilters));
|
||||||
};
|
};
|
||||||
|
|
||||||
pasteButton.IsDisabled = () => clipboard == null;
|
pasteButton.IsDisabled = () => clipboard == null;
|
||||||
pasteButton.IsHighlighted = () => editor.CurrentBrush is EditorCopyPasteBrush;
|
pasteButton.IsHighlighted = () => editor.CurrentBrush is EditorCopyPasteBrush;
|
||||||
|
|
||||||
|
var deleteAreaSelectionButton = areaEditPanel.Get<ButtonWidget>("SELECTION_DELETE_BUTTON");
|
||||||
|
deleteAreaSelectionButton.OnClick = () => editor.DefaultBrush.DeleteSelection(selectionFilters);
|
||||||
|
|
||||||
var closeAreaSelectionButton = areaEditPanel.Get<ButtonWidget>("SELECTION_CANCEL_BUTTON");
|
var closeAreaSelectionButton = areaEditPanel.Get<ButtonWidget>("SELECTION_CANCEL_BUTTON");
|
||||||
closeAreaSelectionButton.OnClick = () => editor.DefaultBrush.ClearSelection(updateSelectedTab: true);
|
closeAreaSelectionButton.OnClick = () => editor.DefaultBrush.ClearSelection(updateSelectedTab: true);
|
||||||
|
|
||||||
@@ -102,15 +105,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
editorActorLayer,
|
editorActorLayer,
|
||||||
resourceLayer,
|
resourceLayer,
|
||||||
editor.DefaultBrush.Selection.Area,
|
editor.DefaultBrush.Selection.Area,
|
||||||
copyFilters);
|
selectionFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateCategoryPanel(MapBlitFilters copyFilter, CheckboxWidget checkbox)
|
void CreateCategoryPanel(MapBlitFilters copyFilter, CheckboxWidget checkbox)
|
||||||
{
|
{
|
||||||
checkbox.GetText = () => copyFilter.ToString();
|
checkbox.GetText = () => copyFilter.ToString();
|
||||||
checkbox.IsChecked = () => copyFilters.HasFlag(copyFilter);
|
checkbox.IsChecked = () => selectionFilters.HasFlag(copyFilter);
|
||||||
checkbox.IsVisible = () => true;
|
checkbox.IsVisible = () => true;
|
||||||
checkbox.OnClick = () => copyFilters ^= copyFilter;
|
checkbox.OnClick = () => selectionFilters ^= copyFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
readonly LabelWidget productionTime;
|
readonly LabelWidget productionTime;
|
||||||
readonly Widget productionPowerIcon;
|
readonly Widget productionPowerIcon;
|
||||||
readonly LabelWidget productionPower;
|
readonly LabelWidget productionPower;
|
||||||
|
readonly List<Sheet> sheets = new();
|
||||||
|
|
||||||
ActorInfo selectedActor;
|
ActorInfo selectedActor;
|
||||||
ScrollItemWidget firstItem;
|
ScrollItemWidget firstItem;
|
||||||
@@ -81,6 +82,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
defaultPortrait = new Png(modData.DefaultFileSystem.Open("encyclopedia/default.png"));
|
defaultPortrait = new Png(modData.DefaultFileSystem.Open("encyclopedia/default.png"));
|
||||||
var spriteBounds = new Rectangle(0, 0, defaultPortrait.Width, defaultPortrait.Height);
|
var spriteBounds = new Rectangle(0, 0, defaultPortrait.Width, defaultPortrait.Height);
|
||||||
var sheet = new Sheet(SheetType.BGRA, spriteBounds.Size.NextPowerOf2());
|
var sheet = new Sheet(SheetType.BGRA, spriteBounds.Size.NextPowerOf2());
|
||||||
|
sheets.Add(sheet);
|
||||||
sheet.CreateBuffer();
|
sheet.CreateBuffer();
|
||||||
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
||||||
portraitSprite = new Sprite(sheet, spriteBounds, TextureChannel.RGBA);
|
portraitSprite = new Sprite(sheet, spriteBounds, TextureChannel.RGBA);
|
||||||
@@ -304,5 +306,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
time = time * bi.BuildDurationModifier * pbi / 10000;
|
time = time * bi.BuildDurationModifier * pbi / 10000;
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
foreach (var sheet in sheets)
|
||||||
|
sheet.Dispose();
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -751,7 +751,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LobbyUtils.SetupNameWidget(template, client, orderManager, worldRenderer);
|
LobbyUtils.SetupNameWidget(template, client, orderManager, worldRenderer, map);
|
||||||
LobbyUtils.SetupTeamWidget(template, client);
|
LobbyUtils.SetupTeamWidget(template, client);
|
||||||
LobbyUtils.SetupHandicapWidget(template, client);
|
LobbyUtils.SetupHandicapWidget(template, client);
|
||||||
LobbyUtils.SetupSpawnWidget(template, client);
|
LobbyUtils.SetupSpawnWidget(template, client);
|
||||||
@@ -803,7 +803,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
LobbyUtils.SetupPlayerActionWidget(template, client, orderManager, worldRenderer,
|
LobbyUtils.SetupPlayerActionWidget(template, client, orderManager, worldRenderer,
|
||||||
lobby, () => panel = PanelType.Kick, () => panel = PanelType.Players);
|
lobby, () => panel = PanelType.Kick, () => panel = PanelType.Players);
|
||||||
else
|
else
|
||||||
LobbyUtils.SetupNameWidget(template, client, orderManager, worldRenderer);
|
LobbyUtils.SetupNameWidget(template, client, orderManager, worldRenderer, map);
|
||||||
|
|
||||||
if (client.IsAdmin)
|
if (client.IsAdmin)
|
||||||
LobbyUtils.SetupReadyWidget(template, client);
|
LobbyUtils.SetupReadyWidget(template, client);
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
[FluentReference]
|
[FluentReference]
|
||||||
const string Bots = "options-lobby-slot.bots";
|
const string Bots = "options-lobby-slot.bots";
|
||||||
|
|
||||||
|
[FluentReference]
|
||||||
|
const string BotPlayer = "label-bot-player";
|
||||||
|
|
||||||
[FluentReference]
|
[FluentReference]
|
||||||
const string BotsDisabled = "options-lobby-slot.bots-disabled";
|
const string BotsDisabled = "options-lobby-slot.bots-disabled";
|
||||||
|
|
||||||
@@ -75,7 +78,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
foreach (var b in map.PlayerActorInfo.TraitInfos<IBotInfo>())
|
foreach (var b in map.PlayerActorInfo.TraitInfos<IBotInfo>())
|
||||||
{
|
{
|
||||||
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
||||||
bots.Add(new SlotDropDownOption(FluentProvider.GetMessage(b.Name),
|
bots.Add(new SlotDropDownOption(map.GetMessage(b.Name),
|
||||||
$"slot_bot {slot.PlayerReference} {botController.Index} {b.Type}",
|
$"slot_bot {slot.PlayerReference} {botController.Index} {b.Type}",
|
||||||
() => client != null && client.Bot == b.Type));
|
() => client != null && client.Bot == b.Type));
|
||||||
}
|
}
|
||||||
@@ -425,14 +428,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
HideChildWidget(parent, "SLOT_OPTIONS");
|
HideChildWidget(parent, "SLOT_OPTIONS");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupNameWidget(Widget parent, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer)
|
public static void SetupNameWidget(Widget parent, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer, MapPreview map)
|
||||||
{
|
{
|
||||||
var label = parent.Get<LabelWidget>("NAME");
|
var label = parent.Get<LabelWidget>("NAME");
|
||||||
label.IsVisible = () => true;
|
label.IsVisible = () => true;
|
||||||
var font = Game.Renderer.Fonts[label.Font];
|
var font = Game.Renderer.Fonts[label.Font];
|
||||||
var name = c.IsBot ? FluentProvider.GetMessage(c.Name) : c.Name;
|
|
||||||
var text = WidgetUtils.TruncateText(name, label.Bounds.Width, font);
|
var clientName = new CachedTransform<MapStatus, string>(s =>
|
||||||
label.GetText = () => text;
|
{
|
||||||
|
var name = c.Name;
|
||||||
|
if (c.IsBot && !map.TryGetMessage(c.Name, out name))
|
||||||
|
name = FluentProvider.GetMessage(BotPlayer);
|
||||||
|
|
||||||
|
return WidgetUtils.TruncateText(name, label.Bounds.Width, font);
|
||||||
|
});
|
||||||
|
|
||||||
|
label.GetText = () => clientName.Update(map.Status);
|
||||||
|
|
||||||
SetupProfileWidget(parent, c, orderManager, worldRenderer);
|
SetupProfileWidget(parent, c, orderManager, worldRenderer);
|
||||||
}
|
}
|
||||||
@@ -450,8 +461,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
var closed = FluentProvider.GetMessage(Closed);
|
var closed = FluentProvider.GetMessage(Closed);
|
||||||
var open = FluentProvider.GetMessage(Open);
|
var open = FluentProvider.GetMessage(Open);
|
||||||
|
|
||||||
|
var clientName = new CachedTransform<MapStatus, string>(s =>
|
||||||
|
{
|
||||||
|
if (c.IsBot)
|
||||||
|
{
|
||||||
|
if (map.TryGetMessage(c.Name, out var message))
|
||||||
|
return message;
|
||||||
|
else
|
||||||
|
return FluentProvider.GetMessage(BotPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Name;
|
||||||
|
});
|
||||||
|
|
||||||
slot.GetText = () => truncated.Update(c != null ?
|
slot.GetText = () => truncated.Update(c != null ?
|
||||||
c.IsBot ? FluentProvider.GetMessage(c.Name) : c.Name
|
clientName.Update(map.Status)
|
||||||
: s.Closed ? closed : open);
|
: s.Closed ? closed : open);
|
||||||
|
|
||||||
slot.OnMouseDown = _ => ShowSlotDropDown(slot, s, c, orderManager, map, modData);
|
slot.OnMouseDown = _ => ShowSlotDropDown(slot, s, c, orderManager, map, modData);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
protected MenuType menuType = MenuType.Main;
|
protected MenuType menuType = MenuType.Main;
|
||||||
readonly Widget rootMenu;
|
readonly Widget rootMenu;
|
||||||
readonly ScrollPanelWidget newsPanel;
|
readonly ScrollPanelWidget newsPanel;
|
||||||
|
readonly int maxNewsHeight;
|
||||||
readonly Widget newsTemplate;
|
readonly Widget newsTemplate;
|
||||||
readonly LabelWidget newsStatus;
|
readonly LabelWidget newsStatus;
|
||||||
readonly ModData modData;
|
readonly ModData modData;
|
||||||
@@ -230,6 +231,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
newsPanel = Ui.LoadWidget<ScrollPanelWidget>("NEWS_PANEL", null, new WidgetArgs());
|
newsPanel = Ui.LoadWidget<ScrollPanelWidget>("NEWS_PANEL", null, new WidgetArgs());
|
||||||
newsTemplate = newsPanel.Get("NEWS_ITEM_TEMPLATE");
|
newsTemplate = newsPanel.Get("NEWS_ITEM_TEMPLATE");
|
||||||
newsPanel.RemoveChild(newsTemplate);
|
newsPanel.RemoveChild(newsTemplate);
|
||||||
|
maxNewsHeight = newsPanel.Bounds.Height;
|
||||||
|
|
||||||
newsStatus = newsPanel.Get<LabelWidget>("NEWS_STATUS");
|
newsStatus = newsPanel.Get<LabelWidget>("NEWS_STATUS");
|
||||||
SetNewsStatus(FluentProvider.GetMessage(LoadingNews));
|
SetNewsStatus(FluentProvider.GetMessage(LoadingNews));
|
||||||
@@ -416,10 +418,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
newsPanel.RemoveChildren();
|
newsPanel.RemoveChildren();
|
||||||
SetNewsStatus("");
|
SetNewsStatus("");
|
||||||
|
|
||||||
foreach (var i in newsItems)
|
foreach (var item in newsItems)
|
||||||
{
|
{
|
||||||
var item = i;
|
|
||||||
|
|
||||||
var newsItem = newsTemplate.Clone();
|
var newsItem = newsTemplate.Clone();
|
||||||
|
|
||||||
var titleLabel = newsItem.Get<LabelWidget>("TITLE");
|
var titleLabel = newsItem.Get<LabelWidget>("TITLE");
|
||||||
@@ -441,6 +441,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
newsPanel.AddChild(newsItem);
|
newsPanel.AddChild(newsItem);
|
||||||
newsPanel.Layout.AdjustChildren();
|
newsPanel.Layout.AdjustChildren();
|
||||||
|
newsPanel.Bounds.Height = Math.Min(newsPanel.ContentHeight, maxNewsHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,18 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
readonly ScrollItemWidget headerTemplate;
|
readonly ScrollItemWidget headerTemplate;
|
||||||
readonly ScrollItemWidget template;
|
readonly ScrollItemWidget template;
|
||||||
|
|
||||||
|
readonly Widget miniOptions;
|
||||||
|
readonly DropDownButtonWidget difficultyButton;
|
||||||
|
readonly DropDownButtonWidget gameSpeedButton;
|
||||||
|
readonly string unsetDifficulty;
|
||||||
|
readonly string defaultTooltop;
|
||||||
|
|
||||||
|
// For remembering options
|
||||||
|
// TODO: this should be persistent across game sessions
|
||||||
|
string selectedDifficulty;
|
||||||
|
string selectedGameSpeed;
|
||||||
|
|
||||||
|
bool minifiedOptions = true;
|
||||||
MapPreview selectedMap;
|
MapPreview selectedMap;
|
||||||
PlayingVideo playingVideo;
|
PlayingVideo playingVideo;
|
||||||
readonly Dictionary<string, string> missionOptions = new();
|
readonly Dictionary<string, string> missionOptions = new();
|
||||||
@@ -125,6 +137,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
stopInfoVideoButton.IsVisible = () => playingVideo == PlayingVideo.Info;
|
stopInfoVideoButton.IsVisible = () => playingVideo == PlayingVideo.Info;
|
||||||
stopInfoVideoButton.OnClick = () => StopVideo(videoPlayer);
|
stopInfoVideoButton.OnClick = () => StopVideo(videoPlayer);
|
||||||
|
|
||||||
|
miniOptions = widget.GetOrNull("MISSION_MINIFIED_OPTIONS");
|
||||||
|
if (miniOptions != null)
|
||||||
|
{
|
||||||
|
miniOptions.IsVisible = () => minifiedOptions;
|
||||||
|
difficultyButton = miniOptions.GetOrNull<DropDownButtonWidget>("DIFFICULTY");
|
||||||
|
gameSpeedButton = miniOptions.GetOrNull<DropDownButtonWidget>("GAMESPEED");
|
||||||
|
unsetDifficulty = FluentProvider.GetMessage(difficultyButton.Text);
|
||||||
|
defaultTooltop = FluentProvider.GetMessage(difficultyButton.TooltipText);
|
||||||
|
}
|
||||||
|
|
||||||
var allPreviews = new List<MapPreview>();
|
var allPreviews = new List<MapPreview>();
|
||||||
missionList.RemoveChildren();
|
missionList.RemoveChildren();
|
||||||
|
|
||||||
@@ -204,16 +226,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
};
|
};
|
||||||
|
|
||||||
var tabContainer = widget.Get("MISSION_TABS");
|
var tabContainer = widget.Get("MISSION_TABS");
|
||||||
tabContainer.IsVisible = () => true;
|
tabContainer.IsVisible = () => !minifiedOptions;
|
||||||
|
|
||||||
var optionsTab = tabContainer.Get<ButtonWidget>("OPTIONS_TAB");
|
var optionsTab = tabContainer.Get<ButtonWidget>("OPTIONS_TAB");
|
||||||
optionsTab.IsHighlighted = () => panel == PanelType.Options;
|
optionsTab.IsHighlighted = () => panel == PanelType.Options;
|
||||||
optionsTab.IsDisabled = () => false;
|
|
||||||
optionsTab.OnClick = () => panel = PanelType.Options;
|
optionsTab.OnClick = () => panel = PanelType.Options;
|
||||||
|
|
||||||
var missionTab = tabContainer.Get<ButtonWidget>("MISSIONINFO_TAB");
|
var missionTab = tabContainer.Get<ButtonWidget>("MISSIONINFO_TAB");
|
||||||
missionTab.IsHighlighted = () => panel == PanelType.MissionInfo;
|
missionTab.IsHighlighted = () => panel == PanelType.MissionInfo;
|
||||||
missionTab.IsDisabled = () => false;
|
|
||||||
missionTab.OnClick = () => panel = PanelType.MissionInfo;
|
missionTab.OnClick = () => panel = PanelType.MissionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,6 +339,44 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
.Where(o => o.IsVisible)
|
.Where(o => o.IsVisible)
|
||||||
.OrderBy(o => o.DisplayOrder).ToArray();
|
.OrderBy(o => o.DisplayOrder).ToArray();
|
||||||
|
|
||||||
|
minifiedOptions = allOptions.All(o => o.Id == "difficulty" || o.Id == "gamespeed");
|
||||||
|
if (minifiedOptions)
|
||||||
|
BuildMinifiedOptions(allOptions);
|
||||||
|
else
|
||||||
|
BuildOptions(allOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMapDifficulty(LobbyOption option)
|
||||||
|
{
|
||||||
|
selectedDifficulty ??= option.DefaultValue;
|
||||||
|
if (option.Values.ContainsKey(selectedDifficulty))
|
||||||
|
missionOptions[option.Id] = selectedDifficulty;
|
||||||
|
else
|
||||||
|
missionOptions[option.Id] = option.DefaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMapSpeed(LobbyOption option)
|
||||||
|
{
|
||||||
|
selectedGameSpeed ??= option.DefaultValue;
|
||||||
|
if (option.Values.ContainsKey(selectedGameSpeed))
|
||||||
|
missionOptions[option.Id] = selectedGameSpeed;
|
||||||
|
else
|
||||||
|
missionOptions[option.Id] = option.DefaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnOptionSelected(string optionId, string value)
|
||||||
|
{
|
||||||
|
// Only remember when the user manually changes the value
|
||||||
|
if (optionId == "difficulty")
|
||||||
|
selectedDifficulty = value;
|
||||||
|
else if (optionId == "gamespeed")
|
||||||
|
selectedGameSpeed = value;
|
||||||
|
|
||||||
|
missionOptions[optionId] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildOptions(LobbyOption[] allOptions)
|
||||||
|
{
|
||||||
Widget row = null;
|
Widget row = null;
|
||||||
var checkboxColumns = new Queue<CheckboxWidget>();
|
var checkboxColumns = new Queue<CheckboxWidget>();
|
||||||
var dropdownColumns = new Queue<DropDownButtonWidget>();
|
var dropdownColumns = new Queue<DropDownButtonWidget>();
|
||||||
@@ -364,6 +422,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
foreach (var option in allOptions.Where(o => o is not LobbyBooleanOption))
|
foreach (var option in allOptions.Where(o => o is not LobbyBooleanOption))
|
||||||
{
|
{
|
||||||
|
if (option.Id == "difficulty")
|
||||||
|
SetMapDifficulty(option);
|
||||||
|
else if (option.Id == "gamespeed")
|
||||||
|
SetMapSpeed(option);
|
||||||
|
else
|
||||||
missionOptions[option.Id] = option.DefaultValue;
|
missionOptions[option.Id] = option.DefaultValue;
|
||||||
|
|
||||||
if (dropdownColumns.Count == 0)
|
if (dropdownColumns.Count == 0)
|
||||||
@@ -378,8 +441,54 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
optionsContainer.AddChild(row);
|
optionsContainer.AddChild(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dropdown = dropdownColumns.Dequeue();
|
var val = dropdownColumns.Dequeue();
|
||||||
|
SetupDropdown(val, option);
|
||||||
|
|
||||||
|
var label = row.GetOrNull<LabelWidget>(val.Id + "_DESC");
|
||||||
|
if (label != null)
|
||||||
|
{
|
||||||
|
label.GetText = () => option.Name + ":";
|
||||||
|
label.IsVisible = () => true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildMinifiedOptions(LobbyOption[] allOptions)
|
||||||
|
{
|
||||||
|
if (difficultyButton != null)
|
||||||
|
{
|
||||||
|
var mapDifficulty = allOptions.FirstOrDefault(sld => sld.Id == "difficulty");
|
||||||
|
if (mapDifficulty != null)
|
||||||
|
{
|
||||||
|
SetMapDifficulty(mapDifficulty);
|
||||||
|
SetupDropdown(difficultyButton, mapDifficulty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
difficultyButton.IsDisabled = () => true;
|
||||||
|
difficultyButton.GetText = () => unsetDifficulty;
|
||||||
|
difficultyButton.GetTooltipText = () => defaultTooltop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameSpeedButton != null)
|
||||||
|
{
|
||||||
|
var gameSpeed = allOptions.FirstOrDefault(sld => sld.Id == "gamespeed");
|
||||||
|
if (gameSpeed != null)
|
||||||
|
{
|
||||||
|
SetMapSpeed(gameSpeed);
|
||||||
|
SetupDropdown(gameSpeedButton, gameSpeed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gameSpeedButton.IsDisabled = () => true;
|
||||||
|
gameSpeedButton.GetText = () => FluentProvider.GetMessage(NotAvailable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupDropdown(DropDownButtonWidget dropdown, LobbyOption option)
|
||||||
|
{
|
||||||
dropdown.GetText = () =>
|
dropdown.GetText = () =>
|
||||||
{
|
{
|
||||||
if (option.Values.TryGetValue(missionOptions[option.Id], out var value))
|
if (option.Values.TryGetValue(missionOptions[option.Id], out var value))
|
||||||
@@ -403,7 +512,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
ScrollItemWidget SetupItem(KeyValuePair<string, string> c, ScrollItemWidget template)
|
ScrollItemWidget SetupItem(KeyValuePair<string, string> c, ScrollItemWidget template)
|
||||||
{
|
{
|
||||||
bool IsSelected() => missionOptions[option.Id] == c.Key;
|
bool IsSelected() => missionOptions[option.Id] == c.Key;
|
||||||
void OnClick() => missionOptions[option.Id] = c.Key;
|
void OnClick() => OnOptionSelected(option.Id, c.Key);
|
||||||
|
|
||||||
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
var item = ScrollItemWidget.Setup(template, IsSelected, OnClick);
|
||||||
item.Get<LabelWidget>("LABEL").GetText = () => c.Value;
|
item.Get<LabelWidget>("LABEL").GetText = () => c.Value;
|
||||||
@@ -412,14 +521,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", option.Values.Count * 30, option.Values, SetupItem);
|
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", option.Values.Count * 30, option.Values, SetupItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
var label = row.GetOrNull<LabelWidget>(dropdown.Id + "_DESC");
|
|
||||||
if (label != null)
|
|
||||||
{
|
|
||||||
label.GetText = () => option.Name + ":";
|
|
||||||
label.IsVisible = () => true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float cachedSoundVolume;
|
float cachedSoundVolume;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BeaconLib;
|
using BeaconLib;
|
||||||
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Server;
|
using OpenRA.Server;
|
||||||
@@ -49,6 +50,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
[FluentReference("bots")]
|
[FluentReference("bots")]
|
||||||
const string BotsLabel = "label-bots-count";
|
const string BotsLabel = "label-bots-count";
|
||||||
|
|
||||||
|
[FluentReference]
|
||||||
|
const string BotPlayer = "label-bot-player";
|
||||||
|
|
||||||
[FluentReference("spectators")]
|
[FluentReference("spectators")]
|
||||||
const string SpectatorsLabel = "label-spectators-count";
|
const string SpectatorsLabel = "label-spectators-count";
|
||||||
|
|
||||||
@@ -604,14 +608,21 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
foreach (var option in kv.Value)
|
foreach (var option in kv.Value)
|
||||||
{
|
{
|
||||||
var o = option;
|
var o = option;
|
||||||
|
var playerName = new CachedTransform<(MapStatus, int, SpriteFont), string>(s =>
|
||||||
|
{
|
||||||
|
var name = o.IsBot
|
||||||
|
? currentMap.TryGetMessage(o.Name, out var msg) ? msg : FluentProvider.GetMessage(BotPlayer)
|
||||||
|
: o.Name;
|
||||||
|
|
||||||
|
return WidgetUtils.TruncateText(name, s.Item2, s.Item3);
|
||||||
|
});
|
||||||
|
|
||||||
var item = ScrollItemWidget.Setup(clientTemplate, () => false, () => { });
|
var item = ScrollItemWidget.Setup(clientTemplate, () => false, () => { });
|
||||||
if (!o.IsSpectator && server.Mod == modData.Manifest.Id)
|
if (!o.IsSpectator && server.Mod == modData.Manifest.Id)
|
||||||
{
|
{
|
||||||
var label = item.Get<LabelWidget>("LABEL");
|
var label = item.Get<LabelWidget>("LABEL");
|
||||||
var font = Game.Renderer.Fonts[label.Font];
|
var font = Game.Renderer.Fonts[label.Font];
|
||||||
var name = WidgetUtils.TruncateText(o.Name, label.Bounds.Width, font);
|
label.GetText = () => playerName.Update((currentMap.Status, label.Bounds.Width, font));
|
||||||
label.GetText = () => name;
|
|
||||||
label.GetColor = () => o.Color;
|
label.GetColor = () => o.Color;
|
||||||
|
|
||||||
var flag = item.Get<ImageWidget>("FLAG");
|
var flag = item.Get<ImageWidget>("FLAG");
|
||||||
@@ -623,11 +634,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
var label = item.Get<LabelWidget>("NOFLAG_LABEL");
|
var label = item.Get<LabelWidget>("NOFLAG_LABEL");
|
||||||
var font = Game.Renderer.Fonts[label.Font];
|
var font = Game.Renderer.Fonts[label.Font];
|
||||||
var name = WidgetUtils.TruncateText(o.Name, label.Bounds.Width, font);
|
|
||||||
|
|
||||||
// Force spectator color to prevent spoofing by the server
|
// Force spectator color to prevent spoofing by the server
|
||||||
var color = o.IsSpectator ? Color.White : o.Color;
|
var color = o.IsSpectator ? Color.White : o.Color;
|
||||||
label.GetText = () => name;
|
label.GetText = () => playerName.Update((currentMap.Status, label.Bounds.Width, font));
|
||||||
label.GetColor = () => color;
|
label.GetColor = () => color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,14 +771,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
if (game.Clients.Length > 0)
|
if (game.Clients.Length > 0)
|
||||||
{
|
{
|
||||||
var displayClients = game.Clients.Select(c => c.Name);
|
var preview = modData.MapCache[game.Map];
|
||||||
|
var tooltip = new CachedTransform<MapStatus, string>(s =>
|
||||||
|
{
|
||||||
|
var displayClients = game.Clients.Select(c => c.IsBot
|
||||||
|
? preview.TryGetMessage(c.Name, out var msg) ? msg : FluentProvider.GetMessage(BotPlayer)
|
||||||
|
: c.Name);
|
||||||
|
|
||||||
if (game.Clients.Length > 10)
|
if (game.Clients.Length > 10)
|
||||||
displayClients = displayClients
|
displayClients = displayClients
|
||||||
.Take(9)
|
.Take(9)
|
||||||
.Append(FluentProvider.GetMessage(OtherPlayers, "players", game.Clients.Length - 9));
|
.Append(FluentProvider.GetMessage(OtherPlayers, "players", game.Clients.Length - 9));
|
||||||
|
|
||||||
var tooltip = displayClients.JoinWith("\n");
|
return displayClients.JoinWith("\n");
|
||||||
players.GetTooltipText = () => tooltip;
|
});
|
||||||
|
|
||||||
|
players.GetTooltipText = () => tooltip.Update(preview.Status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
players.GetTooltipText = null;
|
players.GetTooltipText = null;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
readonly Stopwatch playTime = new();
|
readonly Stopwatch playTime = new();
|
||||||
int textureWidth;
|
int textureWidth;
|
||||||
int textureHeight;
|
int textureHeight;
|
||||||
|
Sheet videoSheet;
|
||||||
|
|
||||||
Action onComplete;
|
Action onComplete;
|
||||||
|
|
||||||
@@ -123,7 +124,8 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
|
|
||||||
textureWidth = Exts.NextPowerOf2(video.Width);
|
textureWidth = Exts.NextPowerOf2(video.Width);
|
||||||
textureHeight = Exts.NextPowerOf2(video.Height);
|
textureHeight = Exts.NextPowerOf2(video.Height);
|
||||||
var videoSheet = new Sheet(SheetType.BGRA, new Size(textureWidth, textureHeight));
|
videoSheet?.Dispose();
|
||||||
|
videoSheet = new Sheet(SheetType.BGRA, new Size(textureWidth, textureHeight));
|
||||||
|
|
||||||
videoSheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
videoSheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
||||||
videoSheet.GetTexture().SetData(video.CurrentFrameData, textureWidth, textureHeight);
|
videoSheet.GetTexture().SetData(video.CurrentFrameData, textureWidth, textureHeight);
|
||||||
@@ -301,5 +303,11 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
Stop();
|
Stop();
|
||||||
Video = null;
|
Video = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Removed()
|
||||||
|
{
|
||||||
|
videoSheet?.Dispose();
|
||||||
|
overlaySheet?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj" />
|
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj" />
|
||||||
<PackageReference Include="OpenRA-Freetype6" Version="1.0.11" />
|
<PackageReference Include="OpenRA-Freetype6" Version="1.0.11" />
|
||||||
<PackageReference Include="OpenRA-OpenAL-CS" Version="1.0.22" />
|
<PackageReference Include="OpenRA-OpenAL-CS" Version="1.0.22" />
|
||||||
<PackageReference Include="OpenRA-SDL2-CS" Version="1.0.41" />
|
<PackageReference Include="OpenRA-SDL2-CS" Version="1.0.42" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="OpenRA.Platforms.Default.dll.config" Condition="'$(TargetPlatform)' != 'win-x64' And '$(TargetPlatform)' != 'win-x86'">
|
<Content Include="OpenRA.Platforms.Default.dll.config" Condition="'$(TargetPlatform)' != 'win-x64' And '$(TargetPlatform)' != 'win-x86'">
|
||||||
|
|||||||
@@ -341,6 +341,14 @@ namespace OpenRA.Platforms.Default
|
|||||||
// Run graphics rendering on a dedicated thread.
|
// Run graphics rendering on a dedicated thread.
|
||||||
// The calling thread will then have more time to process other tasks, since rendering happens in parallel.
|
// The calling thread will then have more time to process other tasks, since rendering happens in parallel.
|
||||||
// If the calling thread is the main game thread, this means it can run more logic and render ticks.
|
// If the calling thread is the main game thread, this means it can run more logic and render ticks.
|
||||||
|
// This is disabled when running in windowed mode on Windows because it breaks the ability to minimize/restore the window.
|
||||||
|
if (Platform.CurrentPlatform == PlatformType.Windows && windowMode == WindowMode.Windowed)
|
||||||
|
{
|
||||||
|
var ctx = new Sdl2GraphicsContext(this);
|
||||||
|
ctx.InitializeOpenGL();
|
||||||
|
Context = ctx;
|
||||||
|
}
|
||||||
|
else
|
||||||
Context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), vertexBatchSize, indexBatchSize);
|
Context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), vertexBatchSize, indexBatchSize);
|
||||||
|
|
||||||
Context.SetVSyncEnabled(Game.Settings.Graphics.VSync);
|
Context.SetVSyncEnabled(Game.Settings.Graphics.VSync);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
</AssemblyAttribute>
|
</AssemblyAttribute>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenRA-SDL2-CS" Version="1.0.41" />
|
<PackageReference Include="OpenRA-SDL2-CS" Version="1.0.42" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj" />
|
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj" />
|
||||||
|
|||||||
@@ -73,26 +73,26 @@ vec4 linear2srgb(vec4 c)
|
|||||||
return c.a * vec4(linear2srgb(c.r / c.a), linear2srgb(c.g / c.a), linear2srgb(c.b / c.a), 1.0f);
|
return c.a * vec4(linear2srgb(c.r / c.a), linear2srgb(c.g / c.a), linear2srgb(c.b / c.a), 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
ivec2 Size(uint samplerIndex)
|
vec2 Size(uint samplerIndex)
|
||||||
{
|
{
|
||||||
switch (samplerIndex)
|
switch (samplerIndex)
|
||||||
{
|
{
|
||||||
case 7u:
|
case 7u:
|
||||||
return textureSize(Texture7, 0);
|
return vec2(textureSize(Texture7, 0));
|
||||||
case 6u:
|
case 6u:
|
||||||
return textureSize(Texture6, 0);
|
return vec2(textureSize(Texture6, 0));
|
||||||
case 5u:
|
case 5u:
|
||||||
return textureSize(Texture5, 0);
|
return vec2(textureSize(Texture5, 0));
|
||||||
case 4u:
|
case 4u:
|
||||||
return textureSize(Texture4, 0);
|
return vec2(textureSize(Texture4, 0));
|
||||||
case 3u:
|
case 3u:
|
||||||
return textureSize(Texture3, 0);
|
return vec2(textureSize(Texture3, 0));
|
||||||
case 2u:
|
case 2u:
|
||||||
return textureSize(Texture2, 0);
|
return vec2(textureSize(Texture2, 0));
|
||||||
case 1u:
|
case 1u:
|
||||||
return textureSize(Texture1, 0);
|
return vec2(textureSize(Texture1, 0));
|
||||||
default:
|
default:
|
||||||
return textureSize(Texture0, 0);
|
return vec2(textureSize(Texture0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ void main()
|
|||||||
vec4 c;
|
vec4 c;
|
||||||
if (EnablePixelArtScaling)
|
if (EnablePixelArtScaling)
|
||||||
{
|
{
|
||||||
vec2 textureSize = vec2(Size(vChannelSampler));
|
vec2 textureSize = Size(vChannelSampler);
|
||||||
vec2 vUv = coords.st * textureSize;
|
vec2 vUv = coords.st * textureSize;
|
||||||
vec2 offset = fract(vUv);
|
vec2 offset = fract(vUv);
|
||||||
vec2 pixelsPerTexel = vec2(1.0 / dFdx(vUv.x), 1.0 / dFdy(vUv.y));
|
vec2 pixelsPerTexel = vec2(1.0 / dFdx(vUv.x), 1.0 / dFdy(vUv.y));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Metadata:
|
Metadata:
|
||||||
Title: All mods
|
Title: All mods
|
||||||
Version: {DEV_VERSION}
|
Version: release-20250330
|
||||||
Hidden: true
|
Hidden: true
|
||||||
|
|
||||||
FileSystem: DefaultFileSystem
|
FileSystem: DefaultFileSystem
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Metadata:
|
Metadata:
|
||||||
Title: mod-title
|
Title: mod-title
|
||||||
Version: {DEV_VERSION}
|
Version: release-20250330
|
||||||
Hidden: true
|
Hidden: true
|
||||||
|
|
||||||
FileSystem: DefaultFileSystem
|
FileSystem: DefaultFileSystem
|
||||||
|
|||||||
@@ -284,29 +284,27 @@ ScrollPanel@NEWS_PANEL:
|
|||||||
Width: 400
|
Width: 400
|
||||||
Height: 265
|
Height: 265
|
||||||
Background: panel-black
|
Background: panel-black
|
||||||
TopBottomSpacing: 5
|
TopBottomSpacing: 10
|
||||||
ItemSpacing: 5
|
ItemSpacing: 5
|
||||||
Children:
|
Children:
|
||||||
Container@NEWS_ITEM_TEMPLATE:
|
Container@NEWS_ITEM_TEMPLATE:
|
||||||
X: 10
|
X: 10
|
||||||
Y: 5
|
|
||||||
Width: PARENT_WIDTH - 40
|
Width: PARENT_WIDTH - 40
|
||||||
Height: 45
|
Height: 40
|
||||||
Children:
|
Children:
|
||||||
Label@TITLE:
|
Label@TITLE:
|
||||||
Y: 1
|
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 20
|
||||||
Align: Center
|
Align: Center
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Label@AUTHOR_DATETIME:
|
Label@AUTHOR_DATETIME:
|
||||||
Y: 26
|
Y: 21
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 15
|
Height: 15
|
||||||
Align: Center
|
Align: Center
|
||||||
Font: TinyBold
|
Font: TinyBold
|
||||||
Label@CONTENT:
|
Label@CONTENT:
|
||||||
Y: 46
|
Y: 40
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Label@NEWS_STATUS:
|
Label@NEWS_STATUS:
|
||||||
X: 80
|
X: 80
|
||||||
|
|||||||
@@ -439,7 +439,7 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
Y: 1
|
Y: 1
|
||||||
Width: 55
|
Width: 55
|
||||||
Height: 25
|
Height: 25
|
||||||
Text: label-tools-bg-categories
|
Text: label-tool-bg-category
|
||||||
Align: Right
|
Align: Right
|
||||||
Font: TinyBold
|
Font: TinyBold
|
||||||
DropDownButton@TOOLS_DROPDOWN:
|
DropDownButton@TOOLS_DROPDOWN:
|
||||||
@@ -634,7 +634,7 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: label-copy-filters
|
Text: label-selection-filters
|
||||||
Checkbox@COPY_FILTER_TERRAIN_CHECKBOX:
|
Checkbox@COPY_FILTER_TERRAIN_CHECKBOX:
|
||||||
X: 7
|
X: 7
|
||||||
Y: 70
|
Y: 70
|
||||||
@@ -688,6 +688,17 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
Width: 55
|
Width: 55
|
||||||
Height: 22
|
Height: 22
|
||||||
Align: Left
|
Align: Left
|
||||||
|
Button@SELECTION_DELETE_BUTTON:
|
||||||
|
X: 7
|
||||||
|
Y: 222
|
||||||
|
Width: 75
|
||||||
|
Height: 25
|
||||||
|
Text: button-delete-area.label
|
||||||
|
Font: Bold
|
||||||
|
Key: EditorDeleteSelection
|
||||||
|
TooltipTemplate: BUTTON_TOOLTIP
|
||||||
|
TooltipText: button-delete-area.tooltip
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Button@SELECTION_CANCEL_BUTTON:
|
Button@SELECTION_CANCEL_BUTTON:
|
||||||
X: 208
|
X: 208
|
||||||
Y: 222
|
Y: 222
|
||||||
@@ -779,8 +790,12 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
X: 7
|
X: 7
|
||||||
Width: 75
|
Width: 75
|
||||||
Height: 25
|
Height: 25
|
||||||
Text: button-container-delete
|
Text: button-delete-actor.label
|
||||||
Font: Bold
|
Font: Bold
|
||||||
|
Key: EditorDeleteSelection
|
||||||
|
TooltipTemplate: BUTTON_TOOLTIP
|
||||||
|
TooltipText: button-delete-actor.tooltip
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Button@CANCEL_BUTTON:
|
Button@CANCEL_BUTTON:
|
||||||
X: 127
|
X: 127
|
||||||
Width: 75
|
Width: 75
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Container@SKIRMISH_STATS:
|
|||||||
Width: 80
|
Width: 80
|
||||||
Height: 20
|
Height: 20
|
||||||
Font: MediumBold
|
Font: MediumBold
|
||||||
Text: label-objective-mission
|
Text: label-mission-objective
|
||||||
Label@STATS_STATUS:
|
Label@STATS_STATUS:
|
||||||
X: 95
|
X: 95
|
||||||
Y: 17
|
Y: 17
|
||||||
@@ -25,7 +25,7 @@ Container@SKIRMISH_STATS:
|
|||||||
Width: 482
|
Width: 482
|
||||||
Height: 20
|
Height: 20
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Text: checkbox-objective-stats
|
Text: checkbox-stats-objective
|
||||||
Disabled: true
|
Disabled: true
|
||||||
TextColorDisabled: FFFFFF
|
TextColorDisabled: FFFFFF
|
||||||
Container@STATS_HEADERS:
|
Container@STATS_HEADERS:
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ Container@OBSERVER_WIDGETS:
|
|||||||
Align: Right
|
Align: Right
|
||||||
Shadow: True
|
Shadow: True
|
||||||
Label@DERRICKS_HEADER:
|
Label@DERRICKS_HEADER:
|
||||||
X: 650
|
X: 645
|
||||||
Width: 80
|
Width: 80
|
||||||
Height: PARENT_HEIGHT
|
Height: PARENT_HEIGHT
|
||||||
Font: Bold
|
Font: Bold
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ Background@KICK_CLIENT_DIALOG:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-kick-client-dialog-texta
|
Text: label-kick-client-dialog-text-a
|
||||||
Label@TEXTB:
|
Label@TEXTB:
|
||||||
Y: 86
|
Y: 86
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-kick-client-dialog-textb
|
Text: label-kick-client-dialog-text-b
|
||||||
Checkbox@PREVENT_REJOINING_CHECKBOX:
|
Checkbox@PREVENT_REJOINING_CHECKBOX:
|
||||||
X: (PARENT_WIDTH - WIDTH) / 2
|
X: (PARENT_WIDTH - WIDTH) / 2
|
||||||
Y: 120
|
Y: 120
|
||||||
@@ -98,14 +98,14 @@ Background@FORCE_START_DIALOG:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-force-start-dialog-texta
|
Text: label-force-start-dialog-text-a
|
||||||
Label@TEXTB:
|
Label@TEXTB:
|
||||||
Y: 86
|
Y: 86
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-force-start-dialog-textb
|
Text: label-force-start-dialog-text-b
|
||||||
Container@KICK_WARNING:
|
Container@KICK_WARNING:
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Children:
|
Children:
|
||||||
|
|||||||
@@ -256,8 +256,8 @@ Container@LOBBY_PLAYER_BIN:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Text: label-lobby-players-faction
|
Text: label-lobby-players-faction
|
||||||
Label@TEAM:
|
Label@TEAM:
|
||||||
X: 435
|
X: 425
|
||||||
Width: 44
|
Width: 45
|
||||||
Height: 25
|
Height: 25
|
||||||
Align: Center
|
Align: Center
|
||||||
DropDownButton@TEAM_DROPDOWN:
|
DropDownButton@TEAM_DROPDOWN:
|
||||||
|
|||||||
@@ -68,6 +68,44 @@ Container@MISSIONBROWSER_PANEL:
|
|||||||
IgnoreMouseOver: True
|
IgnoreMouseOver: True
|
||||||
IgnoreMouseInput: True
|
IgnoreMouseInput: True
|
||||||
ShowSpawnPoints: False
|
ShowSpawnPoints: False
|
||||||
|
Container@MISSION_MINIFIED_OPTIONS:
|
||||||
|
Width: PARENT_WIDTH
|
||||||
|
Height: PARENT_HEIGHT
|
||||||
|
Visible: False
|
||||||
|
Children:
|
||||||
|
LabelForInput@DIFFICULTY_DESC:
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT + 2
|
||||||
|
Width: 56
|
||||||
|
Height: 25
|
||||||
|
Align: Right
|
||||||
|
Text: dropdown-missionbrowser-difficulty.label
|
||||||
|
For: DIFFICULTY
|
||||||
|
DropDownButton@DIFFICULTY:
|
||||||
|
X: 61
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT + 2
|
||||||
|
Width: 120
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
|
Text: label-missionbrowser-normal-difficulty
|
||||||
|
TooltipText: dropdown-missionbrowser-difficulty.description
|
||||||
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
|
LabelForInput@GAMESPEED_DESC:
|
||||||
|
X: PARENT_WIDTH - WIDTH - 125
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT + 2
|
||||||
|
Width: 120
|
||||||
|
Height: 25
|
||||||
|
Align: Right
|
||||||
|
Text: dropdown-missionbrowser-gamespeed
|
||||||
|
For: GAMESPEED
|
||||||
|
DropDownButton@GAMESPEED:
|
||||||
|
X: PARENT_WIDTH - WIDTH
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT + 2
|
||||||
|
Width: 120
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Container@MISSION_TABS:
|
Container@MISSION_TABS:
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Y: PARENT_HEIGHT - 31
|
Y: PARENT_HEIGHT - 31
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ Container@ADVANCED_PANEL:
|
|||||||
Font: Regular
|
Font: Regular
|
||||||
Text: checkbox-sendsysinfo-container
|
Text: checkbox-sendsysinfo-container
|
||||||
Label@SENDSYSINFO_DESC:
|
Label@SENDSYSINFO_DESC:
|
||||||
Y: 15
|
Y: 30
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 30
|
Height: 30
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
## world
|
## world
|
||||||
dropdown-difficulty =
|
dropdown-difficulty =
|
||||||
.label = Difficulty
|
.label = Difficulty
|
||||||
.description = The difficulty of the mission.
|
.description = The difficulty of the mission
|
||||||
|
|
||||||
options-difficulty =
|
options-difficulty =
|
||||||
.easy = Easy
|
.easy = Easy
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ label-save-map-background-directory = Directory:
|
|||||||
label-save-map-background-filename = Filename:
|
label-save-map-background-filename = Filename:
|
||||||
button-save-map-panel = Save
|
button-save-map-panel = Save
|
||||||
label-actor-edit-panel-id = ID
|
label-actor-edit-panel-id = ID
|
||||||
button-container-delete = Delete
|
|
||||||
button-container-ok = OK
|
button-container-ok = OK
|
||||||
button-editor-world-root-options-tooltip = Menu
|
button-editor-world-root-options-tooltip = Menu
|
||||||
label-tiles-bg-search = Search:
|
label-tiles-bg-search = Search:
|
||||||
@@ -66,11 +65,11 @@ label-area-selection = Area Selection
|
|||||||
label-area-info = Area Info
|
label-area-info = Area Info
|
||||||
label-selected-area-diagonal = Diagonal:
|
label-selected-area-diagonal = Diagonal:
|
||||||
label-selected-area-resources = Resources:
|
label-selected-area-resources = Resources:
|
||||||
label-copy-filters = Copy Filters
|
label-selection-filters = Filters
|
||||||
label-filter-terrain = Terrain
|
label-filter-terrain = Terrain
|
||||||
label-filter-resources = Resources
|
label-filter-resources = Resources
|
||||||
label-filter-actors = Actors
|
label-filter-actors = Actors
|
||||||
label-tools-bg-categories = Tool:
|
label-tool-bg-category = Tool:
|
||||||
button-marker-tiles-clear-current = Clear Current
|
button-marker-tiles-clear-current = Clear Current
|
||||||
button-marker-tiles-clear-all = Clear All
|
button-marker-tiles-clear-all = Clear All
|
||||||
label-marker-layer-num-sides = Number of Sides
|
label-marker-layer-num-sides = Number of Sides
|
||||||
@@ -85,6 +84,14 @@ button-map-editor-tab-container-actors-tooltip = Actors
|
|||||||
button-map-editor-tab-container-tools-tooltip = Tools
|
button-map-editor-tab-container-tools-tooltip = Tools
|
||||||
button-map-editor-tab-container-history-tooltip = History
|
button-map-editor-tab-container-history-tooltip = History
|
||||||
|
|
||||||
|
button-delete-area =
|
||||||
|
.label = Delete
|
||||||
|
.tooltip = Remove everything in the selected area
|
||||||
|
|
||||||
|
button-delete-actor =
|
||||||
|
.label = Delete
|
||||||
|
.tooltip = Remove the selected actor
|
||||||
|
|
||||||
button-editor-world-root-copy =
|
button-editor-world-root-copy =
|
||||||
.label = Copy
|
.label = Copy
|
||||||
.tooltip = Copy the selected area
|
.tooltip = Copy the selected area
|
||||||
@@ -166,8 +173,8 @@ label-script-error-panel-desc-b = The details of the error have been saved to lu
|
|||||||
label-script-error-panel-desc-c = Please send this file to the map author so that they can fix this issue.
|
label-script-error-panel-desc-c = Please send this file to the map author so that they can fix this issue.
|
||||||
|
|
||||||
## ingame-infostats.yaml
|
## ingame-infostats.yaml
|
||||||
label-objective-mission = Mission:
|
label-mission-objective = Mission:
|
||||||
checkbox-objective-stats = Destroy all opposition!
|
checkbox-stats-objective = Destroy all opposition!
|
||||||
label-stats-player = Player
|
label-stats-player = Player
|
||||||
label-stats-faction = Faction
|
label-stats-faction = Faction
|
||||||
label-stats-score = Score
|
label-stats-score = Score
|
||||||
@@ -233,7 +240,8 @@ supportpowers-support-powers-palette =
|
|||||||
|
|
||||||
button-command-bar-attack-move =
|
button-command-bar-attack-move =
|
||||||
.tooltip = Attack Move
|
.tooltip = Attack Move
|
||||||
.tooltipdesc = Selected units will move to the desired location
|
.tooltipdesc =
|
||||||
|
Selected units will move to the desired location
|
||||||
and attack any enemies they encounter en route.
|
and attack any enemies they encounter en route.
|
||||||
|
|
||||||
Hold <(Ctrl)> while targeting to order an Assault Move
|
Hold <(Ctrl)> while targeting to order an Assault Move
|
||||||
@@ -243,7 +251,8 @@ button-command-bar-attack-move =
|
|||||||
|
|
||||||
button-command-bar-force-move =
|
button-command-bar-force-move =
|
||||||
.tooltip = Force Move
|
.tooltip = Force Move
|
||||||
.tooltipdesc = Selected units will move to the desired location
|
.tooltipdesc =
|
||||||
|
Selected units will move to the desired location
|
||||||
- Default activity for the target is suppressed
|
- Default activity for the target is suppressed
|
||||||
- Vehicles will attempt to crush enemies at the target location
|
- Vehicles will attempt to crush enemies at the target location
|
||||||
- Helicopters will land at the target location
|
- Helicopters will land at the target location
|
||||||
@@ -253,7 +262,8 @@ button-command-bar-force-move =
|
|||||||
|
|
||||||
button-command-bar-force-attack =
|
button-command-bar-force-attack =
|
||||||
.tooltip = Force Attack
|
.tooltip = Force Attack
|
||||||
.tooltipdesc = Selected units will attack the targeted unit or location
|
.tooltipdesc =
|
||||||
|
Selected units will attack the targeted unit or location
|
||||||
- Default activity for the target is suppressed
|
- Default activity for the target is suppressed
|
||||||
- Allows targeting of own or ally forces
|
- Allows targeting of own or ally forces
|
||||||
- Long-range artillery units will always target the
|
- Long-range artillery units will always target the
|
||||||
@@ -264,13 +274,15 @@ button-command-bar-force-attack =
|
|||||||
|
|
||||||
button-command-bar-guard =
|
button-command-bar-guard =
|
||||||
.tooltip = Guard
|
.tooltip = Guard
|
||||||
.tooltipdesc = Selected units will follow the targeted unit.
|
.tooltipdesc =
|
||||||
|
Selected units will follow the targeted unit.
|
||||||
|
|
||||||
Left-click icon then right-click on target unit.
|
Left-click icon then right-click on target unit.
|
||||||
|
|
||||||
button-command-bar-deploy =
|
button-command-bar-deploy =
|
||||||
.tooltip = Deploy
|
.tooltip = Deploy
|
||||||
.tooltipdesc = Selected units will perform their default deploy activity
|
.tooltipdesc =
|
||||||
|
Selected units will perform their default deploy activity
|
||||||
- MCVs will unpack into a Construction Yard
|
- MCVs will unpack into a Construction Yard
|
||||||
- Construction Yards will re-pack into a MCV
|
- Construction Yards will re-pack into a MCV
|
||||||
- Transports will unload their passengers
|
- Transports will unload their passengers
|
||||||
@@ -279,21 +291,24 @@ button-command-bar-deploy =
|
|||||||
|
|
||||||
button-command-bar-scatter =
|
button-command-bar-scatter =
|
||||||
.tooltip = Scatter
|
.tooltip = Scatter
|
||||||
.tooltipdesc = Selected units will stop their current activity
|
.tooltipdesc =
|
||||||
|
Selected units will stop their current activity
|
||||||
and move to a nearby location.
|
and move to a nearby location.
|
||||||
|
|
||||||
Acts immediately on selected units.
|
Acts immediately on selected units.
|
||||||
|
|
||||||
button-command-bar-stop =
|
button-command-bar-stop =
|
||||||
.tooltip = Stop
|
.tooltip = Stop
|
||||||
.tooltipdesc = Selected units will stop their current activity.
|
.tooltipdesc =
|
||||||
|
Selected units will stop their current activity.
|
||||||
Selected buildings will reset their rally point.
|
Selected buildings will reset their rally point.
|
||||||
|
|
||||||
Acts immediately on selected targets.
|
Acts immediately on selected targets.
|
||||||
|
|
||||||
button-command-bar-queue-orders =
|
button-command-bar-queue-orders =
|
||||||
.tooltip = Waypoint Mode
|
.tooltip = Waypoint Mode
|
||||||
.tooltipdesc = Use Waypoint Mode to give multiple linking commands
|
.tooltipdesc =
|
||||||
|
Use Waypoint Mode to give multiple linking commands
|
||||||
to the selected units. Units will execute the commands
|
to the selected units. Units will execute the commands
|
||||||
immediately upon receiving them.
|
immediately upon receiving them.
|
||||||
|
|
||||||
@@ -302,25 +317,29 @@ button-command-bar-queue-orders =
|
|||||||
|
|
||||||
button-stance-bar-attackanything =
|
button-stance-bar-attackanything =
|
||||||
.tooltip = Attack Anything Stance
|
.tooltip = Attack Anything Stance
|
||||||
.tooltipdesc = Set the selected units to Attack Anything stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Attack Anything stance:
|
||||||
- Units will attack enemy units and structures on sight
|
- Units will attack enemy units and structures on sight
|
||||||
- Units will pursue attackers across the battlefield
|
- Units will pursue attackers across the battlefield
|
||||||
|
|
||||||
button-stance-bar-defend =
|
button-stance-bar-defend =
|
||||||
.tooltip = Defend Stance
|
.tooltip = Defend Stance
|
||||||
.tooltipdesc = Set the selected units to Defend stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Defend stance:
|
||||||
- Units will attack enemy units on sight
|
- Units will attack enemy units on sight
|
||||||
- Units will not move or pursue enemies
|
- Units will not move or pursue enemies
|
||||||
|
|
||||||
button-stance-bar-returnfire =
|
button-stance-bar-returnfire =
|
||||||
.tooltip = Return Fire Stance
|
.tooltip = Return Fire Stance
|
||||||
.tooltipdesc = Set the selected units to Return Fire stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Return Fire stance:
|
||||||
- Units will retaliate against enemies that attack them
|
- Units will retaliate against enemies that attack them
|
||||||
- Units will not move or pursue enemies
|
- Units will not move or pursue enemies
|
||||||
|
|
||||||
button-stance-bar-holdfire =
|
button-stance-bar-holdfire =
|
||||||
.tooltip = Hold Fire Stance
|
.tooltip = Hold Fire Stance
|
||||||
.tooltipdesc = Set the selected units to Hold Fire stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Hold Fire stance:
|
||||||
- Units will not fire upon enemies
|
- Units will not fire upon enemies
|
||||||
- Units will not move or pursue enemies
|
- Units will not move or pursue enemies
|
||||||
|
|
||||||
@@ -340,15 +359,15 @@ productionpalette-player-widgets-production-palette =
|
|||||||
.hold = On Hold
|
.hold = On Hold
|
||||||
|
|
||||||
## lobby-kickdialogs.yaml
|
## lobby-kickdialogs.yaml
|
||||||
label-kick-client-dialog-texta = You may also apply a temporary ban, preventing
|
label-kick-client-dialog-text-a = You may also apply a temporary ban, preventing
|
||||||
label-kick-client-dialog-textb = them from joining for the remainder of this game.
|
label-kick-client-dialog-text-b = them from joining for the remainder of this game.
|
||||||
checkbox-kick-client-dialog-prevent-rejoining = Temporarily Ban
|
checkbox-kick-client-dialog-prevent-rejoining = Temporarily Ban
|
||||||
button-kick-client-dialog = Kick
|
button-kick-client-dialog = Kick
|
||||||
label-kick-spectators-dialog-title = Kick Spectators
|
label-kick-spectators-dialog-title = Kick Spectators
|
||||||
button-kick-spectators-dialog-ok = Ok
|
button-kick-spectators-dialog-ok = Ok
|
||||||
label-force-start-dialog-title = Start Game?
|
label-force-start-dialog-title = Start Game?
|
||||||
label-force-start-dialog-texta = One or more players are not yet ready.
|
label-force-start-dialog-text-a = One or more players are not yet ready.
|
||||||
label-force-start-dialog-textb = Are you sure that you want to force start the game?
|
label-force-start-dialog-text-b = Are you sure that you want to force start the game?
|
||||||
label-kick-warning-a = One or more clients are missing the selected
|
label-kick-warning-a = One or more clients are missing the selected
|
||||||
label-kick-warning-b = map, and will be kicked from the server.
|
label-kick-warning-b = map, and will be kicked from the server.
|
||||||
button-force-start-dialog-start = Start
|
button-force-start-dialog-start = Start
|
||||||
@@ -512,6 +531,12 @@ button-missionbrowser-panel-stop-briefing-video = Stop Briefing
|
|||||||
button-missionbrowser-panel-start-info-video = Watch Info Video
|
button-missionbrowser-panel-start-info-video = Watch Info Video
|
||||||
button-missionbrowser-panel-stop-info-video = Stop Info Video
|
button-missionbrowser-panel-stop-info-video = Stop Info Video
|
||||||
button-missionbrowser-panel-play = Play
|
button-missionbrowser-panel-play = Play
|
||||||
|
dropdown-missionbrowser-difficulty =
|
||||||
|
.label = Difficulty
|
||||||
|
.description = The difficulty of the mission
|
||||||
|
|
||||||
|
dropdown-missionbrowser-gamespeed = Speed:
|
||||||
|
label-missionbrowser-normal-difficulty = Normal
|
||||||
|
|
||||||
## multiplayer-browser.yaml
|
## multiplayer-browser.yaml
|
||||||
image-bg-password-protected-tooltip = Requires Password
|
image-bg-password-protected-tooltip = Requires Password
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ destroy-gdi-supporter-houses = Destroy the houses of the GDI supporters
|
|||||||
in the village.
|
in the village.
|
||||||
|
|
||||||
## nod06c
|
## nod06c
|
||||||
infiltrate-barracks-factory-conyard = Infiltrate the barracks, weapons factory and
|
capture-barracks-factory-conyard = Capture the barracks, weapons factory and
|
||||||
construction yard.
|
construction yard.
|
||||||
|
|
||||||
## nod07a
|
## nod07a
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ resource-tiberium = Tiberium
|
|||||||
faction-random =
|
faction-random =
|
||||||
.name = Any
|
.name = Any
|
||||||
.description = Random Faction
|
.description = Random Faction
|
||||||
A random faction is chosen at the start of the game.
|
A random faction is chosen at the start of the game
|
||||||
|
|
||||||
faction-gdi =
|
faction-gdi =
|
||||||
.name = GDI
|
.name = GDI
|
||||||
@@ -61,25 +61,34 @@ notification-structure-lost = Structure lost.
|
|||||||
## aircraft.yaml
|
## aircraft.yaml
|
||||||
actor-tran =
|
actor-tran =
|
||||||
.name = Chinook Transport
|
.name = Chinook Transport
|
||||||
.description = Fast Infantry Transport Helicopter.
|
.description =
|
||||||
Unarmed.
|
Fast Infantry Transport Helicopter.
|
||||||
.encyclopedia = The chinook is a flying transport capable of carrying a detachement of infantry. It is mostly used to transport commandos or engineers for backline-destruction.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
The chinook is a flying transport capable of carrying a detachement of infantry. It is mostly used to transport commandos or engineers for backline-destruction.
|
||||||
|
|
||||||
Like all aircraft, it can be handy in a pinch to crush a commando by landing!
|
Like all aircraft, it can be handy in a pinch to crush a commando by landing!
|
||||||
|
|
||||||
actor-heli =
|
actor-heli =
|
||||||
.name = Apache Longbow
|
.name = Apache Longbow
|
||||||
.description = Helicopter Gunship with chainguns.
|
.description =
|
||||||
Strong vs. Infantry, Light Vehicles and Aircraft.
|
Helicopter Gunship with chainguns.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry, Light Vehicles and Aircraft
|
||||||
.encyclopedia = Has more health than the Orca and acts as a support unit. It works well with artillery, as it can kill approaching light vehicles.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Has more health than the Orca and acts as a support unit. It works well with artillery, as it can kill approaching light vehicles.
|
||||||
|
|
||||||
Ammo is automatically reloaded in the air.
|
Ammo is automatically reloaded in the air.
|
||||||
|
|
||||||
actor-orca =
|
actor-orca =
|
||||||
.name = Orca
|
.name = Orca
|
||||||
.description = Helicopter gunship with AG missiles.
|
.description =
|
||||||
Strong vs. Buildings and Tanks.
|
Helicopter gunship with AG missiles.
|
||||||
Weak vs. Infantry.
|
Strong vs Buildings and Tanks
|
||||||
.encyclopedia = Fast but fragile, the Orca harasses enemy vehicles and aircraft with AT missiles. It is best used opportunistically, and can be kept alive longer with careful micro. Its AA missiles are effective but have a hard time hitting fast-moving air targets.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
Fast but fragile, the Orca harasses enemy vehicles and aircraft with AT missiles. It is best used opportunistically, and can be kept alive longer with careful micro. Its AA missiles are effective but have a hard time hitting fast-moving air targets.
|
||||||
|
|
||||||
Ammo is automatically reloaded in the air.
|
Ammo is automatically reloaded in the air.
|
||||||
|
|
||||||
actor-c17-name = Supply Aircraft
|
actor-c17-name = Supply Aircraft
|
||||||
@@ -220,80 +229,112 @@ actor-truck-husk-name = Supply Truck (Destroyed)
|
|||||||
## infantry.yaml
|
## infantry.yaml
|
||||||
actor-e1 =
|
actor-e1 =
|
||||||
.name = Minigunner
|
.name = Minigunner
|
||||||
.description = General-purpose infantry.
|
.description =
|
||||||
Strong vs. Infantry.
|
General-purpose infantry.
|
||||||
Weak vs. Vehicles.
|
Strong vs Infantry
|
||||||
.encyclopedia = The humble Minigunner is a highly specialized infantry unit designed to soak damage and kill other infantry.
|
Weak vs Vehicles
|
||||||
|
.encyclopedia =
|
||||||
|
The humble Minigunner is a highly specialized infantry unit designed to soak damage and kill other infantry.
|
||||||
|
|
||||||
Like most TD units, they can see farther than they can shoot, and work well in packs to eliminate enemy infantry.
|
Like most TD units, they can see farther than they can shoot, and work well in packs to eliminate enemy infantry.
|
||||||
|
|
||||||
actor-e2 =
|
actor-e2 =
|
||||||
.name = Grenadier
|
.name = Grenadier
|
||||||
.description = Fast infantry with grenades.
|
.description =
|
||||||
Strong vs. Buildings, slow-moving targets.
|
Fast infantry with grenades.
|
||||||
.encyclopedia = Fast and able to keep up with medium tanks, letting it work well with flanking armies.
|
Strong vs Buildings, slow-moving targets
|
||||||
|
.encyclopedia =
|
||||||
|
Fast and able to keep up with medium tanks, letting it work well with flanking armies.
|
||||||
|
|
||||||
While not as powerful as the Minigunner or a Rocket soldier, its speed can be used to your advantage.
|
While not as powerful as the Minigunner or a Rocket soldier, its speed can be used to your advantage.
|
||||||
|
|
||||||
actor-e3 =
|
actor-e3 =
|
||||||
.name = Rocket Soldier
|
.name = Rocket Soldier
|
||||||
.description = Anti-tank/Anti-aircraft infantry.
|
.description =
|
||||||
Strong vs. Tanks and Aircraft.
|
Anti-tank/Anti-aircraft infantry.
|
||||||
Weak vs. Infantry.
|
Strong vs Tanks and Aircraft
|
||||||
.encyclopedia = Highly vulnerable but excelling at eliminating enemy armor and aircraft. It is the slowest unit in the game, lagging behind other infantry and even mammoth tanks.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
Highly vulnerable but excelling at eliminating enemy armor and aircraft. It is the slowest unit in the game, lagging behind other infantry and even mammoth tanks.
|
||||||
|
|
||||||
Its large weapons range makes up for its slow speed, making it most effective when used defensively, where it can be protected and provide vision.
|
Its large weapons range makes up for its slow speed, making it most effective when used defensively, where it can be protected and provide vision.
|
||||||
|
|
||||||
actor-e4 =
|
actor-e4 =
|
||||||
.name = Flamethrower
|
.name = Flamethrower
|
||||||
.description = Advanced anti-infantry unit.
|
.description =
|
||||||
Strong vs. Infantry and Buildings.
|
Advanced anti-infantry unit.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry and Buildings
|
||||||
.encyclopedia = Good for flanking and burning down structures. It has more health than a standard Minigunner, but its short weapons range makes it difficult to use in large armies.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Good for flanking and burning down structures. It has more health than a standard Minigunner, but its short weapons range makes it difficult to use in large armies.
|
||||||
|
|
||||||
actor-e5 =
|
actor-e5 =
|
||||||
.name = Chemical Warrior
|
.name = Chemical Warrior
|
||||||
.description = Advanced general-purpose infantry.
|
.description =
|
||||||
Strong vs. all Ground units.
|
Advanced general-purpose infantry.
|
||||||
.encyclopedia = Similar stats to the Flamethrower but deals good damage vs. heavy armor. Great for stopping enemy armor from crushing your forces.
|
Strong vs all Ground units
|
||||||
|
.encyclopedia =
|
||||||
|
Similar stats to the Flamethrower but deals good damage vs heavy armor. Great for stopping enemy armor from crushing your forces.
|
||||||
|
|
||||||
It can walk on Tiberium without taking damage, making it particularly useful for harvester harassment on certain maps.
|
It can walk on Tiberium without taking damage, making it particularly useful for harvester harassment on certain maps.
|
||||||
|
|
||||||
actor-e6 =
|
actor-e6 =
|
||||||
.name = Engineer
|
.name = Engineer
|
||||||
.description = Damages and captures enemy structures.
|
.description =
|
||||||
|
Damages and captures enemy structures.
|
||||||
Repairs destroyed vehicles.
|
Repairs destroyed vehicles.
|
||||||
Unarmed.
|
Unarmed
|
||||||
.encyclopedia = Like the rocket soldier, the Engineer is slow and requires escorts to be used effectively. It can instantly capture structures but is consumed in the process.
|
.encyclopedia =
|
||||||
|
Like the rocket soldier, the Engineer is slow and requires escorts to be used effectively. It can instantly capture structures but is consumed in the process.
|
||||||
|
|
||||||
Capturing a civilian structure requires only one engineer, while capturing an enemy structure typically requires two engineers, or one if the structure is heavily damaged.
|
Capturing a civilian structure requires only one engineer, while capturing an enemy structure typically requires two engineers, or one if the structure is heavily damaged.
|
||||||
|
|
||||||
Engineers can also be used to repair friendly structures or restore husks from destroyed vehicles.
|
Engineers can also be used to repair friendly structures or restore husks from destroyed vehicles.
|
||||||
|
|
||||||
actor-rmbo =
|
actor-rmbo =
|
||||||
.name = Commando
|
.name = Commando
|
||||||
.description = Elite sniper infantry unit.
|
.description =
|
||||||
Strong vs Infantry and Buildings.
|
Elite sniper infantry unit.
|
||||||
Weak vs Vehicles.
|
Strong vs Infantry and Buildings
|
||||||
.encyclopedia = Equipped with a long-range sniper rifle, the Commando fires slowly but can eliminate enemy infantry from a distance when well-supported.
|
Weak vs Vehicles
|
||||||
|
.encyclopedia =
|
||||||
|
Equipped with a long-range sniper rifle, the Commando fires slowly but can eliminate enemy infantry from a distance when well-supported.
|
||||||
|
|
||||||
It carries C4, for surprise backline structure destruction.
|
It carries C4, for surprise backline structure destruction.
|
||||||
|
|
||||||
actor-pvice =
|
actor-pvice =
|
||||||
.description = Mutated abomination that spits liquid Tiberium.
|
.description =
|
||||||
Strong vs Infantry and Buildings.
|
Mutated abomination that spits liquid Tiberium.
|
||||||
Weak vs Aircraft.
|
Strong vs Infantry and Buildings
|
||||||
.encyclopedia = A mutated lifeform created from the strange properties of Tiberium, when infantry units are expose to it.
|
Weak vs Aircraft
|
||||||
|
.encyclopedia =
|
||||||
|
A mutated lifeform created from the strange properties of Tiberium, when infantry units are expose to it.
|
||||||
|
|
||||||
They regenerate health quickly and have a short-range Tiberium weapon.
|
They regenerate health quickly and have a short-range Tiberium weapon.
|
||||||
|
|
||||||
actor-steg =
|
actor-steg =
|
||||||
.name = Stegosaurus
|
.name = Stegosaurus
|
||||||
.description = A large, heavily built, herbivorous quadruped.
|
.description =
|
||||||
|
A large, heavily built,
|
||||||
|
herbivorous quadruped.
|
||||||
|
|
||||||
actor-trex =
|
actor-trex =
|
||||||
.name = Tyrannosaurus rex
|
.name = Tyrannosaurus rex
|
||||||
.description = Bipedal carnivore with a massive skull.
|
.description =
|
||||||
|
Bipedal carnivore with
|
||||||
|
a massive skull.
|
||||||
|
|
||||||
actor-tric =
|
actor-tric =
|
||||||
.name = Triceratops
|
.name = Triceratops
|
||||||
.description = Quadruped with large bony frill and three horns.
|
.description =
|
||||||
|
Quadruped with large bony
|
||||||
|
frill and three horns.
|
||||||
|
|
||||||
actor-rapt =
|
actor-rapt =
|
||||||
.name = Velociraptor
|
.name = Velociraptor
|
||||||
.description = Bipedal with enlarged sickle-shaped claw on each hindfoot.
|
.description =
|
||||||
|
Bipedal with enlarged sickle-shaped
|
||||||
|
claw on each hindfoot.
|
||||||
|
|
||||||
## misc.yaml
|
## misc.yaml
|
||||||
actor-wcrate-name = Wooden Crate
|
actor-wcrate-name = Wooden Crate
|
||||||
@@ -328,7 +369,9 @@ notification-nuclear-warhead-approaching = Nuclear warhead approaching.
|
|||||||
actor-fact =
|
actor-fact =
|
||||||
.name = Construction Yard
|
.name = Construction Yard
|
||||||
.description = Builds structures.
|
.description = Builds structures.
|
||||||
.encyclopedia = The core of any base. It produces buildings and defenses while also providing a build radius. It has a large health pool, but is difficult to replace, making it paramount to defend.
|
.encyclopedia =
|
||||||
|
The core of any base. It produces buildings and defenses while also providing a build radius. It has a large health pool, but is difficult to replace, making it paramount to defend.
|
||||||
|
|
||||||
It can be unpacked into a mobile version using the deploy key, but takes a small amount of time to do so.
|
It can be unpacked into a mobile version using the deploy key, but takes a small amount of time to do so.
|
||||||
|
|
||||||
actor-fact-gdi-name = GDI Construction Yard
|
actor-fact-gdi-name = GDI Construction Yard
|
||||||
@@ -337,143 +380,184 @@ actor-fact-nod-name = Nod Construction Yard
|
|||||||
actor-nuke =
|
actor-nuke =
|
||||||
.name = Power Plant
|
.name = Power Plant
|
||||||
.description = Generates power.
|
.description = Generates power.
|
||||||
.encyclopedia = Provides power to the structures in your base. Power output is directly related to the power plant's condition, so protect them during battles.
|
.encyclopedia =
|
||||||
|
Provides power to the structures in your base. Power output is directly related to the power plant's condition, so protect them during battles.
|
||||||
|
|
||||||
actor-nuk2 =
|
actor-nuk2 =
|
||||||
.name = Advanced Power Plant
|
.name = Advanced Power Plant
|
||||||
.description = Provides more power, cheaper than the
|
.description =
|
||||||
|
Provides more power, cheaper than the
|
||||||
standard Power Plant.
|
standard Power Plant.
|
||||||
.encyclopedia = Provides more power to the structures in your base, making it more cost-effective than the Power Plant. Power output is directly related to its condition, so protect it during battle.
|
.encyclopedia =
|
||||||
|
Provides more power to the structures in your base, making it more cost-effective than the Power Plant. Power output is directly related to its condition, so protect it during battle.
|
||||||
|
|
||||||
actor-proc =
|
actor-proc =
|
||||||
.name = Tiberium Refinery
|
.name = Tiberium Refinery
|
||||||
.description = Processes raw Tiberium
|
.description =
|
||||||
|
Processes raw Tiberium
|
||||||
into usable resources.
|
into usable resources.
|
||||||
.encyclopedia = Stores and processes the alien material and resource, Tiberium. Harvesters collect Tiberium in the field and deposit it at the refinery, where it is converted into credits.
|
.encyclopedia =
|
||||||
|
Stores and processes the alien material and resource, Tiberium. Harvesters collect Tiberium in the field and deposit it at the refinery, where it is converted into credits.
|
||||||
|
|
||||||
The refinery stores Tiberium and immediately deploys a harvester once constructed. 3 harvesters is the maximum it can handle for close refining.
|
The refinery stores Tiberium and immediately deploys a harvester once constructed. 3 harvesters is the maximum it can handle for close refining.
|
||||||
|
|
||||||
actor-silo =
|
actor-silo =
|
||||||
.name = Tiberium Silo
|
.name = Tiberium Silo
|
||||||
.description = Stores processed Tiberium.
|
.description = Stores processed Tiberium.
|
||||||
.encyclopedia = Stores credits. If storage is full, harvesters will wait until credits are spent.
|
.encyclopedia =
|
||||||
|
Stores credits. If storage is full, harvesters will wait until credits are spent.
|
||||||
|
|
||||||
Useful when harvesting the more valuable blue Tiberium, as a single refinery cannot store a full load.
|
Useful when harvesting the more valuable blue Tiberium, as a single refinery cannot store a full load.
|
||||||
|
|
||||||
actor-pyle =
|
actor-pyle =
|
||||||
.name = Barracks
|
.name = Barracks
|
||||||
.description = Trains infantry
|
.description = Trains infantry.
|
||||||
.encyclopedia = Produces infantry for GDI. Once unlocked, advanced GDI infantry are hard-hitting and fast.
|
.encyclopedia =
|
||||||
|
Produces infantry for GDI. Once unlocked, advanced GDI infantry are hard-hitting and fast.
|
||||||
|
|
||||||
actor-hand =
|
actor-hand =
|
||||||
.name = Hand of Nod
|
.name = Hand of Nod
|
||||||
.description = Trains infantry
|
.description = Trains infantry.
|
||||||
.encyclopedia = Produces infantry for Nod. Once unlocked, advanced Nod infantry are slow but have high health pools.
|
.encyclopedia =
|
||||||
|
Produces infantry for Nod. Once unlocked, advanced Nod infantry are slow but have high health pools.
|
||||||
|
|
||||||
actor-afld =
|
actor-afld =
|
||||||
.name = Airstrip
|
.name = Airstrip
|
||||||
.description = Provides a dropzone
|
.description =
|
||||||
|
Provides a dropzone
|
||||||
for vehicle reinforcements.
|
for vehicle reinforcements.
|
||||||
.encyclopedia = Delivers vehicles by plane for Nod. Nod vehicles are fast but fragile. Produce harvesters at the start to jumpstart your economy.
|
.encyclopedia =
|
||||||
|
Delivers vehicles by plane for Nod. Nod vehicles are fast but fragile. Produce harvesters at the start to jumpstart your economy.
|
||||||
|
|
||||||
actor-weap =
|
actor-weap =
|
||||||
.name = Weapons Factory
|
.name = Weapons Factory
|
||||||
.description = Produces vehicles.
|
.description = Produces vehicles.
|
||||||
.encyclopedia = Produces vehicles for GDI. GDI vehicles tend to be slow but hard-hitting. Produce harvesters at the start to jumpstart your economy.
|
.encyclopedia =
|
||||||
|
Produces vehicles for GDI. GDI vehicles tend to be slow but hard-hitting. Produce harvesters at the start to jumpstart your economy.
|
||||||
|
|
||||||
actor-hpad =
|
actor-hpad =
|
||||||
.name = Helipad
|
.name = Helipad
|
||||||
.description = Produces and repairs helicopters.
|
.description =
|
||||||
.encyclopedia = Produces and repairs helicopters. Requires a Communications Center to build advanced attack helicopters.
|
Produces and repairs helicopters.
|
||||||
|
.encyclopedia =
|
||||||
|
Produces and repairs helicopters. Requires a Communications Center to build advanced attack helicopters.
|
||||||
|
|
||||||
actor-hq =
|
actor-hq =
|
||||||
.name = Communications Center
|
.name = Communications Center
|
||||||
.description = Provides radar and Air Strike support power
|
.description =
|
||||||
|
Provides radar and Air Strike support power.
|
||||||
Unlocks higher-tech units and buildings.
|
Unlocks higher-tech units and buildings.
|
||||||
Requires power to operate.
|
Requires power to operate.
|
||||||
.airstrikepower-name = Air Strike
|
.airstrikepower-name = Air Strike
|
||||||
.airstrikepower-description = Deploy an aerial napalm strike.
|
.airstrikepower-description = Deploy an aerial napalm strike.
|
||||||
Burns buildings and infantry along a line.
|
Burns buildings and infantry along a line.
|
||||||
.encyclopedia = Grants the player access to the minimap (top right) when there is sufficient power. Unlocks new units while also granting access to the airstrike support power.
|
.encyclopedia =
|
||||||
|
Grants the player access to the minimap (top right) when there is sufficient power. Unlocks new units while also granting access to the airstrike support power.
|
||||||
|
|
||||||
actor-fix =
|
actor-fix =
|
||||||
.name = Repair Facility
|
.name = Repair Facility
|
||||||
.description = Repairs vehicles.
|
.description = Repairs vehicles.
|
||||||
.encyclopedia = Repairs vehicles. The repair command can be used on units to send them to the nearest repair facility.
|
.encyclopedia =
|
||||||
|
Repairs vehicles. The repair command can be used on units to send them to the nearest repair facility.
|
||||||
|
|
||||||
actor-eye =
|
actor-eye =
|
||||||
.name = Advanced Communications Center
|
.name = Advanced Communications Center
|
||||||
.description = Provides radar and Orbital Ion Cannon support power.
|
.description =
|
||||||
|
Provides radar and Orbital Ion Cannon support power.
|
||||||
Unlocks Mammoth Tank and Commando.
|
Unlocks Mammoth Tank and Commando.
|
||||||
Requires power to operate.
|
Requires power to operate.
|
||||||
.ioncannonpower-name = Ion Cannon
|
.ioncannonpower-name = Ion Cannon
|
||||||
.ioncannonpower-description = Initiates an Ion Cannon strike.
|
.ioncannonpower-description = Initiates an Ion Cannon strike.
|
||||||
Applies instant damage to a small area.
|
Applies instant damage to a small area.
|
||||||
.encyclopedia = Unlocks advanced units and the ion cannon support power. If the Communications Center is lost, it restores minimap functionality and unit production.
|
.encyclopedia =
|
||||||
|
Unlocks advanced units and the ion cannon support power. If the Communications Center is lost, it restores minimap functionality and unit production.
|
||||||
|
|
||||||
actor-tmpl =
|
actor-tmpl =
|
||||||
.name = Temple of Nod
|
.name = Temple of Nod
|
||||||
.description = Provides Nuclear Strike support power.
|
.description =
|
||||||
|
Provides Nuclear Strike support power.
|
||||||
Unlocks Stealth Tank, Chem. Warrior and Obelisk of Light.
|
Unlocks Stealth Tank, Chem. Warrior and Obelisk of Light.
|
||||||
Requires power to operate.
|
Requires power to operate.
|
||||||
.nukepower-name = Nuclear Strike
|
.nukepower-name = Nuclear Strike
|
||||||
.nukepower-description = Launches a tactical nuclear warhead.
|
.nukepower-description = Launches a tactical nuclear warhead.
|
||||||
Applies heavy damage over a large area.
|
Applies heavy damage over a large area.
|
||||||
.encyclopedia = Unlocks advanced units and the Nuke support power. Keeps unit unlocks online if the Communications Center is lost.
|
.encyclopedia =
|
||||||
|
Unlocks advanced units and the Nuke support power. Keeps unit unlocks online if the Communications Center is lost.
|
||||||
|
|
||||||
actor-gun =
|
actor-gun =
|
||||||
.name = Turret
|
.name = Turret
|
||||||
.description = Basic Anti-Tank base defense.
|
.description =
|
||||||
Strong vs Tanks and Vehicles.
|
Basic Anti-Tank base defense.
|
||||||
Weak vs Infantry.
|
Strong vs Tanks and Vehicles
|
||||||
.encyclopedia = Base defense armed with an armor-piercing cannon, it deals significant damage to vehicles in range.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
Base defense armed with an armor-piercing cannon, it deals significant damage to vehicles in range.
|
||||||
|
|
||||||
actor-sam =
|
actor-sam =
|
||||||
.name = SAM Site
|
.name = SAM Site
|
||||||
.description = Anti-Aircraft base defense.
|
.description =
|
||||||
Strong vs Aircraft.
|
Anti-Aircraft base defense.
|
||||||
Cannot target Ground units.
|
Strong vs Aircraft
|
||||||
.encyclopedia = Nod anti-air base defense. It remains protected when closed and opens to engage aircraft.
|
Cannot target Ground units
|
||||||
|
.encyclopedia =
|
||||||
|
Nod anti-air base defense. It remains protected when closed and opens to engage aircraft.
|
||||||
|
|
||||||
actor-obli =
|
actor-obli =
|
||||||
.name = Obelisk of Light
|
.name = Obelisk of Light
|
||||||
.description = Advanced base defense.
|
.description =
|
||||||
|
Advanced base defense.
|
||||||
Requires power to operate.
|
Requires power to operate.
|
||||||
Strong vs. all Ground units.
|
Strong vs all Ground units
|
||||||
Cannot target Aircraft.
|
Cannot target Aircraft
|
||||||
.encyclopedia = Advanced defense for Nod that quickly destroys ground targets with a powerful laser.
|
.encyclopedia =
|
||||||
|
Advanced defense for Nod that quickly destroys ground targets with a powerful laser.
|
||||||
|
|
||||||
actor-gtwr =
|
actor-gtwr =
|
||||||
.name = Guard Tower
|
.name = Guard Tower
|
||||||
.description = Basic defensive structure.
|
.description =
|
||||||
Strong vs. Infantry.
|
Basic defensive structure.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry
|
||||||
.encyclopedia = Base defense armed with a high-velocity machine gun, it shreds infantry and light vehicles within range with its large area of effect.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Base defense armed with a high-velocity machine gun, it shreds infantry and light vehicles within range with its large area of effect.
|
||||||
|
|
||||||
actor-atwr =
|
actor-atwr =
|
||||||
.name = Advanced Guard Tower
|
.name = Advanced Guard Tower
|
||||||
.description = All-purpose defensive structure.
|
.description =
|
||||||
Strong vs. Aircraft and Infantry.
|
All-purpose defensive structure.
|
||||||
Weak vs. Tanks.
|
Strong vs Aircraft and Infantry
|
||||||
.encyclopedia = Advanced defense for GDI that fires volleys of high explosive missiles at both ground and air targets. Effective versus everything.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Advanced defense for GDI that fires volleys of high explosive missiles at both ground and air targets. Effective versus everything.
|
||||||
|
|
||||||
actor-sbag =
|
actor-sbag =
|
||||||
.name = Sandbag Barrier
|
.name = Sandbag Barrier
|
||||||
.description = Stops infantry and light vehicles.
|
.description =
|
||||||
|
Stops infantry and light vehicles.
|
||||||
Can be crushed by tanks.
|
Can be crushed by tanks.
|
||||||
.encyclopedia = Blocks movement of infantry and light vehicles, but can be crushed by tanks. Immune to small arms fire.
|
.encyclopedia =
|
||||||
|
Blocks movement of infantry and light vehicles, but can be crushed by tanks. Immune to small arms fire.
|
||||||
|
|
||||||
This barrier can be built in multiple segments once an initial sandbag has been placed.
|
This barrier can be built in multiple segments once an initial sandbag has been placed.
|
||||||
|
|
||||||
actor-cycl =
|
actor-cycl =
|
||||||
.name = Chain Link Barrier
|
.name = Chain Link Barrier
|
||||||
.description = Stops infantry and light vehicles.
|
.description =
|
||||||
|
Stops infantry and light vehicles.
|
||||||
Can be crushed by tanks.
|
Can be crushed by tanks.
|
||||||
.encyclopedia = Blocks infantry movement and light vehicles, but can be crushed by tanks. Immune to small arms fire.
|
.encyclopedia =
|
||||||
|
Blocks movement of infantry and light vehicles, but can be crushed by tanks. Immune to small arms fire.
|
||||||
|
|
||||||
This barrier can be built in multiple segments once an initial chain link has been placed.
|
This barrier can be built in multiple segments once an initial chain link has been placed.
|
||||||
|
|
||||||
actor-brik =
|
actor-brik =
|
||||||
.name = Concrete Barrier
|
.name = Concrete Barrier
|
||||||
.description = Stops infantry and most tanks.
|
.description =
|
||||||
|
Stops infantry and most tanks.
|
||||||
Blocks some projectiles.
|
Blocks some projectiles.
|
||||||
.encyclopedia = Blocks all unit movement, except for Mammoth Tanks which can crush it. Immune to small arms fire.
|
.encyclopedia =
|
||||||
|
Blocks all unit movement, except for Mammoth Tanks which can crush it. Immune to small arms fire.
|
||||||
|
|
||||||
This barrier can be built in multiple segments once an initial wall has been placed.
|
This barrier can be built in multiple segments once an initial wall has been placed.
|
||||||
|
|
||||||
actor-barracks-name = Infantry Production
|
actor-barracks-name = Infantry Production
|
||||||
@@ -490,25 +574,29 @@ actor-hosp =
|
|||||||
.name = Hospital
|
.name = Hospital
|
||||||
.captured-desc = Provides infantry with self-healing.
|
.captured-desc = Provides infantry with self-healing.
|
||||||
.capturable-desc = Capture to enable self-healing for infantry.
|
.capturable-desc = Capture to enable self-healing for infantry.
|
||||||
.encyclopedia = Heals friendly infantry over time when captured.
|
.encyclopedia =
|
||||||
|
Heals friendly infantry over time when captured.
|
||||||
|
|
||||||
actor-miss =
|
actor-miss =
|
||||||
.name = Tech Center
|
.name = Tech Center
|
||||||
.captured-desc = Provides range of vision.
|
.captured-desc = Provides range of vision.
|
||||||
.capturable-desc = Capture to give visual range.
|
.capturable-desc = Capture to give visual range.
|
||||||
.encyclopedia = Provides a wide area of vision when captured.
|
.encyclopedia =
|
||||||
|
Provides a wide area of vision when captured.
|
||||||
|
|
||||||
actor-bio =
|
actor-bio =
|
||||||
.name = Biological Lab
|
.name = Biological Lab
|
||||||
.captured-desc = Provides infantry with Tiberium immunity.
|
.captured-desc = Provides infantry with Tiberium immunity.
|
||||||
.capturable-desc = Capture to enable Tiberium immunity for infantry.
|
.capturable-desc = Capture to enable Tiberium immunity for infantry.
|
||||||
.encyclopedia = Grants friendly infantry immunity to Tiberium when captured.
|
.encyclopedia =
|
||||||
|
Grants friendly infantry immunity to Tiberium when captured.
|
||||||
|
|
||||||
actor-v19 =
|
actor-v19 =
|
||||||
.name = Oil Derrick
|
.name = Oil Derrick
|
||||||
.captured-desc = Provides additional funds.
|
.captured-desc = Provides additional funds.
|
||||||
.capturable-desc = Capture to receive additional funds.
|
.capturable-desc = Capture to receive additional funds.
|
||||||
.encyclopedia = Produces a small amount of income frequently when captured. Makes less money than building a harvester, but provides consistent income.
|
.encyclopedia =
|
||||||
|
Produces a small amount of income frequently when captured. Makes less money than building a harvester, but provides consistent income.
|
||||||
|
|
||||||
## trees.yaml
|
## trees.yaml
|
||||||
actor-splitblue-name = Blue Blossom Tree
|
actor-splitblue-name = Blue Blossom Tree
|
||||||
@@ -518,124 +606,166 @@ actor-t13-transformable-name = (Tree that can transform into a Blossom Tree)
|
|||||||
## vehicles.yaml
|
## vehicles.yaml
|
||||||
actor-mcv =
|
actor-mcv =
|
||||||
.name = Mobile Construction Vehicle
|
.name = Mobile Construction Vehicle
|
||||||
.description = Deploys into a Construction Yard.
|
.description =
|
||||||
Unarmed.
|
Deploys into a Construction Yard.
|
||||||
.encyclopedia = Deploying an MCV changes it into a Construction Yard. The MCV has more health in its deployed form, but undeploying can be helpful to escape infantry.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
Deploying an MCV changes it into a Construction Yard. The MCV has more health in its deployed form, but undeploying can be helpful to escape infantry.
|
||||||
|
|
||||||
If you have a teammate, they can “gift” you an MCV by destroying an undeployed one near your base, allowing you to reclaim it with an engineer.
|
If you have a teammate, they can “gift” you an MCV by destroying an undeployed one near your base, allowing you to reclaim it with an engineer.
|
||||||
|
|
||||||
actor-harv =
|
actor-harv =
|
||||||
.name = Harvester
|
.name = Harvester
|
||||||
.generic-name = Harvester
|
.generic-name = Harvester
|
||||||
.description = Collects Tiberium for processing.
|
.description =
|
||||||
Unarmed.
|
Collects Tiberium for processing.
|
||||||
.encyclopedia = Harvesters slowly mine Tiberium and deposit it in your refinery, where it is converted into credits. They can also be sent to allied refineries to provide funds.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
Harvesters slowly mine Tiberium and deposit it in your refinery, where it is converted into credits. They can also be sent to allied refineries to provide funds.
|
||||||
|
|
||||||
notification-harvester-lost = Harvester lost.
|
notification-harvester-lost = Harvester lost.
|
||||||
|
|
||||||
actor-apc =
|
actor-apc =
|
||||||
.name = APC
|
.name = APC
|
||||||
.description = Armed infantry transport.
|
.description =
|
||||||
|
Armed infantry transport.
|
||||||
Can attack Aircraft.
|
Can attack Aircraft.
|
||||||
Strong vs. Vehicles.
|
Strong vs Vehicles
|
||||||
Weak vs. Infantry.
|
Weak vs Infantry
|
||||||
.encyclopedia = The APC (Armored Personnel Carrier) transports infantry, making it handy for capturing civilian structures. While its flak gun does not do much damage to enemy vehicles, the APC can resist enemy shots while your Hum-vees deal the damage.
|
.encyclopedia =
|
||||||
|
The APC (Armored Personnel Carrier) transports infantry, making it handy for capturing civilian structures. While its flak gun does not do much damage to enemy vehicles, the APC can resist enemy shots while your Hum-vees deal the damage.
|
||||||
|
|
||||||
It also functions as your primary AA unit; if you hit the stop command, it'll retarget onto any nearby enemy air units.
|
It also functions as your primary AA unit; if you hit the stop command, it'll retarget onto any nearby enemy air units.
|
||||||
|
|
||||||
actor-arty =
|
actor-arty =
|
||||||
.name = Artillery
|
.name = Artillery
|
||||||
.description = Long-range artillery.
|
.description =
|
||||||
Strong vs. Infantry, Vehicles and Buildings.
|
Long-range artillery.
|
||||||
.encyclopedia = Nod's artillery is a glass cannon, fragile but dealing large amounts of damage at long range. Particularly strong vs structures and infantry, it can destroy stationary tanks.
|
Strong vs Infantry, Vehicles and Buildings
|
||||||
|
.encyclopedia =
|
||||||
|
Nod's artillery is a glass cannon, fragile but dealing large amounts of damage at long range. Particularly strong vs structures and infantry, it can destroy stationary tanks.
|
||||||
|
|
||||||
Highly vulnerable when clumped due to its explosion on death.
|
Highly vulnerable when clumped due to its explosion on death.
|
||||||
|
|
||||||
actor-ftnk =
|
actor-ftnk =
|
||||||
.name = Flame Tank
|
.name = Flame Tank
|
||||||
.description = Heavily armored flame-throwing vehicle.
|
.description =
|
||||||
Strong vs. Infantry, Buildings and Vehicles.
|
Heavily armored flame-throwing vehicle.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry, Buildings and Vehicles
|
||||||
.encyclopedia = Roast infantry and structures alike, making them great for surprise attacks. Be wary of their splash damage on death, but be aware it can also be used to your advantage.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Roast infantry and structures alike, making them great for surprise attacks. Be wary of their splash damage on death, but be aware it can also be used to your advantage.
|
||||||
|
|
||||||
actor-bggy =
|
actor-bggy =
|
||||||
.name = Nod Buggy
|
.name = Nod Buggy
|
||||||
.description = Fast scout and anti-infantry vehicle.
|
.description =
|
||||||
Strong vs. Infantry.
|
Fast scout and anti-infantry vehicle.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry
|
||||||
.encyclopedia = Strong versus light vehicles and infantry, Buggies are great at scouting and killing isolated infantry. Though it is a little cheaper and faster than the GDI Hum-vee, they are more fragile.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Strong versus light vehicles and infantry, Buggies are great at scouting and killing isolated infantry. Though it is a little cheaper and faster than the GDI Hum-vee, they are more fragile.
|
||||||
|
|
||||||
actor-bike =
|
actor-bike =
|
||||||
.name = Recon Bike
|
.name = Recon Bike
|
||||||
.description = Fast scout vehicle with rockets.
|
.description =
|
||||||
|
Fast scout vehicle with rockets.
|
||||||
Can attack Aircraft.
|
Can attack Aircraft.
|
||||||
Strong vs. Vehicles and Tanks.
|
Strong vs Vehicles and Tanks
|
||||||
Weak vs. Infantry.
|
Weak vs Infantry
|
||||||
.encyclopedia = The Nod bike is a very fast vehicle armed with armor-piercing rockets, which makes it great for hit and run and harvester harassment.
|
.encyclopedia =
|
||||||
|
The Nod bike is a very fast vehicle armed with armor-piercing rockets, which makes it great for hit and run and harvester harassment.
|
||||||
|
|
||||||
Be wary that its rockets are slow and have a hard time hitting fast-moving targets.
|
Be wary that its rockets are slow and have a hard time hitting fast-moving targets.
|
||||||
|
|
||||||
actor-jeep =
|
actor-jeep =
|
||||||
.name = Hum-vee
|
.name = Hum-vee
|
||||||
.description = Fast scout and anti-infantry vehicle.
|
.description =
|
||||||
Strong vs. Infantry.
|
Fast scout and anti-infantry vehicle.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry
|
||||||
.encyclopedia = Strong versus light vehicles and infantry, Hum-vees are great at scouting and eliminating isolated infantry.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Strong versus light vehicles and infantry, Hum-vees are great at scouting and eliminating isolated infantry.
|
||||||
|
|
||||||
They're excellent for dealing with Nod bike spam and should be built instead of tanks in such engagements. Although a little slower than the Nod buggy, it has more health.
|
They're excellent for dealing with Nod bike spam and should be built instead of tanks in such engagements. Although a little slower than the Nod buggy, it has more health.
|
||||||
|
|
||||||
actor-ltnk =
|
actor-ltnk =
|
||||||
.name = Light Tank
|
.name = Light Tank
|
||||||
.description = Fast, light tank.
|
.description =
|
||||||
Strong vs. Vehicles and Tanks.
|
Fast, light tank.
|
||||||
Weak vs. Infantry.
|
Strong vs Vehicles and Tanks
|
||||||
.encyclopedia = With its great speed and high health pool, the light tank works great as a frontline unit in various compositions despite its damage output.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
With its great speed and high health pool, the light tank works great as a frontline unit in various compositions despite its damage output.
|
||||||
|
|
||||||
It should be combined with bikes, stealth tanks, or infantry when facing medium tanks.
|
It should be combined with bikes, stealth tanks, or infantry when facing medium tanks.
|
||||||
|
|
||||||
actor-mtnk =
|
actor-mtnk =
|
||||||
.name = Medium Tank
|
.name = Medium Tank
|
||||||
.description = General-Purpose GDI Tank.
|
.description =
|
||||||
Strong vs. Tanks and Vehicles.
|
General-purpose GDI Tank.
|
||||||
Weak vs. Infantry.
|
Strong vs Tanks and Vehicles
|
||||||
.encyclopedia = The workhorse of GDI, offering a good balance of speed, durability and firepower. It will easily destroy Nod light tanks and can tear through structures if it sneaks into a base.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
The workhorse of GDI, offering a good balance of speed, durability and firepower. It will easily destroy Nod light tanks and can tear through structures if it sneaks into a base.
|
||||||
|
|
||||||
Mix minigunners with your medium tank armies to deal with enemy infantry.
|
Mix minigunners with your medium tank armies to deal with enemy infantry.
|
||||||
|
|
||||||
actor-htnk =
|
actor-htnk =
|
||||||
.name = Mammoth Tank
|
.name = Mammoth Tank
|
||||||
.description = Heavily armored GDI Tank.
|
.description =
|
||||||
|
Heavily armored GDI Tank.
|
||||||
Can attack Aircraft.
|
Can attack Aircraft.
|
||||||
Strong vs. Everything.
|
Strong vs Everything
|
||||||
.encyclopedia = A crawling battle station, capable of self-repair and engaging any threat. It is particularly effective against enemy armor, but can also destroy small amounts of infantry or aircraft.
|
.encyclopedia =
|
||||||
|
A crawling battle station, capable of self-repair and engaging any threat. It is particularly effective against enemy armor, but can also destroy small amounts of infantry or aircraft.
|
||||||
|
|
||||||
When in an enemy base, put it on aggressive stance to have it carve a path of destruction as it moves.
|
When in an enemy base, put it on aggressive stance to have it carve a path of destruction as it moves.
|
||||||
|
|
||||||
actor-msam =
|
actor-msam =
|
||||||
.name = Rocket Launcher
|
.name = Rocket Launcher
|
||||||
.description = Long-range rocket artillery.
|
.description =
|
||||||
Strong vs. all ground units.
|
Long-range rocket artillery.
|
||||||
.encyclopedia = Referred to as “MLRS” by players (Multiple Launch Rocket System), this artillery platform fires volleys of rockets at distant targets. It is particularly effective against light vehicles and does moderate damage vs infantry, buildings, and heavy armor.
|
Strong vs all ground units
|
||||||
|
.encyclopedia =
|
||||||
|
Referred to as “MLRS” by players (Multiple Launch Rocket System), this artillery platform fires volleys of rockets at distant targets. It is particularly effective against light vehicles and does moderate damage vs infantry, buildings, and heavy armor.
|
||||||
|
|
||||||
A strong unit to build vs enemy artillery, its high bullet velocity and damage to light vehicles makes it the perfect counter to Nod artillery.
|
A strong unit to build vs enemy artillery, its high bullet velocity and damage to light vehicles makes it the perfect counter to Nod artillery.
|
||||||
|
|
||||||
actor-mlrs =
|
actor-mlrs =
|
||||||
.name = Mobile SAM.
|
.name = Mobile SAM
|
||||||
.description = Powerful anti-air unit.
|
.description =
|
||||||
|
Powerful anti-air unit.
|
||||||
Cannot attack ground units.
|
Cannot attack ground units.
|
||||||
.encyclopedia = Generally referred to as “MSAM” by players, this Nod vehicle is a dedicated anti-air vehicle when their bikes do not cut it. It fires slow-moving missiles with powerful splash damage.
|
.encyclopedia =
|
||||||
|
Generally referred to as “MSAM” by players, this Nod vehicle is a dedicated anti-air vehicle when their bikes do not cut it. It fires slow-moving missiles with powerful splash damage.
|
||||||
|
|
||||||
actor-stnk =
|
actor-stnk =
|
||||||
.name = Stealth Tank
|
.name = Stealth Tank
|
||||||
.description = Long-range missile tank that can cloak.
|
.description =
|
||||||
|
Long-range missile tank that can cloak.
|
||||||
Can attack Aircraft.
|
Can attack Aircraft.
|
||||||
Has weak armor. Can be spotted by infantry and defense structures.
|
Has weak armor. Can be spotted by infantry and
|
||||||
Strong vs. Vehicles and Tanks.
|
defense structures.
|
||||||
Weak vs. Infantry.
|
Strong vs Vehicles and Tanks
|
||||||
.encyclopedia = Cloaked units that become visible when damaged or firing their weapons. They can also be detected by defenses within a small radius or infantry at a one-cell range.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
Cloaked units that become visible when damaged or firing their weapons. They can also be detected by defenses within a small radius or infantry at a one-cell range.
|
||||||
|
|
||||||
Their long-range AP missiles are excellent for dealing with enemy armor or air. They can also crush infantry in a pinch.
|
Their long-range AP missiles are excellent for dealing with enemy armor or air. They can also crush infantry in a pinch.
|
||||||
|
|
||||||
actor-mhq =
|
actor-mhq =
|
||||||
.name = Mobile HQ
|
.name = Mobile HQ
|
||||||
.description = Mobile base of operations.
|
.description =
|
||||||
|
Mobile base of operations.
|
||||||
|
|
||||||
actor-truck =
|
actor-truck =
|
||||||
.name = Supply Truck
|
.name = Supply Truck
|
||||||
.description = Transports cash to other players.
|
.description =
|
||||||
Builds quickly.
|
Transports cash to other players.
|
||||||
Unarmed.
|
Builds quickly
|
||||||
.encyclopedia = Supply trucks are a convenient way to share cash when your ally is out of money, or you can't spend yours fast enough. They build far quicker than their cost suggests.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
Supply trucks are a convenient way to share cash when your ally is out of money, or you can't spend yours fast enough. They build far quicker than their cost suggests.
|
||||||
|
|
||||||
## ai.yaml
|
## ai.yaml
|
||||||
bot-cabal =
|
bot-cabal =
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ WorldLoaded = function()
|
|||||||
InitObjectives(Nod)
|
InitObjectives(Nod)
|
||||||
|
|
||||||
NodObjective1 = AddPrimaryObjective(Nod, "steal-nuclear-detonator")
|
NodObjective1 = AddPrimaryObjective(Nod, "steal-nuclear-detonator")
|
||||||
InfiltrateObjective = AddSecondaryObjective(Nod, "infiltrate-barracks-factory-conyard")
|
CaptureObjective = AddSecondaryObjective(Nod, "capture-barracks-factory-conyard")
|
||||||
|
|
||||||
InsertNodUnits()
|
InsertNodUnits()
|
||||||
|
|
||||||
@@ -111,18 +111,18 @@ WorldLoaded = function()
|
|||||||
Trigger.AfterDelay(ProductionDelay, ProdTriggerFunction)
|
Trigger.AfterDelay(ProductionDelay, ProdTriggerFunction)
|
||||||
|
|
||||||
Trigger.OnAnyKilled(BuildingsToCapture, function()
|
Trigger.OnAnyKilled(BuildingsToCapture, function()
|
||||||
if not Nod.IsObjectiveCompleted(InfiltrateObjective) then
|
if not Nod.IsObjectiveCompleted(CaptureObjective) then
|
||||||
Nod.MarkFailedObjective(InfiltrateObjective)
|
Nod.MarkFailedObjective(CaptureObjective)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Utils.Do(BuildingsToCapture, function(building)
|
|
||||||
local captured = 0
|
local captured = 0
|
||||||
|
Utils.Do(BuildingsToCapture, function(building)
|
||||||
Trigger.OnCapture(building, function()
|
Trigger.OnCapture(building, function()
|
||||||
captured = captured + 1
|
captured = captured + 1
|
||||||
|
|
||||||
if captured == 3 then
|
if captured == 3 then
|
||||||
Nod.MarkCompletedObjective(InfiltrateObjective)
|
Nod.MarkCompletedObjective(CaptureObjective)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Metadata:
|
Metadata:
|
||||||
Title: mod-title
|
Title: mod-title
|
||||||
Version: {DEV_VERSION}
|
Version: release-20250330
|
||||||
Website: https://www.openra.net
|
Website: https://www.openra.net
|
||||||
WebIcon32: https://www.openra.net/images/icons/cnc_32x32.png
|
WebIcon32: https://www.openra.net/images/icons/cnc_32x32.png
|
||||||
WindowTitle: mod-windowtitle
|
WindowTitle: mod-windowtitle
|
||||||
@@ -8,13 +8,13 @@ Metadata:
|
|||||||
PackageFormats: Mix
|
PackageFormats: Mix
|
||||||
|
|
||||||
FileSystem: ContentInstallerFileSystem
|
FileSystem: ContentInstallerFileSystem
|
||||||
Packages:
|
SystemPackages:
|
||||||
^EngineDir
|
^EngineDir
|
||||||
$cnc: cnc
|
$cnc: cnc
|
||||||
^EngineDir|mods/common: common
|
^EngineDir|mods/common: common
|
||||||
~^SupportDir|Content/cnc: content
|
~^SupportDir|Content/cnc: content
|
||||||
cnc|scripts
|
|
||||||
common|scripts
|
common|scripts
|
||||||
|
cnc|scripts
|
||||||
cnc|uibits
|
cnc|uibits
|
||||||
ContentPackages:
|
ContentPackages:
|
||||||
content|speech.mix
|
content|speech.mix
|
||||||
@@ -30,6 +30,7 @@ FileSystem: ContentInstallerFileSystem
|
|||||||
~content|scores-covertops.mix
|
~content|scores-covertops.mix
|
||||||
~content|transit.mix
|
~content|transit.mix
|
||||||
~content|general.mix
|
~content|general.mix
|
||||||
|
# Below are mod-provided (system) packages that need to be loaded after the content packages so they can override content assets.
|
||||||
cnc|bits/snow.mix
|
cnc|bits/snow.mix
|
||||||
cnc|bits
|
cnc|bits
|
||||||
cnc|bits/jungle
|
cnc|bits/jungle
|
||||||
@@ -39,7 +40,7 @@ FileSystem: ContentInstallerFileSystem
|
|||||||
|
|
||||||
MapFolders:
|
MapFolders:
|
||||||
cnc|maps: System
|
cnc|maps: System
|
||||||
~^SupportDir|maps/cnc/{DEV_VERSION}: User
|
~^SupportDir|maps/cnc/release-20250330: User
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
cnc|rules/misc.yaml
|
cnc|rules/misc.yaml
|
||||||
|
|||||||
@@ -69,8 +69,6 @@ tc04:
|
|||||||
SNOW: tc04.sno
|
SNOW: tc04.sno
|
||||||
JUNGLE: tc04.jun
|
JUNGLE: tc04.jun
|
||||||
idle:
|
idle:
|
||||||
damaged-idle:
|
|
||||||
Start: 1
|
|
||||||
|
|
||||||
tc04.husk:
|
tc04.husk:
|
||||||
Defaults:
|
Defaults:
|
||||||
@@ -80,7 +78,7 @@ tc04.husk:
|
|||||||
SNOW: tc04.sno
|
SNOW: tc04.sno
|
||||||
JUNGLE: tc04.jun
|
JUNGLE: tc04.jun
|
||||||
idle:
|
idle:
|
||||||
Start: 2
|
Start: 1
|
||||||
|
|
||||||
tc05:
|
tc05:
|
||||||
Defaults:
|
Defaults:
|
||||||
@@ -90,8 +88,6 @@ tc05:
|
|||||||
SNOW: tc05.sno
|
SNOW: tc05.sno
|
||||||
JUNGLE: tc05.jun
|
JUNGLE: tc05.jun
|
||||||
idle:
|
idle:
|
||||||
damaged-idle:
|
|
||||||
Start: 1
|
|
||||||
|
|
||||||
tc05.husk:
|
tc05.husk:
|
||||||
Defaults:
|
Defaults:
|
||||||
@@ -101,7 +97,7 @@ tc05.husk:
|
|||||||
SNOW: tc05.sno
|
SNOW: tc05.sno
|
||||||
JUNGLE: tc05.jun
|
JUNGLE: tc05.jun
|
||||||
idle:
|
idle:
|
||||||
Start: 2
|
Start: 1
|
||||||
|
|
||||||
tc03:
|
tc03:
|
||||||
Defaults:
|
Defaults:
|
||||||
|
|||||||
@@ -152,32 +152,30 @@ ScrollPanel@SPECTATOR_LABEL_DROPDOWN_TEMPLATE:
|
|||||||
ScrollPanel@NEWS_PANEL:
|
ScrollPanel@NEWS_PANEL:
|
||||||
Width: 400
|
Width: 400
|
||||||
Height: 265
|
Height: 265
|
||||||
TopBottomSpacing: 5
|
TopBottomSpacing: 15
|
||||||
ItemSpacing: 5
|
ItemSpacing: 5
|
||||||
Children:
|
Children:
|
||||||
Container@NEWS_ITEM_TEMPLATE:
|
Container@NEWS_ITEM_TEMPLATE:
|
||||||
X: 10
|
X: 10
|
||||||
Y: 5
|
|
||||||
Width: PARENT_WIDTH - 40
|
Width: PARENT_WIDTH - 40
|
||||||
Height: 45
|
Height: 40
|
||||||
Children:
|
Children:
|
||||||
Label@TITLE:
|
Label@TITLE:
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 15
|
||||||
Align: Center
|
Align: Center
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Label@AUTHOR_DATETIME:
|
Label@AUTHOR_DATETIME:
|
||||||
Y: 25
|
Y: 20
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 15
|
Height: 15
|
||||||
Align: Center
|
Align: Center
|
||||||
Font: TinyBold
|
Font: TinyBold
|
||||||
Label@CONTENT:
|
Label@CONTENT:
|
||||||
Y: 45
|
Y: 40
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Label@NEWS_STATUS:
|
Label@NEWS_STATUS:
|
||||||
X: 80
|
X: 80
|
||||||
Y: 0
|
|
||||||
Width: PARENT_WIDTH - 80 - 80 - 24
|
Width: PARENT_WIDTH - 80 - 80 - 24
|
||||||
Height: PARENT_HEIGHT
|
Height: PARENT_HEIGHT
|
||||||
Align: Center
|
Align: Center
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
Y: 12
|
Y: 12
|
||||||
Width: 55
|
Width: 55
|
||||||
Height: 25
|
Height: 25
|
||||||
Text: label-tools-bg-categories
|
Text: label-tool-bg-category
|
||||||
Align: Right
|
Align: Right
|
||||||
Font: TinyBold
|
Font: TinyBold
|
||||||
DropDownButton@TOOLS_DROPDOWN:
|
DropDownButton@TOOLS_DROPDOWN:
|
||||||
@@ -600,7 +600,7 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: label-copy-filters
|
Text: label-selection-filters
|
||||||
Checkbox@COPY_FILTER_TERRAIN_CHECKBOX:
|
Checkbox@COPY_FILTER_TERRAIN_CHECKBOX:
|
||||||
X: 5
|
X: 5
|
||||||
Y: 70
|
Y: 70
|
||||||
@@ -654,6 +654,17 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
Width: 55
|
Width: 55
|
||||||
Height: 22
|
Height: 22
|
||||||
Align: Left
|
Align: Left
|
||||||
|
Button@SELECTION_DELETE_BUTTON:
|
||||||
|
X: 5
|
||||||
|
Y: 222
|
||||||
|
Width: 75
|
||||||
|
Height: 25
|
||||||
|
Text: button-delete-area.label
|
||||||
|
Font: Bold
|
||||||
|
Key: EditorDeleteSelection
|
||||||
|
TooltipTemplate: BUTTON_TOOLTIP
|
||||||
|
TooltipText: button-delete-area.tooltip
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Button@SELECTION_CANCEL_BUTTON:
|
Button@SELECTION_CANCEL_BUTTON:
|
||||||
X: 208
|
X: 208
|
||||||
Y: 222
|
Y: 222
|
||||||
@@ -747,8 +758,12 @@ Container@EDITOR_WORLD_ROOT:
|
|||||||
X: 5
|
X: 5
|
||||||
Width: 75
|
Width: 75
|
||||||
Height: 25
|
Height: 25
|
||||||
Text: button-container-delete
|
Text: button-delete-actor.label
|
||||||
Font: Bold
|
Font: Bold
|
||||||
|
Key: EditorDeleteSelection
|
||||||
|
TooltipTemplate: BUTTON_TOOLTIP
|
||||||
|
TooltipText: button-delete-actor.tooltip
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Button@CANCEL_BUTTON:
|
Button@CANCEL_BUTTON:
|
||||||
X: 127
|
X: 127
|
||||||
Width: 75
|
Width: 75
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Container@SKIRMISH_STATS:
|
|||||||
Width: 482
|
Width: 482
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: MediumBold
|
Font: MediumBold
|
||||||
Text: label-objective-mission
|
Text: label-mission-objective
|
||||||
Label@STATS_STATUS:
|
Label@STATS_STATUS:
|
||||||
X: 100
|
X: 100
|
||||||
Y: 22
|
Y: 22
|
||||||
@@ -25,7 +25,7 @@ Container@SKIRMISH_STATS:
|
|||||||
Width: 482
|
Width: 482
|
||||||
Height: 20
|
Height: 20
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Text: checkbox-objective-stats
|
Text: checkbox-stats-objective
|
||||||
Disabled: true
|
Disabled: true
|
||||||
TextColorDisabled: FFFFFF
|
TextColorDisabled: FFFFFF
|
||||||
Container@STATS_HEADERS:
|
Container@STATS_HEADERS:
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ Background@KICK_CLIENT_DIALOG:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-kick-client-dialog-texta
|
Text: label-kick-client-dialog-text-a
|
||||||
Label@TEXTB:
|
Label@TEXTB:
|
||||||
Y: 86
|
Y: 86
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-kick-client-dialog-textb
|
Text: label-kick-client-dialog-text-b
|
||||||
Checkbox@PREVENT_REJOINING_CHECKBOX:
|
Checkbox@PREVENT_REJOINING_CHECKBOX:
|
||||||
X: (PARENT_WIDTH - WIDTH) / 2
|
X: (PARENT_WIDTH - WIDTH) / 2
|
||||||
Y: 120
|
Y: 120
|
||||||
@@ -97,14 +97,14 @@ Background@FORCE_START_DIALOG:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-force-start-dialog-texta
|
Text: label-force-start-dialog-text-a
|
||||||
Label@TEXTB:
|
Label@TEXTB:
|
||||||
Y: 86
|
Y: 86
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-force-start-dialog-textb
|
Text: label-force-start-dialog-text-b
|
||||||
Container@KICK_WARNING:
|
Container@KICK_WARNING:
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Children:
|
Children:
|
||||||
|
|||||||
@@ -252,8 +252,8 @@ Container@LOBBY_PLAYER_BIN:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Text: label-lobby-players-faction
|
Text: label-lobby-players-faction
|
||||||
Label@TEAM:
|
Label@TEAM:
|
||||||
X: 420
|
X: 410
|
||||||
Width: 42
|
Width: 43
|
||||||
Height: 25
|
Height: 25
|
||||||
Text: label-lobby-players-team
|
Text: label-lobby-players-team
|
||||||
Align: Center
|
Align: Center
|
||||||
|
|||||||
@@ -76,6 +76,44 @@ Background@MISSIONBROWSER_PANEL:
|
|||||||
Height: 31
|
Height: 31
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Text: button-missionbrowser-panel-mission-options
|
Text: button-missionbrowser-panel-mission-options
|
||||||
|
Container@MISSION_MINIFIED_OPTIONS:
|
||||||
|
Width: PARENT_WIDTH
|
||||||
|
Height: PARENT_HEIGHT
|
||||||
|
Visible: False
|
||||||
|
Children:
|
||||||
|
LabelForInput@DIFFICULTY_DESC:
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT
|
||||||
|
Width: 56
|
||||||
|
Height: 25
|
||||||
|
Align: Right
|
||||||
|
Text: dropdown-missionbrowser-difficulty.label
|
||||||
|
For: DIFFICULTY
|
||||||
|
DropDownButton@DIFFICULTY:
|
||||||
|
X: 61
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT
|
||||||
|
Width: 135
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
|
Text: label-missionbrowser-normal-difficulty
|
||||||
|
TooltipText: dropdown-missionbrowser-difficulty.description
|
||||||
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
|
LabelForInput@GAMESPEED_DESC:
|
||||||
|
X: PARENT_WIDTH - WIDTH - 115
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT
|
||||||
|
Width: 120
|
||||||
|
Height: 25
|
||||||
|
Align: Right
|
||||||
|
Text: dropdown-missionbrowser-gamespeed
|
||||||
|
For: GAMESPEED
|
||||||
|
DropDownButton@GAMESPEED:
|
||||||
|
X: PARENT_WIDTH - WIDTH
|
||||||
|
Y: PARENT_HEIGHT - HEIGHT
|
||||||
|
Width: 110
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Container@MISSION_DETAIL:
|
Container@MISSION_DETAIL:
|
||||||
Y: 212
|
Y: 212
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ Container@ADVANCED_PANEL:
|
|||||||
Font: Regular
|
Font: Regular
|
||||||
Text: checkbox-sendsysinfo-container
|
Text: checkbox-sendsysinfo-container
|
||||||
Label@SENDSYSINFO_DESC:
|
Label@SENDSYSINFO_DESC:
|
||||||
Y: 15
|
Y: 30
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 30
|
Height: 30
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ label-save-map-panel-directory = Directory:
|
|||||||
label-save-map-panel-filename = Filename:
|
label-save-map-panel-filename = Filename:
|
||||||
button-save-map-panel = Save
|
button-save-map-panel = Save
|
||||||
label-actor-edit-panel-id = ID
|
label-actor-edit-panel-id = ID
|
||||||
button-container-delete = Delete
|
|
||||||
button-container-ok = OK
|
button-container-ok = OK
|
||||||
label-tiles-bg-search = Search:
|
label-tiles-bg-search = Search:
|
||||||
label-bg-filter = Filter:
|
label-bg-filter = Filter:
|
||||||
@@ -62,11 +61,11 @@ label-area-selection = Area Selection
|
|||||||
label-area-info = Area Info
|
label-area-info = Area Info
|
||||||
label-selected-area-diagonal = Diagonal:
|
label-selected-area-diagonal = Diagonal:
|
||||||
label-selected-area-resources = Resources:
|
label-selected-area-resources = Resources:
|
||||||
label-copy-filters = Copy Filters
|
label-selection-filters = Filters
|
||||||
label-filter-terrain = Terrain
|
label-filter-terrain = Terrain
|
||||||
label-filter-resources = Resources
|
label-filter-resources = Resources
|
||||||
label-filter-actors = Actors
|
label-filter-actors = Actors
|
||||||
label-tools-bg-categories = Tool:
|
label-tool-bg-category = Tool:
|
||||||
button-marker-tiles-clear-current = Clear Current
|
button-marker-tiles-clear-current = Clear Current
|
||||||
button-marker-tiles-clear-all = Clear All
|
button-marker-tiles-clear-all = Clear All
|
||||||
label-marker-layer-num-sides = Number of Sides
|
label-marker-layer-num-sides = Number of Sides
|
||||||
@@ -81,6 +80,14 @@ button-map-editor-tab-container-actors-tooltip = Actors
|
|||||||
button-map-editor-tab-container-tools-tooltip = Tools
|
button-map-editor-tab-container-tools-tooltip = Tools
|
||||||
button-map-editor-tab-container-history-tooltip = History
|
button-map-editor-tab-container-history-tooltip = History
|
||||||
|
|
||||||
|
button-delete-area =
|
||||||
|
.label = Delete
|
||||||
|
.tooltip = Remove everything in the selected area
|
||||||
|
|
||||||
|
button-delete-actor =
|
||||||
|
.label = Delete
|
||||||
|
.tooltip = Remove the selected actor
|
||||||
|
|
||||||
button-editor-world-root-options =
|
button-editor-world-root-options =
|
||||||
.label = Menu
|
.label = Menu
|
||||||
.tooltip = Menu
|
.tooltip = Menu
|
||||||
@@ -156,8 +163,8 @@ label-script-error-panel-desc-b = The details of the error have been saved to lu
|
|||||||
label-script-error-panel-desc-c = Please send this file to the map author so that they can fix this issue.
|
label-script-error-panel-desc-c = Please send this file to the map author so that they can fix this issue.
|
||||||
|
|
||||||
## ingame-infostats.yaml
|
## ingame-infostats.yaml
|
||||||
label-objective-mission = Mission:
|
label-mission-objective = Mission:
|
||||||
checkbox-objective-stats = Destroy all opposition!
|
checkbox-stats-objective = Destroy all opposition!
|
||||||
label-stats-player = Player
|
label-stats-player = Player
|
||||||
label-stats-faction = Faction
|
label-stats-faction = Faction
|
||||||
label-stats-score = Score
|
label-stats-score = Score
|
||||||
@@ -167,15 +174,15 @@ label-stats-actions = Actions
|
|||||||
label-menu-buttons-title = Options
|
label-menu-buttons-title = Options
|
||||||
|
|
||||||
## lobby-kickdialogs.yaml
|
## lobby-kickdialogs.yaml
|
||||||
label-kick-client-dialog-texta = You may also apply a temporary ban, preventing
|
label-kick-client-dialog-text-a = You may also apply a temporary ban, preventing
|
||||||
label-kick-client-dialog-textb = them from joining for the remainder of this game.
|
label-kick-client-dialog-text-b = them from joining for the remainder of this game.
|
||||||
checkbox-kick-client-dialog-prevent-rejoining = Temporarily Ban
|
checkbox-kick-client-dialog-prevent-rejoining = Temporarily Ban
|
||||||
button-kick-client-dialog = Kick
|
button-kick-client-dialog = Kick
|
||||||
label-kick-spectators-dialog-title = Kick Spectators
|
label-kick-spectators-dialog-title = Kick Spectators
|
||||||
button-kick-spectators-dialog-ok = Ok
|
button-kick-spectators-dialog-ok = Ok
|
||||||
label-force-start-dialog-title = Start Game?
|
label-force-start-dialog-title = Start Game?
|
||||||
label-force-start-dialog-texta = One or more players are not yet ready.
|
label-force-start-dialog-text-a = One or more players are not yet ready.
|
||||||
label-force-start-dialog-textb = Are you sure that you want to force start the game?
|
label-force-start-dialog-text-b = Are you sure that you want to force start the game?
|
||||||
label-kick-warning-a = One or more clients are missing the selected
|
label-kick-warning-a = One or more clients are missing the selected
|
||||||
label-kick-warning-b = map, and will be kicked from the server.
|
label-kick-warning-b = map, and will be kicked from the server.
|
||||||
button-force-start-dialog-start = Start
|
button-force-start-dialog-start = Start
|
||||||
@@ -343,6 +350,12 @@ button-missionbrowser-panel-stop-info-video = Stop Info Video
|
|||||||
button-missionbrowser-panel-play = Play
|
button-missionbrowser-panel-play = Play
|
||||||
button-missionbrowser-panel-mission-info = Mission Info
|
button-missionbrowser-panel-mission-info = Mission Info
|
||||||
button-missionbrowser-panel-mission-options = Options
|
button-missionbrowser-panel-mission-options = Options
|
||||||
|
dropdown-missionbrowser-difficulty =
|
||||||
|
.label = Difficulty
|
||||||
|
.description = The difficulty of the mission
|
||||||
|
|
||||||
|
dropdown-missionbrowser-gamespeed = Speed:
|
||||||
|
label-missionbrowser-normal-difficulty = Normal
|
||||||
|
|
||||||
## multiplayer-browser.yaml
|
## multiplayer-browser.yaml
|
||||||
image-multiplayer-panel-password-protected-tooltip = Requires Password
|
image-multiplayer-panel-password-protected-tooltip = Requires Password
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ notification-insufficient-enabled-spawn-points = Unable to start the game until
|
|||||||
notification-malformed-command = Malformed { $command } command.
|
notification-malformed-command = Malformed { $command } command.
|
||||||
notification-state-unchanged-ready = Cannot change state when marked as ready.
|
notification-state-unchanged-ready = Cannot change state when marked as ready.
|
||||||
notification-invalid-faction-selected = Invalid faction selected: { $faction }.
|
notification-invalid-faction-selected = Invalid faction selected: { $faction }.
|
||||||
notification-supported-factions = Supported values: { $factions }.
|
|
||||||
notification-state-unchanged-game-started = State cannot be changed once the game has started ({ $command }).
|
notification-state-unchanged-game-started = State cannot be changed once the game has started ({ $command }).
|
||||||
notification-requires-host = Only the host can do that.
|
notification-requires-host = Only the host can do that.
|
||||||
notification-invalid-bot-slot = Cannot add bots to a slot with another client.
|
notification-invalid-bot-slot = Cannot add bots to a slot with another client.
|
||||||
@@ -206,6 +205,9 @@ label-chat-availability =
|
|||||||
*[other] Chat available in { $seconds } seconds...
|
*[other] Chat available in { $seconds } seconds...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## LobbyLogic, ServerListLogic
|
||||||
|
label-bot-player = AI Player
|
||||||
|
|
||||||
## IngameMenuLogic
|
## IngameMenuLogic
|
||||||
menu-ingame =
|
menu-ingame =
|
||||||
.leave = Leave
|
.leave = Leave
|
||||||
@@ -804,6 +806,7 @@ notification-copied-tiles =
|
|||||||
|
|
||||||
## EditorDefaultBrush
|
## EditorDefaultBrush
|
||||||
notification-selected-area = Selected area { $x },{ $y } ({ $width },{ $height })
|
notification-selected-area = Selected area { $x },{ $y } ({ $width },{ $height })
|
||||||
|
notification-removed-area = Removed area { $x },{ $y } ({ $width },{ $height })
|
||||||
notification-selected-actor = Selected actor { $id }
|
notification-selected-actor = Selected actor { $id }
|
||||||
notification-cleared-selection = Cleared selection
|
notification-cleared-selection = Cleared selection
|
||||||
notification-removed-actor = Removed { $name } ({ $id })
|
notification-removed-actor = Removed { $name } ({ $id })
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ hotkey-description-editorredo = Redo
|
|||||||
hotkey-description-editorcopy = Copy
|
hotkey-description-editorcopy = Copy
|
||||||
hotkey-description-editorquicksave = Save Map
|
hotkey-description-editorquicksave = Save Map
|
||||||
hotkey-description-editorpaste = Paste
|
hotkey-description-editorpaste = Paste
|
||||||
|
hotkey-description-editordeleteselection = Delete Selection
|
||||||
hotkey-description-editorselecttab = Select Tab
|
hotkey-description-editorselecttab = Select Tab
|
||||||
hotkey-description-editortilestab = Tiles Tab
|
hotkey-description-editortilestab = Tiles Tab
|
||||||
hotkey-description-editoroverlaystab = Overlays Tab
|
hotkey-description-editoroverlaystab = Overlays Tab
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ EditorPaste: V Ctrl
|
|||||||
Platform:
|
Platform:
|
||||||
OSX: V Meta
|
OSX: V Meta
|
||||||
|
|
||||||
|
EditorDeleteSelection: DELETE
|
||||||
|
Description: hotkey-description-editordeleteselection
|
||||||
|
Types: Editor
|
||||||
|
Contexts: editor
|
||||||
|
Platform:
|
||||||
|
OSX: BACKSPACE
|
||||||
|
|
||||||
EditorSelectTab: E
|
EditorSelectTab: E
|
||||||
Description: hotkey-description-editorselecttab
|
Description: hotkey-description-editorselecttab
|
||||||
Types: Editor
|
Types: Editor
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Metadata:
|
Metadata:
|
||||||
Title: mod-title
|
Title: mod-title
|
||||||
Version: {DEV_VERSION}
|
Version: release-20250330
|
||||||
Hidden: true
|
Hidden: true
|
||||||
|
|
||||||
FileSystem: DefaultFileSystem
|
FileSystem: DefaultFileSystem
|
||||||
|
|||||||
@@ -116,32 +116,30 @@ ScrollPanel@SPECTATOR_DROPDOWN_TEMPLATE:
|
|||||||
ScrollPanel@NEWS_PANEL:
|
ScrollPanel@NEWS_PANEL:
|
||||||
Width: 400
|
Width: 400
|
||||||
Height: 265
|
Height: 265
|
||||||
TopBottomSpacing: 5
|
TopBottomSpacing: 15
|
||||||
ItemSpacing: 5
|
ItemSpacing: 5
|
||||||
Children:
|
Children:
|
||||||
Container@NEWS_ITEM_TEMPLATE:
|
Container@NEWS_ITEM_TEMPLATE:
|
||||||
X: 10
|
X: 10
|
||||||
Y: 5
|
|
||||||
Width: PARENT_WIDTH - 40
|
Width: PARENT_WIDTH - 40
|
||||||
Height: 45
|
Height: 40
|
||||||
Children:
|
Children:
|
||||||
Label@TITLE:
|
Label@TITLE:
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 25
|
Height: 15
|
||||||
Align: Center
|
Align: Center
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Label@AUTHOR_DATETIME:
|
Label@AUTHOR_DATETIME:
|
||||||
Y: 25
|
Y: 20
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Height: 15
|
Height: 15
|
||||||
Align: Center
|
Align: Center
|
||||||
Font: TinyBold
|
Font: TinyBold
|
||||||
Label@CONTENT:
|
Label@CONTENT:
|
||||||
Y: 45
|
Y: 40
|
||||||
Width: PARENT_WIDTH
|
Width: PARENT_WIDTH
|
||||||
Label@NEWS_STATUS:
|
Label@NEWS_STATUS:
|
||||||
X: 80
|
X: 80
|
||||||
Y: 0
|
|
||||||
Width: PARENT_WIDTH - 80 - 80 - 24
|
Width: PARENT_WIDTH - 80 - 80 - 24
|
||||||
Height: PARENT_HEIGHT
|
Height: PARENT_HEIGHT
|
||||||
Align: Center
|
Align: Center
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Container@SKIRMISH_STATS:
|
|||||||
Width: 482
|
Width: 482
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: MediumBold
|
Font: MediumBold
|
||||||
Text: label-objective-mission
|
Text: label-mission-objective
|
||||||
Label@STATS_STATUS:
|
Label@STATS_STATUS:
|
||||||
X: 100
|
X: 100
|
||||||
Y: 22
|
Y: 22
|
||||||
@@ -25,7 +25,7 @@ Container@SKIRMISH_STATS:
|
|||||||
Width: 482
|
Width: 482
|
||||||
Height: 20
|
Height: 20
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Text: checkbox-objective-stats
|
Text: checkbox-stats-objective
|
||||||
Disabled: true
|
Disabled: true
|
||||||
TextColorDisabled: FFFFFF
|
TextColorDisabled: FFFFFF
|
||||||
Container@STATS_HEADERS:
|
Container@STATS_HEADERS:
|
||||||
|
|||||||
@@ -252,8 +252,8 @@ Container@LOBBY_PLAYER_BIN:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Text: label-lobby-players-faction
|
Text: label-lobby-players-faction
|
||||||
Label@TEAM:
|
Label@TEAM:
|
||||||
X: 420
|
X: 410
|
||||||
Width: 42
|
Width: 43
|
||||||
Height: 25
|
Height: 25
|
||||||
Align: Center
|
Align: Center
|
||||||
Text: label-lobby-players-team
|
Text: label-lobby-players-team
|
||||||
|
|||||||
@@ -144,6 +144,45 @@ Background@MISSIONBROWSER_PANEL:
|
|||||||
Visible: False
|
Visible: False
|
||||||
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
TooltipContainer: TOOLTIP_CONTAINER
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
|
Container@MISSION_MINIFIED_OPTIONS:
|
||||||
|
X: 220
|
||||||
|
Width: PARENT_WIDTH - 220
|
||||||
|
Height: PARENT_HEIGHT
|
||||||
|
Visible: False
|
||||||
|
Children:
|
||||||
|
LabelForInput@DIFFICULTY_DESC:
|
||||||
|
Y: PARENT_HEIGHT - 80
|
||||||
|
Width: 56
|
||||||
|
Height: 25
|
||||||
|
Align: Right
|
||||||
|
Text: dropdown-missionbrowser-difficulty.label
|
||||||
|
For: DIFFICULTY
|
||||||
|
DropDownButton@DIFFICULTY:
|
||||||
|
X: 71
|
||||||
|
Y: PARENT_HEIGHT - 80
|
||||||
|
Width: 140
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
|
Text: label-missionbrowser-normal-difficulty
|
||||||
|
TooltipText: dropdown-missionbrowser-difficulty.description
|
||||||
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
|
LabelForInput@GAMESPEED_DESC:
|
||||||
|
X: PARENT_WIDTH - 140 - WIDTH - 35
|
||||||
|
Y: PARENT_HEIGHT - 80
|
||||||
|
Width: 56
|
||||||
|
Height: 25
|
||||||
|
Align: Right
|
||||||
|
Text: dropdown-missionbrowser-gamespeed
|
||||||
|
For: GAMESPEED
|
||||||
|
DropDownButton@GAMESPEED:
|
||||||
|
X: PARENT_WIDTH - 160
|
||||||
|
Y: PARENT_HEIGHT - 80
|
||||||
|
Width: 140
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
|
PanelRoot: MISSION_DROPDOWN_PANEL_ROOT
|
||||||
|
TooltipContainer: TOOLTIP_CONTAINER
|
||||||
Button@START_BRIEFING_VIDEO_BUTTON:
|
Button@START_BRIEFING_VIDEO_BUTTON:
|
||||||
X: 20
|
X: 20
|
||||||
Y: PARENT_HEIGHT - 45
|
Y: PARENT_HEIGHT - 45
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
## world
|
## world
|
||||||
dropdown-difficulty =
|
dropdown-difficulty =
|
||||||
.label = Difficulty
|
.label = Difficulty
|
||||||
.description = The difficulty of the mission.
|
.description = The difficulty of the mission
|
||||||
|
|
||||||
options-difficulty =
|
options-difficulty =
|
||||||
.easy = Easy
|
.easy = Easy
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ supportpowers-support-powers-palette =
|
|||||||
|
|
||||||
button-command-bar-attack-move =
|
button-command-bar-attack-move =
|
||||||
.tooltip = Attack Move
|
.tooltip = Attack Move
|
||||||
.tooltipdesc = Selected units will move to the desired location
|
.tooltipdesc =
|
||||||
|
Selected units will move to the desired location
|
||||||
and attack any enemies they encounter en route.
|
and attack any enemies they encounter en route.
|
||||||
|
|
||||||
Hold <(Ctrl)> while targeting to order an Assault Move
|
Hold <(Ctrl)> while targeting to order an Assault Move
|
||||||
@@ -78,7 +79,8 @@ button-command-bar-attack-move =
|
|||||||
|
|
||||||
button-command-bar-force-move =
|
button-command-bar-force-move =
|
||||||
.tooltip = Force Move
|
.tooltip = Force Move
|
||||||
.tooltipdesc = Selected units will move to the desired location
|
.tooltipdesc =
|
||||||
|
Selected units will move to the desired location
|
||||||
- Default activity for the target is suppressed
|
- Default activity for the target is suppressed
|
||||||
- Vehicles will attempt to crush enemies at the target location
|
- Vehicles will attempt to crush enemies at the target location
|
||||||
- Deployed thumpers will undeploy and move to the target location
|
- Deployed thumpers will undeploy and move to the target location
|
||||||
@@ -88,7 +90,8 @@ button-command-bar-force-move =
|
|||||||
|
|
||||||
button-command-bar-force-attack =
|
button-command-bar-force-attack =
|
||||||
.tooltip = Force Attack
|
.tooltip = Force Attack
|
||||||
.tooltipdesc = Selected units will attack the targeted unit or location
|
.tooltipdesc =
|
||||||
|
Selected units will attack the targeted unit or location
|
||||||
- Default activity for the target is suppressed
|
- Default activity for the target is suppressed
|
||||||
- Allows targeting of own or ally forces
|
- Allows targeting of own or ally forces
|
||||||
|
|
||||||
@@ -97,13 +100,15 @@ button-command-bar-force-attack =
|
|||||||
|
|
||||||
button-command-bar-guard =
|
button-command-bar-guard =
|
||||||
.tooltip = Guard
|
.tooltip = Guard
|
||||||
.tooltipdesc = Selected units will follow the targeted unit.
|
.tooltipdesc =
|
||||||
|
Selected units will follow the targeted unit.
|
||||||
|
|
||||||
Left-click icon then right-click on target unit.
|
Left-click icon then right-click on target unit.
|
||||||
|
|
||||||
button-command-bar-deploy =
|
button-command-bar-deploy =
|
||||||
.tooltip = Deploy
|
.tooltip = Deploy
|
||||||
.tooltipdesc = Selected units will perform their default deploy activity
|
.tooltipdesc =
|
||||||
|
Selected units will perform their default deploy activity
|
||||||
- MCVs will unpack into a Construction Yard
|
- MCVs will unpack into a Construction Yard
|
||||||
- Thumpers will start or stop attracting worms
|
- Thumpers will start or stop attracting worms
|
||||||
- Devastators will become immobilized and explode
|
- Devastators will become immobilized and explode
|
||||||
@@ -112,21 +117,24 @@ button-command-bar-deploy =
|
|||||||
|
|
||||||
button-command-bar-scatter =
|
button-command-bar-scatter =
|
||||||
.tooltip = Scatter
|
.tooltip = Scatter
|
||||||
.tooltipdesc = Selected units will stop their current activity
|
.tooltipdesc =
|
||||||
|
Selected units will stop their current activity
|
||||||
and move to a nearby location.
|
and move to a nearby location.
|
||||||
|
|
||||||
Acts immediately on selected units.
|
Acts immediately on selected units.
|
||||||
|
|
||||||
button-command-bar-stop =
|
button-command-bar-stop =
|
||||||
.tooltip = Stop
|
.tooltip = Stop
|
||||||
.tooltipdesc = Selected units will stop their current activity.
|
.tooltipdesc =
|
||||||
|
Selected units will stop their current activity.
|
||||||
Selected buildings will reset their rally point.
|
Selected buildings will reset their rally point.
|
||||||
|
|
||||||
Acts immediately on selected targets.
|
Acts immediately on selected targets.
|
||||||
|
|
||||||
button-command-bar-queue-orders =
|
button-command-bar-queue-orders =
|
||||||
.tooltip = Waypoint Mode
|
.tooltip = Waypoint Mode
|
||||||
.tooltipdesc = Use Waypoint Mode to give multiple linking commands
|
.tooltipdesc =
|
||||||
|
Use Waypoint Mode to give multiple linking commands
|
||||||
to the selected units. Units will execute the commands
|
to the selected units. Units will execute the commands
|
||||||
immediately upon receiving them.
|
immediately upon receiving them.
|
||||||
|
|
||||||
@@ -135,25 +143,29 @@ button-command-bar-queue-orders =
|
|||||||
|
|
||||||
button-stance-bar-attackanything =
|
button-stance-bar-attackanything =
|
||||||
.tooltip = Attack Anything Stance
|
.tooltip = Attack Anything Stance
|
||||||
.tooltipdesc = Set the selected units to Attack Anything stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Attack Anything stance:
|
||||||
- Units will attack enemy units and structures on sight
|
- Units will attack enemy units and structures on sight
|
||||||
- Units will pursue attackers across the battlefield
|
- Units will pursue attackers across the battlefield
|
||||||
|
|
||||||
button-stance-bar-defend =
|
button-stance-bar-defend =
|
||||||
.tooltip = Defend Stance
|
.tooltip = Defend Stance
|
||||||
.tooltipdesc = Set the selected units to Defend stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Defend stance:
|
||||||
- Units will attack enemy units on sight
|
- Units will attack enemy units on sight
|
||||||
- Units will not move or pursue enemies
|
- Units will not move or pursue enemies
|
||||||
|
|
||||||
button-stance-bar-returnfire =
|
button-stance-bar-returnfire =
|
||||||
.tooltip = Return Fire Stance
|
.tooltip = Return Fire Stance
|
||||||
.tooltipdesc = Set the selected units to Return Fire stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Return Fire stance:
|
||||||
- Units will retaliate against enemies that attack them
|
- Units will retaliate against enemies that attack them
|
||||||
- Units will not move or pursue enemies
|
- Units will not move or pursue enemies
|
||||||
|
|
||||||
button-stance-bar-holdfire =
|
button-stance-bar-holdfire =
|
||||||
.tooltip = Hold Fire Stance
|
.tooltip = Hold Fire Stance
|
||||||
.tooltipdesc = Set the selected units to Hold Fire stance:
|
.tooltipdesc =
|
||||||
|
Set the selected units to Hold Fire stance:
|
||||||
- Units will not fire upon enemies
|
- Units will not fire upon enemies
|
||||||
- Units will not move or pursue enemies
|
- Units will not move or pursue enemies
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ not-enough-silos = We don't have enough silo space to store the required amount
|
|||||||
|
|
||||||
## atreides-01ab, harkonnen-01ab, ordos01ab
|
## atreides-01ab, harkonnen-01ab, ordos01ab
|
||||||
build-concrete = Build a concrete foundation before placing structures.
|
build-concrete = Build a concrete foundation before placing structures.
|
||||||
build-windtrap = Build a Wind Trap to generate power.
|
build-wind-trap = Build a Wind Trap to generate power.
|
||||||
build-refinery = Build a Refinery to collect Spice.
|
build-refinery = Build a Refinery to collect Spice.
|
||||||
build-silo = Build a Silo to store additional Spice.
|
build-silo = Build a Silo to store additional Spice.
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ eliminate-ordos-units-reinforcements = Eliminate all Ordos forces and reinforcem
|
|||||||
destroy-harkonnen = Destroy the Harkonnen.
|
destroy-harkonnen = Destroy the Harkonnen.
|
||||||
|
|
||||||
## atreides-04
|
## atreides-04
|
||||||
fremen-leader = Fremen Leader.
|
fremen-leader = Fremen Leader
|
||||||
sietch-integrity = Sietch structural integrity: { $integrity }%
|
sietch-integrity = Sietch structural integrity: { $integrity }%
|
||||||
protect-fremen-sietch = Protect the Fremen Sietch.
|
protect-fremen-sietch = Protect the Fremen Sietch.
|
||||||
keep-sietch-intact = Keep the Sietch { $integrity }% intact!
|
keep-sietch-intact = Keep the Sietch { $integrity }% intact!
|
||||||
@@ -127,7 +127,7 @@ atreides-hostile = The Atreides are now hostile!
|
|||||||
mercenaries-annihilated = The Mercenaries have been annihilated!
|
mercenaries-annihilated = The Mercenaries have been annihilated!
|
||||||
ally-mercenaries = Persuade the Mercenaries to fight alongside House Harkonnen.
|
ally-mercenaries = Persuade the Mercenaries to fight alongside House Harkonnen.
|
||||||
mercenary-leader-captured-allied = Leader Captured. The mercenaries have been persuaded to fight with House Harkonnen.
|
mercenary-leader-captured-allied = Leader Captured. The mercenaries have been persuaded to fight with House Harkonnen.
|
||||||
can-not-stand-harkonnen-must-become-neutral = We cannot stand against the Harkonnen. We must become neutral.
|
cannot-stand-harkonnen-must-become-neutral = We cannot stand against the Harkonnen. We must become neutral.
|
||||||
atreides-commander = Atreides Commander
|
atreides-commander = Atreides Commander
|
||||||
|
|
||||||
## harkonnen-09ab
|
## harkonnen-09ab
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ resource-spice = Spice
|
|||||||
|
|
||||||
faction-random =
|
faction-random =
|
||||||
.name = Any
|
.name = Any
|
||||||
.description = Random House.
|
.description = Random House
|
||||||
A random house is chosen at the start of the game.
|
A random house is chosen at the start of the game
|
||||||
|
|
||||||
faction-atreides =
|
faction-atreides =
|
||||||
.name = Atreides
|
.name = Atreides
|
||||||
@@ -65,7 +65,7 @@ faction-harkonnen =
|
|||||||
wealth, and the destruction of House Atreides.
|
wealth, and the destruction of House Atreides.
|
||||||
|
|
||||||
Faction Variations:
|
Faction Variations:
|
||||||
- Combat Tanks are more durable but move at a slower speed.
|
- Combat Tanks are more durable but move at a slower speed
|
||||||
|
|
||||||
Special Units:
|
Special Units:
|
||||||
- Sardaukar
|
- Sardaukar
|
||||||
@@ -82,8 +82,8 @@ faction-ordos =
|
|||||||
and forbidden Ixian technologies to gain the upper hand.
|
and forbidden Ixian technologies to gain the upper hand.
|
||||||
|
|
||||||
Faction Variations:
|
Faction Variations:
|
||||||
- Trikes are replaced by Raider Trikes.
|
- Trikes are replaced by Raider Trikes
|
||||||
- Combat Tanks are faster but less durable.
|
- Combat Tanks are faster but less durable
|
||||||
|
|
||||||
Special Units:
|
Special Units:
|
||||||
- Raider Trike
|
- Raider Trike
|
||||||
@@ -112,18 +112,22 @@ notification-primary-building-selected = Primary building selected.
|
|||||||
## aircraft.yaml
|
## aircraft.yaml
|
||||||
actor-carryall-reinforce =
|
actor-carryall-reinforce =
|
||||||
.name = Carryall
|
.name = Carryall
|
||||||
.description = Large winged, planet-bound ship
|
.description =
|
||||||
|
Large winged, planet-bound ship
|
||||||
Automatically lifts harvesters to and from Spice fields.
|
Automatically lifts harvesters to and from Spice fields.
|
||||||
Lifts vehicles to Repair Pads when ordered to.
|
Lifts vehicles to Repair Pads when ordered to.
|
||||||
|
|
||||||
actor-carryall-encyclopedia = Automatically transport Harvesters between the Spice Fields and Refineries. They can also pick up units and deliver them to the Repair Pad when ordered to.
|
actor-carryall-encyclopedia =
|
||||||
|
Automatically transport Harvesters between the Spice Fields and Refineries. They can also pick up units and deliver them to the Repair Pad when ordered to.
|
||||||
|
|
||||||
The Carryall is a lightly armored transport aircraft. It is vulnerable to missiles and can only be hit by anti-aircraft weapons.
|
The Carryall is a lightly armored transport aircraft. It is vulnerable to missiles and can only be hit by anti-aircraft weapons.
|
||||||
|
|
||||||
actor-frigate-name = Frigate
|
actor-frigate-name = Frigate
|
||||||
|
|
||||||
actor-ornithopter =
|
actor-ornithopter =
|
||||||
.name = Ornithopter
|
.name = Ornithopter
|
||||||
.encyclopedia = The fastest aircraft on Dune, it is lightly armored and capable of dropping 500 lb bombs. Highly effective against infantry and lightly armored targets, with the ability to damage other armor types.
|
.encyclopedia =
|
||||||
|
The fastest aircraft on Dune, it is lightly armored and capable of dropping 500 lb bombs. Highly effective against infantry and lightly armored targets, with the ability to damage other armor types.
|
||||||
|
|
||||||
actor-ornithopter-husk-name = Ornithopter
|
actor-ornithopter-husk-name = Ornithopter
|
||||||
actor-carryall-husk-name = Carryall
|
actor-carryall-husk-name = Carryall
|
||||||
@@ -159,80 +163,99 @@ meta-combat-tank-husk-name = Combat Tank (Destroyed)
|
|||||||
## infantry.yaml
|
## infantry.yaml
|
||||||
actor-light-inf =
|
actor-light-inf =
|
||||||
.name = Light Infantry
|
.name = Light Infantry
|
||||||
.description = General-purpose infantry.
|
.description =
|
||||||
Strong vs. Infantry.
|
General-purpose infantry.
|
||||||
Weak vs. Vehicles and Artillery.
|
Strong vs Infantry
|
||||||
.encyclopedia = Lightly armored foot soldiers, equipped with 9mm RP assault rifles. They are effective against infantry and lightly armored vehicles.
|
Weak vs Vehicles and Artillery
|
||||||
|
.encyclopedia =
|
||||||
|
Lightly armored foot soldiers, equipped with 9mm RP assault rifles. They are effective against infantry and lightly armored vehicles.
|
||||||
|
|
||||||
Light Infantry are resistant to missiles and large-caliber guns, but are very vulnerable to high-explosives, fire and bullet weapons.
|
Light Infantry are resistant to missiles and large-caliber guns, but are very vulnerable to high-explosives, fire, and small arms.
|
||||||
|
|
||||||
actor-engineer =
|
actor-engineer =
|
||||||
.name = Engineer
|
.name = Engineer
|
||||||
.description = Infiltrates and captures enemy structures.
|
.description =
|
||||||
Strong vs. Buildings.
|
Infiltrates and captures enemy
|
||||||
Weak vs. Everything.
|
structures.
|
||||||
Repairs damaged cliffs.
|
Strong vs Buildings
|
||||||
.encyclopedia = Can be used to capture enemy buildings.
|
Weak vs Everything
|
||||||
|
Repairs damaged cliffs
|
||||||
|
.encyclopedia =
|
||||||
|
Can be used to capture enemy buildings.
|
||||||
|
|
||||||
Engineers are resistant to anti-tank weaponry but are very vulnerable to high-explosives, fire and firearms.
|
Engineers are resistant to anti-tank weaponry but are very vulnerable to high-explosives, fire, and small arms.
|
||||||
|
|
||||||
actor-trooper =
|
actor-trooper =
|
||||||
.name = Trooper
|
.name = Trooper
|
||||||
.description = Anti-tank infantry.
|
.description =
|
||||||
Strong vs. Tanks.
|
Anti-tank infantry.
|
||||||
Weak vs. Infantry and Artillery.
|
Strong vs Tanks
|
||||||
.encyclopedia = Armed with wire-guided, armor-piercing missile warheads, Troopers are very effective against vehicles and buildings but struggle against infantry.
|
Weak vs Infantry and Artillery
|
||||||
|
.encyclopedia =
|
||||||
|
Armed with wire-guided, armor-piercing missile warheads, Troopers are very effective against vehicles and buildings but struggle against infantry.
|
||||||
|
|
||||||
Troopers are resistant to anti-tank weaponry but very vulnerable to high-explosives, fire and bullet weapons.
|
Troopers are resistant to anti-tank weaponry but very vulnerable to high-explosives, fire and bullet weapons.
|
||||||
|
|
||||||
actor-thumper =
|
actor-thumper =
|
||||||
.name = Thumper Infantry
|
.name = Thumper Infantry
|
||||||
.description = Attracts nearby worms when deployed.
|
.description =
|
||||||
Unarmed.
|
Attracts nearby worms when deployed.
|
||||||
.encyclopedia = Deploys a loud hammering device that draws Sandworms to the area.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
Deploys a loud hammering device that draws Sandworms to the area.
|
||||||
|
|
||||||
actor-fremen =
|
actor-fremen =
|
||||||
.name = Fremen
|
.name = Fremen
|
||||||
.description = Elite infantry unit with assault rifles and rockets.
|
.description =
|
||||||
Strong vs. Infantry and Vehicles.
|
Elite infantry unit with assault rifles and rockets.
|
||||||
Weak vs. Artillery.
|
Strong vs Infantry and Vehicles
|
||||||
Special Ability: Invisibility.
|
Weak vs Artillery
|
||||||
.encyclopedia = The native desert warriors of Dune, armed with 10mm Assault Rifles and Rockets. Their firepower is equally effective against infantry and vehicles.
|
Special Ability: Invisibility
|
||||||
|
.encyclopedia =
|
||||||
|
The native desert warriors of Dune, armed with 10mm Assault Rifles and Rockets. Their firepower is equally effective against infantry and vehicles.
|
||||||
|
|
||||||
Fremen units are very vulnerable to high-explosive and bullet weapons.
|
Fremen units are very vulnerable to high-explosive and bullet weapons.
|
||||||
|
|
||||||
actor-grenadier =
|
actor-grenadier =
|
||||||
.name = Grenadier
|
.name = Grenadier
|
||||||
.description = Infantry with grenades.
|
.description =
|
||||||
Strong vs. Buildings and Infantry.
|
Infantry with grenades.
|
||||||
Weak vs. Vehicles.
|
Strong vs Buildings and Infantry
|
||||||
.encyclopedia = An infantry artillery unit strong against buildings. They have a chance of exploding when killed, so should not be grouped together.
|
Weak vs Vehicles
|
||||||
|
.encyclopedia =
|
||||||
|
An infantry artillery unit strong against buildings. They have a chance of exploding when killed, so should not be grouped together.
|
||||||
|
|
||||||
actor-sardaukar =
|
actor-sardaukar =
|
||||||
.name = Sardaukar
|
.name = Sardaukar
|
||||||
.description = Elite Corrino assault infantry.
|
.description =
|
||||||
Strong vs. Infantry and Vehicles.
|
Elite Corrino assault infantry.
|
||||||
Weak vs. Artillery.
|
Strong vs Infantry and Vehicles
|
||||||
.encyclopedia = Powerful heavy troopers equipped with a machine gun that is effective against infantry and a rocket launcher for targeting vehicles.
|
Weak vs Artillery
|
||||||
|
.encyclopedia =
|
||||||
|
Powerful heavy troopers equipped with a machine gun that is effective against infantry and a rocket launcher for targeting vehicles.
|
||||||
|
|
||||||
actor-mpsardaukar-description = Elite Harkonnen assault infantry.
|
actor-mpsardaukar-description =
|
||||||
Strong vs. Infantry and Vehicles.
|
Elite Harkonnen assault infantry.
|
||||||
Weak vs. Artillery.
|
Strong vs Infantry and Vehicles
|
||||||
|
Weak vs Artillery
|
||||||
|
|
||||||
actor-saboteur =
|
actor-saboteur =
|
||||||
.name = Saboteur
|
.name = Saboteur
|
||||||
.description = Sneaky infantry with explosives.
|
.description =
|
||||||
|
Sneaky infantry with explosives.
|
||||||
Turns invisible for a limited time.
|
Turns invisible for a limited time.
|
||||||
Strong vs. Buildings.
|
Strong vs Buildings
|
||||||
Weak vs. Everything.
|
Weak vs Everything
|
||||||
Special Ability: Destroys buildings.
|
Special Ability: Destroys buildings
|
||||||
.encyclopedia = A specialized military unit of House Ordos, capable of demolishing enemy buildings upon entry, but dying in the resulting explosion. It can activate stealth mode to become invisible.
|
.encyclopedia =
|
||||||
|
A specialized military unit of House Ordos, capable of demolishing enemy buildings upon entry, but dying in the resulting explosion. It can activate stealth mode to become invisible.
|
||||||
|
|
||||||
The Saboteur is resistant to anti-tank weaponry, but very vulnerable to high-explosives, fire, and bullet weapons.
|
The Saboteur is resistant to anti-tank weaponry, but very vulnerable to high-explosives, fire, and bullet weapons.
|
||||||
|
|
||||||
actor-nsfremen-description = Elite infantry unit with assault rifles and rockets.
|
actor-nsfremen-description =
|
||||||
Strong vs. Infantry and Vehicles.
|
Elite infantry unit with assault rifles and rockets.
|
||||||
Weak vs. Artillery.
|
Strong vs Infantry and Vehicles
|
||||||
|
Weak vs Artillery
|
||||||
|
|
||||||
## misc.yaml
|
## misc.yaml
|
||||||
actor-crate-name = Crate
|
actor-crate-name = Crate
|
||||||
@@ -243,40 +266,53 @@ actor-wormspawner-name = (worm spawning location)
|
|||||||
|
|
||||||
actor-upgrade-conyard =
|
actor-upgrade-conyard =
|
||||||
.name = Construction Yard Upgrade
|
.name = Construction Yard Upgrade
|
||||||
.description = Unlocks additional construction options:
|
.description =
|
||||||
(Large Concrete Slab and Rocket Turret)
|
Unlocks additional construction options:
|
||||||
|
- Large Concrete Slab
|
||||||
|
- Rocket Turret
|
||||||
|
|
||||||
actor-upgrade-barracks =
|
actor-upgrade-barracks =
|
||||||
.name = Barracks Upgrade
|
.name = Barracks Upgrade
|
||||||
.description = Unlocks additional infantry:
|
.description =
|
||||||
(Trooper, Engineer and Thumper Infantry)
|
Unlocks additional infantry:
|
||||||
|
- Trooper
|
||||||
|
- Engineer
|
||||||
|
- Thumper Infantry
|
||||||
|
|
||||||
Required to unlock faction-specific infantry:
|
Required to unlock faction-specific infantry:
|
||||||
(Atreides: Grenadier, Harkonnen: Sardaukar)
|
- Atreides: Grenadier
|
||||||
|
- Harkonnen: Sardaukar
|
||||||
|
|
||||||
actor-upgrade-light =
|
actor-upgrade-light =
|
||||||
.name = Light Factory Upgrade
|
.name = Light Factory Upgrade
|
||||||
.description = Unlocks additional light units:
|
.description =
|
||||||
(Missile Quad)
|
Unlocks additional light units:
|
||||||
|
- Missile Quad
|
||||||
|
|
||||||
Required to unlock a faction-specific light unit:
|
Required to unlock a faction-specific light unit:
|
||||||
(Ordos: Stealth Raider Trike)
|
- Ordos: Stealth Raider Trike
|
||||||
|
|
||||||
actor-upgrade-heavy =
|
actor-upgrade-heavy =
|
||||||
.name = Heavy Factory Upgrade
|
.name = Heavy Factory Upgrade
|
||||||
.description = Unlocks additional construction options:
|
.description =
|
||||||
(Repair Pad and IX Research Center)
|
Unlocks additional construction options:
|
||||||
|
- Repair Pad
|
||||||
|
- IX Research Center
|
||||||
|
|
||||||
Unlocks additional heavy units:
|
Unlocks additional heavy units:
|
||||||
(Siege Tank, Missile Tank and MCV)
|
- Siege Tank
|
||||||
|
- Missile Tank
|
||||||
|
- MCV
|
||||||
|
|
||||||
actor-upgrade-hightech =
|
actor-upgrade-hightech =
|
||||||
.name = High Tech Factory Upgrade
|
.name = High Tech Factory Upgrade
|
||||||
.description = Unlocks the Atreides Air Strike superweapon.
|
.description =
|
||||||
|
Unlocks the Atreides Air Strike superweapon.
|
||||||
|
|
||||||
actor-deathhand =
|
actor-deathhand =
|
||||||
.name = Death Hand
|
.name = Death Hand
|
||||||
.encyclopedia = Armed with atomic cluster munitions, it detonates above its target, inflicting great damage over a wide area.
|
.encyclopedia =
|
||||||
|
Armed with atomic cluster munitions, it detonates above its target, inflicting great damage over a wide area.
|
||||||
|
|
||||||
## structures.yaml
|
## structures.yaml
|
||||||
notification-construction-complete = Construction complete.
|
notification-construction-complete = Construction complete.
|
||||||
@@ -295,12 +331,14 @@ notification-saboteur-ready = Saboteur ready.
|
|||||||
|
|
||||||
meta-concrete =
|
meta-concrete =
|
||||||
.generic-name = Structure
|
.generic-name = Structure
|
||||||
.description = Provides a strong foundation that protects
|
.description =
|
||||||
against terrain damage.
|
Provides a strong foundation that
|
||||||
|
protects against terrain damage.
|
||||||
|
|
||||||
actor-concrete-a =
|
actor-concrete-a =
|
||||||
.name = Concrete Slab
|
.name = Concrete Slab
|
||||||
.encyclopedia = Buildings not constructed on a Concrete Slab will sustain ongoing damage from the harsh desert environment of Dune. While repairs are possible, placing structures on concrete prevents continuous weathering.
|
.encyclopedia =
|
||||||
|
Buildings not constructed on a Concrete Slab will sustain ongoing damage from the harsh desert environment of Dune. While repairs are possible, placing structures on concrete prevents continuous weathering.
|
||||||
|
|
||||||
Concrete is vulnerable to most weapons and cannot be repaired once damaged.
|
Concrete is vulnerable to most weapons and cannot be repaired once damaged.
|
||||||
|
|
||||||
@@ -309,64 +347,78 @@ actor-concrete-b-name = Large Concrete Slab
|
|||||||
actor-construction-yard =
|
actor-construction-yard =
|
||||||
.name = Construction Yard
|
.name = Construction Yard
|
||||||
.description = Produces structures.
|
.description = Produces structures.
|
||||||
.encyclopedia = Serving as the foundation of any base built on Arrakis, the Construction Yard produces a small amount of power and enables the construction of new structures. Protect this structure! It is critical to the success of your base.
|
.encyclopedia =
|
||||||
|
Serving as the foundation of any base built on Arrakis, the Construction Yard produces a small amount of power and enables the construction of new structures. Protect this structure! It is critical to the success of your base.
|
||||||
|
|
||||||
Construction yards are fairly strong, but vulnerable to all weapons to varying degrees.
|
Construction yards are fairly strong, but vulnerable to all weapons to varying degrees.
|
||||||
|
|
||||||
actor-wind-trap =
|
actor-wind-trap =
|
||||||
.name = Wind Trap
|
.name = Wind Trap
|
||||||
.description = Supplies power to other structures.
|
.description =
|
||||||
.encyclopedia = Produces power and water for your base. Large, above-ground ducts funnel wind currents underground into massive turbines, which drive power generators and humidity extractors.
|
Supplies power to other
|
||||||
|
structures.
|
||||||
|
.encyclopedia =
|
||||||
|
Produces power and water for your base. Large, above-ground ducts funnel wind currents underground into massive turbines, which drive power generators and humidity extractors.
|
||||||
|
|
||||||
Wind Traps are vulnerable to most weapons.
|
Wind Traps are vulnerable to most weapons.
|
||||||
|
|
||||||
actor-barracks =
|
actor-barracks =
|
||||||
.name = Barracks
|
.name = Barracks
|
||||||
.description = Trains infantry.
|
.description = Trains infantry.
|
||||||
.encyclopedia = Required for producing and training light infantry units, it can be upgraded to train advanced infantry in later missions.
|
.encyclopedia =
|
||||||
|
Required for producing and training light infantry units, it can be upgraded to train advanced infantry in later missions.
|
||||||
|
|
||||||
Barracks are vulnerable to most weapons.
|
Barracks are vulnerable to most weapons.
|
||||||
|
|
||||||
actor-refinery =
|
actor-refinery =
|
||||||
.name = Spice Refinery
|
.name = Spice Refinery
|
||||||
.description = Harvesters unload Spice here for processing.
|
.description =
|
||||||
.encyclopedia = The basis of all Spice production on Dune. Harvesters transport mined Spice to the Refinery where it is converted into credits. Refined Spice is automatically distributed to Silos and Refineries for storage. Each refinery can store Spice. A Spice Harvester is delivered by Carryall once a Refinery is built.
|
Harvesters unload Spice here
|
||||||
|
for processing.
|
||||||
|
.encyclopedia =
|
||||||
|
The basis of all Spice production on Dune. Harvesters transport mined Spice to the Refinery where it is converted into credits. Refined Spice is automatically distributed to Silos and Refineries for storage. Each refinery can store Spice. A Spice Harvester is delivered by Carryall once a Refinery is built.
|
||||||
|
|
||||||
Refineries are vulnerable to most weapons.
|
Refineries are vulnerable to most weapons.
|
||||||
|
|
||||||
actor-silo =
|
actor-silo =
|
||||||
.name = Silo
|
.name = Silo
|
||||||
.description = Stores excess harvested Spice.
|
.description = Stores excess harvested Spice.
|
||||||
.encyclopedia = Store mined Spice. Any surplus from Refineries is evenly distributed among all available Silos. If storage capacity is exceeded, excess Spice is lost. Destroyed or captured Silos redistribute their contents, provided there is sufficient space.
|
.encyclopedia =
|
||||||
|
Store mined Spice. Any surplus from Refineries is evenly distributed among all available Silos. If storage capacity is exceeded, excess Spice is lost. Destroyed or captured Silos redistribute their contents, provided there is sufficient space.
|
||||||
|
|
||||||
The Spice Silo is vulnerable to most weapons.
|
The Spice Silo is vulnerable to most weapons.
|
||||||
|
|
||||||
actor-light-factory =
|
actor-light-factory =
|
||||||
.name = Light Factory
|
.name = Light Factory
|
||||||
.description = Produces light vehicles.
|
.description = Produces light vehicles.
|
||||||
.encyclopedia = Required to produce small, lightly armored combat vehicles. It can be upgraded in later missions to manufacture more advanced light vehicles.
|
.encyclopedia =
|
||||||
|
Required to produce small, lightly armored combat vehicles. It can be upgraded in later missions to manufacture more advanced light vehicles.
|
||||||
|
|
||||||
A Light Factory is vulnerable to most weapons.
|
A Light Factory is vulnerable to most weapons.
|
||||||
|
|
||||||
actor-heavy-factory =
|
actor-heavy-factory =
|
||||||
.name = Heavy Factory
|
.name = Heavy Factory
|
||||||
.description = Produces heavy vehicles.
|
.description = Produces heavy vehicles.
|
||||||
.encyclopedia = Enables the construction of heavy vehicles such as Harvesters and Combat Tanks. With upgrades, it unlocks advanced vehicles, though some may require additional buildings.
|
.encyclopedia =
|
||||||
|
Enables the construction of heavy vehicles such as Harvesters and Combat Tanks. With upgrades, it unlocks advanced vehicles, though some may require additional buildings.
|
||||||
|
|
||||||
The Heavy Factory is vulnerable to most weapons.
|
The Heavy Factory is vulnerable to most weapons.
|
||||||
|
|
||||||
actor-outpost =
|
actor-outpost =
|
||||||
.name = Outpost
|
.name = Outpost
|
||||||
.description = Provides a radar map of the battlefield.
|
.description =
|
||||||
|
Provides a radar map of the battlefield.
|
||||||
Requires power to operate.
|
Requires power to operate.
|
||||||
.encyclopedia = Once enough power is available, the Radar Outpost activates, providing a radar map.
|
.encyclopedia =
|
||||||
|
Once enough power is available, the Radar Outpost activates, providing a radar map.
|
||||||
|
|
||||||
The Radar Outpost is vulnerable to most weapons.
|
The Radar Outpost is vulnerable to most weapons.
|
||||||
|
|
||||||
actor-starport =
|
actor-starport =
|
||||||
.name = Starport
|
.name = Starport
|
||||||
.description = Dropzone for quick reinforcements, at a price.
|
.description = Dropzone for quick reinforcements, at a price.
|
||||||
.encyclopedia = Unlocks intergalactic trade with the CHOAM Merchants' Guild, where vehicles and airborne units can be purchased at varying rates. This facility is essential for acquiring units from the Guild.
|
.encyclopedia =
|
||||||
|
Unlocks intergalactic trade with the CHOAM Merchants' Guild, where vehicles and airborne units can be purchased at varying rates. This facility is essential for acquiring units from the Guild.
|
||||||
|
|
||||||
Even with heavy armor, the Starport is vulnerable to most weapons.
|
Even with heavy armor, the Starport is vulnerable to most weapons.
|
||||||
|
|
||||||
@@ -374,35 +426,41 @@ actor-wall =
|
|||||||
.name = Concrete Wall
|
.name = Concrete Wall
|
||||||
.generic-name = Structure
|
.generic-name = Structure
|
||||||
.description = Stops units and blocks enemy fire.
|
.description = Stops units and blocks enemy fire.
|
||||||
.encyclopedia = The most effective defensive barriers on Dune, blocking tank fire and impeding unit movement.
|
.encyclopedia =
|
||||||
|
The most effective defensive barriers on Dune, blocking tank fire and impeding unit movement.
|
||||||
|
|
||||||
Walls can only be damaged by explosive weapons, missiles and shells. Similar to concrete slabs, they cannot be repaired once damaged.
|
Walls can only be damaged by explosive weapons, missiles and shells. Similar to Concrete Slabs, they cannot be repaired once damaged.
|
||||||
|
|
||||||
actor-medium-gun-turret =
|
actor-medium-gun-turret =
|
||||||
.name = Gun Turret
|
.name = Gun Turret
|
||||||
.description = Defensive structure.
|
.description =
|
||||||
Strong vs. Tanks.
|
Defensive structure.
|
||||||
Weak vs. Infantry and Aircraft.
|
Strong vs Tanks
|
||||||
.encyclopedia = A medium-range weapon that is effective against all types of vehicle, particularly heavily armored ones. It automatically fires upon any enemy unit within its range and requires power to operate.
|
Weak vs Infantry and Aircraft
|
||||||
|
.encyclopedia =
|
||||||
|
A medium-range weapon that is effective against all types of vehicle, particularly heavily armored ones. It automatically fires upon any enemy unit within its range and requires power to operate.
|
||||||
|
|
||||||
The Gun Turret is resistant to firearms and explosive weapons, but vulnerable to missiles and high-caliber guns.
|
The Gun Turret is resistant to small arms and explosive weapons, but vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-large-gun-turret =
|
actor-large-gun-turret =
|
||||||
.name = Rocket Turret
|
.name = Rocket Turret
|
||||||
.description = Defensive structure.
|
.description =
|
||||||
Strong vs. Infantry and Aircraft.
|
Defensive structure.
|
||||||
Weak vs. Tanks.
|
|
||||||
|
|
||||||
Requires power to operate.
|
Requires power to operate.
|
||||||
.encyclopedia = An enhanced defensive structure with a longer range and faster rate of fire than the Gun Turret. Its advanced targeting system requires power to operate.
|
Strong vs Infantry and Aircraft
|
||||||
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
An enhanced defensive structure with a longer range and faster rate of fire than the Gun Turret. Its advanced targeting system requires power to operate.
|
||||||
|
|
||||||
The Rocket Turret is resistant to firearms and explosive weapons, but vulnerable to missiles and high-caliber guns.
|
The Rocket Turret is resistant to firearms and explosive weapons, but vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-repair-pad =
|
actor-repair-pad =
|
||||||
.name = Repair Pad
|
.name = Repair Pad
|
||||||
.description = Repairs vehicles.
|
.description =
|
||||||
|
Repairs vehicles.
|
||||||
Allows MCVs to be built.
|
Allows MCVs to be built.
|
||||||
.encyclopedia = Repairs units for a fraction of their production cost.
|
.encyclopedia =
|
||||||
|
Repairs units for a fraction of their production cost.
|
||||||
|
|
||||||
The Repair Pad is vulnerable to most weapons.
|
The Repair Pad is vulnerable to most weapons.
|
||||||
|
|
||||||
@@ -411,96 +469,113 @@ actor-high-tech-factory =
|
|||||||
.description = Unlocks advanced technology.
|
.description = Unlocks advanced technology.
|
||||||
.airstrikepower-name = Air Strike
|
.airstrikepower-name = Air Strike
|
||||||
.airstrikepower-description = Ornithopters bomb the target.
|
.airstrikepower-description = Ornithopters bomb the target.
|
||||||
.encyclopedia = Produces airborne units, and is required to build Carryalls. House Atreides can upgrade this facility to build Ornithopters for air strikes in later missions.
|
.encyclopedia =
|
||||||
|
Produces airborne units, and is required to build Carryalls. House Atreides can upgrade this facility to build Ornithopters for air strikes in later missions.
|
||||||
|
|
||||||
The High Tech Factory is vulnerable to most weapons.
|
The High Tech Factory is vulnerable to most weapons.
|
||||||
|
|
||||||
actor-research-centre =
|
actor-research-centre =
|
||||||
.name = IX Research Center
|
.name = IX Research Center
|
||||||
.description = Unlocks advanced tanks.
|
.description = Unlocks advanced tanks.
|
||||||
.encyclopedia = Provides technology upgrades for both structures and vehicles. This facility is required to develop advanced special weapons and prototypes.
|
.encyclopedia =
|
||||||
|
Provides technology upgrades for both structures and vehicles. This facility is required to develop advanced special weapons and prototypes.
|
||||||
|
|
||||||
The IX Research Center is vulnerable to most weapons.
|
The IX Research Center is vulnerable to most weapons.
|
||||||
|
|
||||||
actor-palace =
|
actor-palace =
|
||||||
.name = Palace
|
.name = Palace
|
||||||
.description = Unlocks elite infantry and weapons.
|
.description = Unlocks elite infantry and weapons.
|
||||||
.encyclopedia = Serves as the command center once built, offering additional options and special weapons.
|
.encyclopedia =
|
||||||
|
Serves as the command center once built, offering additional options and special weapons.
|
||||||
|
|
||||||
Even with heavy armor, the Palace is vulnerable to most weapons.
|
Even with heavy armor, the Palace is vulnerable to most weapons.
|
||||||
.nukepower-name = Death Hand
|
.nukepower-name = Death Hand
|
||||||
.nukepower-description = Launches an atomic missile at a target location.
|
.nukepower-description = Launches an atomic missile at a target location.
|
||||||
.produceactorpower-fremen-name = Recruit Fremen
|
.produceactorpower-fremen-name = Recruit Fremen
|
||||||
.produceactorpower-fremen-description = Elite infantry unit with assault rifles and rockets.
|
.produceactorpower-fremen-description = Elite infantry unit with assault rifles and rockets.
|
||||||
Strong vs. Infantry and Vehicles.
|
Strong vs Infantry and Vehicles
|
||||||
Weak vs. Artillery.
|
Weak vs Artillery
|
||||||
Special Ability: Invisibility.
|
Special Ability: Invisibility
|
||||||
.produceactorpower-saboteur-name = Recruit Saboteur
|
.produceactorpower-saboteur-name = Recruit Saboteur
|
||||||
.produceactorpower-saboteur-description = Sneaky infantry with explosives.
|
.produceactorpower-saboteur-description = Sneaky infantry with explosives.
|
||||||
Can be deployed to become invisible for a limited time.
|
Can be deployed to become invisible for a limited time.
|
||||||
Strong vs Buildings.
|
Strong vs Buildings
|
||||||
Weak vs Everything.
|
Weak vs Everything
|
||||||
Special Ability: Destroys buildings.
|
Special Ability: Destroys buildings
|
||||||
|
|
||||||
## vehicles.yaml
|
## vehicles.yaml
|
||||||
actor-mcv =
|
actor-mcv =
|
||||||
.name = Mobile Construction Vehicle
|
.name = Mobile Construction Vehicle
|
||||||
.description = Deploys into a Construction Yard.
|
.description =
|
||||||
Unarmed.
|
Deploys into a Construction Yard.
|
||||||
.encyclopedia = Must be driven to an area where it can be deployed. After finding a suitable rock surface, the MCV can be transformed into a Construction Yard.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
Must be driven to an area where it can be deployed. After finding a suitable rock surface, the MCV can be transformed into a Construction Yard.
|
||||||
|
|
||||||
MCVs are resistant to bullets and light-explosives. They are vulnerable to missiles and high-caliber guns.
|
MCVs are resistant to bullets and light-explosives. They are vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-harvester =
|
actor-harvester =
|
||||||
.name = Spice Harvester
|
.name = Spice Harvester
|
||||||
.description = Collects Spice for processing.
|
.description =
|
||||||
Unarmed.
|
Collects Spice for processing.
|
||||||
.encyclopedia = Resistant to bullets, and to some degree, high explosives. They are vulnerable to missiles and high-caliber guns.
|
Unarmed
|
||||||
|
.encyclopedia =
|
||||||
|
Resistant to bullets, and to some degree, high explosives. They are vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
A Harvester is included with a Refinery.
|
A Harvester is included with a Refinery.
|
||||||
|
|
||||||
actor-trike =
|
actor-trike =
|
||||||
.name = Trike
|
.name = Trike
|
||||||
.description = Fast scout.
|
.description =
|
||||||
Strong vs. Infantry.
|
Fast scout.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry
|
||||||
.encyclopedia = Lightly armored, three-wheeled vehicles armed with heavy machine guns, effective against infantry and lightly armored vehicles.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Lightly armored, three-wheeled vehicles armed with heavy machine guns, effective against infantry and lightly armored vehicles.
|
||||||
|
|
||||||
Trikes are vulnerable to most weapons, high-caliber guns are slightly less effective against them.
|
Trikes are vulnerable to most weapons, high-caliber guns are slightly less effective against them.
|
||||||
|
|
||||||
actor-quad =
|
actor-quad =
|
||||||
.name = Missile Quad
|
.name = Missile Quad
|
||||||
.description = Missile Scout.
|
.description =
|
||||||
Strong vs. Vehicles.
|
Missile Scout.
|
||||||
Weak vs. Infantry.
|
Strong vs Vehicles
|
||||||
.encyclopedia = Superior to the Trike in both armor and firepower, the Quad is a four-wheeled vehicle firing armor-piercing rockets. It is effective against most vehicles.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
Superior to the Trike in both armor and firepower, the Quad is a four-wheeled vehicle firing armor-piercing rockets. It is effective against most vehicles.
|
||||||
|
|
||||||
Quads are resistant to bullets and, to a lesser degree, explosives. They are vulnerable to missiles and high-caliber guns.
|
Quads are resistant to bullets and, to a lesser degree, explosives. They are vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-siege-tank =
|
actor-siege-tank =
|
||||||
.name = Siege Tank
|
.name = Siege Tank
|
||||||
.description = Siege Artillery.
|
.description =
|
||||||
Strong vs. Infantry and Buildings.
|
Siege Artillery.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry and Buildings
|
||||||
.encyclopedia = Incredibly effective against infantry and lightly armored vehicles, but struggles against heavily armored targets. It has a long firing range.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Incredibly effective against infantry and lightly armored vehicles, but struggles against heavily armored targets. It has a long firing range.
|
||||||
|
|
||||||
Siege Tanks are resistant to bullets, and to some degree, explosives. They are vulnerable to missiles and high-caliber guns.
|
Siege Tanks are resistant to bullets, and to some degree, explosives. They are vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-missile-tank =
|
actor-missile-tank =
|
||||||
.name = Missile Tank
|
.name = Missile Tank
|
||||||
.description = Rocket Artillery.
|
.description =
|
||||||
Strong vs. Vehicles, Buildings and Aircraft.
|
Rocket Artillery.
|
||||||
Weak vs. Infantry.
|
Strong vs Vehicles, Buildings and Aircraft
|
||||||
.encyclopedia = Shoots down aircraft and is effective against most targets, except infantry.
|
Weak vs Infantry
|
||||||
|
.encyclopedia =
|
||||||
|
Shoots down aircraft and is effective against most targets, except infantry.
|
||||||
|
|
||||||
Missile Tanks are vulnerable to most weapons, high-caliber guns are slightly less effective.
|
Missile Tanks are vulnerable to most weapons, high-caliber guns are slightly less effective.
|
||||||
|
|
||||||
actor-sonic-tank =
|
actor-sonic-tank =
|
||||||
.name = Sonic Tank
|
.name = Sonic Tank
|
||||||
.description = Fires sonic shocks.
|
.description =
|
||||||
Strong vs. Infantry and Vehicles.
|
Fires sonic shocks.
|
||||||
Weak vs. Artillery.
|
Strong vs Infantry and Vehicles
|
||||||
.encyclopedia = Most effective against infantry and lightly armored vehicles, but weaker against armored targets.
|
Weak vs Artillery
|
||||||
|
.encyclopedia =
|
||||||
|
Most effective against infantry and lightly armored vehicles, but weaker against armored targets.
|
||||||
|
|
||||||
Its sonic waves damage all units in their path.
|
Its sonic waves damage all units in their path.
|
||||||
|
|
||||||
@@ -508,56 +583,68 @@ actor-sonic-tank =
|
|||||||
|
|
||||||
actor-devastator =
|
actor-devastator =
|
||||||
.name = Devastator
|
.name = Devastator
|
||||||
.description = Super Heavy Tank.
|
.description =
|
||||||
Strong vs. Tanks.
|
Super Heavy Tank.
|
||||||
Weak vs. Artillery.
|
Strong vs Tanks
|
||||||
.encyclopedia = As the most powerful tank on Dune, the Devastator is slow but highly effective against most units. It fires dual plasma charges and can self-destruct on command, damaging nearby units and structures.
|
Weak vs Artillery
|
||||||
|
.encyclopedia =
|
||||||
|
As the most powerful tank on Dune, the Devastator is slow but highly effective against most units. It fires dual plasma charges and can self-destruct on command, damaging nearby units and structures.
|
||||||
|
|
||||||
Resistant to bullets and high explosives, but vulnerable to missiles and high-caliber guns.
|
Resistant to bullets and high explosives, but vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-raider =
|
actor-raider =
|
||||||
.name = Raider Trike
|
.name = Raider Trike
|
||||||
.description = Improved Scout.
|
.description =
|
||||||
Strong vs. Infantry and Light Vehicles.
|
Improved Scout.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry and Light Vehicles
|
||||||
.encyclopedia = Raider Trikes, upgraded by House Ordos, have enhanced firepower, speed, and armor. Equipped with dual 20mm cannons, they are strong against infantry and lightly armored vehicles.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
Raider Trikes, upgraded by House Ordos, have enhanced firepower, speed, and armor. Equipped with dual 20mm cannons, they are strong against infantry and lightly armored vehicles.
|
||||||
|
|
||||||
Raiders are vulnerable to most weapons, though high-caliber guns are slightly less effective against them.
|
Raiders are vulnerable to most weapons, though high-caliber guns are slightly less effective against them.
|
||||||
|
|
||||||
actor-stealth-raider =
|
actor-stealth-raider =
|
||||||
.name = Stealth Raider Trike
|
.name = Stealth Raider Trike
|
||||||
.description = Invisible Raider Trike.
|
.description =
|
||||||
Strong vs. Infantry and Light Vehicles.
|
Invisible Raider Trike.
|
||||||
Weak vs. Tanks.
|
Strong vs Infantry and Light Vehicles
|
||||||
.encyclopedia = A cloaked version of the Raider, good for stealth attacks. It uncloaks when it fires its machine guns.
|
Weak vs Tanks
|
||||||
|
.encyclopedia =
|
||||||
|
A cloaked version of the Raider, good for stealth attacks. It uncloaks when it fires its machine guns.
|
||||||
|
|
||||||
actor-deviator =
|
actor-deviator =
|
||||||
.name = Deviator
|
.name = Deviator
|
||||||
.description = Fires a warhead that changes
|
.description =
|
||||||
the allegiance of enemy vehicles.
|
Fires a warhead that changes the
|
||||||
.encyclopedia = Fires missiles that release a silicon cloud, temporarily altering the allegiance of targeted vehicles. Personnel are only slightly affected by the cloud.
|
allegiance of enemy vehicles.
|
||||||
|
.encyclopedia =
|
||||||
|
Fires missiles that release a silicon cloud, temporarily altering the allegiance of targeted vehicles. Personnel are only slightly affected by the cloud.
|
||||||
|
|
||||||
The Deviator is vulnerable to most weapons, high-caliber guns are slightly less effective.
|
The Deviator is vulnerable to most weapons, high-caliber guns are slightly less effective.
|
||||||
|
|
||||||
meta-combat-tank-description = Main Battle Tank.
|
meta-combat-tank-description =
|
||||||
Strong vs. Tanks.
|
Main Battle Tank.
|
||||||
Weak vs. Infantry.
|
Strong vs Tanks
|
||||||
|
Weak vs Infantry
|
||||||
|
|
||||||
actor-combat-tank-a =
|
actor-combat-tank-a =
|
||||||
.name = Atreides Combat Tank
|
.name = Atreides Combat Tank
|
||||||
.encyclopedia = Effective against most vehicles but less suited against lightly armored targets.
|
.encyclopedia =
|
||||||
|
Effective against most vehicles but less suited against lightly armored targets.
|
||||||
|
|
||||||
Resistant to bullets and heavy explosives, but vulnerable to missiles and high-caliber guns.
|
Resistant to bullets and heavy explosives, but vulnerable to missiles and high-caliber guns.
|
||||||
|
|
||||||
actor-combat-tank-h =
|
actor-combat-tank-h =
|
||||||
.name = Harkonnen Combat Tank
|
.name = Harkonnen Combat Tank
|
||||||
.encyclopedia = Effective against most vehicles but less suited against lightly armored targets.
|
.encyclopedia =
|
||||||
|
Effective against most vehicles but less suited against lightly armored targets.
|
||||||
|
|
||||||
Stronger than its counterparts, but also slower.
|
Stronger than its counterparts, but also slower.
|
||||||
|
|
||||||
actor-combat-tank-o =
|
actor-combat-tank-o =
|
||||||
.name = Ordos Combat Tank
|
.name = Ordos Combat Tank
|
||||||
.encyclopedia = Effective against most vehicles but less suited against lightly armored targets.
|
.encyclopedia =
|
||||||
|
Effective against most vehicles but less suited against lightly armored targets.
|
||||||
|
|
||||||
The fastest variant of Combat Tank, but also the weakest.
|
The fastest variant of Combat Tank, but also the weakest.
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ AtreidesEntryPath = { AtreidesWaypoint.Location, AtreidesRally.Location }
|
|||||||
Messages =
|
Messages =
|
||||||
{
|
{
|
||||||
UserInterface.GetFluentMessage("build-concrete"),
|
UserInterface.GetFluentMessage("build-concrete"),
|
||||||
UserInterface.GetFluentMessage("build-windtrap"),
|
UserInterface.GetFluentMessage("build-wind-trap"),
|
||||||
UserInterface.GetFluentMessage("build-refinery"),
|
UserInterface.GetFluentMessage("build-refinery"),
|
||||||
UserInterface.GetFluentMessage("build-silo")
|
UserInterface.GetFluentMessage("build-silo")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ AtreidesEntryPath = { AtreidesWaypoint.Location, AtreidesRally.Location }
|
|||||||
Messages =
|
Messages =
|
||||||
{
|
{
|
||||||
UserInterface.GetFluentMessage("build-concrete"),
|
UserInterface.GetFluentMessage("build-concrete"),
|
||||||
UserInterface.GetFluentMessage("build-windtrap"),
|
UserInterface.GetFluentMessage("build-wind-trap"),
|
||||||
UserInterface.GetFluentMessage("build-refinery"),
|
UserInterface.GetFluentMessage("build-refinery"),
|
||||||
UserInterface.GetFluentMessage("build-silo")
|
UserInterface.GetFluentMessage("build-silo")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location }
|
|||||||
Messages =
|
Messages =
|
||||||
{
|
{
|
||||||
UserInterface.GetFluentMessage("build-concrete"),
|
UserInterface.GetFluentMessage("build-concrete"),
|
||||||
UserInterface.GetFluentMessage("build-windtrap"),
|
UserInterface.GetFluentMessage("build-wind-trap"),
|
||||||
UserInterface.GetFluentMessage("build-refinery"),
|
UserInterface.GetFluentMessage("build-refinery"),
|
||||||
UserInterface.GetFluentMessage("build-silo")
|
UserInterface.GetFluentMessage("build-silo")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location }
|
|||||||
Messages =
|
Messages =
|
||||||
{
|
{
|
||||||
UserInterface.GetFluentMessage("build-concrete"),
|
UserInterface.GetFluentMessage("build-concrete"),
|
||||||
UserInterface.GetFluentMessage("build-windtrap"),
|
UserInterface.GetFluentMessage("build-wind-trap"),
|
||||||
UserInterface.GetFluentMessage("build-refinery"),
|
UserInterface.GetFluentMessage("build-refinery"),
|
||||||
UserInterface.GetFluentMessage("build-silo")
|
UserInterface.GetFluentMessage("build-silo")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,3 +79,4 @@ outpost:
|
|||||||
Tooltip@Modified:
|
Tooltip@Modified:
|
||||||
Name: actor-outpost-modified-name
|
Name: actor-outpost-modified-name
|
||||||
RequiresCondition: modified
|
RequiresCondition: modified
|
||||||
|
ShowOwnerRow: false
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user