Compare commits

...

26 Commits

Author SHA1 Message Date
Paul Chote
e55de6e2a0 Restore missing versioned source code package. 2021-01-03 15:09:54 +00:00
Paul Chote
299b8880dd Fix api output directory. 2020-12-14 18:33:35 +01:00
Paul Chote
61027e4067 Fix docs.openra.net repository reference. 2020-12-14 18:33:35 +01:00
Paul Chote
a7249c10dc Fix docs.openra.net documentation workflow. 2020-12-13 15:35:31 +01:00
Paul Chote
611d12ac78 Migrate CI and packaging from Travis CI to GitHub Actions. 2020-12-12 20:17:29 +00:00
abcdefg30
ef9f26a60d Fix MissionObjectives not properly ending the game 2020-12-12 14:59:49 +01:00
abcdefg30
aeaffc0a8e Properly restrict the spectator view in mission maps 2020-12-12 14:59:49 +01:00
Paul Chote
e3084e230e Switch mirror for nsis3 package. 2020-12-12 14:54:50 +01:00
Paul Chote
4c01c772f8 Fix incorrect animation playing when moving infantry stop to attack. 2020-12-12 14:40:13 +01:00
Paul Chote
ed94f7680a Revert "Fix WithInfantryBody wrongly overwriting attack animations"
This reverts commit 1a63cc4a41.
2020-12-12 14:40:13 +01:00
yuantse
408d66cdaf Add Allies 09a 2020-12-12 13:18:08 +01:00
Smittytron
c4a0f2f169 Add Counterstrike mission Sarin Gas 3: Controlled Burn 2020-12-12 13:15:18 +01:00
Paul Chote
26b28d26da Prevent Civilians from wandering onto Tiberium. 2020-12-12 12:54:46 +01:00
Paul Chote
8ded6dafd4 Add AvoidTerrainTypes to ScaredyCat. 2020-12-12 12:54:46 +01:00
Paul Chote
57a94ad667 Add AvoidTerrainTypes to Wanders. 2020-12-12 12:54:46 +01:00
Paul Chote
53933a4d8f Fix restart black screen race condition. 2020-12-11 22:57:57 +01:00
Paul Chote
6606d7dd93 Add DisplayFaction details to the replay metadata. 2020-12-11 18:05:44 +01:00
Paul Chote
7a256dcafa Fix rally point target line exit display. 2020-12-11 17:25:30 +01:00
abcdefg30
7899c52b6d Add an update rule 2020-12-11 17:13:02 +01:00
abcdefg30
919c670502 Update the rules of the default mods 2020-12-11 17:13:02 +01:00
abcdefg30
aac3174efc Rename Stances to Relationships in the yaml api 2020-12-11 17:13:02 +01:00
Paul Chote
a8d3d5c79a Fix Neutral crushing checks. 2020-12-08 20:17:11 +01:00
Paul Chote
7c852d90fb Ignore aircraft when searching for enemy targets. 2020-12-07 23:39:22 +01:00
Paul Chote
269ce9c406 Exclude carryalls from AI squads. 2020-12-07 23:39:22 +01:00
Paul Chote
53d98ec255 Abort squad states that are not able to move. 2020-12-07 23:39:22 +01:00
Paul Chote
7a7cd21578 Fix TD SAM Site facings being reset when damaged while closed. 2020-12-07 01:44:04 +01:00
117 changed files with 3996 additions and 496 deletions

48
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Continuous Integration
on:
push:
pull_request:
branches: [ bleed ]
jobs:
linux-mono:
name: Linux (mono)
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Check Code
run: |
mono --version
make check
mono ~/.nuget/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe --noresult bin/OpenRA.Test.dll
- name: Check Mods
run: |
sudo apt-get install lua5.1
make check-scripts
make test
windows:
name: Windows (Framework 4.7)
runs-on: windows-2019
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Check Code
shell: powershell
run: |
.\make.ps1 check
Invoke-Expression "$home\.nuget\packages\nunit.consolerunner\3.11.1\tools\nunit3-console.exe --noresult bin/OpenRA.Test.dll"
- name: Check Mods
run: |
chocolatey install lua --version 5.1.5.52
$ENV:Path = $ENV:Path + ";C:\Program Files (x86)\Lua\5.1\"
.\make.ps1 check-scripts
.\make.ps1 test

107
.github/workflows/documentation.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: Deploy Documentation
on:
workflow_dispatch:
inputs:
tag:
description: 'Git Tag'
required: true
default: 'release-xxxxxxxx'
jobs:
wiki:
name: Update Wiki
if: github.repository == 'openra/openra'
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.tag }}
- name: Prepare Environment
run: |
make all
- name: Clone Wiki
uses: actions/checkout@v2
with:
repository: openra/openra.wiki
token: ${{ secrets.DOCS_TOKEN }}
path: wiki
- name: Update Wiki (Playtest)
if: startsWith(github.event.inputs.tag, 'playtest-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings (playtest).md"
- name: Update Wiki (Release)
if: startsWith(github.event.inputs.tag, 'release-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings.md"
- name: Push Wiki
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
cd wiki
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add --all
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
git push origin master
docs:
name: Update docs.openra.net
if: github.repository == 'openra/openra'
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.tag }}
- name: Prepare Environment
run: |
make all
- name: Clone docs.openra.net
uses: actions/checkout@v2
with:
repository: openra/docs
token: ${{ secrets.DOCS_TOKEN }}
path: docs
- name: Update docs.openra.net (Playtest)
if: startsWith(github.event.inputs.tag, 'playtest-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --docs "${GIT_TAG}" > "docs/api/playtest/traits.md"
./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/playtest/weapons.md"
./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/playtest/lua.md"
- name: Update docs.openra.net (Release)
if: startsWith(github.event.inputs.tag, 'release-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --docs "${GIT_TAG}" > "docs/api/release/traits.md"
./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/release/weapons.md"
./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/release/lua.md"
- name: Push docs.openra.net
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
cd docs
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add --all
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
git push origin master

88
.github/workflows/itch.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: Deploy itch.io Packages
on:
workflow_dispatch:
inputs:
tag:
description: 'Git Tag'
required: true
default: 'release-xxxxxxxx'
jobs:
itch:
name: Deploy to itch.io
runs-on: ubuntu-20.04
if: github.repository == 'openra/openra'
steps:
- name: Download Packages
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}-x64.exe"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}-x64-winportable.zip" -O "OpenRA-${GIT_TAG}-x64-win-itch.zip"
wget -q "https://github.com${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}.dmg"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Dune-2000-x86_64.AppImage"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Red-Alert-x86_64.AppImage"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Tiberian-Dawn-x86_64.AppImage"
wget -q "https://raw.githubusercontent.com/${{ github.repository }}/${GIT_TAG}/packaging/.itch.toml"
zip -u "OpenRA-${GIT_TAG}-x64-win-itch.zip" .itch.toml
- name: Publish Windows Installer
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: win
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-${{ github.event.inputs.tag }}}-x64.exe"
- name: Publish Windows Itch Bundle
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: itch
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip
- name: Publish macOS Package
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: macos
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-${{ github.event.inputs.tag }}}.dmg"
- name: Publish RA AppImage
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: linux-ra
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-Red-Alert-x86_64.AppImage
- name: Publish TD AppImage
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: linux-cnc
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-Tiberian-Dawn-x86_64.AppImage
- name: Publish D2k AppImage
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: linux-d2k
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-Dune-2000-x86_64.AppImage

113
.github/workflows/packaging.yml vendored Normal file
View File

