diff --git a/OpenRA.sln b/OpenRA.sln index 14e8258a61..118fe03616 100644 --- a/OpenRA.sln +++ b/OpenRA.sln @@ -33,6 +33,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tiberian Dawn Lua scripts", mods\cnc\maps\gdi04c\gdi04c.lua = mods\cnc\maps\gdi04c\gdi04c.lua mods\cnc\maps\gdi05a\gdi05a.lua = mods\cnc\maps\gdi05a\gdi05a.lua mods\cnc\maps\nod01\nod01.lua = mods\cnc\maps\nod01\nod01.lua + mods\cnc\maps\nod02a\nod02a.lua = mods\cnc\maps\nod02a\nod02a.lua mods\cnc\maps\nod03a\nod03a.lua = mods\cnc\maps\nod03a\nod03a.lua mods\cnc\maps\nod03b\nod03b.lua = mods\cnc\maps\nod03b\nod03b.lua mods\cnc\maps\shellmap\shellmap.lua = mods\cnc\maps\shellmap\shellmap.lua diff --git a/mods/cnc/maps/nod02a/map.bin b/mods/cnc/maps/nod02a/map.bin new file mode 100644 index 0000000000..4fcece8e79 Binary files /dev/null and b/mods/cnc/maps/nod02a/map.bin differ diff --git a/mods/cnc/maps/nod02a/map.png b/mods/cnc/maps/nod02a/map.png new file mode 100644 index 0000000000..f7eed9db98 Binary files /dev/null and b/mods/cnc/maps/nod02a/map.png differ diff --git a/mods/cnc/maps/nod02a/map.yaml b/mods/cnc/maps/nod02a/map.yaml new file mode 100644 index 0000000000..e8869abbe8 --- /dev/null +++ b/mods/cnc/maps/nod02a/map.yaml @@ -0,0 +1,360 @@ +MapFormat: 7 + +RequiresMod: cnc + +Title: Invasion of Egypt (a) + +Description: GDI has kept a stranglehold on Egypt for many years. Set up a forward attack base in your area. To do this you must select your Mobile Construction Vehicle (MCV) and right click on it. From here you can begin to build a base. This area contains plenty of Tiberium, so establishing the base should be easy. + +Author: Westwood Studios + +Tileset: DESERT + +MapSize: 64,64 + +Bounds: 27,34,36,26 + +Visibility: MissionSelector + +Type: Campaign + +Videos: + Briefing: nod2.vqa + GameLost: deskill.vqa + GameWon: airstrk.vqa + GameStart: seige.vqa + +Options: + Crates: False + Creeps: False + Fog: True + Shroud: True + AllyBuildRadius: False + FragileAlliances: False + StartingCash: 4000 + ConfigurableStartingUnits: False + ShortGame: False + +Players: + PlayerReference@GDI: + Name: GDI + Race: gdi + ColorRamp: 31,222,183 + Enemies: Nod + PlayerReference@Nod: + Name: Nod + Playable: True + AllowBots: False + Required: True + LockRace: True + Race: nod + LockColor: True + ColorRamp: 3,255,127 + LockSpawn: True + LockTeam: True + Enemies: GDI + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Race: gdi + +Actors: + Actor0: t08 + Location: 30,52 + Owner: Neutral + Actor1: t18 + Location: 34,52 + Owner: Neutral + Actor2: t08 + Location: 57,47 + Owner: Neutral + Actor3: t08 + Location: 38,59 + Owner: Neutral + Actor4: silo + Location: 33,40 + Owner: GDI + Actor9: silo + Location: 32,42 + Owner: GDI + Actor10: jeep + Location: 30,46 + Owner: GDI + Facing: 128 + Actor11: jeep + Location: 31,35 + Owner: GDI + Facing: 64 + Actor17: e1 + Location: 34,56 + Owner: GDI + SubCell: 3 + Actor18: e1 + Location: 43,35 + Owner: GDI + SubCell: 3 + Actor19: e1 + Location: 43,36 + Owner: GDI + SubCell: 3 + Actor31: e1 + Location: 47,53 + Owner: GDI + SubCell: 4 + Actor32: e1 + Location: 49,54 + Owner: GDI + Facing: 224 + SubCell: 1 + Actor35: e1 + Location: 34,57 + Owner: GDI + Facing: 64 + SubCell: 1 + waypoint27: waypoint + Location: 27,51 + Owner: Neutral + waypoint26: waypoint + Location: 49,35 + Owner: Neutral + waypoint10: waypoint + Location: 30,44 + Owner: Neutral + waypoint9: waypoint + Location: 55,40 + Owner: Neutral + waypoint8: waypoint + Location: 48,41 + Owner: Neutral + waypoint7: waypoint + Location: 60,58 + Owner: Neutral + waypoint6: waypoint + Location: 61,47 + Owner: Neutral + waypoint5: waypoint + Location: 48,55 + Owner: Neutral + waypoint4: waypoint + Location: 41,51 + Owner: Neutral + waypoint3: waypoint + Location: 28,36 + Owner: Neutral + waypoint2: waypoint + Location: 28,51 + Owner: Neutral + waypoint1: waypoint + Location: 40,43 + Owner: Neutral + waypoint0: waypoint + Location: 40,35 + Owner: Neutral + Refinery: proc + Location: 30,38 + Owner: GDI + Barracks: pyle + Location: 34,43 + Owner: GDI + Powerplant: nuke + Location: 35,40 + Owner: GDI + Yard: fact + Location: 33,37 + Owner: GDI + Guard1: e1 + Location: 42,39 + Owner: GDI + Facing: 64 + SubCell: 0 + Guard2: e1 + Location: 38,38 + Owner: GDI + Facing: 64 + SubCell: 2 + Guard3: e1 + Location: 35,49 + Owner: GDI + Facing: 96 + SubCell: 0 + Guard4: e1 + Location: 34,48 + Owner: GDI + Facing: 96 + SubCell: 3 + Guard5: e1 + Location: 39,40 + Owner: GDI + Facing: 64 + SubCell: 1 + Guard6: e1 + Location: 40,56 + Owner: GDI + Facing: 96 + SubCell: 4 + Guard7: e1 + Location: 38,54 + Owner: GDI + Facing: 32 + SubCell: 3 + McvEntry: waypoint + Location: 62,43 + Owner: Neutral + McvRally: waypoint + Location: 57,41 + Owner: Neutral + UnitsEntry: waypoint + Location: 62,38 + Owner: Neutral + UnitsRally: waypoint + Location: 56,38 + Owner: Neutral + +Smudges: + +Rules: + Player: + -ConquestVictoryConditions: + MissionObjectives: + EarlyGameOver: true + World: + -CrateSpawner: + -SpawnMPUnits: + -MPStartLocations: + ObjectivesPanel: + PanelName: MISSION_OBJECTIVES + LuaScript: + Scripts: nod02a.lua + ^Vehicle: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Tank: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Helicopter: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Infantry: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Plane: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Ship: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Building: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + ^Wall: + Tooltip: + ShowOwnerRow: false + ^Husk: + Tooltip: + GenericVisibility: Enemy, Ally, Neutral + GenericStancePrefix: false + ShowOwnerRow: false + NUK2: + Buildable: + Prerequisites: ~disabled + GUN: + Buildable: + Prerequisites: ~disabled + CYCL: + Buildable: + Prerequisites: ~disabled + FIX: + Buildable: + Prerequisites: ~disabled + HPAD: + Buildable: + Prerequisites: ~disabled + OBLI: + Buildable: + Prerequisites: ~disabled + BRIK: + Buildable: + Prerequisites: ~disabled + TMPL: + Buildable: + Prerequisites: ~disabled + FTNK: + Buildable: + Prerequisites: ~disabled + STNK: + Buildable: + Prerequisites: ~disabled + ARTY: + Buildable: + Prerequisites: ~disabled + E5: + Buildable: + Prerequisites: ~disabled + RMBO: + Buildable: + Prerequisites: ~disabled + MLRS: + Buildable: + Prerequisites: ~disabled + MCV: + Buildable: + Prerequisites: ~disabled + LST: + Buildable: + Prerequisites: ~disabled + C17: + Buildable: + Prerequisites: ~disabled + SAM: + Buildable: + Prerequisites: ~disabled + HQ: + Buildable: + Prerequisites: ~disabled + AFLD: + Buildable: + Prerequisites: ~disabled + E4: + Buildable: + Prerequisites: ~disabled + E3: + Buildable: + Prerequisites: ~disabled + E2: + Buildable: + Prerequisites: ~disabled + SBAG: + Buildable: + Prerequisites: ~disabled + GTWR: + Buildable: + Prerequisites: ~disabled + WEAP: + Buildable: + Prerequisites: ~disabled + EYE: + Buildable: + Prerequisites: ~disabled + ATWR: + Buildable: + Prerequisites: ~disabled + +Sequences: + +VoxelSequences: + +Weapons: + +Voices: + +Notifications: + +Translations: diff --git a/mods/cnc/maps/nod02a/nod02a.lua b/mods/cnc/maps/nod02a/nod02a.lua new file mode 100644 index 0000000000..101fb7f6e2 --- /dev/null +++ b/mods/cnc/maps/nod02a/nod02a.lua @@ -0,0 +1,264 @@ +NodUnits = { "bggy", "e1", "e1", "e1", "e1", "e1", "bggy", "e1", "e1", "e1", "bggy" } +NodBaseBuildings = { "hand", "fact", "nuke" } + +DfndActorTriggerActivator = { Refinery, Barracks, Powerplant, Yard } +Atk3ActorTriggerActivator = { Guard1, Guard2, Guard3, Guard4, Guard5, Guard6, Guard7 } + +Atk1CellTriggerActivator = { CPos.New(45,37), CPos.New(44,37), CPos.New(45,36), CPos.New(44,36), CPos.New(45,35), CPos.New(44,35), CPos.New(45,34), CPos.New(44,34) } +Atk4CellTriggerActivator = { CPos.New(50,47), CPos.New(49,47), CPos.New(48,47), CPos.New(47,47), CPos.New(46,47), CPos.New(45,47), CPos.New(44,47), CPos.New(43,47), CPos.New(42,47), CPos.New(41,47), CPos.New(40,47), CPos.New(39,47), CPos.New(38,47), CPos.New(37,47), CPos.New(50,46), CPos.New(49,46), CPos.New(48,46), CPos.New(47,46), CPos.New(46,46), CPos.New(45,46), CPos.New(44,46), CPos.New(43,46), CPos.New(42,46), CPos.New(41,46), CPos.New(40,46), CPos.New(39,46), CPos.New(38,46) } + +Atk2TriggerFunctionTime = DateTime.Seconds(40) +Atk5TriggerFunctionTime = DateTime.Minutes(1) + DateTime.Seconds(15) +Atk6TriggerFunctionTime = DateTime.Minutes(1) + DateTime.Seconds(20) +Atk7TriggerFunctionTime = DateTime.Seconds(50) +Pat1TriggerFunctionTime = DateTime.Seconds(30) + +Atk1Waypoints = { waypoint2, waypoint4, waypoint5, waypoint6 } +Atk2Waypoints = { waypoint2, waypoint5, waypoint7, waypoint6 } +Atk3Waypoints = { waypoint2, waypoint4, waypoint5, waypoint9 } +Atk4Waypoints = { waypoint0, waypoint8, waypoint9 } +Pat1Waypoints = { waypoint0, waypoint1, waypoint2, waypoint3 } + +UnitToRebuild = 'e1' +GDIStartUnits = 0 + +getActors = function(owner, units) + local maxUnits = 0 + local actors = { } + for type, count in pairs(units) do + local globalActors = Map.ActorsInBox(Map.TopLeft, Map.BottomRight, function(actor) + return actor.Owner == owner and actor.Type == type and not actor.IsDead + end) + if #globalActors < count then + maxUnits = #globalActors + else + maxUnits = count + end + for i = 1, maxUnits, 1 do + actors[#actors + 1] = globalActors[i] + end + end + return actors +end + +InsertNodUnits = function() + Reinforcements.Reinforce(Nod, NodUnits, { UnitsEntry.Location, UnitsRally.Location }, 15) + Reinforcements.Reinforce(Nod, { "mcv" }, { McvEntry.Location, McvRally.Location }) +end + +OnAnyDamaged = function(actors, func) + Utils.Do(actors, function(actor) + Trigger.OnDamaged(actor, func) + end) +end + +CheckForBase = function(player, buildings) + local checked = { } + local baseBuildings = Map.ActorsInBox(Map.TopLeft, Map.BottomRight, function(actor) + if actor.Owner ~= Nod or Utils.Any(checked, function(bldng) return bldng.Type == actor.Type end) then + return false + end + + local found = false + for i = 1, #buildings, 1 do + if actor.Type == buildings[i] then + found = true + checked[#checked + 1] = actor + end + end + return found + end) + return #baseBuildings >= 3 +end + +DfndTriggerFunction = function() + local list = GDI.GetGroundAttackers() + Utils.Do(list, function(unit) + unit.Hunt() + end) +end + +Atk2TriggerFunction = function() + local MyActors = getActors(GDI, { ['e1'] = 3 }) + Utils.Do(MyActors, function(actor) + Atk2Movement(actor) + end) +end + +Atk3TriggerFunction = function() + if not Atk3TriggerSwitch then + Atk3TriggerSwitch = true + MyActors = getActors(GDI, { ['e1'] = 4 }) + Utils.Do(MyActors, function(actor) + Atk3Movement(actor) + end) + end +end + +Atk5TriggerFunction = function() + local MyActors = getActors(GDI, { ['e1'] = 3 }) + Utils.Do(MyActors, function(actor) + Atk2Movement(actor) + end) +end + +Atk6TriggerFunction = function() + local MyActors = getActors(GDI, { ['e1'] = 4 }) + Utils.Do(MyActors, function(actor) + Atk3Movement(actor) + end) +end + +Atk7TriggerFunction = function() + local MyActors = getActors(GDI, { ['e1'] = 3 }) + Utils.Do(MyActors, function(actor) + Atk4Movement(actor) + end) +end + +Pat1TriggerFunction = function() + local MyActors = getActors(GDI, { ['e1'] = 3 }) + Utils.Do(MyActors, function(actor) + Pat1Movement(actor) + end) +end + +Atk1Movement = function(unit) + Utils.Do(Atk1Waypoints, function(waypoint) + unit.AttackMove(waypoint.Location) + end) +end + +Atk2Movement = function(unit) + Utils.Do(Atk2Waypoints, function(waypoint) + unit.AttackMove(waypoint.Location) + end) +end + +Atk3Movement = function(unit) + Utils.Do(Atk3Waypoints, function(waypoint) + unit.AttackMove(waypoint.Location) + end) +end + +Atk4Movement = function(unit) + Utils.Do(Atk4Waypoints, function(waypoint) + unit.AttackMove(waypoint.Location) + end) +end + +Pat1Movement = function(unit) + Utils.Do(Pat1Waypoints, function(waypoint) + unit.Move(waypoint.Location) + end) +end + +WorldLoaded = function() + GDI = Player.GetPlayer("GDI") + Nod = Player.GetPlayer("Nod") + + Trigger.OnObjectiveAdded(Nod, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + Trigger.OnObjectiveCompleted(Nod, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + + Trigger.OnObjectiveFailed(Nod, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + Trigger.OnPlayerWon(Nod, function() + Media.PlaySpeechNotification(Nod, "Win") + end) + + Trigger.OnPlayerLost(Nod, function() + Media.PlaySpeechNotification(Nod, "Lose") + end) + + NodObjective1 = Nod.AddPrimaryObjective("Build a base") + NodObjective2 = Nod.AddPrimaryObjective("Destroy the GDI base") + GDIObjective = GDI.AddPrimaryObjective("Kill all enemies!") + + OnAnyDamaged(Atk3ActorTriggerActivator, Atk3TriggerFunction) + Trigger.OnAllRemovedFromWorld(DfndActorTriggerActivator, DfndTriggerFunction) + + Trigger.AfterDelay(Atk2TriggerFunctionTime, Atk2TriggerFunction) + Trigger.AfterDelay(Atk5TriggerFunctionTime, Atk5TriggerFunction) + Trigger.AfterDelay(Atk6TriggerFunctionTime, Atk6TriggerFunction) + Trigger.AfterDelay(Atk7TriggerFunctionTime, Atk7TriggerFunction) + Trigger.AfterDelay(Pat1TriggerFunctionTime, Pat1TriggerFunction) + + Trigger.OnEnteredFootprint(Atk1CellTriggerActivator, function(a, id) + if a.Owner == Nod then + MyActors = getActors(GDI, { ['e1'] = 5 }) + Utils.Do(MyActors, function(actor) + Atk1Movement(actor) + end) + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnEnteredFootprint(Atk4CellTriggerActivator, function(a, id) + if a.Owner == Nod then + MyActors = getActors(GDI, { ['e1'] = 3 } ) + Utils.Do(MyActors, function(actor) + Atk2Movement(actor) + end) + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.AfterDelay(0, getStartUnits) + InsertNodUnits() +end + +Tick = function() + if GDI.HasNoRequiredUnits() then + Nod.MarkCompletedObjective(NodObjective2) + end + + if Nod.HasNoRequiredUnits() then + if DateTime.GameTime > 2 then + GDI.MarkCompletedObjective(GDIObjective) + end + end + + if DateTime.GameTime % DateTime.Seconds(1) == 0 and not Nod.IsObjectiveCompleted(NodObjective1) and CheckForBase(Nod, NodBaseBuildings) then + Nod.MarkCompletedObjective(NodObjective1) + end + + if DateTime.GameTime % DateTime.Seconds(3) == 0 and Barracks.IsInWorld then + checkProduction(GDI) + end +end + +checkProduction = function(player) + local Units = Map.ActorsInBox(Map.TopLeft, Map.BottomRight, function(actor) + return actor.Owner == player and actor.Type == UnitToRebuild + end) + + if #Units < GDIStartUnits then + local unitsToProduce = GDIStartUnits - #Units + if Barracks.IsInWorld and unitsToProduce > 0 then + local UnitsType = { } + for i = 1, unitsToProduce, 1 do + UnitsType[i] = UnitToRebuild + end + + Barracks.Build(UnitsType) + end + end +end + +getStartUnits = function() + local Units = Map.ActorsInBox(Map.TopLeft, Map.BottomRight, function(actor) + return actor.Owner == GDI + end) + Utils.Do(Units, function(unit) + if unit.Type == UnitToRebuild then + GDIStartUnits = GDIStartUnits + 1 + end + end) +end diff --git a/mods/cnc/missions.yaml b/mods/cnc/missions.yaml index d91e5b1b15..13b311812b 100644 --- a/mods/cnc/missions.yaml +++ b/mods/cnc/missions.yaml @@ -9,5 +9,6 @@ GDI Campaign: Nod Campaign: ./mods/cnc/maps/nod01 + ./mods/cnc/maps/nod02a ./mods/cnc/maps/nod03a ./mods/cnc/maps/nod03b