Jump to content


Photo

I got carpet bombing to work


26 replies to this topic

#21 Moreartillery

Moreartillery
  • Members
  • 122 posts

Posted 04 November 2019 - 12:00 AM

That works well. Can you also add a restriction for landing near enemy units?

 

Also could you add a 'minimum time between attacks' modifier which is per bomber rather then shared between all of them?

 

Finally can you write code that lets tyranids gain resources from the cannibalize action, without changing the effect for tau?



#22 Gambit

Gambit

    title available

  • Members
  • 6,320 posts
  • Location:Athens, Greece

Posted 04 November 2019 - 11:21 AM

That works well. Can you also add a restriction for landing near enemy units?

Yes, but that would make the flyovers TOO "stingy"...

There almost always will be other squads nearby.

 

Also could you add a 'minimum time between attacks' modifier which is per bomber rather then shared between all of them?

We only need to make the variable local for this (self.) :thumbsuphappy:

I will make it so today or tomorrow.

 

 

Finally can you write code that lets tyranids gain resources from the cannibalize action, without changing the effect for tau?

This requires SCaR (it is not AI) and I will have to make a new rule for that.

It is more time-consuming.

If it is really necessary, I will do it.

But most possibly at this weekend.


-In search of Papasmurf...

#23 Gambit

Gambit

    title available

  • Members
  • 6,320 posts
  • Location:Athens, Greece

Posted 05 November 2019 - 07:44 PM

OK, ready:

----------------------------------------
-- File: 'maraudertactic.ai'
-- Created by Gambit @ 02.11.2019

class 'MarauderTactic' (GuardVehicleTactic)

Marauder = {}

function MarauderTactic:__init( squad_ai ) super( squad_ai )

    self:SetName("Marauder Tactic")

    -- Modifiable Stats
    Marauder.G_Time_Between_Successive_Attacks = 0        -- If multiple bombers, do not have them attack simultaneously. Keep lower than 6, if enabled.
    self.iMinAttackTimeInterval = 16                    -- For EACH bomber, the time between successive attack (keep in mind the time each attack takes!).
    Marauder.G_Proximity_Return_Distance = 38            -- The distance from base that we deem minimum to consider the flyer is "back to base".
    Marauder.G_Max_Attacking_Range_From_Base = 280        -- The max range OF THE ENEMY, that the flyer will attempt a fly-over.
    Marauder.G_AttackInfantry = true                    -- Self-explanatory.
    Marauder.G_AttackVehicles = true                    -- Self-explanatory. If both true, target will be chosen randomly.
    Marauder.G_AttackInfiltratedUnits = false            -- Self-explanatory.
    Marauder.G_AttackOnlyUnitsWeCanSee = false            -- Self-explanatory. Experiential. Better keep it to [false].
    Marauder.G_AttackOnlyUnitsWeCanSeeRange = 35        -- If previous is true, this is the detecting range (proximity) of our nearby troops.
    Marauder.G_DoNotAttackIfEnemyBuildingsAtLandingProximity = true        -- Self-explanatory.
    Marauder.G_DoNotAttackIfEnemyBuildingsWithin = 35                    -- If the above is enabled, this is the range.
    Marauder.G_DoNotAttackIfEnemyTroopsAtLandingProximity = true        -- Self-explanatory.
    Marauder.G_DoNotAttackIfEnemyTroopsWithin = 30                        -- If the above is enabled, this is the range. The flyer will try to land far.
    Marauder.G_HQ_Name = "guard_hq"                        -- The name of the HQ of the player. It is the AE name. No need to change, for Guard.

    -- Other Stats
    self.initialPosition = self.squad_ai:GetPosition()
    Marauder.G_Proximity_Return_Distance_Sqr = Marauder.G_Proximity_Return_Distance * Marauder.G_Proximity_Return_Distance
    Marauder.G_Proximity_Return_Distance_Triangulation = Marauder.G_Proximity_Return_Distance * 0.6
    Marauder.G_NextAttackTMR = g_iGMT
    self.iAttackTMR = g_iGMT
    if Marauder.G_Update_HQsTMR == nil then
        Marauder.G_Update_HQsTMR = g_iGMT
    end
    if Marauder.G_Player_HQsPositions == nil then
        Marauder.G_Player_HQsPositions = {}
    end
end


