• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

LUA Trait Help

For great people the AI only ever considers what the great people can do, like create a great work, and if they can't do that at that moment then as I recall they will only ever consider whether they can use them to create a Holy Site, or an Academy, or what-have-you.

See, this is half the battle... trying to figure out whether the AI will actually take advantage of your abilities. Do you think it's possible (or worth it) to write lua to force the non-human players to garrison the Griot?

And no there aren't any flavors to assign to a unit to make the AI want to use them as a garrison more than they would otherwise except for the basic Defense flavoring.

Is it possible to flavour the Griot in 100 defense that way like a combat unit? So long as the AI at least considers garrisoning a Griot - I'm not expecting them to garrison it throughout the whole game, just when it seems appropriate.

Also, what are using to make the building bump the city's tourism by 10% ?

Not sure if it would work, but I added a "<GreatWorksTourismModifier>10</GreatWorksTourismModifier>" row that I pilfered from the Hotel.xml (which is 50 instead) to the Griot Dummy Building. Given that tourism seems to only be displayed as full integers, rather than decimals, I wasn't sure if 10% was appropriate.

Also, was this what you were thinking when discussing a condensed 'PlayerDoTurn' function?:

Code:
function UUBoosts(iPlayer)
    local pPlayer = Players[iPlayer]
    if pPlayer:GetCivilizationType() == senegal ID then   
        for pCity in pPlayer:Cities() do pCity:GetGarrisonedUnit() then
                for pUnits in pPlayer:Units() do
                    if pUnit:GetUnitType() == griotID then
                        pCity:SetNumRealBuilding(griDummyBID, 1)
                    else
                        pCity:SetNumRealBuilding(griDummyBID, 0)
                    if pUnit:GetUnitType() == gendarmerieID then
                        pCity:SetNumRealBuilding(genDummyBID, 1)
                    else
                        pCity:SetNumRealBuilding(genDummyBID, 0)
                    end
                end
            end
        end
    end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)

Alternatively, I have also written this as well to satisfy not using GetGarrisonedUnit() instead:

Code:
function UUBoosts(iPlayer)
    local pPlayer = Players[iPlayer]
    if pPlayer:GetCivilizationType() == senegal ID then   
        for pCity in pPlayer:Cities() do
            for pUnit in pPlayer:Units() do
                if pUnit:GetX() == pCity:GetX() and pUnit:GetY() == pCity:GetY() then
                    if pUnit:GetUnitType() == griotID then
                        pCity:SetNumRealBuilding(griDummyBID, 1)
                    else
                        pCity:SetNumRealBuilding(griDummyBID, 0)
                    if pUnit:GetUnitType() == gendarmerieID then
                        pCity:SetNumRealBuilding(genDummyBID, 1)
                    else
                        pCity:SetNumRealBuilding(genDummyBID, 0)
                    end
                end
            end
        end
    end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)
 
Every "if" has to have its own "then" and its own "end". "elseif" is a sub-set of "if"
Code:
if (something == onething) then
   --do something
elseif (something == somethingelse) then
   --do something else
elseif (something == somethirdthing) then
   -- do something even more wierd
else
   --do a fourth thing if none of the other conditions are met
end
  1. Evaluations are done "top-down", so if the condition on the "if" line is met none of the other are considered.
  2. If the condition on the "if" line is not met but the condition on the first "elseif" line is met, then none of the lower-down conditions will ever be considered.
  3. The "else" condition will only be executed if none of the other conditions are met, and it will always be executed if none of the other conditions are met.
  4. Also an "else" condition should never be listed above any "elseif" condition.
  5. And note that the "else" condition does not require a "then" whereas all the "elseif" conditions do require a "then"

