Merge pull request #11702 from Mailaender/infiltration-mission

Added Scott's Allies04 co-op multiplayer mission as "Infiltration"
This commit is contained in:
Oliver Brakmann
2016-09-04 18:41:09 +02:00
committed by GitHub
9 changed files with 2474 additions and 2 deletions

View File

@@ -252,6 +252,7 @@
<Compile Include="Scripting\Properties\ProductionProperties.cs" /> <Compile Include="Scripting\Properties\ProductionProperties.cs" />
<Compile Include="Scripting\Properties\RepairableBuildingProperties.cs" /> <Compile Include="Scripting\Properties\RepairableBuildingProperties.cs" />
<Compile Include="Scripting\Properties\ResourceProperties.cs" /> <Compile Include="Scripting\Properties\ResourceProperties.cs" />
<Compile Include="Scripting\Properties\SellableProperties.cs" />
<Compile Include="Scripting\Properties\TransformProperties.cs" /> <Compile Include="Scripting\Properties\TransformProperties.cs" />
<Compile Include="Scripting\Properties\TransportProperties.cs" /> <Compile Include="Scripting\Properties\TransportProperties.cs" />
<Compile Include="Scripting\Properties\UpgradeProperties.cs" /> <Compile Include="Scripting\Properties\UpgradeProperties.cs" />

View File

