New Civilopedia Section: Routes

By the time you are working with the pedia I'd suggest a slight change for the Civilizations tab.

Currently it looks like this:
upload_2017-8-15_12-50-44.png


The space for Unique Buildings is not big enough to display the whole title.

If you could change it like this...
upload_2017-8-15_12-53-53.png

...than it would look much better.

I know it's a small thing. Just a suggestion.
 
I can do that. It does look a little better and leaves room if anyone wants to add more UB's. I doubt anyone would ever add more than 5 total UU's per civilization.
 
The Civilopedia screens are all handled in Assets\Python\Contrib\Sevopedia. The _init_ section at the beginning covers the placement of the panels. X and Y are the starting points and W and H are the width and height.

All I have to do is change self.W_BUILDING to equal self.W_MAIN_PANE instead of its originally hardcoded 130. Then the building panel will be exactly as wide as the panel for the civilization icon. The unit panel is set up to start 10 units (possibly pixels, but I think it's a bigger unit than that) from the right edge of the building panel and run all the way to the right edge, so it self-adjusts.
 
Alright, well, at least the reason why clicking on Cart Path doesn't do anything is because no value is defined for this parameter PEDIA_ROUTE . I just checked CvScreenEnums.py and there isn't one, so it's probably not in any other imports of CvScreensInterface:

Code:
def pediaJumpToRoute(argsList):
    if (bUsingSevopedia):
        pediaMainScreen.pediaJump(SevoScreenEnums.PEDIA_ROUTES, argsList[0], True, False)
    else:
        pediaMainScreen.pediaJump(PEDIA_ROUTE, argsList[0], True)
You also know there is no such SevoScreenEnum.

Even if there was a definition for this identifier, pediaJump in CvPediaMain will only do what's expected if PEDIA_ROUTE (in CvScreensInterface) equals a PEDIA_ROUTE that's defined for module CvScreenEnums CvPediaMain and not equal to the other CvScreenEnums constants.

Both modules import from CvScreenEnums, so that's where the number is needed. Finding an unused integer seems to be all you need, since these aren't actual enums, and this is a language that doesn't compile.

Do you know where the module CvPythonExtensions is defined? That's where I have to track down CivilopediaPageTypes.

---
Other things I need to know:
Where does Python contribute the Route definitions? The enum in the c source file starts with just NO_ROUTE.
Where is CvPediaScreen module, or any of the other imports of CvPediaMain ?
These questions would let me answer -> where is CvPediaMain::getSortedList() defined and will it produce the correct list?

Is there a getButton() defined for the type that's returned by the Python getRouteInfo(int) method declared on the CyGlobalContext?
 
Last edited:
Do you think there's a problem with the Python for the routes page? If there was, wouldn't the problem show up if you looked at the Sevopedia before you started the game? I think the problem is the routes widget in the DLL, not the Python. Or did you try that already and didn't work?
 
I can't find evidence that the game would ever load a "routes page" if one existed, except for the Sevopedia. We're not debugging the Sevopedia.
I neither can find evidence that c code has anything to do with showing civilopedia pages except for passing a message from Python back to Python, for some reason, when 'jumping' to a page.

The problems we know about are (1) that browsing the list of Routes shows just Cart Path, an error which must be explained by something wrong with the placeRoutes() function or something it uses, and (2) clicking Cart Path doesn't give any info on Cart Path or change anything at all, which I'm pretty sure has to do with the use of an identifier that is undefined in CvScreensInterface at the passage I quoted above.

What do you know that calls a c function? I have to trace execution starting from somewhere relevant, and the big ball of mud naturally doesn't have helpful signage. I don't know how to find the Python modules in the import statements and they have at least one declaration that is a suspect in the placeRoutes() bug.
 
I can't find evidence that the game would ever load a "routes page" if one existed, except for the Sevopedia. We're not debugging the Sevopedia.
I neither can find evidence that c code has anything to do with showing civilopedia pages except for passing a message from Python back to Python, for some reason, when 'jumping' to a page.

The JUMP_TO widgets are in the c code. They are not in the Python. In the original Civilopedia, doPediaRouteJump doesn't care about the type of route it is being fed, so clicking on either Road or Railroad jumped to the Movement page.This is why I keep thinking the widget is the problem. If doPediaRouteJump was coded the same way as doPediaImprovementJump, I think it would solve the problem, but that doesn't explain why the routes pages work fine out-of-game.

The problems we know about are (1) that browsing the list of Routes shows just Cart Path, an error which must be explained by something wrong with the placeRoutes() function or something it uses, and (2) clicking Cart Path doesn't give any info on Cart Path or change anything at all, which I'm pretty sure has to do with the use of an identifier that is undefined in CvScreensInterface at the passage I quoted above.

What do you know that calls a c function? I have to trace execution starting from somewhere relevant, and the big ball of mud naturally doesn't have helpful signage. I don't know how to find the Python modules in the import statements and they have at least one declaration that is a suspect in the placeRoutes() bug.

I don't think CvPythonExtensions is actually defined anywhere. I tried searching all my Civ4 files and Google searching for it and nothing came up.

I have Python exceptions turned on and when I am in-game and try to either bring up the Routes page or click on Cart Path, I get that the last call is to placeItems in SevopediaMain. This is the line that Python exceptions is saying is the problem (line 834 of SevoPediaMain.py):
Code:
screen.setTableText(self.ITEM_LIST_ID, 0, i, u"<font=3>" + item[0] + u"</font>", info(item[1]).getButton(), widget, data1, data2, CvUtil.FONT_LEFT_JUSTIFY)

widget is the one place in that line where the C code gets called, and the WIDGET_PEDIA_JUMP_TO_ROUTE is the only C call that I can see in placeRoutes. It's the one thing that is not the same as every other place in SevoPediaMain.

getSortedList is defined for the original Civilopedia in Civ4\Assets\Python\CvPediaScreen.py. For anything that isn't defined in the mod, it might be defined in the BTS files or the original Civ4 files. getSortedList is defined again for the Sevopedia at the very end of SevoPediaMain.py. There is a difference there from the original definition, so it might be worth a look.

Let me know more about what you are doing and I will see if I can be more helpful.
 
I'm doing multiple things, hoping one idea sticks.

The WIDGET_PEDIA_JUMP_TO_ROUTE reference is not the issue. That reference is to a value object, a struct in c-terms, which gets read by a c-function that looks like this:

CvDLLWidgetData::executeAction ( <Widget> ):
-> (a bunch of case switching)
if <Widget> 's 'Widget Type' field is equal with the WIDGET_PEDIA_JUMP_TO_ROUTE value, invoke "doPediaJumpToRoute" with the other data from <Widget>

and doPediaJumpToRoute( <Widget> ) is just:
get an Access Lock for Python (which I assume has to do with concurrency)
use the Python adjunct to call a function named "pediaJumpToRoute" in something named "CvScreensInterface" with the argument <Widget>.data1

I can guess that executeAction() is a function that gets called on anything that gets clicked, which is how the Widget helps to define what clicking in different contexts does in a polymorphic way.
As I said, this is just taking the request and throwing it back to a Python runtime. We know that the data1 field should be correct, since that gets set to the Infos integer for the specific Route when getSortedList() produces the list for placeRoutes() .

What I need to know is more of the building block stuff, because I can't seem to verify the existence and/or correctness of some of the "utility" calls. For instance, the getSortedList that comes from base Civ4BTS has some kooky lines about checking if the Infos it grabs return false for "isGraphicalOnly()" . Something to check though: If I assume the Infos for Rise of Mankind's Routes get populated from XML, then the isGraphicalOnly has to be set to 0 for these Routes. Don't get your hopes up, because the default might be 0. I can't find where defaults are set for the database... in Civ 5 the defaults are in a file that defines the table, but here there's only files that give the schema of the XML.

I'm going to rely on you some more for file references. My file system search is ass, I just proved it doesn't actually search file contents.
If I understand something you wrote earlier in this thread, ROUTES don't have their own page exactly, because that wouldn't be much to base a PAGE on. You instead look at Routes from the MAIN_PAGE directly? Is that how it's intended? I'm curious because the c-file doesn't have a value for "CIVILOPEDIA_PAGE_ROUTES" in the ..._PAGE_TYPES enum, but it is exposed to Python, for extension I guess? Like, one stumbling point for me right now is I can't even find the materials for the New Dawn Concepts page. Because my file search is ass. Where are any references to "CIVILOPEDIA_PAGE_CONCEPT_AND" or "CIVILOPEDIA_PAGE_CONCEPT_NEW" in Python, for example ? Where is the content of the New Dawn Concepts page written?

----
I'm trying something to at least fix the jumping part. I'm going to "subclass" the CvScreenEnums file and graft a PEDIA_ROUTE definition into it. I can change the behaviour of the two modules I care about and not break anything outside those two.

Python question: If I run the function sort() on an array of tuples like this: [("Elizabeth II", 52) , ("Pedro II", 31) , (0 , 0) , (0 , 0) , ("Important" , 1)] there's no problems, right?
 
I think what we might need here is that CIVILOPEDIA_PAGE_ROUTES definition in the C code. I just found that in CvScreenEnums.py, I did not define the value for PEDIA_ROUTE. If I do try and add that definition, I get a bunch of Python errors while the mod is still loading. I did define PEDIA_ROUTES in SevoScreenEnums.py, but having CIVILOPEDIA_PAGE_ROUTES missing from CvScreenEnums seems to me like one possible cause for a problem.

GraphicalOnly is a flag for the Civilopedia that means "don't display this". Routes don't even get this flag; they don't use the same schema as improvements. Improvements use the Terrain schema, while routes use the Misc schema. The original intention for Routes in the BTS Civilopedia was that you would just look at the Movement concept page, because there were only two routes. It's just that we have 9 (including Tunnel) that made me want to add pages for each route.

The concepts pages are written in SevoPediaMain.py. Anything that doesn't fit another category gets sorted into there.

Also, I have no idea how sort() works. I just know enough Python to get the results I want (most of the time) out of Civ4's options.
 
Alright well the subclassing thing didn't work. All I managed to change was the great person meter became misaligned and that and the GG meter moved onto the same row with the tech icons. ... how.

GraphicalOnly is not only for Routes, or at least the call written for getSortedList assumes otherwise. The C code gives a base class for RouteInfos and isGraphicalOnly is declared there, and exported for Python to define. When CvPediaMain calls getSortedList, it has to scope to something imported by that module, and SevoPedia's getSortedList isn't included. So I think the only one that's called is the one from CvUtil.py in BTS\Assets\Python . And that's actually BTS\ Assets(\Python), not BTS\BTS\Assets(\Python) where most BTS data lives on a Steam installation. This function builds a list of tuples where (0 , 0) takes the place of anything where the Infos object passed to the sorter gives (not isGraphicalOnly()) . I'll just try putting isGraphicalOnly of 0 on all the routes, it can't hurt.

So in SevoPediaRoute there is a class defined that can define a screen for routes. But where is CvPediaRoute defined? It's an import of CvPediaMain, and it's used to define how the interface is displayed here, lines 95 to 97:

Code:
        self.pediaFeature = CvPediaFeature.CvPediaFeature(self)
        self.pediaRoute = CvPediaRoute.CvPediaRoute(self)
        self.pediaImprovement = CvPediaImprovement.CvPediaImprovement(self)

Later, this field pediaRoute is the receiver of a call to interfaceScreen(iEntry) which I can gather would load the Routes screen with the specific Route pulled up to start. This of course isn't doing what it should.
It seems to be an analogue of the showScreen function in CvPediaMain, which , by the way, defines how placeRoutes or placeWhatever actually gets called. Again this uses a CivilopediaPageTypes module. It's quite circuitous, but it looks like showScreen(iEntry) is actually showScreen(ofCategory) , which should be passed the category for the PAGE_TYPE of ROUTES itself... this is meant to govern what clicking on "Routes" in the outer left panel does. Let's assume that is working, since clicking Routes does give us a list of Cart Path at least. By the way, this implies that CIVILOPEDIA_PAGE_ROUTE is exists and defined, just in the mysteriously-located CivilopediaPageTypes object.
Oh! CivilopediaPageTypes is imported as a member of CvPythonExtensions, which I think I know comes from which C-file. Even though that enum looks incomplete in the C-file, we know it gets extended somewhere. Interesting.

You won't be able to simply add an Enum, because then the NUM_OF_THOSE_ENUMS , which is itself a value of the enum, would be incorrect. The subclassing thing should be able to sidestep that problem... it really should be the silver bullet here, because all we need is a value to check equality when CvScreensInterface communicates with CvPediaMain, something called "PEDIA_ROUTE", while the CIVILOPEDIA_PAGE_ROUTE type already exists.


Maybe I collided with another number in use?

By the way the type is CIVILOPEDIA_PAGE_ROUTE singular. We don't have to worry about this.
 
You do have a CvPediaRoute module, right? It should have a interfaceScreen(iRoute) function like SevoPediaRoute does, otherwise pediaJump of course isn't gonna do anything because it's calling for some class that doesn't exist. interfaceScreen makes the panels, shows the yield information, shows the movement bonus.... There wasn't a Routes page in BTS so I know that someone on the team wrote this code.

I tried adding an enum to PageTypes, I got a missing UI game, with no ability to load the tech screen (which is the only screen I remember a hotkey for). I can order units with keys and select a tech or build using the popup. Ugh why does software have to be so difficult.
 
I never did any kind of CvPediaRoute module. I just added the Sevopedia page. I'm not sure even what you are actually referring to by a module. Is that Python or C? I can't do anything with C.
 
I didn't apply my test correctly, so I did now, and I got a game that just played the same as standard, except where if you open to the Routes page in the pedia, and open the Index and then Contents repeatedly, the pedia sometimes will go blank in response to the Contents click. Also, the Cart Path persists as the first thing open on the civilopedia after you've viewed Routes once. This is after I extended the CivilopediaPageTypes enum in the DLL, and wrote a python file to replace CvScreenEnums, so that those two files had a definition for PEDIA_ROUTE .

I can't find where the Routes data become loaded in game memory. But it does, so that doesn't mean much. Search says that nothing in the SDK ever calls CvRouteInfo::read (<XML>) , so something inaccessible is responsible for putting the Routes data into memory. I'm really focused on this side because that function, where the python error occurs, in placeRoutes . . . the only heavy lifting in that function on that line is the fact it's going through a list that was built using the getRouteInfo() function. Like I said, there's almost nothing here that can fail.

Making all the Routes display in the Routes page, and not break the index, that may be a C problem. What it looks like also needs to be done, is defining a civilopedia page for Routes. There isn't one. Clicking Cart Path does nothing because there never was anything for it to do. Right now, CvPediaRoute is just a name. This is a Python problem.

To let Cart Path load a help page, and the other Routes when I get them into the list, you have to produce a python module named CvPediaRoute that has a class named CvPediaRoute which at least has a function named interfaceScreen(self, iRoute) that will put the data you want. By module I mean what a python file imports with an import statement. You can base all your information on the same thing written for the Sevopedia page. The class constructs on CvPediaRoute(self, main) just like the Sevopedia one. The function I mentioned is the only contractual behaviour, and it looks like that function is responsible for cleaning up when it starts, with a call to main.deleteAllWidgets() . But you have to use the display dimensions that work for the Civilopedia.

Synthesizing a class file from SevoPediaRoute.py and the base game's CvPediaImprovement.py, CvPediaPromotion.py, etc. seems like something you would be better at. You actually wrote the Sevopedia one, so you know what the pedia page should actually tell people. And you can work at that while I investigate the Electric Railroad type. I don't want to have only it and the getSortedList function remain as the things I can actually examine, so I might as well look at the Index to see why that might break.
 
Last edited:
Hello friends, I do not have much idea,
but look, it was to leave a possible clue about the problem

I play in Spanish, and Civilopedia (before playing): the word "ROUTES" appears (it does NOT appear translated to "RUTAS") that would be the correct translation

regards

 
I repeatedly find places where my information is incomplete. We cannot verify the function setTableText. I can't inspect the object that receives this call, known as CyGInterfaceScreen(string, int), which is crucial because it is the only thing different between the Civilopedia and Sevopedia at least when the Index is concerned. The Index is part of the Sevopedia project; there isn't a Civilopedia index.
Another way my information is incomplete is I can't find where the Index button is placed in the Civilopedia. I can't explain why there is an Index button; I only see the exit, forward, back, and content buttons generated in CvPediaMain.py and its parent class.

I can't explain why the Civilopedia is able to browse anything, because tracing it from pediaShow() out of CvScreensInterface would lead me to believe that it starts in a bad state owing to it calling pediaJump(CvScreenEnums.PEDIA_CONCEPT_AND, 0, False) , which actually does nothing, and in particular, it doesn't do any of these following things that are expected to occur if the pedia is launched on, say, pediaJump(CvScreenEnums.PEDIA_MAIN, 0, False):


In showScreen, self.iCategory becomes 0, unlike in Sevopedia where an attribute with that name starts as -1. self.deleteAllWidgets(), then self.setPediaCommonWidgets().
A configuration series follows, then self.placeLinks(True) is called, and then conditionally there is a call of whichever self.placeXYZ() function corresponds to the value 0 of the CivilopediaPageTypes enum, if that enum is in the list between lines 118 and 148 of CvPediaMain.py. I believe the enum starts on CIVILOPEDIA_PAGE_TECH , so placeTechs() will be called.

placeLinks(True) is something I mostly can't analyze, but it does call self.getScreen().appendListBoxStringNoUpdate() to the object self.LIST_ID for each of the main categories and again with WIDGET_PEDIA_MAIN for their behaviour.

There are calls to some of those screen functions whose definitions we don't have, and at least the functions are called in the same order as in SevoPedia startup - addListBoxGFC(), clearListBoxGFC(), appendListBoxStringNoUpdate(), and updateListBox(). Then setSelectedListBoxStringGFC(self.LIST_ID, 0) . This 0 is a very unsanitary literal, but we can only presume it is safe in this call.

I modified pediaShow() to provide these initial conditions and nothing changed.

The Civilopedia may launch in an unusual state, which can explain why attempting to load Routes data when clicking Cart Path doesn't work. Fixing this would require a lot of love to basically torch the Firaxis enterprise, something I always support but do not have time for. However, explaining why we can't draw Electric Railroad comes down to that inaccessible function, and its receiver, and that's the end of the tech help I know how to provide. It's precisely the same call parameters, with, yes, a possibly different environment, but it would look like only the condition of the receiver matters. And that receiver is some kind of object named CyGInterfaceScreen that is provided by interop with something in the program we don't have access to. All we know is that it is constructed on
CyGInterfaceScreen("PediaMainScreen", CvScreenEnums.PEDIA_CONCEPT_AND) in one case, and
CyGInterfaceScreen("PediaMainScreen", SevoScreenEnums.PEDIA_MAIN) in the other.

:yuck:
---
Have you tried boogieman approaches like shortening the Description key for Electric Railroad, or setting a different button? I have to guess the reasons that this screen interface object might abort is for memory concerns or if something it does takes too long to complete.
 
Top Bottom