@@ -0,0 +1,113 @@
name: Release Packaging
on:
push:
tags:
- 'release-*'
- 'playtest-*'
- 'devtest-*'
jobs:
source:
name: Source Tarball
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
- name: Package Source
run: |
mkdir -p build/source
./packaging/source/buildpackage.sh "${GIT_TAG}" "${PWD}/build/source"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/source/*
linux:
name: Linux AppImages
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
- name: Package AppImages
run: |
mkdir -p build/linux
./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/linux/*
macos:
name: macOS Disk Images
runs-on: macos-10.15
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
- name: Package Disk Images
env:
MACOS_DEVELOPER_IDENTITY: ${{ secrets.MACOS_DEVELOPER_IDENTITY }}
MACOS_DEVELOPER_CERTIFICATE_BASE64: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_BASE64 }}
MACOS_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_PASSWORD }}
MACOS_DEVELOPER_USERNAME: ${{ secrets.MACOS_DEVELOPER_USERNAME }}
MACOS_DEVELOPER_PASSWORD: ${{ secrets.MACOS_DEVELOPER_PASSWORD }}
run: |
mkdir -p build/macos
./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/macos/*
windows:
name: Windows Installers
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Prepare Environment
run: |
echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
sudo apt install nsis
- name: Package Installers
run: |
mkdir -p build/windows
./packaging/windows/buildpackage.sh "${GIT_TAG}" "${PWD}/build/windows"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/windows/*

View File

@@ -1,92 +0,0 @@
# Travis-CI Build for OpenRA
# see travis-ci.org for details
language: csharp
mono: 6.4.0
os: linux
dist: xenial
jobs:
include:
- os: linux
dist: xenial
- os: osx
if: tag IS present
osx_image: xcode10
addons:
apt:
packages:
- lua5.1
- dpkg
- zsync
- imagemagick
# Environment variables
env:
secure: "C0+Hlfa0YGErxUuWV00Tj6p45otC/D3YwYFuLpi2mj1rDFn/4dgh5WRngjvdDBVbXJ3duaZ78jPHWm1jr7vn2jqj9yETsCIK9psWd38ep/FEBM0SDr6MUD89OuXk/YyvxJAE+UXF6bXg7giey09g/CwBigjMW7ynET3wNAWPHPs="
# Fetch dependencies
# Run the build script
# Check source code with StyleCop
# call OpenRA to check for YAML errors
# Run the NUnit tests
script:
- make all
- |
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
make check || travis_terminate 1;
make check-scripts || travis_terminate 1;
make test || travis_terminate 1;
mono ~/.nuget/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe --noresult bin/OpenRA.Test.dll || travis_terminate 1;
fi
# Only watch the development branch and tagged release.
branches:
only:
- /^release-.*$/
- /^playtest-.*$/
- /^devtest-.*$/
- /^prep-.*$/
- bleed
# Notify developers when build passed/failed.
notifications:
irc:
if: repo = OpenRA/OpenRA
template:
- "%{repository}#%{build_number} %{commit} %{author}: %{message} %{build_url}"
channels:
- "irc.freenode.net#openra"
use_notice: true
skip_join: true
before_deploy:
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
wget https://mirrors.edge.kernel.org/ubuntu/pool/universe/n/nsis/nsis-common_3.04-1_all.deb;
wget https://mirrors.edge.kernel.org/ubuntu/pool/universe/n/nsis/nsis_3.04-1_amd64.deb;
sudo dpkg -i nsis-common_3.04-1_all.deb;
sudo dpkg -i nsis_3.04-1_amd64.deb;
echo ${TRAVIS_REPO_SLUG};
if [[ "${TRAVIS_REPO_SLUG}" == "OpenRA/OpenRA" ]]; then
cd packaging && ./update-wiki.sh ${TRAVIS_TAG} && ./update-docs.sh ${TRAVIS_TAG} && cd ..;
fi;
fi
- export PATH=${PATH}:${HOME}/usr/bin
- DOTVERSION=`echo ${TRAVIS_TAG} | sed "s/-/\\./g"`
- cd packaging
- mkdir build
- ./package-all.sh ${TRAVIS_TAG} ${PWD}/build/
- if [[ "${TRAVIS_REPO_SLUG}" == "OpenRA/OpenRA" ]]; then
./upload-itch.sh ${TRAVIS_TAG} ${PWD}/build/;
fi
deploy:
provider: releases
token: ${GH_DEPLOY_API_KEY}
file_glob: true
file: build/*
skip_cleanup: true
on:
all_branches: true
tags: true

View File

@@ -934,9 +934,11 @@ namespace OpenRA
AdvertiseOnline = false
};
// Always connect to local games using the same loopback connection
// Exposing multiple endpoints introduces a race condition on the client's PlayerIndex (sometimes 0, sometimes 1)
// This would break the Restart button, which relies on the PlayerIndex always being the same for local servers
var endpoints = new List<IPEndPoint>
{
new IPEndPoint(IPAddress.IPv6Loopback, 0),
new IPEndPoint(IPAddress.Loopback, 0)
};
server = new Server.Server(endpoints, settings, ModData, ServerType.Local);

View File

@@ -119,6 +119,8 @@ namespace OpenRA
IsBot = runtimePlayer.IsBot,
FactionName = runtimePlayer.Faction.Name,
FactionId = runtimePlayer.Faction.InternalName,
DisplayFactionName = runtimePlayer.DisplayFaction.Name,
DisplayFactionId = runtimePlayer.DisplayFaction.InternalName,
Color = runtimePlayer.Color,
Team = client.Team,
SpawnPoint = runtimePlayer.SpawnPoint,
@@ -157,6 +159,10 @@ namespace OpenRA
public string FactionId;
public Color Color;
/// <summary>The faction (including Random, etc.) that was selected in the lobby.</summary>
public string DisplayFactionName;
public string DisplayFactionId;
/// <summary>The team ID on start-up, or 0 if the player is not part of a team.</summary>
public int Team;
public int SpawnPoint;

View File

@@ -64,7 +64,7 @@ namespace OpenRA
public readonly Shroud Shroud;
public readonly FrozenActorLayer FrozenActorLayer;
/// <summary>The faction (including Random, etc) that was selected in the lobby.</summary>
/// <summary>The faction (including Random, etc.) that was selected in the lobby.</summary>
public readonly FactionInfo DisplayFaction;
/// <summary>The spawn point index that was assigned for client-based players.</summary>
@@ -80,7 +80,8 @@ namespace OpenRA
{
get
{
return spectating || WinState != WinState.Undefined;
// Players in mission maps must not leave the player view
return !inMissionMap && (spectating || WinState != WinState.Undefined);
}
}

View File

@@ -18,6 +18,7 @@ namespace OpenRA.Primitives
static class LongBitSetAllocator<T> where T : class
{
static readonly Cache<string, long> Bits = new Cache<string, long>(Allocate);
static long allBits = 1;
static long nextBits = 1;
static long Allocate(string value)
@@ -25,6 +26,7 @@ namespace OpenRA.Primitives
lock (Bits)
{
var bits = nextBits;
allBits |= bits;
nextBits <<= 1;
if (nextBits == 0)
@@ -85,6 +87,8 @@ namespace OpenRA.Primitives
nextBits = 1;
}
}
public static long Mask { get { return allBits; } }
}
// Opitmized BitSet to be used only when guaranteed to be no more than 64 values.
@@ -114,6 +118,7 @@ namespace OpenRA.Primitives
public static bool operator ==(LongBitSet<T> me, LongBitSet<T> other) { return me.bits == other.bits; }
public static bool operator !=(LongBitSet<T> me, LongBitSet<T> other) { return !(me == other); }
public static LongBitSet<T> operator ~(LongBitSet<T> me) { return new LongBitSet<T>(me.bits ^ LongBitSetAllocator<T>.Mask); }
public bool Equals(LongBitSet<T> other) { return other == this; }
public override bool Equals(object obj) { return obj is LongBitSet<T> && Equals((LongBitSet<T>)obj); }

View File

@@ -79,8 +79,8 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("The condition to grant to self while disguised.")]
public readonly string DisguisedCondition = null;
[Desc("What diplomatic stances can this actor disguise as.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships the owner of the disguise target needs.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Target types of actors that this actor disguise as.")]
public readonly BitSet<TargetableType> TargetTypes = new BitSet<TargetableType>("Disguise");
@@ -299,7 +299,7 @@ namespace OpenRA.Mods.Cnc.Traits
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{
var stance = self.Owner.RelationshipWith(target.Owner);
if (!info.ValidStances.HasStance(stance))
if (!info.ValidRelationships.HasStance(stance))
return false;
return info.TargetTypes.Overlaps(target.GetAllTargetTypes());
@@ -308,7 +308,7 @@ namespace OpenRA.Mods.Cnc.Traits
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
{
var stance = self.Owner.RelationshipWith(target.Owner);
if (!info.ValidStances.HasStance(stance))
if (!info.ValidRelationships.HasStance(stance))
return false;
return info.TargetTypes.Overlaps(target.Info.GetAllTargetTypes());

View File

@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Cnc.Traits
protected override bool ShouldRender(Actor self)
{
return infiltrators.Any(i => Info.ValidStances.HasStance(i.RelationshipWith(self.World.RenderPlayer)));
return infiltrators.Any(i => Info.ValidRelationships.HasStance(i.RelationshipWith(self.World.RenderPlayer)));
}
}
}

View File

@@ -30,8 +30,8 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("Color to use for the target line.")]
public readonly Color TargetLineColor = Color.Crimson;
[Desc("What diplomatic stances can be infiltrated by this actor.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships the owner of the infiltration target needs.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Behaviour when entering the target.",
"Possible values are Exit, Suicide, Dispose.")]
@@ -101,10 +101,10 @@ namespace OpenRA.Mods.Cnc.Traits
{
case TargetType.Actor:
return Info.Types.Overlaps(target.Actor.GetEnabledTargetTypes()) &&
Info.ValidStances.HasStance(self.Owner.RelationshipWith(target.Actor.Owner));
Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(target.Actor.Owner));
case TargetType.FrozenActor:
return target.FrozenActor.IsValid && Info.Types.Overlaps(target.FrozenActor.TargetTypes) &&
Info.ValidStances.HasStance(self.Owner.RelationshipWith(target.FrozenActor.Owner));
Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(target.FrozenActor.Owner));
default:
return false;
}
@@ -136,7 +136,7 @@ namespace OpenRA.Mods.Cnc.Traits
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{
var stance = self.Owner.RelationshipWith(target.Owner);
if (!info.ValidStances.HasStance(stance))
if (!info.ValidRelationships.HasStance(stance))
return false;
return info.Types.Overlaps(target.GetAllTargetTypes());
@@ -145,7 +145,7 @@ namespace OpenRA.Mods.Cnc.Traits
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
{
var stance = self.Owner.RelationshipWith(target.Owner);
if (!info.ValidStances.HasStance(stance))
if (!info.ValidRelationships.HasStance(stance))
return false;
return info.Types.Overlaps(target.Info.GetAllTargetTypes());

View File

@@ -65,7 +65,7 @@ namespace OpenRA.Mods.Cnc.Traits
return self.World.NoPlayersMask;
// Friendly units should move around!
return info.BlockFriendly ? self.Owner.EnemyPlayersMask : self.World.AllPlayersMask;
return info.BlockFriendly ? ~self.Owner.AlliedPlayersMask : self.World.AllPlayersMask;
}
}

View File

@@ -23,6 +23,9 @@ namespace OpenRA.Mods.Cnc.Traits.Render
[Desc("This actor has turret art with facings baked into the sprite.")]
public class WithEmbeddedTurretSpriteBodyInfo : WithSpriteBodyInfo, Requires<TurretedInfo>, Requires<BodyOrientationInfo>
{
[Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from the sequence.")]
public readonly int QuantizedFacings = -1;
public override object Create(ActorInitializer init) { return new WithEmbeddedTurretSpriteBody(init, this); }
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
@@ -43,6 +46,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public class WithEmbeddedTurretSpriteBody : WithSpriteBody
{
readonly WithEmbeddedTurretSpriteBodyInfo info;
readonly Turreted turreted;
static Func<WAngle> MakeTurretFacingFunc(Actor self)
@@ -52,22 +56,23 @@ namespace OpenRA.Mods.Cnc.Traits.Render
return () => turreted.WorldOrientation.Yaw;
}
public WithEmbeddedTurretSpriteBody(ActorInitializer init, WithSpriteBodyInfo info)
public WithEmbeddedTurretSpriteBody(ActorInitializer init, WithEmbeddedTurretSpriteBodyInfo info)
: base(init, info, MakeTurretFacingFunc(init.Self))
{
this.info = info;
turreted = init.Self.TraitsImplementing<Turreted>().FirstOrDefault();
}
protected override void TraitEnabled(Actor self)
{
base.TraitEnabled(self);
turreted.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings;
turreted.QuantizedFacings = info.QuantizedFacings >= 0 ? info.QuantizedFacings : DefaultAnimation.CurrentSequence.Facings;
}
protected override void DamageStateChanged(Actor self)
{
base.DamageStateChanged(self);
turreted.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings;
turreted.QuantizedFacings = info.QuantizedFacings >= 0 ? info.QuantizedFacings : DefaultAnimation.CurrentSequence.Facings;
}
}
}

View File

@@ -124,7 +124,7 @@ namespace OpenRA.Mods.Common.Activities
foreach (var t in enterActor.TraitsImplementing<INotifyCapture>())
t.OnCapture(enterActor, self, oldOwner, self.Owner, captures.Info.CaptureTypes);
if (self.Owner.RelationshipWith(oldOwner).HasStance(captures.Info.PlayerExperienceStances))
if (self.Owner.RelationshipWith(oldOwner).HasStance(captures.Info.PlayerExperienceRelationships))
self.Owner.PlayerActor.TraitOrDefault<PlayerExperience>()?.GiveExperience(captures.Info.PlayerExperience);
if (captures.Info.ConsumedByCapture)

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Activities
// Make sure we can still repair the target before entering
// (but not before, because this may stop the actor in the middle of nowhere)
var stance = self.Owner.RelationshipWith(enterActor.Owner);
if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || enterEngineerRepariable == null || enterEngineerRepariable.IsTraitDisabled || !info.ValidStances.HasStance(stance))
if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || enterEngineerRepariable == null || enterEngineerRepariable.IsTraitDisabled || !info.ValidRelationships.HasStance(stance))
{
Cancel(self, true);
return false;
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Activities
return;
var stance = self.Owner.RelationshipWith(enterActor.Owner);
if (!info.ValidStances.HasStance(stance))
if (!info.ValidRelationships.HasStance(stance))
return;
if (enterHealth.DamageState == DamageState.Undamaged)

View File

@@ -23,16 +23,14 @@ namespace OpenRA.Mods.Common.Effects
readonly RallyPoint rp;
readonly Animation flag;
readonly Animation circles;
readonly ExitInfo[] exits;
List<WPos> targetLineNodes = new List<WPos> { };
List<CPos> cachedLocations;
public RallyPointIndicator(Actor building, RallyPoint rp, ExitInfo[] exits)
public RallyPointIndicator(Actor building, RallyPoint rp)
{
this.building = building;
this.rp = rp;
this.exits = exits;
if (rp.Info.Image != null)
{
@@ -73,21 +71,8 @@ namespace OpenRA.Mods.Common.Effects
if (targetLineNodes.Count == 0)
return;
var exitPos = building.CenterPosition;
// Find closest exit
var dist = int.MaxValue;
foreach (var exit in exits)
{
var ep = building.CenterPosition + exit.SpawnOffset;
var len = (targetLineNodes[0] - ep).Length;
if (len < dist)
{
dist = len;
exitPos = ep;
}
}
var exit = building.NearestExitOrDefault(targetLineNodes[0]);
var exitPos = exit != null ? building.World.Map.CenterOfCell(building.Location + exit.Info.ExitCell) : building.CenterPosition;
targetLineNodes.Insert(0, exitPos);
}

View File

@@ -96,8 +96,8 @@ namespace OpenRA.Mods.Common.Projectiles
[Desc("Terrain where the projectile explodes instead of bouncing.")]
public readonly HashSet<string> InvalidBounceTerrain = new HashSet<string>();
[Desc("If projectile touches an actor with one of these stances during or after the first bounce, trigger explosion.")]
public readonly PlayerRelationship ValidBounceBlockerStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
[Desc("Trigger the explosion if the projectile touches an actor thats owner has these player relationships.")]
public readonly PlayerRelationship ValidBounceBlockerRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
[Desc("Altitude above terrain below which to explode. Zero effectively deactivates airburst.")]
public readonly WDist AirburstAltitude = WDist.Zero;
@@ -319,7 +319,7 @@ namespace OpenRA.Mods.Common.Projectiles
if (checkTargetType && !Target.FromActor(victim).IsValidFor(firedBy))
continue;
if (!info.ValidBounceBlockerStances.HasStance(firedBy.Owner.RelationshipWith(victim.Owner)))
if (!info.ValidBounceBlockerRelationships.HasStance(firedBy.Owner.RelationshipWith(victim.Owner)))
continue;
// If the impact position is within any actor's HitShape, we have a direct hit

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Accepted `DeliversCash` types. Leave empty to accept all types.")]
public readonly HashSet<string> ValidTypes = new HashSet<string>();
[Desc("Stance the delivering actor needs to enter.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("Player relationships the owner of the delivering actor needs.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Play a randomly selected sound from this list when accepting cash.")]
public readonly string[] Sounds = { };
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Traits
public class AcceptsDeliveredCash : INotifyCashTransfer
{
AcceptsDeliveredCashInfo info;
readonly AcceptsDeliveredCashInfo info;
public AcceptsDeliveredCash(Actor self, AcceptsDeliveredCashInfo info)
{

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Accepted `DeliversExperience` types. Leave empty to accept all types.")]
public readonly HashSet<string> ValidTypes = new HashSet<string>();
[Desc("Stance the delivering actor needs to enter.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("Player relationships the owner of the delivering actor needs.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
public override object Create(ActorInitializer init) { return new AcceptsDeliveredExperience(init.Self, this); }
}

View File

@@ -68,8 +68,8 @@ namespace OpenRA.Mods.Common.Traits
public WeaponInfo WeaponInfo { get; private set; }
public WDist ModifiedRange { get; private set; }
public readonly PlayerRelationship TargetStances = PlayerRelationship.Enemy;
public readonly PlayerRelationship ForceTargetStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Enemy;
public readonly PlayerRelationship ForceTargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
// TODO: instead of having multiple Armaments and unique AttackBase,
// an actor should be able to have multiple AttackBases with

View File

@@ -377,7 +377,7 @@ namespace OpenRA.Mods.Common.Traits
return Armaments.Where(a =>
!a.IsTraitDisabled
&& (owner == null || (forceAttack ? a.Info.ForceTargetStances : a.Info.TargetStances).HasStance(self.Owner.RelationshipWith(owner)))
&& (owner == null || (forceAttack ? a.Info.ForceTargetRelationships : a.Info.TargetRelationships).HasStance(self.Owner.RelationshipWith(owner)))
&& a.Weapon.IsValidAgainst(t, self.World, self));
}
@@ -408,7 +408,7 @@ namespace OpenRA.Mods.Common.Traits
var stances = PlayerRelationship.None;
foreach (var armament in Armaments)
if (!armament.IsTraitDisabled)
stances |= armament.Info.TargetStances;
stances |= armament.Info.TargetRelationships;
return stances;
}

View File

@@ -326,7 +326,7 @@ namespace OpenRA.Mods.Common.Traits
return activeTargetPriorities.Any(ati =>
{
// Incompatible stances
if (!ati.ValidStances.HasStance(self.Owner.RelationshipWith(owner)))
if (!ati.ValidRelationships.HasStance(self.Owner.RelationshipWith(owner)))
return false;
// Incompatible target types
@@ -391,7 +391,7 @@ namespace OpenRA.Mods.Common.Traits
return false;
// Incompatible stances
if (!ati.ValidStances.HasStance(self.Owner.RelationshipWith(owner)))
if (!ati.ValidRelationships.HasStance(self.Owner.RelationshipWith(owner)))
return false;
// Incompatible target types

View File

@@ -23,8 +23,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Target types that can't be AutoTargeted.", "Overrules ValidTargets.")]
public readonly BitSet<TargetableType> InvalidTargets;
[Desc("Stances between actor's and target's owner which can be AutoTargeted.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Relationships between actor's and target's owner needed for AutoTargeting.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("ValidTargets with larger priorities will be AutoTargeted before lower priorities.")]
public readonly int Priority = 1;

View File

@@ -37,8 +37,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Should visibility (Shroud, Fog, Cloak, etc) be considered when searching for capturable targets?")]
public readonly bool CheckCaptureTargetsForVisibility = true;
[Desc("Player stances that capturers should attempt to target.")]
public readonly PlayerRelationship CapturableStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
[Desc("Player relationships that capturers should attempt to target.")]
public readonly PlayerRelationship CapturableRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
public override object Create(ActorInitializer init) { return new CaptureManagerBotModule(init.Self, this); }
}
@@ -133,7 +133,7 @@ namespace OpenRA.Mods.Common.Traits
return;
var randPlayer = world.Players.Where(p => !p.Spectating
&& Info.CapturableStances.HasStance(player.RelationshipWith(p))).Random(world.LocalRandom);
&& Info.CapturableRelationships.HasStance(player.RelationshipWith(p))).Random(world.LocalRandom);
var targetOptions = Info.CheckCaptureTargetsForVisibility
? GetVisibleActorsBelongingToPlayer(randPlayer)

View File

@@ -132,7 +132,7 @@ namespace OpenRA.Mods.Common.Traits
// Use for proactive targeting.
public bool IsPreferredEnemyUnit(Actor a)
{
if (a == null || a.IsDead || Player.RelationshipWith(a.Owner) != PlayerRelationship.Enemy || a.Info.HasTraitInfo<HuskInfo>())
if (a == null || a.IsDead || Player.RelationshipWith(a.Owner) != PlayerRelationship.Enemy || a.Info.HasTraitInfo<HuskInfo>() || a.Info.HasTraitInfo<AircraftInfo>())
return false;
var targetTypes = a.GetEnabledTargetTypes();

View File

@@ -68,6 +68,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
class GroundUnitsAttackMoveState : GroundStateBase, IState
{
int lastUpdatedTick;
CPos? lastLeaderLocation;
Actor lastTarget;
public void Activate(Squad owner) { }
public void Tick(Squad owner)
@@ -91,6 +95,27 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
if (leader == null)
return;
if (leader.Location != lastLeaderLocation)
{
lastLeaderLocation = leader.Location;
lastUpdatedTick = owner.World.WorldTick;
}
if (owner.TargetActor != lastTarget)
{
lastTarget = owner.TargetActor;
lastUpdatedTick = owner.World.WorldTick;
}
// HACK: Drop back to the idle state if we haven't moved in 2.5 seconds
// This works around the squad being stuck trying to attack-move to a location
// that they cannot path to, generating expensive pathfinding calls each tick.
if (owner.World.WorldTick > lastUpdatedTick + 63)
{
owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true);
return;
}
var ownUnits = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.Units.Count) / 3)
.Where(a => a.Owner == owner.Units.First().Owner && owner.Units.Contains(a)).ToHashSet();
@@ -126,6 +151,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
class GroundUnitsAttackState : GroundStateBase, IState
{
int lastUpdatedTick;
CPos? lastLeaderLocation;
Actor lastTarget;
public void Activate(Squad owner) { }
public void Tick(Squad owner)
@@ -145,6 +174,28 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
}
}
var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition);
if (leader.Location != lastLeaderLocation)
{
lastLeaderLocation = leader.Location;
lastUpdatedTick = owner.World.WorldTick;
}
if (owner.TargetActor != lastTarget)
{
lastTarget = owner.TargetActor;
lastUpdatedTick = owner.World.WorldTick;
}
// HACK: Drop back to the idle state if we haven't moved in 2.5 seconds
// This works around the squad being stuck trying to attack-move to a location
// that they cannot path to, generating expensive pathfinding calls each tick.
if (owner.World.WorldTick > lastUpdatedTick + 63)
{
owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true);
return;
}
foreach (var a in owner.Units)
if (!BusyAttack(a))
owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false));

View File

@@ -93,6 +93,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
class NavyUnitsAttackMoveState : NavyStateBase, IState
{
int lastUpdatedTick;
CPos? lastLeaderLocation;
Actor lastTarget;
public void Activate(Squad owner) { }
public void Tick(Squad owner)
@@ -116,6 +120,27 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
if (leader == null)
return;
if (leader.Location != lastLeaderLocation)
{
lastLeaderLocation = leader.Location;
lastUpdatedTick = owner.World.WorldTick;
}
if (owner.TargetActor != lastTarget)
{
lastTarget = owner.TargetActor;
lastUpdatedTick = owner.World.WorldTick;
}
// HACK: Drop back to the idle state if we haven't moved in 2.5 seconds
// This works around the squad being stuck trying to attack-move to a location
// that they cannot path to, generating expensive pathfinding calls each tick.
if (owner.World.WorldTick > lastUpdatedTick + 63)
{
owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true);
return;
}
var ownUnits = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.Units.Count) / 3)
.Where(a => a.Owner == owner.Units.First().Owner && owner.Units.Contains(a)).ToHashSet();
@@ -151,6 +176,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
class NavyUnitsAttackState : NavyStateBase, IState
{
int lastUpdatedTick;
CPos? lastLeaderLocation;
Actor lastTarget;
public void Activate(Squad owner) { }
public void Tick(Squad owner)
@@ -170,6 +199,28 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
}
}
var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition);
if (leader.Location != lastLeaderLocation)
{
lastLeaderLocation = leader.Location;
lastUpdatedTick = owner.World.WorldTick;
}
if (owner.TargetActor != lastTarget)
{
lastTarget = owner.TargetActor;
lastUpdatedTick = owner.World.WorldTick;
}
// HACK: Drop back to the idle state if we haven't moved in 2.5 seconds
// This works around the squad being stuck trying to attack-move to a location
// that they cannot path to, generating expensive pathfinding calls each tick.
if (owner.World.WorldTick > lastUpdatedTick + 63)
{
owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true);
return;
}
foreach (var a in owner.Units)
if (!BusyAttack(a))
owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false));

View File

@@ -75,13 +75,7 @@ namespace OpenRA.Mods.Common.Traits
void INotifyCreated.Created(Actor self)
{
// Display only the first level of priority
var priorityExits = self.Info.TraitInfos<ExitInfo>()
.GroupBy(e => e.Priority)
.FirstOrDefault();
var exits = priorityExits != null ? priorityExits.ToArray() : new ExitInfo[0];
self.World.Add(new RallyPointIndicator(self, this, exits));
self.World.Add(new RallyPointIndicator(self, this));
}
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)

View File

@@ -22,8 +22,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("CaptureTypes (from the Captures trait) that are able to capture this.")]
public readonly BitSet<CaptureType> Types = default(BitSet<CaptureType>);
[Desc("What diplomatic stances can be captured by this actor.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("What player relationships the target's owner needs to be captured by this actor.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Cancel the actor's current activity when getting captured.")]
public readonly bool CancelActivity = false;

View File

@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits
// Actors with FrozenUnderFog should therefore not disable the Capturable trait.
var stance = captor.Owner.RelationshipWith(frozenActor.Owner);
return frozenActor.Info.TraitInfos<CapturableInfo>()
.Any(c => c.ValidStances.HasStance(stance) && captures.Info.CaptureTypes.Overlaps(c.Types));
.Any(c => c.ValidRelationships.HasStance(stance) && captures.Info.CaptureTypes.Overlaps(c.Types));
}
}
@@ -108,13 +108,13 @@ namespace OpenRA.Mods.Common.Traits
allyCapturableTypes = neutralCapturableTypes = enemyCapturableTypes = default(BitSet<CaptureType>);
foreach (var c in enabledCapturable)
{
if (c.Info.ValidStances.HasStance(PlayerRelationship.Ally))
if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Ally))
allyCapturableTypes = allyCapturableTypes.Union(c.Info.Types);
if (c.Info.ValidStances.HasStance(PlayerRelationship.Neutral))
if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Neutral))
neutralCapturableTypes = neutralCapturableTypes.Union(c.Info.Types);
if (c.Info.ValidStances.HasStance(PlayerRelationship.Enemy))
if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Enemy))
enemyCapturableTypes = enemyCapturableTypes.Union(c.Info.Types);
}
}

View File

@@ -43,8 +43,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Experience granted to the capturing player.")]
public readonly int PlayerExperience = 0;
[Desc("Stance that the structure's previous owner needs to have for the capturing player to receive Experience.")]
public readonly PlayerRelationship PlayerExperienceStances = PlayerRelationship.Enemy;
[Desc("Relationships that the structure's previous owner needs to have for the capturing player to receive Experience.")]
public readonly PlayerRelationship PlayerExperienceRelationships = PlayerRelationship.Enemy;
[Desc("Cursor to display when the health of the target actor is above the sabotage threshold.")]
public readonly string SabotageCursor = "capture";

View File

@@ -30,8 +30,8 @@ namespace OpenRA.Mods.Common.Traits
"Ignored if 0 (actors are selected regardless of vertical distance).")]
public readonly WDist MaximumVerticalOffset = WDist.Zero;
[Desc("What diplomatic stances are affected.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("What player relationships are affected.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Condition is applied permanently to this actor.")]
public readonly bool AffectsParent = false;
@@ -111,7 +111,7 @@ namespace OpenRA.Mods.Common.Traits
return;
var stance = self.Owner.RelationshipWith(a.Owner);
if (!Info.ValidStances.HasStance(stance))
if (!Info.ValidRelationships.HasStance(stance))
return;
var external = a.TraitsImplementing<ExternalCondition>()
@@ -135,7 +135,7 @@ namespace OpenRA.Mods.Common.Traits
if ((produced.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= Info.Range.LengthSquared)
{
var stance = self.Owner.RelationshipWith(produced.Owner);
if (!Info.ValidStances.HasStance(stance))
if (!Info.ValidRelationships.HasStance(stance))
return;
var external = produced.TraitsImplementing<ExternalCondition>()

View File

@@ -17,8 +17,8 @@ namespace OpenRA.Mods.Common.Traits
{
public class CreatesShroudInfo : AffectsShroudInfo
{
[Desc("Stance the watching player needs to see the generated shroud.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Relationship the watching player needs to see the generated shroud.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
public override object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); }
}
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits
protected override void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv)
{
if (!info.ValidStances.HasStance(self.Owner.RelationshipWith(p)))
if (!info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)))
return;
p.Shroud.AddSource(this, Shroud.SourceType.Shroud, uv);

View File

@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled || !self.IsAtGroundLevel() || !Info.CrushClasses.Overlaps(crushClasses))
return self.World.NoPlayersMask;
return Info.CrushedByFriendlies ? self.World.AllPlayersMask : self.Owner.EnemyPlayersMask;
return Info.CrushedByFriendlies ? self.World.AllPlayersMask : ~self.Owner.AlliedPlayersMask;
}
bool CrushableInner(BitSet<CrushClass> crushClasses, Player crushOwner)

View File

@@ -99,7 +99,7 @@ namespace OpenRA.Mods.Common.Traits
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
{
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredCashInfo>();
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
return false;
if (targetInfo.ValidTypes.Count == 0)
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.Traits
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
{
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredCashInfo>();
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
return false;
if (targetInfo.ValidTypes.Count == 0)

View File

@@ -109,7 +109,7 @@ namespace OpenRA.Mods.Common.Traits
return false;
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredExperienceInfo>();
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
return false;
if (targetInfo.ValidTypes.Count == 0)
@@ -129,7 +129,7 @@ namespace OpenRA.Mods.Common.Traits
return false;
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredExperienceInfo>();
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
return false;
if (targetInfo.ValidTypes.Count == 0)

View File

@@ -47,8 +47,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Color to use for the target line.")]
public readonly Color TargetLineColor = Color.Crimson;
public readonly PlayerRelationship TargetStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
public readonly PlayerRelationship ForceTargetStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
public readonly PlayerRelationship ForceTargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
[Desc("Cursor to display when hovering over a demolishable target.")]
public readonly string Cursor = "c4";
@@ -118,10 +118,10 @@ namespace OpenRA.Mods.Common.Traits
return false;
var stance = target.Owner.RelationshipWith(self.Owner);
if (!info.TargetStances.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
if (!info.TargetRelationships.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
return false;
if (!info.ForceTargetStances.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
if (!info.ForceTargetRelationships.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
return false;
return target.TraitsImplementing<IDemolishable>().Any(i => i.IsValidTarget(target, self));
@@ -130,10 +130,10 @@ namespace OpenRA.Mods.Common.Traits
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
{
var stance = target.Owner.RelationshipWith(self.Owner);
if (!info.TargetStances.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
if (!info.TargetRelationships.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
return false;
if (!info.ForceTargetStances.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
if (!info.ForceTargetRelationships.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
return false;
return target.Info.TraitInfos<IDemolishableInfo>().Any(i => i.IsValidTarget(target.Info, self));

View File

@@ -33,8 +33,8 @@ namespace OpenRA.Mods.Common.Traits
"Possible values are Exit, Suicide, Dispose.")]
public readonly EnterBehaviour EnterBehaviour = EnterBehaviour.Dispose;
[Desc("What diplomatic stances allow target to be repaired by this actor.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("What player relationship the target's owner needs to be repaired by this actor.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Sound to play when repairing is done.")]
public readonly string RepairSound = null;
@@ -117,7 +117,7 @@ namespace OpenRA.Mods.Common.Traits
if (!engineerRepairable.Info.Types.IsEmpty && !engineerRepairable.Info.Types.Overlaps(info.Types))
return false;
if (!info.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
if (!info.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
return false;
if (target.GetDamageState() == DamageState.Undamaged)
@@ -139,7 +139,7 @@ namespace OpenRA.Mods.Common.Traits
if (!engineerRepairable.Types.IsEmpty && !engineerRepairable.Types.Overlaps(info.Types))
return false;
if (!info.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
if (!info.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
return false;
if (target.DamageState == DamageState.Undamaged)

View File

@@ -23,8 +23,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Percentage of the killed actor's Cost or CustomSellValue to be given.")]
public readonly int Percentage = 10;
[Desc("Stance the attacking player needs to receive the bounty.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships the attacking player needs to receive the bounty.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Whether to show a floating text announcing the won bounty.")]
public readonly bool ShowBounty = true;
@@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Traits
if (e.Attacker == null || e.Attacker.Disposed || IsTraitDisabled)
return;
if (!Info.ValidStances.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
if (!Info.ValidRelationships.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
return;
if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes))

View File

@@ -21,8 +21,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("If -1, use the value of the unit cost.")]
public readonly int Experience = -1;
[Desc("Stance the attacking player needs to receive the experience.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships the attacking player needs to receive the experience.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Percentage of the `Experience` value that is being granted to the killing actor.")]
public readonly int ActorExperienceModifier = 10000;
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits
if (exp == 0 || e.Attacker == null || e.Attacker.Disposed)
return;
if (!info.ValidStances.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
if (!info.ValidRelationships.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
return;
exp = Util.ApplyPercentageModifiers(exp, experienceModifiers);

View File

@@ -9,6 +9,8 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
@@ -28,6 +30,9 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Chance (out of 100) the unit has to enter panic mode when attacking.")]
public readonly int AttackPanicChance = 20;
[Desc("The terrain types that this actor should avoid running on to while panicking.")]
public readonly HashSet<string> AvoidTerrainTypes = new HashSet<string>();
[SequenceReference(prefix: true)]
public readonly string PanicSequencePrefix = "panic-";
@@ -39,6 +44,7 @@ namespace OpenRA.Mods.Common.Traits
readonly ScaredyCatInfo info;
readonly Mobile mobile;
readonly Actor self;
readonly Func<CPos, bool> avoidTerrainFilter;
[Sync]
int panicStartedTick;
@@ -52,6 +58,9 @@ namespace OpenRA.Mods.Common.Traits
this.self = self;
this.info = info;
mobile = self.Trait<Mobile>();
if (info.AvoidTerrainTypes.Count > 0)
avoidTerrainFilter = c => info.AvoidTerrainTypes.Contains(self.World.Map.GetTerrainInfo(c).Type);
}
public void Panic()
@@ -79,7 +88,10 @@ namespace OpenRA.Mods.Common.Traits
if (!Panicking)
return;
mobile.Nudge(self);
// Note: This is just a modified copy of Mobile.Nudge
var cell = mobile.GetAdjacentCell(self.Location, avoidTerrainFilter);
if (cell != null)
self.QueueActivity(false, mobile.MoveTo(cell.Value, 0));
}
void INotifyDamage.Damaged(Actor self, AttackInfo e)

View File

@@ -19,8 +19,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Range of the deflection.")]
public readonly WDist Range = WDist.Zero;
[Desc("What diplomatic stances are affected.")]
public readonly PlayerRelationship DeflectionStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("What player relationships are affected.")]
public readonly PlayerRelationship DeflectionRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Chance of deflecting missiles.")]
public readonly int Chance = 100;
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Traits
public class JamsMissiles : ConditionalTrait<JamsMissilesInfo>
{
public WDist Range { get { return IsTraitDisabled ? WDist.Zero : Info.Range; } }
public PlayerRelationship DeflectionStances { get { return Info.DeflectionStances; } }
public PlayerRelationship DeflectionStances { get { return Info.DeflectionRelationships; } }
public int Chance { get { return Info.Chance; } }
public JamsMissiles(JamsMissilesInfo info)

View File

@@ -364,14 +364,14 @@ namespace OpenRA.Mods.Common.Traits
self.QueueActivity(false, MoveTo(cell.Value, 0));
}
public CPos? GetAdjacentCell(CPos nextCell)
public CPos? GetAdjacentCell(CPos nextCell, Func<CPos, bool> preferToAvoid = null)
{
var availCells = new List<CPos>();
var notStupidCells = new List<CPos>();
foreach (CVec direction in CVec.Directions)
{
var p = ToCell + direction;
if (CanEnterCell(p) && CanStayInCell(p))
if (CanEnterCell(p) && CanStayInCell(p) && (preferToAvoid == null || !preferToAvoid(p)))
availCells.Add(p);
else if (p != nextCell && p != ToCell)
notStupidCells.Add(p);

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("This actor will remain visible (but not updated visually) under fog, once discovered.")]
public class FrozenUnderFogInfo : TraitInfo, Requires<BuildingInfo>, IDefaultVisibilityInfo
{
[Desc("Players with these stances can always see the actor.")]
public readonly PlayerRelationship AlwaysVisibleStances = PlayerRelationship.Ally;
[Desc("Players with these relationships can always see the actor.")]
public readonly PlayerRelationship AlwaysVisibleRelationships = PlayerRelationship.Ally;
public override object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
}
@@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.Traits
return true;
var stance = self.Owner.RelationshipWith(byPlayer);
return info.AlwaysVisibleStances.HasStance(stance) || IsVisibleInner(self, byPlayer);
return info.AlwaysVisibleRelationships.HasStance(stance) || IsVisibleInner(self, byPlayer);
}
void ITick.Tick(Actor self)

View File

@@ -19,8 +19,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("The actor stays invisible under the shroud.")]
public class HiddenUnderShroudInfo : TraitInfo, IDefaultVisibilityInfo
{
[Desc("Players with these stances can always see the actor.")]
public readonly PlayerRelationship AlwaysVisibleStances = PlayerRelationship.Ally;
[Desc("Players with these relationships can always see the actor.")]
public readonly PlayerRelationship AlwaysVisibleRelationships = PlayerRelationship.Ally;
[Desc("Possible values are CenterPosition (reveal when the center is visible) and ",
"Footprint (reveal when any footprint cell is visible).")]
@@ -56,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits
return true;
var stance = self.Owner.RelationshipWith(byPlayer);
return Info.AlwaysVisibleStances.HasStance(stance) || IsVisibleInner(self, byPlayer);
return Info.AlwaysVisibleRelationships.HasStance(stance) || IsVisibleInner(self, byPlayer);
}
IEnumerable<IRenderable> IRenderModifier.ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)

View File

@@ -12,6 +12,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
@@ -58,15 +59,19 @@ namespace OpenRA.Mods.Common.Traits
[NotificationReference("Speech")]
public readonly string LeaveNotification = null;
public override object Create(ActorInitializer init) { return new MissionObjectives(init.World, this); }
public override object Create(ActorInitializer init) { return new MissionObjectives(init.Self.Owner, this); }
}
public class MissionObjectives : INotifyWinStateChanged, ISync, IResolveOrder
public class MissionObjectives : INotifyWinStateChanged, ISync, IResolveOrder, IWorldLoaded
{
public readonly MissionObjectivesInfo Info;
readonly List<MissionObjective> objectives = new List<MissionObjective>();
readonly Player player;
public ReadOnlyList<MissionObjective> Objectives;
Player[] enemies;
Player[] allies;
[Sync]
public int ObjectivesHash
{
@@ -83,12 +88,21 @@ namespace OpenRA.Mods.Common.Traits
// The player's WinState is only updated when his allies have all completed their objective as well.
public WinState WinStateCooperative { get; private set; }
public MissionObjectives(World world, MissionObjectivesInfo info)
public MissionObjectives(Player player, MissionObjectivesInfo info)
{
Info = info;
this.player = player;
Objectives = new ReadOnlyList<MissionObjective>(objectives);
}
void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr)
{
// Players and NonCombatants are fixed once the game starts, but the result of IsAlliedWith
// may change once players are marked as spectators, so cache these
allies = player.World.Players.Where(p => !p.NonCombatant && player.IsAlliedWith(p)).ToArray();
enemies = player.World.Players.Where(p => !p.NonCombatant && player.RelationshipWith(p) == PlayerRelationship.Enemy).ToArray();
}
public int Add(Player player, string description, string type, bool required = true, bool inhibitAnnouncement = false)
{
var newID = objectives.Count;
@@ -140,10 +154,9 @@ namespace OpenRA.Mods.Common.Traits
void CheckIfGameIsOver(Player player)
{
var players = player.World.Players.Where(p => !p.NonCombatant);
var gameOver = players.All(p => p.WinState != WinState.Undefined || !p.HasObjectives);
var gameOver = player.World.Players.All(p => p.NonCombatant || p.WinState != WinState.Undefined || !p.HasObjectives);
if (gameOver)
{
Game.RunAfterDelay(Info.GameOverDelay, () =>
{
if (!Game.IsCurrentWorld(player.World))
@@ -153,17 +166,14 @@ namespace OpenRA.Mods.Common.Traits
player.World.SetPauseState(true);
player.World.PauseStateLocked = true;
});
}
}
void INotifyWinStateChanged.OnPlayerWon(Player player)
{
var players = player.World.Players.Where(p => !p.NonCombatant);
var enemies = players.Where(p => !p.IsAlliedWith(player));
if (Info.Cooperative)
{
WinStateCooperative = WinState.Won;
var allies = players.Where(p => p.IsAlliedWith(player));
if (allies.All(p => p.PlayerActor.Trait<MissionObjectives>().WinStateCooperative == WinState.Won))
{
@@ -193,13 +203,9 @@ namespace OpenRA.Mods.Common.Traits
void INotifyWinStateChanged.OnPlayerLost(Player player)
{
var players = player.World.Players.Where(p => !p.NonCombatant);
var enemies = players.Where(p => !p.IsAlliedWith(player));
if (Info.Cooperative)
{
WinStateCooperative = WinState.Lost;
var allies = players.Where(p => p.IsAlliedWith(player));
if (allies.Any(p => p.PlayerActor.Trait<MissionObjectives>().WinStateCooperative == WinState.Lost))
{

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits.Radar
{
public readonly bool UseLocation = false;
[Desc("Player stances who can view this actor on radar.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships who can view this actor on radar.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
public override object Create(ActorInitializer init) { return new AppearsOnRadar(this); }
}
@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits.Radar
public void PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer)
{
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
if (IsTraitDisabled || (viewer != null && !Info.ValidStances.HasStance(self.Owner.RelationshipWith(viewer))))
if (IsTraitDisabled || (viewer != null && !Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(viewer))))
return;
var color = Game.Settings.Game.UsePlayerStanceColors ? self.Owner.PlayerStanceColor(self) : self.Owner.Color;

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits.Render
class CashTricklerBarInfo : TraitInfo, Requires<CashTricklerInfo>
{
[Desc("Defines to which players the bar is to be shown.")]
public readonly PlayerRelationship DisplayStances = PlayerRelationship.Ally;
public readonly PlayerRelationship DisplayRelationships = PlayerRelationship.Ally;
public readonly Color Color = Color.Magenta;
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits.Render
float ISelectionBar.GetValue()
{
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
if (viewer != null && !info.DisplayStances.HasStance(self.Owner.RelationshipWith(viewer)))
if (viewer != null && !info.DisplayRelationships.HasStance(self.Owner.RelationshipWith(viewer)))
return 0;
var complete = cashTricklers.Min(ct => (float)ct.Ticks / ct.Info.Interval);

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits.Render
class SupportPowerChargeBarInfo : ConditionalTraitInfo
{
[Desc("Defines to which players the bar is to be shown.")]
public readonly PlayerRelationship DisplayStances = PlayerRelationship.Ally;
public readonly PlayerRelationship DisplayRelationships = PlayerRelationship.Ally;
public readonly Color Color = Color.Magenta;
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Traits.Render
return 0;
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
if (viewer != null && !Info.DisplayStances.HasStance(self.Owner.RelationshipWith(viewer)))
if (viewer != null && !Info.DisplayRelationships.HasStance(self.Owner.RelationshipWith(viewer)))
return 0;
return 1 - (float)power.RemainingTicks / power.TotalTicks;

View File

@@ -24,8 +24,8 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Position in the actor's selection box to draw the decoration.")]
public readonly string Position = "TopLeft";
[Desc("Player stances who can view the decoration.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("Player relationships who can view the decoration.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Should this be visible only when selected?")]
public readonly bool RequiresSelection = false;
@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Traits.Render
if (self.World.RenderPlayer != null)
{
var stance = self.Owner.RelationshipWith(self.World.RenderPlayer);
if (!Info.ValidStances.HasStance(stance))
if (!Info.ValidRelationships.HasStance(stance))
return false;
}

View File

@@ -148,7 +148,12 @@ namespace OpenRA.Mods.Common.Traits.Render
void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel)
{
Attacking(self, target, a);
// Lambdas can't use 'in' variables, so capture a copy for later
var attackTarget = target;
// HACK: The FrameEndTask makes sure that this runs after Tick(), preventing that from
// overriding the animation when an infantry unit stops to attack
self.World.AddFrameEndTask(_ => Attacking(self, attackTarget, a));
}
void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { }
@@ -160,10 +165,6 @@ namespace OpenRA.Mods.Common.Traits.Render
protected virtual void Tick(Actor self)
{
// Attacking takes care of reverting back to PlayStandAnimation
if (state == AnimationState.Attacking)
return;
if (rsm != null)
{
if (wasModifying != rsm.IsModifyingSequence)

View File

@@ -40,9 +40,9 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("If set, the color of the owning player will be used instead of `Color`.")]
public readonly bool UsePlayerColor = false;
[Desc("Stances of players which will be able to see the circle.",
[Desc("Player relationships which will be able to see the circle.",
"Valid values are combinations of `None`, `Ally`, `Enemy` and `Neutral`.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("When to show the range circle. Valid values are `Always`, and `WhenSelected`")]
public readonly RangeCircleVisibility Visible = RangeCircleVisibility.WhenSelected;
@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Traits.Render
return false;
var p = self.World.RenderPlayer;
return p == null || Info.ValidStances.HasStance(self.Owner.RelationshipWith(p)) || (p.Spectating && !p.NonCombatant);
return p == null || Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)) || (p.Spectating && !p.NonCombatant);
}
}

View File

@@ -18,8 +18,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Reveal this actor's last position when killed.")]
public class RevealOnDeathInfo : ConditionalTraitInfo
{
[Desc("Stances relative to the actors' owner that shroud will be revealed for.")]
public readonly PlayerRelationship RevealForStances = PlayerRelationship.Ally;
[Desc("Relationships relative to the actors' owner that shroud will be revealed for.")]
public readonly PlayerRelationship RevealForRelationships = PlayerRelationship.Ally;
[Desc("Duration of the reveal.")]
public readonly int Duration = 25;
@@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits
w.Add(new RevealShroudEffect(self.CenterPosition, info.Radius,
info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility,
owner, info.RevealForStances, duration: info.Duration));
owner, info.RevealForRelationships, duration: info.Duration));
});
}
}

View File

@@ -21,8 +21,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("The armament types which trigger revealing.")]
public readonly string[] ArmamentNames = { "primary", "secondary" };
[Desc("Stances relative to the target player this actor will be revealed to during firing.")]
public readonly PlayerRelationship RevealForStancesRelativeToTarget = PlayerRelationship.Ally;
[Desc("Player relationships relative to the target player this actor will be revealed to during firing.")]
public readonly PlayerRelationship RevealForRelationships = PlayerRelationship.Ally;
[Desc("Duration of the reveal.")]
public readonly int Duration = 25;
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.Traits
{
self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(self.CenterPosition, info.Radius,
info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility,
targetPlayer, info.RevealForStancesRelativeToTarget, duration: info.Duration)));
targetPlayer, info.RevealForRelationships, duration: info.Duration)));
}
}

View File

@@ -16,8 +16,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Reveals shroud and fog across the whole map while active.")]
public class RevealsMapInfo : ConditionalTraitInfo
{
[Desc("Stance the watching player needs to see the shroud removed.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("Relationships the watching player needs to see the shroud removed.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Can this actor reveal shroud generated by the `GeneratesShroud` trait?")]
public readonly bool RevealGeneratedShroud = true;
@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits
protected void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv)
{
if (!Info.ValidStances.HasStance(self.Owner.RelationshipWith(p)))
if (!Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)))
return;
p.Shroud.AddSource(this, type, uv);

View File

@@ -17,8 +17,8 @@ namespace OpenRA.Mods.Common.Traits
{
public class RevealsShroudInfo : AffectsShroudInfo
{
[Desc("Stance the watching player needs to see the shroud removed.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("Relationships the watching player needs to see the shroud removed.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Can this actor reveal shroud generated by the GeneratesShroud trait?")]
public readonly bool RevealGeneratedShroud = true;
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Traits
protected override void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv)
{
if (!info.ValidStances.HasStance(self.Owner.RelationshipWith(p)))
if (!info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)))
return;
p.Shroud.AddSource(this, type, uv);

View File

@@ -21,8 +21,8 @@ namespace OpenRA.Mods.Common.Traits.Sound
[Desc("Voice to play.")]
public readonly string Voice = null;
[Desc("Player stances who can hear this voice.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships who can hear this voice.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Play the voice to the owning player even if Stance.Ally is not included in ValidStances.")]
public readonly bool PlayToOwner = true;
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits.Sound
if (player == null)
return;
if (Info.ValidStances.HasStance(self.Owner.RelationshipWith(player)))
if (Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(player)))
self.PlayVoice(Info.Voice);
else if (Info.PlayToOwner && self.Owner == player)
self.PlayVoice(Info.Voice);

View File

@@ -39,8 +39,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Sound to instantly play at the targeted area.")]
public readonly string OnFireSound = null;
[Desc("Player stances which condition can be applied to.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
[Desc("Player relationships which condition can be applied to.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[SequenceReference]
[Desc("Sequence to play for granting actor when activated.",
@@ -96,7 +96,7 @@ namespace OpenRA.Mods.Common.Traits
return units.Distinct().Where(a =>
{
if (!info.ValidStances.HasStance(Self.Owner.RelationshipWith(a.Owner)))
if (!info.ValidRelationships.HasStance(Self.Owner.RelationshipWith(a.Owner)))
return false;
return a.TraitsImplementing<ExternalCondition>()

View File

@@ -94,8 +94,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Can the camera reveal shroud generated by the GeneratesShroud trait?")]
public readonly bool RevealGeneratedShroud = true;
[Desc("Reveal cells to players with these stances only.")]
public readonly PlayerRelationship CameraStances = PlayerRelationship.Ally;
[Desc("Reveal cells to players with these relationships only.")]
public readonly PlayerRelationship CameraRelationships = PlayerRelationship.Ally;
[Desc("Amount of time before detonation to spawn the camera.")]
public readonly int CameraSpawnAdvance = 25;
@@ -180,7 +180,7 @@ namespace OpenRA.Mods.Common.Traits
var type = info.RevealGeneratedShroud ? Shroud.SourceType.Visibility
: Shroud.SourceType.PassiveVisibility;
self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraStances,
self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraRelationships,
info.FlightDelay - info.CameraSpawnAdvance, info.CameraSpawnAdvance + info.CameraRemoveDelay)));
}

View File

@@ -77,7 +77,7 @@ namespace OpenRA.Mods.Common.Traits
public readonly string IncomingSpeechNotification = null;
[Desc("Defines to which players the timer is shown.")]
public readonly PlayerRelationship DisplayTimerStances = PlayerRelationship.None;
public readonly PlayerRelationship DisplayTimerRelationships = PlayerRelationship.None;
[Desc("Beacons are only supported on the Airstrike, Paratroopers, and Nuke powers")]
public readonly bool DisplayBeacon = false;

View File

@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
[Translate]
public readonly string Description = "";
[Desc("Player stances who can view the description.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Player relationships who can view the description.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
public override object Create(ActorInitializer init) { return new TooltipDescription(init.Self, this); }
}
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits
if (Owner == null || forPlayer == null)
return false;
return Info.ValidStances.HasStance(Owner.RelationshipWith(forPlayer));
return Info.ValidRelationships.HasStance(Owner.RelationshipWith(forPlayer));
}
public string TooltipText

View File

@@ -9,6 +9,8 @@
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
@@ -27,6 +29,9 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Maximum amount of ticks the actor will sit idly before starting to wander.")]
public readonly int MaxMoveDelay = 0;
[Desc("The terrain types that this actor should avoid wandering on to.")]
public readonly HashSet<string> AvoidTerrainTypes = new HashSet<string>();
public override object Create(ActorInitializer init) { return new Wanders(init.Self, this); }
}
@@ -75,8 +80,8 @@ namespace OpenRA.Mods.Common.Traits
return;
var targetCell = PickTargetLocation();
if (targetCell != CPos.Zero)
DoAction(self, targetCell);
if (targetCell.HasValue)
DoAction(self, targetCell.Value);
}
void INotifyIdle.TickIdle(Actor self)
@@ -84,7 +89,7 @@ namespace OpenRA.Mods.Common.Traits
TickIdle(self);
}
CPos PickTargetLocation()
CPos? PickTargetLocation()
{
var target = self.CenterPosition + new WVec(0, -1024 * effectiveMoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255)));
var targetCell = self.World.Map.CellContaining(target);
@@ -95,7 +100,15 @@ namespace OpenRA.Mods.Common.Traits
if (++ticksIdle % info.ReduceMoveRadiusDelay == 0)
effectiveMoveRadius--;
return CPos.Zero; // We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop
// We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop
return null;
}
if (info.AvoidTerrainTypes.Count > 0)
{
var terrainType = self.World.Map.GetTerrainInfo(targetCell).Type;
if (Info.AvoidTerrainTypes.Contains(terrainType))
return null;
}
ticksIdle = 0;

View File

@@ -60,6 +60,8 @@ namespace OpenRA.Mods.Common.Traits
IsBot = client.Bot != null,
FactionName = resolvedFaction.Name,
FactionId = resolvedFaction.InternalName,
DisplayFactionName = clientFaction.Name,
DisplayFactionId = clientFaction.InternalName,
Color = client.Color,
Team = client.Team,
SpawnPoint = resolvedSpawnPoint,

View File

@@ -0,0 +1,104 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
namespace OpenRA.Mods.Common.UpdateRules.Rules
{
public class RenameStances : UpdateRule
{
public override string Name { get { return "Renamed player 'Stances' to 'Relationships'."; } }
public override string Description
{
get
{
return "'Stances' in regards to a player have been renamed to 'Relationships'.\n" +
"The yaml values did not change.";
}
}
readonly (string TraitName, string OldName, string NewName)[] traits =
{
("Disguise", "ValidStances", "ValidRelationships"),
("Infiltrates", "ValidStances", "ValidRelationships"),
("AcceptsDeliveredCash", "ValidStances", "ValidRelationships"),
("AcceptsDeliveredExperience", "ValidStances", "ValidRelationships"),
("Armament", "TargetStances", "TargetRelationships"),
("Armament", "ForceTargetStances", "ForceTargetRelationships"),
("AutoTargetPriority", "ValidStances", "ValidRelationships"),
("CaptureManagerBotModule", "CapturableStances", "CapturableRelationships"),
("Capturable", "ValidStances", "ValidRelationships"),
("Captures", "PlayerExperienceStances", "PlayerExperienceRelationships"),
("ProximityExternalCondition", "ValidStances", "ValidRelationships"),
("CreatesShroud", "ValidStances", "ValidRelationships"),
("Demolition", "TargetStances", "TargetRelationships"),
("Demolition", "ForceTargetStances", "ForceTargetRelationships"),
("EngineerRepair", "ValidStances", "ValidRelationships"),
("GivesBounty", "ValidStances", "ValidRelationships"),
("GivesExperience", "ValidStances", "ValidRelationships"),
("JamsMissiles", "DeflectionStances", "DeflectionRelationships"),
("FrozenUnderFog", "AlwaysVisibleStances", "AlwaysVisibleRelationships"),
("HiddenUnderShroud", "AlwaysVisibleStances", "AlwaysVisibleRelationships"),
("HiddenUnderFog", "AlwaysVisibleStances", "AlwaysVisibleRelationships"),
("AppearsOnRadar", "ValidStances", "ValidRelationships"),
("CashTricklerBar", "DisplayStances", "DisplayRelationships"),
("SupportPowerChargeBar", "DisplayStances", "DisplayRelationships"),
("WithAmmoPipsDecoration", "ValidStances", "ValidRelationships"),
("WithCargoPipsDecoration", "ValidStances", "ValidRelationships"),
("WithDecoration", "ValidStances", "ValidRelationships"),
("WithHarvesterPipsDecoration", "ValidStances", "ValidRelationships"),
("WithNameTagDecoration", "ValidStances", "ValidRelationships"),
("WithResourceStoragePipsDecoration", "ValidStances", "ValidRelationships"),
("WithTextDecoration", "ValidStances", "ValidRelationships"),
("WithRangeCircle", "ValidStances", "ValidRelationships"),
("RevealOnDeath", "RevealForStances", "RevealForRelationships"),
("RevealOnFire", "RevealForStancesRelativeToTarget", "RevealForRelationships"),
("RevealsMap", "ValidStances", "ValidRelationships"),
("RevealsShroud", "ValidStances", "ValidRelationships"),
("VoiceAnnouncement", "ValidStances", "ValidRelationships"),
("GrantExternalConditionPower", "ValidStances", "ValidRelationships"),
("NukePower", "CameraStances", "CameraRelationships"),
("NukePower", "DisplayTimerStances", "DisplayTimerRelationships"),
("AttackOrderPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("ChronoshiftPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("DropPodsPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("GpsPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("GrantPrerequisiteChargeDrainPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("IonCannonPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("AirstrikePower", "DisplayTimerStances", "DisplayTimerRelationships"),
("GrantExternalConditionPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("ParatroopersPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("ProduceActorPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("SpawnActorPower", "DisplayTimerStances", "DisplayTimerRelationships"),
("TooltipDescription", "ValidStances", "ValidRelationships")
};
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
foreach (var field in traits)
foreach (var traitNode in actorNode.ChildrenMatching(field.TraitName))
traitNode.RenameChildrenMatching(field.OldName, field.NewName);
yield break;
}
public override IEnumerable<string> UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode)
{
foreach (var projectileNode in weaponNode.ChildrenMatching("Projectile"))
projectileNode.RenameChildrenMatching("ValidBounceBlockerStances", "ValidBounceBlockerRelationships");
foreach (var warheadNode in weaponNode.ChildrenMatching("Warhead"))
warheadNode.RenameChildrenMatching("ValidStances", "ValidRelationships");
yield break;
}
}
}

View File

@@ -73,6 +73,7 @@ namespace OpenRA.Mods.Common.UpdateRules
new RenameSelfHealing(),
new ReplaceBurns(),
new RemoveMuzzleSplitFacings(),
new RenameStances(),
new RemoveTurnToDock(),
new RenameSmudgeSmokeFields(),
new RenameCircleContrast(),

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Warheads
public override bool IsValidAgainst(Actor victim, Actor firedBy)
{
var stance = firedBy.Owner.RelationshipWith(victim.Owner);
if (!ValidStances.HasStance(stance))
if (!ValidRelationships.HasStance(stance))
return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.

View File

@@ -31,8 +31,8 @@ namespace OpenRA.Mods.Common.Warheads
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
public readonly BitSet<TargetableType> InvalidTargets;
[Desc("What diplomatic stances are affected.")]
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("What player relationships are affected.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
[Desc("Can this warhead affect the actor that fired it.")]
public readonly bool AffectsParent = false;
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Warheads
return false;
var stance = firedBy.Owner.RelationshipWith(victim.Owner);
if (!ValidStances.HasStance(stance))
if (!ValidRelationships.HasStance(stance))
return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
@@ -81,7 +81,7 @@ namespace OpenRA.Mods.Common.Warheads
// AffectsParent checks do not make sense for FrozenActors, so skip to stance checks
var stance = firedBy.Owner.RelationshipWith(victim.Owner);
if (!ValidStances.HasStance(stance))
if (!ValidRelationships.HasStance(stance))
return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Widgets
powers = world.ActorsWithTrait<SupportPowerManager>()
.Where(p => !p.Actor.IsDead && !p.Actor.Owner.NonCombatant)
.SelectMany(s => s.Trait.Powers.Values)
.Where(p => p.Instances.Any() && p.Info.DisplayTimerStances != PlayerRelationship.None && !p.Disabled);
.Where(p => p.Instances.Any() && p.Info.DisplayTimerRelationships != PlayerRelationship.None && !p.Disabled);
// Timers in replays should be synced to the effective game time, not the playback time.
timestep = world.Timestep;
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Widgets
{
var owner = p.Instances[0].Self.Owner;
var viewer = owner.World.RenderPlayer ?? owner.World.LocalPlayer;
return viewer == null || p.Info.DisplayTimerStances.HasStance(owner.RelationshipWith(viewer));
return viewer == null || p.Info.DisplayTimerRelationships.HasStance(owner.RelationshipWith(viewer));
});
texts = displayedPowers.Select(p =>

View File

@@ -4,7 +4,7 @@ A Libre/Free Real Time Strategy game engine supporting early Westwood classics.
* Website: [http://www.openra.net](http://www.openra.net)
* IRC: \#openra on irc.freenode.net
* Repository: [https://github.com/OpenRA/OpenRA](https://github.com/OpenRA/OpenRA) [![Travis CI build status](https://travis-ci.org/OpenRA/OpenRA.svg?branch=bleed)](https://travis-ci.org/OpenRA/OpenRA) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/axc9k6jd25ej2o4w?svg=true)](https://ci.appveyor.com/project/OpenRA/openra)
* Repository: [https://github.com/OpenRA/OpenRA](https://github.com/OpenRA/OpenRA) ![Continuous Integration](https://github.com/OpenRA/OpenRA/workflows/Continuous%20Integration/badge.svg)
Please read the [FAQ](http://wiki.openra.net/FAQ) in our [Wiki](http://wiki.openra.net) and report problems at [http://bugs.openra.net](http://bugs.openra.net).

View File

@@ -1,28 +0,0 @@
version: 1.0.{build}
image: Visual Studio 2017
install:
build_script:
- make all
test_script:
- nunit3-console bin/OpenRA.Test.dll --result=myresults.xml;format=AppVeyor
after_test:
- appveyor DownloadFile "https://github.com/OpenRA/GeoIP-Database/releases/download/monthly/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" -FileName IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
- pip install Pillow
- python -c "from PIL import Image; i = Image.open('packaging/artwork/ra_256x256.png'); i.save('ra.ico')"
- python -c "from PIL import Image; i = Image.open('packaging/artwork/cnc_256x256.png'); i.save('cnc.ico')"
- python -c "from PIL import Image; i = Image.open('packaging/artwork/d2k_256x256.png'); i.save('d2k.ico')"
- msbuild -t:Build "OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="win-x64" -p:LauncherName="RedAlert" -p:LauncherIcon="../ra.ico" -p:ModID="ra" -p:DisplayName="Red Alert" -p:FaqUrl="http://wiki.openra.net/FAQ"
- msbuild -t:Build "OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="win-x64" -p:LauncherName="TiberianDawn" -p:LauncherIcon="../cnc.ico" -p:ModID="cnc" -p:DisplayName="Tiberian Dawn" -p:FaqUrl="http://wiki.openra.net/FAQ"
- msbuild -t:Build "OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="win-x64" -p:LauncherName="Dune2000" -p:LauncherIcon="../d2k.ico" -p:ModID="d2k" -p:DisplayName="Dune 2000" -p:FaqUrl="http://wiki.openra.net/FAQ"
- move /Y %APPVEYOR_BUILD_FOLDER%\bin\* %APPVEYOR_BUILD_FOLDER%
- if defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_TAG_NAME%
- if not defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_COMMIT:~0,7%
- '"C:\Program Files (x86)\NSIS\makensis.exe" /DSRCDIR="%APPVEYOR_BUILD_FOLDER%" /DTAG="git-%VERSION%" /DSUFFIX=" (dev)" /V3 /DOUTFILE="OpenRA-$(VERSION).exe" packaging/windows/OpenRA.nsi'
artifacts:
- path: OpenRA-$(VERSION).exe
name: Installer

View File

@@ -117,7 +117,7 @@ BOAT:
Health:
HP: 150000
RevealsShroud:
ValidStances: Ally, Neutral, Enemy
ValidRelationships: Ally, Neutral, Enemy
Range: 4c0
TRAN.IN:

View File

@@ -169,7 +169,7 @@ BOAT:
Except: Attack
RevealsShroud:
Range: 4c0
ValidStances: Enemy, Neutral, Ally
ValidRelationships: Enemy, Neutral, Ally
FACT.IN:
Inherits: FACT

View File

@@ -137,7 +137,7 @@ BOAT:
RejectsOrders:
Except: Attack
RevealsShroud:
ValidStances: Ally, Neutral, Enemy
ValidRelationships: Ally, Neutral, Enemy
Range: 4c0
TRAN.IN:

View File

@@ -189,7 +189,7 @@ C17:
Repulsable: False
MaximumPitch: 36
HiddenUnderFog:
AlwaysVisibleStances: None
AlwaysVisibleRelationships: None
Type: CenterPosition
Cargo:
MaxWeight: 10

View File

@@ -93,7 +93,7 @@
Palette: effect
Position: BottomRight
Margin: 5, 6
ValidStances: Ally, Enemy, Neutral
ValidRelationships: Ally, Enemy, Neutral
RequiresCondition: rank-veteran == 1
WithDecoration@RANK-2:
Image: rank
@@ -101,7 +101,7 @@
Palette: effect
Position: BottomRight
Margin: 5, 6
ValidStances: Ally, Enemy, Neutral
ValidRelationships: Ally, Enemy, Neutral
RequiresCondition: rank-veteran == 2
WithDecoration@RANK-ELITE:
Image: rank
@@ -109,7 +109,7 @@
Palette: effect
Position: BottomRight
Margin: 5, 6
ValidStances: Ally, Enemy, Neutral
ValidRelationships: Ally, Enemy, Neutral
RequiresCondition: rank-elite
^InfantryExperienceHospitalHazmatOverrides:
@@ -468,6 +468,7 @@
Notification: CivilianKilled
NotifyAll: true
ScaredyCat:
AvoidTerrainTypes: Tiberium, BlueTiberium
Crushable:
CrushSound: squish2.aud
Voiced:
@@ -475,6 +476,7 @@
Wanders:
MinMoveDelay: 150
MaxMoveDelay: 750
AvoidTerrainTypes: Tiberium, BlueTiberium
MapEditorData:
Categories: Civilian infantry
@@ -606,7 +608,7 @@
UseLocation: true
HiddenUnderFog:
Type: GroundPosition
AlwaysVisibleStances: None
AlwaysVisibleRelationships: None
ActorLostNotification:
AttackMove:
WithShadow:
@@ -995,7 +997,7 @@
Type: Light
HiddenUnderFog:
Type: CenterPosition
AlwaysVisibleStances: None
AlwaysVisibleRelationships: None
WithFacingSpriteBody:
HitShape:
MapEditorData:
@@ -1011,7 +1013,7 @@
CaptureManager:
Capturable:
Types: husk
ValidStances: Enemy, Neutral, Ally
ValidRelationships: Enemy, Neutral, Ally
TransformOnCapture:
ForceHealthPercentage: 25
Tooltip:

View File

@@ -909,6 +909,7 @@ SAM:
RealignDelay: -1
-WithSpriteBody:
WithEmbeddedTurretSpriteBody:
QuantizedFacings: 32
Armament:
Weapon: Dragon
MuzzleSequence: muzzle

View File

@@ -14,10 +14,10 @@ V19:
Name: Oil Derrick
TooltipDescription@ally:
Description: Provides additional funds.
ValidStances: Ally
ValidRelationships: Ally
TooltipDescription@other:
Description: Capture to receive additional funds.
ValidStances: Neutral, Enemy
ValidRelationships: Neutral, Enemy
SpawnActorOnDeath:
Actor: V19.Husk
UpdatesDerrickCount:
@@ -52,10 +52,10 @@ HOSP:
Name: Hospital
TooltipDescription@ally:
Description: Provides infantry with self-healing.
ValidStances: Ally
ValidRelationships: Ally
TooltipDescription@other:
Description: Capture to enable self-healing for infantry.
ValidStances: Neutral, Enemy
ValidRelationships: Neutral, Enemy
SpawnActorOnDeath:
Actor: HOSP.Husk
WithBuildingBib:
@@ -88,10 +88,10 @@ BIO:
Name: Biological Lab
TooltipDescription@ally:
Description: Provides infantry with Tiberium immunity. Produces Visceroids.
ValidStances: Ally
ValidRelationships: Ally
TooltipDescription@other:
Description: Capture to enable Tiberium immunity for infantry. Produces Visceroids.
ValidStances: Neutral, Enemy
ValidRelationships: Neutral, Enemy
Exit@1:
SpawnOffset: 0,-426,0
ExitCell: 0,-1

View File

@@ -219,7 +219,7 @@ Player:
RequiresCondition: enable-omnius-ai
SquadSize: 8
MaxBaseRadius: 40
ExcludeFromSquadsTypes: harvester, mcv
ExcludeFromSquadsTypes: harvester, mcv, carryall, carryall.reinforce
ConstructionYardTypes: construction_yard
IgnoredEnemyTargetTypes: Creep
UnitBuilderBotModule@omnius:
@@ -263,7 +263,7 @@ Player:
RequiresCondition: enable-vidious-ai
SquadSize: 6
MaxBaseRadius: 40
ExcludeFromSquadsTypes: harvester, mcv
ExcludeFromSquadsTypes: harvester, mcv, carryall, carryall.reinforce
ConstructionYardTypes: construction_yard
IgnoredEnemyTargetTypes: Creep
UnitBuilderBotModule@vidious:
@@ -302,7 +302,7 @@ Player:
RequiresCondition: enable-gladius-ai
SquadSize: 10
MaxBaseRadius: 40
ExcludeFromSquadsTypes: harvester, mcv
ExcludeFromSquadsTypes: harvester, mcv, carryall, carryall.reinforce
ConstructionYardTypes: construction_yard
IgnoredEnemyTargetTypes: Creep
UnitBuilderBotModule@gladius:

View File

@@ -250,7 +250,7 @@
Type: light
HiddenUnderFog:
Type: CenterPosition
AlwaysVisibleStances: None
AlwaysVisibleRelationships: None
Tooltip:
GenericName: Destroyed Unit
ScriptTriggers:
@@ -376,7 +376,7 @@
UseLocation: true
HiddenUnderFog:
Type: GroundPosition
AlwaysVisibleStances: None
AlwaysVisibleRelationships: None
ActorLostNotification:
AttackMove:
WithFacingSpriteBody:

View File

@@ -19,7 +19,7 @@ Sound:
Falloff: 100, 100
Damage: 860
AffectsParent: false
ValidStances: Neutral, Enemy
ValidRelationships: Neutral, Enemy
Versus:
none: 200
wall: 50
@@ -36,7 +36,7 @@ Sound:
Falloff: 100, 100
Damage: 430 # Only does half damage to friendly units
AffectsParent: false
ValidStances: Ally
ValidRelationships: Ally
Versus:
none: 200
wall: 50

View File

@@ -68,7 +68,7 @@ TRUK.mission:
-SpawnActorOnDeath:
RevealsShroud:
Range: 4c0
ValidStances: Ally, Enemy
ValidRelationships: Ally, Enemy
RequiresCondition: hijacked
ExternalCondition@hijacked:
Condition: hijacked

View File

@@ -0,0 +1,209 @@
--[[
Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version. For more
information, see COPYING.
]]
WTransWays =
{
{ USSRRFEntry.Location, USSRUnload1.Location },
{ USSRRFEntry.Location, USSRUnload2.Location }
}
WTransUnits =
{
hard = { { "3tnk", "3tnk", "3tnk", "v2rl", "v2rl" }, { "v2rl", "v2rl", "e4", "e4", "3tnk" } },
normal = { { "e1", "e1", "3tnk", "3tnk", "v2rl" }, { "e4", "e4", "e4", "e4", "v2rl" } },
easy = { { "e1", "e1", "e1", "e2", "e2" }, { "e2", "3tnk", "3tnk" } }
}
WTransDelays =
{
easy = 7,
normal = 6,
hard = 5
}
SubAttackGroupSize =
{
easy = 1,
normal = 2,
hard = 3
}
InfantryUnits =
{
hard = { "e1", "e2", "e2", "e4", "e4" },
normal = { "e1", "e1", "e2", "e2", "e4" },
easy = { "e1", "e1", "e1", "e2", "e2" }
}
ProductionInterval =
{
easy = DateTime.Seconds(60),
normal = DateTime.Seconds(40),
hard = DateTime.Seconds(20)
}
ParadropDelay =
{
easy = 7,
normal = 6,
hard = 5
}
InfantryAttackGroup = { }
InfantryAttackGroupSize = 5
VehicleAttackGroup = { }
VehicleAttackGroupSize = 3
SubAttackGroup = { }
SovietAircraftType = { "yak" }
SovietSSType = { "ss" }
VehicleUnits = { "3tnk", "3tnk", "3tnk", "v2rl" }
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
SendInfantryAttackGroup = function()
if #InfantryAttackGroup < InfantryAttackGroupSize then
return
end
Utils.Do(InfantryAttackGroup, IdleHunt)
InfantryAttackGroup = { }
end
SendVehicleAttackGroup = function()
if #VehicleAttackGroup < VehicleAttackGroupSize then
return
end
Utils.Do(VehicleAttackGroup, IdleHunt)
VehicleAttackGroup = { }
end
SendSubAttackGroup = function()
if #SubAttackGroup < SubAttackGroupSize then
return
end
Utils.Do(SubAttackGroup, IdleHunt)
SubAttackGroup = { }
end
ProduceSovietInfantry = function()
if (Barracks.IsDead or Barracks.Owner ~= USSR) and (BarracksA.IsDead or BarracksA.Owner ~= USSR) then
return
end
USSR.Build({ Utils.Random(InfantryUnits) }, function(units)
table.insert(InfantryAttackGroup, units[1])
SendInfantryAttackGroup()
Trigger.AfterDelay(ProductionInterval, ProduceSovietInfantry)
end)
end
ProduceSovietVehicle = function()
if WarFactory.IsDead or WarFactory.Owner ~= USSR then
return
end
USSR.Build({ Utils.Random(VehicleUnits) }, function(units)
table.insert(VehicleAttackGroup, units[1])
SendVehicleAttackGroup()
Trigger.AfterDelay(ProductionInterval, ProduceSovietVehicle)
end)
end
ProduceSovietSub = function()
if SubPen.IsDead or SubPen.Owner ~= USSR then
return
end
USSR.Build(SovietSSType, function(units)
table.insert(SubAttackGroup, units[1])
SendSubAttackGroup()
Trigger.AfterDelay(ProductionInterval, ProduceSovietSub)
end)
end
ProduceAircraft = function()
if Airfield.IsDead or Airfield.Owner ~= USSR then
return
end
USSR.Build(SovietAircraftType, function(units)
local yak = units[1]
Trigger.OnKilled(yak, ProduceAircraft)
InitializeAttackAircraft(yak, Greece)
end)
end
WTransWaves = function()
if SubPen.IsDead or SubPen.Owner ~= USSR then
return
end
local way = Utils.Random(WTransWays)
local units = Utils.Random(WTransUnits)
local attackUnits = Reinforcements.ReinforceWithTransport(USSR, "lst", units , way, { way[2], way[1] })[2]
Utils.Do(attackUnits, function(a)
Trigger.OnAddedToWorld(a, function()
a.AttackMove(KosyginExtractPoint.Location)
IdleHunt(a)
end)
end)
Trigger.AfterDelay(DateTime.Minutes(WTransDelays), WTransWaves)
end
MMGroupGuardGate = function()
if not MM1.IsDead then
MM1.AttackMove(WP78.Location)
end
if not MM2.IsDead then
MM2.AttackMove(WP79.Location)
end
if not MM1.IsDead then
MM3.AttackMove(WP80.Location)
end
end
TankGroupWallGuard = function()
if not WGTank01.IsDead then
WGTank01.AttackMove(WP72.Location)
end
if not WGTank02.IsDead then
WGTank02.AttackMove(WP72.Location)
end
if not WGV2.IsDead then
WGV2.AttackMove(WP72.Location)
end
end
Paradrop = function()
if Airfield.IsDead or Airfield.Owner ~= USSR then
return
end
local aircraft = PowerProxy.TargetParatroopers(KosyginExtractPoint.CenterPosition)
Utils.Do(aircraft, function(a)
Trigger.OnPassengerExited(a, function(t, p)
IdleHunt(p)
end)
end)
Trigger.AfterDelay(DateTime.Minutes(ParadropDelay), Paradrop)
end
ActivateAI = function()
local difficulty = Map.LobbyOption("difficulty")
WTransUnits = WTransUnits[difficulty]
WTransDelays = WTransDelays[difficulty]
SubAttackGroupSize = SubAttackGroupSize[difficulty]
InfantryUnits = InfantryUnits[difficulty]
ProductionInterval = ProductionInterval[difficulty]
ParadropDelay = ParadropDelay[difficulty]
PowerProxy = Actor.Create("powerproxy.paratroopers", false, { Owner = USSR })
local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == USSR and self.HasProperty("StartBuildingRepairs") end)
Utils.Do(buildings, function(actor)
Trigger.OnDamaged(actor, function(building)
if building.Owner == USSR and building.Health < building.MaxHealth * 3/4 then
building.StartBuildingRepairs()
end
end)
end)
Trigger.AfterDelay(DateTime.Minutes(2), ProduceAircraft)
Trigger.AfterDelay(DateTime.Minutes(2), ProduceSovietInfantry)
Trigger.AfterDelay(DateTime.Minutes(2), ProduceSovietVehicle)
Trigger.AfterDelay(DateTime.Minutes(4), ProduceSovietSub)
Trigger.AfterDelay(DateTime.Minutes(5), MMGroupGuardGate)
Trigger.AfterDelay(DateTime.Minutes(5), TankGroupWallGuard)
Trigger.AfterDelay(DateTime.Minutes(WTransDelays), WTransWaves)
Trigger.AfterDelay(DateTime.Minutes(ParadropDelay), Paradrop)
end

View File

@@ -0,0 +1,184 @@
--[[
Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version. For more
information, see COPYING.
]]
lstReinforcements =
{
actors = { "mcv" },
entryPath = { AlliedMCVEntry.Location, Unload1.Location },
exitPath = { AlliedMCVEntry.Location }
}
ExtractionHelicopterType = "tran.extraction"
ExtractionPath = { HeliWP01.Location, HeliWP02.Location, HeliWP03.Location }
Dog5PatrolPath = { WP94.Location, WP93.Location }
Dog6PatrolPath = { WP90.Location, WP91.Location, WP92.Location, WP91.Location }
TankGroup10 = { TankGroup101, TankGroup102 }
TankGroup10PatrolPath = { WP81.Location, WP82.Location, WP83.Location, WP84.Location, WP85.Location, WP84.Location, WP83.Location, WP82.Location }
HuntDogsGroup = { Dog701, Dog702, Dog703, Dog704, Dog705, Dog706 }
KosyginType = "gnrl"
KosyginContacted = false
MissionAccomplished = function()
Media.PlaySpeechNotification(Greece, "MissionAccomplished")
end
MissionFailed = function()
Media.PlaySpeechNotification(Greece, "MissionFailed")
end
InitialAlliedReinforcements = function()
Trigger.AfterDelay(DateTime.Seconds(1), function()
Media.PlaySpeechNotification(Greece, "ReinforcementsArrived")
Reinforcements.ReinforceWithTransport(Greece, "lst.reinforcement", lstReinforcements.actors, lstReinforcements.entryPath, lstReinforcements.exitPath)
end)
end
RescueFailed = function()
Media.PlaySpeechNotification(Greece, "ObjectiveNotMet")
Greece.MarkFailedObjective(KosyginSurviveObjective)
end
InitialSovietPatrols = function()
Dog5.Patrol(Dog5PatrolPath, true, DateTime.Seconds(60))
Dog6.Patrol(Dog6PatrolPath, true, DateTime.Seconds(90))
for i = 1, 2 do
TankGroup10[i].Patrol(TankGroup10PatrolPath, true, DateTime.Seconds(30))
end
end
CreateKosygin = function()
Greece.MarkCompletedObjective(UseSpyObjective)
Media.PlaySpeechNotification(Greece, "ObjectiveMet")
local kosygin = Actor.Create(KosyginType, true, { Location = KosyginSpawnPoint.Location, Owner = Greece })
Trigger.OnKilled(kosygin, RescueFailed)
ExtractObjective = Greece.AddObjective("Extract Kosygin and\nget him back to your base.")
Trigger.AfterDelay(DateTime.Seconds(1), function() Media.PlaySpeechNotification(Greece, "TargetFreed") end)
end
DogsGuardGates = function()
if not Dog707.IsDead then
Dog707.AttackMove(WP89.Location)
end
if not Dog708.IsDead then
Dog708.AttackMove(WP81.Location)
end
if not Dog709.IsDead then
Dog709.AttackMove(WP79.Location)
end
end
InfiltrateForwardCenter = function()
Trigger.OnInfiltrated(USSRFC, function()
if not KosyginContacted then
KosyginContacted = true
CreateKosygin()
DogsGuardGates()
end
end)
Trigger.OnKilledOrCaptured(USSRFC, function()
if not Greece.IsObjectiveCompleted(UseSpyObjective) then
Greece.MarkFailedObjective(UseSpyObjective)
end
end)
end
Tick = function()
USSR.Cash = 5000
if Greece.HasNoRequiredUnits() then
USSR.MarkCompletedObjective(USSRObj)
end
end
TriggerHuntKosygin = function()
Trigger.OnEnteredProximityTrigger(WP79.CenterPosition, WDist.FromCells(4), function(actor, triggerflee)
if actor.Type == KosyginType then
Trigger.RemoveProximityTrigger(triggerflee)
for i = 1, 6 do
if not HuntDogsGroup[i].IsDead then
HuntDogsGroup[i].Attack(actor)
end
end
end
end)
Trigger.OnEnteredProximityTrigger(WP81.CenterPosition, WDist.FromCells(4), function(actor, triggerflee)
if actor.Type == KosyginType then
Trigger.RemoveProximityTrigger(triggerflee)
for i = 1, 6 do
if not HuntDogsGroup[i].IsDead then
HuntDogsGroup[i].Attack(actor)
end
end
end
end)
Trigger.OnEnteredProximityTrigger(WP89.CenterPosition, WDist.FromCells(4), function(actor, triggerflee)
if actor.Type == KosyginType then
Trigger.RemoveProximityTrigger(triggerflee)
for i = 1, 6 do
if not HuntDogsGroup[i].IsDead then
HuntDogsGroup[i].Attack(actor)
end
end
end
end)
end
TriggerRevealUSSRBase = function()
Trigger.OnEnteredProximityTrigger(LowerBaseWP.CenterPosition, WDist.FromCells(10), function(a, id)
if a.Owner == Greece then
Trigger.RemoveProximityTrigger(id)
local cam = Actor.Create("Camera", true, { Owner = Greece, Location = RevealLowerBase.Location })
Trigger.AfterDelay(DateTime.Seconds(15), cam.Destroy)
end
end)
end
TriggerRevealUSSRFC = function()
Trigger.OnEnteredProximityTrigger(UpperBaseWP.CenterPosition, WDist.FromCells(10), function(a, id)
if a.Owner == Greece then
Trigger.RemoveProximityTrigger(id)
local cam = Actor.Create("Camera", true, { Owner = Greece, Location = KosyginSpawnPoint.Location })
Trigger.AfterDelay(DateTime.Seconds(15), cam.Destroy)
end
end)
end
TriggerExtractKosygin = function()
Trigger.OnEnteredProximityTrigger(KosyginExtractPoint.CenterPosition, WDist.FromCells(10), function(actor, triggerflee)
if actor.Type == KosyginType then
Reinforcements.ReinforceWithTransport(Greece, ExtractionHelicopterType, nil, ExtractionPath)
Trigger.RemoveProximityTrigger(triggerflee)
Trigger.AfterDelay(DateTime.Seconds(10), function()
Greece.MarkCompletedObjective(KosyginSurviveObjective)
Greece.MarkCompletedObjective(ExtractObjective)
Media.PlaySpeechNotification(Greece, "ObjectiveMet")
end)
end
end)
end
WorldLoaded = function()
Greece = Player.GetPlayer("Greece")
USSR = Player.GetPlayer("USSR")
Camera.Position = DefaultCameraPosition.CenterPosition
UseSpyObjective = Greece.AddObjective("Infiltrate the Soviet command center and\ncontact Kosygin.")
KosyginSurviveObjective = Greece.AddObjective("Kosygin must survive.")
USSRObj = USSR.AddObjective("Eliminate all Allied forces.")
Trigger.OnPlayerLost(Greece, MissionFailed)
Trigger.OnPlayerWon(Greece, MissionAccomplished)
InitialAlliedReinforcements()
InfiltrateForwardCenter()
InitialSovietPatrols()
TriggerRevealUSSRBase()
TriggerRevealUSSRFC()
TriggerExtractKosygin()
TriggerHuntKosygin()
ActivateAI()
end

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,975 @@
MapFormat: 11
RequiresMod: ra
Title: 09a: Evacuate Kosygin
Author: Westwood Studios
Tileset: TEMPERAT
MapSize: 86,72
Bounds: 1,1,84,70
Visibility: MissionSelector
Categories: Campaign
LockPreview: True
Players:
PlayerReference@Neutral:
Name: Neutral
OwnsWorld: True
NonCombatant: True
Faction: england
PlayerReference@Creeps:
Name: Creeps
NonCombatant: True
Faction: england
PlayerReference@USSR:
Name: USSR
Bot: campaign
Faction: soviet
Color: FF1400
Enemies: Greece
PlayerReference@Greece:
Name: Greece
Playable: True
Required: True
LockFaction: True
Faction: allies
LockColor: True
Color: E2E6F5
Enemies: USSR
Actors:
Actor0: t17
Owner: Neutral
Location: 18,21
Health: 100
Actor1: tc02
Owner: Neutral
Location: 7,33
Actor2: tc04
Owner: Neutral
Location: 1,28
Actor3: t08
Owner: Neutral
Location: 6,29
Actor4: tc04
Owner: Neutral
Location: 9,27
Health: 100
Actor5: tc05
Owner: Neutral
Location: 12,27
Actor6: tc03
Owner: Neutral
Location: 11,29
Actor7: tc05
Owner: Neutral
Location: 67,11
Actor8: t16
Owner: Neutral
Location: 73,10
Actor9: t12
Owner: Neutral
Location: 67,8
Actor10: t02
Owner: Neutral
Location: 67,4
Actor11: t17
Owner: Neutral
Location: 69,1
Actor12: t14
Owner: Neutral
Location: 71,3
Actor13: t03
Owner: Neutral
Location: 72,7
Actor14: t12
Owner: Neutral
Location: 59,19
Actor15: mine
Owner: Neutral
Location: 69,57
Actor16: t08
Owner: Neutral
Location: 65,52
Actor17: tc02
Owner: Neutral
Location: 61,50
Actor18: t07
Owner: Neutral
Location: 60,53
Actor19: tc01
Owner: Neutral
Location: 55,53
Actor20: mine
Owner: Neutral
Location: 43,58
Actor21: t10
Owner: Neutral
Location: 29,63
Actor22: t08
Owner: Neutral
Location: 28,63
Actor23: t07
Owner: Neutral
Location: 30,62
Actor24: tc05
Owner: Neutral
Location: 22,49
Actor25: tc04
Owner: Neutral
Location: 25,49
Actor26: tc03
Owner: Neutral
Location: 11,58
Actor28: tc02
Owner: Neutral
Location: 13,60
Actor30: t11
Owner: Neutral
Location: 12,59
Actor29: tc01
Owner: Neutral
Location: 15,61
Actor31: tc04
Owner: Neutral
Location: 22,27
Health: 100
Actor32: tc04
Owner: Neutral
Location: 19,31
Actor33: tc03
Owner: Neutral
Location: 24,31
Actor34: tc04
Owner: Neutral
Location: 26,31
Actor35: t10
Owner: Neutral
Location: 26,28
Actor36: tc02
Owner: Neutral
Location: 31,25
Health: 100
Actor37: tc01
Owner: Neutral
Location: 46,36
Actor38: t11
Owner: Neutral
Location: 44,35
Actor39: t16
Owner: Neutral
Location: 48,35
Actor40: t11
Owner: Neutral
Location: 45,31
Actor41: t13
Owner: Neutral
Location: 41,27
Actor42: tc05
Owner: Neutral
Location: 35,38
Actor43: tc01
Owner: Neutral
Location: 33,39
Actor44: tc02
Owner: Neutral
Location: 38,37
Actor46: t17
Owner: Neutral
Location: 38,31
Actor47: t15
Owner: Neutral
Location: 35,31
Actor48: t16
Owner: Neutral
Location: 38,29
Actor49: brik
Owner: USSR
Location: 1,1
Actor50: brik
Owner: USSR
Location: 1,1
Actor51: brik
Owner: USSR
Location: 1,2
Actor52: brik
Owner: USSR
Location: 1,3
Actor53: brik
Owner: USSR
Location: 1,4
Actor54: brik
Owner: USSR
Location: 1,5
Actor55: brik
Owner: USSR
Location: 1,6
Actor56: brik
Owner: USSR
Location: 1,7
Actor57: brik
Owner: USSR
Location: 1,8
Actor58: brik
Owner: USSR
Location: 1,10
Actor59: brik
Owner: USSR
Location: 1,9
Actor60: brik
Owner: USSR
Location: 1,11
Actor61: brik
Owner: USSR
Location: 1,12
Actor62: brik
Owner: USSR
Location: 1,13
Actor63: brik
Owner: USSR
Location: 1,14
Actor64: brik
Owner: USSR
Location: 1,15
Actor65: brik
Owner: USSR
Location: 1,16
Actor66: brik
Owner: USSR
Location: 1,17
Actor67: brik
Owner: USSR
Location: 1,18
Actor68: brik
Owner: USSR
Location: 1,19
Actor69: brik
Owner: USSR
Location: 2,19
Actor76: brik
Owner: USSR
Location: 8,19
Actor77: brik
Owner: USSR
Location: 9,19
Actor81: brik
Owner: USSR
Location: 24,19
Actor82: brik
Owner: USSR
Location: 23,19
Actor83: brik
Owner: USSR
Location: 24,20
Actor84: brik
Owner: USSR
Location: 23,20
Actor85: brik
Owner: USSR
Location: 22,20
Actor86: brik
Owner: USSR
Location: 21,20
Actor87: brik
Owner: USSR
Location: 20,20
Actor88: brik
Owner: USSR
Location: 19,20
Actor89: brik
Owner: USSR
Location: 18,20
Actor90: brik
Owner: USSR
Location: 17,20
Actor91: brik
Owner: USSR
Location: 17,19
Actor92: brik
Owner: USSR
Location: 18,19
Actor93: brik
Owner: USSR
Location: 27,10
Actor94: brik
Owner: USSR
Location: 27,9
Actor95: brik
Owner: USSR
Location: 26,10
Actor96: brik
Owner: USSR
Location: 26,9
Actor97: brik
Owner: USSR
Location: 26,8
Actor98: brik
Owner: USSR
Location: 27,8
Actor99: brik
Owner: USSR
Location: 26,7
Actor100: brik
Owner: USSR
Location: 27,7
Actor101: brik
Owner: USSR
Location: 26,1
Actor102: brik
Owner: USSR
Location: 26,2
Actor103: brik
Owner: USSR
Location: 27,1
Actor104: brik
Owner: USSR
Location: 27,2
Actor105: brik
Owner: USSR
Location: 25,1
Actor106: brik
Owner: USSR
Location: 24,1
Actor107: brik
Owner: USSR
Location: 23,1
Actor108: brik
Owner: USSR
Location: 23,1
Actor109: brik
Owner: USSR
Location: 22,1
Actor110: brik
Owner: USSR
Location: 21,1
Actor111: brik
Owner: USSR
Location: 20,1
Actor112: brik
Owner: USSR
Location: 20,1
Actor113: brik
Owner: USSR
Location: 19,1
Actor114: brik
Owner: USSR
Location: 18,1
Actor115: brik
Owner: USSR
Location: 17,1
Actor116: brik
Owner: USSR
Location: 17,1
Actor117: brik
Owner: USSR
Location: 16,1
Actor118: brik
Owner: USSR
Location: 15,1
Actor119: brik
Owner: USSR
Location: 14,1
Actor120: brik
Owner: USSR
Location: 13,1
Actor121: brik
Owner: USSR
Location: 12,1
Actor122: brik
Owner: USSR
Location: 11,1
Actor123: brik
Owner: USSR
Location: 10,1
Actor124: brik
Owner: USSR
Location: 9,1
Actor125: brik
Owner: USSR
Location: 8,1
Actor126: brik
Owner: USSR
Location: 7,1
Actor127: brik
Owner: USSR
Location: 7,1
Actor128: brik
Owner: USSR
Location: 6,1
Actor129: brik
Owner: USSR
Location: 6,1
Actor130: brik
Owner: USSR
Location: 4,1
Actor131: brik
Owner: USSR
Location: 5,1
Actor132: brik
Owner: USSR
Location: 3,1
Actor133: brik
Owner: USSR
Location: 2,1
Actor134: fenc
Owner: USSR
Location: 2,2
Health: 100
Actor135: fenc
Owner: USSR
Location: 3,2
Actor136: fenc
Owner: USSR
Location: 4,2
Actor137: fenc
Owner: USSR
Location: 5,2
Actor138: fenc
Owner: USSR
Location: 5,3
Actor139: fenc
Owner: USSR
Location: 2,3
Actor140: fenc
Owner: USSR
Location: 2,4
Actor141: fenc
Owner: USSR
Location: 2,4
Actor142: fenc
Owner: USSR
Location: 2,5
Actor143: fenc
Owner: USSR
Location: 3,5
Dog703: dog
Location: 4,3
SubCell: 3
Health: 100
Facing: 384
Owner: USSR
Dog702: dog
Location: 3,3
SubCell: 3
Owner: USSR
Health: 100
Facing: 384
Dog706: dog
Location: 4,4
SubCell: 3
Owner: USSR
Health: 100
Facing: 384
Dog705: dog
Location: 3,4
SubCell: 3
Owner: USSR
Health: 100
Facing: 384
Dog704: dog
Location: 4,4
SubCell: 1
Owner: USSR
Health: 100
Facing: 384
Dog701: dog
SubCell: 1
Location: 3,3
Health: 100
Facing: 384
Owner: USSR
Actor150: apwr
Owner: USSR
Location: 6,2
Actor151: apwr
Owner: USSR
Location: 9,2
Kennel: kenn
Owner: USSR
Location: 12,2
Actor153: apwr
Owner: USSR
Location: 22,2
Actor154: apwr
Owner: USSR
Location: 19,2
Actor155: stek
Owner: USSR
Location: 16,1
Actor156: apwr
Owner: USSR
Location: 6,6
Actor157: fact
Owner: USSR
Location: 6,9
Airfield: afld
Owner: USSR
Location: 2,10
Actor161: proc
Owner: USSR
Location: 23,7
Actor171: fenc
Owner: USSR
Location: 18,18
Actor172: fenc
Owner: USSR
Location: 17,18
Actor173: fenc
Owner: USSR
Location: 16,18
Actor174: fenc
Owner: USSR
Location: 16,18
Actor175: fenc
Owner: USSR
Location: 15,18
Actor176: fenc
Owner: USSR
Location: 15,17
Actor177: brik
Owner: USSR
Location: 1,20
Actor178: brik
Owner: USSR
Location: 2,20
Actor179: brik
Owner: USSR
Location: 3,20
Actor180: brik
Owner: USSR
Location: 4,20
Actor181: brik
Owner: USSR
Location: 5,20
Actor182: brik
Owner: USSR
Location: 6,20
Actor183: brik
Owner: USSR
Location: 6,20
Actor184: brik
Owner: USSR
Location: 7,20
Actor185: brik
Owner: USSR
Location: 8,20
Actor186: brik
Owner: USSR
Location: 9,20
Actor187: tsla
Owner: USSR
Location: 9,17
Actor188: ftur
Owner: USSR
TurretFacing: 384
Location: 10,17
Actor189: fenc
Owner: USSR
Location: 11,17
Actor190: fenc
Owner: USSR
Location: 8,18
Actor191: fenc
Owner: USSR
Location: 9,18
Actor192: fenc
Owner: USSR
Location: 10,18
Actor193: fenc
Owner: USSR
Location: 11,18
Actor194: apwr
Owner: USSR
Location: 7,14
Actor195: apwr
Owner: USSR
Location: 2,14
Actor196: ftur
Owner: USSR
TurretFacing: 384
Location: 16,17
Actor197: tsla
Owner: USSR
Location: 17,17
Actor199: fenc
Owner: USSR
Location: 24,18
Actor200: fenc
Owner: USSR
Location: 24,17
Actor201: fenc
Owner: USSR
Location: 24,16
Actor202: fenc
Owner: USSR
Location: 23,18
Actor203: fenc
Owner: USSR
Location: 22,18
Actor204: fenc
Owner: USSR
Location: 21,18
Actor205: fenc
Owner: USSR
Location: 21,17
Actor206: fenc
Owner: USSR
Location: 21,16
Dog709: dog
Location: 22,17
SubCell: 3
Owner: USSR
Health: 100
Facing: 384
Dog710: dog
Location: 23,17
SubCell: 3
Health: 100
Facing: 384
Owner: USSR
Dog708: dog
Location: 23,16
SubCell: 3
Owner: USSR
Health: 100
Facing: 384
Dog707: dog
Location: 22,16
SubCell: 3
Owner: USSR
Health: 100
Facing: 384
Actor211: tsla
Owner: USSR
Location: 37,15
Actor212: ftur
Owner: USSR
TurretFacing: 384
Location: 29,17
Actor213: ftur
Owner: USSR
TurretFacing: 384
Location: 29,13
Actor214: kenn
Owner: USSR
Location: 26,11
Actor215: dome
Owner: USSR
Location: 22,12
Barracks: barr
Owner: USSR
Location: 17,12
Health: 100
BarracksA: barr
Owner: USSR
Location: 20,7
Health: 100
Actor218: tsla
Owner: USSR
Location: 30,4
WarFactory: weap
Owner: USSR
Location: 12,9
Health: 100
USSRFC: fcom
Owner: USSR
Location: 13,4
SubPen: spen
Owner: USSR
Location: 33,10
Actor222: ss
Owner: USSR
Location: 57,13
Facing: 612
Actor223: ss
Owner: USSR
Location: 58,13
Facing: 632
Actor224: ss
Owner: USSR
Location: 60,13
Facing: 652
Actor225: ss
Owner: USSR
Location: 61,12
Facing: 668
Actor226: ss
Owner: USSR
Location: 60,11
Facing: 632
Actor227: harv
Owner: USSR
Location: 39,3
Facing: 0
TankGroup101: 3tnk
Owner: USSR
Location: 27,3
TurretFacing: 0
Health: 100
Facing: 753
TankGroup102: 3tnk
Owner: USSR
Location: 28,4
TurretFacing: 0
Health: 100
Facing: 761
Actor230: dog
Owner: USSR
SubCell: 3
Location: 26,3
Health: 100
Facing: 716
Actor231: dog
Owner: USSR
SubCell: 3
Location: 26,5
Health: 100
Facing: 769
Actor232: e1
Owner: USSR
SubCell: 3
Location: 25,4
Health: 100
Facing: 756
TurretFacing: 756
Actor233: v2rl
Owner: USSR
Location: 19,6
Health: 100
Facing: 531
Actor234: v2rl
Owner: USSR
Location: 17,8
Health: 100
Facing: 515
Actor235: 3tnk
Owner: USSR
Location: 18,7
TurretFacing: 0
Health: 100
Facing: 507
WGV2: v2rl
Owner: USSR
Location: 9,5
Health: 100
Facing: 504
Actor237: v2rl
Owner: USSR
Location: 11,7
Health: 100
Facing: 520
Actor238: 3tnk
Owner: USSR
Location: 10,6
Health: 100
Facing: 512
TurretFacing: 0
MM2: 4tnk
Owner: USSR
Location: 13,13
TurretFacing: 0
Health: 100
Facing: 528
MM1: 4tnk
Owner: USSR
Location: 12,15
TurretFacing: 0
Health: 100
Facing: 508
MM3: 4tnk
Owner: USSR
Location: 14,15
TurretFacing: 0
Health: 100
Facing: 528
WGTank01: 3tnk
Owner: USSR
Location: 5,12
TurretFacing: 0
Health: 100
Facing: 604
WGTank02: 3tnk
Owner: USSR
Location: 6,16
TurretFacing: 0
Health: 100
Facing: 636
Actor244: dog
Owner: USSR
SubCell: 3
Location: 12,22
Health: 100
Facing: 539
Actor245: dog
Owner: USSR
SubCell: 3
Location: 14,22
Health: 100
Facing: 507
Actor246: e1
Owner: USSR
SubCell: 3
Location: 13,21
Health: 100
Facing: 384
TurretFacing: 384
Actor247: 3tnk
Owner: USSR
Location: 18,16
Health: 100
Facing: 384
TurretFacing: 0
Actor248: 3tnk
Owner: USSR
Location: 15,2
TurretFacing: 0
Health: 100
Facing: 523
Actor249: e1
Owner: Greece
SubCell: 3
Location: 17,60
Health: 100
Facing: 634
TurretFacing: 634
Actor250: e1
Owner: Greece
SubCell: 3
Location: 23,62
Health: 100
TurretFacing: 29
Facing: 29
AlliedMCVEntry: waypoint
Owner: Neutral
Location: 19,70
Unload1: waypoint
Owner: Neutral
Location: 19,63
DefaultCameraPosition: waypoint
Owner: Neutral
Location: 21,60
HeliLandZone: waypoint
Owner: Neutral
Location: 21,62
KosyginSpawnPoint: waypoint
Owner: Neutral
Location: 14,6
KosyginExtractPoint: waypoint
Owner: Neutral
Location: 25,57
HeliWP01: waypoint
Owner: Neutral
Location: 58,70
HeliWP02: waypoint
Owner: Neutral
Location: 58,66
HeliWP03: waypoint
Owner: Neutral
Location: 16,55
LowerBaseWP: waypoint
Owner: Neutral
Location: 13,25
USSRUnload1: waypoint
Owner: Neutral
Location: 53,53
USSRRFEntry: waypoint
Owner: Neutral
Location: 80,1
RevealLowerBase: waypoint
Owner: Neutral
Location: 13,19
Harbor: waypoint
Owner: Neutral
Location: 22,43
USSRUnload2: waypoint
Owner: Neutral
Location: 55,63
WP92: waypoint
Owner: Neutral
Location: 20,31
WP91: waypoint
Owner: Neutral
Location: 22,27
WP90: waypoint
Owner: Neutral
Location: 31,25
Dog6: dog
Owner: USSR
SubCell: 3
Location: 22,31
Health: 100
Facing: 384
Dog5: dog
Owner: USSR
SubCell: 3
Location: 10,25
Health: 100
Facing: 384
WP93: waypoint
Owner: Neutral
Location: 9,27
WP94: waypoint
Owner: Neutral
Location: 1,28
WP88: waypoint
Owner: Neutral
Location: 13,23
WP81: waypoint
Owner: Neutral
Location: 27,4
WP82: waypoint
Owner: Neutral
Location: 37,4
WP83: waypoint
Owner: Neutral
Location: 46,8
WP84: waypoint
Owner: Neutral
Location: 52,11
WP85: waypoint
Owner: Neutral
Location: 60,2
WP89: waypoint
Owner: Neutral
Location: 30,15
WP79: waypoint
Owner: Neutral
Location: 13,18
WP78: waypoint
Owner: Neutral
Location: 12,18
WP80: waypoint
Owner: Neutral
Location: 14,18
WPHNTG: waypoint
Owner: Neutral
Location: 15,9
WP4: waypoint
Owner: Neutral
Location: 19,13
WP76: waypoint
Owner: Neutral
Location: 56,7
WP72: waypoint
Owner: Neutral
Location: 5,18
WP18: waypoint
Owner: Neutral
Location: 42,9
WP17: waypoint
Owner: Neutral
Location: 47,12
UpperBaseWP: waypoint
Owner: Neutral
Location: 13,8
Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml
Weapons: weapons.yaml

View File

@@ -0,0 +1,148 @@
Player:
PlayerResources:
DefaultCash: 10000
World:
LuaScript:
Scripts: campaign-global.lua, allies09a.lua, allies09a-AI.lua
MissionData:
Briefing: One of Stalin's top atomic strategists, Vladimir Kosygin, wishes to defect. His knowledge of Stalin's atomic strategies is invaluable to us. We will extract him from the Riga compound where he is stationed.\n\nUse a spy to infiltrate the Soviet command center and contact Kosygin. Once he is out of the building, guide him back to your base any way you can.
StartVideo:
WinVideo:
LossVideo:
ScriptLobbyDropdown@difficulty:
ID: difficulty
Label: Difficulty
Values:
easy: Easy
normal: Normal
hard: Hard
Default: normal
LST.Reinforcement:
Inherits: LST
RejectsOrders:
-Buildable:
-Selectable:
RenderSprites:
Image: lst
Interactable:
TRAN.Extraction:
Inherits: TRAN
RejectsOrders:
-Selectable:
RenderSprites:
Image: tran
Interactable:
powerproxy.paratroopers:
ParatroopersPower:
DropItems: E1,E1,E1,E2,E2
MCV:
Buildable:
Prerequisites: ~disabled
TRUK:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
3TNK:
Buildable:
Prerequisites: ~vehicles.soviet
V2RL:
Buildable:
Prerequisites: ~vehicles.soviet
4TNK:
Buildable:
Prerequisites: ~vehicles.soviet
QTNK:
Buildable:
Prerequisites: ~disabled
AFLD:
Buildable:
Prerequisites: ~disabled
HPAD:
Buildable:
Prerequisites: ~disabled
ATEK:
Buildable:
Prerequisites: ~disabled
STEK:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
IRON:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: ~disabled
BRIK:
Buildable:
Prerequisites: ~disabled
MECH:
Buildable:
Prerequisites: ~disabled
THF:
Buildable:
Prerequisites: ~disabled
E7:
Buildable:
Prerequisites: ~disabled
E7.noautotarget:
Buildable:
Prerequisites: ~disabled
MIG:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled
MSUB:
Buildable:
Prerequisites: ~disabled
FCOM:
Targetable:
TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate
GNRL:
Targetable:
TargetTypes: Kosygin
AutoTarget:
InitialStance: HoldFire
InitialStanceAI: HoldFire
DOG:
AutoTargetPriority@DEFAULT:
ValidTargets: Infantry, Kosygin

View File

@@ -0,0 +1,4 @@
DogJaw:
ValidTargets: Infantry, Kosygin
Warhead@1Dam: TargetDamage
ValidTargets: Infantry, Kosygin

View File

@@ -32,7 +32,7 @@ MISS:
Name: Soviet Air Force HQ
Capturable:
Types: building
ValidStances: Enemy
ValidRelationships: Enemy
CaptureManager:
TENT:

View File

@@ -137,7 +137,7 @@ PBOX:
RevealsShroud@friendly:
Range: 6c0
RequiresCondition: friendly
ValidStances: Ally, Enemy
ValidRelationships: Ally, Enemy
ExternalCondition@friendly:
Condition: friendly
Turreted:

View File

@@ -48,7 +48,7 @@ DTRK:
MaxWeight: 1
RevealsShroud:
Range: 4c0
ValidStances: Neutral
ValidRelationships: Neutral
RequiresCondition: mission
ExternalCondition@mission:
Condition: mission

View File

@@ -0,0 +1,152 @@
--[[
Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version. For more
information, see COPYING.
]]
AttackGroup = { }
AttackGroupSize = 10
BGAttackGroup = { }
BGAttackGroupSize = 8
SovietInfantry = { "e1", "e2", "e4" }
SovietVehicles = { "3tnk", "3tnk", "v2rl" }
SovietAircraftType = { "mig", "yak" }
Planes = { }
ProductionInterval =
{
easy = DateTime.Seconds(30),
normal = DateTime.Seconds(20),
hard = DateTime.Seconds(10)
}
SendBGAttackGroup = function()
if #BGAttackGroup < BGAttackGroupSize then
return
end
Utils.Do(BGAttackGroup, function(unit)
if not unit.IsDead then
IdleHunt(unit)
end
end)
BGAttackGroup = { }
end
ProduceBadGuyInfantry = function()
if BadGuyRax.IsDead or BadGuyRax.Owner ~= BadGuy then
return
end
BadGuy.Build({ Utils.Random(SovietInfantry) }, function(units)
table.insert(BGAttackGroup, units[1])
SendBGAttackGroup()
Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceBadGuyInfantry)
end)
end
SendAttackGroup = function()
if #AttackGroup < AttackGroupSize then
return
end
Utils.Do(AttackGroup, function(unit)
if not unit.IsDead then
IdleHunt(unit)
end
end)
AttackGroup = { }
end
ProduceUSSRInfantry = function()
if (USSRRax1.IsDead or USSRRax1.Owner ~= USSR) and (USSRRax2.IsDead or USSRRax2.Owner ~= USSR) then
return
end
USSR.Build({ Utils.Random(SovietInfantry) }, function(units)
table.insert(AttackGroup, units[1])
SendAttackGroup()
Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceUSSRInfantry)
end)
end
ProduceVehicles = function()
if USSRWarFactory.IsDead or USSRWarFactory.Owner ~= USSR then
return
end
USSR.Build({ Utils.Random(SovietVehicles) }, function(units)
table.insert(AttackGroup, units[1])
SendAttackGroup()
Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceVehicles)
end)
end
GroundAttackUnits = { {"4tnk", "3tnk", "e2", "e2", "e2", "e2" }, { "3tnk", "3tnk", "v2rl", "e4", "e4", "e4" }, {"ttnk", "ttnk", "ttnk", "shok", "shok", "shok" } }
GroundAttackPaths =
{
{ SovietGroundEntry1.Location },
{ SovietGroundEntry2.Location },
{ SovietGroundEntry3.Location }
}
GroundWavesDelays =
{
easy = 4,
normal = 3,
hard = 2
}
GroundWaves = function()
if not ForwardCommand.IsDead then
local path = Utils.Random(GroundAttackPaths)
local units = Reinforcements.Reinforce(BadGuy, Utils.Random(GroundAttackUnits), path)
Utils.Do(units, IdleHunt)
Trigger.AfterDelay(DateTime.Minutes(GroundWavesDelays), GroundWaves)
end
end
ProduceAircraft = function()
if Airfield.IsDead or Airfield.Owner ~= USSR then
return
end
USSR.Build({ Utils.Random(SovietAircraftType) }, function(units)
local plane = units[1]
Planes[#Planes + 1] = plane
Trigger.OnKilled(plane, ProduceAircraft)
local alive = Utils.Where(Planes, function(y) return not y.IsDead end)
if #alive < 2 then
Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Map.LobbyOption("difficulty")] / 2), ProduceAircraft)
end
InitializeAttackAircraft(plane, Greece)
end)
end
ActivateAI = function()
local difficulty = Map.LobbyOption("difficulty")
GroundWavesDelays = GroundWavesDelays[difficulty]
local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == USSR and self.HasProperty("StartBuildingRepairs") end)
Utils.Do(buildings, function(actor)
Trigger.OnDamaged(actor, function(building)
if building.Owner == USSR and building.Health < building.MaxHealth * 3/4 then
building.StartBuildingRepairs()
end
end)
end)
ProduceBadGuyInfantry()
ProduceUSSRInfantry()
ProduceVehicles()
Trigger.AfterDelay(DateTime.Minutes(GroundWavesDelays), GroundWaves)
Trigger.AfterDelay(DateTime.Minutes(5), ProduceAircraft)
end

View File

@@ -0,0 +1,149 @@
--[[
Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version. For more
information, see COPYING.
]]
StartUnits = { APC, StartSpy, Rifle1, Rifle2, Rifle3, Rifle4, Rocket1, Rocket2, Rocket3, Rocket4, Rocket5 }
SarinPlants = { SarinLab1, SarinLab2, SarinLab3, SarinLab4, SarinLab5 }
MammothStart = { CPos.New(37, 46), CPos.New(37, 47), CPos.New(37, 48), CPos.New(37, 49), CPos.New(37,50) }
NorthPatrol = { NorthPatrol1.Location, NorthPatrol2.Location, NorthPatrol3.Location, NorthPatrol4.Location, NorthPatrol5.Location }
BarrerlInvestigators = { Alert1, Alert2, Alert3, Alert4, Alert5 }
RaxTeam = { "e1", "e2", "e2", "e4", "e4", "shok" }
SouthPatrol = { SouthPatrol1.Location, SouthPatrol2.Location, SouthPatrol3.Location }
MCVReinforcements =
{
easy = { "1tnk", "1tnk", "2tnk", "2tnk", "2tnk", "2tnk", "arty", "mcv" },
normal = { "1tnk", "1tnk", "2tnk", "2tnk", "mcv" },
hard = { "1tnk", "1tnk", "mcv" }
}
IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end
SetupTriggers = function()
Trigger.OnEnteredFootprint(MammothStart, function(actor, mammothcam)
if actor.Owner == Greece then
Trigger.RemoveFootprintTrigger(mammothcam)
NorthMammoth.Patrol(NorthPatrol, true, 20)
local mammothCamera = Actor.Create("camera", true, { Owner = Greece, Location = NorthPatrol1.Location })
Trigger.AfterDelay(DateTime.Seconds(10), function()
mammothCamera.Destroy()
end)
end
end)
Trigger.OnEnteredProximityTrigger(NorthPatrol3.CenterPosition, WDist.FromCells(8), function(actor, trigger1)
if actor.Owner == Greece then
Trigger.RemoveProximityTrigger(trigger1)
local baseCamera = Actor.Create("camera", true, { Owner = Greece, Location = BaseCam.Location })
if Map.LobbyOption("difficulty") == "hard" then
Reinforcements.Reinforce(BadGuy, RaxTeam, { BadGuyRaxSpawn.Location, BaseCam.Location }, 0)
end
Trigger.AfterDelay(DateTime.Seconds(10), function()
baseCamera.Destroy()
end)
end
end)
Trigger.OnAllRemovedFromWorld(StartUnits, function()
if not MCVArrived then
USSR.MarkCompletedObjective(SovietObj)
end
end)
Trigger.OnKilled(VeryImportantBarrel, function()
Utils.Do(BarrerlInvestigators, function(actor)
if not actor.IsDead then
actor.AttackMove(AlertGo.Location)
end
end)
end)
Trigger.OnAnyKilled(SarinPlants, function()
Greece.MarkFailedObjective(CaptureSarin)
end)
Trigger.OnAllKilledOrCaptured(SarinPlants, function()
Greece.MarkCompletedObjective(CaptureSarin)
end)
end
MCVArrived = false
MCVArrivedTick = false
PowerDownTeslas = function()
if not MCVArrived then
CaptureSarin = Greece.AddObjective("Capture all Sarin processing plants intact.")
KillBase = Greece.AddObjective("Destroy the enemy compound.")
Greece.MarkCompletedObjective(TakeOutPower)
Media.PlaySpeechNotification(Greece, "ReinforcementsArrived")
Reinforcements.Reinforce(Greece, MCVReinforcements[Map.LobbyOption("difficulty")], { AlliesSpawn.Location, AlliesMove.Location })
local baseFlare = Actor.Create("flare", true, { Owner = Greece, Location = AlliedBase.Location })
Actor.Create("proc", true, { Owner = USSR, Location = Proc1.Location })
Actor.Create("proc", true, { Owner = USSR, Location = Proc2.Location })
SouthMammoth.Patrol(SouthPatrol, true, 20)
MCVArrived = true
Trigger.AfterDelay(DateTime.Seconds(1), function()
MCVArrivedTick = true
end)
Trigger.AfterDelay(DateTime.Seconds(60), function()
local attackers = Reinforcements.Reinforce(USSR, { "e1", "e1", "e1", "e2", "e4" }, { SovietGroundEntry3.Location }, 5)
Utils.Do(attackers, IdleHunt)
end)
Trigger.AfterDelay(DateTime.Seconds(100), function()
baseFlare.Destroy()
ActivateAI()
end)
end
end
Tick = function()
USSR.Cash = 10000
BadGuy.Cash = 10000
if BadGuy.PowerState ~= "Normal" then
PowerDownTeslas()
end
if Greece.HasNoRequiredUnits() and MCVArrivedTick then
USSR.MarkCompletedObjective(SovietObj)
end
if USSR.HasNoRequiredUnits() then
Greece.MarkCompletedObjective(KillBase)
end
end
WorldLoaded = function()
Greece = Player.GetPlayer("Greece")
USSR = Player.GetPlayer("USSR")
BadGuy = Player.GetPlayer("BadGuy")
SovietObj = USSR.AddObjective("Defeat the Allies.")
TakeOutPower = Greece.AddObjective("Bring down the power of the base to the east.")
Trigger.OnObjectiveAdded(Greece, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
end)
Trigger.OnObjectiveCompleted(Greece, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
end)
Trigger.OnObjectiveFailed(Greece, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
end)
Trigger.OnPlayerLost(Greece, function()
Media.PlaySpeechNotification(Greece, "Lose")
end)
Trigger.OnPlayerWon(Greece, function()
Media.PlaySpeechNotification(Greece, "Win")
end)
StartSpy.DisguiseAsType("e1", BadGuy)
Camera.Position = DefaultCameraPosition.CenterPosition
SetupTriggers()
end

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
World:
LuaScript:
Scripts: campaign-global.lua, controlledburn.lua, controlledburn-AI.lua
MissionData:
WinVideo: apcescpe.vqa
LossVideo: tesla.vqa
Briefing: We have infiltrated the Soviet's Sarin facility. However, the main entrance is guarded by a wall of Tesla coils. We can't move a large force in until they are taken down.\n\nInfiltrate the power grid to the east or destroy its power plants. Once done, reinforcements will arrive.\n\nDestroy the Soviet compound, but capture all of the Sarin processor buildings intact -- we can't have a chemical spill.
ScriptLobbyDropdown@difficulty:
ID: difficulty
Label: Difficulty
Values:
easy: Easy
normal: Normal
hard: Hard
Default: normal
Player:
PlayerResources:
DefaultCash: 7500
APC:
Buildable:
Prerequisites: ~vehicles.allies
TRUK:
Buildable:
Prerequisites: ~disabled
MGG:
Buildable:
Prerequisites: ~disabled
FTRK:
Buildable:
Prerequisites: ~disabled
DTRK:
Buildable:
Prerequisites: ~disabled
CTNK:
Buildable:
Prerequisites: ~disabled
STNK:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
ATEK:
Buildable:
Prerequisites: ~disabled
BIO:
Tooltip:
Name: Sarin Processing Plant
E7:
Buildable:
Prerequisites: ~disabled
E3:
Buildable:
Prerequisites: ~tent
MH60:
Buildable:
Prerequisites: ~disabled
TRAN:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~hpad

View File

@@ -25,7 +25,7 @@ JEEP:
Explodes:
ProximityExternalCondition@JAMMER:
Range: 10c0
ValidStances: Enemy, Neutral
ValidRelationships: Enemy, Neutral
Condition: jammed
YAK:

View File

@@ -10,6 +10,7 @@ Allied Campaign:
allies-07
allies-08a
allies-08b
allies-09a
Soviet Campaign:
soviet-01
soviet-02a
@@ -27,6 +28,7 @@ Soviet Campaign:
Counterstrike:
sarin-gas-1-crackdown
sarin-gas-2-down-under
sarin-gas-3-controlled-burn
fall-of-greece-1-personal-war
siberian-conflict-1-fresh-tracks
soviet-soldier-volkov-n-chitzkoi

Some files were not shown because too many files have changed in this diff Show More