diff --git a/OpenRA.sln b/OpenRA.sln index ec0593a8f7..6e52afbaf6 100644 --- a/OpenRA.sln +++ b/OpenRA.sln @@ -44,6 +44,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tiberian Dawn Lua scripts", mods\cnc\maps\nod06a\nod06a.lua = mods\cnc\maps\nod06a\nod06a.lua mods\cnc\maps\nod06b\nod06b.lua = mods\cnc\maps\nod06b\nod06b.lua mods\cnc\maps\nod06c\nod06c.lua = mods\cnc\maps\nod06c\nod06c.lua + mods\cnc\maps\nod07a\nod07a-AI.lua = mods\cnc\maps\nod07a\nod07a-AI.lua + mods\cnc\maps\nod07a\nod07a.lua = mods\cnc\maps\nod07a\nod07a.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/nod07a/map.bin b/mods/cnc/maps/nod07a/map.bin new file mode 100644 index 0000000000..ffe3a14213 Binary files /dev/null and b/mods/cnc/maps/nod07a/map.bin differ diff --git a/mods/cnc/maps/nod07a/map.png b/mods/cnc/maps/nod07a/map.png new file mode 100644 index 0000000000..8d64e8c574 Binary files /dev/null and b/mods/cnc/maps/nod07a/map.png differ diff --git a/mods/cnc/maps/nod07a/map.yaml b/mods/cnc/maps/nod07a/map.yaml new file mode 100644 index 0000000000..0201464f40 --- /dev/null +++ b/mods/cnc/maps/nod07a/map.yaml @@ -0,0 +1,597 @@ +MapFormat: 11 + +RequiresMod: cnc + +Title: Sick And Dying (a) + +Author: Westwood Studios + +Tileset: DESERT + +MapSize: 64,64 + +Bounds: 2,6,58,55 + +Visibility: MissionSelector + +Categories: Campaign + +LockPreview: True + +Players: + PlayerReference@GDI: + Name: GDI + Faction: gdi + Color: F5D378 + Allies: Civilians + Enemies: Nod + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: gdi + PlayerReference@Civilians: + Name: Civilians + NonCombatant: True + Faction: gdi + Allies: GDI + Enemies: Nod + PlayerReference@Nod: + Name: Nod + Faction: nod + AllowBots: False + Playable: True + Required: True + LockFaction: True + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: GDI, Civilians + PlayerReference@NodBase: + Name: NodBase + Faction: nod + Color: FE1100 + +Actors: + Actor0: cycl + Location: 30,60 + Owner: GDI + Actor1: cycl + Location: 29,60 + Owner: GDI + Actor2: cycl + Location: 28,60 + Owner: GDI + Actor3: cycl + Location: 27,60 + Owner: GDI + Actor4: cycl + Location: 26,60 + Owner: GDI + Actor5: cycl + Location: 25,60 + Owner: GDI + Actor6: cycl + Location: 24,60 + Owner: GDI + Actor7: cycl + Location: 23,60 + Owner: GDI + Actor8: cycl + Location: 22,60 + Owner: GDI + Actor9: cycl + Location: 21,60 + Owner: GDI + Actor10: cycl + Location: 20,60 + Owner: GDI + Actor11: cycl + Location: 19,60 + Owner: GDI + Actor12: cycl + Location: 18,60 + Owner: GDI + Actor13: cycl + Location: 17,60 + Owner: GDI + Actor14: cycl + Location: 16,60 + Owner: GDI + Actor15: cycl + Location: 15,60 + Owner: GDI + Actor16: cycl + Location: 14,60 + Owner: GDI + Actor17: cycl + Location: 13,60 + Owner: GDI + Actor18: cycl + Location: 12,60 + Owner: GDI + Actor19: cycl + Location: 11,60 + Owner: GDI + Actor20: cycl + Location: 30,59 + Owner: GDI + Actor21: cycl + Location: 11,59 + Owner: GDI + Actor22: cycl + Location: 30,58 + Owner: GDI + Actor23: cycl + Location: 11,58 + Owner: GDI + Actor24: cycl + Location: 30,57 + Owner: GDI + Actor25: cycl + Location: 11,57 + Owner: GDI + Actor26: cycl + Location: 30,56 + Owner: GDI + Actor27: cycl + Location: 30,55 + Owner: GDI + Actor28: cycl + Location: 30,54 + Owner: GDI + Actor29: cycl + Location: 30,53 + Owner: GDI + Actor30: cycl + Location: 11,53 + Owner: GDI + Actor31: cycl + Location: 30,52 + Owner: GDI + Actor32: cycl + Location: 11,52 + Owner: GDI + Actor33: cycl + Location: 30,51 + Owner: GDI + Actor34: cycl + Location: 11,51 + Owner: GDI + Actor35: cycl + Location: 30,50 + Owner: GDI + Actor36: cycl + Location: 29,50 + Owner: GDI + Actor37: cycl + Location: 28,50 + Owner: GDI + Actor38: cycl + Location: 27,50 + Owner: GDI + Actor39: cycl + Location: 26,50 + Owner: GDI + Actor40: cycl + Location: 25,50 + Owner: GDI + Actor41: cycl + Location: 24,50 + Owner: GDI + Actor42: cycl + Location: 23,50 + Owner: GDI + Actor43: cycl + Location: 22,50 + Owner: GDI + Actor44: cycl + Location: 21,50 + Owner: GDI + Actor45: cycl + Location: 20,50 + Owner: GDI + Actor46: cycl + Location: 19,50 + Owner: GDI + Actor47: cycl + Location: 18,50 + Owner: GDI + Actor48: cycl + Location: 12,50 + Owner: GDI + Actor49: cycl + Location: 11,50 + Owner: GDI + Actor50: t18 + Location: 44,41 + Owner: Neutral + Actor51: t08 + Location: 16,47 + Owner: Neutral + Actor52: t08 + Location: 3,47 + Owner: Neutral + Actor53: t08 + Location: 49,42 + Owner: Neutral + Actor54: t08 + Location: 44,54 + Owner: Neutral + Actor55: t08 + Location: 46,55 + Owner: Neutral + Actor56: t08 + Location: 29,19 + Owner: Neutral + Actor57: t18 + Location: 15,20 + Owner: Neutral + Actor58: t18 + Location: 13,43 + Owner: Neutral + Actor59: t18 + Location: 8,46 + Owner: Neutral + Actor60: t18 + Location: 16,48 + Owner: Neutral + Actor61: t08 + Location: 3,23 + Owner: Neutral + Actor62: t08 + Location: 6,22 + Owner: Neutral + Actor63: t08 + Location: 17,28 + Owner: Neutral + Actor64: t08 + Location: 22,16 + Owner: Neutral + Actor80: hosp + Location: 4,49 + Owner: GDI + Actor82: v20 + Location: 17,42 + Owner: Civilians + Actor83: v21 + Location: 19,43 + Owner: Civilians + Actor84: v22 + Location: 16,46 + Owner: Civilians + Actor85: v23 + Location: 17,47 + Owner: Civilians + Actor86: v24 + Location: 12,43 + Owner: Civilians + Actor87: v27 + Location: 11,47 + Owner: Civilians + Actor88: v27 + Location: 9,48 + Owner: Civilians + Actor89: v28 + Location: 8,48 + Owner: Civilians + Actor90: v29 + Location: 14,43 + Owner: Civilians + Actor91: v30 + Location: 16,48 + Owner: Civilians + Actor92: v28 + Location: 9,46 + Owner: Civilians + Actor93: v29 + Location: 10,47 + Owner: Civilians + Actor94: v33 + Location: 54,53 + Owner: Civilians + Actor95: v35 + Location: 53,53 + Owner: Civilians + Actor96: v36 + Location: 43,53 + Owner: Civilians + Actor97: v32 + Location: 42,54 + Owner: Civilians + Actor98: v31 + Location: 45,54 + Owner: Civilians + Actor99: v30 + Location: 44,55 + Owner: Civilians + Actor100: v29 + Location: 42,53 + Owner: Civilians + Actor101: v28 + Location: 47,55 + Owner: Civilians + Actor102: v26 + Location: 47,54 + Owner: Civilians + Actor106: v25 + Location: 14,47 + Owner: Civilians + Actor107: jeep + Location: 17,59 + Owner: GDI + Actor108: jeep + Location: 29,53 + Owner: GDI + Actor109: mtnk + Location: 28,59 + Owner: GDI + Actor110: mtnk + Location: 12,59 + Owner: GDI + Actor111: mtnk + Location: 13,59 + Owner: GDI + Actor115: mtnk + Location: 18,28 + Owner: GDI + Facing: 32 + Actor116: mtnk + Location: 17,21 + Owner: GDI + Facing: 96 + Actor117: e2 + Location: 20,52 + Owner: GDI + SubCell: 1 + Actor118: e2 + Location: 13,53 + Owner: GDI + SubCell: 2 + Actor119: e2 + Location: 12,52 + Owner: GDI + SubCell: 3 + Actor120: e1 + Location: 21,52 + Owner: GDI + SubCell: 2 + Actor121: e1 + Location: 13,52 + Owner: GDI + SubCell: 1 + Actor122: e1 + Location: 20,51 + Owner: GDI + SubCell: 3 + Actor123: e2 + Location: 8,45 + Owner: GDI + SubCell: 2 + Actor124: e2 + Location: 9,50 + Owner: GDI + SubCell: 1 + Actor125: e2 + Location: 9,45 + Owner: GDI + SubCell: 3 + Actor126: c6 + Location: 18,51 + Owner: Civilians + Facing: 32 + SubCell: 4 + Actor127: c5 + Location: 10,48 + Owner: Civilians + Facing: 224 + SubCell: 0 + Actor142: c8 + Location: 48,52 + Owner: Civilians + Facing: 224 + SubCell: 4 + Actor143: c4 + Location: 52,57 + Owner: Civilians + Facing: 32 + SubCell: 1 + Actor144: c3 + Location: 11,46 + Owner: Civilians + SubCell: 4 + Actor145: c9 + Location: 15,44 + Owner: Civilians + Facing: 64 + SubCell: 0 + Actor146: e2 + Location: 12,57 + Owner: GDI + SubCell: 2 + Actor147: e2 + Location: 13,57 + Owner: GDI + SubCell: 1 + Actor148: e2 + Location: 12,57 + Owner: GDI + SubCell: 4 + Actor149: e2 + Location: 13,57 + Owner: GDI + SubCell: 3 + waypoint27: waypoint + Location: 32,35 + Owner: Neutral + waypoint26: waypoint + Location: 47,35 + Owner: Neutral + waypoint24: waypoint + Location: 52,15 + Owner: Neutral + waypoint25: waypoint + Location: 54,14 + Owner: Neutral + waypoint14: waypoint + Location: 13,47 + Owner: Neutral + waypoint13: waypoint + Location: 52,8 + Owner: Neutral + waypoint12: waypoint + Location: 14,8 + Owner: Neutral + waypoint11: waypoint + Location: 9,24 + Owner: Neutral + waypoint10: waypoint + Location: 22,25 + Owner: Neutral + waypoint9: waypoint + Location: 31,19 + Owner: Neutral + waypoint8: waypoint + Location: 53,21 + Owner: Neutral + waypoint7: waypoint + Location: 58,27 + Owner: Neutral + waypoint6: waypoint + Location: 39,25 + Owner: Neutral + waypoint5: waypoint + Location: 35,40 + Owner: Neutral + waypoint4: waypoint + Location: 22,32 + Owner: Neutral + waypoint3: waypoint + Location: 9,44 + Owner: Neutral + waypoint2: waypoint + Location: 7,50 + Owner: Neutral + waypoint1: waypoint + Location: 9,54 + Owner: Neutral + waypoint0: waypoint + Location: 15,54 + Owner: Neutral + AttackPath1: waypoint + Owner: Neutral + Location: 26,25 + AttackPath2: waypoint + Owner: Neutral + Location: 37,33 + GDIBuilding1: gtwr + Location: 10,53 + Owner: GDI + GDIBuilding2: gtwr + Location: 13,50 + Owner: GDI + GDIBuilding3: gtwr + Location: 17,50 + Owner: GDI + GDIBuilding4: gtwr + Location: 10,57 + Owner: GDI + GDIBuilding5: nuke + Location: 2,48 + Owner: GDI + GDIBuilding6: silo + Location: 25,51 + Owner: GDI + GDIBuilding7: silo + Location: 14,58 + Owner: GDI + GDIBuilding8: silo + Location: 25,53 + Owner: GDI + GDICYard: fact + Location: 22,57 + Owner: GDI + GDIHarvester: harv + Location: 13,55 + Owner: GDI + Facing: 192 + GDIHQ: hq + Location: 20,57 + Owner: GDI + GDINuke1: nuke + Location: 16,56 + Owner: GDI + GDINuke2: nuke + Location: 18,57 + Owner: GDI + GDINuke3: nuke + Location: 27,51 + Owner: GDI + GDIPyle: pyle + Location: 18,54 + Owner: GDI + GDIProc: proc + Location: 22,51 + Owner: GDI + FreeActor: False + GDISearchTopLeft: waypoint + Owner: Neutral + Location: 11,50 + GDISearchBottomRight: waypoint + Owner: Neutral + Location: 30,60 + GDIWeap: weap + Location: 27,54 + Owner: GDI + NodBuilding1: fact + Location: 54,11 + Owner: NodBase + Health: 46 + NodBuilding2: proc + Location: 51,11 + Owner: NodBase + Health: 45 + FreeActor: False + NodBuilding3: nuke + Location: 55,14 + Owner: NodBase + Health: 47 + NodHarvester: harv + Owner: NodBase + Location: 46,31 + Facing: 92 + ReinforcementsBottomSpawn: waypoint + Owner: Neutral + Location: 59,41 + ReinforcementsEngineersRally: waypoint + Owner: Neutral + Location: 52,40 + ReinforcementsFlamersRally: waypoint + Owner: Neutral + Location: 54,39 + ReinforcementsGDISpawn: waypoint + Owner: Neutral + Location: 8,6 + ReinforcementsGunnersRally: waypoint + Owner: Neutral + Location: 54,41 + ReinforcementsHelicopterSpawn: waypoint + Owner: Neutral + Location: 59,16 + ReinforcementsRocketsRally: waypoint + Owner: Neutral + Location: 52,41 + ReinforcementsTank1Rally: waypoint + Owner: Neutral + Location: 51,40 + ReinforcementsTank2Rally: waypoint + Owner: Neutral + Location: 56,40 + ReinforcementsTopSpawn: waypoint + Owner: Neutral + Location: 59,38 + +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/nod07a/nod07a-AI.lua b/mods/cnc/maps/nod07a/nod07a-AI.lua new file mode 100644 index 0000000000..1e5574b3ab --- /dev/null +++ b/mods/cnc/maps/nod07a/nod07a-AI.lua @@ -0,0 +1,193 @@ +AttackPaths = { { AttackPath1 }, { AttackPath2 } } +GDIBase = { GDICYard, GDIPyle, GDIWeap, GDIHQ, GDIProc, GDINuke1, GDINuke2, GDINuke3, GDIBuilding1, GDIBuilding2, GDIBuilding3, GDIBuilding4, GDIBuilding5, GDIBuilding6, GDIBuilding7, GDIBuilding8 } +InfantryAttackGroup = { } +InfantryGroupSize = 4 +InfantryProductionCooldown = DateTime.Minutes(3) +InfantryProductionTypes = { "e1", "e1", "e2" } +HarvesterProductionType = { "harv" } +VehicleAttackGroup = { } +VehicleGroupSize = 4 +VehicleProductionCooldown = DateTime.Minutes(4) +VehicleProductionTypes = { "jeep", "jeep", "mtnk", "mtnk", "mtnk" } +StartingCash = 4000 + +BaseProc = { type = "proc", pos = CPos.New(22, 51), cost = 1500, exists = true } +BaseNuke1 = { type = "nuke", pos = CPos.New(16, 56), cost = 500, exists = true } +BaseNuke2 = { type = "nuke", pos = CPos.New(18, 57), cost = 500, exists = true } +BaseNuke3 = { type = "nuke", pos = CPos.New(27, 51), cost = 500, exists = true } +InfantryProduction = { type = "pyle", pos = CPos.New(18, 54), cost = 500, exists = true } +VehicleProduction = { type = "weap", pos = CPos.New(27, 54), cost = 2000, exists = true } + +BaseBuildings = { BaseProc, BaseNuke1, BaseNuke2, BaseNuke3, InfantryProduction, VehicleProduction } + +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 + +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) +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(GDIPyle, function(building) + InfantryProduction.exists = false +end) + +Trigger.OnKilled(GDIWeap, function(building) + VehicleProduction.exists = false +end) diff --git a/mods/cnc/maps/nod07a/nod07a.lua b/mods/cnc/maps/nod07a/nod07a.lua new file mode 100644 index 0000000000..f72a07b6f8 --- /dev/null +++ b/mods/cnc/maps/nod07a/nod07a.lua @@ -0,0 +1,270 @@ +GDI1 = { teamType = "atk", units = { ['e2'] = 3 }, waypoints = { waypoint0, waypoint1, waypoint2, waypoint14 }, delay = 40 } +GDI2 = { teamType = "atk", units = { ['mtnk'] = 2 }, waypoints = { waypoint0, waypoint1, waypoint2, waypoint3, waypoint4, waypoint9 }, delay = 30 } +GDI3 = { teamType = "atk", units = { ['e2'] = 4 }, waypoints = { waypoint0, waypoint4, waypoint5, waypoint6, waypoint7, waypoint8 }, delay = 40 } +GDI4 = { teamType = "atk", units = { ['e1'] = 1, ['e2'] = 2 }, waypoints = { waypoint0, waypoint4, waypoint9 }, delay = 30 } +GDI5 = { teamType = "atk", units = { ['mtnk'] = 1 }, waypoints = { waypoint0, waypoint4, waypoint10, waypoint11, waypoint12, waypoint13 }, delay = 80 } +GDI6 = { teamType = "atk", units = { ['mtnk'] = 1 }, waypoints = { waypoint0, waypoint4, waypoint9 }, delay = 50 } +GDI7 = { teamType = "atk", units = { ['jeep'] = 1 }, waypoints = { waypoint0, waypoint4, waypoint5, waypoint6, waypoint7, waypoint8 }, delay = 40 } +GDI8 = { teamType = "rei", units = { ['e2'] = 3, ['e6'] = 2 }, waypoints = { waypoint12, waypoint11, waypoint10, waypoint4, waypoint5, waypoint8 }, delay = 8 } +GDI9 = { teamType = "atk", units = { ['e2'] = 4 }, waypoints = { waypoint8 }, delay = 80 } +GDI10 = { teamType = "atk", units = { ['e2'] = 4 }, waypoints = { waypoint14 }, delay = 0 } + +AirstrikeDelay = DateTime.Minutes(2) + DateTime.Seconds(20) + +AutoAttackWaves = { GDI3, GDI4, GDI5, GDI6, GDI7, GDI8, GDI9, GDI10 } +IntroAttackWaves = { GDI1, GDI2 } +WhitelistedStructures = { 'afld', 'hand', 'hq', 'nuke', 'silo', 'proc', 'sam' } + +NodUnitsBikes = { 'bike', 'bike', 'bike' } +NodUnitsEngineers = { 'e6', 'e6' } +NodUnitsRockets = { 'e3', 'e3', 'e3', 'e3' } +NodUnitsGunners = { 'e1', 'e1', 'e1', 'e1' } +NodUnitsFlamers = { 'e4', 'e4', 'e4', 'e4' } +ReinforcementsRockets = { 'e3', 'e3', 'e3', 'e3', 'e3' } + +NodBase = { NodBuilding1, NodBuilding2, NodBuilding3, NodHarvester } + +AbandonedBaseTrigger = { CPos.New(12, 42), CPos.New(11, 42), CPos.New(10, 42), CPos.New(13, 41), CPos.New(12, 41), CPos.New(11, 41), CPos.New(14, 40), CPos.New(13, 40), CPos.New(12, 40), CPos.New(6, 40), CPos.New(5, 40), CPos.New(4, 40), CPos.New(6, 39), CPos.New(5, 39), CPos.New(4, 39), CPos.New(6, 38), CPos.New(5, 38), CPos.New(4, 38) } +ReinforcementsTrigger = { CPos.New(35, 23), CPos.New(34, 23), CPos.New(35, 22), CPos.New(34, 22), CPos.New(35, 21), CPos.New(34, 21), CPos.New(35, 20), CPos.New(34, 20), CPos.New(35, 19), CPos.New(34, 19), CPos.New(35, 18), CPos.New(34, 18), CPos.New(35, 17), CPos.New(34, 17), CPos.New(35, 16), CPos.New(34, 16), CPos.New(35, 15), CPos.New(34, 15), CPos.New(35, 14), CPos.New(34, 14), CPos.New(35, 13), CPos.New(34, 13), CPos.New(35, 12), CPos.New(34, 12), CPos.New(47, 11), CPos.New(46, 11), CPos.New(57, 19), CPos.New(56, 19), CPos.New(55, 19), CPos.New(54, 19), CPos.New(53, 19), CPos.New(52, 19), CPos.New(51, 19), CPos.New(50, 19), CPos.New(49, 19), CPos.New(48, 19), CPos.New(47, 19), CPos.New(46, 19), CPos.New(57, 18), CPos.New(56, 18), CPos.New(55, 18), CPos.New(54, 18), CPos.New(53, 18), CPos.New(52, 18), CPos.New(51, 18), CPos.New(50, 18), CPos.New(49, 18), CPos.New(48, 18), CPos.New(47, 18), CPos.New(46, 18), CPos.New(47, 17), CPos.New(46, 17), CPos.New(47, 16), CPos.New(46, 16), CPos.New(47, 15), CPos.New(46, 15), CPos.New(47, 14), CPos.New(46, 14), CPos.New(47, 13), CPos.New(46, 13), CPos.New(47, 12), CPos.New(46, 12) } + +CaptureStructures = function(actor) + for i = 1, #WhitelistedStructures do + structures = player.GetActorsByType(WhitelistedStructures[i]) + if #structures > 0 then + if not actor.IsDead and not structures[1].IsDead then + actor.Capture(structures[1]) + return + end + end + end +end + +CheckForSams = function() + 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 + +GetCargo = function(team) + cargo = { } + for type, count in pairs(team.units) do + for i = 1, count, 1 do + cargo[#cargo + 1] = type + end + end + return cargo +end + +InsertNodUnits = function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.Reinforce(player, { 'ltnk'}, { ReinforcementsTopSpawn.Location, ReinforcementsTank1Rally.Location }, 1) + Reinforcements.Reinforce(player, NodUnitsEngineers, { ReinforcementsTopSpawn.Location, ReinforcementsEngineersRally.Location }, 10) + Reinforcements.Reinforce(player, NodUnitsRockets, { ReinforcementsTopSpawn.Location, ReinforcementsRocketsRally.Location }, 10) + + Trigger.AfterDelay(DateTime.Seconds(3), function() + Reinforcements.Reinforce(player, NodUnitsGunners, { ReinforcementsBottomSpawn.Location, ReinforcementsGunnersRally.Location }, 10) + Reinforcements.Reinforce(player, NodUnitsFlamers, { ReinforcementsTopSpawn.Location, ReinforcementsFlamersRally.Location }, 10) + Reinforcements.Reinforce(player, { 'ltnk'}, { ReinforcementsBottomSpawn.Location, ReinforcementsTank2Rally.Location }, 10) + end) +end + +SendAttackWave = function(team) + for type, amount in pairs(team.units) do + count = 0 + actors = enemy.GetActorsByType(type) + Utils.Do(actors, function(actor) + if actor.IsIdle and count < amount then + SetAttackWaypoints(actor, team.waypoints) + if actor.Type == "e6" then + CaptureStructures(actor) + else + IdleHunt(actor) + end + 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 + team = Waves[counter] + if team.teamType == "atk" then + SendAttackWave(team) + elseif team.teamType == "rei" then + SendReinforcementsWave(team) + end + Trigger.AfterDelay(DateTime.Seconds(team.delay), function() SendWaves(counter + 1, Waves) end) + end +end + +SendReinforcementsWave = function(team) + Reinforcements.ReinforceWithTransport(enemy, "apc", GetCargo(team), { ReinforcementsGDISpawn.Location, waypoint12.Location}, nil, function(transport, passengers) + SetReinforcementsWaypoints(transport, team.waypoints) + transport.UnloadPassengers() + Trigger.OnPassengerExited(transport, function(_, passenger) + Utils.Do(passengers, function(actor) + if actor.Type == "e6" then + CaptureStructures(actor) + else + IdleHunt(actor) + end + end) + if not transport.HasPassengers then + IdleHunt(transport) + end + end) + end) +end + +SetReinforcementsWaypoints = function(actor, waypoints) + if not actor.IsDead then + Utils.Do(waypoints, function(waypoint) + actor.Move(waypoint.Location) + end) + end +end + +StartWaves = function(Waves) + SendWaves(1, Waves) +end + +Trigger.OnEnteredFootprint(AbandonedBaseTrigger, function(a, id) + if not abandonedBaseTrigger and a.Owner == player then + abandonedBaseTrigger = true + + FlareCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint25.Location }) + Flare = Actor.Create("flare", true, { Owner = player, Location = waypoint25.Location }) + + Utils.Do(NodBase, function(actor) + if not actor.IsDead then + actor.Owner = player + end + end) + + player.MarkCompletedObjective(NodObjective1) + + Trigger.AfterDelay(DateTime.Seconds(3), function() + Media.PlaySpeechNotification(player, "NewOptions") + end) + end +end) + +Trigger.OnEnteredFootprint(ReinforcementsTrigger, function(a, id) + if not reinforcementsTrigger and a.Owner == player and a.Type ~= 'harv' then + reinforcementsTrigger = true + + Trigger.AfterDelay(DateTime.Seconds(5), function() + Media.PlaySpeechNotification(player, "Reinforce") + Reinforcements.ReinforceWithTransport(player, 'tran.in', ReinforcementsRockets, { ReinforcementsHelicopterSpawn.Location, waypoint24.Location }, { ReinforcementsHelicopterSpawn.Location }, nil, nil) + end) + + StartWaves(IntroAttackWaves) + + Trigger.AfterDelay(AirstrikeDelay, function() SendGDIAirstrike(GDIHQ, AirstrikeDelay) end) + + Trigger.AfterDelay(DateTime.Minutes(2), function() ProduceInfantry(GDIPyle) end) + + Trigger.AfterDelay(DateTime.Minutes(3), function() ProduceVehicle(GDIWeap) end) + + Trigger.AfterDelay(DateTime.Minutes(3), function()StartWaves(AutoAttackWaves) end) + + Trigger.AfterDelay(DateTime.Minutes(2), function() + Flare.Destroy() + FlareCamera.Kill() + end) + end +end) + +WorldLoaded = function() + player = Player.GetPlayer("Nod") + enemy = Player.GetPlayer("GDI") + Camera.Position = waypoint26.CenterPosition + + InsertNodUnits() + StartAI(GDICYard) + + 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("Find the Nod base.") + NodObjective2 = player.AddPrimaryObjective("Eliminate all GDI forces in the area.") + NodObjective3 = 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 DateTime.GameTime > 2 and player.HasNoRequiredUnits() then + enemy.MarkCompletedObjective(GDIObjective) + end + + if DateTime.GameTime > 2 and enemy.HasNoRequiredUnits() then + player.MarkCompletedObjective(NodObjective2) + end + + if not player.IsObjectiveCompleted(NodObjective3) and CheckForSams() then + player.MarkCompletedObjective(NodObjective3) + end +end diff --git a/mods/cnc/maps/nod07a/rules.yaml b/mods/cnc/maps/nod07a/rules.yaml new file mode 100644 index 0000000000..e605388948 --- /dev/null +++ b/mods/cnc/maps/nod07a/rules.yaml @@ -0,0 +1,141 @@ +World: + LuaScript: + Scripts: nod07a.lua, nod07a-AI.lua + MusicPlaylist: + StartingMusic: linefire + VictoryMusic: nod_win1 + MissionData: + Briefing: The Brotherhood has located a huge field of Tiberium in the area.\n\nThe nearby village has laid claim to the field.\n\nEliminate the villagers, as to prevent any infection of our own workers.\n\nGDI forces are reported to be minimal, so elimination of them is of secondary importance. + BriefingVideo: nod7a.vqa + StartVideo: tankgo.vqa + LossVideo: visor.vqa + +Player: + PlayerResources: + DefaultCash: 1000 + +^Bridge: + DamageMultiplier@INVULNERABLE: + Modifier: 0 + +^CivBuilding: + AutoTargetIgnore: + +CYCL: + Buildable: + Prerequisites: ~disabled + +NUK2: + Buildable: + Prerequisites: ~disabled + +HPAD: + Buildable: + Prerequisites: ~disabled + +BRIK: + Buildable: + Prerequisites: ~disabled + +EYE: + Buildable: + Prerequisites: ~disabled + +GUN: + Buildable: + Prerequisites: ~disabled + +OBLI: + Buildable: + Prerequisites: ~disabled + +TMPL: + Buildable: + Prerequisites: ~disabled + +E2: + Buildable: + Prerequisites: ~pyle + +E5: + Buildable: + Prerequisites: ~disabled + +E6: + -RepairsBridges: + +HARV: + Harvester: + SearchFromOrderRadius: 45 + +HTNK: + Buildable: + Prerequisites: ~disabled + +RMBO: + Buildable: + Prerequisites: ~disabled + +MCV: + Buildable: + Prerequisites: ~disabled + +MTNK: + Buildable: + Prerequisites: ~weap + +FTNK: + Buildable: + Prerequisites: ~disabled + +MLRS: + Buildable: + Prerequisites: ~disabled + +MSAM: + Buildable: + Prerequisites: ~disabled + +ATWR: + Buildable: + Prerequisites: ~disabled + +HELI: + Buildable: + Prerequisites: ~disabled + +STNK: + Buildable: + Prerequisites: ~disabled + +ARTY: + Buildable: + Prerequisites: ~disabled + +FIX: + Buildable: + Prerequisites: ~disabled + +SBAG: + Buildable: + Queue: Defence.GDI, Defence.Nod + +GTWR: + Buildable: + Queue: Defence.GDI + Armament: + Weapon: HighV.in + +HQ: + AirstrikePower: + Prerequisites: gdi + SquadSize: 1 + +TRAN.IN: + Inherits: TRAN + RejectsOrders: + -Selectable: + RenderSprites: + Image: TRAN + Buildable: + Prerequisites: ~disabled diff --git a/mods/cnc/maps/nod07a/weapons.yaml b/mods/cnc/maps/nod07a/weapons.yaml new file mode 100644 index 0000000000..d2a64156ab --- /dev/null +++ b/mods/cnc/maps/nod07a/weapons.yaml @@ -0,0 +1,3 @@ +HighV.IN: + Inherits: HighV + Range: 4c0 diff --git a/mods/cnc/missions.yaml b/mods/cnc/missions.yaml index 6441dc6b19..0512dc9117 100644 --- a/mods/cnc/missions.yaml +++ b/mods/cnc/missions.yaml @@ -21,6 +21,7 @@ Nod Campaign: ./mods/cnc/maps/nod06a ./mods/cnc/maps/nod06b ./mods/cnc/maps/nod06c + ./mods/cnc/maps/nod07a Funpark Campaign: ./mods/cnc/maps/funpark01