Changing Beakers

tesb

Emperor
Joined
Jan 16, 2010
Messages
1,593
Hello,

i want to change the cost of technologies based on the affinity the player has and the affinity the tech provides, e.g.:

for every x point in y affinity, all technologies of the other two affinity cost 10% more.
this would make it very difficult to research everything.

my problem is that i need the lua functions for:
1) how do i get the affinity level
2) how do i get if a tech provides an affinity (i could simply hardcode it by looking what techs provides what affinities in the xml)
3) how do i get beaker cost of said technolgy
4) how to change beaker cost

thanks.
 
I believe whoward compiled a list of all methods exposed to Lua somewhere; I can't seem to find it though.

Outside of that, your best bet for most of these is going to be to use a program capable of searching all files within a directory. I'm sure there's a method along the lines of player:GetAffinityLevel() but A) you'll need to define "player" as a/the valid player object (search "player" in the existing Lua to see how Firaxis does it) and B) I'm not sure what nor how a "GetAffinityLevel" method would return or if it may be split into 3 seperate methods for each affinity, etc.

You'd probably be better off hardcoding the techs unless you're aiming for compatibility with tech tree overhauls. The current beaker cost will most likely be irrelavent. Changing the beaker cost is probably going to require some form of tomfoolery (hidden policies, that alter the beaker cost, you grant to the player for example).
 
hm the problem with player:GetAffinityLevel(), is that it includes quest rewards, basically my script should do (i am coming from civ4 python):
on tech researched:
-> check if tech grants affinity
--> check affinity type
---> increase all tech costs granting other affinities by x%

i don't even know where to start to call the function automatically when a tech is researched. in civ4 there was an xml for such triggers (e.g. call a certain function every turn)


edit:
compiling some useful functions:
x = player:GetCurrentResearch()
player:GetResearchCost(x)

i did not find SetResearchCost :(

y = pTeamTechs:GetLastTechAcquired();
 
1) Look in TopPanel.lua for the code that displays the three affinity bars top left

2)
Code:
function GetAffinityPoints(sTechType, sAffinityType)
  local iAffinityValue = 0
  for row in GameInfo.Technology_Affinities{TechType = sTechType, AffinityType = sAffinityType} do
    iAffinityValue = row.AffinityValue
  end

  return iAffinityValue
end

GetAffinityPoints("TECH_ALIEN_BIOLOGY", "AFFINITY_TYPE_HARMONY")

3) Look in TechPanel.lua for the code that displays the cost (and progress towards) the tech currently being researched

4) With difficulty. Even if there's a building/policy/tech that gives a bonus towards beakers (and off the top of my head I can't think of one) they rarely work with negative modifiers (ie a -10% bonus to make something cost 110% is almost always ignored and it just becomes +0%)
 
thank you. i was looking for function that changes the beaker cost instead of applying a research penalty, i.e. something like player:GetResearchCost:
player:SetResearchCost
:D

but i guess it does not exist?

edit:
i could use
ChangeResearchProgress

but this would be a bit counterintuitive because you would not be displayed as increased costs in the tech web

edit 2:

basically:

function on every turn
-> cycle through every major civ
--> get affinity level
----> get current research
------> change research progress depending if the tech grants an affinity and what affinity the player has
 
i don't even know where to start to call the function automatically when a tech is researched

Code:
function OnTeamTechResearched(iTeam, iTech, iChange)
  if (iChange > 0) then
    -- iTeam just researched iTech
  else
    -- iTeam just "lost" iTech, never happens during game play,
    -- but can if techs are being manipulated by Lua
  end
end
GameEvents.TeamTechResearched.Add(OnTeamTechResearched)
 
this is my current code (first time lua user):

Spoiler :

