New Grigori Adventurer Spawning Mechanic

Valkrionn

The Hamster King
Joined
May 23, 2008
Messages
14,450
Location
Crestview FL
Normally, I post new features in the Download thread. This time, however, it's a large enough shift that I'd like suggestions on how exactly to balance it. ;)


First, let me describe the basics of the new system: Rather than a chance each turn to spawn an Adventurer, something that is highly random and unpredictable, we now have a counter that increases each turn.

Think of it as a return to the steady, predictable GP system, without the limitation of being unable to use other GPs. ;)


Some details:

Here's the Adventurer Counter formula:
Code:
iGrigoriSpawn = iGrigoriSpawn + ((iNumPalace + iNumMuseums +iNumTaverns + iNumGuilds + iCivicMod) * iGrigoriMod)
iGrigoriSpawn - This is the variable used to keep track of the total.
iNumPalace - Will always be one after you found a city, just used to prevent it from running on the first turn.
iNumMuseums - Number of Museums you own.
iNumTaverns - Number of Taverns.
iNumGuilds - Number of Adventurer's Guilds.
iCivicMod - If you are following Apprenticeship, this is equal to 2. Otherwise, 0.
iGrigoriMod - This is the variable used to increase the cost with each Adventurer. Initially set to 1, it is decreased by 10% each time you spawn an Adventurer.
This does NOT mean by 0.10. Rather, it's a percent... Will decrease like this: 1 -> 0.9 -> 0.81 -> 0.739, etc
Now, this is just what I used to test it. I'm willing to listen to any reasonable suggestions as to how to balance this. ;) I'm hoping to have it well balanced for the first version, rather than needing to rebalance it multiple times.


Edit: One thing I could change easily would be to change the way iGrigoriMod works... Rather than modify the formula itself, I could use it to increase the amount needed to spawn an adventurer directly. So rather than always needing 100, I could increase it to 110, 120, so on. Would have to think on how to show this correctly in the display, though. ;)
 
Let's see.

The first adventurer will come at roughly FfH speeds. You start with 1/100 per turn but education, a top priority tech, will triple that(apprenticeship is an early no brainer) and you can cancel out the slower start with a push from mysticism - with 2 cities and a few hammers you can get to 5/100.

After the first one things kick into really high gear. The second standard GP costs 3 times as many points as the first, but under this new system, in order to triple the cost of an adventurer compared to the first one you need to spawn like 7 of them. Meanwhile iGrigoriSpawn will keep increasing at rates well beyond normal FfH. Each city you get will add 1 more with a museum, and then you hit currency, spam guilds, and double this bonus. With 6 cities and no apprenticeship - a reasonable midgame estimate - you can have 13 points per turn, which gives you quite a steady stream of heroes, something like once every 15 turns if you have already popped 5 of them.

Oh, and you get regular GPs at a normal rate independent of this.

