Adding strength with unhappiness - can it be done?

AW Arcaeca

Deus Vult
Joined
Mar 10, 2013
Messages
3,019
Location
Operation Padlock ground zero
Essentially, what I want to do is give a specific type of unit +10% combat on flat terrain when the empire is unhappy, +15% when the empire is very unhappy and +20% when the empire is SUPER unhappy - but I don't want them to stack.

So this is my first attempt at coding something like that:
Code:
function CombatModIncreaseWithUnhappiness
	local pPlayer = Players[iPlayer]
	local pUnit = pPlayer:Units()
	if (pPlayer:IsAlive()) then
		if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_THIS_CIV) then
			if (pPlayer:IsEmpireUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:OpenDefenseModifier(10)
					pUnit:OpenAttackModifier(10)
				end
			end
			if (pPlayer:IsEmpireVeryUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:OpenDefenseModifier(15)
					pUnit:OpenAttackModifier(15)
				end
			end	
			if (pPlayer:IsEmpireSuperUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:OpenDefenseModifier(20)
					pUnit:OpenAttackModifier(20)
				end
			end
		end
	end	
Events.ActivePlayerTurnStart.Add(CombatModIcreaseWithUnhappiness)
I'm not entirely sure about how to actually give the unit a combat modifier...

Assuming this doesn't work, would it work better if instead of giving the unit a promotion when the empire is unhappy, which promotion gives +10% combat and all that?
 
There are no API methods (C++ or Lua) for adding combat modifiers directly to units. You'll have to add and remove promotions to achieve this effect
 
Sort of related question. I noticed that BNW subtracts strength for unhappiness (at 2% per 1 unhappiness, iirc). Can I disable this via lua/xml?

(I'm applying my own system via Morale promotions, but I need total control since it is applied differently for different kinds of units.)
 
VERY_UNHAPPY_COMBAT_PENALTY_PER_UNHAPPY and VERY_UNHAPPY_MAX_COMBAT_PENALTY in Defines. Setting at least one of these to 0 should disable the effect.
 
Well, making the promotions should be easy enough, all it will require is something like this:
Spoiler :
Code:
<Unit_Promotions>
	<Row>
		<Type>PROMOTION_UNHAPPY_OPEN_COMBAT_MOD</Type>
		<Description>TXT_KEY_PROMOTION_UNHAPPY_OPEN_COMBAT_MOD</Description>
		<Help>TXT_KEY_PROMOTION_UNHAPPY_OPEN_COMBAT_MOD_HELP</Help>
		<Sound>AS2D_IF_LEVELUP</Sound>
		<CannotBeChosen>true</CannotBeChosen>
		<OpenAttack>10</OpenAttack>
		<OpenDefense>10</OpenDefense>
		<PortraitIndex>26</PortraitIndex>
		<IconAtlas>PROMOTION_ATLAS</IconAtlas>
		<PediaType>PEDIA_SHARED</PediaType>
		<PediaEntry>TXT_KEY_PROMOTION_UNHAPPY_OPEN_COMBAT_MOD</PediaEntry>
	</Row>-<Row>
		<Type>PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD</Type>
		<Description>TXT_KEY_PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD</Description>
		<Help>TXT_KEY_PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD_HELP</Help>
		<Sound>AS2D_IF_LEVELUP</Sound>
		<CannotBeChosen>true</CannotBeChosen>
		<OpenAttack>15</OpenAttack>
		<OpenDefense>15</OpenDefense>
		<PortraitIndex>26</PortraitIndex>
		<IconAtlas>PROMOTION_ATLAS</IconAtlas>
		<PediaType>PEDIA_SHARED</PediaType>
		<PediaEntry>TXT_KEY_PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD</PediaEntry>
	</Row>-<Row>
		<Type>PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD</Type>
		<Description>TXT_KEY_PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD</Description>
		<Help>TXT_KEY_PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD_HELP</Help>
		<Sound>AS2D_IF_LEVELUP</Sound>
		<CannotBeChosen>true</CannotBeChosen>
		<OpenAttack>20</OpenAttack>
		<OpenDefense>20</OpenDefense>
		<PortraitIndex>26</PortraitIndex>
		<IconAtlas>PROMOTION_ATLAS</IconAtlas>
		<PediaType>PEDIA_SHARED</PediaType>
		<PediaEntry>TXT_KEY_PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD</PediaEntry>
	</Row>
</Unit_Promotions>
So all I would need to do, in theory, is change the lua code like so:
Spoiler :
Code:
function CombatModIncreaseWithUnhappiness
	local pPlayer = Players[iPlayer]
	local pUnit = pPlayer:Units()
	if (pPlayer:IsAlive()) then
		if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_THIS_CIV) then
			if (pPlayer:IsEmpireUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					[COLOR="Blue"][B]pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, true)[/B][/COLOR]
				end
			end
			if (pPlayer:IsEmpireVeryUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					[COLOR="Blue"][B]pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, true)[/B][/COLOR]				
				end
			end	
			if (pPlayer:IsEmpireSuperUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					[COLOR="Blue"][B]pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, true)[/B][/COLOR]
				end
			end
		end
	end	
Events.ActivePlayerTurnStart.Add(CombatModIcreaseWithUnhappiness)
Right?
The question is now: Where can I find this VERY_UNHAPPY_COMBAT_PENALTY_PER_UNHAPPY thing in the files?
 
Well, making the promotions should be easy enough, all it will require is something like this:
Spoiler :
Code:
<Unit_Promotions>
	<Row>
		<Type>PROMOTION_UNHAPPY_OPEN_COMBAT_MOD</Type>
		<Description>TXT_KEY_PROMOTION_UNHAPPY_OPEN_COMBAT_MOD</Description>
		<Help>TXT_KEY_PROMOTION_UNHAPPY_OPEN_COMBAT_MOD_HELP</Help>
		<Sound>AS2D_IF_LEVELUP</Sound>
		<CannotBeChosen>true</CannotBeChosen>
		<OpenAttack>10</OpenAttack>
		<OpenDefense>10</OpenDefense>
		<PortraitIndex>26</PortraitIndex>
		<IconAtlas>PROMOTION_ATLAS</IconAtlas>
		<PediaType>PEDIA_SHARED</PediaType>
		<PediaEntry>TXT_KEY_PROMOTION_UNHAPPY_OPEN_COMBAT_MOD</PediaEntry>
	</Row>-<Row>
		<Type>PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD</Type>
		<Description>TXT_KEY_PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD</Description>
		<Help>TXT_KEY_PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD_HELP</Help>
		<Sound>AS2D_IF_LEVELUP</Sound>
		<CannotBeChosen>true</CannotBeChosen>
		<OpenAttack>15</OpenAttack>
		<OpenDefense>15</OpenDefense>
		<PortraitIndex>26</PortraitIndex>
		<IconAtlas>PROMOTION_ATLAS</IconAtlas>
		<PediaType>PEDIA_SHARED</PediaType>
		<PediaEntry>TXT_KEY_PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD</PediaEntry>
	</Row>-<Row>
		<Type>PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD</Type>
		<Description>TXT_KEY_PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD</Description>
		<Help>TXT_KEY_PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD_HELP</Help>
		<Sound>AS2D_IF_LEVELUP</Sound>
		<CannotBeChosen>true</CannotBeChosen>
		<OpenAttack>20</OpenAttack>
		<OpenDefense>20</OpenDefense>
		<PortraitIndex>26</PortraitIndex>
		<IconAtlas>PROMOTION_ATLAS</IconAtlas>
		<PediaType>PEDIA_SHARED</PediaType>
		<PediaEntry>TXT_KEY_PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD</PediaEntry>
	</Row>
</Unit_Promotions>
So all I would need to do, in theory, is change the lua code like so:
Spoiler :
Code:
function CombatModIncreaseWithUnhappiness
	local pPlayer = Players[iPlayer]
	local pUnit = pPlayer:Units()
	if (pPlayer:IsAlive()) then
		if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_THIS_CIV) then
			if (pPlayer:IsEmpireUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					[COLOR="Blue"][B]pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, true)[/B][/COLOR]
				end
			end
			if (pPlayer:IsEmpireVeryUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					[COLOR="Blue"][B]pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, true)[/B][/COLOR]				
				end
			end	
			if (pPlayer:IsEmpireSuperUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					[COLOR="Blue"][B]pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, true)[/B][/COLOR]
				end
			end
		end
	end	
Events.ActivePlayerTurnStart.Add(CombatModIcreaseWithUnhappiness)
Right?

You'll need to remove the other promotions in each of these cases as well, otherwise they will stack. You'll also need to remove them all in the case that none of the conditions apply, otherwise if you go to negative happiness and back to positive, your units will maintain their bonus.

Your 'function' line should have (iPlayer) at the end, because the event gives you a parameter (the playerID, otherwise where would iPlayer come from?). Also, this will only work for the human player (ActivePlayerTurnStart) so why not use GameEvents.PlayerDoTurn instead, which will work for the AI? Further to this, though, doing this on the turn change means if you do something during your turn to gain happiness, the promotions won't be updated appropriate until the beginning of your next turn. I can't see a way around that last one from Lua, though, since there are no more specific relevant events.

Also, the promotions table is UnitPromotions (not Unit_Promotions) because Firaxis is really consistent with its use of underscores.

EDIT: I've just realized you're not looping over the player's units, you're just assigning the iterator to a local variable and then treating it like a unit object (which doesn't work).

You want something like this: (this isn't exactly correct, I don't remember the names of the functions off the top of my head, but it's the right sort of idea)

Code:
if civType == GameInfoTypes.MY_CIV then
    for pUnit in pPlayer:Units() do
        if pPlayer:IsEmpireUnhappy() then
            pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY, true)
            pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY, false)
            -- false for last one too
        elseif pPlayer:IsEmpireVeryUnhappy() then
            -- relevant promotions
        elseif pPlayer:IsEmpireSuperUnhappy() then
            -- relevant promotions
        else
            -- remove all promotions here
        end
    end
end

EDIT 2: You've also got a typo (missing "n" in "Increase" in the line that adds the event subscriber). I would recommend always doing copy-paste for things like that.

The question is now: Where can I find this VERY_UNHAPPY_COMBAT_PENALTY_PER_UNHAPPY thing in the files?

It's in the Defines table, you can update it there like any other GameData table.
 
so the lua should look like this then?
Code:
function CombatModIncreaseWithUnhappiness(iPlayer)
	local pPlayer = Players[iPlayer]
	local pUnit = pPlayer:GetUnits()
	if (pPlayer:IsAlive()) then
		if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_THIS_CIV) then
			for pUnit in pPlayer:Units() do
			if (pPlayer:IsEmpireUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, true)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, false)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, false)
				end
			elseif (pPlayer:IsEmpireVeryUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, false)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, true)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, false)
				end
			elseif (pPlayer:IsEmpireSuperUnhappy()) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, false)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, false)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, true)
				end
			else (pPlayer:IsEmpireUnhappy() == false) and (pPlayer:IsEmpireVeryUnhappy() == false) and (pPlayer:IsEmpireSuperUnhappy() == false) then
				if (pUnit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT) then
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, false)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, false)
					pUnit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, false)
				end
			end
		end
	end
