Units - Ranged Pillage

whoward69

DLL Minion
Joined
May 30, 2011
Messages
8,699
Location
Near Portsmouth, UK
Late era ranged units can bombard tiles and "pillage" them.

Battleships, Bombers, Artillery and Guided Missiles will "pillage" improvements and routes (for no gold)

Missile Cruisers, Stealth Bombers and Rocket Artillery in addition to "pillaging" the improvement/route also have a chance to destroy the improvement/route if it has already been pillaged.

While this mod is functional, it really serves as a basis for further development as there is no logic for the AI to use these type of attacks, and there are also several unresolved special cases - should it be as easy to pillage a citadel as a fort as a farm?

Mod can be downloaded from my web site, it requires v94 or later of my DLL
 
Thank you for this mod component of yours, I've found it very useful. However, is there any chance to make this work without DLL?
 
It's reliant on new GameEvents added in the DLL, so no.
 
wow nice!! i miss tile bombing from civ 3. so weird i just saw a thread talking about that and i googled to see if someone had made a mod for it yet.

compatible with CP/VP?
 
I'm using this mod + VP (which should include the DLL functions), but this improvement doesn't seem to be attackable:

20210307223511_1.jpg


What am I doing wrong?
 
Are you sure VP has my V94 events
 
Don't know then. Does the same setup up work with DLL-VMC?
 
I didn't get to make those mods work together, as I felt there was a better chance of trying to get the ranged pillaging outright integrated into VP - which would also require proper AI.

That being said, you can always try and promote my feature request :)
i don't think it'll get incorporated, i don't think there's anyway to teach the AI how to use it really. but it should definitely be made an optional compatible modmod imo. but oh well, i'm going to learn coding this year at uni so maybe i'll figure it out in a years time or so lol xD
 
Late era ranged units can bombard tiles and "pillage" them.

Battleships, Bombers, Artillery and Guided Missiles will "pillage" improvements and routes (for no gold)

Missile Cruisers, Stealth Bombers and Rocket Artillery in addition to "pillaging" the improvement/route also have a chance to destroy the improvement/route if it has already been pillaged.

While this mod is functional, it really serves as a basis for further development as there is no logic for the AI to use these type of attacks, and there are also several unresolved special cases - should it be as easy to pillage a citadel as a fort as a farm?

Mod can be downloaded from my web site, it requires v94 or later of my DLL
Is this supposed to work without a war declaration? I can attack any tiles of other civs without consequences.
Also, I can attack my own tiles, so once I accidentally destroyed an airbase with 3 stealth bombers in it :D
Will there be some new version of the mod?
 
As the first implies, it's more of a proof of concept mod than something to be used in game, but it's easy enough to fix those two issues.

Code:
    local iRangedPillage = pUnitInfo.RangedPillage
    local iPlotPlayer = pPlot:GetOwner()
   
    if (iPlotPlayer == iPlayer) then
      -- Don't pillage our own stuff!
      return false
    elseif (iPlotPlayer ~= -1) then
      -- Are we at war with the plot owner
      return Teams[pPlayer:GetTeam()]:IsAtWar(Players[iPlotPlayer]:GetTeam())
    end

    if (pPlot:GetImprovementType() ~= -1) then
 
Last edited:
As the first implies, it's ore of a proof of concept mod than something to be used in game, but it's easy enough to fix those two issues.

Code:
    local iRangedPillage = pUnitInfo.RangedPillage
    local iPlotPlayer = pPlot:GetOwner()
  
    if (iPlotPlayer == iPlayer) then
      -- Don't pillage our own stuff!
      return false
    elseif (iPlotPlayer ~= -1) then
      -- Are we at war with the plot owner
      return Teams[pPlayer:GetTeam()]:IsAtWar(Players[iPlotPlayer]:GetTeam())
    end

    if (pPlot:GetImprovementType() ~= -1) then