I can't draw a direct comparison to the current random system because I don't know the code and I only just downloaded RfE, so I have no emprical data. (I found a post of yours containing precise figures for the random system, but it's old and from before the system was implemented - the values have probably been revised since.) But it's quite the buff compared to the FfH/FF version, all told.

But the grigori are crap right now, so I'm okay with this, especially because the buff becomes really big around midgame where the grig are terribly deficient at war.
 
Let's see.

The first adventurer will come at roughly FfH speeds. You start with 1/100 per turn but education, a top priority tech, will triple that(apprenticeship is an early no brainer) and you can cancel out the slower start with a push from mysticism - with 2 cities and a few hammers you can get to 5/100.

After the first one things kick into really high gear. The second standard GP costs 3 times as many points as the first, but under this new system, in order to triple the cost of an adventurer compared to the first one you need to spawn like 7 of them. Meanwhile iGrigoriSpawn will keep increasing at rates well beyond normal FfH. Each city you get will add 1 more with a museum, and then you hit currency, spam guilds, and double this bonus. With 6 cities and no apprenticeship - a reasonable midgame estimate - you can have 13 points per turn, which gives you quite a steady stream of heroes, something like once every 15 turns if you have already popped 5 of them.

Oh, and you get regular GPs at a normal rate independent of this.

I can't draw a direct comparison to the current random system because I don't know the code and I only just downloaded RfE, so I have no emprical data. (I found a post of yours containing precise figures for the random system, but it's old and from before the system was implemented - the values have probably been revised since.) But it's quite the buff compared to the FfH/FF version, all told.

But the grigori are crap right now, so I'm okay with this, especially because the buff becomes really big around midgame where the grig are terribly deficient at war.

Well, the values I listed were simply for testing purposes... This is the first global variable I've added using python. :lol:

Although I'm already adding the variables themselves to CvPlayer, as pure python isn't saved if you completely exit Civ.... :mischief:

Anyway. Actual values will likely be lower. I think the Civic/Palace values will stay the same... Others will be reduced in value based on how early/cheap they are. I'm also leaning towards having the mod change the amount required, rather than amount gained... Can display it like this:
GrigoriSpawn / GrigoriMod
GrigoriSpawn would be the total points you possess, as now. GrigoriMod would be rewritten to be the amount of points required. So say you have 48 points, and require 120... Next to the Mana Bar you'll see:
[Adventurer Button Icon] 48 / 120
I think that will be clear enough, yes?

And yes, overall it's a boost from FfH... It might actually be a nerf from the previous system in RifE, depends on how you look at it. On the one hand, currently you have the potential for a large amount early on... On the other, the random number generator can also screw you, giving you nothing. :lol: This system is predictable.
 
Since I wasn't clear at first: Yeah, I like the concept of handling it this way. It makes the mechanic stronger than in base FfH for a civ that desperately needs it, removes from RfE the current random style that makes me hate playing Scions, and is easy enough to display in the UI like you described. I was just mulling over the specifics.

On how exactly the grigmod works: It doesn't really matter balance wise, does it? It does the same thing either way, with only the specific values mattering. I guess if having it increase the cost makes it easier to display, go for it.

If you make museums and guilds less effective, you'll nerf the spawn rate fairly evenly throughout the game, since early empires have apprenticeship to pick up some of the slack and lategame ones have taverns. This strikes me as the best solution if you're going to nerf the mechanism from your original outline, because they still keep the big mid-to-late boost, since costs still scale up pretty gently. That's the most important thing the grig need to get out of this, imo.
 
Since I wasn't clear at first: Yeah, I like the concept of handling it this way. It makes the mechanic stronger than in base FfH for a civ that desperately needs it, removes from RfE the current random style that makes me hate playing Scions, and is easy enough to display in the UI like you described. I was just mulling over the specifics.

Actually, you were very clear. Glad you like the idea. ;)

One thing that's bugged me in your posts, as trivial as it is: The correct acronym is RifE. Not RfE. ;) Only reason I mention it is the name just changed, so I'd like to get people in the habit as quickly as possible. :lol:

On how exactly the grigmod works: It doesn't really matter balance wise, does it? It does the same thing either way, with only the specific values mattering. I guess if having it increase the cost makes it easier to display, go for it.

Actually, it's potentially VERY important. Whereas simply reducing the amount works, it doesn't work well when you get to higher numbers of awakened... While increasing the cap is a much more intuitive mechanic, easily visible, MUCH easier to balance, and all around better. Only reason I didn't go with it originally is I hadn't thought of how to display it... While setting it up, the display was the last thing I did. Was working on it still when I made the thread. :lol:

If you make museums and guilds less effective, you'll nerf the spawn rate fairly evenly throughout the game, since early empires have apprenticeship to pick up some of the slack and lategame ones have taverns. This strikes me as the best solution if you're going to nerf the mechanism from your original outline, because they still keep the big mid-to-late boost, since costs still scale up pretty gently. That's the most important thing the grig need to get out of this, imo.

I agree, seems like the best setup to me too.
 
Alright. The variables are now stored in CvPlayer, in the DLL, so they persist across save games. ;)