I would do as
Code:
function UUBoosts(iPlayer)
	local pPlayer = Players[iPlayer]
	if (pPlayer:GetCivilizationType() == senegalID) then   
		for pCity in pPlayer:Cities() do
			pCity:SetNumRealBuilding(griDummyBID, 0)
			pCity:SetNumRealBuilding(genDummyBID, 0)
			local pCityPlot = pCity:Plot()
			if pCityPlot:IsUnit() then
				for i = 0, (pCityPlot:GetNumUnits() - 1) do
					local pUnit = pCityPlot:GetUnit(i)
					if pUnit then
						if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
							pCity:SetNumRealBuilding(griDummyBID, 1)
						elseif (pUnit:GetUnitType() == gendarmerieID) and (pUnit:GetOwner() == iPlayer) then
							pCity:SetNumRealBuilding(genDummyBID, 1)
						end
					end
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)
I'm pretty sure you defined the variable as "senegalID" rather than "senegal ID"

Some people will use the "Plot:GetUnit()" method to extract the unit object for a unit that is on a plot if there is a unit there, but the problem with that method is that it only ever will give you the "zero" unit that is on a plot. And if the "zero" unit is a Naval Great Person that is what you will get, for example, regardless of whether there is a land combat unit on the same plot. The only way to ensure you are getting all the data you need to look at (or are getting the correct sort of data, really) for all units that may be on a plot is to do an iteration through all the units occupying the plot, as shown.

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

About the only way you'd be able to get an AI to "garrison" a great person unit would be to set the unit's moves to "0" every turn. Giving a great person a giant defense value would not have any effect so long as the great person's <DefaultUnitAI> value in table <Units> is one of the great-people values. For great people the game does not consider unit-flavorings, and as I recall how it works, if the <DefaultUnitAI> is one of the great-people settings the AI will not try to do anything with the unit except its two usual great people abilities. If you don't allow your unique great person to do any of the usual great people things by not stating it can do X in the definition of the unit, I think all the AI will do is leave the unit idle wherever it first appeared. You really can't very easily get the AI to anything outside the scope of normal great people things with custom verions of great people.
 
Last edited:
Thanks again buddy, this must have taken you forever to learn...

it only ever will give you the "zero" unit that is on a plot

What defines a zero unit? Is it the unit that hits the plot first?

Is it possible to clarify if I can flavour the Griot in 90-100 defense that way like a combat unit? So long as the AI at least considers garrisoning a Griot - I'm not expecting them to garrison it throughout the whole game, just when it seems appropriate. E.g.

Code:
    <Unit_Flavors>
        <Row>
            <UnitType>UNIT_GRIOT</UnitType>
            <FlavorType>FLAVOR_CULTURE</FlavorType>
            <Flavor>1</Flavor>
        </Row>
        <Row>
            <UnitType>UNIT_GRIOT</UnitType>
            <FlavorType>FLAVOR_DEFENSE</FlavorType>
            <Flavor>90</Flavor>
        </Row>
    </Unit_Flavors>
 
I can't remember which is your great person. But for the great person it will not matter. For the other unit, it will only garrison reliably as I recall if it thinks it (the AI's empire) is being attacked, as I recall. And then the AI will probably garrison a city under threat with some other unit, because the ways of AI "thinking" are, well, ... what they are, and they never seem to want to do what we would like them to do.

-----

The "zero" unit is the way I refer to the first unit it would iterate through when going through all units on a plot. Has nothing to do with how long the unit has been on the plot.
 
Last edited:
Hmmm... maybe it would be better if instead of garrisoning the unit(s), they could simply appear in the city's working radius for the effects to work? Then the AI would have a chance of benefitting from it too?

Is it then just a simple case of changing "pCity:Plot()" to "pCity:GetCityIndexPlot()"?
 
Hence:

Code:
function UUBoosts(iPlayer)
    local pPlayer = Players[iPlayer]
    if (pPlayer:GetCivilizationType() == senegalID) then  
        for pCity in pPlayer:Cities() do
            pCity:SetNumRealBuilding(griotDummyBuildingID, 0)
            pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 0)
            for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do
                local pCityPlot = pCity:GetCityIndexPlot(iPlot)
                if pCityPlot:IsUnit() then
                    for iUnit = 0, (pCityPlot:GetNumUnits() - 1) do
                        local pUnit = pCityPlot:GetUnit(iUnit)
                        if pUnit then
                            if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
                                pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                            elseif (pUnit:GetUnitType() == gendarmerieID) and (pUnit:GetOwner() == iPlayer) then
                                pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 1)
                            end
                        end
                    end
                end
            end
        end
    end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)
 
