Experiencing problems with lua

Countbuffalo

Chieftain
Joined
Aug 16, 2013
Messages
94
For my Civ I'm writing several pieces of Lua, I've created what I need, though it doesn't seem to work.

This first piece is meant to give +1 happiness from every wheat resource in the player's territory using a dummy building:

Code:
function Happinessfromwheat(iplayer)
   local pplayer = Players[player]
   if pplayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then
   for pCity in pPlayer:Cities() do

   local NumberCultureBuildings = 0;
   for i = 0, pcity:GetNumCityPlots() -1,1 do
   local pPlot = Pcity:GetCityIndexPlot(i)
   if pPlot:GetOwner() ==player a pPlot:GetResourceType() == GameInfoTypes.RESOURCE_WHEAT then
   local NumberCultureBuildings = NumberCultureBuildings + 1
   end

pCity:SetNumRealBuilding(GameInfoTypes["BUILDING_UDON"], NumberCultureBuildings)
   end
end




If anyone can lend me a hand I'd be grateful, thanks.
 
  1. 'player' is never defined anywhere, so will always give 'nil', and lead to 'nil value errors'
    • you are using 'iplayer' as the variable for the data sent to your function as the function's 1st argument, so all your references within your function have to exactly-match that usage.
      Code:
      function Happinessfromwheat(iplayer)
  2. lua is case-sensitive, so 'pplayer' != 'pPlayer' so in this line
    Code:
    if pplayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then
    the conditions will never be met because 'pPlayer' has never been defined, and therefore would result in a 'nil value' error or 'nil' being compared to a number error
  3. You have similar variable-naming issues in your references to the city currently being processed in the code. You are using 'pCity' on the line
    Code:
    for pCity in pPlayer:Cities() do
    therefore all references to an individual city within that loop must match to this usage and cannot use 'pcity' or 'Pcity'.
  4. you are missing at least two 'ends' in your code. Fixing the variable-name errors already mentioned, and using tabs instead of space-indenting to align your 'end' commands with matching 'for', 'if', etc., commands, two missing 'end' commands are more easily seen
    Code:
    function Happinessfromwheat(iplayer)
    	local pPlayer = Players[iplayer]
    	if pPlayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then
    		for pCity in pPlayer:Cities() do
    			local NumberCultureBuildings = 0;
    			for i = 0, pCity:GetNumCityPlots() -1,1 do
    				local pPlot = pCity:GetCityIndexPlot(i)
    				if pPlot:GetOwner() == iplayer a pPlot:GetResourceType() == GameInfoTypes.RESOURCE_WHEAT then
    					local NumberCultureBuildings = NumberCultureBuildings + 1
    				end
    			end
    			pCity:SetNumRealBuilding(GameInfoTypes["BUILDING_UDON"], NumberCultureBuildings)
    		[color="red"]???[/color]
    	[color="red"]???[/color]
    end
  5. You have a typo here:
    Code:
    if pPlot:GetOwner() == iplayer [color="red"]a[/color] pPlot:GetResourceType() == GameInfoTypes.RESOURCE_WHEAT then
    The lonely a needs to be 'and'
  6. You also have never told the game to use your function by assigning the function as an additional item to be run under one of the game's lua 'hook events', so even fixing the code-errors already mentioned will not cause anything to happen
  7. You need as this
    Code:
    function Happinessfromwheat(iplayer)
    	local pPlayer = Players[iplayer]
    	if pPlayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then
    		for pCity in pPlayer:Cities() do
    			local NumberCultureBuildings = 0;
    			for i = 0, pCity:GetNumCityPlots() -1,1 do
    				local pPlot = pCity:GetCityIndexPlot(i)
    				if pPlot:GetOwner() == iplayer and pPlot:GetResourceType() == GameInfoTypes.RESOURCE_WHEAT then
    					NumberCultureBuildings = NumberCultureBuildings + 1
    				end
    			end
    			pCity:SetNumRealBuilding(GameInfoTypes["BUILDING_UDON"], NumberCultureBuildings)
    		end
    	end
    end
    GameEvents.PlayerDoTurn.Add(Happinessfromwheat)
    And this assumes I have not missed any other errors.
 