I've also changed the system, like discussed above... iGrigoriSpawn is the total of the value of your buildings/civics, and iGrigoriMod is the required amount to spawn. Works nicely. ;)

For modders looking to steal the setup: I used int tags rather than float, so the both values must be modified thusly: iGrigoriSpawn = int(iGrigoriSpawn * 100). When calling it, simply use (pPlayer.getGrigoriSpawn() / 100) to get the correct value. ;)

Aside from that little note, everything is easy to understand and clearly marked in the DLL... Will be posting an updated source in just a few minutes, and if anyone wants the python now I'll upload it. ;)
 
Have you though about linking it to a trait?

As things are, it's not obvious how adventurer spawning works with things like Tolerant. If Grigori got Adventurers as a result of a civ trait it would be obvious.
 
Great idea Valkrionn!!! Really great.
I just yesterday explained to Opera why I do not like current method of spawning adventurers/awakened.
And it can be easily adopted for awakaned, right?
It is dll mostly, right? I really want to get rid of it from python.

Regarding increasing cost, I beg you to go the way that allows more precise setting. While I quite like the asymptotic reduction of points generated, increasing required amount seems like the way to go. More intuitive and easier to link modifiers with predictable results.

Odalrick is right, linking it to trait or even better to civ info would be great for providing info to players.
Civ info I think is better as both adventurer and awakend are very civ specific - no need to add separate trait that does just that.
Maybe a trait that increases the rate though? I.E. for Menec from LENA (and Orbis)

Waiting for the complete code to dig into :)
If you need any help, feel free to ask.
 
Have you though about linking it to a trait?

As things are, it's not obvious how adventurer spawning works with things like Tolerant. If Grigori got Adventurers as a result of a civ trait it would be obvious.

It could be, yes. At the moment everything but storing the variables is done in python. I put those in DLL in order to maintain them when you exit/reload the game.... Eventually I'll probably make two new tags for civs: 'SpecialUnitSpawn' and 'SpawnUnit'. One is a bool, simply turn on/off, other is used to list the type of unit.

Then add some new tags to buildings/events/civics/religions to allow you to modify the amount stored each turn.

Won't be doing any of that until after the patch though. As it is, I was planning on using just python.... The bit of DLL work snuck up on me. :p

Great idea Valkrionn!!! Really great.
I just yesterday explained to Opera why I do not like current method of spawning adventurers/awakened.
And it can be easily adopted for awakaned, right?
It is dll mostly, right? I really want to get rid of it from python.

Regarding increasing cost, I beg you to go the way that allows more precise setting. While I quite like the asymptotic reduction of points generated, increasing required amount seems like the way to go. More intuitive and easier to link modifiers with predictable results.

Odalrick is right, linking it to trait or even better to civ info would be great for providing info to players.
Civ info I think is better as both adventurer and awakend are very civ specific - no need to add separate trait that does just that.
Maybe a trait that increases the rate though? I.E. for Menec from LENA (and Orbis)

Waiting for the complete code to dig into :)
If you need any help, feel free to ask.

Why don't you like awakened spawning? Not planning to change that one myself. :lol:

It's still python that does the actual work... But the spawn code is vastly simplified. Mostly because there's no need for so many modifiers anymore... It's not a random chance, it's a stored variable. ;)

Yeah, I've already gone that route with the costs. Rather than reduce the points you generate, I increase the costs. I did it the other way at first because I wasn't thinking about how I'd display it yet, and was thinking I'd have just the one number... I'll post a screenie of the new display soon.

An entirely DLL-based system is something I want to do, like I mentioned above, but don't have the time before this weekend... When I'm going on a vacation for a week or two with some friends I haven't seen in a while. Essentially, a drunk roadtrip, until we're out of money. :lol: Main reason I want the patch out this week. ;)
 
Perhaps every exploration of a dungeon or whenever the Grigori borders encompass a dungeon or epic lair the number would rise.

That could be interesting....


And one thing I neglected to mention, is that one of the main reasons I want it in python for now is the ease with which it can be balanced. Once we've got it right, it can be moved to the DLL. ;)
 
