Are all existing .lua scripts UI related?

CivilizationAce

Warlord
Joined
Jan 17, 2017
Messages
240
Maybe I'm missing the wood for the trees. I can't find any LUA scripts in the base game that aren't part of the UI.

I was hoping to learn to catch an event in the game (player taking a barbarian encampment) and produce an effect on the game (small chance to make a unit) but these aren't going to help with either of those.

Does the program use LUA for anything apart from the UI so I can get some example of how to actually interact with the game? If so which files should I be looking at please?
 
You won't find. Lua is used for UI, and some support like map scripts and fire tuner panels. The game core is written in C++ and compiled into dll or exe. It exposes some functions to Lua and calls user functions when an event happens. The events are the key here, there quite many, but certainly not everything that happens in the game.
For clearing barb camp you might try to use Events.ImprovementActivated.
 
The scenarios use Lua files in a GameplayScripts context (as opposed to UI context)

A reminder from here:
The gameplay DLL is running on a separate thread and has it's own set of lua exposures. The UI scripts act on cached data that may not be 100% in sync with the state of the gameplay dll (for example if it's playing back combat) Because of this the UI-side lua scripts have some different exposures than the gameplay side.

The available object and events are listed here, there may be more object available since the 2 last patches.
 
The available object and events are listed here, there may be more object available since the 2 last patches.
We discussed this list in a different thread. You've shown how to go through game's objects using i.e. getmetatable. I've been using it ever since (thx again!) but I cannot do this with Event. When I use getmetatable and so on, I get an error that table expected instead of function. Because __index from Events is a function. If I call it - I get another function... so, how did you iterate through Events?
 
Looking at other people's mods may be more helpful than looking at the base game files, since, aside from scenarios and the tutorial, lua in the base game is mostly used for UI. I always try and comment my own code in the hopes it will be useful to other people (as well as being useful to me when I come back and look at it after a few weeks).

The list of lua objects Gedemon mentioned above is very useful, and I find the "search in files" feature of Notepad++ useful for finding examples of where a particular event/function has been used in the base game files.
 
Needs to be added as InGame Action of AddGameplayScripts action-type in modbuddy, and then the new lua file you create needs this code (at least as a starting example)
Code:
local iBarbEncampmentIndex = GameInfo.Improvements["IMPROVEMENT_BARBARIAN_CAMP"].Index
function OnImprovementActivated(iX, iY, iPlayer, iUnitID, iImprovementIndex, iInteger1, iInteger2, iInteger3)
	print("Events.ImprovementActivated fired for function OnImprovementActivated: Dumping Data to Lua log:")
	print("Plot X,Y was X" .. iX .. ",Y" .. iY)
	print("iPlayer was " .. iPlayer)
	print("iUnitID was " .. iUnitID)
	print("iImprovementIndex was " .. iImprovementIndex)
	print("iInteger1 was " .. iInteger1)
	print("iInteger2 was " .. iInteger2)
	print("iInteger3 was " .. iInteger3)
	print("Events.ImprovementActivated fired for function OnImprovementActivated: End of Dumping Data to Lua log")
	if (iImprovementIndex == iBarbEncampmentIndex) and (iPlayer ~= -1) and (iUnitID ~= -1) then
		print("A Valid Player with a Valid unit cleared a Barb Encampment")
		local pPlayer = Players[iPlayer]
		local pPlayerUnits = pPlayer:GetUnits()
		local pUnit = pPlayerUnits:FindID(iUnitID)
		--now we have valid lua objects for the Player, the PlayerUnitsGroup, and the individual unit (pUnit) that stepped on the Barb Camp.
		--we can do crazy lua stuffs now
	end
end
function OnLoadScreenClose()
	Events.ImprovementActivated.Add(OnImprovementActivated)
end
Events.LoadScreenClose.Add(OnLoadScreenClose)
When I ran a listener that printed all the data for the various args depending on what was being done I got these three for stepping on a Goody Hut and having a city "claim" a goody hut:
Code:
--data was OnImprovementActivated(31, 81, 0, 131073, 9, -1, 0, 0) for the starting warrior of player #0 stepping on a GoodyHut
--data was OnImprovementActivated(44, 33, 0, 1572869, 9, -1, 0, 0) for a scout of player #0 stepping on a GoodyHut
--data was OnImprovementActivated(11, 52, -1, -1, 9, 0, 0, 0) for a settler of player #0 founding a city next to a GoodyHut
"9" is the Index # for "IMPROVEMENT_GOODY_HUT". But you should use a method like I did to get the Index# of an item from the game's database because you cannot know if some other mod that is also running has re-assigned the Index#s by deleting, adding, etc.
 
Thanks all, and particularly LeeS. It will take me some time to make sense of this, because I'm still at the stage of working out what can be done with Lua. Once I've got to grip with that I certainly hope to do some "crazy lua stuff" :).