Thank you.
I've never created or modified mods, so please correct me if I'm wrong.
In the previous version of the code the line
Code:
if (pPlot:GetImprovementType() ~= -1) then
was reached every time, but now it will be reached only if tile has no owner.
Won't it cause troubles with the AI behavior since in the code below we're returning pPlayer:IsHuman() ?
Maybe it should be like this?
Code:
    local iRangedPillage = pUnitInfo.RangedPillage
    local iPlotPlayer = pPlot:GetOwner()
   
    if (iPlotPlayer == iPlayer or iPlotPlayer ~= -1 and not Teams[pPlayer:GetTeam()]:IsAtWar(Players[iPlotPlayer]:GetTeam())) then
      return false
    end
   
    if (pPlot:GetImprovementType() ~= -1) then
 
It should be
Code:
    local iRangedPillage = pUnitInfo.RangedPillage
    local iPlotPlayer = pPlot:GetOwner()
    
    if (iPlotPlayer == iPlayer) then
      -- Don't pillage our own stuff!
      return false
    elseif (iPlotPlayer ~= -1) then
      -- Need to be at war with the plot owner
      if (not Teams[pPlayer:GetTeam()]:IsAtWar(Players[iPlotPlayer]:GetTeam())) then
        return false
      end
    end

    if (pPlot:GetImprovementType() ~= -1) then

The event is only called if the standard code doesn't allow a ranged attack on the tile - so if there's an enemy unit/city on the tile we never get to this event.

pPlayer:IsHuman() is use to block the AI attacking these extra tiles, as it would have no idea how to do this strategically and would just waste attacks on trrops bombarding farms et al
 
It should be
Code:
    local iRangedPillage = pUnitInfo.RangedPillage
    local iPlotPlayer = pPlot:GetOwner()
   
    if (iPlotPlayer == iPlayer) then
      -- Don't pillage our own stuff!
      return false
    elseif (iPlotPlayer ~= -1) then
      -- Need to be at war with the plot owner
      if (not Teams[pPlayer:GetTeam()]:IsAtWar(Players[iPlotPlayer]:GetTeam())) then
        return false
      end
    end

    if (pPlot:GetImprovementType() ~= -1) then

The event is only called if the standard code doesn't allow a ranged attack on the tile - so if there's an enemy unit/city on the tile we never get to this event.

pPlayer:IsHuman() is use to block the AI attacking these extra tiles, as it would have no idea how to do this strategically and would just waste attacks on trrops bombarding farms et al
This code is logically equal to the code I provided above, since if inside the elseif can be simplified to a single elseif, but then we have if and elseif that return the same value, so it can be simplified to the single if expression.
 
Also, I found it a bit overpowered to use Guided Missile multiple times to pillage tiles, since the game itself describes it as "a one-shot unit which is destroyed when it attacks an enemy target", especially when combined with mod 'Units - Missiles No Supply'. So I changed the code so it would be destroyed after pillaging as well as after an attack on an enemy unit.

So if anyone's interested, I'm adding updated code that in conclusion results in the next differences from the initial version:
1. Player can't pillage own tiles
2. Player can't pillage another civilization's or city-state's tiles if he's not at war with them (but still can pillage tiles that have no owner)
3. Guided Missiles are destroyed after pillaging as well as after the usual ranged attack

Thanks @whoward69 for the help.

UnitsRangedPillage.sql
SQL:
ALTER TABLE Units ADD RangedPillage INTEGER DEFAULT 0;

UPDATE Units SET RangedPillage=1 WHERE Class IN ('UNITCLASS_BATTLESHIP', 'UNITCLASS_BOMBER', 'UNITCLASS_ARTILLERY');
UPDATE Units SET RangedPillage=2 WHERE Class IN ('UNITCLASS_MISSILE_CRUISER', 'UNITCLASS_STEALTH_BOMBER', 'UNITCLASS_ROCKET_ARTILLERY');
UPDATE Units SET RangedPillage=3 WHERE Class IN ('UNITCLASS_GUIDED_MISSILE');

UPDATE CustomModOptions SET Value=1 WHERE Name='EVENTS_UNIT_RANGEATTACK';