That would work for giving a better chance whether or not to add the buildings. You could also implement that method when the player is an AI, and implement your original idea for needing to "garrison" the unit if the player is a human. Because humans can undersand complex additional stuff.

Just bear in mind that a single plot can be processed for more than one city when a player huddle-spams their cities, as the AI especially likes to do.

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

I see the forum's auto-formatting "got" you. :)
 
So I've been playing around with my concepts a bit. I think what I'll do is have the Gendarmerie (combat unit) have the city garrison bonus and have the Griot (great person) have the territory bonus. My thinking is that the AI may decide to send it out on a tour, which may require one or two turns in its territory while its leaving the country, thus reaping some benefit. I'd hate to unbalance it in a way that make the AI have different boosts to that of a human. Thus I've written this code:

Code:
function UUBoosts(iPlayer)
    local pPlayer = Players[iPlayer]
    if (pPlayer:GetCivilizationType() == senegalID) then   
        for pCity in pPlayer:Cities() do
            pCity:SetNumRealBuilding(griotDummyBuildingID, 0)
            pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 0)
            local pCityPlot = pCity:Plot()
            if pCityPlot:IsUnit() then -- Gendarmerie Boost
                for i = 0, (pCityPlot:GetNumUnits() - 1) do
                    local pUnit = pCityPlot:GetUnit(i)
                    if pUnit then
                        if (pUnit:GetUnitType() == gendarmerieID) and (pUnit:GetOwner() == iPlayer) then
                            pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 1)
                        end
                    end
                end
            for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do -- Griot Boost
                local pCityTerritoryPlot = pCity:GetCityIndexPlot(iPlot)
                if pCityTerritoryPlot:IsUnit() then
                    for iUnit = 0, (pCityTerritoryPlot:GetNumUnits() - 1) do
                        local pUnit = pCityTerritoryPlot:GetUnit(iUnit)
                        if pUnit then
                            if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
                                pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                            end
                        end
                    end
                end
            end
        end
    end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)

which I hope incorporates both in one function.
 
Also, I was thinking I would only limit the human player to one or two Griots (great person) at a time. This would effectively stop the human player from being able to 'hoard' Griots to their hearts content, since each city could conceivably have a large number of plots, and thus a large number of Griots to occupy each spot.

But does the city only allow one dummy building of each type to be built? Or will multiple dummy buildings be built for each Griot?
 
First, you are missing a needed "end" to terminate the "if pCityPlot:IsUnit() then".

Second, since your code is always setting the number of dummies in a particular city to "1", a single city will never have more than "1" of each type of dummy, regardless of how many of the units are within its "territory".

Third, pCity:GetNumCityPlots() always returns all 37 possible plots within a 3-tile radius of a city, regardless of how many plots a city or a player owns around the city.

Fourth, you can add as many copies of a dummy building to a single city as you want. This is often used to get "stackable" effects. Some effects that come from buildings will only implement, however, for the 1st Building_X placed in a city, and will not implement "stacked" effects for certain building-properties no matter how many additional copies of the same building are placed within the same city. For more info on these "stacking" limits, see the link in my signature re "Dummy Buildings and Building-Class Structure Issues".

Fifth, my suggestion re the difference between a human player and an AI player was to force the human player to actually park the unit in a city, but allow the AI to merely have the unit in or around a city. This actually benefits the AI more than the human. The AI would not understand it would need to "garrison" the unit to get the effect, and would generally not want to: the human would be able to handle this need, and the cost-vs-reward of this -- for example if there's a civilian unit parked in a city, then that city cannot buy workers, settlers, missionaries, great people, etc. And if there is a land combat unit parked in a city, that city cannot purchase land combat units.

Sometimes we just have to make our code do "X" if the player is a human, and do "Y" if the player is an AI, because the AI is essentially just pretty darned stupid.
 