Code:
function AffinityResearchDelay(iPlayer)
        local pPlayer = Players[iPlayer];
		local ipur = pPlayer:GetAffinityLevel(GameInfo.Affinity_Types["AFFINITY_TYPE_PURITY"].ID);
		local ihar = pPlayer:GetAffinityLevel(GameInfo.Affinity_Types["AFFINITY_TYPE_HARMONY"].ID);
		local isup = pPlayer:GetAffinityLevel(GameInfo.Affinity_Types["AFFINITY_TYPE_SUPREMACY"].ID);
		local techType = pPlayer:GetCurrentResearch();
		-- what type of affinity (atype) does the current research techType grant (0 = no affinity, 1=pur, 2 =har, 3=sup)?
		atype = something(techType)
		
		
		-- skip the rest if the player has no affinity points or the tech is affinity neutral
		if (atype == 0) or (ipur + ihar + isup == 0) then
			return;
		
		-- sum of opposing affinities
		if (atype == 1) then
		   oAff = ihar + isup;
		elseif (atype == 2) then
			oAff = ipur + isup;
		elseif (atype == 3) then
			oAff = ihar + ipur;
		
		-- calculate research delay
		local iRPT = pPlayer:GetScience();
		malus = 0.15*oAff;
		delay = -1*(iRPT - (iRPT/(malus + 1));

		-- delay tech
		local team = Teams[pPlayer:GetTeam()];
		local teamTechs = team:GetTeamTechs();
		teamTechs:ChangeResearchProgress(techType, delay, pPlayer);
		
		--needs hookup with ui to display delay in beakers tooltip
		
		
		
end
GameEvents.PlayerDoTurn.Add(AffinityResearchDelay)


i have the following problems:
1) i don't know if you can give negative science in the ChangeResearchProgress function

2) i still need a function that gives me the affinity type from the tech as an integer? i am not so sure how i can check it, if i use the function you posted, because it returns strings

3) does the hookup through GameEvents.PlayerDoTurn automatically cycle through all players including ai?

4) is it possible to display the science malus (=negative bonus) in the tooltip of the main screen science ui, i.e. if you hover of the beaker symbol there is another line like: "- x beakers from other affinities"


please let me know if you spot any other major issues
 
1) Yes, all the ChangeXyz() methods take both positive and negative values

2) The GetAffinityPoints() function posted takes string parameters and returns an int, if you want the affinity type related to a tech use

Code:
function GetAffinityForTech(sTechType)
  local sAffinityType = nil

  for row in GameInfo.Technology_Affinities{TechType = sTechType} do
    sAffinityType = row.AffinityType
  end

  return sAffinityType
end

local iAffinity = -1
local sAffinityType = GetAffinityForTech("TECH_ALIEN_BIOLOGY")
if (sAffinity) then
  -- See http://forums.civfanatics.com/showthread.php?t=485884
  iAffinity = GameInfoTypes[sAffinityType]
end

3) Yes, in general all GameEvents.Abc fire for all players, take care with Events.Xyz though as those generally only fire for human players

4) Only by replacing the game core TopPanel.lua file, but that's generally not a good idea for a cosmetic change as you make your mod incompatible with every other mod that also changes the TopPanel.lua file (which may be making non-cosmetic changes)
 
regarding 2)

i want a function that basically looks like

iSomething = GetAffinityForTech(TechType)

you say that the function returns an integer, but how do i change the TechType into a string for the input argument then?
i.e.
sTechType = ???(TechType)

with
TechType = pPlayer:GetCurrentResearch()
 
See the tutorial link in the code comment, but basically

Code:
sTechType = GameInfo.Technologies[iTechId].Type
iTechId = GameInfoTypes[sTechType]
 
i hope this will work:

Code:
...
		local techType = pPlayer:GetCurrentResearch();
		local sTechType = GameInfo.Technologies[techType].Type;
		
		-- what type of affinity (atype) does the current research techType grant (0 = no affinity, 1=pur, 2 =har, 3=sup)?
		local sAffType = nil;
		local atype = 0;
		for row in GameInfo.Technology_Affinities{sTechType} do
			sAffType = row.AffinityType
		end
		if (sAffType) then
			atype = GameInfoTypes[sAffType]
		end