function MarauderTactic:InitAbilities()

    --[[ Init ability ID's  / ABILITIES NO LONGER USED!
    if Marauder.smoke_id == nil then
        Marauder.smoke_id = cpu_manager.stats:GetAbilityID( "guard_smoke_bombs" )
        Marauder.krak_id = cpu_manager.stats:GetAbilityID( "guard_krak_bombs" )
        Marauder.incendiary_id = cpu_manager.stats:GetAbilityID( "guard_incendiary_bombs" )
    end]]
end


function MarauderTactic:DoAbilities()

    -- First, update HQs positions every 8 secs
    if g_iGMT > Marauder.G_Update_HQsTMR + 8 then
        Marauder.G_Update_HQsTMR = g_iGMT
        self:UpdateHQs()
    end

    -- Now check if we must return (after an attack), or we are at a base
    self.initialPosition = self.squad_ai:GetPosition()
    local must_retrun = true
    for i = 1, table.getn(Marauder.G_Player_HQsPositions) do
        if distance_sqr(Marauder.G_Player_HQsPositions[i],self.initialPosition) < Marauder.G_Proximity_Return_Distance_Sqr then
            must_retrun = false
            break
        end
    end

    if self.squad_ai:CanJump() then
        -- In case we are away from the base, return to a random valid place (HQ)
        if must_retrun then
            local all_bases = table.getn(Marauder.G_Player_HQsPositions)
            if all_bases > 0 then
                local iBasePos = Marauder.G_Player_HQsPositions[math.random(1,all_bases)]
                self:ForceSquadJumpNearBack(iBasePos)
            end
        -- We are at base. We must try to perform an attack
        else
            if g_iGMT < Marauder.G_NextAttackTMR + Marauder.G_Time_Between_Successive_Attacks
            or g_iGMT < self.iAttackTMR + self.iMinAttackTimeInterval then
                return
            end
            local iEnemySquadInf = nil
            local iEnemySquadVeh = nil
            local iEnemySquad = nil
            if Marauder.G_AttackInfantry then
                iEnemySquadInf = Ability.Filters.CloseInfantryEnemy(self.initialPosition, Marauder.G_Max_Attacking_Range_From_Base, 5)
                --cpu_manager.cpu_player:FindFirstInfantryEnemy(self.initialPosition, Marauder.G_Max_Attacking_Range_From_Base, 5)
            end
            if Marauder.G_AttackVehicles then
                iEnemySquadVeh = Ability.Filters.CloseVehicleEnemy(self.initialPosition, Marauder.G_Max_Attacking_Range_From_Base, 1)
                --cpu_manager.cpu_player:FindFirstVehicleEnemy(self.initialPosition, Marauder.G_Max_Attacking_Range_From_Base, 1)
            end
            if iEnemySquadInf ~= nil and iEnemySquadVeh ~= nil then
                if math.random(1,2) == 1 then
                    iEnemySquad = iEnemySquadInf
                else
                    iEnemySquad = iEnemySquadVeh
                end
            elseif iEnemySquadInf ~= nil and iEnemySquadVeh == nil then
                iEnemySquad = iEnemySquadInf
            else
                iEnemySquad = iEnemySquadVeh
            end
            if iEnemySquad ~= nil then
                if Marauder.G_AttackInfiltratedUnits or (not iEnemySquad:IsInfiltrating()) then
                    local iEnemyPos = iEnemySquad:GetPosition()
                    if (not Marauder.G_AttackOnlyUnitsWeCanSee) or self:WeCanSeePos(iEnemyPos) then
                        -- Do NOT perform a flyover, if we have our troops nearby!
                        if cpu_manager.cpu_player:FindFirstHurtSquad( iEnemyPos, 6 ) == nil then
                            self:ForceSquadAttackJumpNear(iEnemyPos)
                            Marauder.G_NextAttackTMR = g_iGMT
                        end
                    end
                end
            end
        end
    end

    --[[ Check if we can deploy smoke / ABILITIES NO LONGER USED!
    if (self.squad_ai:CanDoAbility(Marauder.smoke_id)) then
    
        -- Search a squad
        local iRange = self.squad_ai:GetAbilityRange(Marauder.smoke_id)
        local oUnit = Ability.Filters.CloseHurt(self.squad_ai:GetPosition(), iRange, 1)
        if (oUnit ~= nil and oUnit:IsInCombat() and cpu_manager:GetUnitStrength(oUnit) > 150) then
            self.squad_ai:DoSpecialAbilitySquad(Marauder.smoke_id, oUnit:GetSquad())
        end
    end
    -- Check if we're in close combat - Krak
    local oEnemySquad = Ability.Filters.CloseVehicleEnemy(self.squad_ai:GetPosition(), 0, 1)
    if (oEnemySquad ~= nil) then
    
        -- Check if we can drop Krak Bombs
        if (self.squad_ai:CanDoAbility(Marauder.krak_id)) then
            self.squad_ai:DoSpecialAbility(Marauder.krak_id)
        end
    end
    -- Check if we're in close combat - Incendiary
    oEnemySquad = Ability.Filters.CloseInfantryEnemy(self.squad_ai:GetPosition(), 0, 5)
    if (oEnemySquad ~= nil and not oEnemySquad:IsBroken()) then
    
        -- Check if we can drop Incendiary Bombs
        if (self.squad_ai:CanDoAbility(Marauder.incendiary_id)) then
            self.squad_ai:DoSpecialAbility(Marauder.incendiary_id)
        end
    end]]
    --[[ Checks jump-able stuck squads, and force them to jump nearby / NO LONGER USED!
    if self.squad_ai:CanJump() then
        self:SolveStuckCase()
    end]]
