--MISSION ADJUSTED d2kA.lua clone ActorRegister={} TrackedPairs = {} TrackedProduction = {} ConditionRecord = {} AP_upgradestate={} --atreides powers upgrade state log AP_ConditionRecord={} --outpost airpower condition record ReinforcementSquads = { {"vet_light_inf","vet_light_inf","vet_light_inf","vet_trooper","vet_trooper"}, {"quad","quad","mpsardaukar", "mpsardaukar"}, {"guild_agent"} } WorldLoaded = function() neut=Player.GetPlayer("Neutral") mp0=Player.GetPlayer("Multi0") mp1=Player.GetPlayer("Multi1") mp2=Player.GetPlayer("Multi2") mp3=Player.GetPlayer("Multi3") men0=Player.GetPlayer("South Mentat") men1=Player.GetPlayer("North Mentat") op0=Player.GetPlayer("South Outpost") op1=Player.GetPlayer("North Outpost") smug=Player.GetPlayer("Smugglers") --Initial Objectives initializeObjectives() --Defeat Triggers initializeDefeatTriggers() --spawn faction specific starting units spawnOutpostUnits(mp0,op0) spawnOutpostUnits(mp1,op1) SendInitialReinforcements4p(mp0,mp1,mp2,mp3) --set up smuggler discoverables initiateSmugglerTriggers() --set up discoverable bases initiateDiscoverableBasesSouth(men0,op0) handBaseFromTo(mp0,men0) handBuildingsToSouthOutpost(op0) initiateDiscoverableBasesNorth(men1,op1) handBaseFromTo(mp1,men1) handBuildingsToNorthOutpost(op1) --Send mission introduction text soldierSays(mp0,GernericSoldier[1]) soldierSays(mp1,GernericSoldier[2]) if mp2 then soldierSays(mp2,GernericSoldier[4]..mp0.Faction..GernericSoldier[5]) end if mp3 then soldierSays(mp3,GernericSoldier[4]..mp1.Faction..GernericSoldier[6]) end end Tick = function() --team defeat triggers if delayTrigger0==false and mp0.HasNoRequiredUnits() then defeatTeam1() end if delayTrigger1==false and mp1.HasNoRequiredUnits() then defeatTeam2() end --for smugglers to continue harvesting removeSmugglerSurplusMoney() --for timed rock island reinforcements rockIslandClockTick() --check register for new actors and only call act.Type=="whatever" when neccessary since it is expensive local new_actors = ActorsAddedToWorld(Map.ActorsInWorld,ActorRegister) for _,act in pairs(new_actors) do --LOCATION CHECKS --needed for rock-isle-capture obectives if (mp2 and act.Owner==mp2) or (mp3 and act.Owner==mp3) then if act.HasProperty("AcceptsCondition") and act.AcceptsCondition("isRelevantBuilding") then checkRockIsleLocations(act) end end --ACTOR TYPE CHECKS local T=act.Type --needed for airdrop powers if (T=="waypoint_dummy_a" or T=="waypoint_dummy_h" or T=="waypoint_dummy_o") then dropAirReinforcements(act.Location,act) --for atreides improved airdrop powers executeAtreidesPowerUpgrade(act.Owner,"drop") --needed for improved Atreides air powers elseif T=="palace.atreides" then queueAtreidesPowerUpgrades(act.Owner) --Media.Debug("palace placed") Trigger.OnRemovedFromWorld(act, function(victim) if not victim.Owner.GetActorsByType("palace.atreides")[1] then queueAtreidesPowerDegrade(victim.Owner) --Media.Debug("after triggering") end end ) Trigger.OnCapture(act, function(capped,captor,oldOwner,newOwner) queueAtreidesPowerUpgrades(newOwner) end ) elseif T=="ornithopter" then executeAtreidesPowerUpgrade(act.Owner,"strike") elseif T=="upgrade.hightech" then executeAtreidesPowerUpgrade(act.Owner,"strike") elseif T=="upgrade.outpost" then executeAtreidesPowerUpgrade(act.Owner,"drop") --...handle silo replacement on silo upgrade elseif T=="upgrade.silo" then replace_silos(act.Owner) --...Handle saboteur entering a harvester which is getting picked up by a carryall before the Demolition charge explodes (Both will die) elseif (T == "harvester" or T == "advanced_harvester_h" or T == "advanced_harvester_a" or T == "advanced_harvester_o" or T == "harvester.starport") and TrackedPairs[tostring(act)]==nil then TrackedPairs[tostring(act)]='NoCarryall' Trigger.OnKilled(act, function(harvester,killer) local MaybeCarryall = TrackedPairs[tostring(harvester)] if MaybeCarryall~='NoCarryall' and MaybeCarryall~=nil then if MaybeCarryall.HasProperty('Kill') then MaybeCarryall.Kill() Media.PlaySound('EXPLLG2.WAV') end else end end ) Trigger.OnRemovedFromWorld(act, function(harv) local carryalls = Map.ActorsInCircle(harv.CenterPosition, WDist.New(1), function(carry) if (carry.Type=="carryall" or carry.Type=="carryall.starport") then return carry else return nil end end ) if carryalls[1]~=nil then TrackedPairs[tostring(harv)]=carryalls[1] end end ) Trigger.OnAddedToWorld(act,function(harv) local carryalls = Map.ActorsInCircle(harv.CenterPosition, WDist.New(1), function(carry) if (carry.Type=="carryall" or carry.Type=="carryall.starport") then return carry else return nil end end ) if carryalls[1]~=nil then TrackedPairs[tostring(harv)]='NoCarryall' end end ) --...handle guild agent unit-built icons on unit constructing buildings elseif (T=="barracks" or T=="light_factory" or T=="heavy_factory" or T=="high_tech_factory" or T=="starport") and TrackedProduction[tostring(act)]==nil then TrackedProduction[tostring(act)]= true Trigger.OnProduction(act, function(prod,prodded) grantProductionIcon(prod,prodded) end ) end end end function ActorsAddedToWorld(newlist,register) local new_actor_list={} for key,act in pairs(newlist) do if not register[tostring(act)] then register[tostring(act)]=true table.insert(new_actor_list,act) end end return new_actor_list end function queueAtreidesPowerDegrade(player) --Media.Debug("Degrade:") --Media.Debug(tostring(AP_upgradestate[tostring(player)])) local state = AP_upgradestate[tostring(player)] if state=="notstrike" or state=="notdrop" or state==nil then return else AP_upgradestate[tostring(player)]="queued_undo" end end function queueAtreidesPowerUpgrades(player) --Media.Debug("Upgrade:") --Media.Debug(tostring(AP_upgradestate[tostring(player)])) local state = AP_upgradestate[tostring(player)] if state=="strike" or state=="drop" or state=="both" then return else AP_upgradestate[tostring(player)]="queued" end end function executeAtreidesPowerUpgrade(player,power) --Media.Debug("Execute:") --Media.Debug(tostring(AP_upgradestate[tostring(player)])) local state = AP_upgradestate[tostring(player)] local undo=false if not state then return --no palace elseif state=="both" then return --power allready upgraded elseif state==power or state=="not"..power then return elseif state=="queued_undo" then AP_upgradestate[tostring(player)]="not"..power undo=true --no palace and no degrades done elseif state=="queued" then AP_upgradestate[tostring(player)]=power --palace, but no upgrades done elseif string.sub(state,1,3)=="not" and string.sub(state,4)~=power then AP_upgradestate[tostring(player)]=nil undo=true --other power upgrade degrade done elseif string.sub(state,1,3)~="not" and state~=power then AP_upgradestate[tostring(player)]="both" --other power upgrade done else Media.Debug("should not happen") end --Media.Debug(power.." executing "..tostring(AP_upgradestate[tostring(player)])) local PowerProviders if power=="strike" then PowerProviders = player.GetActorsByType("high_tech_factory") elseif power=="drop" then PowerProviders = player.GetActorsByType("outpost") end if not undo then for _,powerprovider in pairs(PowerProviders) do AP_ConditionRecord[tostring(powerprovider)] = powerprovider.GrantCondition("improved_"..power) end else for _,powerprovider in pairs(PowerProviders) do if AP_ConditionRecord[tostring(powerprovider)] then powerprovider.RevokeCondition(AP_ConditionRecord[tostring(powerprovider)]) AP_ConditionRecord[tostring(powerprovider)]=nil end end end end grantProductionIcon = function(producer,unit) if ConditionRecord[tostring(producer)] then producer.RevokeCondition(ConditionRecord[tostring(producer)]) ConditionRecord[tostring(producer)]=nil end local T=unit.Type if producer.Type == 'barracks' then if T=='light_inf' or T=='trooper' or T=='engineer' or T=='thumper' or T=='assassin' or T=='loyalist' or T=='mpsardaukar' or T=='saboteur' or T=='propaganda_corps' or T=='guild_agent' then ConditionRecord[tostring(producer)] = producer.GrantCondition(tostring(unit.Type)..'_ICO') end elseif producer.Type == 'light_factory' then if T=='raider' or T=='trike_a' or T=='quad_hmg' or T=='quad' or T=='stealth_raider' or T=='troop_crawler' then ConditionRecord[tostring(producer)] = producer.GrantCondition(tostring(unit.Type)..'_ICO') end elseif producer.Type == 'heavy_factory' then if T=='advanced_harvester_o' or T=='advanced_harvester_a' or T=='advanced_harvester_h' or T=='combat_tank_a' or T=='combat_tank_h' or T=='combat_tank_o' or T=='siege_tank_o' or T=='siege_tank_a' or T=='deviator' or T=='missile_tank_a' or T=='missile_tank_o' or T=='sonic_tank' or T=='devastator' or T=='mcv' or T=='missile_tank_h' or T=='siege_tank_h' then ConditionRecord[tostring(producer)] =producer.GrantCondition(tostring(unit.Type)..'_ICO') end elseif producer.Type == 'high_tech_factory' then if T=='carryall' or T=='light_thopter' then ConditionRecord[tostring(producer)] =producer.GrantCondition(tostring(unit.Type)..'_ICO') end elseif producer.Type == 'starport' then if T=='carryall.starport' or T=='harvester.starport' or T=='combat_tank_m.starport' or T=='missile_tank.starport' or T=='siege_tank.starport' or T=='trike.starport' or T=='quad.starport' or T=='mobile_crane.starport' then ConditionRecord[tostring(producer)] =producer.GrantCondition(string.sub(tostring(unit.Type),1,-10)..'_ICO') end end end function replace_silos(player) local res = player.Resources for _, actor in pairs(player.GetActorsByType("silo")) do local loc=actor.Location actor.Destroy() Actor.Create("advanced_silo", true, { Owner = player, Location = loc }) end --give the game time to contemplate consequences of rapid player.ResourceCapacity changes, then correct. Trigger.AfterDelay(DateTime.Seconds(0.1), function() player.Resources = res end ) end function dropAirReinforcements(location,dummy) local squad if dummy.Type=="waypoint_dummy_a" then squad=1 elseif dummy.Type=="waypoint_dummy_h" then squad=2 elseif dummy.Type=="waypoint_dummy_o" then squad=3 end --Carryall reinforcements local base = dummy.Owner.GetActorsByType("outpost")[1] local edge = getMapEdge(base.Location, location) local path = {edge,location} local units = Reinforcements.ReinforceWithTransport(dummy.Owner, "carryall.controllable", ReinforcementSquads[squad], path, {path[2], path[1]}) local carryall = units[1] Trigger.OnPassengerExited(carryall, function(carry, pass) if not carry.HasPassengers then carry.Move(path[1]) carry.Destroy() end end ) end function getMapEdge(posB,posA) local bnds = {} bnds.Top=(Map.TopLeft.Y)/1024 bnds.Bottom=(Map.BottomRight.Y+1)/1024 bnds.Left=(Map.TopLeft.X)/1024 bnds.Right=(Map.BottomRight.X+1)/1024 --catch zero devision errors if posB.X-posA.X == 0 then if posB.Y<posA.Y then return CPos.New(posA.X,bnds.Top) else return CPos.New(posA.X,bnds.Bottom) end elseif posB.Y-posA.Y == 0 then if posB.X<posA.X then return CPos.New(bnds.Left,posA.Y) else return CPos.New(bnds.Right,posA.Y) end end --compute all boundary intersections local slope = (posB.Y-posA.Y)/(posB.X-posA.X) local topX = posA.X - (posA.Y-bnds.Top)/slope local bottomX= posA.X + (bnds.Bottom-posA.Y)/slope local rightY = posA.Y + (bnds.Right-posA.X)*slope local leftY = posA.Y - (posA.X-bnds.Left)*slope local top = CPos.New(math.floor(topX),bnds.Top) local bottom = CPos.New(math.floor(bottomX),bnds.Bottom) local right = CPos.New(bnds.Right, math.floor(rightY)) local left = CPos.New(bnds.Left, math.floor(leftY)) --decide which of them is reasonable local positiveDelX = 0 < (posB.X-posA.X) local positiveSlope= 0 < slope if positiveDelX and positiveSlope then if bottom.X<=bnds.Right then return bottom else return right end elseif positiveDelX and not positiveSlope then if top.X<=bnds.Right then return top else return right end elseif not positiveDelX and positiveSlope then if top.X>=bnds.Left then return top else return left end elseif not positiveDelX and not positiveSlope then if bottom.X>=bnds.Left then return bottom else return left end end Media.DisplayMessage(" in Function getMapEdge, no Edge matched, returning default. (0,0)","Error") return CPos.New(0,0) end