A couple more "quick" inquiries

I drew an overly complicated diagram to figure this out...
Would it be:
Code:
if not (GameInfo.Builds{Type=GameInfo.Unit_Builds{UnitType=GameInfo.Units{ID=pUnit:GetUnitType()}.Type}.ID == GameInfoTypes.BUILD_AW_SECRETSECRECY) then return end
This way I'm at least comparing two variables of the same type, although I may have missed a logical step here somewhere...
And also maybe function calls. Do I need more parens?
I think you're going backwards here. It's becoming convoluted enough that I can't see my way clear to parsing what you are looking at any more.

It would help to see the context within which this line is 'living' in order to understand what, where, when, who you need to have or look at in that segment of your lua. Also a non-code description of what you are trying to accomplish in that portion of your code and why.

hint: I find it is sometimes easier to understand what I am actually telling the game to do by breaking things into smaller elements that are easier for me to understand, and only after a complex construction is working 'roll' it all into one line.
 
Do unclaimed tiles technically belong to barbarians or something?

Because I'm having one heck of a time trying to debug some lua right now, and the results of debugging-by-print-statements are very perplexing:
Code:
[59334.777] UI_Functions: Not failed yet!
[59334.777] UI_Functions: We've got our player!
[59334.777] UI_Functions: And they're [REDACTED] too?!? That's swell!
[59334.777] UI_Functions: Units!
[59334.777] UI_Functions: The plot is thus
[COLOR="Red"][59334.777] UI_Functions: This plot belongs to someone else![/COLOR]
That last line makes no sense, at least to me, to be there:
Code:
if (not (pPlot:GetOwner() == iPlayer)) and (not (pPlot:GetOwner() == nil)) then
			print('This plot belongs to someone else!')
			return
		end -- if it belongs to someone but not you, don't keep going
(Thank you forums, for screwing up the indentation :cringe:)
Plot.GetOwner returns an player ID, right? pPlot during the playtest was an unclaimed plot. But according to this... it's apparently claimed by someone, and not nil...? Or did I screw something else up?

EDIT: plz ignore, nil should be -1
 
Okay, two one more problem:
Second, some errors from TSL and TSL Serializer that I don't know how to fix, or if I should indeed worry about them:
Spoiler :
Code:
[62178.847] TableSaverLoader016: Loading TableSaverLoader.lua...
[62178.847] TSLSerializerCoreV3: Loading TSL Serializer Core...
[62178.847] TSLSerializerCoreV3: TSL Serializer Core Version: 3
[62178.847] Runtime Error: C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Imported\TSLSerializerCoreV3.lua:71: attempt to index global 'TSLMaster' (a nil value)
[62178.847] Runtime Error: Error loading C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Imported\TSLSerializerCoreV3.lua.
[62178.847] TSLSerializerV3_AW_Redacted: Loading TSL Serializer Client...
[62178.862] TSLSerializerV3_AW_Redacted: TSL Serializer Client Version: 3
[62178.862] Runtime Error: C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Imported\TSLSerializerV3_AW_Redacted.lua:147: Error! tableRoot is not defined properly, or is not a table! Received: [nil] Aborting...
[62178.862] Runtime Error: Error loading C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Imported\TSLSerializerV3_AW_Urartu.lua.
[62178.862] TSLSerializerHookup: Loading TableSaverLoader.lua...
[62178.862] TSLSerializerHookup: Loading TSL Serializer Client...
[62178.862] TSLSerializerHookup: TSL Serializer Client Version: 3
[62178.862] TSLSerializerHookup: Loading TSL Serializer Core...
[62178.878] TSLSerializerHookup: TSL Serializer Core Version: 3
[62178.878] TSLSerializerHookup: LuaEvents for TSL Master not yet active. Enabling...
[62178.878] TSLSerializerHookup: TSL Serializer Master activation completed.
[62178.878] TSLSerializerHookup: Core TSL Serializer components for version 3 loaded successfully.
[62178.878] TSLSerializerHookup: TSL Master is active, retrieving ID...
[62178.878] TSLSerializerHookup: Index is currently 1
[62178.878] TSLSerializerHookup: TSL Master assigning index of 1 to ID request.
[62178.878] TSLSerializerHookup: Received ID of 1 from TSL Master.
[62178.894] TSLSerializerHookup: Registering table 'AW_Redacted_Table' for use with TSLSerializer...
[62178.894] TSLSerializerHookup: TSL Serializer version 3 loaded successfully.
[62178.894] TSLSerializerHookup: New Game
[62178.894] Runtime Error: C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Imported\TableSaverLoader016.lua:139: attempt to concatenate local 'DBTablePrefix' (a nil value)
[62178.894] Runtime Error: Error loading C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Lua/TSLSerializerHookup.lua.
...
[62188.784] TSLSerializerHookup: Game control acquired by player. TSL Master standing by...
[62188.784] TSLSerializerHookup: Player entering game...
..
[62274.912] TSLSerializerHookup: Creating SavedGameDB tables for new game: AW_Redacted_Table_Data and AW_Redacted_Table_Info
[62275.115] TSLSerializerHookup: TableSave time: 0.13999999999999, inserts: 0, deletes: 0, updates: 0, unchanged: 0, checksum: 0
Sorry. This mod is refusing to work correctly. :/
 
Oh, and this, which I can't figure out for the life of me:
Code:
[39099.856] Runtime Error: C:\Users\AW\Documents\My Games\Sid Meier's Civilization 5\MODS\AW's [REDACTED] Mod (v 1)\Imported\PlotIterators.lua:151: attempt to call method 'GetX' (a nil value)
It refers to this line of PlotIterators:
Spoiler :
Code:
function PlotAreaSweepIterator(pPlot, r, sector, anticlock, inwards, centre)
  [B][COLOR="Red"]print(string.format("PlotAreaSweepIterator((%i, %i), r=%i, s=%i, d=%s, w=%s, c=%s)", pPlot:GetX(), pPlot:GetY(), r, (sector or SECTOR_NORTH), (anticlock and "rev" or "fwd"), (inwards and "in" or "out"), (centre and "yes" or "no")))[/COLOR][/B]
  -- This coroutine walks each radial in sequence
  local next = coroutine.create(function ()
    if (centre and not inwards) then
      coroutine.yield(pPlot)
    end

    local iterators = {}
    for i=1, r, 1 do
      iterators[i] = PlotRingIterator(pPlot, i, sector, anticlock)
    end

    for s=1, 6, 1 do
      -- In ring (n+1) there are (n+1)*6 or 6n + 6 plots,
      -- so we need to call the (n+1)th iterator six more times than the nth, or once more per outer loop
      -- eg for 3 rings we need a plot from ring 1, 2, 3, 2, 3, 3 repeated 6 times
      if (inwards) then
        for i=r, 1, -1 do
          for j=r, i, -1 do
            coroutine.yield(iterators[j]())
          end
        end
      else
        for i=1, r, 1 do
          for j=i, r, 1 do
            coroutine.yield(iterators[j]())
          end
        end
      end
    end

    if (centre and inwards) then
      coroutine.yield(pPlot)
    end

    return nil
  end)

  -- This function returns the next plot in the sequence
  return function ()
    local success, pAreaPlot = coroutine.resume(next)
    return success and pAreaPlot or nil
  end
end
PlotAreaSweepIterator is called in my code, which gets this far:
Spoiler :
Code:
tPlots = {}

GameEvents.PlayerDoTurn.Add(
function(iPlayer)
	if (tPlots[iPlayer] == nil) then
		tPlots[iPlayer] = {}
	end
	local pPlayer = Players[iPlayer]
	for pUnit in pPlayer:Units() do
		local pPlot = pUnit:GetPlot()
		if (not (pPlot:GetOwner() == iPlayer)) and (not (pPlot:GetOwner() == (-1))) then
			print('This plot belongs to someone else!... specifically, player #'..pPlot:GetOwner()..'.')
			return
		end
		if not (pPlot:GetImprovementType() == GameInfoTypes.IMPROVEMENT_AW_SECRETIMPROVEMENT) then return end
		if not (pUnit:GetUnitType() == GameInfoTypes.UNIT_WORKER) then return end
		pPlot:SetOwner(iPlayer)
		[COLOR="blue"]table.insert(tPlots[iPlayer], pPlot)[/COLOR]
	end
end)

GameEvents.PlayerDoTurn.Add(
function(iPlayer)
	-- don't keep going if the player doesn't have any Secret Improvements
	if (#tPlots[iPlayer] < 1) or (tPlots[iPlayer] == nil) then return end
	local pPlayer = Players[iPlayer]
	-- turnly table constructor
	-- (tYieldPlots doesn't need to be hooked into TSL, since it's going to be created, truncated and destroyed every turn anyway)
	if (tYieldPlots == nil) then
		tYieldPlots = {}
	end
	tYieldPlots[iPlayer] = {}
	[COLOR="Blue"]for iPlayer, pPlot in pairs(tPlots) do[/COLOR]
		if (pPlot == nil) then return end -- just in case:
		iFood = 0
		iGold = 0
		iProduction = 0
		[B]for pLoopPlot in PlotAreaSweepIterator(pPlot, 1, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_EXCLUDE) do[/B]
...
Blue lines show where plots are inserted into and extracted from tPlots.

When it decides that pPlot is nil - since the error is basically complaining about us trying to do nil:GetX(), to my understanding - even though we checked to make sure it wasn't... And we know PlotIterators is hooked up correctly because lua traces the error back to it... Am I not inserting and extracting data from tPlots correctly?

I've spent... I dunno, 5 or so hours without success trying to figure out how to fix this... I'm just clean out of ideas... :undecide:
 
1st. It isn't a problem with the plotiterators. It has to be a problem with your code.

2nd. Looking at your code you have these:
Code:
if not (pPlot:GetImprovementType() == GameInfoTypes.IMPROVEMENT_AW_SECRETIMPROVEMENT) then return end
if not (pUnit:GetUnitType() == GameInfoTypes.UNIT_WORKER) then return end
In and of themselves, and properly used, there is nothing wrong with this sort of construction. I use it myself quite often. Unfortunately you are mis-applying them within a loop through all of a player's units. This is bound to be prone to errors and unintended consequences. You are also indescriminately using return all over the place in your PlayerDoTurn function.

So what is happening?

Spoiler your code 1 :
All color coding has been added by me
Code:
tPlots = {}

GameEvents.PlayerDoTurn.Add(
function(iPlayer)
	if (tPlots[iPlayer] == nil) then
		tPlots[iPlayer] = {}
	end
	local pPlayer = Players[iPlayer]
	[color="blue"]for pUnit in pPlayer:Units() do
		local pPlot = pUnit:GetPlot()[/color]
		[color="green"]if (not (pPlot:GetOwner() == iPlayer)) and (not (pPlot:GetOwner() == (-1))) then
			print('This plot belongs to someone else!... specifically, player #'..pPlot:GetOwner()..'.')
			return
		end[/color]
		[color="red"]if not (pPlot:GetImprovementType() == GameInfoTypes.IMPROVEMENT_AW_SECRETIMPROVEMENT) then return end
		if not (pUnit:GetUnitType() == GameInfoTypes.UNIT_WORKER) then return end[/color]
		pPlot:SetOwner(iPlayer)
		table.insert(tPlots[iPlayer], pPlot)
	[color="blue"]end[/color]
end)
  1. The blue part starts looking through a player's units, and for each unit gets the plot the unit is occupying. All fine and good.
  2. The green part looks to see who owns the plot, and only lets the function proceed if the plot does not belong to the wrong player. The problem here is that when the plot belongs to the 'wrong player', you are completely exiting the entire function and not processing any information for any of the player's other units. If this occurs for the 1st unit in the player's list of units, then tPlots[iPlayer] will remain a table with no contents.
  3. The red part will:
    • completely exit the entire function when the plot the unit is occupying does not contain the improvement specified as IMPROVEMENT_AW_SECRETIMPROVEMENT. If this occurs for the 1st of the player's units, then, again, not only will no further processing be made for the player's other units, but tPlots[iPlayer] will remain a table with no contents.
    • completely exit the entire function when the unit currently being processed is not a worker. If this occurs for the 1st of the player's units, then, again, not only will no further processing be made for the player's other units, but tPlots[iPlayer] will remain a table with no contents. This in my view is the largest inherent flaw in the way the code is structured, because a player's units are processed sequentially (just as are cities) and the oldest will be processed 1st. The most likely outcome is that the 1st unit processed will be a Recon Unit or a Warrior, and in such case the entire function will end on that 1st unit, even if the function manages to get past the other limiting lines of code. The end is result is that tPlots[iPlayer] will remain an empty table.

Spoiler your code 2 :

I believe you problems here are a misunderstanding of the form your table is taking
  1. Table tPlots will be in a form of "keys" and "values" where the "keys" will be integer values from "0" to the Max Player (theoretically). The "values" for each of these "keys" will be a sub-table listing all the qaulifying plots for an individual player, in the form of integer "keys" with corresponding plot-reference "value" data.
  2. This:
    Code:
    for iPlayer, pPlot in pairs(tPlots) do
    is the same as this:
    Code:
    for k, v in pairs(tPlots) do
    or this:
    Code:
    for iPlayer, PlotTable in pairs(tPlots) do
    but in none of these cases are you yet getting at a plot object reference, you are getting at a table, and then you are trying to insert a table reference into this:
    Code:
    for pLoopPlot in PlotAreaSweepIterator(pPlot, 1, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_EXCLUDE) do
  3. If I wanted to look through the table of qualifying plots for the current iPlayer I would do something more like this:
    Code:
    if tPlots[iPlayer] ~= nil and type(tPlots[iPlayer]) == "table" then
    	for k,[color="blue"]v[/color] in pairs(tPlots[iPlayer]) do
    		local iFood, iGold, iProduction = 0, 0, 0
    		for pLoopPlot in PlotAreaSweepIterator([color="blue"]v[/color], 1, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_EXCLUDE) do
    			--stuff with getting iFood, iGold, iProduction would go here, but would be specific to each of the plots contained within table tPlots[iPlayer]
    			--and therefore must be completely processed and dealt with before moving on to the next plot referenced within the table
    		end
    	end
    end

Your Original 2nd chunk of code:
Code:
GameEvents.PlayerDoTurn.Add(
function(iPlayer)
	-- don't keep going if the player doesn't have any Secret Improvements
	if (#tPlots[iPlayer] < 1) or (tPlots[iPlayer] == nil) then return end
	local pPlayer = Players[iPlayer]
	-- turnly table constructor
	-- (tYieldPlots doesn't need to be hooked into TSL, since it's going to be created, truncated and destroyed every turn anyway)
	if (tYieldPlots == nil) then
		tYieldPlots = {}
	end
	tYieldPlots[iPlayer] = {}
	for iPlayer, pPlot in pairs(tPlots) do
		if (pPlot == nil) then return end -- just in case:
		iFood = 0
		iGold = 0
		iProduction = 0
		for pLoopPlot in PlotAreaSweepIterator(pPlot, 1, SECTOR_NORTH, DIRECTION_CLOCKWISE, DIRECTION_OUTWARDS, CENTRE_EXCLUDE) do
...
 
Yeah, I discovered it should've been "for k, pPlot in pairs(tPlots[iPlayer]) do" after taking a break, mowing the lawn and taking a shower, and fiddling around with this simplified code on the lua demo page:
Spoiler :
Code:
t = {}
x = {}
x[1] = "hi"
x[2] = "yes"
x[3] = "chicken"
x[4] = "lua"

function a(i)
	if (t[i] == nil) then
		t[i] = {}
	end
	for k,v in pairs(x) do
		table.insert(t[i],v)
	end
end

function b(i)
	for i,s in pairs(t[i]) do
		print(s)
	end
end

a(2)
b(2)
It's working splendidly now that I realized that the "pairs" iterator was assigning the player ID to the value iPlayer instead of actually using it as the key, thus throwing everything off. :D

But about the whole "return" problem... well, with the limited testing I've been working with, it seems to be working well; the plot is claimed at the beginning of the player's turn and then proceeds to do the other stuff. But if "return" would theoretically make the entire function end, what should I use instead? "break"?

And one last question; this should be easier:
How do I make something happen at the beginning of every tenth turn? It's that tenth turn part that's throwing me off; all that I want to do is call a function I've already defined.

EDIT: And I'm noticing some problems with my code:
1) Even when I change the "return"s to "break"s, it doesn't solve the problem because that still ends the "for" loop unit iterator. Suggestions?
2) Keep a worker on the tile for two turns... and the plot will be added twice to the table. :crazyeye: This means that the second part of the code will loop over that plot's adjacent plots twice. The problem stacks; every turn a worker spends on that plot is one more time the plot is added to the table. A simple "if not (tPlots[iPlayer] == pPlot) then" check isn't working. Suggestions...?

Naturally, the game doesn't recognize either of these as errors.
 
every 10 turns:

either of:
Code:
if Game.GetGameTurn() % 10  == 0 then

or

if Game.GetElapsedGameTurns()  % 10 == 0 then
Reason it doesn't matter which is that '%' is the 'modulus' command in lua, which gives the 'remainder' for a/b. By comparing the resultant remainder to '0', it is looking for a 'once every 10 turns' condition, and does not care what the actual turn number or elasped turn number is, only if they are evenly divisible by 10.

The other I would have to think some more about and perhaps respond sometime tomorrow. Had really bad storms go through wherein I live last night, only just got internet restored a few minutes ago.
 
In order for me to have any chance to help you I'd need to see the mod itself. If you are still on the secrecy bug-a-boo just PM me with a link and a description of what it is you want to have happen when something else is true or has happened. By now I am completely lost in terms of what you are wanting your mod to do because you have had so many different versions of what you are asking for help with on this thread.
 
Modulus - the operator I always forget exists because I never use it. :lol: That will do nicely, thank you.
As for my edits in my last post, I'll try to rephrase them - I've already provided the relevant code:

#1) You were concerned about these lines:
Code:
if not (pPlot:GetImprovementType() == GameInfoTypes.IMPROVEMENT_AW_SECRETIMPROVEMENT) then return end
if not (pUnit:GetUnitType() == GameInfoTypes.UNIT_WORKER) then return end
which would make the function instantly be terminated when the game runs into a unit that doesn't fit the bill instead of moving onto the next one, which you were completely right about. Plots aren't getting added to the table because the game proceeds to iterate over... some other unit, I don't know for sure which one, ignoring perfectly valid workers standing on perfectly valid improvements that it would've iterated over later.
So I tried replacing "return" with "break". But that didn't help because it just terminates the iterator instead of the entire function... which is functionally just as useless. There's nothing after the iterator, so the function ends without contributing anything to society.
Now my question is, what do I replace "break" with? Is there a different keyword I should be using, or should I just format the checks differently or what? Remove "not" and "return" from both lines, probably?

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

#2 I was asking, how can I check to see that a value does not already exist in a table before using table.insert to add said value?
Basically, plots are getting added to the table multiple times, which causes problems. I've tried adding "if not (tPlots[iPlayer] == pPlot) then" before "table.insert(tPlots[iPlayer], pPlot)", like so:
Code:
if not (tPlots[iPlayer] == pPlot) then
			table.insert(tPlots[iPlayer], pPlot)
		end
Again, thank you for the indentation help, forums...
...but this results in no success, probably because pPlot ~= {pPlot}. I need to figure out how to rephrase that conditional statement so that it does something useful; else, every turn that the worker spends on pPlot is one more time pPlot is added to tPlots[iPlayer], meaning that the problem becomes progressively worse.

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

I trust that was clearer, albeit longer.
 
Item ItemType
tPlots[iPlayer] lua table
pPlot plot reference

To determine if an individual pPlot reference is already stored as a "Value" within lua table tPlots[iPlayer] you would need to look through the contents of lua table tPlots[iPlayer] to determine if pPlot is already listed there as a value within one of the k,v pairs.

In other words, you would need to loop through the contents of lua table tPlots[iPlayer] looking for whether there is a match to pPlot or not.

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

But other than clarifying issues with specific lines of code, I do not understand what it is you want the code to do in a larger sense, so cannot tell if you are headed down a wrong path that is simply going to be a time-waster. I guess you explained it all somewhere in the previous pages of the thread, but by now you've asked about and everyone has discussed so many different things I can't figure out what it is you want to accomplish. And without the mod itself it's darn near impossible to tell if you are running into difficulties because you've omitted some small but fundamental requirement with getting everything hooked up, or if perhaps I and Darkscythe have given you advices that have sent you off on a wrong tangent. What you've showed so far to be honest still makes no sense to me so far as what you are trying to accomplish because there is insufficient context. I need the context of the larger mod (with all its associated lua files and their implimentation methods) as well as a description of what it is you want to have happen with regard to these plots (because I can't anymore make heads or tails of the previous pages of this thread).
 
Alright, let's necro this for the umpteenth time because I can't for the life of me figure out how to write what should be a simple function:

Basically I'm trying to make the opposite of the "nearest city" function that a lot of people use, the standard one from the 1066 scenario that takes pPlayer and pPlot as parameters - one that will return the farthest city. And while that's all fine and dandy, in my code I also need to be able to find the second farthest city. So how do you do that?
So I tried adding another parameter to the function, which I called "index". Basically where index = n, the function would return the nth farthest city from the specified plot. So my best idea for how to go about doing that is to make a temporary table, populate it so that each entry's key is the city ID and its value is the distance, and then sort the entries in descending order of distance. Finally we can simply return pPlayer:GetCityByID(table[index]).

The problem lies here: sorting the entries in descending order of distance.
Do I use table.sort or what? The lua documentation for table.sort is completely lost on me; generally I find the official lua documentation to answer nothing useful as to how a function or keyword is used, but I gather that the first parameter of table.sort is the table, and the second is some kind of sorting function.
Or am I just doing this completely wrong altogether?

Code:
function GetFarthestCity(pPlayer, pPlot, index)
	if (index == nil) then
		index = 1;
	end
	local iMinDist = 1;
	local pTargetCity = nil;
	local tDistances = {}
	for pCity in pPlayer:Cities() do
		local iDist = Map.PlotDistance(pCity:GetX(), pCity:GetY(), pPlot:GetX(), pPlot:GetY())
		tDistances[pCity:GetID()] = iDist		
	end
	-- I'm not sure what to do here...
	[B][COLOR="Red"]table.sort(tDistances)[/COLOR][/B]
	local pTargetCity = pPlayer:GetCityByID(tDistances[index])
	return pTargetCity
end
 
This run at the lua demo page:
Code:
TableTest = {}
TableTest[1567] = 15
TableTest[6565] = 16
TableTest[15] = 17
TableTest[1] = 5
table.sort(TableTest)
print("TableTest contents after sort comand")
for k,v in pairs(TableTest) do print(k,v) end
TableTest2 = {}
table.insert(TableTest2, 15)
table.insert(TableTest2, 16)
table.insert(TableTest2, 17)
table.insert(TableTest2, 5)
print("TableTest2 contents before sort")
for k,v in pairs(TableTest2) do print(k,v) end
table.sort(TableTest2)
print("TableTest2 contents after sort")
for k,v in pairs(TableTest2) do print(k,v) end
Gives this result:
Code:
TableTest contents after sort comand
1	5
6565	16
15	17
1567	15
TableTest2 contents before sort
1	15
2	16
3	17
4	5
TableTest2 contents after sort
1	5
2	15
3	16
4	17
The documentation on the lua reference and manual that I use http://www.lua.org/manual/5.2/manual.html#6.5 I am also finding as clear as muddy waters on the use of the [,comp] part of the function.

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

Besides all that, tDistances[index] would give you not the City ID#, but rather the distance of the city from plot pPlot because you are saving the distance as the "v" in your table tDistances, and the ID# of the city you are using as the "k" element in the table:
Code:
[COLOR="green"]tDistances[/COLOR][[COLOR="Red"]pCity:GetID()[/COLOR]] = [COLOR="Magenta"]iDist[/COLOR]
 
As LeeS pointed out, indexing them by ID and then sorting them will destroy your record of IDs. At worst, you could do nested tables:

[1] = {ID, dist},
[2] = {ID, dist}...

However, I'm kinda wondering why you need to sort at all?

Code:
function GetFarthestCity(pPlayer, pPlot, index)
	local farID, secondID
	local farDist, secondDist = 1
	
	for pCity in pPlayer:Cities() do
		local iDist = Map.PlotDistance(pCity:GetX(), pCity:GetY(), pPlot:GetX(), pPlot:GetY())
		if iDist > farDist then
			secondID = farID
			secondDist = farDist
			farID = pCity:GetID()
			farDist = iDist
		elseif iDist > secondDist then
			secondID = pCity:GetID()
			secondDist = iDist
		end
	end
	
	if farDist == secondDist and farID ~= secondID then
		--we gotz us a tie
	end
	
	--return stuff here
end

edit: This does not take into account the possibility of a tie. You should be able to figure something out for that (if you even want/need to mess with it).
edit2: Also, there's the possibility that it finds the furthest city first, resulting in the second furthest never registering. --fixed
 
So... there's no good way to find the nth farthest city away? I was hoping to be able to use this as a utility function for potentially something in the future.
I think doing this in table format seems to be the problem; if we could do it in list format, like {{ID, Dist},{ID, Dist},{ID, Dist}} and sort it in descending order of distance, we could just pull the city ID of the farthest city with list[1][1], second farthest with list[2][1], etc. Ofc, I have even less of an idea how to do that... can you even sort lists?

Anyway, now I've run into an SQL error.
(BTW, both this problem and the last are for E&D compatibility.)
I need to be able to create new buildings if and only if E&D is active, because... I don't really want E&D compatibility buildings - which aren't supposed to be invisible BTW - cluttering up the pedia and so forth. I was told that SQLite doesn't support "INSERT IF" statements, like normal SQL does; neither does CASE have any spot within an INSERT statement. So... I guess that leaves us with only the option of inserting junk and updating it if E&D is active, or deleting it if E&D isn't. Unless there's a better solution?
 
To do nth then yes, sorting a table would be the correct approach and nested tables would be the way to go.

Code:
function GetFarthestCity(pPlayer, pPlot, index)
	local tDistances = {}
	
	for pCity in pPlayer:Cities() do
		local cityID = pCity:GetID()
		local iDist = Map.PlotDistance(pCity:GetX(), pCity:GetY(), pPlot:GetX(), pPlot:GetY())
		
		table.insert(tDistances, {cityID, iDist})
	end
	
	--this SHOULD sort the table by distance in ascending order.
	table.sort(tDistances, function(a, b) return a[2] > b[2] end)
	
	--print the sorted table:
	for i = 1, #tDistances, 1 do
		print(string.format("index %d: {cityID %d, distance %f}", i, tDistances[i][1], tDistances[i][2]))
	end
	--return stuff here
end

This is untested code but I believe it should produce desirable results.

edit: Note that this approach is going to be significantly slower than the approach which forgoes tables. If performance impact is a factor, weigh whether or not you actually need "nth" functionality.
 
Speed is probably not an issue. Looks good, thanks. :D Although:
Code:
--this SHOULD sort the table by distance in [B]ascending[/B] order.
Does that mean that the city with the largest distance value is at the top or bottom?

And then "-- return stuff here" can be replaced with "return pPlayer:GetCityByID(tDistances[index][1])"
 
Ascending order should mean that the furthest city would be in the first index, and the 2nd in the second and so-on.

I put the print in there so you could verify that (the sign in the sort function can be inverted if needed though I'm pretty sure greater than is the one you want); I'd comment out the print once you're sure it's working properly. And yes, put whatever you want in place of my "--return" comment. :lol:

edit: Also, ties are possible and exactly how that could affect the output I can't say. I'd think it would be deterministic but there's the possibility that if two cities are tied for furthest, it could flip flop them on concurrent calls. :dunno:
 
Well, ties would be a problem depending only on how the table gets populates. It would be a problem if it got populated, say, like this:
Code:
tDistances[1] = {{6, 12}}
tDistances[2] = {{2, 10},{7,10}}
tDistances[3] = {{3, 7}}
tDistances[4] = {{4, 5},{5,5}}
...
(Although in this case we would have to actually return pPlayer:GetCityByID(tDistances[index][1][1].)
And we're assuming pPlot = pPlayer:GetCapitalCity():GetPlot().
Because then GetFarthestCity(pPlayer, pPlot, 1) returns city #6, GetFarthestCity(pPlayer, pPlot, 2) returns city #2 - so far so good - but GetFarthestCity(pPlayer, pPlot, 3) returns city #3 - city #7 gets skipped over entirely!
Now imagine that the player only has 3 cities, which is the bare minimum needed to enact one of my decisions (capital + at least two extra). The table might* be populated like this:
Code:
tDistances[1] = {{2, 5},{3,5}}
tDistances[2] = {{1, 0}}
Consequently... the game calculates the capital as being the second-farthest city from itself! :crazyeye:

But by my reckoning, none of that is a problem if the table instead gets populated something more like this:
Code:
tDistances[1] = {6, 12}
tDistances[2] = {2, 10}
tDistances[3] = {7,10}
tDistances[4] = {3, 7}
tDistances[5] = {4, 5}
tDistances[6] = {5,5}
No city gets skipped over.

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

Also, no ideas for the SQL query? :(

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

And so here's Thursday's mental workout of the day :lol::
% chance with floats
It's easy enough to say "x has a y% chance of happening" in lua, using JFD's GetRandom(lower, upper) function:
Code:
if (GetRandom(1,100) <= y) then
	x
end
But GetRandom, AFAIK, always returns an integer, which isn't a problem if y is also an integer.
But what if it isn't? How about something with, say, a 0.831% chance of happening? As far as GetRandom is concerned, this is 1%.
Maybe affix a random float to GetRandom(1,99)? Something like GetRandom(1,99)+math.random()? (math.random(0,99) returns an integer, so that's also no good) But then how do we round whatever we get off to three decimal places?

*Gotta love them edge cases :p
 
The list will be populated linearly. It won't go restructuring itself. :D

However, say you have this:
Code:
[1] = {5, 20}
[2] = {7,20}
...

It may be possible that upon being called again it instead returns this:
Code:
[1] = {7,20}
[2] = {5,20}
...
I don't know if it would be deterministic or not.

I know very little about SQL so... next order of business.

I'm not familiar with JFD's GetRandom() so I can't say for certain regarding it, however Lua's built-in math.random() returns a decimal floating point number between 0 and 1 when you call it without parameters so:

Code:
if (math.random() <= 0.831) then

Note that this approach is not tied to the game's RNG system, which has a number of implications.

If you really needed to use the game's random system to do this, I'd set up something like this:

Code:
function RandomFloat()
	return (Game.Rand(65535, "") / 65535) --iirc 65535 was the max limit Civ's .Rand could handle before it broke.
end

This provides 16 bits of precision so rounding errors won't occur until at least the 5th digit past the decimal...
 
But if the lower and upper parameters are 0 and 1 respectively, then 0.831 turns into 83.1% instead of, well, 0.831%. So maybe:
Code:
if ((math.random(0,99)+math.random()) <= 0.831) then
That way it will generate a random integer and then attach a random float to it.
The thing that worries me about this is that on the lua demo page, no matter how many times you run math.random(0,99), despite that it should always return a random value, it returns 84. Similar situation with math.random(). Try it! I put in "print((math.random(0,99)+math.random()))" and it always outputs "84.394382926635". Always. I don't know if this means that there's something wrong with the lua demo page, or if we use this method that the "dice roll" will always result in the same number.
 
Top Bottom