Craig_Sutter
Deity
The following code works and is tied to a PlayerDoTurn event.
There is also a CityCanTrain function that occurs that restricts this function somewhat. It restricts the training of said unit to 1 for every 2 cities. A separate function also deducts the cost from faith and refunds the gold of said unit... in effect, the unit is bought with faith. That function checks that the player's faith is greater than the gold cost.
This results as expected. Units are purchased with gold and are restricted by the CityCanTrain function as expected... and faith is deducted in the right amounts. The problem is that the function below seems to be ignoring the faith adjustments done by the other function, and will purchase as many units as CityCanTrain will allow, regardless of the faith check in the code below and in the CityCanTrain function. It seems as if the deductions from faith occur after the function fires in total, and not incrementally as each city purchases a unit. Players will go into negative faith to purchase all units available in one turn.
I need to adjust the function below somehow. The CityCanTrain function does not allow a human player to buy a unit if the faith requirements are not met, so the problem must be in the set up below... which, when finished, will only fire for AI players (as you can see from the commented out bit...)
If there is no way to easily stop the player going into negative faith, I would prefer they be restricted to purchasing one unit per turn instead... hence, the code needs to be fixed to check faith prior to every unit being purchased or a BREAK needs to be inserted to stop cycling through the cities upon one unit being built.
I include the CityCanTrain and Religious Cost functions for completeness... although they are working as expected for the human player. And they include code governing a lot of other units...
Thank-you for your help.
There is also a CityCanTrain function that occurs that restricts this function somewhat. It restricts the training of said unit to 1 for every 2 cities. A separate function also deducts the cost from faith and refunds the gold of said unit... in effect, the unit is bought with faith. That function checks that the player's faith is greater than the gold cost.
This results as expected. Units are purchased with gold and are restricted by the CityCanTrain function as expected... and faith is deducted in the right amounts. The problem is that the function below seems to be ignoring the faith adjustments done by the other function, and will purchase as many units as CityCanTrain will allow, regardless of the faith check in the code below and in the CityCanTrain function. It seems as if the deductions from faith occur after the function fires in total, and not incrementally as each city purchases a unit. Players will go into negative faith to purchase all units available in one turn.
I need to adjust the function below somehow. The CityCanTrain function does not allow a human player to buy a unit if the faith requirements are not met, so the problem must be in the set up below... which, when finished, will only fire for AI players (as you can see from the commented out bit...)
If there is no way to easily stop the player going into negative faith, I would prefer they be restricted to purchasing one unit per turn instead... hence, the code needs to be fixed to check faith prior to every unit being purchased or a BREAK needs to be inserted to stop cycling through the cities upon one unit being built.
Code:
-- To spawn a BerserkerWarrior in AI player city and deduct purchase price while adding promotion and experience from city.
function ForceBerserkerWarriorPurchase (iPlayer)
for iPlayer=0, GameDefines.MAX_CIV_PLAYERS - 1 do
local pPlayer = Players[iPlayer]
if pPlayer:IsAlive () and pPlayer:GetNumCities() >= 1 then --and not pPlayer:IsHuman() then
for pCity in pPlayer:Cities() do
local pUnit = GameInfoTypes["UNIT_BERSERKER_WARRIOR"]
local cost = pCity:GetUnitPurchaseCost(pUnit)
local currentFaith = pPlayer:GetFaith()
local pPlot = pCity:Plot()
local iPromotion
local iActiveUnit
local ActiveUnit
-- determine if Player can purchase BerserkerWarrior in city and has enough gold then spawn and deduct gold
if (pCity:IsCanPurchase(true, true, pUnit, -1, -1, YieldTypes.YIELD_GOLD)) and currentFaith >= cost then
local SpawnUnit;
local iSpawnX = pPlot:GetX();
local iSpawnY = pPlot:GetY();
-- spawn the unit and deduct gold
SpawnUnit = pPlayer:InitUnit(GameInfoTypes["UNIT_BERSERKER_WARRIOR"], iSpawnX, iSpawnY, UNITAI_ATTACK, DIRECTION_NORTHWEST )
SpawnUnit:SetExperience(pCity:GetDomainFreeExperience( SpawnUnit:GetDomainType()))
SpawnUnit:SetMoves(0)
pPlayer:ChangeGold( -cost )
print (pCity:GetName() , "...spawning and paying for BerserkerWarrior...");
-- loop for promotions from buildings in city
for promotion in GameInfo.UnitPromotions() do
iPromotion = promotion.ID
-- check for promotions from city
if ( pCity:GetFreePromotionCount( iPromotion ) > 0 ) then
-- find units in city
local ActiveUnit = pPlot:GetUnit(i)
local iActiveUnit = GameInfo.Units[ActiveUnit:GetUnitType()].ID
-- see if unit created this turn
if ActiveUnit:GetGameTurnCreated() == Game.GetGameTurn() then
--check if unit can get promotion and give it
-- looks for unit combat class and changes it to string
local sCombatClass = "none"
for row in GameInfo.Units() do
if row.ID == iActiveUnit then
sCombatClass = tostring(row.CombatClass)
--print("...finding CombatClass of...", ActiveUnit:GetName())
end
end
--looks for promotion combat type (class) and changes it to string
local sType = "none"
for row in GameInfo.UnitPromotions() do
if row.ID == iPromotion then
sType = tostring(row.Type)
-- print("...finding Promotion Type...", sType)
end
end
local sUnitCombatType = "none"
local sPromotionType = "none"
for row in GameInfo.UnitPromotions_UnitCombats() do
sPromotionType = tostring(row.PromotionType)
sUnitCombatType = tostring(row.UnitCombatType)
--print("...finding... Promotion Combat Type...", tostring(row.UnitCombatType))
if sType == sPromotionType then
--print("Checking if...", sType, "... equals...", sPromotionType)
if sUnitCombatType == sCombatClass then
print(pPlayer:GetName(), "...spawned unit......getting Promotion...", ActiveUnit:GetName() )
ActiveUnit:SetHasPromotion(iPromotion, true);
end
end
end
end
end
end
end
end
end
end
end
--to set city operations
local g_lastTurn = -1
local function OnPlayerDoTurn(iPlayer)
--print("OnPlayerDoTurn ", iPlayer)
local gameTurn = Game.GetGameTurn()
if g_lastTurn < gameTurn then
g_lastTurn = gameTurn
--per game turn function here
ForceBerserkerWarriorPurchase (iPlayer)
end
end
GameEvents.PlayerDoTurn.Add(OnPlayerDoTurn)
I include the CityCanTrain and Religious Cost functions for completeness... although they are working as expected for the human player. And they include code governing a lot of other units...
Spoiler :
Code:
--allows building of Berserker units equal to the number of unique buildings
local iBer_Warrior = GameInfoTypes.UNIT_BERSERKER_WARRIOR
local iBerserker = GameInfoTypes.UNIT_BERSERKER
local iBerserkerHall = GameInfoTypes.BUILDING_PAGODA
function BerserkerUnit(iPlayer, iCity, iUnit)
--differentiate Berserker units
if iUnit == iBer_Warrior or iUnit == iBerserker then
-- check for Berserker building
local player = Players[iPlayer]
local city = player:GetCityByID(iCity)
if city:IsHasBuilding(iBerserkerHall) then
-- check number of Berserker units
local numUnits = 0
for unit in player:Units() do
if unit:GetUnitType() == iBer_Warrior or unit:GetUnitType() == iBerserker then
numUnits = numUnits + 1
end
end
--print("numUnits was calculated as... ", numUnits)
-- find number of buildings of applicable type
BuildingCount = player:CountNumBuildings(iBerserkerHall)
--print("BuildingCount was calculated as... ", BuildingCount)
--check if the player has enough faith
cost = city:GetUnitPurchaseCost( iUnit )
currentFaith = player:GetFaith()
gold = player:GetGold()
return math.ceil(BuildingCount/2) > numUnits and currentFaith >= cost and gold>=cost--compare fraction of building count to number of units and check if enough faith ... return TRUE if BuildingCount/X > numUnits
else
--print("City was seen as NOT having the required number and type of buildings for the unit, so FALSE is returned")
return false --needed when the city does not have a building that allows the unit
end
else
return true --default needed for units NOT in Berserker Units
end
end
GameEvents.CityCanTrain.Add(BerserkerUnit)
Spoiler :
Code:
--converts gold cost of religious units to faith amount
local iBer_Warrior = GameInfoTypes.UNIT_BERSERKER_WARRIOR
local iBerserker = GameInfoTypes.UNIT_BERSERKER
local iStellinga = GameInfoTypes.UNIT_SAXON_STELLINGA
local iScariti = GameInfoTypes.UNIT_SCARITI_CHRISTI
local iMiles = GameInfoTypes.UNIT_MILES_CHRISTI
local iFootKnight = GameInfoTypes.UNIT_FOOT_KNIGHT
local iCrusader = GameInfoTypes.UNIT_CRUSADER
function faithpurchase( iPlayer, iUnit )
local unit = Players[iPlayer]:GetUnitByID( iUnit )
local iUnitType = unit:GetUnitType()
if iUnitType == iBer_Warrior or iUnitType == iBerserker or iUnitType == iStellinga or iUnitType == iScariti or iUnitType == iMiles or iUnitType == iFootKnight or iUnitType == iCrusader then
local player = Players[iPlayer]
local plot = unit:GetPlot()
if plot:IsCity() then
local city = plot:GetPlotCity()
local cost = city:GetUnitPurchaseCost(iUnitType)
player:ChangeGold( cost )
player:ChangeFaith(-cost)
print (player:GetName() ,"...is trained...", unit:GetName(), "...religious unit in...", city:GetName());
-- else (you could decide what if anything to do here if the plot is not a city plot)
end
end
end
LuaEvents.SerialEventUnitCreatedGood.Add( faithpurchase )
Thank-you for your help.