As promised, here are some screenshots....

Spoiler Full Screen :
Civ4ScreenShot0004.jpg


Spoiler Zoomed In :
Image1-2.jpg



Now I'll post the relevant bits of python... Ahwaric, these just overwrite what should already be in CustomFunctions and MainInterface.

As of now, I'm not using any buildingmods, just the number of buildings... Those will be added back, so it's just commented out. Same goes with the gamespeed adjustment. I'm not sure on whether or not to include a modifier for the AI... Probably should, but I won't drop the human rate to do it. I've also left the original formula in a commented out section, as reference. Using php tags in order to highlight the commented sections.

CustomFunctions.py
PHP:
# Start Grigori Adventurer spawning

    def doTurnGrigori(self, iPlayer):
        pPlayer = gc.getPlayer(iPlayer)
        pCapital = pPlayer.getCapitalCity()
        iAdventurer = gc.getInfoTypeForString('UNIT_ADVENTURER')
        
        iGrigoriSpawn = pPlayer.getGrigoriSpawn()
        iGrigoriMod = pPlayer.getGrigoriMod()
        
        self.doChanceAdventurerSpawn(iPlayer)
        
        if iGrigoriSpawn >= iGrigoriMod:
            spawnUnit = pPlayer.initUnit(iAdventurer, pCapital.getX(), pCapital.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
            pPlayer.changeGrigoriSpawn(0 - iGrigoriSpawn)
            pPlayer.changeGrigoriMod(1000)
   


         
    def doChanceAdventurerSpawn(self, iPlayer):
        if iPlayer == -1:
            pPlayer = gc.getPlayer(gc.getGame().getActivePlayer())
        else:
            pPlayer = gc.getPlayer(iPlayer)

        iGrigoriSpawn = (pPlayer.getGrigoriSpawn() / 100)
            
        if pPlayer.getNumCities() > 0 and pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_GRIGORI'):
        
            iAdventurer = gc.getInfoTypeForString('UNIT_ADVENTURER')
            iAdventurerClass = gc.getInfoTypeForString('UNITCLASS_ADVENTURER')
            iMuseum = gc.getInfoTypeForString('BUILDING_MUSEUM')
            iTavern = gc.getInfoTypeForString('BUILDING_TAVERN_GRIGORI')
            iPalace = gc.getInfoTypeForString('BUILDING_PALACE_GRIGORI')
            iGuild = gc.getInfoTypeForString('BUILDING_ADVENTURERS_GUILD')
            iNumMuseums = pPlayer.countNumBuildings(iMuseum) 
            iNumTaverns = pPlayer.countNumBuildings(iTavern)
            iNumGuilds = pPlayer.countNumBuildings(iGuild)
            iNumPalace = pPlayer.countNumBuildings(iPalace)

# Different buildings give different modifiers.  Aristocracy gives a +66% mod.  (
#            iPalaceMod = iNumPalace 
#            iMuseumMod = iNumMuseums * 0.5
#            iTavernsMod = iNumTaverns * 0.15
#            iGuildsMod = iNumGuilds * 0.25
            iCivicMod = 0.00
            iCivicMult = 1
            if pPlayer.getCivics(gc.getInfoTypeForString('CIVICOPTION_LABOR')) == gc.getInfoTypeForString('CIVIC_APPRENTICESHIP'):
                iCivicMod = 2
                iCivicMult = 1.25

# Modifies the rate based on gamespeed.
#            iSpeedMod = 1
#            estiEnd = CyGame().getEstimateEndTurn()
#            if ( estiEnd >= 1500 ):
#                iSpeedMod = 2.0
#            elif ( estiEnd >= 750 ):
#                iSpeedMod = 1.5
#            elif ( estiEnd >= 500 ):
#                iSpeedMod = 1.0
#            elif ( estiEnd >= 330 ):
#                iSpeedMod = 0.67
#            else:
#                iSpeedMod = iSpeedMod
                

# Difficulty level modifier
#            iHumanmod = 1
#            iAImod = 1
#            if pPlayer.isHuman() == True:
#                iDifficulty = gc.getNumHandicapInfos() + 1 - int(gc.getGame().getHandicapType())
#                iHumanmod = .5 + (iDifficulty * 0.1)
#                iAImod = 1
#            
#            if pPlayer.isHuman() == False:
#                iDifficulty = gc.getNumHandicapInfos() + 1 - int(gc.getGame().getHandicapType())
#                iAImod = .7 + (iDifficulty * 0.1)
#                iHumanmod = 1
                
# default adjustments of gamespeed training are M =2, E = 1.5, N = 1, Q = .67
#            iGrigoriSpawn = round(((iPalaceMod + iMuseumMod + iTavernsMod + iGuildsMod + iCivicMod + 2) * iCivicMult * iGrigoriMod * iHumanmod / iSpeedMod * 0.01 / iAImod),2)

            iGrigoriSpawn = iNumPalace + iNumMuseums +iNumTaverns + iNumGuilds + iCivicMod
            iGrigoriSpawn = int(iGrigoriSpawn * 100)
            pPlayer.changeGrigoriSpawn(iGrigoriSpawn)
            
            return iGrigoriSpawn
# End Grigori
MainInterface.py
Code:
#Adventurer display
elif pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_GRIGORI') and pPlayer.getNumCities() > 0:
			
 #figuring spawn chance

	fGrigoriSpawn = (pPlayer.getGrigoriSpawn() / 100)
	fGrigoriMod = (pPlayer.getGrigoriMod() / 100)
#/figuring spawn chance
	if fGrigoriSpawn > 0:

		SRstr = u"<font=2i>%s</font>" %(str(" ") + str(fGrigoriSpawn) + str(" / ") + str(fGrigoriMod) + str(" "))
		screen.setImageButton("Adventurerchance", "Art/Interface/Buttons/Units/Adventurer.dds", 182, 7, 16, 16, WidgetTypes.WIDGET_GENERAL, -1, -1 )
		screen.setText( "SRText", "Background", SRstr, CvUtil.FONT_LEFT_JUSTIFY, 194, 5, 0.5, FontTypes.GAME_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1 )
		screen.setHitTest( "SRText", HitTestTypes.HITTEST_NOHIT )
	else:
		screen.hide( "Adventurerchance" )
		screen.hide( "SRText" )
#/Adventurer display
 
Interesting. I suppose that in order to do the Meritocrat Trait that I had planned for Goodreau, I would need to add a new tag iLeaderMod = 0 or x1.5?
 
Would be easy to setup like the Spiderkin trait for the Archos.

Code:
fMeritocrat = 1
if pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_MERITOCRAT')):
	fMeritocrat = 1.30

Then change add it to the formula like so:

Code:
 iGrigoriSpawn = ((iNumPalace + iNumMuseums +iNumTaverns + iNumGuilds + iCivicMod) * fMeritocrat)

Alternatively, you could make it additive....

Code:
iMeritocrat = 1
if pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_MERITOCRAT')):
	iMeritocrat = 3

Code:
 iGrigoriSpawn = (iNumPalace + iNumMuseums +iNumTaverns + iNumGuilds + iCivicMod + iMeritocrat)

The first method has a smaller effect early on, with a higher effect later. The second method has a higher effect early, less effect later. Or you can do a mix, and balance it out. ;)