First of all: Enable logging. This will help you tremendously.

After that, you'll get an error message telling you about the fact you haven't closed the function (there is a few 'end' statements missing).

After solving this syntax error, we come back to the second line of code:
Code:
function Happinessfromwheat([U]iplayer[/U])
[COLOR="Red"]   local pplayer = Players[[U]player[/U]][/COLOR]
[...]

You will never have the right player, because 'player' isn't defined anywhere. This should be 'iplayer'.


Right after that, we have another problem:
Code:
if [B]pplayer[/B]:IsAlive() and [B]pPlayer[/B]:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then
		for pCity in [B]pPlayer[/B]:Cities() do
Lua is case-sensitive, which means pplayer was indeed defined before, while pPlayer wasn't, so the code will never go past the second check (it will return 'pPlayer isn't defined anywhere').
We see this same issue a bit later with pCity.


After a bit, in the near end of the code, we see this:
Code:
if pPlot:GetOwner() [U]==player[/U] [B]a[/B] pPlot:GetResourceType() == GameInfoTypes.RESOURCE_WHEAT then
pPlot:GetOwner() returns the owner's ID, so what you're looking for here is iPlayer. Also, you need to get a space between those == and the variable.
Also, that 'a' should be 'and'.


Lastly, this:
Code:
[B]local[/B] NumberCultureBuildings = NumberCultureBuildings + 1
You're creating a whole new NumberCultureBuildings with that 'local', different from the one in the beginning of the code. Drop this off. For more about local variables, take a look at the tutorial at the end of this post.


In the end, your code will look like this:
Code:
function Happinessfromwheat(iPlayer)
   local pPlayer = Players[iPlayer]
	if pPlayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then
		for pCity in pPlayer:Cities() do
			local NumberCultureBuildings = 0
			for i = 0, pCity:GetNumCityPlots() -1, 1 do
				local pPlot = pCity:GetCityIndexPlot(i)
				if pPlot:GetOwner() == iPlayer and pPlot:GetResourceType() == GameInfoTypes["RESOURCE_WHEAT"] then
					NumberCultureBuildings = NumberCultureBuildings + 1
				end
			end
			pCity:SetNumRealBuilding(GameInfoTypes["BUILDING_UDON"], NumberCultureBuildings)
		end
	end
end


[COLOR="Blue"]GameEvents.PlayerDoTurn.Add(Happinessfromwheat)[/COLOR]

The blue line is assuming you have posted your whole code, which means it wasn't being hooked to anything so no way it would work anyway.


Here is a beginner's guide for Lua. It is just the initial steps, but it might help you with your coding career.



