Add Negotiations mission (Red Alert)

This commit is contained in:
JovialFeline
2024-04-30 18:25:28 -04:00
committed by Gustas
parent c63be29770
commit 670067ae3a
12 changed files with 3587 additions and 3 deletions

View File

@@ -14,7 +14,7 @@ actor-crate-name = Crate
## campaign-tooltips.yaml
actor-technology-center-name = Technology Center
## allies-05a, allies-05b, allies-05c
## allies-05a, allies-05b, allies-05c, negotiations
actor-prison-name = Prison
## fall-of-greece-1-personal-war, situation-critical

View File

@@ -17,7 +17,7 @@ find-einstein = Find Einstein.
einstein-survive = Einstein must survive.
protect-civilians = Protect all civilians.
## allies-01, allies-03, allies-05abc, evacuation
## allies-01, allies-03, allies-05abc, evacuation, negotiations
tanya-rules-of-engagement = According to the rules of engagement I need your explicit orders to fire, Commander!
# allies-01, allies-05abc, evacuation
@@ -214,6 +214,20 @@ all-engineers-killed = All engineers were killed.
kill-stavros = Kill Stavros.
sabotage-facility = Sabotage the facility with our engineers.
## negotiations
all-hostages-killed = All hostages were killed.
church-destroyed = The church was destroyed.
free-hostages = Locate & free the hostages.
get-hostages-to-church = Get hostages to church.
signal-for-reinforcements = Signal for reinforcements at your drop-off point.
guide-thank-you = Thank you! I'll help you get into town!
guide-follow-me = Follow me!
guide-patrol-coming = Uh oh, a patrol is coming this way.
guide-come-this-way = Come this way! Hurry!
guide-safe-to-move = It's safe to move now. Let's go.
hostage-dies-in = Hostage dies in { $time }
keep-all-hostages-alive = Keep all hostages alive.
## production-disruption, shock-therapy
capture-enemy-radar-dome = Capture the enemy radar dome.
@@ -274,7 +288,7 @@ destroy-soviet-convoy = Destroy all Soviet convoy trucks.
destroy-bridges-slow-convoy = Destroy the nearby bridges to slow the
convoys down.
## siberian-conflict-3-wasteland
## siberian-conflict-3-wasteland, negotiations
destroy-soviet-units-infrastructure = Destroy all Soviet units and structures.
## situation-critical

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,347 @@
--[[
Copyright (c) The OpenRA Developers and Contributors
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.
]]
BuildIntervals =
{
easy = DateTime.Seconds(25),
normal = DateTime.Seconds(15),
hard = DateTime.Seconds(10)
}
StructureRebuildGrace = BuildIntervals[Difficulty]
InfantryTeams =
{
{
types = { "e1", "e1" }
},
{
types = { "e2", "e2" }
},
{
types = { "e4", "e4" },
requirements = { "ftur" }
},
{
types = { "e1", "e1", "e2", "e2" },
onBuilt = AttackFromChurch
},
{
types = { "shok", "shok" },
requirements = { "ai.hard", "techcenter", "tsla" }
}
}
VehicleTeams =
{
{
types = { "3tnk" },
requirements = { "fix" }
},
{
types = { "ttnk", "3tnk" },
requirements = { "techcenter", "fix", "tsla" }
}
}
HarvesterTeam =
{
types = { "harv" },
buildTime = Actor.BuildTime("harv"),
onBuilt = function(actors)
Utils.Do(actors, function(actor)
actor.FindResources()
end)
end
}
PrepareBadGuy = function()
BadGuy.Cash = 100000
if Difficulty == "hard" then
SpawnMiscActor("ai.hard", BadGuy)
end
PrepareTeamBuildTimes(InfantryTeams)
PrepareTeamBuildTimes(VehicleTeams)
SetBotStructures(
{ type = "powr", exists = false, shape = "2x3", location = CPos.New(40, 51) },
{ type = "proc", exists = false, shape = "3x4", location = CPos.New(33, 52) },
{ type = "barr", exists = false, shape = "2x3", location = CPos.New(40, 55), onBuilt = BuildInfantry, onKilled = CheckNewBase, rebuildSkipped = true },
{ type = "powr", exists = false, shape = "2x3", location = CPos.New(30, 50) },
{ type = "ftur", exists = false, shape = "1x1", location = CPos.New(39, 58), onKilled = CheckNewBase },
{ type = "ftur", exists = false, shape = "1x1", location = CPos.New(43, 57), onKilled = CheckNewBase },
{ type = "powr", exists = false, shape = "2x3", location = CPos.New(30, 53) },
{ type = "weap", exists = false, shape = "3x3", location = CPos.New(33, 56), onBuilt = BuildVehicles, onKilled = CheckNewBase, rebuildSkipped = true },
-- Tesla coil is originally built before factory.
-- For convention, coil is swapped (and service depot added).
{ type = "tsla", exists = false, shape = "1x1", location = CPos.New(37, 57), onKilled = CheckNewBase },
{ type = "fix", exists = false, shape = "3x3", location = CPos.New(30, 56) }
)
Trigger.OnEnteredFootprint( { BuilderRally.Location }, function(actor, id)
if actor.Type ~= "fact" then
return
end
Trigger.RemoveFootprintTrigger(id)
ActivateBot()
Trigger.OnKilled(actor, CheckNewBase)
end)
end
CheckNewBase = function()
if IsNewBaseOkay() then
return
end
PrepareTechSale()
if Difficulty == "hard" then
StartFireSale(BadGuy)
end
end
IsNewBaseOkay = function()
local types = { "fact", "barr", "ftur", "weap", "tsla" }
return Utils.Any(types, function(type)
return BadGuy.HasPrerequisites({ type })
end)
end
PrepareTechSale = function()
if ForwardTech.IsDead or ForwardTech.Owner == USSR then
return
end
ForwardTech.Owner = USSR
if ForwardCommand.IsDead then
StartFireSale(USSR)
end
end
ActivateBot = function()
CheckStructures(BadGuy, DateTime.Seconds(5))
BadGuy.GrantCondition("ai-enabled")
end
PrepareTeamBuildTimes = function(teamCollection)
Utils.Do(teamCollection, function(team)
local time = 0
Utils.Do(team.types, function(type)
time = time + Actor.BuildTime(type)
end)
team.buildTime = time
end)
end
SelectTeam = function(teamCollection)
local teams = Utils.Shuffle(teamCollection)
for i = 1, #teams do
local team = teams[i]
if AreTeamRequirementsMet(team.requirements) then
return team
end
end
return { }
end
AreTeamRequirementsMet = function(requirements)
if not requirements then
return true
end
return BadGuy.HasPrerequisites(requirements)
end
BuildTeam = function(player, team, nextBuild)
if not team.types then
-- No teams had their prerequisites.
Trigger.AfterDelay(BuildIntervals[Difficulty], nextBuild)
return
end
local onBuilt = team.onBuilt or GroupIdleHunt
player.Build(team.types, onBuilt)
Trigger.AfterDelay(team.buildTime, nextBuild)
end
BuildInfantry = function()
if #BadGuy.GetActorsByType("barr") < 1 then
return
end
local team = SelectTeam(InfantryTeams)
BuildTeam(BadGuy, team, function()
Trigger.AfterDelay(BuildIntervals[Difficulty], BuildInfantry)
end)
end
BuildVehicles = function()
if #BadGuy.GetActorsByType("weap") < 1 then
return
end
local team = nil
if IsHarvesterNeeded(BadGuy) then
team = HarvesterTeam
end
team = team or SelectTeam(VehicleTeams)
BuildTeam(BadGuy, team, function()
Trigger.AfterDelay(BuildIntervals[Difficulty], BuildVehicles)
end)
end
IsHarvesterNeeded = function(player)
return player.HasPrerequisites({ "proc" }) and #player.GetActorsByType("harv") < 1
end
AttackFromChurch = function(actors)
local path =
{
BadGuyRally.Location,
ForestPatrolStart.Location,
GuideHouseReveal.Location,
ChurchRally.Location,
GuideHouseReveal.Location
}
GroupTightPatrol(actors, path, false, 0, GroupIdleHunt)
end
--[[
These kind of work like the original [BASE] and [STRUCTURES] .INI sections.
Check a list every so often and (re)build structures that are missing,
in order, and if circumstances allow for it.
]]
SetBotStructures = function(...)
local structures = { ... }
Utils.Do(structures, function(structure)
structure.cost = Actor.Cost(structure.type)
structure.buildTime = Actor.BuildTime(structure.type)
structure.position = WPos.New(structure.location.X * 1024, structure.location.Y * 1024, 0)
end)
BadGuyStructures = structures
end
CheckStructures = function(player, interval, rushed)
if #player.GetActorsByType("fact") < 1 then
return
end
local buildingScheduled = false
for _, structure in pairs(BadGuyStructures) do
if not structure.exists then
buildingScheduled = true
ScheduleStructure(player, structure, rushed or structure.buildTime, interval)
break
end
end
if buildingScheduled then
return
end
Trigger.AfterDelay(interval, function()
CheckStructures(player, interval)
end)
end
ScheduleStructure = function(player, structure, buildTime, interval)
Trigger.AfterDelay(buildTime, function()
if #player.GetActorsByType("fact") < 1 then
return
end
local success, blocked = BuildStructure(player, structure)
if not success and blocked then
CheckStructures(player, interval, DateTime.Seconds(2))
return
end
Trigger.AfterDelay(interval, function()
CheckStructures(player, interval)
end)
end)
end
AddRebuildTrigger = function(actor, structure)
if structure.rebuildSkipped then
return
end
Trigger.OnRemovedFromWorld(actor, function()
-- Period before the bot can consider replacement.
Trigger.AfterDelay(StructureRebuildGrace, function()
structure.exists = false
end)
end)
end
BuildStructure = function(player, structure)
if structure.cost > player.Cash then
return false
end
local blocked = IsStructureAreaBlocked(player, structure.position, structure.shape)
if blocked then
return false, "blocked"
end
local actor = Actor.Create(structure.type, true, { Owner = player, Location = structure.location })
structure.exists = true
player.Cash = player.Cash - structure.cost
AddRebuildTrigger(actor, structure)
if structure.onKilled then
Trigger.OnKilled(actor, structure.onKilled)
end
if structure.onBuilt then
-- Build() will not work properly on producers if called immediately.
Trigger.AfterDelay(1, function()
structure.onBuilt(actor)
end)
end
return actor
end
StructureFootprints =
{
["1x1"] = WVec.New(1 * 1024, 1 * 1024, 0),
["2x3"] = WVec.New(2 * 1024, 3 * 1024, 0),
["3x3"] = WVec.New(3 * 1024, 3 * 1024, 0),
["3x4"] = WVec.New(3 * 1024, 4 * 1024, 0),
}
IsStructureAreaBlocked = function(player, position, shape)
local foot = StructureFootprints[shape]
local blockers = Map.ActorsInBox(position, position + foot, function(actor)
return actor.CenterPosition.Z == 0 and actor.HasProperty("Health")
end)
if #blockers == 0 then
return false
end
ScatterBlockers(player, blockers)
return true
end
ScatterBlockers = function(player, actors)
Utils.Do(actors, function(actor)
if actor.IsIdle and actor.Owner == player and actor.HasProperty("Scatter") then
actor.Scatter()
end
end)
end