Last edited:
Third, pCity:GetNumCityPlots() always returns all 37 possible plots within a 3-tile radius of a city, regardless of how many plots a city or a player owns around the city.

Is there a method that potentially iterates through all tiles owned by a city (which also goes beyond a 3 tile radius?)

I was thinking that, for example, if two cities are 4 tiles apart (as is the minimum), then there would be an overlap where 1 Griot would be present in two cities and thus produce a dummy building in each

I've noticed GetCityIndexPlot and GetCityPlotIndex, would they be any good? What's the difference between them?
 
GetCityPlotIndex merely gives you the plot ID # for the plot the city is located on.

To look at plots outside the city's 3-ring radius you would have to use William Howard's Plot Iterators utility, which allows you to iterate through all plots within a specified range of a central plot (and his system allows you to set-up other types of iterations, such as only looking at plots that are 4 tiles away from a central plot).

To ensure that only one city ever gets to use the same unit, you can create a table holding all the unit-IDs (for example) which have already given a dummy building to a city, and if a second city would be able to use this same unit, simply dis-allow it.
Code:
--some stuff snipped out
local tUnitsAlreadyProcessed = {}
      --create a table to hold the unit IDs before starting the loop through the player's cities
for pCity in pPlayer:Cities() do
	--some other stuff snipped out
	for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do -- Griot Boost
		local pCityTerritoryPlot = pCity:GetCityIndexPlot(iPlot)
		if pCityTerritoryPlot:IsUnit() then
			for iUnit = 0, (pCityTerritoryPlot:GetNumUnits() - 1) do
				local pUnit = pCityTerritoryPlot:GetUnit(iUnit)
				if pUnit then
					if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
						local iUnitID = pUnit:GetID()
						if not tUnitsAlreadyProcessed[iUnitID] then
							 --if the unit's ID# has not already been added as a "key" in the table, add the dummy building
							--then add the unit's ID# as a "Key" in the table with a value of text "processed"
							pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
							tUnitsAlreadyProcessed[iUnitID] = "processed"
						end
					end
				end
			end
		end
	end
end
---some stuff snipped out
 
Last edited:
Tables can prove quite useful it seems, thanks for the tip

I would still prefer to keep the plot iterations within friendly territory so is it possible to use the following method:

Plot:IsFriendly() somewhere in the code?
 
Code:
  <api object="Plot" method="IsFriendlyTerritory">
      <arg pos="2" type="PlayerTypes" name="ePlayer"/>
      <ret type="bool"/>
  </api>
I've never used it so I am not sure if it gives "true" for all "friendly or allied" city-states or just the allied ones, and whether any civ you have a declaration of friendship with also returns "true", but I suspect it would. It should return true for your own territory.

There is also
Code:
  <api object="Plot" method="IsOwned">
      <method class="CvPlot" fn="isOwned"/>
      <ret type="bool"/>
  </api>
But you can often just as easily use a comparison of Plot:GetOwner() to a specific Player ID directly when you want to limit an affect to plots owned by the player without need for the extra step of checking whether the plot is owned.
 
Would this code hold up then? I've added the GetOwner method to the third line? I wasn't sure if I'd be defining the variable as senegalID or iPlayer...

Code:
            for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do -- Griot Boost
                local pCityTerritoryPlot = pCity:GetCityIndexPlot(iPlot)
                if (pCityTerritoryPlot:GetOwner() == senegalID) then
                    if pCityTerritoryPlot:IsUnit() then
                        for iUnit = 0, (pCityTerritoryPlot:GetNumUnits() - 1) do
                            local pUnit = pCityTerritoryPlot:GetUnit(iUnit)
                            if pUnit then
                                if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
                                    local iUnitID = pUnit:GetID()
                                    if not tUnitsAlreadyProcessed[iUnitID] then
                                        --if the unit's ID# has not already been added as a "key" in the table, add the dummy building
                                        --then add the unit's ID# as a "Key" in the table with a value of text "processed"
                                        pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                                        tUnitsAlreadyProcessed[iUnitID] = "processed"
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end

