diff --git a/OpenRA.sln b/OpenRA.sln index 5da7941277..a5512bf76d 100644 --- a/OpenRA.sln +++ b/OpenRA.sln @@ -52,6 +52,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tiberian Dawn Lua scripts", mods\cnc\maps\nod08a\nod08a.lua = mods\cnc\maps\nod08a\nod08a.lua mods\cnc\maps\nod08b\nod08b-AI.lua = mods\cnc\maps\nod08b\nod08b-AI.lua mods\cnc\maps\nod08b\nod08b.lua = mods\cnc\maps\nod08b\nod08b.lua + mods\cnc\maps\nod09\nod09-AI.lua = mods\cnc\maps\nod09\nod09-AI.lua + mods\cnc\maps\nod09\nod09.lua = mods\cnc\maps\nod09\nod09.lua mods\cnc\maps\funpark01\scj01ea.lua = mods\cnc\maps\funpark01\scj01ea.lua mods\cnc\maps\shellmap\shellmap.lua = mods\cnc\maps\shellmap\shellmap.lua EndProjectSection diff --git a/mods/cnc/maps/nod09/map.bin b/mods/cnc/maps/nod09/map.bin new file mode 100644 index 0000000000..eea1a1e9e2 Binary files /dev/null and b/mods/cnc/maps/nod09/map.bin differ diff --git a/mods/cnc/maps/nod09/map.png b/mods/cnc/maps/nod09/map.png new file mode 100644 index 0000000000..d906ad4577 Binary files /dev/null and b/mods/cnc/maps/nod09/map.png differ diff --git a/mods/cnc/maps/nod09/map.yaml b/mods/cnc/maps/nod09/map.yaml new file mode 100644 index 0000000000..5ed1efa779 --- /dev/null +++ b/mods/cnc/maps/nod09/map.yaml @@ -0,0 +1,886 @@ +MapFormat: 11 + +RequiresMod: cnc + +Title: Reinforce Egypt + +Author: Westwood Studios + +Tileset: DESERT + +MapSize: 64,64 + +Bounds: 1,3,61,59 + +Visibility: MissionSelector + +Categories: Campaign + +LockPreview: True + +Players: + PlayerReference@GDI: + Name: GDI + LockFaction: True + Faction: gdi + Color: F5D378 + Allies: Outpost + Enemies: Nod + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: gdi + PlayerReference@Civilians: + Name: Civilians + NonCombatant: True + Faction: gdi + Enemies: Nod + PlayerReference@Outpost: + Name: Outpost + Faction: gdi + Color: F5D378 + Allies: GDI + Enemies: Nod + PlayerReference@Nod: + Name: Nod + AllowBots: False + Playable: True + Required: True + Faction: nod + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: GDI, Civilians + PlayerReference@NodBase: + Name: NodBase + NonCombatant: True + Faction: nod + Color: FE1100 + Enemies: Nod + +Actors: + Actor0: brik + Location: 25,54 + Owner: NodBase + Actor1: brik + Location: 24,54 + Owner: NodBase + Actor2: brik + Location: 23,54 + Owner: NodBase + Actor3: brik + Location: 22,54 + Owner: NodBase + Actor4: brik + Location: 21,54 + Owner: NodBase + Actor5: brik + Location: 19,54 + Owner: NodBase + Actor6: brik + Location: 18,54 + Owner: NodBase + Actor7: brik + Location: 17,54 + Owner: NodBase + Actor8: brik + Location: 15,54 + Owner: NodBase + Actor9: brik + Location: 14,54 + Owner: NodBase + Actor10: brik + Location: 13,54 + Owner: NodBase + Actor11: brik + Location: 12,54 + Owner: NodBase + Actor12: brik + Location: 11,54 + Owner: NodBase + Actor13: brik + Location: 10,54 + Owner: NodBase + Actor14: brik + Location: 9,54 + Owner: NodBase + Actor15: brik + Location: 25,53 + Owner: NodBase + Actor16: brik + Location: 24,53 + Owner: NodBase + Actor17: brik + Location: 10,53 + Owner: NodBase + Actor18: brik + Location: 9,53 + Owner: NodBase + Actor19: brik + Location: 25,52 + Owner: NodBase + Actor20: brik + Location: 9,52 + Owner: NodBase + Actor21: brik + Location: 9,51 + Owner: NodBase + Actor22: brik + Location: 25,50 + Owner: NodBase + Actor23: brik + Location: 25,49 + Owner: NodBase + Actor24: brik + Location: 61,16 + Owner: GDI + Actor25: brik + Location: 60,16 + Owner: GDI + Actor26: brik + Location: 59,16 + Owner: GDI + Actor27: brik + Location: 58,16 + Owner: GDI + Actor28: brik + Location: 57,16 + Owner: GDI + Actor29: brik + Location: 56,16 + Owner: GDI + Actor30: brik + Location: 55,16 + Owner: GDI + Actor31: brik + Location: 54,16 + Owner: GDI + Actor32: brik + Location: 53,16 + Owner: GDI + Actor33: brik + Location: 52,16 + Owner: GDI + Actor34: brik + Location: 51,16 + Owner: GDI + Actor35: brik + Location: 50,16 + Owner: GDI + Actor36: brik + Location: 49,16 + Owner: GDI + Actor37: brik + Location: 48,16 + Owner: GDI + Actor38: brik + Location: 47,16 + Owner: GDI + Actor39: brik + Location: 46,16 + Owner: GDI + Actor40: brik + Location: 45,16 + Owner: GDI + Actor41: brik + Location: 44,16 + Owner: GDI + Actor42: brik + Location: 43,16 + Owner: GDI + Actor43: brik + Location: 61,15 + Owner: GDI + Actor44: brik + Location: 60,15 + Owner: GDI + Actor45: brik + Location: 44,15 + Owner: GDI + Actor46: brik + Location: 43,15 + Owner: GDI + Actor47: brik + Location: 61,14 + Owner: GDI + Actor48: brik + Location: 43,14 + Owner: GDI + Actor49: brik + Location: 61,13 + Owner: GDI + Actor50: brik + Location: 43,13 + Owner: GDI + Actor51: brik + Location: 61,12 + Owner: GDI + Actor52: brik + Location: 44,12 + Owner: GDI + Actor53: brik + Location: 43,12 + Owner: GDI + Actor54: brik + Location: 61,11 + Owner: GDI + Actor55: brik + Location: 44,11 + Owner: GDI + Actor56: brik + Location: 43,11 + Owner: GDI + Actor57: brik + Location: 61,10 + Owner: GDI + Actor58: brik + Location: 61,9 + Owner: GDI + Actor59: brik + Location: 61,8 + Owner: GDI + Actor60: brik + Location: 61,7 + Owner: GDI + Actor61: brik + Location: 44,7 + Owner: GDI + Actor62: brik + Location: 43,7 + Owner: GDI + Actor63: brik + Location: 61,6 + Owner: GDI + Actor64: brik + Location: 44,6 + Owner: GDI + Actor65: brik + Location: 43,6 + Owner: GDI + Actor66: brik + Location: 61,5 + Owner: GDI + Actor67: brik + Location: 43,5 + Owner: GDI + Actor68: brik + Location: 61,4 + Owner: GDI + Actor69: brik + Location: 44,4 + Owner: GDI + Actor70: brik + Location: 43,4 + Owner: GDI + Actor71: brik + Location: 61,3 + Owner: GDI + Actor72: brik + Location: 60,3 + Owner: GDI + Actor73: brik + Location: 59,3 + Owner: GDI + Actor74: brik + Location: 58,3 + Owner: GDI + Actor75: brik + Location: 57,3 + Owner: GDI + Actor76: brik + Location: 56,3 + Owner: GDI + Actor77: brik + Location: 55,3 + Owner: GDI + Actor78: brik + Location: 54,3 + Owner: GDI + Actor79: brik + Location: 53,3 + Owner: GDI + Actor80: brik + Location: 52,3 + Owner: GDI + Actor81: brik + Location: 51,3 + Owner: GDI + Actor82: brik + Location: 50,3 + Owner: GDI + Actor83: brik + Location: 49,3 + Owner: GDI + Actor84: brik + Location: 48,3 + Owner: GDI + Actor85: brik + Location: 47,3 + Owner: GDI + Actor86: brik + Location: 46,3 + Owner: GDI + Actor87: brik + Location: 45,3 + Owner: GDI + Actor88: brik + Location: 44,3 + Owner: GDI + Actor89: brik + Location: 43,3 + Owner: GDI + Actor90: t08 + Location: 5,14 + Owner: Neutral + Actor91: t08 + Location: 49,37 + Owner: Neutral + Actor92: rock1 + Location: 51,53 + Owner: Neutral + Actor93: t08 + Location: 50,55 + Owner: Neutral + Actor94: split3 + Location: 56,48 + Owner: Neutral + Actor95: split3 + Location: 6,24 + Owner: Neutral + Actor96: t18 + Location: 2,19 + Owner: Neutral + Actor97: t18 + Location: 4,5 + Owner: Neutral + Actor98: t08 + Location: 9,32 + Owner: Neutral + Actor99: t08 + Location: 1,28 + Owner: Neutral + Actor100: t08 + Location: 50,31 + Owner: Neutral + Actor101: t08 + Location: 51,31 + Owner: Neutral + Actor102: t08 + Location: 39,32 + Owner: Neutral + Actor103: t08 + Location: 12,16 + Owner: Neutral + Actor104: t08 + Location: 1,5 + Owner: Neutral + Actor105: t08 + Location: 3,9 + Owner: Neutral + Actor106: rock1 + Location: 1,12 + Owner: Neutral + Actor107: t08 + Location: 23,19 + Owner: Neutral + Actor108: t08 + Location: 17,19 + Owner: Neutral + Actor109: t08 + Location: 16,18 + Owner: Neutral + Actor110: t08 + Location: 16,11 + Owner: Neutral + Actor111: t08 + Location: 16,10 + Owner: Neutral + Actor112: t08 + Location: 29,15 + Owner: Neutral + Actor113: split3 + Location: 47,23 + Owner: Neutral + Actor114: split3 + Location: 38,20 + Owner: Neutral + Actor115: rock4 + Location: 47,54 + Owner: Neutral + Actor116: t18 + Location: 54,23 + Owner: Neutral + Actor117: t18 + Location: 56,27 + Owner: Neutral + Actor118: t08 + Location: 60,23 + Owner: Neutral + Actor119: t08 + Location: 59,24 + Owner: Neutral + Actor120: rock2 + Location: 60,24 + Owner: Neutral + Actor126: v20 + Location: 3,4 + Owner: Civilians + Actor127: v23 + Location: 13,12 + Owner: Civilians + Actor128: v24 + Location: 1,6 + Owner: Civilians + Actor129: v26 + Location: 6,7 + Owner: Civilians + Actor130: v28 + Location: 4,9 + Owner: Civilians + Actor131: v29 + Location: 5,9 + Owner: Civilians + Actor132: v30 + Location: 4,4 + Owner: Civilians + Actor133: v31 + Location: 2,8 + Owner: Civilians + Actor134: v32 + Location: 1,9 + Owner: Civilians + Actor135: v33 + Location: 2,10 + Owner: Civilians + Actor136: v34 + Location: 4,10 + Owner: Civilians + Actor137: v35 + Location: 3,11 + Owner: Civilians + Actor138: v25 + Location: 4,7 + Owner: Civilians + Actor153: jeep + Location: 50,14 + Owner: GDI + Actor154: jeep + Location: 52,5 + Owner: GDI + Facing: 96 + Actor155: jeep + Location: 47,13 + Owner: GDI + Actor156: mtnk + Location: 14,37 + Owner: GDI + Actor157: mtnk + Location: 48,14 + Owner: GDI + Actor158: mtnk + Location: 46,14 + Owner: GDI + Actor159: mtnk + Location: 52,12 + Owner: GDI + Facing: 96 + Actor162: jeep + Location: 9,17 + Owner: GDI + Facing: 64 + Actor163: jeep + Location: 23,4 + Owner: GDI + Facing: 96 + Actor164: jeep + Location: 1,19 + Owner: GDI + Facing: 64 + Actor165: e2 + Location: 57,15 + Owner: GDI + SubCell: 4 + Actor166: e2 + Location: 59,15 + Owner: GDI + SubCell: 0 + Actor167: e2 + Location: 47,15 + Owner: GDI + SubCell: 4 + Actor168: e1 + Location: 50,12 + Owner: GDI + SubCell: 2 + Actor169: e1 + Location: 49,10 + Owner: GDI + SubCell: 3 + Actor170: e2 + Location: 51,30 + Owner: GDI + SubCell: 2 + Actor171: e2 + Location: 52,31 + Owner: GDI + SubCell: 1 + Actor172: e2 + Location: 50,30 + Owner: GDI + SubCell: 4 + Actor173: e1 + Location: 32,41 + Owner: GDI + SubCell: 0 + Actor174: e1 + Location: 31,41 + Owner: GDI + SubCell: 1 + Actor175: e1 + Location: 32,40 + Owner: GDI + SubCell: 2 + Actor176: e1 + Location: 34,40 + Owner: GDI + SubCell: 0 + Actor177: e1 + Location: 18,37 + Owner: GDI + SubCell: 1 + Actor178: e1 + Location: 18,38 + Owner: GDI + SubCell: 3 + Actor179: e1 + Location: 19,37 + Owner: GDI + SubCell: 3 + Actor180: e2 + Location: 40,32 + Owner: GDI + SubCell: 1 + Actor181: e2 + Location: 21,17 + Owner: GDI + Facing: 160 + SubCell: 1 + Actor182: e2 + Location: 11,16 + Owner: GDI + Facing: 96 + SubCell: 2 + Actor183: e2 + Location: 21,17 + Owner: GDI + Facing: 160 + SubCell: 4 + Actor184: e2 + Location: 11,16 + Owner: GDI + Facing: 96 + SubCell: 3 + Actor185: c3 + Location: 6,9 + Owner: Civilians + Facing: 96 + SubCell: 1 + Actor186: c4 + Location: 6,4 + Owner: Civilians + Facing: 160 + SubCell: 3 + Actor187: c5 + Location: 4,11 + Owner: Civilians + Facing: 32 + SubCell: 4 + Actor189: e2 + Location: 21,4 + Owner: GDI + Facing: 160 + SubCell: 3 + Actor190: e2 + Location: 20,4 + Owner: GDI + Facing: 160 + SubCell: 1 + Actor191: e2 + Location: 27,6 + Owner: GDI + Facing: 96 + SubCell: 4 + Actor192: e2 + Location: 27,5 + Owner: GDI + Facing: 64 + SubCell: 3 + Actor193: e2 + Location: 42,26 + Owner: GDI + Facing: 96 + SubCell: 1 + Actor194: e2 + Location: 40,25 + Owner: GDI + SubCell: 1 + Actor195: e1 + Location: 57,31 + Owner: GDI + SubCell: 4 + Actor196: e1 + Location: 59,30 + Owner: GDI + SubCell: 3 + Actor197: e1 + Location: 58,29 + Owner: GDI + SubCell: 1 + Actor198: e2 + Location: 52,15 + Owner: GDI + SubCell: 1 + Actor199: e2 + Location: 52,14 + Owner: GDI + SubCell: 3 + Actor200: e2 + Location: 52,14 + Owner: GDI + SubCell: 4 + Actor201: e2 + Location: 52,15 + Owner: GDI + SubCell: 2 + Actor202: e1 + Location: 54,14 + Owner: GDI + SubCell: 3 + Actor203: e1 + Location: 54,15 + Owner: GDI + SubCell: 1 + Actor204: e1 + Location: 54,15 + Owner: GDI + SubCell: 2 + Actor205: e1 + Location: 54,14 + Owner: GDI + SubCell: 4 + Actor206: e3 + Location: 55,14 + Owner: GDI + SubCell: 4 + Actor207: e3 + Location: 55,15 + Owner: GDI + SubCell: 2 + Actor208: e3 + Location: 56,15 + Owner: GDI + SubCell: 1 + Actor209: e3 + Location: 56,14 + Owner: GDI + SubCell: 3 + Actor244: msam + Owner: GDI + Location: 54,6 + Facing: 92 + TurretFacing: 92 + waypoint27: waypoint + Location: 32,32 + Owner: Neutral + waypoint15: waypoint + Location: 51,15 + Owner: Neutral + waypoint14: waypoint + Location: 21,39 + Owner: Neutral + waypoint13: waypoint + Location: 33,43 + Owner: Neutral + waypoint12: waypoint + Location: 44,29 + Owner: Neutral + waypoint11: waypoint + Location: 24,26 + Owner: Neutral + waypoint10: waypoint + Location: 18,21 + Owner: Neutral + waypoint9: waypoint + Location: 23,14 + Owner: Neutral + waypoint8: waypoint + Location: 34,13 + Owner: Neutral + waypoint7: waypoint + Location: 13,37 + Owner: Neutral + waypoint6: waypoint + Location: 34,36 + Owner: Neutral + waypoint5: waypoint + Location: 16,31 + Owner: Neutral + waypoint4: waypoint + Location: 11,19 + Owner: Neutral + waypoint3: waypoint + Location: 32,4 + Owner: Neutral + waypoint2: waypoint + Location: 9,5 + Owner: Neutral + waypoint1: waypoint + Location: 20,10 + Owner: Neutral + waypoint0: waypoint + Location: 40,9 + Owner: Neutral + AttackPath1: waypoint + Owner: Neutral + Location: 10,21 + AttackPath2: waypoint + Location: 17,21 + Owner: Neutral + CameraEngineerPath: camera + Location: 09,20 + Owner: Neutral + CameraIntro: camera + Location: 48,23 + Owner: Neutral + FlareEngineer: waypoint + Location: 9,4 + Owner: Neutral + FlareRocket: waypoint + Location: 20,12 + Owner: Neutral + GDIBuilding1: gtwr + Location: 42,11 + Owner: GDI + GDIBuilding2: gtwr + Location: 42,7 + Owner: GDI + GDIBuilding3: gtwr + Location: 43,17 + Owner: GDI + GDIBuilding4: atwr + Owner: GDI + Location: 45,6 + TurretFacing: 92 + GDIBuilding5: atwr + Owner: GDI + Location: 45,10 + TurretFacing: 92 + GDIBuilding6: silo + Location: 59,13 + Owner: GDI + GDIBuilding7: silo + Location: 57,13 + Owner: GDI + GDIBuilding8: silo + Location: 46,6 + Owner: GDI + GDIBuilding9: silo + Location: 46,4 + Owner: GDI + GDIBuilding10: hpad + Location: 56,4 + Owner: GDI + GDIBuilding11: hpad + Location: 54,4 + Owner: GDI + GDICYard: fact + Location: 58,4 + Owner: GDI + GDICYardLocation: waypoint + Owner: Neutral + Location: 59,6 + GDIHarvester: harv + Owner: GDI + Location: 54,12 + Facing: 92 + GDIHQ: hq + Location: 57,10 + Owner: GDI + GDINuke1: nuke + Location: 57,7 + Owner: GDI + GDINuke2: nuke + Location: 55,7 + Owner: GDI + GDINuke3: nuke + Location: 59,7 + Owner: GDI + GDINuke4: nuke + Owner: GDI + Location: 59,10 + GDIOrca1: orca + Owner: GDI + Location: 51,4 + Facing: 92 + GDIOrca2: orca + Owner: GDI + Location: 53,4 + Facing: 92 + GDIProc: proc + Owner: GDI + Location: 54,10 + FreeActor: False + GDIPyle: pyle + Location: 49,4 + Owner: GDI + GDIWeap: weap + Location: 51,6 + Owner: GDI + Gunboat: boat + Location: 60,58 + Owner: GDI + Facing: 192 + GunboatLeft: waypoint + Owner: Neutral + Location: 1,58 + GunboatRight: waypoint + Owner: Neutral + Location: 61,58 + HelicopterEntryEngineer: waypoint + Owner: Neutral + Location: 1,3 + HelicopterEntryRmbo: waypoint + Owner: Neutral + Location: 61,23 + HelicopterEntryRocket: waypoint + Owner: Neutral + Location: 12,3 + HelicopterGoalEngineer: waypoint + Location: 8,5 + Owner: Neutral + HelicopterGoalRmbo: waypoint + Owner: Neutral + Location: 58,25 + HelicopterGoalRocket: waypoint + Location: 19,12 + Owner: Neutral + NodCYard: fact + Location: 14,48 + Owner: NodBase + OutpostNuke: nukeout.in + Location: 19,51 + Owner: Outpost + OutpostProc: procout.in + Location: 16,50 + Owner: Outpost + FreeActor: False + OutpostHarv: harv + Location: 8,49 + Owner: Outpost + Facing: 64 + +Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml + +Weapons: weapons.yaml diff --git a/mods/cnc/maps/nod09/nod09-AI.lua b/mods/cnc/maps/nod09/nod09-AI.lua new file mode 100644 index 0000000000..11ac48a9e5 --- /dev/null +++ b/mods/cnc/maps/nod09/nod09-AI.lua @@ -0,0 +1,220 @@ +AttackPaths = { { AttackPath1 }, { AttackPath2 } } +GDIBase = { GDICYard, GDIPyle, GDIWeap, GDIHQ, GDIProc, GDINuke1, GDINuke2, GDINuke3, GDIBuilding1, GDIBuilding2, GDIBuilding3, GDIBuilding4, GDIBuilding5, GDIBuilding6, GDIBuilding7, GDIBuilding8, GDIBuilding9, GDIBuilding10, GDIBuilding11 } +GDIOrcas = { GDIOrca1, GDIOrca2 } +InfantryAttackGroup = { } +InfantryGroupSize = 5 +InfantryProductionCooldown = DateTime.Minutes(3) +InfantryProductionTypes = { "e1", "e1", "e2" } +HarvesterProductionType = { "harv" } +VehicleAttackGroup = { } +VehicleGroupSize = 5 +VehicleProductionCooldown = DateTime.Minutes(3) +VehicleProductionTypes = { "jeep", "jeep", "mtnk", "mtnk", "mtnk", "msam" } +StartingCash = 4000 + +BaseProc = { type = "proc", pos = CPos.New(54, 10), cost = 1500, exists = true } +BaseNuke1 = { type = "nuke", pos = CPos.New(57, 7), cost = 500, exists = true } +BaseNuke2 = { type = "nuke", pos = CPos.New(55, 7), cost = 500, exists = true } +BaseNuke3 = { type = "nuke", pos = CPos.New(59, 7), cost = 500, exists = true } +BaseNuke4 = { type = "nuke", pos = CPos.New(59, 10), cost = 500, exists = true } +InfantryProduction = { type = "pyle", pos = CPos.New(49, 4), cost = 500, exists = true } +VehicleProduction = { type = "weap", pos = CPos.New(51, 6), cost = 2000, exists = true } + +BaseBuildings = { BaseProc, BaseNuke1, BaseNuke2, BaseNuke3, BaseNuke4, InfantryProduction, VehicleProduction } + +AutoGuard = function(guards) + Utils.Do(guards, function(guard) + Trigger.OnDamaged(guard, function(guard) + IdleHunt(guard) + end) + end) +end + +BuildBase = function(cyard) + Utils.Do(BaseBuildings, function(building) + if not building.exists and not cyardIsBuilding then + BuildBuilding(building, cyard) + return + end + end) + Trigger.AfterDelay(DateTime.Seconds(10), function() BuildBase(cyard) end) +end + +BuildBuilding = function(building, cyard) + cyardIsBuilding = true + + Trigger.AfterDelay(Actor.BuildTime(building.type), function() + cyardIsBuilding = false + + if cyard.IsDead or cyard.Owner ~= enemy then + return + end + + local actor = Actor.Create(building.type, true, { Owner = enemy, Location = building.pos }) + enemy.Cash = enemy.Cash - building.cost + + building.exists = true + + if actor.Type == 'pyle' or actor.Type == 'hand' then + Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(actor) end) + elseif actor.Type == 'weap' or actor.Type == 'afld' then + Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceVehicle(actor) end) + end + + Trigger.OnKilled(actor, function() building.exists = false end) + + Trigger.OnDamaged(actor, function(building) + if building.Owner == enemy and building.Health < building.MaxHealth * 3/4 then + building.StartBuildingRepairs() + end + end) + + Trigger.AfterDelay(DateTime.Seconds(10), function() BuildBase(cyard) end) + end) +end + +CheckForHarvester = function() + local harv = enemy.GetActorsByType("harv") + return #harv > 0 +end + +GuardBase = function() + Utils.Do(GDIBase, function(building) + Trigger.OnDamaged(building, function(guard) + Utils.Do(GDIOrcas, function(guard) + if not guard.IsDead and not building.IsDead then + guard.Guard(building) + end + end) + end) + end) +end + +IdleHunt = function(unit) + if not unit.IsDead then + Trigger.OnIdle(unit, unit.Hunt) + end +end + +IdlingUnits = function(enemy) + local lazyUnits = enemy.GetGroundAttackers() + + Utils.Do(lazyUnits, function(unit) + IdleHunt(unit) + end) +end + +ProduceHarvester = function(building) + if not buildingHarvester then + buildingHarvester = true + building.Build(HarvesterProductionType, function() + buildingHarvester = false + end) + end +end + +ProduceInfantry = function(building) + if building.IsDead then + return + elseif not CheckForHarvester() then + Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(building) end) + end + + local delay = Utils.RandomInteger(DateTime.Seconds(3), DateTime.Seconds(9)) + local toBuild = { Utils.Random(InfantryProductionTypes) } + local Path = Utils.Random(AttackPaths) + building.Build(toBuild, function(unit) + InfantryAttackGroup[#InfantryAttackGroup + 1] = unit[1] + + if #InfantryAttackGroup >= InfantryGroupSize then + SendUnits(InfantryAttackGroup, Path) + InfantryAttackGroup = { } + Trigger.AfterDelay(InfantryProductionCooldown, function() ProduceInfantry(building) end) + else + Trigger.AfterDelay(delay, function() ProduceInfantry(building) end) + end + end) + +end + +ProduceVehicle = function(building) + if building.IsDead then + return + elseif not CheckForHarvester() then + ProduceHarvester(building) + Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceVehicle(building) end) + end + + local delay = Utils.RandomInteger(DateTime.Seconds(12), DateTime.Seconds(17)) + local toBuild = { Utils.Random(VehicleProductionTypes) } + local Path = Utils.Random(AttackPaths) + building.Build(toBuild, function(unit) + VehicleAttackGroup[#VehicleAttackGroup + 1] = unit[1] + + if #VehicleAttackGroup >= VehicleGroupSize then + SendUnits(VehicleAttackGroup, Path) + VehicleAttackGroup = { } + Trigger.AfterDelay(VehicleProductionCooldown, function() ProduceVehicle(building) end) + else + Trigger.AfterDelay(delay, function() ProduceVehicle(building) end) + end + end) +end + +SendUnits = function(units, waypoints) + Utils.Do(units, function(unit) + if not unit.IsDead then + Utils.Do(waypoints, function(waypoint) + unit.AttackMove(waypoint.Location) + end) + IdleHunt(unit) + end + end) +end + +StartAI = function(cyard) + Utils.Do(Map.NamedActors, function(actor) + if actor.Owner == enemy and actor.HasProperty("StartBuildingRepairs") then + Trigger.OnDamaged(actor, function(building) + if building.Owner == enemy and building.Health < 3/4 * building.MaxHealth then + building.StartBuildingRepairs() + end + end) + end + end) + enemy.Cash = StartingCash + BuildBase(cyard) + GuardBase() +end + +Trigger.OnAllKilledOrCaptured(GDIBase, function() + IdlingUnits(enemy) +end) + +Trigger.OnKilled(GDIProc, function(building) + BaseProc.exists = false +end) + +Trigger.OnKilled(GDINuke1, function(building) + BaseNuke1.exists = false +end) + +Trigger.OnKilled(GDINuke2, function(building) + BaseNuke2.exists = false +end) + +Trigger.OnKilled(GDINuke3, function(building) + BaseNuke3.exists = false +end) + +Trigger.OnKilled(GDINuke4, function(building) + BaseNuke4.exists = false +end) + +Trigger.OnKilled(GDIPyle, function(building) + InfantryProduction.exists = false +end) + +Trigger.OnKilled(GDIWeap, function(building) + VehicleProduction.exists = false +end) diff --git a/mods/cnc/maps/nod09/nod09.lua b/mods/cnc/maps/nod09/nod09.lua new file mode 100644 index 0000000000..4219c1e381 --- /dev/null +++ b/mods/cnc/maps/nod09/nod09.lua @@ -0,0 +1,276 @@ +if Map.Difficulty == "Easy" then + Rambo = "rmbo.easy" +elseif Map.Difficulty == "Hard" then + Rambo = "rmbo.hard" +else + Rambo = "rmbo" +end + +WaypointGroup1 = { waypoint0, waypoint3, waypoint2, waypoint4, waypoint5, waypoint7 } +WaypointGroup2 = { waypoint0, waypoint3, waypoint2, waypoint4, waypoint5, waypoint6 } +WaypointGroup3 = { waypoint0, waypoint8, waypoint9, waypoint10, waypoint11, waypoint12, waypoint6, waypoint13 } +Patrol1Waypoints = { waypoint0.Location, waypoint8.Location, waypoint9.Location, waypoint10.Location } +Patrol2Waypoints = { waypoint0.Location, waypoint3.Location, waypoint2.Location, waypoint4.Location } + +GDI1 = { units = { ['e2'] = 3, ['e3'] = 2 }, waypoints = WaypointGroup1, delay = 40 } +GDI2 = { units = { ['e1'] = 2, ['e2'] = 4 }, waypoints = WaypointGroup2, delay = 50 } +GDI4 = { units = { ['jeep'] = 2 }, waypoints = WaypointGroup1, delay = 50 } +GDI5 = { units = { ['mtnk'] = 1 }, waypoints = WaypointGroup1, delay = 40 } +Auto1 = { units = { ['e1'] = 2, ['e3'] = 3 }, waypoints = WaypointGroup3, delay = 40 } +Auto2 = { units = { ['e2'] = 2, ['e3'] = 2 }, waypoints = WaypointGroup3, delay = 50 } +Auto3 = { units = { ['e1'] = 3, ['e2'] = 2 }, waypoints = WaypointGroup2, delay = 60 } +Auto4 = { units = { ['mtnk'] = 1 }, waypoints = WaypointGroup1, delay = 50 } +Auto5 = { units = { ['mtnk'] = 1 }, waypoints = WaypointGroup3, delay = 50 } +Auto6 = { units = { ['e1'] = 2, ['e3'] = 2 }, waypoints = WaypointGroup3, delay = 50 } +Auto7 = { units = { ['msam'] = 1 }, waypoints = WaypointGroup1, delay = 40 } +Auto8 = { units = { ['msam'] = 1 }, waypoints = WaypointGroup3, delay = 50 } + +RmboReinforcements = { Rambo } +EngineerReinforcements = { "e6", "e6" } +RocketReinforcements = { "e3", "e3", "e3", "e3" } + +AutoAttackWaves = { GDI1, GDI2, GDI4, GDI5, Auto1, Auto2, Auto3, Auto4, Auto5, Auto6, Auto7, Auto8 } + +NodBaseTrigger = { CPos.New(9, 52), CPos.New(9, 51), CPos.New(9, 50), CPos.New(9, 49), CPos.New(9, 48), CPos.New(9, 47), CPos.New(9, 46), CPos.New(10, 46), CPos.New(11, 46), CPos.New(12, 46), CPos.New(13, 46), CPos.New(14, 46), CPos.New(15, 46), CPos.New(16, 46), CPos.New(17, 46), CPos.New(18, 46), CPos.New(19, 46), CPos.New(20, 46), CPos.New(21, 46), CPos.New(22, 46), CPos.New(23, 46), CPos.New(24, 46), CPos.New(25, 46), CPos.New(25, 47), CPos.New(25, 48), CPos.New(25, 49), CPos.New(25, 50), CPos.New(25, 51), CPos.New(25, 52) } +EngineerTrigger = { CPos.New(5, 13), CPos.New(6, 13), CPos.New(7, 13), CPos.New(8, 13), CPos.New(9, 13), CPos.New(10, 13), CPos.New(16, 7), CPos.New(16, 6), CPos.New(16, 5), CPos.New(16, 4), CPos.New(16, 3)} +RocketTrigger = { CPos.New(20, 15), CPos.New(21, 15), CPos.New(22, 15), CPos.New(23, 15), CPos.New(24, 15), CPos.New(25, 15), CPos.New(26, 15), CPos.New(32, 15), CPos.New(32, 14), CPos.New(32, 13), CPos.New(32, 12), CPos.New(32, 11)} + +GunboatPatrolPath = { GunboatLeft.Location, GunboatRight.Location } + +AirstrikeDelay = DateTime.Minutes(2) + DateTime.Seconds(30) + +CheckForSams = function(player) + local sams = player.GetActorsByType("sam") + return #sams >= 3 +end + +searches = 0 +getAirstrikeTarget = function() + local list = player.GetGroundAttackers() + + if #list == 0 then + return + end + + local target = list[DateTime.GameTime % #list + 1].CenterPosition + + local sams = Map.ActorsInCircle(target, WDist.New(8 * 1024), function(actor) + return actor.Type == "sam" end) + + if #sams == 0 then + searches = 0 + return target + elseif searches < 6 then + searches = searches + 1 + return getAirstrikeTarget() + else + searches = 0 + return nil + end +end + +SendAttackWave = function(team) + for type, amount in pairs(team.units) do + count = 0 + local actors = enemy.GetActorsByType(type) + Utils.Do(actors, function(actor) + if actor.IsIdle and count < amount then + SetAttackWaypoints(actor, team.waypoints) + IdleHunt(actor) + count = count + 1 + end + end) + end +end + +SetAttackWaypoints = function(actor, waypoints) + if not actor.IsDead then + Utils.Do(waypoints, function(waypoint) + actor.AttackMove(waypoint.Location) + end) + end +end + +SendGDIAirstrike = function(hq, delay) + if not hq.IsDead and hq.Owner == enemy then + local target = getAirstrikeTarget() + + if target then + hq.SendAirstrike(target, false, Facing.NorthEast + 4) + Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end) + else + Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end) + end + end +end + +SendWaves = function(counter, Waves) + if counter <= #Waves then + local team = Waves[counter] + SendAttackWave(team) + Trigger.AfterDelay(DateTime.Seconds(team.delay), function() SendWaves(counter + 1, Waves) end) + end +end + +StartPatrols = function() + local mtnks = enemy.GetActorsByType("mtnk") + local msams = enemy.GetActorsByType("msam") + + if #mtnks >= 1 then + mtnks[1].Patrol(Patrol1Waypoints, true, 20) + end + + if #msams >= 1 then + msams[1].Patrol(Patrol2Waypoints, true, 20) + end +end + +StartWaves = function() + SendWaves(1, AutoAttackWaves) +end + +Trigger.OnEnteredFootprint(NodBaseTrigger, function(a, id) + if not nodBaseTrigger and a.Owner == player then + nodBaseTrigger = true + player.MarkCompletedObjective(NodObjective3) + NodCYard.Owner = player + + local walls = nodBase.GetActorsByType("brik") + Utils.Do(walls, function(actor) + actor.Owner = player + end) + + Trigger.AfterDelay(DateTime.Seconds(2), function() + Media.PlaySpeechNotification(player, "NewOptions") + end) + end +end) + +Trigger.OnEnteredFootprint(RocketTrigger, function(a, id) + if not rocketTrigger and a.Owner == player then + rocketTrigger = true + player.MarkCompletedObjective(NodObjective1) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.ReinforceWithTransport(player, 'tran.in', RocketReinforcements, { HelicopterEntryRocket.Location, HelicopterGoalRocket.Location }, { HelicopterEntryRocket.Location }, nil, nil) + end) + + Trigger.AfterDelay(DateTime.Seconds(10), function() + FlareEngineerCamera1 = Actor.Create("camera", true, { Owner = player, Location = FlareEngineer.Location }) + FlareEngineerCamera2 = Actor.Create("camera", true, { Owner = player, Location = CameraEngineerPath.Location }) + FlareEngineer = Actor.Create("flare", true, { Owner = player, Location = FlareEngineer.Location }) + end) + + Trigger.AfterDelay(DateTime.Minutes(1), function() + FlareRocketCamera.Destroy() + FlareRocket.Destroy() + end) + end +end) + +Trigger.OnEnteredFootprint(EngineerTrigger, function(a, id) + if not engineerTrigger and a.Owner == player then + engineerTrigger = true + player.MarkCompletedObjective(NodObjective2) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.ReinforceWithTransport(player, 'tran.in', EngineerReinforcements, { HelicopterEntryEngineer.Location, HelicopterGoalEngineer.Location }, { HelicopterEntryEngineer.Location }, nil, nil) + end) + + Trigger.AfterDelay(DateTime.Minutes(1), function() + FlareEngineerCamera1.Destroy() + FlareEngineerCamera2.Destroy() + FlareEngineer.Destroy() + end) + end +end) + +Trigger.OnKilledOrCaptured(OutpostProc, function() + if not outpostCaptured then + outpostCaptured = true + + if OutpostProc.IsDead then + player.MarkFailedObjective(NodObjective4) + else + player.MarkCompletedObjective(NodObjective4) + player.Cash = 1000 + end + + StartPatrols() + + Trigger.AfterDelay(DateTime.Minutes(1), function() StartWaves() end) + Trigger.AfterDelay(AirstrikeDelay, function() SendGDIAirstrike(GDIHQ, AirstrikeDelay) end) + Trigger.AfterDelay(DateTime.Minutes(3), function() ProduceInfantry(GDIPyle) end) + Trigger.AfterDelay(DateTime.Minutes(3), function() ProduceVehicle(GDIWeap) end) + end +end) + +Trigger.OnKilled(Gunboat, function() + GunboatCamera.Destroy() +end) + +WorldLoaded = function() + player = Player.GetPlayer("Nod") + enemy = Player.GetPlayer("GDI") + nodBase = Player.GetPlayer("NodBase") + + Camera.Position = CameraIntro.CenterPosition + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.ReinforceWithTransport(player, 'tran.in', RmboReinforcements, { HelicopterEntryRmbo.Location, HelicopterGoalRmbo.Location }, { HelicopterEntryRmbo.Location }, nil, nil) + FlareRocketCamera = Actor.Create("camera", true, { Owner = player, Location = FlareRocket.Location }) + FlareRocket = Actor.Create("flare", true, { Owner = player, Location = FlareRocket.Location }) + + StartAI(GDICYard) + AutoGuard(enemy.GetGroundAttackers()) + + GunboatCamera = Actor.Create("camera.boat", true, { Owner = player, Location = Gunboat.Location }) + Trigger.OnIdle(Gunboat, function() Gunboat.Patrol(GunboatPatrolPath) end) + + Trigger.OnObjectiveAdded(player, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " 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, "Win") + end) + + Trigger.OnPlayerLost(player, function() + Media.PlaySpeechNotification(player, "Lose") + end) + + NodObjective1 = player.AddPrimaryObjective("Secure the first landing zone.") + NodObjective2 = player.AddPrimaryObjective("Secure the second landing zone.") + NodObjective3 = player.AddPrimaryObjective("Locate the Nod base.") + NodObjective4 = player.AddPrimaryObjective("Capture the refinery.") + NodObjective5 = player.AddPrimaryObjective("Eliminate all GDI forces in the area.") + NodObjective6 = player.AddSecondaryObjective("Build 3 SAMs to fend off the GDI bombers.") + GDIObjective = enemy.AddPrimaryObjective("Eliminate all Nod forces in the area.") +end + +Tick = function() + if not Gunboat.IsDead then + GunboatCamera.Teleport(Gunboat.Location) + end + + if DateTime.GameTime > 2 and player.HasNoRequiredUnits() then + enemy.MarkCompletedObjective(GDIObjective) + end + + if DateTime.GameTime > 2 and enemy.HasNoRequiredUnits() then + player.MarkCompletedObjective(NodObjective5) + end + + if not player.IsObjectiveCompleted(NodObjective6) and CheckForSams(player) then + player.MarkCompletedObjective(NodObjective6) + end +end diff --git a/mods/cnc/maps/nod09/rules.yaml b/mods/cnc/maps/nod09/rules.yaml new file mode 100644 index 0000000000..fa55a0e344 --- /dev/null +++ b/mods/cnc/maps/nod09/rules.yaml @@ -0,0 +1,192 @@ +World: + LuaScript: + Scripts: nod09.lua, nod09-AI.lua + MusicPlaylist: + StartingMusic: march + VictoryMusic: nod_win1 + MissionData: + Briefing: GDI is attempting to retake Egypt.\n\nUse every available resource in your efforts to stop them.\n\nThe populace has once again swayed in support of GDI forces, so show no mercy in dealing with the villagers. + LossVideo: banner.vqa + BriefingVideo: nod9.vqa + MapOptions: + Difficulties: Easy, Normal, Hard + SmudgeLayer@SCORCH: + InitialSmudges: + 20,55: sc2,0 + 16,55: sc1,0 + 14,55: sc5,0 + 9,55: sc6,0 + 20,54: sc5,0 + 16,54: sc4,0 + 22,53: sc3,0 + 8,53: sc4,0 + 8,52: sc3,0 + 12,51: sc2,0 + SmudgeLayer@CRATER: + InitialSmudges: + 21,55: cr1,0 + 15,55: cr1,0 + 8,55: cr1,0 + 8,54: cr1,0 + 7,54: cr1,0 + +Player: + PlayerResources: + DefaultCash: 0 + +^Bridge: + DamageMultiplier@INVULNERABLE: + Modifier: 0 + +BRIDGEHUT: + -Targetable: + +NUK2: + Buildable: + Prerequisites: ~disabled + +HPAD: + Buildable: + Prerequisites: ~disabled + +BRIK: + Buildable: + Prerequisites: ~disabled + +EYE: + Buildable: + Prerequisites: ~disabled + +GUN: + Buildable: + Queue: Defence.Nod + +OBLI: + Buildable: + Prerequisites: ~disabled + +TMPL: + Buildable: + Prerequisites: ~disabled + +E2: + Buildable: + Prerequisites: ~pyle + +E5: + Buildable: + Prerequisites: ~disabled + +HARV: + Harvester: + SearchFromOrderRadius: 45 + +HTNK: + Buildable: + Prerequisites: ~disabled + +RMBO: + Buildable: + Prerequisites: ~disabled + +MCV: + Buildable: + Prerequisites: ~disabled + +MLRS: + Buildable: + Prerequisites: ~disabled + +MTNK: + Buildable: + Prerequisites: ~weap + +MSAM: + Buildable: + Prerequisites: ~weap + +HELI: + Buildable: + Prerequisites: ~disabled + +STNK: + Buildable: + Prerequisites: ~disabled + +GTWR: + Buildable: + Queue: Defence.GDI + +SBAG: + Buildable: + Queue: Defence.GDI, Defence.Nod + +HQ: + AirstrikePower: + Prerequisites: gdi + SquadSize: 2 + +BOAT: + Health: + HP: 1500 + AutoTarget: + InitialStance: AttackAnything + RejectsOrders: + Except: Attack + +TRAN.IN: + Inherits: TRAN + RejectsOrders: + -Selectable: + RenderSprites: + Image: TRAN + Buildable: + Prerequisites: ~disabled + +Camera.Boat: + AlwaysVisible: + Mobile: + TerrainSpeeds: + RevealsShroud: + Range: 4c0 + ScriptTriggers: + +NUKEOUT.IN: + Inherits: NUKE + RenderSprites: + Image: nuke + Buildable: + Prerequisites: ~disabled + ProvidesPrerequisite: + Prerequisite: anypower + Capturable: + CaptureThreshold: 100 + +PROCOUT.IN: + Inherits: PROC + RenderSprites: + Image: proc + Buildable: + Prerequisites: ~disabled + ProvidesPrerequisite: + Prerequisite: proc + Capturable: + CaptureThreshold: 100 + +RMBO.easy: + Inherits: RMBO + Health: + HP: 300 + SelfHealing: + Delay: 10 + HealIfBelow: 50 + DamageCooldown: 200 + RenderSprites: + Image: RMBO + +RMBO.hard: + Inherits: RMBO + -AutoTarget: + -AttackMove: + RenderSprites: + Image: RMBO diff --git a/mods/cnc/maps/nod09/weapons.yaml b/mods/cnc/maps/nod09/weapons.yaml new file mode 100644 index 0000000000..c45d009996 --- /dev/null +++ b/mods/cnc/maps/nod09/weapons.yaml @@ -0,0 +1,2 @@ +BoatMissile: + Range: 5c0 diff --git a/mods/cnc/missions.yaml b/mods/cnc/missions.yaml index 1feabcbd80..28f70ced90 100644 --- a/mods/cnc/missions.yaml +++ b/mods/cnc/missions.yaml @@ -25,6 +25,7 @@ Nod Campaign: ./mods/cnc/maps/nod07b ./mods/cnc/maps/nod08a ./mods/cnc/maps/nod08b + ./mods/cnc/maps/nod09 Funpark Campaign: ./mods/cnc/maps/funpark01