1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Experiencing problems with lua

Discussion in 'Civ5 - SDK / LUA' started by Countbuffalo, Feb 19, 2016.

  1. Countbuffalo

    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.
     
  2. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,979
    Location:
    Illinois, USA
    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.
     
  3. bane_

    bane_ Howardianism High-Priest

    Joined:
    Nov 27, 2013
    Messages:
    1,559
    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. :(
     
  4. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,979
    Location:
    Illinois, USA
    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
     
  5. Countbuffalo

    Countbuffalo Chieftain

    Joined:
    Aug 16, 2013
    Messages:
    94
    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.
     
  6. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,979
    Location:
    Illinois, USA
    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.
     
  7. Countbuffalo

    Countbuffalo Chieftain

    Joined:
    Aug 16, 2013
    Messages:
    94
    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?
     

    Attached Files:

  8. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,979
    Location:
    Illinois, USA
    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.
     
  9. Countbuffalo

    Countbuffalo Chieftain

    Joined:
    Aug 16, 2013
    Messages:
    94
    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.
     
  10. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,979
    Location:
    Illinois, USA
    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
     
  11. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,979
    Location:
    Illinois, USA
    5b is the thing that is going to kill you, however.
     

Share This Page