Is there anything else I can write in terms of lua that may get the AI to consider moving their Griot more than wanting to set up a great work or tour?
 
You want iPlayer since senegalID will be the ID# of the civ from table Civilizations, and will never be equal to a PlayerID# from the lua Players table. Same thing as the line where you have
Code:
(pUnit:GetOwner() == iPlayer)

There's really nothing you can easily do in lua to over-ride the normal great people behavior. Any forced move mission you try to do will pretty much always simply be itself over-ridden during turn processing.

About the only other thing you can do for an AI unit would be to set the unit's moves to "0" every turn, and move the unit "manually" in lua, but then that would essentially shut off the ability of the AI to use the unit to do the normal Great Person things. Plus it would require some fairly complicated logic to ensure the unit not being able to move does not result in it being eaten by the Barbs or by an enemy unit, that the target tile each turn is really valid for a movement "destination", etc.
 
Code:
function UUBoosts(iPlayer)
    local pPlayer = Players[iPlayer]
    if (pPlayer:GetCivilizationType() == senegalID) then   
        for pCity in pPlayer:Cities() do
            pCity:SetNumRealBuilding(griotDummyBuildingID, 0)
            pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 0)
            local pCityPlot = pCity:Plot()
            if (pPlayer:IsHuman() == false) then --------------------------------- Griot Boost if Player is not Human
                if (pCity:GetNumGreatWorksInBuilding(operaHouseID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadcastTowerID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadwayID) > 0) or (pCity:GetNumGreatWorksInBuilding(sydneyOperaHouseID) > 0) then
                    pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                end
                for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do
                    local pCityTerritoryPlot = pCity:GetCityIndexPlot(iPlot)
                    if (pCityTerritoryPlot:GetOwner() == iPlayer) then
                        if pCityTerritoryPlot:IsUnit() then
                            for iUnit = 0, (pCityTerritoryPlot:GetNumUnits() - 1) do
                                local pUnit = pCityTerritoryPlot:GetUnit(iUnit)
                                if pUnit then
                                    if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
                                        local iUnitID = pUnit:GetID()
                                        if not tUnitsAlreadyProcessed[iUnitID] then
                                            --if the unit's ID# has not already been added as a "key" in the table, add the dummy building
                                            --then add the unit's ID# as a "Key" in the table with a value of text "processed"
                                            pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                                            tUnitsAlreadyProcessed[iUnitID] = "processed"
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)

Think this looks a bit too simple to work. I'm trying to give the same effects via the dummy building by having at least one great work of music in the above buildings AND the normal method.
 
Well, you've shut everything off for the human player. You forgot the "else" after this, I think (assuming I understand what you are trying to do)
Code:
if (pCity:GetNumGreatWorksInBuilding(operaHouseID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadcastTowerID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadwayID) > 0) or (pCity:GetNumGreatWorksInBuilding(sydneyOperaHouseID) > 0) then
    pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
end

You've also forgotten to create the tUnitsAlreadyProcessed table before starting the loop through the player's cities. You want to do this right below the line
Code:
if (pPlayer:GetCivilizationType() == senegalID) then

As a note in case you didn't realize, GetNumGreatWorksInBuilding wants the ID of a Building-Class as its argument, rather than the ID of any building within such a building-class.
 
Whoops.... sorry, I should have mentioned I snipped the code before I posted it, the full thing is:

Code:
-- UA: Négritude - +2 Griot points are earned for your capital when your units kill, or are killed.
-- UU: Gendarmerie - Replaces Infantry. When garrisoned in a city, the city's spy stealing rate reduced 10%, has +5 defence and generates +2 culture.
-- UU: Griot - Replaces Great Musician. Slower. When in a 3-tile radius of your city's territory, the city produces +1 happiness, +3 culture and +10% tourism. Only 1 set of effects per city.

