• We are currently performing site maintenance, parts of civfanatics are currently offline, but will come back online in the coming days (this includes any time you see the message "account suspended"). For more updates please see here.

Researching all Current Era's Techs Before Advancing to the Next Era?

Grave

1 Goat = 400 Horses
Joined
May 5, 2002
Messages
1,530
Location
Louisiana
Is there a way to prevent advancing to the next era unless all Techs from a previous era are researched first? Basically, what I'm trying to do is each Era will have a "mini-tech" tree associated with it, and in order to advance to the next era, all the Techs from that era must be researched before advancing.

I found a way to do it without any help from LUA: Basically, I would make all the "beginning" techs for a certain era PrereqTech all the "ending" techs of the era before it. So for example: if the TechTree for the Ancient Era ended with Writing, The Wheel, and Bronze Working, then all the beginning techs for Classical Era would each require all three of these techs.

The problem with this is, once you do an entire game's worth of TechTrees this way, the game takes EXTREMELY long to load, and I'm sure you can imagine why.

So what I need to know is, is there an easier way to accomplish this? Would there be some kind of code that can be written in LUA that would prohibit you from entering the next era until all of the current era's techs are researched first?
 
yes, add a function to GameEvents.PlayerCanResearch(playerID, techTypeID)

make it return false if the tech is era n+1 and the player has not researched all techs of era n.
 
yes, add a function to GameEvents.PlayerCanResearch(playerID, techTypeID)

make it return false if the tech is era n+1 and the player has not researched all techs of era n.

Gedemon,

Sorry, I'm afraid I'm not very proficient with LUA. If you don't mind, could you post the example, please? Maybe if I see it, it will make more sense to me.

Thanks,
Grave
 
Well, something like:
Code:
function OnCanResearch(playerID, techID)
   local player = Players[playerID]
   local team = Teams[player:GetTeam()]
   local eraType = GameInfo.Technologies[techID].Era
   local eraID = GameInfoTypes[eraType]

   -- Does this team learnt all of the techs from the previous eras?
   for row in GameInfo.Technologies() do
      local otherEraID = GameInfoTypes[row.Era]
      if otherEraID < eraID and not team:IsHasTech(row.ID) then return false end
   end

   -- None failed, all known
   return true
end
GameEvents.PlayerCanResearch.Add(OnCanResearch)
 
Thanks for that info, DonQuiche.

Ok, so I took your bit of code and pasted it into a new LUA file, called BlockTechEra.lua and put it into the root directory of my mod. I went to the file properties and changed Import to VFS to "true", and then I went into the mod's content tab and added it there as a "custom" type.

I went to test it out, and started a game in the Ancient Era. But when I went to select my first tech, all the Techs at the "beginning" of each era are still showing up. So, I can research Telecommunications at 4000BC, it just takes 1700+ turns. :P

Any ideas what I'm doing wrong?

** EDIT **

Ok, disregard that last bit. I changed the "Custom" setting on the content tab to "InGameUIAddin" and it seems to be working. When the tech notification icon pops up (when you first found a city), it will only show the techs that are available for research immediately.

However, if you just click on a tech from another era (Iron Working, for example) it seems you can research it immediately, and bypass all the other techs in the current era.
 
Well, I do not know what the "custom type" does actually. So let's test whether it works: at the beginning of the file add: print("test"). Now start a new game with your mod and see whether FireTuner (or the lua.log file) prints "test" near the end of the output.

If this does not work, adds a .xml file with the same name and the content below. Then include it in the VFS, remove the "custom" entry in the content tab and add an "InGameUIAddIn" entry with this XML file instead.
Code:
<?xml version="1.0" encoding="utf-8" ?>
<Context />

Anyway, once you saw the "test" line, if it still does not work then look for an error in the lua output (firetuner or the log). If there is no error, adds a print statement here and there, such as print(eraID, otherEraID) within the loop.
 
Changing the content tab from "Custom" to "InGameUIAddIn" seems to help with selecting the correct techs once you found a new city (or complete research on a tech) when you click on the giant research notification icon off to the right.

But, when to go into the techtree view, you can still select basically any tech in the game, and if it's in another era, you can begin research on it immediately.