...

i am assuming that atype = GameInfoTypes[sAffType] returns 1 for purity, 2 for harmony and 3 for supremacy. is this correct?
 
i am assuming that atype = GameInfoTypes[sAffType] returns 1 for purity, 2 for harmony and 3 for supremacy. is this correct?

The actual numerical values are irrelevant, what is important is whatever the value you get for Harmony from GameInfoTypes is (it could be 83 for all it matters) will be the value you need to use in the other functions that require a value of "harmony"
 
but how can i make a comparison then?

for example in the code above atype is a numerical value (probably an integer) and i need to know if it is either harmony, purity or supremacy, i.e.

if atype == (what??) then
...

or can i simply use the returned string and compare it i.e. something like

Code:
  for row in GameInfo.Technology_Affinities{sTechType} do
    sAffinityType = row.AffinityType
  end

...
	if (sAffinityType == "AFFINITY_TYPE_PURITY")
...

does this work?


edit:

just to be sure:
Code:
local ipur = pPlayer:GetAffinityLevel(GameInfo.Affinity_Types["AFFINITY_TYPE_PURITY"].ID);
ipur is an integer with the current affinity level in purity, or did i make a mistake?
 
the formula is

(1/(1+0.15*SumOfOtherAffinities) - 1)*ResearchPerTurn

e.g. if you research a harmony technology and have 50 research per turn and 3 other affinities (any combination of purity and supremacy) you get -15.517... research per turn. this corresponds to 45% increased technology cost.

if i use this value in ChangeResearchProgress does it has to be an integer or is a float value valid as well?
 
If iMyAffinity is known to be an affinity type, you can test if it's harmony with

Code:
if (iMyAffinity == GameInfoTypes.AFFINITY_TYPE_HARMONY) then
end
 
if i use this value in ChangeResearchProgress does it has to be an integer or is a float value valid as well?

Integers only.

(Almost nothing in the game core uses floats - as you can't guarantee that a float on one machine is the same as the float on another for multi-player games)
 
hm i wanted to add a note for debugging purposes

Code:
if pPlayer:IsHuman() then
			local sText = Locale.ConvertTextKey("TXT_KEY_NOTIFICATION_DEBUG_RANDOMTEXT")
			local sTitle = Locale.ConvertTextKey("TXT_KEY_NOTIFICATION_DEBUG_RANDOMTITLE")
			pPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, sText, sTitle, pPlayer:GetCapitalCity():GetX(), pPlayer:GetCapitalCity():GetY())
		end

within the function, but nothing is displayed. i defined the two txt keys in an xml within the mod. did i overlook some obvious issue? sorry for the noob question but i skipped civ5 modding. (modded civ4 from graphics to xml and python)


edit:
did i miss something obvious with lua mods and ModBuddy? i created a new project, added a lua script and an xml (containing the text keys) and build it. in civBE i loaded the mod. did i have to change something in the build properties? i know for xml mods i need to add an action to update the database, but is there something similar for lua? i am a bit baffled why it does not work/crash or give any feedback.
 
so i set the vfs flag to true and commented out most of the code. the current lua script just contains the following line:

Code:
function AffinityResearchDelay(iPlayer)
        local pPlayer = Players[iPlayer]


		if pPlayer:IsHuman() then
			local pCity = pPlayer:GetCapitalCity()

			pPlayer:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, "TEST", "HLP", pCity:GetX(), pCity:GetY())
		end
	
end
GameEvents.PlayerDoTurn.Add(AffinityResearchDelay)

yet i still get no ingame notification, error or any indication that the script runs. the formating in the code above is a bit off. the if - end are one tab further to the left.
 
> Is the file a replacement for a core game file?
NO

>Does this file contain methods registered by events within the file,
>or methods that are then executed directly during game startup?
YES

VFS: False
Requires an InGameUIAddin entry
 
Back
Top Bottom