EDIT: Beaten by 8 whole minutes. :(
 
EDIT: Beaten by 8 whole minutes. :(
I iz teh ninja :D

Though I did miss spotting the second 'localizing' of NumberCultureBuildings, so I guess I only get 1/2 ninja :sad:
I fixed it in my post at the bottom there showing suggested 'clean' code
 
Thanks for the help, I've changed my LUA but it still doesn't want to work, the hiddenbuilding doesn't seem to be working, I even changed the yields to see if it was a issue with the happiness yield.

I'll attach my WIP mod to help get to the bottom of this. My LUA log isn't turning up any errors, nor is my Database log.

Well, I would if it was small enough, I'll have to just put the code. You have the code for the trait, this is the code for the hidden building.

Code:
<Buildings>
		<Row>
			<Type>BUILDING_UDON</Type>
			<BuildingClass>BUILDINGCLASS_UDON</BuildingClass>
			<Cost>-1</Cost>
			<Help>TXT_KEY_BUILDING_UDON_HELP</Help>
			<Description>TXT_KEY_BUILDING_UDON_DESC</Description>
			<Civilopedia>TXT_KEY_BUILDING_UDON_PEDIA</Civilopedia>
			<Strategy>TXT_KEY_BUILDING_UDON_STRATEGY</Strategy>
			<ArtDefineTag>ART_DEF_BUILDING_UDON</ArtDefineTag>
			<GreatWorkCount>-1</GreatWorkCount>
			<MinAreaSize>-1</MinAreaSize>
			<HurryCostModifier>0</HurryCostModifier>
			<IconAtlas>CIV_COLOR_ATLAS_YUNA</IconAtlas>
			<PortraitIndex>0</PortraitIndex>
			<UnmoddedHappiness>1</UnmoddedHappiness>
			<NeverCapture>True</NeverCapture>
			<Happiness>1</Happiness>
		</Row>
 <Buildings>

Strange, I just did a test for the building to give great scientist points instead of happiness, and it seemed to work. But it doesn't work with Happiness.
How would I make it so the building can stack and there can be multiple in one city? The lua has it covered, but the XML doesn't seem to support it.
 
Zip and attach the actual mod itself rather than snippets of code: whoward69's zip your mods and attach tutorial. As stated in the tutorial we want a zip of the active mod from the game's MODS folder, and not the whole project from within the Firaxis Modbuddy folder. Zip the entire folder of your mod, so that we can copy-paste the whole thing into our game's MODS folder if need be.

Happiness and UnmoddedHappiness do in fact 'stack' for multiple copies of the same building, but the 'Happiness' column is what is used by the Colosseum, etc., and so you can never have more 'Happiness' from buildings than you have citizens within a city.

'UnmoddedHappiness' is what some people often refer to as 'Global Happiness', and goes directly to the Empire's 'Happiness Score' on the top ribbon of the game UI. UnmoddedHappiness is not affected by the population within the city.
 
Sorry about that, It was over the file size but I temporarily removed the war and peace music so it'll fit now.

Nevermind, I have absolutely no idea what I'm doing, it seems to work perfectly now. Sorry to waste your time like that.

Thanks for helping me to get it working. I have some other LUA to do, so I might end up coming back.

Thanks again.

Actually, my lua to give 2 tourism for every culture seems to not work, I had a working format earlier, however I realised this gave tourism if the Players culture was LESS than 5, rather than for every value of 5

Code:
function tourismfromculture(PlayerID)
		local pPlayer = Players[PlayerID]

 --If player is Yuna
		if pPlayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"] then

 --Get Civ Culture
			local CultCount = pPlayer:GetTotalJONSCulturePerTurn()
			local CultBldg = GameInfoTypes["BUILDING_HEROES"];
			if    CultCount = 5 then
			
			end

--Create Local building giving tourism
			for city in pPlayer:Cities() do
			city:SetNumRealBuilding(CultBldg, CultCount)
		end 
	end
end

GameEvents.PlayerDoTurn.Add(tourismfromculture)

On top of this, would I need to use something like this:

Code:
local CultCount = math.floor(CultCount * 0.20)

To divide my value by 5? Then for every 5 create a dummy building?
 

Attachments

  • The Hero Club (v 2).zip
    973.3 KB · Views: 32
  1. These don't match to one another:
    Code:
    <GameData>
    	<BuildingClasses>
    		<Row>
    			<Type>[color="blue"]BUILDINGCLASS_UDON[/color]</Type>
    			<DefaultBuilding>[color="blue"]BUILDING_UDON[/color]</DefaultBuilding>
    			<Description>TXT_KEY_BUILDING_UDON</Description>
    		</Row>
    		<Row>
    			<Type>BUILDINGCLASS_HEROES</Type>
    			<DefaultBuilding>BUILDING_HEROES</DefaultBuilding>
    			<Description>TXT_KEY_BUILDING_HEROES</Description>
    		</Row>
    		<Row>
    			<Type>BUILDINGCLASS_GOODDEED</Type>
    			<DefaultBuilding>BUILDING_GOODDEED</DefaultBuilding>
    			<Description>TXT_KEY_BUILDING_GOODDEED</Description>
    		</Row>
    	</BuildingClasses>
    	<Buildings>
    		<Row>
    			<Type>[color="blue"]BUILDING_UDON[/color]</Type>
    			<BuildingClass>[color="red"]BUILDINGCLASS_LIBRARY[/color]</BuildingClass>
    			<Cost>-1</Cost>
    			<Help>TXT_KEY_BUILDING_UDON_HELP</Help>
    			<Description>TXT_KEY_BUILDING_UDON_DESC</Description>
    			<Civilopedia>TXT_KEY_BUILDING_UDON_PEDIA</Civilopedia>
    			<Strategy>TXT_KEY_BUILDING_UDON_STRATEGY</Strategy>
    			<ArtDefineTag>ART_DEF_BUILDING_UDON</ArtDefineTag>
    			<GreatWorkCount>-1</GreatWorkCount>
    			<MinAreaSize>-1</MinAreaSize>
    			<HurryCostModifier>0</HurryCostModifier>
    			<IconAtlas>CIV_COLOR_ATLAS_YUNA</IconAtlas>
    			<PortraitIndex>0</PortraitIndex>
    			<UnmoddedHappiness>1</UnmoddedHappiness>
    			<NeverCapture>True</NeverCapture>
    			<Happiness>1</Happiness>
    		</Row>
  2. For hidden buildings, these are not really required, and not generally useful to specify:
    Code:
    <Help>TXT_KEY_BUILDING_UDON_HELP</Help>
    <Civilopedia>TXT_KEY_BUILDING_UDON_PEDIA</Civilopedia>
    <Strategy>TXT_KEY_BUILDING_UDON_STRATEGY</Strategy>
  3. The game won't really know what to do with this Art-Define
    Code:
    <ArtDefineTag>ART_DEF_BUILDING_UDON</ArtDefineTag>
    so it is generally better to just specify NONE or omit the line altogether if not using one of the pre-defined art-defines Firaxis used with buildings. Although an unknown art-define reference generally doesn't cause anything within <Buildings> to fail of proper implimentation.
  4. Nothing wrong in the lua code, it works just fine.
  5. Your Tourism mechanic, however, has multiple problems:
    • The game is discarding the entire file Tourism.lua because of syntax error(s), the first of which is located on line #9:
      Code:
      -- Unit
      -- Author: Alexander
      -- DateCreated: 2/16/2016 12:23:41 PM
      --------------------------------------------------------------
      function tourismfromculture(PlayerID)
      	local pPlayer = Players[PlayerID]
      
      	--If player is Yuna
      	if pPlayer:IsAlive() and pPlayer:GetCivilizationType() == GameInfoTypes["CIVILIZATION_HERO"][color="red"][b])[/b][/color] then
      
      		--Get Civ Culture
      		local CultCount = pPlayer:GetTotalJONSCulturePerTurn()
      		local CultBldg = GameInfoTypes["BUILDING_HEROES"];
      		if CultCount > 5 then
      			CultCount = 5
      		end
      
      		--Create Local building giving tourism
      		for city in pPlayer:Cities() do
      			city:SetNumRealBuilding(CultBldg, CultCount)
      		end 
      	end
      end
      
      GameEvents.PlayerDoTurn.Add(tourismfromculture)
      You have an extra ) which does not match-up to an opening (
    • The game does not allow multiple copies of the same building within the same city to 'stack' a Tourism effect, so it does not matter how many copies of BUILDING_HEROES is added within one city, all the Tourism that will ever be added within a single city is '2'. Doesn't matter if your code adds '1', '5', or '1500' copies of the building within the same city, you still only get '2' Tourism added to that city because this is what you have stated here
      Code:
      <TechEnhancedTourism>2</TechEnhancedTourism>
    • If the game did not refuse to 'stack' Tourism from multiple copies of the same building, you would be adding +10 Tourism to every city in the player's empire as soon as the player was generating at least 5 Culture Per Turn. This would be essentially a nearly-instant culture victory merely from playing as your civilization as soon as all major civilizations were met by the player.
 
Yeah, I realised I'd need to probably unlock it once a technology was researched, as it's too powerful to have at the start.
 
Checking for equality on a conditional 'if' line requires '==' rather than '='

Haven't looked closely at the rest of your code in the updated post #7 because of the issues mentioned in #s 5b & 5c in my post #8
 
Top Bottom