Would it help if I explained exactly what kind of game mechanic I'm trying to create, or was my original explanation good?
 
Your explanation was clear this is not the problem. I just checked GameEvents and I see no sign of a PlayerCanResearch event, so I wonder whether it still exists.

Let's first check that. Remove the old code and use this one instead:
Code:
function OnCanResearch(playerID, techID)
   return false
end
GameEvents.PlayerCanResearch.Add(OnCanResearch)
What happens then?
 
It was available in patch 1.0.1.332 (see the notes here), hope they didn't removed it (and some other) by inadvertance...
 
When I do that, I start up a game and build my first city. It seems the tech selection menu is blank, where it says "Please select a new technology..."

But, when I open the techtree, I can still select any tech I want to research. The selected tech then shows in the main menu as currently being researched, like a normal game.
 
Ok, then the mystery is solved: Gedemon is right and the event does exist (and the API reference does not mention it) but the tech tree does not care about it.

Or maybe it does, partially. Restore the old code. Now, when you select a modern tech at the beginning, does the research order respect the "must have completed the whole era" rule? If it does not, what happens when you reach a point where the next scheduled tech would break the rule: does civ5 then switch to another tech? You may use IGE for quick testing (to easily grant techs).

Anyway, it seems like you will at least have to modify the tech tree UI (which is a big deal unfortunately). But we first need to be sure that civ5 has no other bad surprise in stock and what's the exact behavior.
 
Ok, then the mystery is solved: Gedemon is right and the event does exist (and the API reference does not mention it) but the tech tree does not care about it.

Or maybe it does, partially. Restore the old code. Now, when you select a modern tech at the beginning, does the research order respect the "must have completed the whole era" rule? If it does not, what happens when you reach a point where the next scheduled tech would break the rule: does civ5 then switch to another tech? You may use IGE for quick testing (to easily grant techs).

Anyway, it seems like you will at least have to modify the tech tree UI (which is a big deal unfortunately). But we first need to be sure that civ5 has no other bad surprise in stock and what's the exact behavior.

When I build my first city, I'll go into the TechTree menu. From there, I can still select a modern tech immediately (Telecommunications, for example, which is at the "beginning" of my Information Era tree). But, if I go to the very end of that tree and select Future Tech, it outlines all the techs I need to research in order to get there (which is all the Information Era techs) just like it would normally in a vanilla game.

So, when I do that and click on Future Tech, it looks like it's ignoring all the techs from the previous eras.
 
But all of this was predictable given what you found previously. We need the answers to the questions I asked in my previous post in order to figure out how exactly does the tree behave in respect to this event. Right now you're focused on the outcome you want but you rather need to focus on understanding what happens. After that we will be able to figure out the best solution to achieve what you want.
 
Or maybe it does, partially. Restore the old code. Now, when you select a modern tech at the beginning, does the research order respect the "must have completed the whole era" rule? If it does not, what happens when you reach a point where the next scheduled tech would break the rule: does civ5 then switch to another tech? You may use IGE for quick testing (to easily grant techs).

But all of this was predictable given what you found previously. We need the answers to the questions I asked in my previous post in order to figure out how exactly does the tree behave in respect to this event. Right now you're focused on the outcome you want but you rather need to focus on understanding what happens. After that we will be able to figure out the best solution to achieve what you want.

Sorry, I see what you mean now. I thought you wanted me to do the test I described previously (with Future Tech).

I started a new game, and your code works exactly like it should. I researched all the Ancient Era techs, and when I finally researched the final tech (The Wheel) the "Classical Era" spash screen appeared. From the tech selection menu, all the "beginner" Classical Era techs were selectable for research.

So, I think this part is working just fine.
 
I wonder if there is something I can do in SQL? This would be an example for an Information Era tech:

Code:
UPDATE Technologies SET Technology_PrereqTechs=(somehow incorporate all previous eras) WHERE Era=ERA_CLASSICAL and Era <> 'ERA_MEDIEVAL' and Era <> 'ERA_RENAISSANCE' and Era <> 'ERA_INDUSTRIAL' and Era <> 'ERA_MODERN' and Era <> 'ERA_POSTMODERN';