View File

@@ -0,0 +1,397 @@
--[[
Copyright (c) The OpenRA Developers and Contributors
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.
]]
ReinforceAllies = function()
Media.PlaySpeechNotification(Greece, "ReinforcementsArrived")
local proxy = SpawnMiscActor("paradrop.allies", GoodGuy, TanyaDrop.Location, DateTime.Seconds(1))
local planes = proxy.TargetParatroopers(TanyaDrop.CenterPosition, Angle.SouthEast)
Utils.Do(planes, function(plane)
Trigger.OnPassengerExited(plane, function(_, passenger)
passenger.Owner = Greece
end)
Trigger.OnAllKilled(plane.Passengers, CheckAlliedDestruction)
end)
local demoTypes = { "2tnk", "2tnk", "2tnk", "dtrk" }
local artilleryTypes = {"2tnk", "2tnk", "arty", "arty", "mech", "mech", "mech" }
local groundPath = { WestRoadEntry.Location, WestRoadRally.Location }
local demoTeam = Reinforcements.Reinforce(Greece, demoTypes, groundPath)
Trigger.OnAllKilled(demoTeam, CheckAlliedDestruction)
Trigger.AfterDelay(DateTime.Seconds(30), function()
if AlliesDefeated then
return
end
Media.PlaySpeechNotification(Greece, "ReinforcementsArrived")
local artilleryTeam = Reinforcements.Reinforce(Greece, artilleryTypes, groundPath)
Trigger.OnAllKilled(artilleryTeam, CheckAlliedDestruction)
end)
end
ReinforceChronoTanks = function(locations)
if ChronoTanksReinforced then
return
end
ChronoTanksReinforced = true
Media.PlaySoundNotification(Greece, "Chronoshift")
Utils.Do(locations, function(location)
local proxy = SpawnMiscActor("powerproxy.chronoshift", GoodGuy, location, DateTime.Seconds(1))
local tank = Actor.Create("ctnk", true, { Owner = Greece, Facing = Angle.NorthWest })
local payload = { [tank] = location }
proxy.Chronoshift(payload)
end)
end
ReinforceTanya = function()
local path = { WestRoadEntry.Location, TanyaDrop.Location }
local plane = Reinforcements.Reinforce(Greece, { "badr.tanya" }, path)[1]
local passengers = { TanyaType }
Trigger.OnAddedToWorld(plane, function()
Utils.Do(passengers, function(type)
local passenger = Actor.Create(type, false, { Owner = Greece })
plane.LoadPassenger(passenger)
Trigger.OnKilled(passenger, OnTanyaKilled)
Tanya = passenger
AnnounceTanyaRules(passenger)
end)
plane.Paradrop(path[2])
end)
end
AnnounceTanyaRules = function(tanya)
if Difficulty == "easy" then
return
end
Trigger.OnAddedToWorld(tanya, function()
Trigger.AfterDelay(DateTime.Seconds(1), function()
Media.DisplayMessage(UserInterface.Translate("tanya-rules-of-engagement"), tanya.TooltipName)
Media.PlaySoundNotification(Greece, "AlertBleep")
end)
end)
end
ReinforceLongbows = function()
if SoutheastTurret.IsDead then
return
end
local goals = { LongbowGoal1, LongbowGoal2, LongbowGoal3 }
local spawnOffset = 0
Utils.Do(goals, function(goal)
local entry = { LongbowEntry.Location + CVec.New(spawnOffset, 15) }
Reinforcements.Reinforce(GoodGuy, { "heli" }, entry, 0, function(helicopter)
helicopter.Wait(DateTime.Seconds(1))
helicopter.AttackMove(goal.Location)
-- Original behavior was to fire at the ground until out of ammo.
Trigger.OnKilled(SoutheastTurret, function()
helicopter.Stop()
helicopter.Wait(10)
helicopter.Move(LongbowExit.Location, 1)
helicopter.Destroy()
end)
end)
spawnOffset = spawnOffset + 5
end)
end
ReinforceBadGuy = function()
-- If ForwardCommand dies early, the General will be busy hunting.
if General.IsDead or ForwardCommand.IsDead then
return
end
BadGuyReinforced = true
Media.PlaySpeechNotification(Greece, "SignalFlareWest")
local flare = SpawnFlare(NorthFlare.Location)
Trigger.OnKilled(General, function()
RemoveActor(flare, DateTime.Seconds(30))
end)
local waterCamera = SpawnPlayerCamera(NorthWaterEntry.Location, -1)
local boatPath = { NorthWaterEntry.Location, BuilderBeach.Location }
local cargo = Reinforcements.ReinforceWithTransport(BadGuy, "lst", { "mcv" }, boatPath, { boatPath[1] })[2]
Utils.Do(cargo, function(builder)
Trigger.OnKilled(builder, CheckNewBase)
Trigger.OnAddedToWorld(builder, function()
local builderCamera = SpawnPlayerCamera(builder.Location, -1, "camera.small")
builder.Move(BuilderRally.Location)
builder.CallFunc(function()
RemoveActor(waterCamera)
RemoveActor(builderCamera)
end)
builder.Deploy()
end)
end)
end
ReinforceNorthChinook = function()
local delay = DateTime.Seconds(4)
local camera = SpawnPlayerCamera(NorthChinookUnload.Location, -1, "camera.small", delay + DateTime.Seconds(2))
Trigger.AfterDelay(delay, function()
local transport = Actor.Create("tran.north", true, { Owner = USSR, Location = NorthChinookEntry.Location, Facing = Angle.South })
local passengers = transport.Passengers
transport.UnloadPassengers(NorthChinookUnload.Location)
transport.Move(SouthChinookExit.Location)
transport.Destroy()
Trigger.OnPassengerExited(transport, function()
if transport.PassengerCount > 0 then
return
end
-- Original unload is slow. Mimic the timing with a short pause.
Trigger.AfterDelay(DateTime.Seconds(3), function()
OrderNorthChinookSoldiers(passengers, camera)
end)
end)
Trigger.OnAnyKilled(passengers, function()
RemoveActor(camera, DateTime.Seconds(1))
end)
end)
end
OrderNorthChinookSoldiers = function(soldiers, camera)
local patrolPath =
{
VillageNortheast.Location,
VillageNorthwest.Location,
VillageSouthwest.Location,
VillageSoutheast.Location
}
local liveSoldiers = Utils.Where(soldiers, IsAlive)
Utils.Do(liveSoldiers, function(soldier)
soldier.AttackMove(NorthChinookRally.Location)
soldier.CallFunc(function()
Trigger.AfterDelay(1, function()
if not AreAllIdleOrDead(liveSoldiers) then
return
end
RemoveActor(camera, DateTime.Seconds(1))
GroupAttackMove(liveSoldiers, VillageBridgeCenter.Location, 2)
GroupTightPatrol(liveSoldiers, patrolPath, true)
GroupHuntOnDamaged(liveSoldiers, Greece)
end)
end)
end)
end
ReinforceVillagePatrol = function()
if VillagePatrolSent then
return
end
VillagePatrolSent = true
local path =
{
VillageSoutheast.Location,
VillageSouthwest.Location,
VillageNorthwest.Location,
VillageNortheast.Location
}
local types = { "e1", "e1", "e2", "dog" }
local origin = { VillagePatrolEntry.Location }
local group = Reinforcements.Reinforce(USSR, types, origin, 0)
GroupTightPatrol(group, path, true)
end
ReinforceGuardHouse = function(intruderType)
if GuardHouse.IsDead then
return
end
local goal = GuideBarrelGoal.Location
if intruderType == TanyaType then
goal = PrisonReveal.Location
end
for i = 1, 4 do
Trigger.AfterDelay(i * 5, function()
local guard = Actor.Create("e1", true, { Owner = USSR, Location = GuardHouseSpawn.Location, SubCell = 4, Facing = Angle.SouthWest })
guard.Move(GuardHouseExit.Location)
guard.AttackMove(goal)
IdleHunt(guard)
end)
end
end
ReinforceHardTeams = function()
if Difficulty ~= "hard" then
return
end
ReinforceBaseDefenders()
ReinforceNorthBeachGuards()
ReinforceV2Team()
ReinforceNorthEdgeGuards()
PrepareSouthChinook()
ReinforceHardDogs()
end
ReinforceBaseDefenders = function()
local origin = BadGuyRally.Location + CVec.New(2, 2)
local types = { "3tnk", "3tnk" }
local defenders = Reinforcements.Reinforce(USSR, types, { origin }, 0, function(actor)
actor.Wait(1)
actor.Scatter()
end)
GroupHuntOnDamaged(defenders, Greece)
local structures = { RoadTurretWest, RoadTurretEast, ForwardPower, ForwardCommand, ForwardTech }
Trigger.OnAnyKilled(structures, function()
GroupIdleHunt(defenders)
end)
end
ReinforceNorthBeachGuards = function()
local types = { "e1", "e1", "e2", "e1" }
local patrolPath = { VillageNortheast.Location, VillageSouthwest.Location }
local soldiers = Reinforcements.Reinforce(USSR, types, { NorthFlare.Location }, 0, function(actor)
actor.Scatter()
end)
Trigger.OnEnteredFootprint({ GeneralRally.Location }, function(actor, id)
if actor.Type ~= "gnrl" then
return
end
Trigger.RemoveFootprintTrigger(id)
GroupHuntOnDamaged(soldiers, Greece)
Utils.Do(soldiers, function(soldier)
if soldier.IsDead then
return
end
soldier.AttackMove(BadGuyRally.Location)
soldier.AttackMove(GuideBarrelGoal.Location)
soldier.AttackMove(VillageNorthwest.Location)
soldier.Patrol(patrolPath, true)
end)
end)
end
ReinforceV2Team = function()
local rocket = Actor.Create("v2rl", true, { Owner = USSR, Facing = Angle.West, Location = SamRocketEntry.Location })
Reinforcements.Reinforce(USSR, { "e1" }, { SamFenceReveal.Location }, 0, function(actor)
actor.Guard(rocket)
end)
end
PrepareSouthChinook = function()
local startPosition = SouthChinookEntry.CenterPosition + WVec.New(0, 0, Actor.CruiseAltitude("tran"))
Trigger.OnEnteredProximityTrigger(SouthChinookProximity.CenterPosition, WDist.FromCells(8), function(actor, id)
if actor.Type ~= TanyaType or not EscortFinished then
return
end
Trigger.RemoveProximityTrigger(id)
local transport = Actor.Create("tran.south", true, { Owner = USSR, CenterPosition = startPosition, Facing = Angle.East })
transport.UnloadPassengers(SouthChinookEntry.Location)
transport.Move(SouthChinookExit.Location)
transport.Destroy()
Utils.Do(transport.Passengers, function(passenger)
Trigger.OnAddedToWorld(passenger, function()
passenger.Wait(DateTime.Seconds(1))
IdleHunt(passenger)
end)
end)
end)
end
ReinforceNorthEdgeGuards = function()
local types = { "e1", "e1", "e2" }
local guards = Reinforcements.Reinforce(USSR, types, { NorthEdgeGuardEntry.Location }, 0, function(actor)
actor.Scatter()
end)
GroupHuntOnDamaged(guards, Greece)
end
ReinforceStartSoldiers = function()
local teams =
{
{
entry = { WestRoadEntry.Location },
types = { "e2", "e2", "e1" }
},
{
entry = { RoadTurretRifle2.Location },
types = { "e1", "e2", "e4" }
}
}
Utils.Do(teams, function(team)
local soldiers = Reinforcements.Reinforce(USSR, team.types, team.entry, 15, function(actor)
actor.AttackMove(TanyaDrop.Location)
actor.Hunt()
end)
Trigger.OnAnyKilled(soldiers, function()
IdleHunt(StartSoldier)
end)
end)
end
ReinforceHardDogs = function()
local startDog = Actor.Create("dog", true, { Owner = USSR, Location = WestRoadEntry.Location, Facing = Angle.South })
startDog.Move(WestRoadRally.Location + CVec.New(-1, 0))
PrepareStartDogAttack(startDog)
local turretDog = Actor.Create("dog.areaguard", true, { Owner = USSR, Location = LongbowGoal2.Location, Facing = Angle.SouthWest })
turretDog.AddTag("TurretDog")
Trigger.OnKilled(turretDog, function()
GroupIdleHunt(SoutheastTurretGuards)
end)
end
PrepareStartDogAttack = function(dog)
-- Tanya will take about 100 ticks/4 seconds to touch the ground.
local delay = DateTime.Seconds(5) + 5
Trigger.OnEnteredFootprint({ TanyaDrop.Location }, function(actor, id)
if actor.Type ~= TanyaType then
return
end
Trigger.RemoveFootprintTrigger(id)
Trigger.AfterDelay(delay, function()
if dog.IsDead or actor.IsDead then
return
end
dog.Attack(actor)
end)
end)
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
Sounds:
Notifications:
HostageShot: gun27
DogWhine: dogw5
GuideOkay: guyokay1
Chronoshift: chrono2