----------------------------------------------------------------------------------------------------------------------------
-- GLOBAL VARIABLES
----------------------------------------------------------------------------------------------------------------------------
local senegalID = GameInfoTypes["CIVILIZATION_SENEGAL"]
local specialistGriotID = GameInfoTypes["SPECIALIST_MUSICIAN"]
local gendarmerieID = GameInfoTypes["UNIT_GENDARMERIE"]
local griotID = GameInfoTypes["UNIT_GRIOT"]
local gendarmerieDummyBuildingID = GameInfoTypes["BUILDING_GENDARMERIE_DUMMY"]
local griotDummyBuildingID = GameInfoTypes["BUILDING_GRIOT_DUMMY"]
local tUnitsAlreadyProcessed = {}
local operaHouseID = GameInfoTypes["BUILDINGCLASS_OPERA_HOUSE"]
local broadcastTowerID = GameInfoTypes["BUILDINGCLASS_BROADCAST_TOWER"]
local broadwayID = GameInfoTypes["BUILDINGCLASS_BROADWAY"]
local sydneyOperaHouseID = GameInfoTypes["BUILDINGCLASS_SYDNEY_OPERA_HOUSE"]
local randnum = math.random( 0 , 100)

----------------------------------------------------------------------------------------------------------------------------
---- WilliamHoward's IsCivInPlay
----------------------------------------------------------------------------------------------------------------------------
function IsCivInPlay(iCivType)
    for iSlot = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
        local iSlotStatus = PreGame.GetSlotStatus(iSlot)
        if (iSlotStatus == SlotStatus.SS_TAKEN or iSlotStatus == SlotStatus.SS_COMPUTER) then
            if (PreGame.GetCivilization(iSlot) == iCivType) then
                return true
            end
        end
    end
    return false
end

----------------------------------------------------------------------------------------------------------------------------
-- UA: NÉGRITUDE
----------------------------------------------------------------------------------------------------------------------------
function GriotPointsWhenUnitDie(iPlayer, iKilledPlayer, iKilledUnit)
    local pKillingPlayer = Players[iPlayer]
    local pKilledPlayer = Players[iKilledPlayer]
    if (pKillingPlayer:GetCivilizationType() == senegalID) or (pKilledPlayer:GetCivilizationType() == senegalID) then
        local griotPoints = 2
        local griotCity = pKillingPlayer:GetCapitalCity()
        if (pKillingPlayer:GetCivilizationType() ~= senegalID) then
            griotCity = pKilledPlayer:GetCapitalCity()
        end
        griotCity:ChangeSpecialistGreatPersonProgressTimes100(specialistGriotID, griotPoints*100)
        if pKillingPlayer:IsHuman() then
            Events.GameplayAlertMessage("Your unit has killed an enemy! Your capital gains 2 [ICON_GREAT_PEOPLE] Great Griot Points!")
        elseif pKilledPlayer:IsHuman() then
            Events.GameplayAlertMessage("Your unit was killed by an enemy. Your capital gains 2 [ICON_GREAT_PEOPLE] Great Griot Points!")
        end
    end
end

if (IsCivInPlay(senegalID) == true) then
    GameEvents.UnitKilledInCombat.Add(GriotPointsWhenUnitDie)
end

