LUA - What do I need to change...

kingchris20

Wisdom Seeker
Joined
Jul 30, 2012
Messages
1,343
Location
Resident of Heaven; Currently in the Waiting Room
To make the below LUA code damage nearby ENEMY units.

The code (from DJSHenninger) as it sits, will heal nearby friendly units (from its civ) +5 HP each turn.

What about it can I update to make it apply damage to nearby enemy units (aka we are at war with).

Spoiler :
Code:
--------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------
function TES_MasterRestorationMage(playerID)
	local player = Players[playerID]
	for unit in player:Units() do
		if unit:IsHasPromotion(GameInfoTypes["PROMOTION_MASTER_RESTORATION_MAGE"]) then
		local unitX = unit:GetX()
		local unitY = unit:GetY()
		local plot = Map.GetPlot(unitX, unitY)
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit:GetOwner() == playerID then
						loopUnit:ChangeDamage(-5)
					end
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(TES_MasterRestorationMage)

Also, can I update the code (as below) for my Alteration Mage to give all friendly units within 3 tiles a +5% defense modifier anywhere on land?

Spoiler :
Code:
--------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------
function TES_MasterAlterationMage(playerID)
	local player = Players[playerID]
	for unit in player:Units() do
		if unit:IsHasPromotion(GameInfoTypes["PROMOTION_MASTER_ALTERATION_MAGE"]) then
		local unitX = unit:GetX()
		local unitY = unit:GetY()
		local plot = Map.GetPlot(unitX, unitY)
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit:GetOwner() == playerID then
						loopUnit:[COLOR="Red"]RoughDefenseModifier[/COLOR](5)
                                                loopUnit:[COLOR="Red"]OpenDefenseModifier[/COLOR](5)
                                                loopUnit:[COLOR="Red"]HillsDefenseModifier[/COLOR](5)
                                                loopUnit:[COLOR="Red"]FortifyDefenseModifier[/COLOR](5)
					end
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(TES_MasterAlterationMage)
 
loopUnit:ChangeDamage(-5)
this makes 5 less damage (ie, healing)​
So, you need to first check that the unit's owner is not the same as "playerID", and if this is true, check if the two players are at war, and if so, add 5 more damage to the "loopunit":
Code:
--------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------

local iPromotionMasterRestorationMage = GameInfoTypes["PROMOTION_MASTER_RESTORATION_MAGE"]

function TES_MasterRestorationMage(playerID)
	local player = Players[playerID]
	local teamID = player:GetTeam()
	local team = Teams[teamID]
	for unit in player:Units() do
		if unit:IsHasPromotion(iPromotionMasterRestorationMage) then
			local plot = unit:GetPlot()
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit:GetOwner() ~= playerID then
						local pOtherPlayer = Players[loopUnit:GetOwner()]
						local iOtherTeam = pOtherPlayer:GetTeam()
						if team:IsAtWar(iOtherTeam) and loopUnit:IsCombatUnit() then
							loopUnit:ChangeDamage(5)
						end
					end
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(TES_MasterRestorationMage)
As written it does not check for whether the player is a specific civ or not. Wasn't clear if that was needed.

