Welcome to Rhye's and Fall of the Greek World (Revived again)

Oh, so this is actually two bugs in one. I've done a few Phoenicia rolls and made the same observations.

The continue button is an obvious miscalculation, RFC does it pretty much the same way except the starting turns are hardcoded there (so there's nothing to miscalculate).

My 2nd example was RFCMarathon, not original RFC (see below the Code for more on that however).

Most mods calculate the button based on RFC's model, which uses Teams. Not sure how that would affect the start date - seems it shouldn't, but it would call into a different routine in the DLL. Even original RFC has some commented-out lines that show Rhye trying variations. However, I'd say it's better to show a button with an auto-turn count of 0 or -1 than stop at 1 with no button. :smoke:

Rhye's CvDawnOfMan button code (for 3000 BC start, excluding the 600 AD delayed start section):

Code:
            iGameTurn = CyGame().getGameTurn()

            iNumAutoPlayTurns = con.tBirth[CyGame().getActiveTeam()]
            iNumTurnsRemaining = iNumAutoPlayTurns - iGameTurn
                       
            #if (iNumTurnsRemaining != self.iTurnsRemaining):                      
            #    self.iTurnsRemaining = iNumTurnsRemaining                              
                        screen = CyGInterfaceScreen( "CvLoadingScreen", self.iScreenID )

                        exponent = 1 + iNumAutoPlayTurns/190
                        if (gc.getPlayer(0).isPlayable()):  #late start condition
                                screen.setBarPercentage("ProgressBar", InfoBarTypes.INFOBAR_STORED, float(math.pow(iGameTurn, exponent)) / float(math.pow(iNumAutoPlayTurns, exponent)))
                        else:
                                screen.setBarPercentage("ProgressBar", InfoBarTypes.INFOBAR_STORED, float(math.pow(iGameTurn-151, exponent)) / float(math.pow(iNumAutoPlayTurns-151, exponent)))
                        screen.setLabel("Text", "", CyTranslator().getText("TXT_KEY_AUTOPLAY_TURNS_REMAINING", (iNumTurnsRemaining,)), CvUtil.FONT_CENTER_JUSTIFY, 530, 445, 0, FontTypes.GAME_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1)
                        if (iNumTurnsRemaining <= 0):  #Rhye
                                screen.show( "Exit" )  #Rhye

Now the weird part is players starting at the wrong turn. The inconsistency here indeed seems to stem from the removal of that setAlive call - if I uncomment it, the game consistently spawns human players after Egypt one turn too late. I've looked into this before, and IIRC this is because setAlive sometimes ends the player's turn for some reason. I'll have to find a workaround for that - spawning human players one turn earlier could work, but there must be some saner way to do it.

RFCMarathon (the example I used in my post) by emryodead is a modmod that adds Epic and Marathon play lengths to otherwise vanilla original RFC; to do so it had to rewrite all the hard-coded turn/date conversions into function calls - and did a pretty good job, with a few minor bugs like the abovementioned starting turn slippage. However the start dates are still set in Consts.py. My suspicion is that random events, possibly the collapse of AI civs during autoplay, cause date and turn calculations to collide in unexpected ways.

I've tried reading setAlive with soft eyes. The only things that jumped out were the call setTurnActive(false), which might advance the turn counter unexpectedly depending on the spawning player's isAlive() status, and (GC.getGameINLINE().getNumGameTurnActive() == 0) OR-sandwiched into the MultiPlayer evaluation; as already mentioned, my c++ foo is very weak. I'll stick to reporting observations. It's less likely to get me in trouble. :rolleyes:
 
My 2nd example was RFCMarathon, not original RFC (see below the Code for more on that however).
Whoops. The tBirth thing tripped me over because it's also present in the original RFC code.

However, I'd say it's better to show a button with an auto-turn count of 0 or -1 than stop at 1 with no button. :smoke:
I believe back when I added the button, I was using a different, even more flawed way to spawn civs, where I checked whether they should start at the end of turns or something. So it actually made sense to wait one extra turn there. Obviously it didn't work all that great (especially with autosaves) because I ended up changing it.

RFCMarathon (the example I used in my post) by emryodead is a modmod that adds Epic and Marathon play lengths to otherwise vanilla original RFC; to do so it had to rewrite all the hard-coded turn/date conversions into function calls - and did a pretty good job, with a few minor bugs like the abovementioned starting turn slippage. However the start dates are still set in Consts.py. My suspicion is that random events, possibly the collapse of AI civs during autoplay, cause date and turn calculations to collide in unexpected ways.
I'm aware of RFCMarathon, though it's not something I've studied extensively. But it might very well have the same bug for the same reason, it uses the same BtS autoplay mechanism after all.

I've tried reading setAlive with soft eyes. The only things that jumped out were the call setTurnActive(false), which might advance the turn counter unexpectedly depending on the spawning player's isAlive() status, and (GC.getGameINLINE().getNumGameTurnActive() == 0) OR-sandwiched into the MultiPlayer evaluation;
setTurnActive sounds familiar, it's probably what I found a month ago when I checked it.

Okay, I started writing this a few hours ago, and since then I think I've found the answer. Basically the problem is, the human player is always at slot 0. Therefore when setAlive is called, all other teams first have to finish their turn, and *then* the game actually starts for the player. The only exception is the first turn, where it is enough to be the first player to be spawned to not skip the turn. Important parts of this seem to be handled by the exe, so apparently the only way to solve this is to either:
- Spawn the player one turn earlier (which is what I've just pushed to the git repo). The easiest way, but it is also an ugly workaround.
- Somehow spawn the player before the turn begins (no clue if/how that'd work).
- Somehow change the player's slot (again, not sure if this is even possible).
 
Okay, I started writing this a few hours ago, and since then I think I've found the answer. Basically the problem is, the human player is always at slot 0. Therefore when setAlive is called, all other teams first have to finish their turn, and *then* the game actually starts for the player. The only exception is the first turn, where it is enough to be the first player to be spawned to not skip the turn. Important parts of this seem to be handled by the exe, so apparently the only way to solve this is to either:
- Spawn the player one turn earlier (which is what I've just pushed to the git repo). The easiest way, but it is also an ugly workaround.
- Somehow spawn the player before the turn begins (no clue if/how that'd work).
- Somehow change the player's slot (again, not sure if this is even possible).

A bit of textual legerdemain can probably mitigate the ugliness. As long as a game that is supposed to start in 2495 BC actually starts in 2495 BC, I don't think most players will care.

The really odd thing if that is the source of the issue, is that it's not consistent - beause some games actually do attempt to start on the correct turn, which is how the button bug drew attenton to this.

It'll be interesting to see how the revision works.
 
Okay I've added 3 goals for Scythia.

<English>Horse Culture</English>
<English>Own 3 horses</English>

<English>Nomadic Way of Life</English>
<English>No foreign culture on the great plains</English>

<English>Destruction of Nineveh</English>
<English>Destroy 3 civilizations</English>

Unfortunately none of them are working! :aargh:

The error for UHV1 is:
Traceback (most recent call last):
File "CvEventInterface", line 23, in onEvent
File "CvEventManager", line 192, in handleEvent
File "CvEventManager", line 372, in onBeginPlayerTurn
File "Victory", line 670, in checkPlayerTurn
AttributeError: 'int' object has no attribute 'countOwnedBonuses'
ERR: Python function onEvent failed, module CvEventInterface

On the plus side, UHV1 does at least change to NO at the time selected.


The error for UHV2 is:
Traceback (most recent call last):
File "CvEventInterface", line 23, in onEvent
File "CvEventManager", line 192, in handleEvent
File "CvEventManager", line 372, in onBeginPlayerTurn
File "Victory", line 662, in checkPlayerTurn
UnboundLocalError: local variable 'bForeignPresence' referenced before assignment
ERR: Python function onEvent failed, module CvEventInterface


As for UHV3, it is just not firing. At the time selected it stays as 'Not Yet' regardless of how many civs have been destroyed.

Any help would be appreciated, I've provided all the code I have added below. :confused:


Code:
        elif civType == iScythia:
            if (iGameTurn == i800BC):
                                        bForeignCulture = False
                                        for x in range(55, 59):
                                                for y in range(55, 59):
                                                        pCurrent = gc.getMap().plot(x,y)
                                                        if (not pCurrent.isWater()):
                                                                for iLoop in range(iNumPlayers): #no minor civs
                                                                        if (iLoop != iScythia):
                                                                                if (pCurrent.getCulture(iLoop) > 0):
                                                                                        bForeignPresence = True
                                                                                        print (iPlayer, "presence in Japan")

                                        print ("bForeignPresence ", bForeignPresence)
                                        if (bForeignPresence == False):
                                                self.setGoal(iScythia, 1, 1)
                                        else:
                                                self.setGoal(iScythia, 1, 0)

            elif (self.getGoal(iScythia, 0) == -1):
                                        if (iGameTurn <= i800BC):
                                                if (iScythia.countOwnedBonuses(bonus('Horse')) + iScythia.getBonusImport(resource('Horse')) >= 1):
                                                        self.setGoal(iScythia, 0, 1)
                                        else:
                                                self.setGoal(iScythia, 0, 0)
            if iGameTurn < i800BC:
                if self.getBabyloniaKilledCivs() >= 1:
                    self.setGoal(iScythia, 2, 1)
            elif iGameTurn == i800BC:
                if self.getBabyloniaKilledCivs() < 1:
                    self.setGoal(iScythia, 2, 0)
                else:
                    self.setGoal(iScythia, 2, 1)



        if attackerType == iScythia:
            if gc.getPlayer(owner).getNumCities() == 0:
                self.setBabyloniaKilledCivs(self.getBabyloniaKilledCivs()+1)
 
I'm on mobile so can't check but I believe iScythia is an integer enum for the civ #, hence the 'int' has no attribute error. You're after something like pScythia.

ETA: e.g pScythia = gc.getPlayer(iScythia)

You're also declaring bForeignCulture then working with bForeignPresence. If there's no foreign presence, the first time it hits bForeignPresence is your print.

As for 3 - the code looks incomplete but I can't be more specific till I get home and put your code in context.

ETA: also, "bonus" and "resource" are not recognised and the syntax of the call to e.g. countOwnedBonuses looks different to what I see in the dll. Where did you get the countOwnedBonuses(bonus('Horse')) code from?
 
Last edited:
OK, I can make UHV2 & UHV3 work for you but UHV1 may need bluepotato's expertise.

Spoiler Revised Code :

Code:
        elif civType == iScythia:
            if (iGameTurn == i800BC):
                bForeignPresence = False
                for x in range(55, 59):
                    for y in range(55, 59):
                        pCurrent = gc.getMap().plot(x,y)
                        if not pCurrent.isWater():
                            for iLoop in range(iNumPlayers): #no minor civs
                                if (iLoop != iScythia):
                                    if (pCurrent.getCulture(iLoop) > 0):
                                        bForeignPresence = True
                                        #print (iLoop, "presence in Scythia")

                #print ("bForeignPresence ", bForeignPresence)
                if (bForeignPresence == False):
                    self.setGoal(iScythia, 1, 1)
                else:
                    self.setGoal(iScythia, 1, 0)

            elif (iGameTurn > i800BC):
                if (self.getGoal(iScythia, 0) == -1):
                    pScythia = gc.getPlayer(iScythia)
                    bonus = gc.getInfoTypeForString("BONUS_HORSE")
                    #if (pScythia.countOwnedBonuses(bonus('Horse')) + pScythia.getBonusImport(resource('Horse')) >= 1):
                    if (pScythia.countOwnedBonuses(bonus) + pScythia.getBonusImport(bonus) >= 1):
                        self.setGoal(iScythia, 0, 1)
                    else:
                        self.setGoal(iScythia, 0, 0)
             
                if (self.getGoal(iScythia, 2) == -1):
                    if self.getBabyloniaKilledCivs() >= 1:
                        self.setGoal(iScythia, 2, 1)
                    else:
                        self.setGoal(iScythia, 2, 0)

#(snip)

    def onCityAcquired(self, owner, attacker, city, bConquest):
        if (not gc.getGame().isVictoryValid(7)): #7 == historical
            return

        iGameTurn = gc.getGame().getGameTurn()
        cityX = city.getX()
        cityY = city.getY()

        ownerType = gc.getPlayer(owner).getCivilizationType()
        attackerType = gc.getPlayer(attacker).getCivilizationType()

        if self.getGoal(iScythia, 0) == -1: # Check if last city
            if attackerType == iScythia:
                if gc.getPlayer(owner).getNumCities() == 0:
                    self.setBabyloniaKilledCivs(self.getBabyloniaKilledCivs()+1)

#(snip)

    def onCityRazed(self, city, conqueror, owner):
        if (not gc.getGame().isVictoryValid(7)): #7 == historical
            return

        if self.getGoal(iScythia, 2) == -1: # Check if last city
            if conqueror == iScythia:
                if gc.getPlayer(owner).getNumCities() == 0:
                    self.setBabyloniaKilledCivs(self.getBabyloniaKilledCivs()+1)

Spoiler Scythia UHVs in 788 BC :
Scythia UHV result.jpg


ETA: The real challenge was not destroying a civ but finding a civ to destroy! I rolled a barbs triumphant game and had to go all the way to Elam to find someone I could kill. Just as well I was testing with a 1 civ requirement instead of the full 3 civs; I don't think I could have reached 3 live civs by 800 BC. :lol:

ETAETA: @Louis the XIV, no, Barb culture doesn't affect UHV 2 (tested and verified) but regular civs (not counting the Independents) do.

ETAETAETA: Belatedly realised UHV3 has no set deadline. UHV3 can be separated from UHV1 by outdenting it to the same level as the if/elif block.
 
Last edited:
I'm on mobile so can't check but I believe iScythia is an integer enum for the civ #, hence the 'int' has no attribute error. You're after something like pScythia.

ETA: e.g pScythia = gc.getPlayer(iScythia)
There's actually a pPlayer variable in the checkPlayerTurn function which can be used here.

OK, I can make UHV2 & UHV3 work for you but UHV1 may need bluepotato's expertise.
Not tested, but I think this should work:
Code:
[after the religion function's definition (line 78)]
def bonus(bonusName):
    return CvUtil.findInfoTypeNum(gc.getBonusInfo, gc.getNumBonusInfos(), "BONUS_" + bonusName.upper())
[...]
[in checkPlayerTurn]
elif self.getGoal(iScythia, 0) == -1:
    if iGameTurn <= i800BC:
        if pPlayer.countOwnedBonuses(bonus('Horse')) + pPlayer.getBonusImport(bonus('Horse')) >= 1:
            self.setGoal(iScythia, 0, 1)
        else:
            self.setGoal(iScythia, 0, 0)
[...]
 
I have an idea for RFCGW. How about a civ in Spain? Usually Spain is mostly empty except for the South so I made some research and found a lot of tribes that existed in Spain in the Classical Age. If @bluepotato agrees to add a Spanish tribe I would be more then willing to create UHV's for it (as best as I can:)), UP, the art for the Civilization, Leaderhead, UU and UB, City list, civilopedia entry, and edit the DLL and recompile it (though I would greatly appreciate it if someone would help me if I fail!) and I would also be happy to edit the 4400 BC map to spawn the Tribe.
It would be an honor to contribute to RFCGW so please let me know if you decide to add a new civ so I can help!
There where many tribes in Iberia, all of them Celtic, so I thought it would be better to have the Celtiberian Tribe represent all of them https://en.wikipedia.org/wiki/Celtiberians
LH: Olyndicus
UU: Eternal Warrior replaces Light Swordsman or Swordsman
UB: Oppida replaces walls
UP: The Power of Stone Works Mastery: All buildings except Wonders cost 20% Less
UHV: Do not let any foreign Civilization control Northern and Central Spain by 1 AD
Conduct 2 Trade Missions with Great Merchants
Build 3 Oppida's, 3 Barracks, and 3 Granaries by 100 BC
Start Year: 1200 BC is when the Celts starting emigrating to Iberia but 300 BC is when most of the tribes started to form
Start City: Numantia
Starting Situation: Depends on what year but if 1200 BC then probably 2 Eternal Warriors, 3 Archers, 2 Settlers, 1 Worker, and 1 Horse Archer
Links: https://en.wikipedia.org/wiki/Celtiberians https://en.wikipedia.org/wiki/First_Celtiberian_War
 
Last edited:
UHV2 should probably be changed to something like "into North Africa" since Carthage could collapse faster than its physically possible for the player to spawn 2 great merchants, I think, but there will almost always be cities in North Africa.

Otherwise I think its a cool idea. Similarly, representing the British celts could be interesting (Boudica was notable enough to make it into the main game after all). I think having more weak civilizations in the west to conquer will also help facilitate an AI Rome's expansion, when so often they end up stuck in Italy
 
UHV2 should probably be changed to something like "into North Africa" since Carthage could collapse faster than its physically possible for the player to spawn 2 great merchants, I think, but there will almost always be cities in North Africa
You're right, anyway I read that the Celtiberians made a lot of trades with the Carthaginians. But I'll change it to just conduct 2 trade missions.
 
I've also considered breaking up the Celts into multiple civs, there's no way they'd naturally settle all their territory without help anyways, so adding the Celtiberians would be a good first step.
Though I'm unsure about their starting date, 300 BC might be somewhat too late, and apparently the Iberian "proto-Celtic" phase ended in the 6th century BC (at least according to this book). So maybe that would be a good time for them to start?

In other news, I think I've finally managed to fix the bug that made the 900 BC scenario unplayable, so now the only thing remaining is actually setting up the scenario with cities, units, etc. This will require a few changes in the code so I can at least specify where the capitals are, but otherwise it should be fairly straightforward so it probably won't take too long.
 
I've also considered breaking up the Celts into multiple civs, there's no way they'd naturally settle all their territory without help anyways, so adding the Celtiberians would be a good first step.
Though I'm unsure about their starting date, 300 BC might be somewhat too late, and apparently the Iberian "proto-Celtic" phase ended in the 6th century BC (at least according to this book). So maybe that would be a good time for them to start?

In other news, I think I've finally managed to fix the bug that made the 900 BC scenario unplayable, so now the only thing remaining is actually setting up the scenario with cities, units, etc. This will require a few changes in the code so I can at least specify where the capitals are, but otherwise it should be fairly straightforward so it probably won't take too long.
Breaking up the Celts into more civs is a not half bad idea. You could have the Gauls, Dacians(I also made a lot of research about them because I had to do a project so I can easily do them), Celtiberians, and the Celts in Scotland and Ireland.
Anyway I read on wikipedia that the Celtiberians fought against the Romans and finally collapsed and came under Roman rule around 70 BC. Of course Wikipedia is not always correct but I think it would be more fun for the Romans to fight with the Celtiberians.
Anyway could you please let me know exactly on your desicion? I don't want to start creating a new flag, button, unit, make research ...etc... for nothing. So please consider it and let me know as soon as possible, especially because you will need to do no work (except the DLL work, I'm a noob at that:undecide:).
EDIT: Oh I thought you said they should end in 600 BC! Now I think you meant they should start in 600 BC! Sorry misunderstanding, yeah I read something about the Celtiberians in 600 BC so that could be a good time for them to start.
 
Oh I thought you said they should end in 600 BC! Now I think you meant they should start in 600 BC! Sorry misunderstanding, yeah I read something about the Celtiberians in 600 BC so that could be a good time for them to start.
Right, I meant specifically this on the page I linked:
> In his view, the use of castros is first seen towards the beginning of the Late Bronze Age, in the 12th century BC, and is then widely adopted [...]. He describes this as a 'proto-Celtic' phase, which is succeeded by three 'Celtic' phases, each lasting about two centuries.
And then it goes on about how they lived in the 'initial Celtic' phase, which began in the 7th-6th centuries BC.

Anyway could you please let me know exactly on your desicion? I don't want to start creating a new flag, button, unit, make research ...etc... for nothing. So please consider it and let me know as soon as possible, especially because you will need to do no work (except the DLL work, I'm a noob at that:undecide:).
I wasn't planning to add new civs for now, but since this is one I wanted to eventually add anyways, and adding new civs doesn't really interfere with anything, you can go ahead.
It certainly isn't about having to work on it, I've tried to make adding new civs as painless as possible (once you know how the system works). You'd have to modify the DLL in two places to add a functioning civ, plus one if you want conditional spawns. I'm more concerned about balance, especially because the AI is just incredibly bad at conquering things. Either way, having something to conquer in Iberia would probably not hurt Rome, at most I'll add some unit spawns for them.
 
Yay:w00t:! I'll start today, I'm working on a map for Spain at the moment but after I finish half of it I'll create some art.
I noticed in RFC DLL's you also have to add a line for the new civ that says its research rate, production rate, etc.. could you please do any DLL changes (except for the UP and Rhyes.cpp)? I don't know how to create WarMaps, Settler Maps, etc..
I will do all the art and XML changes, Python Changes, and after I finish those I'll ask which file contains the UP's so I can create one. Also I will add City Names for the Celtiberians (it's much easier in RFCGW).
So do you agree with the UU, UB, UP, UHV? If you have any other idea for a UHV tell me because the last one isn't that great.
Here are some ideas for Flags and Buttons. Tell me which one is better: https://www.crwflags.com/fotw/images/i/int-celtb.gif http://wiki.battlemaster.org/images/Celtiberia.jpg
 
I noticed in RFC DLL's you also have to add a line for the new civ that says its research rate, production rate, etc.. could you please do any DLL changes (except for the UP and Rhyes.cpp)?
RFGW stores this data in the scenario files, which are simple JSON you can edit in any text editor. Modifiers are the most straightforward to add, you can just copy-paste an existing civ entry and change stuff you want to.
For the other DLL changes, I could make a new git branch where I upload the modified DLL.

I don't know how to create WarMaps, Settler Maps, etc..
I got rid of war maps in 2.0, and there is a settler map editor in the worldbuilder (the one with the settler icon, without a tooltip (no clue why the tooltip is missing)).

which file contains the UP's so I can create one.
Well UPs do happen to be in the DLL. But the proposed one isn't too difficult to implement either, in fact if I remember correctly there is already a similar one.

Also I will add City Names for the Celtiberians (it's much easier in RFCGW).
That's great. Just export the scenario when you're finished and the map file will be generated in the same folder.

So do you agree with the UU, UB, UP, UHV? If you have any other idea for a UHV tell me because the last one isn't that great.
Nothing comes to my mind, but maybe others have some ideas?

Here are some ideas for Flags and Buttons. Tell me which one is better
The first one, I prefer flags without text.
 
Ok, thanks for clearing this with me.
I'll most probably finish tomorrow and when I do I'll upload all the changed files here. The UP is going to be last.
Also I might fail with the UHV so there is a 70% chance I will fail with the UHV.
 
I'll most probably finish tomorrow and when I do I'll upload all the changed files here. The UP is going to be last.
I've made a new branch which already contains their UP in the DLL (as well as other code needed so that it doesn't mess up the civ order). If you used TortoiseGit to get RFGW, you should be able to get it by updating the repository (right click -> git pull) and then selecting the branch as described here.
Also, put the new civ after Etruria in the XML, otherwise some civs will be mixed up.
 
New Pull Request:
Scythia UHVs
Athens UHVs - made easier
Sparta UHVs - made slightly harder
Minor text edit to Sumeria UHVs
 
Back
Top Bottom