Making a UA like Civ 6's Venetian Arsenal

Cloudy

Chieftain
Joined
Mar 23, 2017
Messages
8
Basically, I want so that when a naval unit is built, a second one is produced for free, effectively getting two for one like the Venetian Arsenal's bonus in Civ VI. Only problem, I've not a clue where I can start for this, AFAIK there is not a UA like this, nor anything like it in Civ V. Another condition if possible is to have the ability only active during peacetime. If anyone can give me any advice on how I should approach this, if at all possible, that would be great thanks!
 
You can do this using Lua!

First you need a hook that fires when a unit is trained in a city:
Code:
function myfunction(iPlayer,iCity,iUnit,bGold,bFaithOrCulture)
     --do the stuff here
end

GameEvents.CityTrained.Add(myfunction) --this is the actual hook ('CityTrained')
And some more methods to actually spawn the unit and check if it's naval before the actual spawn:
Code:
pPlayer:InitUnit(iUnitType,iX,iY) --returns pUnit of the newly created unit
pUnit:GetDomainType() --returns GameInfoTypes.DOMAIN_SOMETHING


----
I am a bit in a rush right now, and I will update this post somewhere tonight if that's necessary.


----
EDIT:
The first thing I usually ask myself when making a component is "what Lua trickery might be useful to achieve what I want to do". (This assumes of course that I already know that I want/need to use Lua)
In your case there are 5 (main) things:
- Something that tells me whenever a unit is trained in a city. Generally, this 'whenever' implies that we should use a Lua hook.
- Something that tells me if the unit is naval
- Something that spawns a unit
- Since we want a UA, we need something that checks the civilizationtype of a player.
- Check if a player is at war

Using the Whoward's Lua API reference, the modwiki, older projects of mine, and other general snippets on civfanatics I have found these things:
- GameEvents.CityTrained.Add(iPlayer,iCity,iUnit,bGold,bFaithOrCulture) is a hook that fires whenever a unit is trained or bought (using gold or faith) in a city.
- pUnit:GetDomainType() returns the domain of a unit (GameInfoTypes.DOMAIN_SEA for naval units) (pUnit:GetUnitCombatType() could've also worked, though we'd need more comparisons for the same functionality as checking the unit domain)
- pPlayer:InitUnit(iUnitType,iX,iY) spawns a unit. It returns pUnit of the newly created unit
- pPlayer:GetCivilizationType() returns the Civilizationtype of pPlayer in the form of GameInfoTypes.CIVILIZATION_SOMETHING
- pTeam:IsAtWar(iTeam) checks if pTeam is at war with iTeam. Since we will need to check if the player is at war with any team that are not barbarians (as you are always at war with those), we will also need to iterate over all the teams:
Code:
function IsAtWarWithAnyone(pPlayer)
     local pTeam = Teams[pPlayer:GetTeam()]
     for iOtherTeam = 0, GameDefines.MAX_CIV_TEAMS-1 do
          if pTeam:IsAtWar(iOtherTeam) then
                return true
           end
     end
     return false;
end


Combining these elements into one piece of code grants us this:
Code:
print("MyLuaFileNameHere.lua was loaded!")
local iCiv = GameInfoTypes.CIVILIZATION_FREE_NAVAL_CIV
local iDomainSea = GameInfoTypes.DOMAIN_SEA

function NavalBuyOneGetTwo(iPlayer,iCity,iUnit) --since we do not care about bGold and bFaithOrCulture we can just omit them
     local pPlayer = Players[iPlayer]
     if pPlayer:GetCivilizationType() == iCiv then --is the player playing as the required civilization?
         local pUnit = pPlayer:GetUnitByID(iUnit)
         local pCity = pPlayer:GetCityByID(iCity)
          print("Player "..iPlayer.." is playing as The-Free-Naval-Civ and just trained a unit in "..pCity:GetName().."!")
          if pUnit and pUnit:GetDomainType() == iDomainSea and (not IsAtWarWithAnyone(pPlayer)) then --is the trained/bought unit a naval unit? + Is the player at war?
                print("The trained unit is a naval unit!")
                pPlayer:InitUnit(pUnit:GetUnitType(),pCity:GetX(),pCity:GetY()) --spawn the unit
                print("Another naval unit was spawned")
          else
                print("Land units don't count!")
           end
      end
end
GameEvents.CityTrained.Add(NavalBuyOneGetTwo) --make sure our function fires whenever a unit is trained/bought
 
Last edited:
Great, thanks for such a detailed response! Sorry for my late reply though.
 
Top Bottom