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

A couple more "quick" inquiries

Discussion in 'Civ5 - Creation & Customization' started by AW Arcaeca, Dec 7, 2014.

  1. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    7,140
    Location:
    Illinois, USA
    Only so far as I know for two adjacent of the same improvement. ie, the NoTwoAdjacent column disables two of the same improvement next to each other.
     
  2. whoward69

    whoward69 DLL Minion

    Joined:
    May 30, 2011
    Messages:
    8,532
    Location:
    Near Portsmouth, UK
    It's nothing special. It just makes use of the fact that any civ running out of city names will borrow from others, first those in play, then any other civ in the database. It happens for The Huns as they only start with one name in <Civilization_CityNames>

    Same answer as post #2 here
     
  3. Agent327

    Agent327 Observer

    Joined:
    Oct 28, 2006
    Messages:
    16,102
    Location:
    In orbit
    Yeah, the first time I heard of the Huns' 'unique ability' I thought they must be kidding.

    Anyway, I have a map I edited and it's not showing up as a playable map, even though I put it in the Maps folder. Should I clear cache or something or what am I missing?
     
  4. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    So how about this... what file are the diplomacy responses defined in? Not Civ5Diplomacy_Responses, apparently. :p I'd just like to know what complete list of diplomacy response types exist for G&K; I can take some from other mods, but I don't which ones are BNW exclusive.
     
  5. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Another bump, to ask this hopefully quick lua syntax question:

    I basically have this function:
    Spoiler :
    Code:
    function utilityFunction(pUnit, testX, testY, testZ)
    	local pPlot = pUnit:GetPlot()
    	if testX then
    		if blah blah blah then
    			x = false
    		else
    			x = true
    		end
    	end
    	if testY then
    		if blah blah blah then
    			y = false
    		else
    			y = true
    		end
    	end
    	if testZ then
    		if blah blah blah then
    			z = false
    		else
    			z = true
    		end
    	end
    	return x, y, z
    end

    ("blah blah blah" has something to do with pPlot, so that being in there isn't pointless)
    And later, I want to find x and assign it to a, so I do this:
    Code:
    local a = utilityFunction(unit, true)[1]
    But that results in this error:
    Code:
    [48408.561] Runtime Error: C:\Users\travis\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's[REDACTED] Mod (v 1)\Lua/[REDACTED]/[REDACTED].lua:143: attempt to index a boolean value
    Is this wrong? Shouldn't this be returning a Boolean value (specifically the first one returned by utilityFunction), not indexing one?
     
  6. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    7,140
    Location:
    Illinois, USA
    Compare this:
    Code:
    local a = utilityFunction(unit, true)[1]
    With this:
    Code:
    local a = SomePreviouslyCreatedLuaTableName[1]
    In the second example a will be set to whatever value is currently in the #1 position of the list of items in lua table SomePreviouslyCreatedLuaTableName

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

    So, local a = utilityFunction(unit, true)[1] is interpretting utilityFunction(unit, true) as a reference to a table name. But since that function is returning a boolean ("true" or "false" doesn't matter which) the lua is generating an error because booleans can never be names of tables.
     
  7. DarkScythe

    DarkScythe Hunkalicious Holo

    Joined:
    May 6, 2014
    Messages:
    804
    I don't think you're understanding how the results returned from a function work -- you're trying to address them as a table, but it's not actually being returned as a table, hence the failure.

    A note on your function first, though - you seem to have quite a lot of redundancy going on that could be simplified, though the function is so heavily abstracted that I'm not entirely sure whether or not that's actually the case.

    However, since your 'else' condition is the same for everything, you could potentially simplify that part by simply defining those 'defaults' at the beginning: local x, y, z = true, true, true

    In any case, when you attempt to define the variable a, you include a table index with it -- [1]

    However, look at what utilityFunction returns: return x, y, z

    What are x, y and z?
    Throughout the function, assuming the conditions are correct for it to process each section fully, they hold either true or false -- these are booleans, not tables!

    When a function returns multiple values, each returned value must be held within its own variable. In this case, since utilityFunction() returns 3 values, you need to define up to 3 variables at once with it.

    local a, b, c = utilityFunction(unit, true)

    In this case, a would hold the value of x, b holds y, and c holds z. Since you're only concerned with the first value here, you could do local a = utilityFunction(unit, true) and a would still hold the value of x, but the returned values for y, and z will be discarded and lost. If you want the value of y, you will need to define at the minimum two variables, since the function returns the values in the order you've specified.

    The other issue is that your function is set up to take and process up to three additional parameters -- testX, testY, and testZ, but when you defined a, you only specified the value of testX. This would mean that y and z would never get processed, and their values will be nil.
     
  8. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Okay, another necro because I can't figure this out for the life of me:
    Code:
    function DefaultMoves(unit)
    	local unittype = unit:GetUnitType()
    	[B][COLOR="Red"]return GameInfo.Units{Type=unittype}.Moves[/COLOR][/B]
    end
    Code:
    [50674.272] Runtime Error: C:\Users\travis\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Lua/Functions.lua:10: attempt to index a function value
    Function value? :confused:
     
  9. JFD

    JFD Kathigitarkh

    Joined:
    Oct 19, 2010
    Messages:
    9,130
    Location:
    The Kingdom of New Zealand
    GetUnitType() returns a unit's ID (yay Firaxis :D), so you're comparing two different identifiers, and you don't even actually need to do that where using the GameInfo queries. GameInfo.Units[unittype].Moves would suffice.
     
  10. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Then... how finds one the unit's <Type>? GameInfo.Units[unittype].Type? Or did I totally miss what you're saying?
     
  11. DarkScythe

    DarkScythe Hunkalicious Holo

    Joined:
    May 6, 2014
    Messages:
    804
    If you mean the Unit's Type string, yes.

    If you start with the UnitTypeID, then you can plug that into GameInfo.Units[UnitTypeID].Type and get the unit's type string. Don't confuse it with a UnitID though, since that I believe is something separate to allow the game to track each of a player's individual units.
     
  12. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Alright, how about this:
    Say you've got a citizen unit and a military unit on the same tile. If you're writing code for specifically one of them, how do you specifically assign the other to some variable?
    If you tried to find the unit on that tile, would it return both?
     
  13. DarkScythe

    DarkScythe Hunkalicious Holo

    Joined:
    May 6, 2014
    Messages:
    804
    It generally would, yes.

    For the Lua code I've written for the Shana Civilization, I have code that works through multiple units on a tile.

    The gist of it is that for any given plot, you can grab the number of units on it by using pPlot:GetNumUnits().
    Then, you can iterate over the units in that plot with a simple for loop -- however, note that the unit index actually begins at zero, so you will need to start the loop with something like for i = 0, pPlot:GetNumUnits() - 1 do.
    Within that loop, you can find specific units with the loop iteration by using pPlot:GetUnit(i).
    After that, for Shana at least, I identify combat units with pUnit:IsCombatUnit() which should automatically exclude civilian units such as Workers, Settlers, Missionaries, etc.

    Hope that helps.
     
  14. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Alright, yeah, that seems to have knocked out the related errors, thanks.

    But a new problem, which I assume must be a new problem with the algorithm and not an "actual" error, since the logs and FireTuner report nothing.
    Basically, I want Unit X to "share" movement points with units from Unitcombat Y - that is, when Unit X starts on the same tile, or moves onto the same tile as a unitcombat Y unit, it is immediately given Y's number of moves left. And then X reverts back to its normal moves once it steps off the same tile.

    (EXAMPLE: So if Unitcombat Y was armored units, and unit Y was a tank (5 movement points, right?), and Unit X was a spearman, then if X moved one tile onto Y's tile, X's movement point # isn't 1, but 5. Then if the tank moved one tile, and the spearman moved onto the tank's new tile again, it would have 4 movement points. Hence, as long as the spearman keeps moving onto the tank's tile, it will have the same number of movement points as the tank. But it would revert back to having 0 once it steps off. That's the goal.)

    The latter is working all fine and dandy, but right now, X's moves get completely wiped out when it steps onto Y's tile.
    Spoiler :
    Code:
    GameEvents.UnitSetXY.Add(
    function(iPlayer, iUnit, iX, iY)
    	local pPlayer = Players[iPlayer]
    	local pUnit = pPlayer:GetUnitByID(iUnit)
    	if not (pUnit:GetUnitType() == GameInfoTypes.UNIT_X) then return end
    	local pPlot = pUnit:GetPlot()
    	if (pPlot:GetNumUnits() < 2) then return end [COLOR="seagreen"]-- if the X is alone or no one is on the tile[/COLOR]
    	for i = 0, pPlot:GetNumUnits() - 1 do
    		mUnit = pPlot:GetUnit(i)
    		if not (mUnit == pUnit) then
    			if (mUnit:GetUnitCombatType() == GameInfoTypes.UNITCOMBAT_Y) then
    		[COLOR="SeaGreen"]-- check function names
    		--	pUnit:SetMoves(GameInfo.Units{Type=pUnit:GetPlot():GetUnit():GetUnitType()}.Moves - pUnit:GetPlot():GetUnit():GetMoves())[/COLOR]
    				local iDefMoves = DefaultMoves(mUnit)
    				local iMoves = mUnit:GetMoves()
    				pUnit:SetMoves(iDefMoves - iMoves)
    			else
    				local iMoves = DefaultMoves(pUnit)
    				pUnit:SetMoves(iMoves - (iMoves - pUnit:GetMoves()))
    			end
    		end
    	end
    end)
    
    [COLOR="seagreen"]-- If a X starts a turn on a tile with a Y unit, then the X starts with the same number of movement points as that other unit[/COLOR]GameEvents.PlayerDoTurn.Add(
    function(iPlayer)
    	local pPlayer = Players[iPlayer]
    	for pUnit in pPlayer:Units() do
    		if not (pUnit:GetUnitType() == GameInfoTypes.UNIT_X) then return end
    		if (pUnit:GetPlot():GetUnit():GetUnitCombatType() == GameInfoTypes.UNITCOMBAT_Y) then
    			pUnit:SetMoves(GameInfo.Units[pUnit:GetPlot():GetUnit():GetUnitType()].Moves)
    		end
    	end
    end)

    I put the comment codes in green just to emphasize that one line that was removed but not deleted.

    And I assume DefaultMoves is now working since there are no errors about it, either. All it is is this:
    Code:
    function DefaultMoves(unit)
    	local unittype = unit:GetUnitType()
    	return GameInfo.Units[unittype].Moves
    end
    Just wondering if you could pick out the folly in my algorithm; I think I probably confused myself in the process of writing it.

    EDIT: WAIT!
    Here might be the problem: Do Unit.GetMoves() and DefaultMoves() return the same value? Because if so, then this:
    Code:
    pUnit:SetMoves(iDefMoves - iMoves)
    would always make pUnit's movement points 0.

    I might have just solved my own problem. I'll see what happens when I change that to pUnit:SetMoves(mUnit:MovesLeft()). Plz ignore!
     
  15. DarkScythe

    DarkScythe Hunkalicious Holo

    Joined:
    May 6, 2014
    Messages:
    804
    See the Lua I've written for Shana -- you're making a mistake in your assumption of what type of number pUnit:SetMoves() accepts.

    As part of my MoveEnemiesAndSpawnUnit() function, I override the newly spawned unit's movement with a specific number of moves, specified in the beginning of the file under the configurable variable:
    Code:
    local iSpawnedUnitInitialMovement = 0 -- How many moves a newly spawned Torch or Great Flame Haze should have
    This number is what you are familiar with, and what you get by querying the Units table to get the data from that unit's 'Moves' column.

    However, when I provide the necessary number of moves to the unit, you have to conduct one more step:
    Code:
    local iNewUnitMoves = [B]iSpawnedUnitInitialMovement * 60[/B]
    local pNewUnit = pPlayer:InitUnit(iUnitType, iX, iY)
    [B]pNewUnit:SetMoves(iNewUnitMoves)[/B]
    Therein lies your issue: pUnit:SetMoves() requires the number of moves you want it to have multiplied by 60!
     
  16. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Alright, so the bane of my existence turns out to be, among other things, working with a large number of plots. Somehow, I came the conclusion, I need a way to iterate over all of a player's plots. Since there is no such iterator as Player.Plots(), like there is with cities or units, my solution was to use PlotIterators to find every plot on the map beginning at a player's capital, and for every plot it finds along the way, it will add to a player-specific table.

    What this turns out to be is just my ineptitude on understanding how tables work, yet again.

    The function is this:
    Spoiler :
    Code:
    include("PlotIterators.lua")
    
    tPlayerPlots = {}
    function GetPlayerPlots(iPlayer)
    	-- reset plots:
    	tPlayerPlots[iPlayer] = nil;
    	local pPlayer = Players[iPlayer]
    	local pCap = pPlayer:GetCapitalCity()
    	local iX = pCap:GetX()
    	local iY = pCap:GetY()
    	-- find every plot in the world
    	for pEveryPlot in PlotAreaSweepIterator(Map.GetPlot(iX, iY), 99999, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_EXCLUDE) do
    	-- then add to tPlayerPlots under iPlayer if it's owned by iPlayer
    		if (pEveryPlot:GetOwner() == iPlayer) then
    			table.insert(tPlayerPlots[iPlayer], pEveryPlot)
    		end
    	end
    end
    Every time this function is called, it's supposed to reset the table of Players[iPlayer]'s plots.

    The plots are then accessed like so:
    Spoiler :
    Code:
    GetPlayerPlots(iPlayer)
    	for playerID, pPlot in pairs(tPlayerPlots) do

    And the game is complaining about this:
    Code:
    Runtime Error: C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 2)\LUA\PlotOwner_Functions.lua:20: bad argument #1 to 'insert' (table expected, got nil)
    So, this line:
    Code:
    table.insert(tPlayerPlots[iPlayer], pEveryPlot)
    Is the problem. I know a table can store plots, and not just, say, its coordinates, because code from JFD's Carthage written by sukritact does just that by way of table.insert. So apparently my method of adding plots to only one player's tPlayerPlots isn't working... but how do I fix it? Is it even salvageable?
     
  17. DarkScythe

    DarkScythe Hunkalicious Holo

    Joined:
    May 6, 2014
    Messages:
    804
    Why exactly do you need to track, store, and reset every single plot on the map every turn?

    My Holo Civ makes extensive use of storing and getting plot data, but this sounds overkill, even for me. What are you checking for, and what can possibly change over every single plot?

    Here's the logic I use for Holo:
    Plots can be acquired via several specific means - Founding a City, Capturing a City, City Expansion, or plopping a Citadel.

    This means that, rather than scanning every single plot, I just fire off a function to scan the plots acquired via the aforementioned methods. The owner of these plots shouldn't change unless a City is captured and/or razed, or a Citadel is plopped.

    Having said that, and with regard to your specific inquiry about your table issue:
    This is because that particular table you're trying to insert stuff into isn't actually a table.

    Let's investigate the process Lua has to follow using your current code:

    Code:
    tPlayerPlots = {}
    We now have a table referenced as 'tPlayerPlots' as evidenced by the table constructor: {}

    Code:
    function GetPlayerPlots(iPlayer)
    	-- reset plots:
    	tPlayerPlots[iPlayer] = nil;
    Okay, so when this function runs, it will "reset" the data within the subtable whose index value matches iPlayer. Let's set aside the fact that the very first time this function runs, such a subtable doesn't exist to begin with, because all we've defined so far is this in its entirety: {}

    So, assume we had data there from a previous turn. We now set that subtable to nil -- it's now nothing at all, not even a value; It's dead, Jim. However, there is a secondary consequence here that you've overlooked, and is what is causing your error. We'll return to this point in a minute.

    Code:
    		if (pEveryPlot:GetOwner() == iPlayer) then
    			table.insert(tPlayerPlots[iPlayer], pEveryPlot)
    		end
    Now we get to the meat of the function -- trying to add plots into the table. Unfortunately...

    As you see, you ran into this error. I've bolded the section that we're interested in.

    Why is it saying nil? I thought we defined tPlayerPlots as a table...

    But of course, recall where I stated an issue was overlooked earlier -- You're not trying to insert into just tPlayerPlots, you want to put stuff into tPlayerPlots[iPlayer]! Why isn't it working?

    Let's look at the above code again..
    Code:
    tPlayerPlots[iPlayer] = nil;
    You used this to reset the data in this table, but then you forgot to re-initialize it as a new table!
    Because of this, tPlayerPlots[iPlayer] has the value of nil -- no value at all! This is why Lua complained. You were effectively trying to do table.insert(nil, data) -- how can Lua put data into nothing?

    Here's a quick and dirty example:
    Go here to the Lua demo page -- I love this site, as it lets me quickly test isolated chunks of standard Lua code without having to fire up the game, which is excellent for bits of "logic" code such as this.

    In the box, paste this:
    Code:
    t = {}
    function a()
    t[1] = nil
    --t[1] = {}
    table.insert(t[1], "hi")
    end
    
    a()
    print(t[1][1])
    This is a simplified version of your function, complete with the error. You should see a similar error output when you hit "Run."
    Afterward, uncomment the line I've commented out (this is the line you need to re-initialize the subtable as a table) and hit "Run" again.

    Edit:
    I should note that there is another method of clearing the table while retaining the iPlayer index. In addition to simply doing tPlayerPlots[iPlayer] = {}, you can also iterate through the subtable itself.
    I use this method in my TSL Serializer component, but you can iterate through that subtable and assign a value of 'nil' to every result.

    Code:
    for data in pairs(tPlayerPlots[iPlayer]) do
    	tPlayerPlots[iPlayer][data] = nil
    end
    This would clear all the data inside the tPlayerPlots[iPlayer] table, while leaving that particular reference as a table intact.

    However, in your case, the easiest solution I think is to simply replace the assignment of 'nil' with that of a new table constructor. It will break the reference to the "old" data, and Lua will garbage collect it in due time.
     
  18. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Mmm. Yes, that's working now, thanks.
    However... it creates such incredible lag that the game effectively crashes. :cringe: So... do you know of some better way to iterate over all of pPlayer's plots? Because without a supercomputer mine isn't working so great.
     
  19. DarkScythe

    DarkScythe Hunkalicious Holo

    Joined:
    May 6, 2014
    Messages:
    804
    That was sort of the "overkill" that I was referring to, haha.

    Unfortunately, without knowing why you need to do this, or what you actually need to check, I'm not too sure what the best way about it would be.

    In the worst case, since Cities acquire plots up to 5 tiles away, you can loop through a player's Cities, use each City's plot/coordinates as the starting point, and do a plot sweep around it in a 5-tile radius. Of course, Citadels can extend this range, but only by 1 tile radius, so you can hook into whenever a Citadel is plopped, and scan a 1-tile radius when that happens. However, I believe BuildFinished is a BNW hook, so you might be stuck there for G&K.

    Even so, a 5-tile radius is a LOT of plots, and in a densely-populated map, many of these plots will overlap within other Cities' territories, causing this method to iterate over plots which should have already been accounted for.
     
  20. AW Arcaeca

    AW Arcaeca Deus Vult

    Joined:
    Mar 10, 2013
    Messages:
    2,969
    Gender:
    Male
    Location:
    Operation Padlock ground zero
    Every turn there's a microscopic chance that a random desert mine within your territory will have gold or salt plopped onto its plot, as part of a revamp of the Berbers. (Not sure if it's too close to some other UA...)
    What approach would you recommend for that?
     

Share This Page