UnitsRangedPillage.lua
Code:
print("This is the 'Units - Ranged Pillage' mod script.")

function OnUnitCanRangeAttackAt(iPlayer, iUnit, iX, iY, bNeedWar)
  local pPlayer = Players[iPlayer]
  local pUnit = pPlayer:GetUnitByID(iUnit)
  local pUnitInfo = GameInfo.Units[pUnit:GetUnitType()]

  if (pUnitInfo.RangedPillage > 0) then
    local pPlot = Map.GetPlot(iX, iY)
    local iRangedPillage = pUnitInfo.RangedPillage
    local iPlotPlayer = pPlot:GetOwner()
    
    if (iPlotPlayer == iPlayer or iPlotPlayer ~= -1 and not Teams[pPlayer:GetTeam()]:IsAtWar(Players[iPlotPlayer]:GetTeam())) then
      return false
    end

    if (pPlot:GetImprovementType() ~= -1) then
      print(string.format("%s can range pillage the improvement at (%i, %i)", pUnit:GetName(), iX, iY))

      if (iRangedPillage > 1 or not pPlot:IsImprovementPillaged()) then
        -- TODO - for an AI player, does this unit want to pillage the tile?  This opens a whole can of worms!
        return pPlayer:IsHuman();
      end
    elseif (pPlot:IsRoute()) then
      print(string.format("%s can range pillage the route at (%i, %i)", pUnit:GetName(), iX, iY))

      if (iRangedPillage > 1 or not pPlot:IsRoutePillaged()) then
        -- TODO - for an AI player, does this unit want to pillage the tile?  This opens a whole can of worms!
        return pPlayer:IsHuman();
      end
    end
  end

  return false;
end
GameEvents.UnitCanRangeAttackAt.Add(OnUnitCanRangeAttackAt)

function OnUnitRangeAttackAt(iPlayer, iUnit, iX, iY)
  local pUnit = Players[iPlayer]:GetUnitByID(iUnit)
  local pPlot = Map.GetPlot(iX, iY)

  print(string.format("%s is range pillaging the tile at (%i, %i)", pUnit:GetName(), iX, iY))

  -- Doesn't matter how strong the attacking units RangedPillage is, we can always pillage a functioning improvement/route
  -- Four options for the tile - improvement, pillaged improvement, route, pillaged route
  if (pPlot:GetImprovementType() ~= -1 and not pPlot:IsImprovementPillaged()) then
    -- Non-pillaged improvement, at the very least, pillage it
    pPlot:SetImprovementPillaged(true)
  elseif (pPlot:IsRoute() and not pPlot:IsRoutePillaged()) then
    -- Non-pillaged route, at the very least, pillage it
    pPlot:SetRoutePillaged(true)
  end

  -- Can the attacking unit destroy the improvement/route?
  local pUnitInfo = GameInfo.Units[pUnit:GetUnitType()]
  local iRangedPillage = pUnitInfo.RangedPillage

  if (iRangedPillage > 1) then
    if (Game.Rand(100, "Ranged Pillage") <= (pUnitInfo.RangedCombat / 5)) then
      if (pPlot:GetImprovementType() ~= -1) then
        pPlot:SetImprovementType(-1)
      elseif (pPlot:IsRoute()) then
        pPlot:SetRouteType(-1)
      else
        -- How the heck did we get here?
      end
    end
  end
 
  if (iRangedPillage == 3) then
    pUnit:Kill(true, -1)
  end

  return 1;
end
GameEvents.UnitRangeAttackAt.Add(OnUnitRangeAttackAt)
 
So if anyone's interested, I'm adding updated code that in conclusion results in the next differences from the initial version:
1. Player can't pillage own tiles
2. Player can't pillage another civilization's or city-state's tiles if he's not at war with them (but still can pillage tiles that have no owner)
3. Guided Missiles are destroyed after pillaging as well as after the usual ranged attack
Feel free to attach the complete mod-mod (or publish it elsewhere as my ToU is very open) and not just the code changes, that way it's easier for others to just use the mod
 
Top Bottom