It is ready but not fully tested. Feel free to pick it up if you like to.
You have to modify InfantryTactic:CheckForDance() :
function InfantryTactic:CheckForDance() local stance = self.squad_ai:GetMeleeStance() --ranged squads stationary and in combat or in state of disengage if stance == SquadAI.MSTANCE_Ranged and not self.squad_ai:IsBroken() and -- not self:CommanderAttached() and ((not self.squad_ai:IsInStateMove() and self.squad_ai:IsInCombat()) or self.stateID == Tactic.StateID.DoDance) then local squad_pos = self.squad_ai:GetPosition() local strength, number = cpu_manager:DetailSquadsInVicinity( squad_pos, 30, 30, false ) local enemy_dist = 10 if self:IsCommander() then enemy_dist = 20 -- Dance even if supported well strength = 0 number = 0 elseif self.squad_ai:CanJump() then enemy_dist = 5 elseif self.squad_ai:WasRecentlyHurt() then enemy_dist = 15 end -- Less dancing at low levels local eDifficulty = cpu_manager.cpu_player:GetDifficultyLevel() if (eDifficulty == CpuPlayer.AD_Easy) then enemy_dist = enemy_dist * 0.3 elseif (eDifficulty == CpuPlayer.AD_Standard) then enemy_dist = enemy_dist * 0.6 end -- Dance infantry, commanders and vehicles local vehicle = Ability.Filters.CloseVehicleEnemy( squad_pos, enemy_dist, 1 ) local commander = Ability.Filters.CloseCommanderEnemy( squad_pos, enemy_dist, 1 ) local infantry = Ability.Filters.CloseInfantryEnemy( squad_pos, enemy_dist, 3 ) if (self:CheckDance(infantry)) then local num_own = self.squad_ai:GetNumTroopers() local num_enemy = infantry:GetNumTroopers() stance = infantry:GetMeleeStance() --don't dance if enemy is ranged or we have more than 300% troopers if stance == SquadAI.MSTANCE_Ranged or num_own > num_enemy * 3 then infantry = nil end end -- Commanders only dance commanders if self:IsCommander() then if infantry ~= nil and not infantry:IsAttached() then infantry = nil end vehicle = nil end --close combat enemy nearby and not enough support, lets dance if (( infantry ~= nil and not infantry:IsBroken() ) or ( vehicle ~= nil and not vehicle:IsRanged() and vehicle:GetHealthPercentage() > 0.1 ) or ( commander ~= nil and commander:GetHealthPercentage() > 0.1 )) and ( self.squad_ai:CanJump() or strength <= 0 or number <= 0 ) then local first_call = self.stateID == Tactic.StateID.NoState --check for safe destination if not self:MoveToDisengage() then if not first_call then self.tolerance = self.tolerance + 10 else self.tolerance = self.tolerance_default end self.squad_ai:DoMoveToClosestSafePoint( self.safe_point, self.tolerance ) end --set state local state_func, state_name = self:GetSubState() if state_func ~= self.DoDance then Tactic.SetSubState( self, self.DoDance, "DoDance" ) self.squad_ai:DoSetStance( SquadAI.STANCE_StandGround ) self.stateID = Tactic.StateID.DoDance dlg( "avd", "Start Dance: "..state_name..": "..tostring(self.squad_ai:GetID()) ) else dlg( "avd", "Continue Dance:"..tostring(self.squad_ai:GetID()) ) end cpu_manager:InsertSubState( self.squad_ai:GetID(), self.stateID ) return true end end return false end
You have to add InfantryTactic:IsCommander() :
function InfantryTactic:IsCommander() for i in self.commander do if self.squad_ai:GetStats():GetSquadName() == self.commander[i][1] then return true end end return false end
You have to add this to the farseer/sorceror tactic :
function FarSeerTactic:Update() if (self:IsComplete()) then return end local set_ranged = false local set_melee = false local squad_pos = self.squad_ai:GetPosition() local gmt = cpu_manager.cpu_player:GetGameTime() / 8 -- Check for near commander local commander1 = Ability.Filters.CloseCommanderEnemy( squad_pos, 20, 1 ) local infantry1 = Ability.Filters.CloseInfantryEnemy( squad_pos, 20, 4 ) if commander1 ~= nil or (infanty1 ~= nil and infantry1:IsAttached()) then set_ranged = true end -- Check for distant commander local commander2 = Ability.Filters.CloseCommanderEnemy( squad_pos, 35, 1 ) local infantry2 = Ability.Filters.CloseInfantryEnemy( squad_pos, 35, 4 ) if commander2 == nil and (infanty2 == nil or not infantry2:IsAttached()) then set_melee = true end if set_ranged and commander1 ~= nil then local own_health = self.squad_ai:GetHealthPercentage() local enemy_health = commander1:GetHealthPercentage() -- Reset, commander is weak and should be finished in CC if own_health > 0.8 and enemy_health < 0.3 then set_ranged = false set_melee = true self.dance_time = 0 end end -- Check current stance local stance = self.squad_ai:GetMeleeStance() -- At leat 10 secs ranged stance/dancing if set_ranged and stance == SquadAI.MSTANCE_Assault then self.squad_ai:DoSetMeleeStance( SquadAI.MSTANCE_Ranged ) self.dance_time = cpu_manager.cpu_player:GetGameTime() / 8 elseif set_melee and stance == SquadAI.MSTANCE_Ranged and self.stateID ~= Tactic.StateID.DoDance and gmt > self.dance_time + 10 then self.squad_ai:DoSetDefaultMeleeStance() self.dance_time = 0 end -- State machine if (not InfantryTactic.Update( self )) then return end -- Check new stance stance = self.squad_ai:GetMeleeStance() -- Assassinate win condition -- always attach to a squad if (cpu_manager.assassinate) then self:TryAttachAssassinate() elseif stance == SquadAI.MSTANCE_Assault then -- Do not attach while dancing if (self:TryAttachSquad(false, true, 30, nil, 0.3) == nil) then -- Attach to melee if (self:TryAttachSquad(true, true, 30, 250, nil) == nil) then self:TryAttachSquadMelee() end end end end