I know that wouldn't be the exact code, but I think you get the idea.
 
This is interesting, so the solution works mechanic-wise and this is "just" an UI problem with the techs tree. So you need to think about how you want the tech tree to behave exactly. Things like "can the user still click a tech in a further era" (since the rule will still be respected), "should we render the techs in further eras differently, with a red background for example" (similar to locked techs, which are not used by the base game but are used by some mods), etc? My suggestion to those two questions is "yes" and "yes". Incidentally, it is also the one that requires the least amount of work.

Now, on the display side, you didn't report whether the ordering indices displayed on each tech's corner on the tech tree are correct. Also, if you click optics, are all the ancient eras lit up?

Finally, regarding the modifications of the prereqs, this looks like a bad idea. Look at the tree for two seconds: after each column you would find yourself with a full-height vertical bar. Indeed, pottery would be connected to optics, philosophy, etc, down to iron working. Maybe you could reduce the problem by trimming down unnecessary prereqs (classical techs would be only connected to the last column from the ancient era rather than to every ancient tech) but you would still have a full-height bar at the end of each era and I think this would be confusing. On the contrary I think you should better remove prereqs for all techs at the beginning of an era, so that no link is displayed across eras, but this is polishing.
 
This is interesting, so the solution works mechanic-wise and this is "just" an UI problem with the techs tree. So you need to think about how you want the tech tree to behave exactly. Things like "can the user still click a tech in a further era" (since the rule will still be respected), "should we render the techs in further eras differently, with a red background for example" (similar to locked techs, which are not used by the base game but are used by some mods), etc? My suggestion to those two questions is "yes" and "yes". Incidentally, it is also the one that requires the least amount of work.

Right now, I'm willing to accept whatever works and is easiest to implement. :lol:

I never thought about the locked techs. That's an excellent idea! :goodjob:
But, if they were locked, wouldn't that prevent you from researching them completely?

Now, on the display side, you didn't report whether the ordering indices displayed on each tech's corner on the tech tree are correct. Also, if you click optics, are all the ancient eras lit up?

This only works if you click on one of the latter techs in any given era. If you click on one of the last techs of any given era, the ordering indices appear as they would in a normal game. But if you click on one of the "beginner" techs of an era, it shows as being available immediately, and not requiring any previous era techs as a prerequisite. Since the "beginner" era techs technically do not have PrereqTechs in the XML (in order to draw the tree correctly), when you click on one (Mathematics for example), it's available for research right off the bat if you go in via the TechTree and select it. (see attached screenshot)

Finally, regarding the modifications of the prereqs, this looks like a bad idea. Look at the tree for two seconds: after each column you would find yourself with a full-height vertical bar. Indeed, pottery would be connected to optics, philosophy, etc, down to iron working. Maybe you could reduce the problem by trimming down unnecessary prereqs (classical techs would be only connected to the last column from the ancient era rather than to every ancient tech) but you would still have a full-height bar at the end of each era and I think this would be confusing. On the contrary I think you should better remove prereqs for all techs at the beginning of an era, so that no link is displayed across eras, but this is polishing.

The way I worked around this is by going into TechTree.lua and changing how the techtree pipes draw. Basically, I switched the code so the pipes draw for an ORPrereqTech instead of an PrereqTech.

So, I would basically draw the tree in CIV5Technologies.xml using the <OrPrereqTech>. The problem with this is, as you would expect, this creates an "or" situation when determining PrereqTechs. So to solve that problem, I would copy and paste the entire <OrPrereqTech> section into the <PrereqTech> section and then add all the "ending" era techs as PrereqTechs for the next era. This way, the techtree pipes wouldn't be a mess when viewing them in the game.

Unfortunately, doing it this way makes a mod take literally 5 minutes to load, I'm guessing because the game is figuring out how to "draw" the techtree, even though the pipes are non-existant for <PrereqTech> techs.

If that makes any sense...
 

Attachments

  • 2012-10-01_00002.jpg
    2012-10-01_00002.jpg
    155.5 KB · Views: 232