@@ -0,0 +1,31 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 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 OpenRA.Mods.Common.Traits;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Scripting
{
[ScriptPropertyGroup("General")]
public class SellableProperties : ScriptActorProperties, Requires<SellableInfo>
{
public SellableProperties(ScriptContext context, Actor self)
: base(context, self) { }
[Desc("Start selling the actor.")]
public void Sell()
{
// PERF: No trait lookup cache in the constructor to avoid doing it for all buildings except just the ones getting sold.
Self.Trait<Sellable>().Sell(Self);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common.Scripting
OnIdle, OnDamaged, OnKilled, OnProduction, OnOtherProduction, OnPlayerWon, OnPlayerLost, OnIdle, OnDamaged, OnKilled, OnProduction, OnOtherProduction, OnPlayerWon, OnPlayerLost,
OnObjectiveAdded, OnObjectiveCompleted, OnObjectiveFailed, OnCapture, OnInfiltrated, OnObjectiveAdded, OnObjectiveCompleted, OnObjectiveFailed, OnCapture, OnInfiltrated,
OnAddedToWorld, OnRemovedFromWorld, OnDiscovered, OnPlayerDiscovered, OnAddedToWorld, OnRemovedFromWorld, OnDiscovered, OnPlayerDiscovered,
OnPassengerEntered, OnPassengerExited OnPassengerEntered, OnPassengerExited, OnSelling, OnSold
} }
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")] [Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Scripting
public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyOtherProduction, public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyOtherProduction,
INotifyObjectivesUpdated, INotifyCapture, INotifyInfiltrated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyDiscovered, INotifyActorDisposing, INotifyObjectivesUpdated, INotifyCapture, INotifyInfiltrated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyDiscovered, INotifyActorDisposing,
INotifyPassengerEntered, INotifyPassengerExited INotifyPassengerEntered, INotifyPassengerExited, INotifySold
{ {
readonly World world; readonly World world;
readonly Actor self; readonly Actor self;
@@ -364,6 +364,46 @@ namespace OpenRA.Mods.Common.Scripting
OnRemovedInternal(self); OnRemovedInternal(self);
} }
void INotifySold.Selling(Actor self)
{
if (world.Disposing)
return;
// Run Lua callbacks
foreach (var f in Triggerables(Trigger.OnSelling))
{
try
{
f.Function.Call(f.Self).Dispose();
}
catch (Exception ex)
{
f.Context.FatalError(ex.Message);
return;
}
}
}
void INotifySold.Sold(Actor self)
{
if (world.Disposing)
return;
// Run Lua callbacks
foreach (var f in Triggerables(Trigger.OnSold))
{
try
{
f.Function.Call(f.Self).Dispose();
}
catch (Exception ex)
{
f.Context.FatalError(ex.Message);
return;
}
}
}
public void UnitProducedByOther(Actor self, Actor producee, Actor produced) public void UnitProducedByOther(Actor self, Actor producee, Actor produced)
{ {
if (world.Disposing) if (world.Disposing)

View File

@@ -73,6 +73,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Red Alert Lua scripts", "Re
mods\ra\maps\fort-lonestar\fort-lonestar-AI.lua = mods\ra\maps\fort-lonestar\fort-lonestar-AI.lua mods\ra\maps\fort-lonestar\fort-lonestar-AI.lua = mods\ra\maps\fort-lonestar\fort-lonestar-AI.lua
mods\ra\maps\fort-lonestar\fort-lonestar.lua = mods\ra\maps\fort-lonestar\fort-lonestar.lua mods\ra\maps\fort-lonestar\fort-lonestar.lua = mods\ra\maps\fort-lonestar\fort-lonestar.lua
mods\ra\maps\intervention\intervention.lua = mods\ra\maps\intervention\intervention.lua mods\ra\maps\intervention\intervention.lua = mods\ra\maps\intervention\intervention.lua
mods\ra\maps\infiltration\infiltration.lua = mods\ra\maps\infiltration\infiltration.lua
mods\ra\maps\monster-tank-madness\monster-tank-madness.lua = mods\ra\maps\monster-tank-madness\monster-tank-madness.lua mods\ra\maps\monster-tank-madness\monster-tank-madness.lua = mods\ra\maps\monster-tank-madness\monster-tank-madness.lua
mods\ra\maps\evacuation\evacuation.lua = mods\ra\maps\evacuation\evacuation.lua mods\ra\maps\evacuation\evacuation.lua = mods\ra\maps\evacuation\evacuation.lua
mods\ra\maps\exodus\exodus.lua = mods\ra\maps\exodus\exodus.lua mods\ra\maps\exodus\exodus.lua = mods\ra\maps\exodus\exodus.lua

View File

@@ -0,0 +1,383 @@
Difficulty = Map.LobbyOption("difficulty")
if Difficulty == "hard" then
TimerTicks = DateTime.Minutes(25)
elseif Difficulty == "normal" then
TimerTicks = DateTime.Minutes(28)
else
TimerTicks = DateTime.Minutes(31)
end
Announcements =
{
{ speech = "TwentyMinutesRemaining", delay = DateTime.Minutes(20) },
{ speech = "TenMinutesRemaining", delay = DateTime.Minutes(10) },
{ speech = "WarningFiveMinutesRemaining", delay = DateTime.Minutes(5) },
{ speech = "WarningFourMinutesRemaining", delay = DateTime.Minutes(4) },
{ speech = "WarningThreeMinutesRemaining", delay = DateTime.Minutes(3) },
{ speech = "WarningTwoMinutesRemaining", delay = DateTime.Minutes(2) },
{ speech = "WarningOneMinuteRemaining", delay = DateTime.Minutes(1) }
}
TownAttackers = { TownAttacker1, TownAttacker2, TownAttacker3, TownAttacker4, TownAttacker5, TownAttacker6, TownAttacker7 }
PatrolPoints1 = { PatrolPoint11.Location, PatrolPoint12.Location, PatrolPoint13.Location, PatrolPoint14.Location, PatrolPoint15.Location }
PatrolPoints2 = { PatrolPoint21.Location, PatrolPoint22.Location, PatrolPoint23.Location, PatrolPoint24.Location, PatrolPoint25.Location }
PatrolPoints3 = { PatrolPoint31.Location, PatrolPoint32.Location, PatrolPoint33.Location, PatrolPoint34.Location }
PatrolPoints4 = { PatrolPoint41.Location, PatrolPoint42.Location, PatrolPoint43.Location, PatrolPoint44.Location, PatrolPoint45.Location }
Patrol1 = { "e1", "e1", "e1", "e1", "e1" }
Patrol2 = { "e1", "dog.patrol", "dog.patrol" }
Patrol3 = { "e1", "e1", "dog.patrol" }
TransportType = "lst.unselectable.unloadonly"
SecureLabFailed = function()
Utils.Do(humans, function(player)
if player then
player.MarkFailedObjective(secureLab)
end
end)
end
timerStarted = false
StartTimer = function()
Utils.Do(humans, function(player)
if player.IsLocalPlayer then
TimerColor = player.Color
end
end)
CountDownTimerAnnouncements()
ticked = TimerTicks
timerStarted = true
Trigger.AfterDelay(DateTime.Seconds(3), function()
Utils.Do(humans, function(player)
Media.PlaySpeechNotification(player, "TimerStarted")
end)
end)
end
CountDownTimerAnnouncements = function()
for i = #Announcements, 1, -1 do
local delay = TimerTicks - Announcements[i].delay
Trigger.AfterDelay(delay, function()
if not labSecured then
Utils.Do(humans, function(player)
Media.PlaySpeechNotification(player, Announcements[i].speech)
end)
end
end)
end
end
reinforcementsHaveArrived = false
LabInfiltrated = function()
Utils.Do(humans, function(player)
if player then
secureLab = player.AddPrimaryObjective("Eliminate all units guarding the lab.")
destroyBase = player.AddPrimaryObjective("Destroy the soviet installation.")
player.MarkCompletedObjective(infiltrateLab)
Trigger.ClearAll(Lab)
Trigger.AfterDelay(0, function()
Trigger.OnKilled(Lab, SecureLabFailed)
end)
end
end)
Camera.Position = ReinforcementsUnloadPoint.CenterPosition
local entryPath = { ReinforcementsEntryPoint.Location, ReinforcementsUnloadPoint.Location }
local exit = { ReinforcementsEntryPoint.Location }
mcvActors = { "mcv" }
if player2 then
mcvActors = { "mcv", "mcv" }
end
local reinforcements = Reinforcements.ReinforceWithTransport(allies, TransportType, mcvActors, entryPath, exit)
local mcvs = reinforcements[2]
Trigger.OnAddedToWorld(mcvs[1], function(mcvUnloaded)
-- Don't call this twice (because of the owner change)
if mcvUnloaded.Owner == player1 then
return
end
mcvUnloaded.Owner = player1
if not player2 then
player1.Cash = 5000
end
Media.PlaySpeechNotification(player, "AlliedReinforcementsSouth")
StartTimer()
HijackTruck.Destroy()
reinforcementsHaveArrived = true
end)
if player2 then
Trigger.OnAddedToWorld(mcvs[2], function(mcvUnloaded)
-- Don't call this twice (because of the owner change)
if mcvUnloaded.Owner == player2 then
return
end
mcvUnloaded.Owner = player2
player1.Cash = 2500
player2.Cash = 2500
end)
end
Utils.Do(humans, function(player)
for i = 0, 2 do
Trigger.AfterDelay(DateTime.Seconds(i), function()
Media.PlaySoundNotification(player, "AlertBuzzer")
end)
end
end)
local attackPoint = BridgeAttackPoint.CenterPosition
local radius = WDist.FromCells(5)
local bridge = Map.ActorsInCircle(attackPoint, radius, function(actor)
return actor.Type == "br3"
end)[1]
BridgeTank.Attack(bridge, true, true)
end
InfiltrateLabFailed = function()
Utils.Do(humans, function(player)
if player then
player.MarkFailedObjective(infiltrateLab)
end
end)
end
ChangeOwnerOnAddedToWorld = function(actor, newOwner)
Trigger.OnAddedToWorld(actor, function(unloadedActor)
unloadedActor.Owner = newOwner
Trigger.Clear(unloadedActor, "OnAddedToWorld")
end)
end
InsertSpies = function()
Utils.Do(humans, function(player)
if player then
infiltrateLab = player.AddPrimaryObjective("Get our spy into the laboratory undetected.")
end
end)
Trigger.OnKilled(Lab, function()
if not player1.IsObjectiveCompleted(infiltrateLab) then
InfiltrateLabFailed()
end
end)
-- The delay isn't purely cosmetic, but also prevents a System.InvalidOperationException
-- "Collection was modified after the enumerator was instantiated." in tick_activities
local infiltrationCount = 0
Trigger.OnInfiltrated(Lab, function()
infiltrationCount = infiltrationCount + 1
if (player2 and infiltrationCount == 2) or not player2 then
Trigger.AfterDelay(DateTime.Seconds(3), LabInfiltrated)
end
end)
spyActors = { "spy.strong" }
if player2 then
spyActors = { "spy.strong", "spy.strong" }
end
local entryPath = { SpyReinforcementsEntryPoint.Location, SpyReinforcementsUnloadPoint.Location }
local exit = { SpyReinforcementsExitPoint.Location }
local reinforcements = Reinforcements.ReinforceWithTransport(allies, TransportType, spyActors, entryPath, exit)
local transport = reinforcements[1]
Camera.Position = transport.CenterPosition
spies = reinforcements[2]
Trigger.OnAnyKilled(spies, InfiltrateLabFailed)
ChangeOwnerOnAddedToWorld(spies[1], player1)
if player2 then
ChangeOwnerOnAddedToWorld(spies[2], player2)
end
end
IdleHunt = function(unit)
Trigger.OnIdle(unit, unit.Hunt)
end
StopHunt = function(unit)
if not unit.IsDead then
Trigger.Clear(unit, "OnIdle")
end
end
AttackTown = function()
Utils.Do(TownAttackers, IdleHunt)
Trigger.OnRemovedFromWorld(Hospital, function()
Utils.Do(TownAttackers, StopHunt)
end)
end
CapOre = function(player)
if player.Resources > player.ResourceCapacity * 0.9 then
player.Resources = player.ResourceCapacity * 0.8
end
end
NewPatrol = function(actorType, start, waypoints)
local guard = Actor.Create(actorType, true, { Owner = soviets, Location = start })
guard.Patrol(waypoints, true, Utils.RandomInteger(50, 75))
end
SetupPatrols = function()
Utils.Do(Patrol1, function(patrol1) NewPatrol(patrol1, PatrolPoints1[1], PatrolPoints1) end)
Utils.Do(Patrol2, function(patrol2) NewPatrol(patrol2, PatrolPoints1[3], PatrolPoints1) end)
Utils.Do(Patrol2, function(patrol3) NewPatrol(patrol3, PatrolPoints3[1], PatrolPoints3) end)
Utils.Do(Patrol2, function(patrol4) NewPatrol(patrol4, PatrolPoints4[1], PatrolPoints4) end)
if Difficulty == "hard" then
Utils.Do(Patrol3, function(patrol5) NewPatrol(patrol5, PatrolPoints2[1], PatrolPoints2) end)
end
local checkpoint = { BaseGuardTruckPos.Location }
Trigger.OnEnteredFootprint(checkpoint, function(a, id)
Trigger.RemoveFootprintTrigger(id)
if not BaseGuard.IsDead then
BaseGuard.ScriptedMove(BaseGuardMovePos.Location)
end
end)
end
ticked = 0
SecureLabTimer = function()
if not timerStarted or labSecured then
return
end
if ticked > 0 then
UserInterface.SetMissionText("Secure lab in: " .. Utils.FormatTime(ticked), TimerColor)
ticked = ticked - 1
elseif ticked <= 0 then
TimerColor = soviets.Color
UserInterface.SetMissionText("The Soviet research laboratory was not secured in time.", TimerColor)
SecureLabFailed()
end
end
SovietBaseMaintenanceSetup = function()
local sovietbuildings = Utils.Where(Map.NamedActors, function(a)
return a.Owner == soviets
and a.HasProperty("StartBuildingRepairs") and a.HasProperty("Sell")
end)
-- This includes killed, captured (actor is temporarily removed) and sold.
Trigger.OnAllRemovedFromWorld(sovietbuildings, function()
Utils.Do(humans, function(player)
player.MarkCompletedObjective(destroyBase)
end)
end)
Utils.Do(sovietbuildings, function(sovietbuilding)
Trigger.OnDamaged(sovietbuilding, function(building)
if building.Owner ~= soviets then
return
end
if building.Health < building.MaxHealth * 3/4 then
building.StartBuildingRepairs()
end
if building.Health < building.MaxHealth * 1/4 then
building.Sell()
end
end)
end)
end
CheckPlayerDefeat = function()
if not reinforcementsHaveArrived then
return
end
Utils.Do(humans, function(player)
if player.HasNoRequiredUnits() then
player.MarkFailedObjective(destroyBase)
end
end)
end
labSecured = false
CheckLabSecured = function()
if not reinforcementsHaveArrived or labSecured then
return
end
if player1.HasNoRequiredUnits() or (player2 and player2.HasNoRequiredUnits()) then
Utils.Do(humans, function(player)
player.MarkFailedObjective(secureLab)
end)
end
local radius = WDist.FromCells(10)
local labGuards = Utils.Where(Map.ActorsInCircle(LabWaypoint.CenterPosition, radius), function(a)
return a.Owner == soviets and a.HasProperty("Move")
end)
if #labGuards < 1 then
labSecured = true
Utils.Do(humans, function(player)
player.MarkCompletedObjective(secureLab)
end)
UserInterface.SetMissionText("")
end
end
Tick = function()
CapOre(soviets)
SecureLabTimer()
CheckLabSecured()
CheckPlayerDefeat()
end
WorldLoaded = function()
allies = Player.GetPlayer("Allies")
neutral = Player.GetPlayer("Neutral")
creeps = Player.GetPlayer("Creeps")
soviets = Player.GetPlayer("Soviets")
player1 = Player.GetPlayer("Allies1")
player2 = Player.GetPlayer("Allies2")
humans = { player1, player2 }
Utils.Do(humans, function(player)
if player and player.IsLocalPlayer then
Trigger.OnObjectiveAdded(player, function(p, id)
local objectiveType = string.lower(p.GetObjectiveType(id))
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. objectiveType .. " objective")
end)
Trigger.OnObjectiveCompleted(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
end)
Trigger.OnObjectiveFailed(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
end)
Trigger.OnPlayerWon(player, function()
Media.PlaySpeechNotification(player, "MissionAccomplished")
end)
Trigger.OnPlayerLost(player, function()
Media.PlaySpeechNotification(player, "MissionFailed")
end)
end
end)
InsertSpies()
AttackTown()
SetupPatrols()
SovietBaseMaintenanceSetup()
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,228 @@
World:
GlobalLightingPaletteEffect@HAZE:
Red: 1
Green: 0.55
Blue: 0
MissionData:
Briefing: The Soviets are currently developing a new weapon system at a secret research laboratory. This is a reconnaissance mission. Do not engage until we know what we are up against and wait for reinforcements. Our civilian contacts reported a heavily guarded installation under ruthless command.
LuaScript:
Scripts: infiltration.lua
ScriptLobbyDropdown@difficulty:
ID: difficulty
Label: Difficulty
Values:
easy: Easy
normal: Normal
hard: Hard
Default: normal
^Palettes:
FixedColorPalette@SovietTruk:
Base: player
Name: truk-soviets
RemapIndex: 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
Color: FE1100
MISS:
AutoTargetIgnore:
Targetable:
TargetTypes: Ground, C4, DetonateAttack, Structure, MissionObjective
LST.Unselectable.UnloadOnly:
Inherits: LST
-Selectable:
RenderSprites:
Image: LST
Buildable:
Prerequisites: ~disabled
Cargo:
MaxWeight: 0
PipCount: 0
AutoTargetIgnore:
SPY.Strong:
Inherits: SPY
Buildable:
Prerequisites: ~disabled
RenderSprites:
Image: SPY
Health:
HP: 100
RevealsShroud:
Range: 6c0
Infiltrates:
Types: MissionObjective
ExternalCaptures:
CaptureTypes: MissionObjective
EditorOnlyTooltip:
Description: RenderDebugState.OnOwnerChange will crash
-RenderDebugState:
Passenger:
GrantUpgrades: mobile
DOG.Patrol:
Inherits: DOG
Buildable:
Prerequisites: ~disabled
Mobile:
Speed: 56
RenderSprites:
Image: DOG
TRUK.Hijackable:
Inherits: TRUK
Buildable:
Prerequisites: ~disabled
Mobile:
UpgradeTypes: mobile
UpgradeMinEnabledLevel: 1
Cargo:
Types: Infantry
MaxWeight: 5
PipCount: 5
AutoTargetIgnore:
-Huntable:
ExternalCapturable:
Type: MissionObjective
CaptureCompleteTime: 1
-SupplyTruck:
RenderSprites:
Image: TRUK
Palette: truk-soviets
RevealsShroud:
Range: 6c0
Voiced:
VoiceSet: SpyVoice
E7:
Buildable:
Prerequisites: ~disabled
TRAN:
Buildable:
Prerequisites: ~disabled
BARR:
Buildable:
Prerequisites: ~disabled
MIG:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~disabled
SS:
Buildable:
Prerequisites: ~disabled
AutoTarget:
InitialStanceAI: Defend
ARTY:
Buildable:
Prerequisites: ~disabled
AGUN:
Buildable:
Prerequisites: ~disabled
MSUB:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
SPEN:
Buildable:
Prerequisites: ~disabled
IRON:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
TSLA:
Buildable:
Prerequisites: ~disabled
FTUR:
Buildable:
Prerequisites: ~disabled
SAM:
Buildable:
Prerequisites: ~disabled
HPAD:
Buildable:
Prerequisites: ~disabled
AFLD:
Buildable:
Prerequisites: ~disabled
ATEK:
Buildable:
Prerequisites: ~disabled
STEK:
Buildable:
Prerequisites: ~disabled
4TNK:
Buildable:
Prerequisites: ~disabled
MCV:
Buildable:
Prerequisites: ~disabled
EditorOnlyTooltip:
Description: RenderDebugState.OnOwnerChange will crash
-RenderDebugState:
APC:
Buildable:
Prerequisites: ~disabled
MNLY.AP:
Buildable:
Prerequisites: ~disabled
MNLY.AT:
Buildable:
Prerequisites: ~disabled
TTNK:
Buildable:
Prerequisites: ~disabled
FTRK:
Buildable:
Prerequisites: ~disabled
CTNK:
Buildable:
Prerequisites: ~disabled
MGG:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: ~disabled