Civ VI - LUA Mods - Culture Bombs for Districts & Improvements

Gleb Bazov

Warlord
Joined
Feb 13, 2017
Messages
176
UPDATE #4: Darn! I forgot a snippet of LeeS' code in the Strategic Resource Improvement Culture Bomb, and, for that reason, the function ResourceIsRevealedToPlayer was not working at all. NOW FIXED. Ok, that's it for now! :)

IMPORTANT, UPDATE #3: There were errors in the code in the previous update. They have (hopefully) been all corrected. The functionality is as described below. The Culture Bomb should now work exactly as the Culture Bomb in the base game, except with the far greater flexibility:

(1) 1-tile radius;
(2) Does not capture tiles beyond 5-tile radius around the origin (owner of source plot) city;
(3) Does not capture other civilizations' districts or wonders.

Please make sure to use the latest versions (included below) instead of any of the prior versions. Included:

- District Culture Bomb (adds an adjacency to feature requirement)
- Improvement Culture Bomb (adds the requirement of improvement over strategic resources)
- Australia Trait Replacement Culture Bomb (exactly as base game, except in Lua)

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

UPDATE #2: All three mods updated with the range from the city within which the Culture Bomb will be effective. This range is equivalent to PLOT_INFLUENCE_MAX_ACQUIRE_DISTANCE in Global Parameters, which is set to 5 in the base game.

UPDATE: I have updated the two mods to EXCLUDE tiles with Districts owned by other civs from the culture bomb mechanic. The updated files have been uploaded instead of the original ones.

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

I am also adding the Australia Trait Replacement mod for Anansethespider here, in case anyone else finds it useful. It can be adapted to any other, as required.

NOTE
: This is W.I.P., very little testing done to see all possible conflicts, just the basic functionality so I would really appreciate anyone testing this further (e.g., I have no idea what happens when a different civ's district falls within the culture bomb area, and have not precluded this possibility, but can, if needed).

Here are two results of my recent attempts to learn Lua for Civ VI and test a variety of available mechanics. They were inspired by two requests for help with implementing Culture Bomb functionality for districts (of a specified Civ Type and with a required adjacency) and improvements (place on strategic resources. As the Culture Bomb functionality in XML is severely restricted, Lua seemed like a good place to go.

Neither would have been possible without excellent examples of Lua coding provided from LeeS, from which I liberally borrowed, and a very timely and essential tip from Gedemon.

District Adjacency Culture Bomb - Tied to a Civilization

To customize, edit the Lua file (in the LUA subdirectory) and amend the following values:

local rPlotRadius = 3
This will change the radius of the Culture Bomb. Set by default to 3 to showcase the possibilities in Lua.

local iRequiredDistrict = "DISTRICT_ENCAMPMENT"
This will change the district to which the Culture Bomb applies.

local rRequiredCiv = "CIVILIZATION_EGYPT"
This will change the civilization able to use this Culture Bomb trait.

local rRequiredFeature = "FEATURE_JUNGLE"
This will change the adjacent feature required. Further in the code, the adjacency radius can also be changed (from 1 to 1+x, and the code will check for the presence of the required feature in all the rings).

Strategic Improvement Culture Bomb

To customize, edit the Lua file (in the LUA subdirectory) and amend the following values:

local rPlotRadius = 3
This will change the radius of the Culture Bomb. Set by default to 3 to showcase the possibilities in Lua.

local rResourceClassType = "RESOURCECLASS_STRATEGIC"
This will change the required class of resource (i.e. Luxury, Bonus, Strategic).

By default, the game does not let you place an invalid improvement on a specific type of resource, so there was no need to check further whether an improvement fits the resource in question. As long as the resource is visible to the player, and is of a specified class, and is contained on the improvement's plot, the Culture Bomb will trigger.

Much thanks to LeeS and Gedemon!

gBazov
 

Attachments

Last edited:
This looks really cool. Here's a subproject for you that would prove really immediately useful (to me anyway!).

I would love to modify Australia's ability (trigger culture bomb on pastures) to make it only trigger on pastures over resources. I use a mod that allows building pastures anywhere, and it makes the Australia ability too OP. :D
 
Thanks! :) As for the subproject: Just off the top of my head, modifying Australia's ability (coded in XML) in Lua is a difficult undertaking. I wouldn't know where to start. However, what I can probably do, and do relatively easily, is to remove Austrialia's XML trait altogether and create a completely separate process in Lua that achieves the same thing. In other words, I would duplicate Australia's ability in Lua, using my template for Strategic Improvement Culture Bomb above, and remove Australia's ability in XML. Would that suit your needs? If so, let me know. If not, I'll give some further thought as to how to change the XML effect through Lua.

Cheers!
 
You can also just straight-up add a requirement in the XML to test for being on a resource. There are examples everywhere in the base game.

Gleb, thanks so much! Is this locked to what the game calls a "culture bomb"? As in, it cannot go beyond the border of the city, cant grab wonders/districts, and triggers anything triggered by "culture bombs" (like Poland's conversion ability)?
 
@Atlas627

- In this very early iteration, the mechanic is not locked, as far as I know, from going beyond the borders of the city. On the improvement culture bomb, there is a check whether the plot is within the set of plots "purchased by a city" (local pCity = Cities.GetPlotPurchaseCity(iPlotIndex)), but there is no such check on the District side. However, additional conditions can eventually be placed to restrict the culture bomb.

- As for triggering Poland's conversion abililty - no, does not do this.

- Finally, can it grab wonders, district? I have no idea ....... :))) This requires testing, and I haven't tested this nearly enough (see my opening Note). Maybe, maybe not. Maybe there is a safeguard in the game already that prevents it, maybe there isn't.