end


function MarauderTactic:UpdateHQs()
    Marauder.G_Player_HQsPositions = {}
    for oBuilding in military_manager:GetBases() do
        if (oBuilding:IsValid() and oBuilding:GetBaseName() == Marauder.G_HQ_Name) then
            table.insert(Marauder.G_Player_HQsPositions,oBuilding:GetPosition())
        end
    end
end


-- Unstuck Code --------------------------------------------------
function MarauderTactic:SolveStuckCase()
    local iPosition = self.squad_ai:GetPosition()
    if iPosition.x ~= self.initialPosition.x or iPosition.z ~= self.initialPosition.z then
    -- NOT stuck, update previous position and return, we are all good
        self.initialPosition = iPosition
        return
    end

    -- If we got here, the squad is NOT moving. See if it is simply waiting, or is stuck!
    local state = self.squad_ai:GetTactic():GetState()
    if (self.squad_ai:IsInStateMove() or self.squad_ai:IsInStateAttackMove() or state == "Attack") and not self.squad_ai:IsInCombat()
    and iPosition.x == self.initialPosition.x and iPosition.z == self.initialPosition.z then
    -- STUCK!!!!! Run the unstuck code
        self:ForceSquadJumpNear(iPosition)
    end
    -- Update previous position anyway
    self.initialPosition = self.squad_ai:GetPosition()
end

function MarauderTactic:ForceSquadJumpNear(pos)
    local iPos = self.squad_ai:GetPosition()
    local vJumpPosition = self.squad_ai:GetPosition()
    local jumpDist = self.squad_ai:GetJumpDistance()
    local jumpDistSqr = jumpDist * jumpDist
    local vDir = cpu_manager:GetDirectionToEnemy(pos)
    -- First, try an unstuck jump TOWARDS the enemy
    -- Try to jump somewhere near, perform 30 checks in total, for a viable position
    for i = 1, 12 do
        -- Create a jump position
        vJumpPosition.x = pos.x + vDir.x * math.random(10, jumpDist)
        vJumpPosition.z = pos.z + vDir.z * math.random(10, jumpDist)
        -- Check if target position is in range and if unit is able to jump to target position
        local iDistanceSqr = distance_sqr(vJumpPosition, iPos)
        if iDistanceSqr < jumpDistSqr and self.squad_ai:CanJumpToPosition(vJumpPosition) then
            -- Jump to position
            self.squad_ai:DoJump(vJumpPosition)
            self.last_jump = g_iGMT
            self.m_iLastGatherMove = self.last_jump - 10
            return
        end
    end
    -- Then try any random nearby place, as a secondary option
    for i = 1, 18 do
        -- Create a jump position
        vJumpPosition.x = pos.x + 0.7 * math.random(-jumpDist, jumpDist)
        vJumpPosition.z = pos.z + 0.7 * math.random(-jumpDist, jumpDist)
        -- Check if target position is in range and if unit is able to jump to target position
        local iDistanceSqr = distance_sqr(vJumpPosition, iPos)
        if iDistanceSqr < jumpDistSqr and self.squad_ai:CanJumpToPosition(vJumpPosition) then
            -- Jump to position
            self.squad_ai:DoJump(vJumpPosition)
            self.last_jump = g_iGMT
            self.m_iLastGatherMove = self.last_jump - 10
            return
        end
    end