Meanwhile re the following situation am I going to have to use the plot to infer the player and will the plot already be controlled by the player when Events.ImprovementActivated activates?
Code:
[QUOTE="LeeS, post: 14715046, member: 247111"]--data was OnImprovementActivated(11, 52, -1, -1, 9, 0, 0, 0) for a settler of player #0 founding a city next to a GoodyHut[/QUOTE]
 
The third argument (which I called "iPlayer") in the example code will be the integer ID# of the player from the list of players actually participating in the current game. This info is passed from the gamecore to the lua event.

When you set-up a game, each civ (major or minor) is assigned an integer ID#. The human player (also referred to as the local player) in a single-player game is always assigned #0. Barbs are always assigned #63.

When the gamecore passes a value of -1 for the third argument it really means that no player info in that case really applies to a unit that activated the improvement. But note that in the case where the settler founded a city, the "iPlayer" and "iUnitID" values changed to "-1", whereas the data for the argument I referred to as "iInteger1" changed from -1 to 0. So it would look like it is possible that "iInteger1" reflects the player ID# in cases where there is no valid unit info available (remember that by the time the event is triggered in the case of the settler, the settler is already gone from the game because it was used to make a city). It would make sense if "iInteger1" is actually passing the city-owner when an improvement is activated by city plot-expansion. But I haven't run enough testing of the data-grabbing routines I am currently using to be confident of either of these educated guesses.

Otherwise I think you should be safe using the plot to get the city and from that the player ID# of which player 'cleared' the camp, because the improvement is only being activated in such a case by the city claiming the plot.
 
"iInteger1" changed from -1 to 0
It seems like too much of a coincidence to actually be one, but now I think I've worked out how simple it is to get it from the plot so rather than spend time testing iInteger1 the following should work anyway:
Code:
iPlayer ~= -1 and iPlayer or Map.GetPlot(iX,iY):GetOwner()
presuming that none of that has changed from Civ V, and that I haven't completely messed up – That's the first lua I've written. It does seem like an odd language. I can't imagine how many times I'll forget/regret that 0 doesn't equate to false.

(Edited to fix the case of the methods).
 
Last edited:
The unit I'm planning to make upon the event has a replacement that's only available with a certain civic. That leads to a few questions:
  1. If I use InitUnit will replacement automatically occur?
  2. Presuming that it won't so I'll have to check for availability of the replacement is IsHasTech still about (I could find no reference to it in the base .lua files) in Civ VI and does it have a separate civic equivalent, IsHasCivic or are they both treated as Techs?
  3. Does IsHasTech still only work from the Team rather than the Player?
As I write this it occurs to me that I may be able to test some of this stuff in FireTuner :) but feel free to answer anyway please, as I may also not manage to test it in FireTuner.
 
There are no Team objects in Civ6 like as were used in Civ5. So there is no TeamTechs, nor team functions. You need to use Gedemon's Lua Objects thread as your reference on lua objects in civ6. It is not a wiki, and there is a lot of info we have not gleaned as yet, but it is what there is. https://forums.civfanatics.com/threads/lua-objects.601146/

InitUnit in civ5 simply created a specified unit. the game never considered whether the unit was even valid for the civilization, nor for that matter whether you had enough resources, or the required tech, or even if the specified location for creating the unit was actually any good.

There is no InitUnit in civ6, you need to use
Code:
Player:GetUnits():Create(iUnitIndex, iX, iY)
I haven't tried giving a civilization a unit that is not usually valid for it as specified in the <UnitReplaces> table, but I suspect the game will not at all care about this when executing a "Create".

Code:
--====================================================================================================================
--	Get the ID of the Technology
--sTech must be passed in the form of "TECH_HAMBURGERS"
--====================================================================================================================

function GetTechID(sTech)
	local tTechData = GameInfo.Technologies[sTech]
	if tTechData == nil then
		print("GetTechID: invalid sTech, returning -1")
		return -1
	end
	return tTechData.Index
end
--====================================================================================================================
--	Get Whether the Player Has a Tech
--	needs the player object pointer and the tech's index #
--====================================================================================================================

function PlayerHasTech(pPlayer, iTech)
	if iTech >= 0 then
		local pPlayerTechs = pPlayer:GetTechs()
		if pPlayerTechs ~= nil then
			return pPlayerTechs:HasTech(iTech)
		else
			print("PlayerHasTech: invalid player techs table for player, returning false")
		end
	end
	return false
end
Civics will use Player:GetCulture():HasCivic(iCivicIndex)

Rows in the game's database no longer as a general rule have ID's, they have Index #s, which are essentially "implied" but not an actual column that shows in a table definition. Index #s for a given game-table alsways start at '0' in lua, so since "BUILDING_MONUMENT" is the first row to appear in table <Buildings>, it is assigned Index # of '0'. But you should not rely on this "hard-coding" method, instead use
Code:
local iMonumentIndex = GameInfo.Buildings["BUILDING_MONUMENT"].Index
or for a Warrior unit you would do as
Code:
local iWarriorIndex = GameInfo.Units["UNIT_WARRIOR"].Index
 
Back
Top Bottom