IN OTHER WORDS: This is a culture bomb, but it's not a culture bomb... heh :). It smells and sounds like one (well, no, it does not sound like one), but it's a completely different process.

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

As for adding an XML requirement to test for being on resource (for anansethespider's request). This wouldn't work for the very same reasons that I had to create these two mods in the first place. The Culture Bomb Modifier is at the Player level (for SubjectRequirements) and does not check for anything to do with the improvement that it affects. The only time the improvement (pasture) appears at all, is in the arguments for the modifier. There is, AFAIK, no way to check in XML for the presence of a resource under the improvement for Culture Bomb purposes.
 
Oh yes you're right, I forgot why I had this problem in the first place. Ignore my suggestion Anase.

Gleb, what should I do if I want this to work for multiple districts? Can I list them all or do I have to make new versions of your code?

Edit: I see requiredDistrict == DistrictType but I dont know how to make an OR in Lua. Is it || ?

well I just looked it up. For a moment I forgot I could do that. Seems its just "or"?
 
Question, do you want to make it work for multiple district or for ANY district of a specified civilization?
If for ANY district, then, I think (without testing), just delete "and GameInfo.Districts[unitType].DistrictType == rRequiredDistrict", so you would get:

if orderType == 2 then

if for MULTIPLE districts, then you would have to define a number of variables for your districts (this is to make it simpler -- you could also create a table, but let's not get complicated), as in (at the beginning of the code):

rRequiredDistrictA = "DISTRICT_A"

rRequiredDistrictB = "DISTRICT_B"

etc., then change the condition to (don't forget the brackets):

if orderType == 2 and (GameInfo.Districts[unitType].DistrictType == rRequiredDistrictA or GameInfo.Districts[unitType].DistrictType == rRequiredDistrictB) then

so forth.

Test this and let me know how it works.
 
Oh yes, of course deleting it would work. Wow, its been awhile since I've used functions.

I can't do if (districtType == (A or B)) ?

Also, I don't understand how its supposed to limit the tile grabs to only the ones in range of a city. It looks like its limiting the strategic resource *source* to have to be in range of a city as far as I can tell.
 
@anansethespider Here you go! :) I did some limited testing, and all the functionality works as advertised, but do some more testing and let me know. If there are problems, I'll fix them.

The LUA file contains the parameters. I've set the culture bomb to the radius of 1 plot, the Civilization Type to Australia, and the Improvement Type to Pasture.

The SQL file contains the delete statement for the database. It deletes Australia's existing Culture Bomb trait. The SQL file is set to load at the last possible moment, so it should overwrite any changes made by any other mods or DLCs.
 

Attachments

Ah I can add a cityX and cityY to your function and an AND statement, I assume. My goodness I'm out of practice. And uCity.getX would give me the X value of its plot?
 
@Atlas627 Sorry, I was not clear. It's NOT AT ALL limiting the culture bomb and its grabs to those without a city's purchase plot range. It's only limiting the plot of the strategic improvement to those within that range. I didn't mean that the culture bomb would be limited to it, just the source of the bomb. E.g. if you attach this mechanic to a fort and go build it somewhere outside the city's area, it simply won't work.

As for (districtType == (A or B)) -- sure, you could probably do this, I don't see why not, but I am only a beginner in LUA, and (since I am a lawyer, not a coder by profession, heh, and it has been a very long time since I've programmed even in Basic), you are probably ahead of me there.
 
All the functions you need (and the modding community is aware of) are here: LINK. Yes, uCity:GetX() and uCity:GetY() will get you the values. You need the colon though, not a period in this case.

For Ananse - see above for the file, in case you missed in the flurry of these messages :)) Let me know how it works for you. I am eager to find out!
 