Wow. So basically your "OR" prereqs set contains all of the original "AND" set, minus the inter-era prereqs? And the "AND" set is added with new prereqs to enforce the "one era after the other" rule. Smart. :)

Now the first problem is that you did all of that through copy-pasting and you need a SQL. The second problem is your loading time but there is no reason we cannot fix that. When does the thing hang exactly? Could you try to insert print statements in the tech tree lua file and watch FireTuner to see which part is slow to load?

That being said, your method was, I guess, mainly chosen in order to compensate for your lacks of Lua skills. But I am worried about side-effects such as potential performances problems for the AI and mods compatibility. Leaving the XML unchanged and just using pure Lua tricks seems less intrusive, but maybe this is just a prejudice from my side. I would like to hear other modders' opinion, such as Gedemon's, because I have a poor experience of modding the techs tree and may not be aware of some pitfalls.

Now, to expand on this pure Lua approach, I need you to redo the tests I previously asked but without modifying the XML (I want the inter-eras prereqs to still be in the XML files). However, provided my guesses are correct, then the only thing you need to do is to prevent the UI to display those inter-era links, which is as simple as modifying line 107 and 150 as follow:
* Old: if tech and prereq then
* New: if tech and prereq and tech.Era == prereq.Era then

Well, I guess you should better start with that. Restore your XML prereqs to their original state (use the standard techs, not your custom tree for now if needed), keep the event code we used so far and make the changes I just described to techtree.lua. I guess the result will be almost good, minus a little problem that will appear if you click optics (not every tech in the ancient era will be lit up). Well, one step after the other.

EDIT: Nevermind the stroke part. Initally I assumed that civ5 was using the event for testing techs dependencies. I now understand it doesn't care at all and only deals with prereqs. And that we also have to modify them in order for API like Player.CanResearch to work. As a result I am now pretty certain that the "good way" to do it is to not change the OR prereqs set, add new prereqs to the AND set and use the display trick I detailed in this post.
 
Some SQL code to add the missing prereqs. This is far to be optimized but since those queries are only ran once on startup, I guess this is not needed. Should I be wrong, though, there is room for improvements.

Code:
/* Add new prereqs so that each tech from era N have all the techs from era <N.
*/
INSERT OR IGNORE INTO Technology_PrereqTechs
SELECT 
   TechType, PrereqType 
FROM 
        (SELECT Technologies.Type AS TechType, Eras.ID AS TechEra
         FROM Technologies INNER JOIN Eras 
         WHERE Technologies.Era = Eras.Type)
    CROSS JOIN 
        (SELECT Technologies.Type AS PrereqType, Eras.ID AS PrereqEra
         FROM Technologies INNER JOIN Eras 
         WHERE Technologies.Era = Eras.Type)
WHERE
    PrereqEra < TechEra


/* A table that contains T0 and T2 for all T0 -> T1 -> T2 dependencies 
   (T0 -> T1 is defined in S1, T1 -> T2 in S2).
   Also stores higher order cases such as T0 -> T3 since we do have T0 -> T1 (S1) and T1 -> T3 (S2). 
   Use your own unique, mod-specific, prefix rather than XYZ.
*/
CREATE TABLE XYZ_IndirectPrereqs 
AS SELECT S1.PrereqType AS PrereqType, S2.Type AS Type
FROM Technology_PrereqTechs S1
INNER JOIN Technology_PrereqTechs S2 
ON S1.Type = S2.PrereqType


/* Trims unneeded prereqs: T0 -> T2 when exists T0 -> T1 -> T2.
   Also covers higher order cases (see XYZ_IndirectPrereqs comments).
*/
DELETE S
FROM Technology_PrereqTechs S
WHERE EXISTS 
    (SELECT * FROM XYZ_IndirectPrereqs Indirect 
     WHERE S.Type = Indirect.Type AND S.PrereqType = Indirect.PrereqType)
 
If you're going to mod the core TechTree code, just add another column to the Prereqs table called "DrawPipe" and default it to true, then change the TechTree lua code to only draw pipes if that value is true, then add all the new prereqs for each start era techs with the DrawPipe value set to false
 
Back
Top Bottom