Once it's all in the DLL I'll make sure to allow for traits to modify it.
 
looks promising :goodjob:

if you write it into the DLL you might want to modify it so the whole mechanic can be unlocked not just by civ, but also by trait or tech or similar things.
 
Oh, I'll be sure to make it widely usable. I may not have plans for using it a certain way, but someone else may come up with something good. ;)

Tentative Formula:

Code:
iGrigoriSpawn = round(((iPalaceMod + iMuseumsMod +iTavernsMod + iGuildsMod + iCivicMod) * iCivicMult * iAImod / iSpeedMod), 2)
iGrigoriSpawn = int(iGrigoriSpawn * 100)
pPlayer.changeGrigoriSpawn(iGrigoriSpawn)


  • iPalaceMod - Number of palaces.
    • ALWAYS one, after you settle your first city... Makes sure the screen doesn't try to update before anything exists to check. ;) This is the base amount added each turn.
  • iMuseumsMod - Number of Museums, multiplied by 0.33
    • As the first Adventurer-modifying building available, effects are low. Keep in mind it's relatively cheap... Will be spamming these in all of your cities. ;) Need three to increase the rate by a whole number.
  • iGuildsMod - Number of Adventurer Guilds, multiplied by 0.5
    • Second available building. Slightly higher effect. Need two to increase the rate by a whole number.
  • iTavernsMod - Number of Taverns
    • This one should be your best friend. One by itself will increase the rate a whole number.
  • iCivicMod - Depends on Civics.
    • Currently, 0 naturally and 2 if following Apprenticeship. Could be expanded to other civics as well.
  • iCivicMult - Same as above.
    • 1 naturally, 1.25 if following Apprenticeship.
  • iAImod - Flat value of 1.5
    • Essentially gives the AI half again as many adventurers as a human player. They never use them WELL, so having lots of them should help. ;)
  • iSpeedMod - Based on gamespeed. Keep in mind the value is divided by this number... Higher = Slower.
    • Marathon - 2
    • Epic - 1.5
    • Normal - 1
    • Quick - 0.67

