C++/Lua Request Thread

From earlier, is it possible to make a UI add a feature to a tile through lua?

Yes. You could use SetFeatureType to change the tile's feature. The way I'd do it is to check all tiles a player's workers are on to see if the improvement is there, and set their tiles to have the improvement if so.

Code:
function UIReplaceFeature(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_YOURCIV then
			for pUnit in pPlayer:Units() do
				if pUnit:GetUnitClassType() == GameInfoTypes.UNITCLASS_WORKER then
					pPlot = pUnit:GetPlot()
					if pPlot:GetImprovementTYpe == GameInfoTypes.IMPROVEMENT_YOURIMPROVEMENT then
						pPlot:SetFeatureType(GameInfoTypes.FEATURE_YOURFEATURE, -1)
					end
				end
			end
		end
	end
end

GameEvents.PlayerDoTurn.Add(UIReplaceFeature)

Note that due to the way the graphics engine works, setting features during gameplay will probably cause graphical glitches until the user zooms in on the plot or reloads the game.
 
I've seen your posts about this, but would that happen even if you set them to have UNITAI_SETTLE/UNITAI_WORKER/etc as their only valid AI types?

The first version of my "Population (Refugees)" mod used a "population" unit with UNITAI_SETTLE and a combat of 1 (as they needed to be able to garrison in a city) - any given to the AI just stood around doing nothing. It seems that the combat != 0 over-rides the UNITAI_ designation.

EDIT: Just checked the C++ code and the first pass filter is done on "IsCombatUnit()" (which basically checks for Combat > 0) and NOT the UNITAI_type - hence all the issues
 
The first version of my "Population (Refugees)" mod used a "population" unit with UNITAI_SETTLE and a combat of 1 (as they needed to be able to garrison in a city) - any given to the AI just stood around doing nothing. It seems that the combat != 0 over-rides the UNITAI_ designation.

Why am I not surprised?

Well then, that narrows things down...

Code:
function BoerKillCapturedCivilian(iPlayer, iUnitID)
	local pPlayer = Players[iPlayer]
	local pUnit = pPlayer:GetUnitByID(iUnitID)
	if Players[pUnit:GetOriginalOwner()]:GetCivilizationType() == GameInfoTypes.CIVILIZATION_BOERS and not pUnit:IsCombatUnit() and iPlayer ~= pUnit:GetOriginalOwner() then
		pUnit:Kill(true)
	end
end

GameEvents.UnitSetXY.Add(BoerKillCapturedCivilian)
 
Yes. You could use SetFeatureType to change the tile's feature. The way I'd do it is to check all tiles a player's workers are on to see if the improvement is there, and set their tiles to have the improvement if so.

Code:
function UIReplaceFeature(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_YOURCIV then
			for pUnit in pPlayer:Units() do
				if pUnit:GetUnitClassType() == GameInfoTypes.UNITCLASS_WORKER then
					pPlot = pUnit:GetPlot()
					if pPlot:GetImprovementTYpe == GameInfoTypes.IMPROVEMENT_YOURIMPROVEMENT then
						pPlot:SetFeatureType(GameInfoTypes.FEATURE_YOURFEATURE, -1)
					end
				end
			end
		end
	end
end

GameEvents.PlayerDoTurn.Add(UIReplaceFeature)

Note that due to the way the graphics engine works, setting features during gameplay will probably cause graphical glitches until the user zooms in on the plot or reloads the game.

Thank you very much for your help!
 
Both the UB and the UU are set only to use the unique version of the improvement, but that can easily be changed if needed. I haven't plugged this code into the game, so if it doesn't work, let me know.
Wow, thank you very much! Both the UU Promotion script and the UB code seem to work just fine, though we're still looking for a movement bonus for Great People, and minimum conflict with other mods (like how Leugi's Israel sets a combat class for the Prophet). Would there be an easy way of using Lua to give +1 movement for Boer-spawned Great People, or would it just be better to use XML to give them a combat class + promotion? (Also, the civ is defined as CIVILIZATION_BOER, not _BOERS.) Once again, though, thank you, you're a real life saver!
 
Code:
local iBoers = GameInfoTypes.CIVILIZATION_BOER
local iGPPromo = GameInfoTypes.PROMOTION_BOER_MOVEMENT

function BoerCivilianMovement(iPlayer, iUnitID)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == iBoers then
			local pUnit = pPlayer:GetUnitByID(iUnitID)
			if pUnit:IsGreatPerson() and not pUnit:IsHasPromotion(iGPPromo) then
				pUnit:SetHasPromotion(iGPPromo, true)
				pUnit:SetMoves(pUnit:GetMoves() + 1)
			end
		end
	end
end

GameEvents.UnitSetXY.Add(BoerCivilianMovement)

You'll need to create PROMOTION_BOER_MOVEMENT in XML or SQL to be a promotion which grants +1 Movement, of course.
 
Awesome, it works perfectly! Thank you!
 
I hate to double-post, but there's been a little bit of a design change with the Boers. What sort of changes would need to be made to that Farm defense bonus to apply to all Boer units, as opposed to just the UU?

Additionally, TPangolin wants to rework the Unique Building function: +2% Growth for every 2 Tourism in the city, up to a maximum bonus of 20%. (Or max 10 of the hidden building, which would provide +2% Growth instead of 1%, per city.)
 
I hate to double-post, but there's been a little bit of a design change with the Boers. What sort of changes would need to be made to that Farm defense bonus to apply to all Boer units, as opposed to just the UU?

Code:
local iBoers = GameInfoTypes.CIVILIZATION_BOER
local iPromotion = GameInfoTypes.PROMOTION_BOER_UU_PROMOTION
local iImprovement = GameInfoTypes.IMPROVEMENT_BOERFARM



function BoerUnitHeal(iPlayer, iUnitID)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		local pUnit = pPlayer:GetUnitByID(iUnitID)
		if pPlayer:GetCivilizationType() == iBoers then
			local pPlot = pUnit:GetPlot()
			if pPlot:GetImprovementType() == iImprovement then
				pUnit:SetHasPromotion(iPromotion, true)
				return
			end
		end
		pUnit:SetHasPromotion(iPromotion, false)
	end
end

GameEvents.UnitSetXY.Add(BoerUnitHeal)

Additionally, TPangolin wants to rework the Unique Building function: +2% Growth for every 2 Tourism in the city, up to a maximum bonus of 20%. (Or max 10 of the hidden building, which would provide +2% Growth instead of 1%, per city.)

I'd suggest keeping the bonus per building at 1% and cap it at 20, so that it's easier to fine-tune the code later if needed. I'm assuming you still want the Golden Age effect; if not, delete everything from the "Golden Age from Farm" comment to the line with "pPlayer:ChangeGoldenAgeProgressMeter(iTotalFarms)".

Code:
local iBoers = GameInfoTypes.CIVILIZATION_BOER
local iUB = GameInfoTypes.BUILDING_BOERSTAATSMUSEUM
local iGrowthDummy = GameInfoTypes.BUILDING_BOER_GROWTHDUMMY
local iImprovement = GameInfoTypes.IMPROVEMENT_BOERFARM



function BoerUniqueBuilding(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == iBoers then
			for pCity in pPlayer:Cities() do
				--Growth Bonus
				local iGrowthMod = math.min((math.floor(pCity:GetBaseTourism() / 2)) * 2, 20)
				pCity:SetNumRealBuilding(iGrowthDummy, iGrowthMod)
				--Golden Age from Farm
				local iNumPlots = pCity:GetNumCityPlots()
				local iTotalFarms = 0;
				for iPlot = 0, iNumPlots - 1 do
					local pPlot = pCity:GetCityIndexPlot(iPlot)
					if pPlot and pPlot:GetOwner() == iPlayer and pPlot:GetImprovementType() == iImprovement then
						iTotalFarms = iTotalFarms + 1
					end
				end
			pPlayer:ChangeGoldenAgeProgressMeter(iTotalFarms)
			end
		end
	end
end



GameEvents.PlayerDoTurn.Add(BoerUniqueBuilding)
 
Hi there! I have a few requests for a new Civilization I'm making and wondering if all of them are possible to do.

1. A unique Great Writer's special ability to create Great Works of Writing that also generate a happiness bonus to the Civilization that owns them. I figured this would be more easily done with dummy buildings giving Unmodded Happiness. Also, I'd like it if the happiness bonus will work for any Civilization that can acquire the Great work of writing (i.e. if they trade for it or get the unique Great Writer from a City-state, etc).

2. The civilization's unique building's ability to grant one free copy out of two possible unique resources upon being built. So if a city builds the building, they might get Resource B but another city that builds the building might get Resource A instead. Also the building has a Great Work of Writing slot which when filled, generates one extra copy of whatever resource the building was currently granting in the city that builds it. So a city that has the building that is currently granting one copy of Resource B will gain two copies of Resource B if the Great Work slot is currently filled and vice versa.

3. The civilization's unique ability to gain a free Great Writer in their capital after advancing eras. Probably the easiest one in terms complexity regarding the other two requests.

Thanks in advance!
 
1. A unique Great Writer's special ability to create Great Works of Writing that also generate a happiness bonus to the Civilization that owns them. I figured this would be more easily done with dummy buildings giving Unmodded Happiness. Also, I'd like it if the happiness bonus will work for any Civilization that can acquire the Great work of writing (i.e. if they trade for it or get the unique Great Writer from a City-state, etc).

You can copy and modify the code from my Vocaloid Civilization, since it has a very similar effect (+Science from Great Works using dummy buildings).

2. The civilization's unique building's ability to grant one free copy out of two possible unique resources upon being built. So if a city builds the building, they might get Resource B but another city that builds the building might get Resource A instead. Also the building has a Great Work of Writing slot which when filled, generates one extra copy of whatever resource the building was currently granting in the city that builds it. So a city that has the building that is currently granting one copy of Resource B will gain two copies of Resource B if the Great Work slot is currently filled and vice versa.

Untested; needs checking in-game.

Code:
local iYourCiv = GameInfoTypes.CIVILIZATION_YOUR_CIVILIZATION
local iGWBuilding = GameInfoTypes.BUILDING_YOUR_UNIQUEBUILDING
local iGWClass = GameInfoTypes.BUILDINGCLASS_YOUR_UNIQUEBUILDINGCLASS
local iResourceA = GameInfoTypes.BUILDING_RESOURCE_DUMMY_A
local iResourceB = GameInfoTypes.BUILDING_RESOURCE_DUMMY_B


function GrantInitialResource(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == iYourCiv then
			for pCity in pPlayer:Cities() do
				
				if pCity:IsHasBuilding(iGWBuilding) then
					--Do we already have a resource building? If not, randomly pick one.
					local iResourceType;
					if pCity:IsHasBuilding(iResourceA) then
						iResourceType = iResourceA;
					elseif pCity:IsHasBuilding(iResourceB) then
						iResourceType = iResourceB
					else --Randomly choose one of the two
						local iRand = Map.Rand(2, "Resource Randomize")
						if iRand == 0 then
							iResourceType = iResourceA
						else
							iResourceType = iResourceB
						end
					end
					local iNumBuildings = 1;
					if pCity:GetBuildingGreatWork(iGWClass, 0) > -1 then
						iNumBuildings = 2
					end
					pCity:SetNumRealBuilding(iResourceType, iNumBuildings)			
				else
					pCity:SetNumRealBuilding(iResourceA, 0)	
					pCity:SetNumRealBuilding(iResourceB, 0)		
				end
			end
		end
	end
end

GameEvents.PlayerDoTurn.Add(GrantInitialResource)

3. The civilization's unique ability to gain a free Great Writer in their capital after advancing eras. Probably the easiest one in terms complexity regarding the other two requests.


Code:
local iYourCiv = GameInfoTypes.CIVILIZATION_YOUR_CIVILIZATION
local iCurrentEra = -1;
local iWriter = GameInfoTypes.UNIT_WRITER

function GreatWriterOnEra(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == iYourCiv then
			if iCurrentEra > -1 and iCurrentEra ~= pPlayer:GetCurrentEra() then
				pPlayer:AddFreeUnit(iWriter, UNITAI_WRITER)
			end
			iCurrentEra = pPlayer:GetCurrentEra()
		end
	end
end

GameEvents.PlayerDoTurn.Add(GreatWriterOnEra)
 
Awesome!

Tested out the resource building script and everything seems to be working quite perfectly. Same with the free Great Writer script. I have your Vocaloid mod and I'll modify the code for the bonuses for the great works and test it out later when I have the time.

Again, thanks for the help!
 
I'm currently working on a bulding pack which also adds five new resources; two of the resources will need to appear on the map, but the other three will be produced by new buildings. The resource-generator code I plan to use (DeepBlue's} can put items on a map, but wasn't designed to handle a half-and-half situation like this one. Does another generator program exist which can distinguish map-based resources from others on a single list? Or (given my poor Lua/SQL skills) should I split this mod into two, and have one depend on the other?
 
Anything to do with map scripts and map generation is outside of my experience zone. 'fraid I can't help with this one. Maybe ask Barathor, the author of the More Luxuries mod?
 
For Oman - Part of a UA:

Enemy units receive (small) attrition damage when they end a turn next to a Naval Unit that is stationed on a Sea Resource in friendly territory.

Each Sea Resource worked by a city increases Naval unit Production by +5%.

Also a promotion for a unit that increases the base yield of a Sea Resource by +1 Food when it is on that said tile.
 
Enemy units receive (small) attrition damage when they end a turn next to a Naval Unit that is stationed on a Sea Resource in friendly territory.

Code:
local iOman = GameInfoTypes.CIVILIZATION_OMAN
local iDomain = DomainTypes.DOMAIN_SEA
local iDamage = 5 --Amount of damage to be dealt as attrition, change as you see fit


						
function OmanAttrition(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == iOman then
			for pUnit in pPlayer:Units() do
				local pPlot == pUnit:GetPlot()
				if pUnit:GetDomainType() == iDomain and pUnit:IsCombatUnit() and pPlot():GetResourceType() > -1 then
					local direction_types = {
						DirectionTypes.DIRECTION_NORTHEAST,
						DirectionTypes.DIRECTION_EAST,
						DirectionTypes.DIRECTION_SOUTHEAST,
						DirectionTypes.DIRECTION_SOUTHWEST,
						DirectionTypes.DIRECTION_WEST,
						DirectionTypes.DIRECTION_NORTHWEST
						}
					for a, direction in ipairs(direction_types) do
						local nextPlot = Map.PlotDirection(pPlot:GetX(), pPlot:GetY(), direction)
						if (nextPlot ~= nil) then
							if (nextPlot:IsUnit()) then
								for i = 0, nextPlot:GetNumUnits() do
									local pEnemyUnit = nextPlot:GetUnit(i);
									if (pEnemyUnit ~= nil) then
										if Teams[pPlayer:GetTeam()]:IsAtWar(pEnemyUnit:GetTeam()) then
											pEnemyUnit:ChangeDamage(iDamage, iPlayer)
										end
									end
								end
							end
						end
					end
				end
			end
		end
	end
end

GameEvents.PlayerDoTurn.Add(OmanAttrition)

Each Sea Resource worked by a city increases Naval unit Production by +5%.

Code:
local iOman = GameInfoTypes.CIVILIZATION_OMAN
local iDummy = GameInfoTypes.BUILDING_OMAN_PRODUCTION_DUMMY
local iImprovement = GameInfoTypes.IMPROVEMENT_FISHING_BOATS

--Called from other two functions to actually set the dummy buildings
function DoOmanNavalBonus(iPlayer, pCity)
	local pPlayer = Players[iPlayer]
	local iNumPlots = pCity:GetNumCityPlots()
	local iNumBuildings = 0;
	for iPlot = 0, iNumPlots - 1 do
		local pPlot = pCity:GetCityIndexPlot(iPlot)
		if pPlot and pPlot:GetOwner() == iPlayer and pPlot:IsWater() and pPlot:GetImprovementType() == iImprovement and pCity:IsWorkingPlot(pPlot) then
			iNumBuildings = iNumBuildings + 1
		end
	end
	pCity:SetNumRealBuilding(iDummy, iNumBuildings)
end

--Run above function with all of the player's cities at the start of their turn
function OnTurnOmanNavalBonus(iPlayer)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
		local pPlayer = Players[iPlayer]
		if pPlayer:GetCivilizationType() == iOman then
			for pCity in pPlayer:Cities() do
				DoOmanNavalBonus(iPlayer, pCity)
			end
		end
	end
end

GameEvents.PlayerDoTurn.Add(OnTurnOmanNavalBonus)

--Run above function only with the selected city if they are in the city screen.
--Enables this to be dynamically updated as the player changes worked tiles.
function OnDirtyOmanNavalBonus()
	if UI.IsCityScreenUp() then
		local iPlayer = Game:GetActivePlayer()
		if Players[iPlayer]:GetCivilizationType() == iOman then
			DoOmanNavalBonus(iPlayer, UI.GetHeadSelectedCity())
		end
	end
end

Events.SerialEventCityInfoDirty.Add(OnDirtyOmanNavalBonus)

Also a promotion for a unit that increases the base yield of a Sea Resource by +1 Food when it is on that said tile.

Code:
local iPromotion = GameInfoTypes.PROMOTION_OMAN_NAVAL_PROMOTION
local iFeature = FeatureTypes.FEATURE_OMAN_DUMMY --Dummy feature which should provide +1 Food to the tile
local iNoFeature = FeatureTypes.NO_FEATURE --To remove the feature when a unit moves away

function OmanNavalPromotion(iPlayer, iUnitID)
	if iPlayer < GameDefines.MAX_MAJOR_CIVS then
   		local pPlayer = Players[iPlayer]
		local pUnit = pPlayer:GetUnitByID(iUnitID)
		local pPlot = pUnit:GetPlot()
		if pUnit:IsHasPromotion(iPromotion) and pPlot:IsWater() and pPlot:GetResourceType() > -1 then
			pPlot:SetFeatureType(iFeature, -1)
			return
		end
		pPlot:SetFeatureType(iNoFeature, -1)
	end
end

GameEvents.UnitSetXY.Add(OmanNavalPromotion)
 
I would like to iterate through each plot and get the yield values for all of them. After that, I would like to split up the yields of each plot between the different cities of the empire based on the wealth and populations of the cities and the distances from the cities to plots. After iterating through all plots, final yield values for each city should be calculated and added to cities via dummy buildings.
 
Awesome!

Tested out the resource building script and everything seems to be working quite perfectly. Same with the free Great Writer script. I have your Vocaloid mod and I'll modify the code for the bonuses for the great works and test it out later when I have the time.

Again, thanks for the help!

Alright I've tried out Vice's script from their Vocaloid mod to create an extra bonus from Great Works and it's working great! The works are each creating +1 Happiness for their Civilization. (I cut out the part where the works would increase their bonus depending on the amount of Civilizations influenced)

However, I also want the works to "double" their Culture and Tourism output once Computers is researched. I thought I could take a shortcut by approaching this with the <EnhancedYieldTech> table in the XML with the same dummy building used to generate the +1 Happiness and then adding the appropriate yields that way. Strangely, after researching Computers in-game, the game would only add the bonus to one of the dummy buildings in the city. So a city with 10 of these special Great Works of Writing is only generating the extra culture and tourism from only one of the Great Works. I still have the happiness boost from all of the Great Works, it's just that the added yields from the Great Works once Computers is researched is only applied to one of the Great Works in the city. It doesn't get fixed after refreshing it in the CulturalOverview by moving Great Works around or waiting for the next turn.

I'm guessing that I'll have to approach giving the works added yields once Computers is researched with Lua. :crazyeye: Anyone have any ideas on how this could work?
 
Can somebody show me how to get the following feature in a mod?

When a player Shift-right-clicks a tile, a window like the name city/unit window appears, and when the player fills in the text and closes the window, mousing over the tile shows the usual black rectangle but with the name of the tile displayed along with the yields, terrain, features, and improvements/resources.

I think it would be doable with lua, because I have a mod that lets me right-click the unit panel and have the unit naming window appear, and in Kael's guide I think it mentions how to resize a window. However, I have 0 knowledge of how to (a) write lua, and (b) get a lua file into a mod.

Thank you!
 
Back
Top Bottom