GameEvents.PlayerDoTurn(CombatModIncreaseWithUnhappiness)

And what I meant was, exactly which file would I look in to find those defines?
EDIT: Wait a minute...
Sort of related question. I noticed that BNW subtracts strength for unhappiness (at 2% per 1 unhappiness, iirc). Can I disable this via lua/xml?
Pazyryk mentioned this is something that BNW does - but I don't have BNW. Does that mean I don't have to worry about the whole "Defines" thing, or is it still present in G&K?
 
This might work:
Code:
function CombatModIncreaseWithUnhappiness(playerID)
	local player = Players[playerID];
	if player
		and player:IsAlive()
		and player:GetCivilizationType() == GameInfoTypes.CIVILIZATION_THIS_CIV
	then
		for unit in player:Units() do
			if player:IsEmpireSuperUnhappy() then
				if unit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT then
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, false);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, false);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, true);
				end
			elseif player:IsEmpireVeryUnhappy() then
				if unit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT then
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, false);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, true);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, false);
				end
			elseif player:IsEmpireUnhappy() then
				if unit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT then
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, true);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, false);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, false);
				end
			else
				if unit:GetUnitType() == GameInfoTypes.UNIT_THIS_UNIT then
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_UNHAPPY_OPEN_COMBAT_MOD, false);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_VERY_UNHAPPY_OPEN_COMBAT_MOD, false);
					unit:SetHasPromotion(GameInfoTypes.PROMOTION_SUPER_UNHAPPY_OPEN_COMBAT_MOD, false);
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn(CombatModIncreaseWithUnhappiness)
The "VERY_UNHAPPY_COMBAT_PENALTY_PER_UNHAPPY" is only in BNW. Vanilla and G&K both have "VERY_UNHAPPY_COMBAT_PENALTY" set to -33%: so you would need to compensate for this generic effect in your promotions.
 
Back
Top Bottom