There is a possibility that if the additional 5 damage pushes the unit over the '100' damage it takes to eliminate a unit you could get odd results or behaviors from the game. If that ends up being the case (I've never tried this exact scenario) then a simple check to see if 5 more damage will put the unit over the 'kill' knifeedge can be added to the code.

-----------------------------------------------------------------------------------------------------------

For the Combat % modifier thing:

Instead of trying to give them a combat % modifier (which as I recall is impossible directly via lua) I would give them a promotion. As I recall all you can do in lua is give a direct BaseCombatStrength or BaseRangedCombatStrength "change" as a direct integer value instead of a %. And then you have to be careful with your math and what that Base Combat Strength number has morphed to in order to not give the same effect multiple time to the same unit such that it suddenly has +50 BaseCombatStrength instead of +5. Promotions help automatically keep this under control because even if Unit-X already has Promotion-X, giving the same promotion to the same unit does not give double the promotion effect -- the unit can only have one copy of Promotion-X, regardless of how many times an lua method tries to add the same promotion to the same unit. So I would do something like as this (the code shown here is handiing both effects in one code):
Code:
--------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------

local iPromotionMasterRestorationMage = GameInfoTypes["PROMOTION_MASTER_RESTORATION_MAGE"]
local iPromotionMasterAlterationMage = GameInfoTypes["PROMOTION_MASTER_ALTERATION_MAGE"]
local iPromotionAlterationMageAffect = GameInfoTypes["PROMOTION_X_SOMETHING"]

function TES_MasterRestorationMage(playerID)
	local player = Players[playerID]
	local teamID = player:GetTeam()
	local team = Teams[teamID]
	local tUnitsToGivePromotion = {}
	for unit in player:Units() do
		unit:SetHasPromotion(iPromotionAlterationMageAffect, false)
		if unit:IsHasPromotion(iPromotionMasterRestorationMage) or unit:IsHasPromotion(iPromotionMasterAlterationMage) then
			local plot = unit:GetPlot()
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit and (loopUnit ~= unit) then
						if (loopUnit:GetOwner() ~= playerID) then
							if unit:IsHasPromotion(iPromotionMasterRestorationMage) then
								local pOtherPlayer = Players[loopUnit:GetOwner()]
								local iOtherTeam = pOtherPlayer:GetTeam()
								if team:IsAtWar(iOtherTeam) and loopUnit:IsCombatUnit() then
									loopUnit:ChangeDamage(5)
								end
							end
						else
							if unit:IsHasPromotion(iPromotionMasterAlterationMage) and loopUnit:IsCombatUnit() and not loopUnit:IsHasPromotion(iPromotionMasterAlterationMage) then
								table.insert(tUnitsToGivePromotion, loopUnit)
							end
						end
					end
				end
			end
		end
	end
	for Item,pUnit in pairs(tUnitsToGivePromotion) do
		pUnit:SetHasPromotion(iPromotionAlterationMageAffect, true)
	end
end
GameEvents.PlayerDoTurn.Add(TES_MasterRestorationMage)
"PROMOTION_X_SOMETHING" would then have the combat modifier as an intrinsic property of the promotion.

This line might have to be adjusted if you do not want a unit with either of the PROMOTION_MASTER_RESTORATION_MAGE or PROMOTION_MASTER_ALTERATION_MAGE promotions to have any possibility of getting the PROMOTION_X_SOMETHING promotion:
Code:
if unit:IsHasPromotion(iPromotionMasterAlterationMage) and loopUnit:IsCombatUnit() and not loopUnit:IsHasPromotion(iPromotionMasterAlterationMage) then
 
How about this for the damage code

Code:
include("PlotIterators")
---------------------------------------------------------------

local iPromotionDraugrWightLord = GameInfoTypes["PROMOTION_DRAUGR_WIGHT_LORD"]

function TES_DraugrWightLord(playerID)
	local player = Players[playerID]
	local teamID = player:GetTeam()
	local team = Teams[teamID]
	for unit in player:Units() do
		if unit:IsHasPromotion(iPromotionDraugrWightLord) then
			local plot = unit:GetPlot()
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit:GetOwner() ~= playerID then
						local pOtherPlayer = Players[loopUnit:GetOwner()]
						local iOtherTeam = pOtherPlayer:GetTeam()
						if team:IsAtWar(iOtherTeam) and loopUnit:IsCombatUnit() then
							[COLOR="Red"]if loopUnit:GetCurrHitPoints() > 5 then[/COLOR]
								loopUnit:ChangeDamage(5)
								Events.GameplayAlertMessage('Our Draugr Wight Lord has cast a damage spell on our enemies!')
							end
						end
					end
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(TES_DraugrWightLord)

And that will take care of the Dragur Wight Lord unit ability! :D

--------------------------------------------------------------------------------

As for the Master Alteration Mage ability

I will try out the combat (or defense, haven't decided yet) modifier code tomorrow, thanks for posting it!

--------------------------------------------------------------------------------
Also, yes the first bit of code for the Master Restoration Mage was intended to heal its nearby friendly units (within 3 hexes).

I didn't notice it healing enemy units though, and I didn't try allied/non-enemy units nearby to see if they received healing
 
Since you're dealing in 'Damage' I would stick to 'Damage'. So I would do as
Code:
if loopUnit:GetDamage() < 95 then
	loopUnit:ChangeDamage(5)
	if player:IsHuman() then
		Events.GameplayAlertMessage('Our Draugr Wight Lord has cast a damage spell on our enemies!')
	end
end
You need to wrap your gameplay alert messages in checks for player being human because otherwise when the player whose turn is being processed is not human, the human player will get confusing messages related to what an AI player's units are doing or did. You should do this with any GameplayAlertMessage because all such messages are sent to the human player, regardless of which player the message was originally intended for.
 
Since you're dealing in 'Damage' I would stick to 'Damage'. So I would do as
Code:
if loopUnit:GetDamage() < 95 then
	loopUnit:ChangeDamage(5)
	if player:IsHuman() then
		Events.GameplayAlertMessage('Our Draugr Wight Lord has cast a damage spell on our enemies!')
	end
end
You need to wrap your gameplay alert messages in checks for player being human because otherwise when the player whose turn is being processed is not human, the human player will get confusing messages related to what an AI player's units are doing or did. You should do this with any GameplayAlertMessage because all such messages are sent to the human player, regardless of which player the message was originally intended for.

This code is working great. For the Draugr Wight Lord ability to damage enemy units, is there a way to place a Gameplay alert message for this scenario:

An AI Draugr Wight Lord is causing damage on human player units.

I tested this with an AI DWL and it was indeed damaging my units, but no one else (other players using the mod) would know why their units were taking damage without further investigation (which would be okay), but it might be better if we could pop a code saying "An enemy Draugr Wight Lord has cast a damage spell on our units".
 
This code is working great. For the Draugr Wight Lord ability to damage enemy units, is there a way to place a Gameplay alert message for this scenario:

An AI Draugr Wight Lord is causing damage on human player units.

I tested this with an AI DWL and it was indeed damaging my units, but no one else (other players using the mod) would know why their units were taking damage without further investigation (which would be okay), but it might be better if we could pop a code saying "An enemy Draugr Wight Lord has cast a damage spell on our units".
Since you have already grabbed the player object for the 'loopunit's owner (ie, local pOtherPlayer = Players[loopUnit:GetOwner()]) you can alter to:
Code:
---------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------

local iPromotionDraugrWightLord = GameInfoTypes["PROMOTION_DRAUGR_WIGHT_LORD"]

function TES_DraugrWightLord(playerID)
	local player = Players[playerID]
	local teamID = player:GetTeam()
	local team = Teams[teamID]
	for unit in player:Units() do
		if unit:IsHasPromotion(iPromotionDraugrWightLord) then
			local plot = unit:GetPlot()
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit:GetOwner() ~= playerID then
						local pOtherPlayer = Players[loopUnit:GetOwner()]
						local iOtherTeam = pOtherPlayer:GetTeam()
						if team:IsAtWar(iOtherTeam) and loopUnit:IsCombatUnit() then
							if loopUnit:GetDamage() < 95 then
								loopUnit:ChangeDamage(5)
								if player:IsHuman() then
									Events.GameplayAlertMessage("Our Draugr Wight Lord has cast a damage spell on our enemies!")
								end
								if pOtherPlayer:IsHuman() then
									Events.GameplayAlertMessage("An enemy Draugr Wight Lord has cast a damage spell on our units!")
								end
							end
						end
					end
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(TES_DraugrWightLord)
You might get a boatload clutter of these messages, though, when one or more of these Draugr Wight Lord units has smacked multiple units on the same turn. You'll just have to test a little and determine if it's just a bit too much annoyance muchness if a human user is getting loads of these every turn as part of the turn processing stuff.
 
Okay the Draugr LUA (above post) works perfectly!

Was able to test this one out tonight (quote below)

For the Combat % modifier thing:

Spoiler :
Instead of trying to give them a combat % modifier (which as I recall is impossible directly via lua) I would give them a promotion. As I recall all you can do in lua is give a direct BaseCombatStrength or BaseRangedCombatStrength "change" as a direct integer value instead of a %. And then you have to be careful with your math and what that Base Combat Strength number has morphed to in order to not give the same effect multiple time to the same unit such that it suddenly has +50 BaseCombatStrength instead of +5. Promotions help automatically keep this under control because even if Unit-X already has Promotion-X, giving the same promotion to the same unit does not give double the promotion effect -- the unit can only have one copy of Promotion-X, regardless of how many times an lua method tries to add the same promotion to the same unit. So I would do something like as this (the code shown here is handiing both effects in one code):
Spoiler :
Code:
--------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------

local iPromotionMasterRestorationMage = GameInfoTypes["PROMOTION_MASTER_RESTORATION_MAGE"]
local iPromotionMasterAlterationMage = GameInfoTypes["PROMOTION_MASTER_ALTERATION_MAGE"]
local iPromotionAlterationMageAffect = GameInfoTypes["PROMOTION_X_SOMETHING"]

function TES_MasterRestorationMage(playerID)
	local player = Players[playerID]
	local teamID = player:GetTeam()
	local team = Teams[teamID]
	local tUnitsToGivePromotion = {}
	for unit in player:Units() do
		unit:SetHasPromotion(iPromotionAlterationMageAffect, false)
		if unit:IsHasPromotion(iPromotionMasterRestorationMage) or unit:IsHasPromotion(iPromotionMasterAlterationMage) then
			local plot = unit:GetPlot()
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit and (loopUnit ~= unit) then
						if (loopUnit:GetOwner() ~= playerID) then
							if unit:IsHasPromotion(iPromotionMasterRestorationMage) then
								local pOtherPlayer = Players[loopUnit:GetOwner()]
								local iOtherTeam = pOtherPlayer:GetTeam()
								if team:IsAtWar(iOtherTeam) and loopUnit:IsCombatUnit() then
									loopUnit:ChangeDamage(5)
								end
							end
						else
							if unit:IsHasPromotion(iPromotionMasterAlterationMage) and loopUnit:IsCombatUnit() and not loopUnit:IsHasPromotion(iPromotionMasterAlterationMage) then
								table.insert(tUnitsToGivePromotion, loopUnit)
							end
						end
					end
				end
			end
		end
	end
	for Item,pUnit in pairs(tUnitsToGivePromotion) do
		pUnit:SetHasPromotion(iPromotionAlterationMageAffect, true)
	end
end
GameEvents.PlayerDoTurn.Add(TES_MasterRestorationMage)
"PROMOTION_X_SOMETHING" would then have the combat modifier as an intrinsic property of the promotion.


I think I've got something that seems to be working well in the game for the Alteration Mage, it is applying only to friendlies and my promotion is showing up and working on each unit within a 3 tile radius.

Would you please check the code (made a couple changes) and make sure it looks good/won't present any unwanted problems...

Spoiler :
Code:
--------------------------------------------------------------
include("PlotIterators")
---------------------------------------------------------------

local iPromotionMasterAlterationMage = GameInfoTypes["PROMOTION_MASTER_ALTERATION_MAGE"]
local iPromotionAlterationMageAffect = GameInfoTypes["PROMOTION_MAGE_ARMOR_EFFECT"]

function TES_MasterAlterationMage(playerID)
	local player = Players[playerID]
	local teamID = player:GetTeam()
	local team = Teams[teamID]
	local tUnitsToGivePromotion = {}
	for unit in player:Units() do
		unit:SetHasPromotion(iPromotionAlterationMageAffect, false)
		if unit:IsHasPromotion(iPromotionMasterAlterationMage) then
			local plot = unit:GetPlot()
			for loopPlot in PlotAreaSweepIterator(plot, 3, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE) do
				for iVal = 0,(loopPlot:GetNumUnits() - 1) do
					local loopUnit = loopPlot:GetUnit(iVal)
					if loopUnit:GetOwner() == playerID then
						if loopUnit:IsCombatUnit() then
							table.insert(tUnitsToGivePromotion, loopUnit)
						end
					end
				end
			end
		end
	end
	for Item,pUnit in pairs(tUnitsToGivePromotion) do
			pUnit:SetHasPromotion(iPromotionAlterationMageAffect, true)
	end
end
GameEvents.PlayerDoTurn.Add(TES_MasterAlterationMage)
 
Looks OK. The valid test is actually using it in-game. I've learned that no matter how many times I look over a code searching for errors it is trivially easy to miss seeing the most obvious whoopsies.
 
Top Bottom