end


function MarauderTactic:ForceSquadJumpNearBack(pos)
    local iPos = self.squad_ai:GetPosition()
    local vJumpPosition = self.squad_ai:GetPosition()
    local jumpDist = self.squad_ai:GetJumpDistance()
    local jumpDistSqr = jumpDist * jumpDist
    local vDir = cpu_manager:GetDirectionToEnemy(pos)
    -- Try to jump somewhere near, perform 15 checks in total, for a viable position, AWAY from the enemy
    for i = 1, 15 do
        -- Create a jump position
        vJumpPosition.x = pos.x - vDir.x * math.random(4, Marauder.G_Proximity_Return_Distance_Triangulation)
        vJumpPosition.z = pos.z - vDir.z * math.random(4, Marauder.G_Proximity_Return_Distance_Triangulation)
        -- Check if target position is in range and if unit is able to jump to target position
        local iDistanceSqr = distance_sqr(vJumpPosition, iPos)
        if iDistanceSqr < jumpDistSqr and self.squad_ai:CanJumpToPosition(vJumpPosition) then
            -- Jump to position
            self.squad_ai:DoJump(vJumpPosition)
            --self.last_jump = g_iGMT
            --self.m_iLastGatherMove = self.last_jump - 10
            return
        end
    end
end


function MarauderTactic:ForceSquadAttackJumpNear(pos)
    local vJumpPosition = self.squad_ai:GetPosition()
    local jumpDist = self.squad_ai:GetJumpDistance()
    local jumpDistSqr = jumpDist * jumpDist    
    local ix = 0; local iz = 0;
    if sqr(pos.x-vJumpPosition.x) < 0.0001 then
        iz = 1
    else
        local a = (pos.z-vJumpPosition.z)/(pos.x-vJumpPosition.x)
        ix = math.sqrt(1/(sqr(a) + 1))
        iz = math.abs(a*ix)
    end
    if vJumpPosition.x > pos.x then ix = -1*ix end
    if vJumpPosition.z > pos.z then iz = -1*iz end
    -- Try to jump somewhere near, perform 10 checks in total, for a viable position
    local rndm = math.random(20, 30)
    for i = 1, 10 do
        -- Create a jump position
        if Marauder.G_DoNotAttackIfEnemyTroopsAtLandingProximity then
            rndm = rndm + 4
        else
            rndm = math.random(25, 40)
        end
        vJumpPosition.x = pos.x + ix*rndm
        vJumpPosition.z = pos.z + iz*rndm
        -- Check if target position is in range and if unit is able to jump to target position
        local iDistanceSqr = distance_sqr(vJumpPosition, self.initialPosition)
        if iDistanceSqr < jumpDistSqr and self.squad_ai:CanJumpToPosition(vJumpPosition) then
            local perform_the_attack = true
            if Marauder.G_DoNotAttackIfEnemyBuildingsAtLandingProximity then
                -- Do NOT attempt the jump, if we are to land near enemy buildings!
                local iBuilding =  Ability.EntityFilters.CloseBaseEntityEnemy(vJumpPosition, Marauder.G_DoNotAttackIfEnemyBuildingsWithin, 1)
                if iBuilding ~= nil then perform_the_attack = false end
            end
            if perform_the_attack and Marauder.G_DoNotAttackIfEnemyTroopsAtLandingProximity then
                -- Do NOT attempt the jump, if we are to land near enemy troops!
                local iSquad =  Ability.Filters.CloseEnemy(vJumpPosition, Marauder.G_DoNotAttackIfEnemyTroopsWithin, 3)
                if iSquad ~= nil then perform_the_attack = false end
            end
            -- Now, Jump to position, if we must
            if perform_the_attack then
                self.squad_ai:DoJump(vJumpPosition)
                self.iAttackTMR = g_iGMT
                --self.last_jump = g_iGMT
                --self.m_iLastGatherMove = self.last_jump - 10
                return
            end
        end
    end
end