----------------------------------------------------------------------------------------------------------------------------
-- UU Boosts (Gendarmerie boosted by city garrison and Griot boosted by city limits)
----------------------------------------------------------------------------------------------------------------------------
function UUBoosts(iPlayer)
    local pPlayer = Players[iPlayer]
    if (pPlayer:GetCivilizationType() == senegalID) then   
        for pCity in pPlayer:Cities() do
            pCity:SetNumRealBuilding(griotDummyBuildingID, 0)
            pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 0)
            local pCityPlot = pCity:Plot()
            if pCityPlot:IsUnit() then -- Gendarmerie Boost
                for i = 0, (pCityPlot:GetNumUnits() - 1) do
                    local pUnit = pCityPlot:GetUnit(i)
                    if pUnit then
                        if (pUnit:GetUnitType() == gendarmerieID) and (pUnit:GetOwner() == iPlayer) then
                            pCity:SetNumRealBuilding(gendarmerieDummyBuildingID, 1)
                        end
                    end
                end
            end
            if (pPlayer:IsHuman() == true) then --------------------------------- Griot Boost if Player is Human
                for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do
                    local pCityTerritoryPlot = pCity:GetCityIndexPlot(iPlot)
                    if (pCityTerritoryPlot:GetOwner() == iPlayer) then
                        if pCityTerritoryPlot:IsUnit() then
                            for iUnit = 0, (pCityTerritoryPlot:GetNumUnits() - 1) do
                                local pUnit = pCityTerritoryPlot:GetUnit(iUnit)
                                if pUnit then
                                    if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
                                        local iUnitID = pUnit:GetID()
                                        if not tUnitsAlreadyProcessed[iUnitID] then
                                            --if the unit's ID# has not already been added as a "key" in the table, add the dummy building
                                            --then add the unit's ID# as a "Key" in the table with a value of text "processed"
                                            pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                                            tUnitsAlreadyProcessed[iUnitID] = "processed"
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
            if (pPlayer:IsHuman() == false) then --------------------------------- Griot Boost if Player is not Human
                if randnum >= 33 then
                    if (pCity:GetNumGreatWorksInBuilding(operaHouseID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadcastTowerID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadwayID) > 0) or (pCity:GetNumGreatWorksInBuilding(sydneyOperaHouseID) > 0) then
                        pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                    end
                end
                for iPlot = 0, pCity:GetNumCityPlots() - 1, 1 do
                    local pCityTerritoryPlot = pCity:GetCityIndexPlot(iPlot)
                    if (pCityTerritoryPlot:GetOwner() == iPlayer) then
                        if pCityTerritoryPlot:IsUnit() then
                            for iUnit = 0, (pCityTerritoryPlot:GetNumUnits() - 1) do
                                local pUnit = pCityTerritoryPlot:GetUnit(iUnit)
                                if pUnit then
                                    if (pUnit:GetUnitType() == griotID) and (pUnit:GetOwner() == iPlayer) then
                                        local iUnitID = pUnit:GetID()
                                        if not tUnitsAlreadyProcessed[iUnitID] then
                                            --if the unit's ID# has not already been added as a "key" in the table, add the dummy building
                                            --then add the unit's ID# as a "Key" in the table with a value of text "processed"
                                            pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                                            tUnitsAlreadyProcessed[iUnitID] = "processed"
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end
GameEvents.PlayerDoTurn.Add(UUBoosts)

Please note that I have tried to add a random number ("randnum") variable to the script to make the AI's cheat effect happen one third of the time (to reflect a great musicians three options for this civ), please let me know if it's shoddy or not
 
You still need to create the tUnitsAlreadyProcessed inside the UUBoosts function after the line
Code:
if (pPlayer:GetCivilizationType() == senegalID) then
Otherwise all data added to the table will persist throughout the game session and once a single unit causes a griotDummyBuildingID to be added to a city, the same unit cannot ever thereafter cause the building to be restored to or added to any city.

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

Doing this at the point you are will grab a randum number up to 100 at the start of each game session as it loads
Code:
local randnum = math.random( 0 , 100)
If the generated number is less that 33 then this code will never execute at all
Code:
                if randnum >= 33 then
                    if (pCity:GetNumGreatWorksInBuilding(operaHouseID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadcastTowerID) > 0) or (pCity:GetNumGreatWorksInBuilding(broadwayID) > 0) or (pCity:GetNumGreatWorksInBuilding(sydneyOperaHouseID) > 0) then
                        pCity:SetNumRealBuilding(griotDummyBuildingID, 1)
                    end
                end
The way you have it coded, though, would apply a 66% likelihood, were you not caching the value at the start of the game.

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

Randum numbers generated by the game are not actually random. Unless you reset the lua random number generator system, the number you get from doing "math.random(0,100)" at load of the game will probably always be the same number. Enabling the game's somewhat hidden option for reseeding the random number generator doesn't make a difference because you aren't reseeding the lua math.random

I would discard caching the variable at game start and simply do as
Code:
if math.random( 0 , 100) <= 33 then
This way every time the number generater is accessed it will be different.
 
Back
Top Bottom