These values are put into the formula, the result is rounded to two decimal places, the result of THAT is multiplied by 100 and converted to an int... Allows it to be stored properly. That value is then called and compared to the amount needed, in the following formula...

Code:
if iGrigoriSpawn >= iGrigoriMod:
    spawnUnit = pPlayer.initUnit(iAdventurer, pCapital.getX(), pCapital.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
    pPlayer.changeGrigoriSpawn(0 - iGrigoriSpawn)
    pPlayer.changeGrigoriMod(2000)

iGrigoriSpawn is the value the last formula gave. iGrigoriMod is the amount needed. If the first is greater than or equal to the second, the following things happen:

  • Adventurer is spawned in the Capital.
  • GrigoriSpawn is set to 0. Used a 'change' function... Easier to add/subtract the amount stored, more difficult to reset. Ended up 'changing' the value by zero minus itself... Which results in a new value of 0.
  • GrigoriMod is increased by 2000. Keep in mind that the values stored are 100 times as high as those displayed/used... Made an int to store them in, as that's what I'm used to. :lol: Increasing the variable by 2000 has the result of increasing the cap by 20. I feel that's a reasonable increases... Doubles in cost after your fifth adventurer, but by then enough time has passed that you're earning 2-3 times the amount of points.



All of these values are still subject to change, but I'm reasonably happy with it.
 
Slight change to the second formula... Bolded the difference.

Code:
if iGrigoriSpawn >= iGrigoriMod:
    spawnUnit = pPlayer.initUnit(iAdventurer, pCapital.getX(), pCapital.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
    pPlayer.changeGrigoriSpawn(0 - [B]iGrigoriMod[/B])
    pPlayer.changeGrigoriMod(2000)

Realized that due to the way the code is run, often times you'll get the adventurer and have the counter reset the turn AFTER you reach the amount needed. Rather than wipe GrigoriSpawn, I now reduce it by the current cap... Allows you to maintain any extra you accrued. ;)


Now, for a screenshot of the finished display.... It shows the correct, decimal amount, no major rounding, and then displays the cap. I'm satisfied with it... Easy to read, out of the way unless you need it.

Two drawbacks to it's placing.... While not immediately obvious, it is in fact part of the Mana display widget. This means if you close the mana bar, the Adventurer display will also close. The background also makes it difficult to make out the Adventurer icon. I can live with both of those hiccups, though. ;)

Original, unmagnified image:
AdventurerDisplayOriginal.jpg


Spoiler 3x Zoom :
AdventurerDisplay.jpg
 
Back
Top Bottom