LUA questions

Bonci

King
Joined
Oct 22, 2005
Messages
799
Location
Tridentum - Italia
How do you guys know method and event names? Is there any documentation or is it reverse engineering?

I'm trying to find a mod which deletes units to see how the function is called, does anyone know?

Thanks!
 
Nice, thank you!
Sorry if i ask many questions, but I think that if I understand some things I'll be able to work things out on my own.
I have some code like this:
Code:
function OnPlayerTurnActivated(iPlayer,bFirst)
if (iPlayer < PlayerManager.GetWasEverAliveMajorsCount()) then
...
end
end
Events.PlayerTurnActivated.Add(OnPlayerTurnActivated)
because I want the following code to be applied only to major civs, not city states.

But when I pass the turn I get this:
Code:
Runtime Error: C:/path/file.lua:108: attempt to index a nil value
stack traceback:
    C:/path/file.lua:108: in function 'OnPlayerTurnActivated'
    [C]: in function 'func'
    [C]: in function '(anonymous)'

108 is the second line, not the declaration of the function.

How can iPlayer be nil?
 
It's not the id, else you'd get a message about using < with nil.

And PlayerManager should be avaible in all context IIRC.
 
The first argument passed for PlayerTurnActivated will be the ID # of the player from the Players table.
Code:
function PlayerTurnBegin(iPlayer)
	PrintToLog("[PlayerTurnBegin] iPlayer is " .. tostring(iPlayer))
	if iPlayer == 63 then
		PrintToLog("[PlayerTurnBegin] Player # " .. iPlayer .. " (Barbarians) cannot normally have cities")
		return
	end
	local pPlayer = Players[iPlayer]
	local pCities = pPlayer:GetCities();
	if pCities:GetCount() > 0 then
		PrintToLog("[PlayerTurnBegin] Player # " .. iPlayer .. " has some cities")
		for i, pCity in pCities:Members() do
			SetCityUnlockerStatuses(pCity)
		end
	else
		PrintToLog("[PlayerTurnBegin] Player # " .. iPlayer .. " has no cities")
	end
end
Events.PlayerTurnActivated.Add(PlayerTurnBegin)
So try something like
Code:
local pPlayer = Players[iPlayer]
if pPlayer:IsMajor() then
     --do stuff
end
 
Last edited:
the problem with this:
Code:
if (iPlayer < PlayerManager.GetWasEverAliveMajorsCount()) then
as a method to sort out whether the player is a major civ or not is that PlayerManager.GetWasEverAliveMajorsCount() only gives you an integer number for the amount of major players that were ever alive during the course of the game. But the player ID#s passed to the event hooks start at '0' for the human player. If only the human player was ever alive as a major player in the game, this would print "1" in the lua log:
Code:
print(PlayerManager.GetWasEverAliveMajorsCount())
From the testing I remember doing in civ6 for these sorts of things, civ6 works differently than civ5, and the 1st City-State in such a one-major-player game would get assigned player ID# "1". So the 1st city-state will always be seen as meeting this condition:
Code:
if (iPlayer < PlayerManager.GetWasEverAliveMajorsCount()) then
Far better to get the player object via
Code:
local pPlayer = Players[iPlayer]
and then asking whether that currently-being-processed player is a Major Civ via
Code:
if pPlayer:IsMajor() then
 
Last edited:
eeesh. I just realised I typed { instead of [ in one place in my previous post, but it sounds like you caught that already. I fixed my previous post.

It was correct in Post #5 but I mis-typed in Post #6.
 
Now I'm trying to delete all the units of a player

Code:
local aPlayerUnits = pPlayer:GetUnits();
for loop,iPlayerUnit in ipairs(aPlayerUnits) do
      print ("unit: "..tostring(iPlayerUnit))
      local pPlayerUnit = player:GetUnits():FindID(iPlayerUnit);
      pPlayer:GetUnits():Destroy(pPlayerUnit)
end

But the code never goes inside the loop, as if there were no units...but there are in game.
No errors though.

I also tried
Code:
local aPlayerUnits = pPlayer:GetUnits():Members();
but then i get an error saying aPlayerUnits is a function and not a table.
 
  1. Your player objects are not the same.
    Code:
    player:GetUnits():FindID(iPlayerUnit);
    pPlayer:GetUnits():Destroy(pPlayerUnit)
  2. This is an example of looking through a player's units and recording the XY grid position of the first settler found in the player's units:
    Code:
    local pPlayerUnits = pPlayer:GetUnits()
    local iStartingX, iStartingY = -1,-1
    for i, pUnit in pPlayerUnits:Members() do
    	if "LOC_UNIT_SETTLER_NAME" == UnitManager.GetTypeName(pUnit) then
    		print("Settler found by the UnitManager.GetTypeName(pUnit) method")
    		iStartingX, iStartingY = pUnit:GetX(), pUnit:GetY()
    		break
    	end
    end
  3. pPlayerUnits:Members() is structured as it if were an lua table. Never destroy items within the table of a player's units, for example, while in the midst of iterating through the items within the table. Doing so will almost always result in items within the list not being processed because the removal of a previous item causes a de-synch in the item #s (the "i" values in this case).
  4. I would try as follows:
    Code:
    local pPlayerUnits = pPlayer:GetUnits()
    local tUnitsToDestroy = {}
    for i,pUnitToDestroy in pPlayerUnits:Members() do
    	table.insert(tUnitsToDestroy, pUnitToDestroy)
    end
    for iKey,pUnitToDestroy in pairs(tUnitsToDestroy) do
    	pPlayerUnits:Destroy(pUnitToDestroy)
    end
    tUnitsToDestroy = {}
    This should work assuming Destroy(Unit) works as stated and does not require additional info (the methodology works in civ5 lua except that civ5 uses Kill()) because when you are running through the list of items in table tUnitsToDestroy you are not actually removing anything listed in table tUnitsToDestroy, strange as it may seem.
  5. Note that if you are attempting the code within a UI context rather than as part of a GameplayScripts,
    Code:
    Player:GetUnits():Destroy(Unit)
    appears only to be available within a GameplayScript context.
 
Ok, understood :)
On the line
Code:
pPlayerUnits:Destroy(pUnitToDestroy)
I get "function expected instead of nil" do you think there is some other parameter that needs to be passed?

Those errors are not very clear :(
 
it's an indication that
Code:
pPlayer:GetUnits():  Destroy(pUnitToDestroy)
isn't actually hooked up to anything as yet within GameplayScripts. I've run into this for a few other items in Gedemon's list of lua objects.
 
Since the time this was posted, something must have been updated in the base game files, because the following simple function:

Code:
function OnWarriorAddedToMap( playerID : number, unitID : number )
    local pPlayer = Players[ playerID ]
    if pPlayer ~= nil then
        local pUnit = pPlayer:GetUnits():FindID(unitID)
        if pUnit:GetType() == GameInfo.Units["UNIT_WARRIOR"].Index then
            pPlayer:GetUnits():Destroy(pUnit)
        end
    end
end
Events.UnitAddedToMap.Add(OnWarriorAddedToMap);

works without any issues. Unless I am misunderstanding the actual mechanic you are trying to achieve here. :) If so, my apologies. However, if the functions has been turned on since, this is welcome news, as it indicates that other previously-dormant functions may have also been activated.
 
Back
Top Bottom