I have never used Lua before, but have experience in several other languages. You're doing very well haha

I think your function will hand me tiles I can't normally get (other people's districts and wonders) since you are going straight to the world builder to reassign ownership, so it might bypass sensible rules. Idk if worldbuilder or a district/wonder's attachment to a city has higher priority.

And thanks, I would've been an idiot and used a period. Too used to C++ and Python lol
 
NP :) There are ways to limit the behaviour of the WorldBuilder function. As follows:

Plot:GetOwner()

Plot:GetDistrictType()

for k,pPickPlot in pairs (function) do
if NOT pPickPlot:GetOwner() ~= pPlayer and pPickPlot:GetDistrictType() ~= -1 then
ASSIGN OWNERSHIP​
end​
end

As for using WorldBuilder at all... the problem was that using the other available function -- Plot:SetOwner() produced some very bizzare results. The ownership was changed, but the tiles were NOT workable by the city. That function is bugged.
 
Last edited:
Atlas, so I changed the Culture Bomb function to the following:

--====================================================================================================================
-- Culture Bomb Function
--====================================================================================================================

function DetonateCultureBomb( PlotX, PlotY, iPlotRadius, pPlayer, pCity )
if (PlotX ~= nil) and (PlotY ~= nil) and (PlotX > 0) and (PlotY > 0) then
for k,pPickPlot in pairs(GetAllPlotsInRadiusR(Map.GetPlot(PlotX, PlotY), iPlotRadius, "ExcludeCenterPlot")) do
local bAddPlot = (Map.GetPlotDistance(PlotX, PlotY, pPickPlot:GetX(), pPickPlot:GetY()) <= iPlotRadius)
if bAddPlot then
local pOtherOwner = pPickPlot:GetOwner()
local pOtherDistrict = pPickPlot:GetDistrictType()
if not (pOtherOwner ~= pPlayer and pOtherDistrict ~= -1) then
WorldBuilder.CityManager():SetPlotOwner( pPickPlot:GetX(), pPickPlot:GetY(), pPlayer, pCity )
end
end
end
end
end

I don't get any errors, and it looks fine. This would check for the presence of other Civilizations districts'in the culture bomb area and deny them.
There is also Plot:GetWonderType(). Now, I think this checks for Wonders(Buildings), but it may not. There is another function down the list that
checks for Natural Wonders. You can use this one as well to further impose some checks and balances.
 
Just for testing purposes:

if not pPickPlot:IsNaturalWonder() then

successfully excluded a Natural Wonder tile from the culture bomb. So, the other limiters above should work as intended.
 
Atlas, so I changed the Culture Bomb function to the following:

--====================================================================================================================
-- Culture Bomb Function
--====================================================================================================================

function DetonateCultureBomb( PlotX, PlotY, iPlotRadius, pPlayer, pCity )
if (PlotX ~= nil) and (PlotY ~= nil) and (PlotX > 0) and (PlotY > 0) then
for k,pPickPlot in pairs(GetAllPlotsInRadiusR(Map.GetPlot(PlotX, PlotY), iPlotRadius, "ExcludeCenterPlot")) do
local bAddPlot = (Map.GetPlotDistance(PlotX, PlotY, pPickPlot:GetX(), pPickPlot:GetY()) <= iPlotRadius)
if bAddPlot then
local pOtherOwner = pPickPlot:GetOwner()
local pOtherDistrict = pPickPlot:GetDistrictType()
if not (pOtherOwner ~= pPlayer and pOtherDistrict ~= -1) then
WorldBuilder.CityManager():SetPlotOwner( pPickPlot:GetX(), pPickPlot:GetY(), pPlayer, pCity )
end
end
end
end
end

I don't get any errors, and it looks fine. This would check for the presence of other Civilizations districts'in the culture bomb area and deny them.
There is also Plot:GetWonderType(). Now, I think this checks for Wonders(Buildings), but it may not. There is another function down the list that
checks for Natural Wonders. You can use this one as well to further impose some checks and balances.

If there is no owner, won't pOtherOwner = NULL and thus ~= pPlayer?

I made 2 changes to your code and then tested it. The first is to remove the district check, the second is to add a check for distance from the city.

local bAddPlot = ((Map.GetPlotDistance(PlotX, PlotY, pPickPlot:GetX(), pPickPlot:GetY()) <= iPlotRadius) and (Map.GetPlotDistance(pCity:GetX(), pCity:GetY(), pPickPlot:GetX(), pPickPlot:GetY()) <= 3))

and of course I changed it to be Brazil instead of Egypt. And nothing happens when I place a district next to rainforest. I'm pretty sure I've done everything correctly. See anything horribly wrong?
 
Back
Top Bottom