View File

@@ -0,0 +1,196 @@
World:
LuaScript:
Scripts: campaign.lua, utils.lua, negotiations.lua, negotiations-ai.lua, negotiations-reinforcements.lua
MissionData:
Briefing: A Soviet force has holed up in a small town, threatening to kill a hostage every few minutes until their demands are met. We do not negotiate with terrorists -- explain this to them.\n\nLocate the hostages, free as many of them as you can, and get them safely to a nearby abandoned church. Once done, return to your drop-off point, signal for reinforcements, and finish off the Soviet forces.
WinVideo: allymorf.vqa
LossVideo: battle.vqa
TimeLimitManager:
SkipTimerExpiredNotification: true
StartGameNotification:
Notification: TimerStarted
ScriptLobbyDropdown@difficulty:
ID: difficulty
Label: dropdown-difficulty.label
Description: dropdown-difficulty.description
Values:
easy: options-difficulty.easy
normal: options-difficulty.normal
hard: options-difficulty.hard
Default: normal
Player:
ExternalCondition@BadGuy:
Condition: ai-enabled
HarvesterBotModule:
RequiresCondition: ai-enabled
BuildingRepairBotModule:
RequiresCondition: ai-enabled
MissionObjectives:
Cooperative: true
ai.hard:
ProvidesPrerequisite:
Prerequisite: ai.hard
Interactable:
AlwaysVisible:
paradrop.allies:
Inherits: powerproxy.paratroopers
ParatroopersPower:
DropItems: e1,e1,e3,e3,e3,e3,e1,e1,e1,medi
SquadSize: 2
DisplayBeacon: false
powerproxy.chronoshift:
AlwaysVisible:
ChronoshiftPower:
Dimensions: 1, 1
Footprint: x
CAMERA.tiny:
Inherits: CAMERA
RevealsShroud:
Range: 2c0
CAMERA.small:
Inherits: CAMERA
RevealsShroud:
Range: 4c0
CTNK:
Chronoshiftable:
ChronoshiftSound:
V2RL:
AutoTarget:
# A mobile V2 can be annoying to chase, or too much with the dog attack.
InitialStanceAI: Defend
# This type will mimic the wide guard range sometimes given to RA '96 dogs by
# Area Guard orders. An extra dog on Hard difficulty will also use this.
DOG.areaguard:
Inherits: DOG
RenderSprites:
Image: dog
AutoTarget:
ScanRadius: 9
RevealsShroud:
Range: 9c0
ScriptTags:
# Keep SAMs online if the nearby truck blows; original SAMs require no power.
# This does not affect the MCV-built base.
APWR:
PowerMultiplier:
Modifier: 200
MISS:
Tooltip:
Name: actor-prison-name
STEK:
ProvidesPrerequisite@TeslaTanks:
Prerequisite: vehicles.russia
ProvidesPrerequisite@ShockTroopers:
Prerequisite: infantry.russia
Power:
Amount: 0
SpawnActorsOnSell:
# Swap out the normal Technician that resembles one of the civilians.
# Swap Engineers as well because they're useless for hunting.
ActorTypes: e1,tecn2,tecn2,c8,c9
V08:
# Keep close to original death time of ~10s (at normal 5/7).
DamageMultiplier:
Modifier: 250
C1:
ExternalCondition@untargetable:
Condition: untargetable
Targetable:
RequiresCondition: !untargetable
Infiltrates:
Types: SpyInfiltrate
ValidRelationships: Ally, Neutral
-Wanders:
V01:
InfiltrateForPowerOutage:
Types: SpyInfiltrate
Targetable@Guide:
TargetTypes: SpyInfiltrate
Cargo:
MaxWeight: 5
Types: c2,c3,c4,c5,c6
LoadedCondition: loaded
RevealsShroud:
RequiresCondition: !loaded
Range: 4c0
Type: CenterPosition
ValidRelationships: Ally, Neutral
^Hostage:
# Not hostile to Soviets but will "guard" Tanya as she returns to the church.
Inherits@Armed: ^ArmedCivilian
Guard:
TargetLineColor: 00000000
RevealsShroud@Imprisoned:
Range: 1c512
ValidRelationships: Neutral
C2:
Inherits@Hostage: ^Hostage
C3:
Inherits@Hostage: ^Hostage
C4:
Inherits@Hostage: ^Hostage
C5:
Inherits@Hostage: ^Hostage
C6:
Inherits@Hostage: ^Hostage
C8:
Inherits@Armed: ^ArmedCivilian
C9:
Inherits@Armed: ^ArmedCivilian
GNRL:
SpeedMultiplier:
Modifier: 150
AutoTarget:
InitialStanceAI: Defend
BADR.tanya:
Inherits: BADR
RenderSprites:
Image: badr
ParaDrop:
# Avoid dropping Tanya short of her target waypoint (and any triggers).
DropRange: 0c512
HELI:
# Make it less obvious that the Guide House rifles do nothing until revealed.
RevealsShroudMultiplier:
Modifier: 70
TRAN.north:
Inherits: TRAN
RenderSprites:
Image: tran
Cargo:
InitialUnits: e2,e2,e3,shok,shok
TRAN.south:
Inherits: TRAN
RenderSprites:
Image: tran
Cargo:
InitialUnits: e1,e1,e4,e2,e2
AfterUnloadDelay: 0

View File

@@ -0,0 +1,12 @@
# Like original, avoid hitting targets besides the southeast flame turret.
HellfireAG:
ValidTargets: Structure
# The default explosion can kill the prison barrels, freeing all hostages.
# The original spread seems closer to half the default.
# Clipped the last two damage warheads to avoid this.
MiniNuke:
Warhead@7Dam_areanuke2: SpreadDamage
Spread: 2c512
Warhead@10Dam_areanuke3: SpreadDamage
Spread: 2c512

View File

@@ -50,6 +50,7 @@ Aftermath Allied Missions:
in-the-nick-of-time
production-disruption
monster-tank-madness
negotiations
Aftermath Soviet Missions:
shock-therapy
situation-critical