function MarauderTactic:WeCanSeePos(iPos)
    local iRangeSqr = Marauder.G_AttackOnlyUnitsWeCanSeeRange * Marauder.G_AttackOnlyUnitsWeCanSeeRange
    for oUnit in military_manager:GetSquads() do
        if oUnit:IsValid() then
            if distance_sqr(oUnit:GetPosition(),iPos) < iRangeSqr then
                return true
            end
        end
    end
    return false
end

I added/coded both requests.

Now that code is VERY nasty!!! See the variables and modify the accordingly.

The additions:
1] Each flyer will have its own Timer between successive attacks. I have set it at self.iMinAttackTimeInterval = 16.

But 16 is TOO small, because we must also count the time each attack requres fr the flyer!! I would set it to 30.

2] I wrote a very agressive code, so that the flyers WILL NOT land near enemies. And it proved to be more effeicient that the previous itteration!! In short, it check for laning possitions even FAR AFTER the enemy it flyes over. This is the Marauder.G_DoNotAttackIfEnemyTroopsAtLandingProximity, by the way.

 

Sorry for the delay, it was/is a very busy week.

 

 

EDIT: If we are striving for perfection, I think we can squeeze some more nastiness from the code.

Specifically, from the point where the flyers WON'T land if enemy buildings are nearby.

In this case, I can allow it to STILL LAND, if the enemy buildings have no weapons  :twisted: 

This will require much CPU horsepower, however.

And it involves the usage of the HasWeapons() function, that I have only seen it working on LPs, and NOT "every" building... But I do not see why it shouldn't.

Anyway, just saying...


Edited by Gambit, 05 November 2019 - 07:52 PM.

-In search of Papasmurf...

#24 Moreartillery

Moreartillery
  • Members
  • 122 posts

Posted 06 November 2019 - 07:30 AM

I've been trying different settings with your latest code and having some issues with consistency, I've seen them land too close to stormboys and the ork listing post, but keep their distance from other buildings. I'm testing with G_AttackOnlyUnitsWeCanSee = false

 

It seems like the building proximity works about 3/4s of the time.


Edited by Moreartillery, 06 November 2019 - 07:49 AM.


#25 Gambit

Gambit

    title available

  • Members
  • 6,320 posts
  • Location:Athens, Greece

Posted 06 November 2019 - 11:12 AM

For the Stormboys, I suppose their squad would be a couple of member only, because the code ignore squads with 2 members or less.

You can change it, if you set the:

local iSquad =  Ability.Filters.CloseEnemy(vJumpPosition, Marauder.G_DoNotAttackIfEnemyTroopsWithin, 3)

to

local iSquad =  Ability.Filters.CloseEnemy(vJumpPosition, Marauder.G_DoNotAttackIfEnemyTroopsWithin, 1)

 

Also note that jumping squads tend to scatter around, so their actual position may be differemt than it seems.

To counter this, increase the Marauder.G_DoNotAttackIfEnemyTroopsWithin from 30 to 40.

 

 

 

As for landing near LPs... Hmmm... The logic of the code is consistent.

But I do not know with 100% certainty if the function call of Ability.EntityFilters.CloseBaseEntityEnemy, DOES include LPs...

Are you OK with how it is now?

Because it will need MORE lines to check for LPs as well.

And I do not have time to do it at the moment...


-In search of Papasmurf...

#26 Moreartillery

Moreartillery
  • Members
  • 122 posts

Posted 06 November 2019 - 08:40 PM

Its ok as is. I was just hoping to hide the turnaround beyond LOS because its unrealistic for bombers to land behind enemy lines. If its too much work you could do the tyranids scar instead. Theres no rush, I'm still at least month from releasing the tyranids update.



#27 Gambit

Gambit

    title available

  • Members
  • 6,320 posts
  • Location:Athens, Greece

Posted 07 November 2019 - 12:08 PM

I was just hoping to hide the turnaround beyond LOS because its unrealistic for bombers to land behind enemy lines.

Since they fly, they can see what is behind and land accordingly. I think it is quite realistic, really (all things considered).

 

If its too much work you could do the tyranids scar instead. Theres no rush, I'm still at least month from releasing the tyranids update.

The Tyranids SCaR will take a while. My schedule is more than full at the moment brother - just as I said previously.

But by all means, PM me with the specifics of the code (for example, which resource you want to increase when devouring, and by how much, and if it is squad size dependent). Etc.


-In search of Papasmurf...



Reply to this topic



  


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users