Gedemon's Civilization, development thread

No silly questions, the UI will be one of the most challenging part of the mod development as there is a lot of data and not so much place on the screen.

This part especially is a WIP, with the formula introduced in a recent patch still in a testing/development phase

The current formula is quite complex, it's this function ("self" is the plot object)

Code:
function GetOutputPerYield(self)
    if self:IsWater() then
        return PlotOutputFactor[self:GetEraType()]
    else
        return self:GetSize() * self:GetActivityFactor() * PlotOutputFactor[self:GetEraType()]
    end
end

where:
  • PlotOutputFactor is a table that contains different values per era
Code:
PlotOutputFactor     = {
    ["ERA_ANCIENT"]         = 0.50 ,
    ["ERA_CLASSICAL"]         = 0.65 ,
    ["ERA_MEDIEVAL"]         = 0.80 ,
    ["ERA_RENAISSANCE"]     = 1.00 ,
    ["ERA_INDUSTRIAL"]         = 2.00 ,
    ["ERA_MODERN"]             = 3.00 ,
    ["ERA_ATOMIC"]             = 4.00 ,
    ["ERA_INFORMATION"]     = 5.00 ,
}

  • self:GetSize() return the size of the plot based on it's population but not rounded (the screen shows "size 3" which means between 2.50000... and 3.499999...) as by the formula below (where populationPerSizepower is 2.8 as in civ4/5 IIRC)
Code:
function GetSize(self)
    return math.pow(self:GetPopulation()/1000, 1/populationPerSizepower)
end

  • and self:GetActivityFactor() is the function below, where employmentFromResources and employed are real population values. Incidentally it's the ratio that directly gives the Activity Percent shown on your screenshot
Code:
function GetActivityFactor(self)
    local employmentFromResources     = self:GetMaxEmployment()
    local employed                    = self:GetEmployed()
    if employmentFromResources > employed  then
        return (self:GetEmploymentSize(employed) / self:GetEmploymentSize(employmentFromResources))
    else
        return 1
    end
end

self:GetEmploymentSize() is another function that return a size, as shown below, but using a variable pow and factor per era (where for population size we use a fixed pow = 2.8 and fixed factor = 1000)
Code:
function GetEmploymentSize(self, num)
    return GCO.Round(math.pow( num / self:GetRuralEmploymentFactor(), 1  / self:GetRuralEmploymentPow()))
end

Here self:GetRuralEmploymentFactor() and self:GetRuralEmploymentPow() returns the values from the table below, depending on the plot's owner era or the game's average era:
Code:
PlotEmploymentPow        = {
    ["ERA_ANCIENT"]         = 1.80 , -- 1.80 = Max City pop Pow - 1.00 : this way the summation of all worked plots can't be > to the total city population (using pow 2.80) <- but this is obsolete as we use urban population only to determine city size
    ["ERA_CLASSICAL"]         = 1.79 ,
    ["ERA_MEDIEVAL"]         = 1.77 ,
    ["ERA_RENAISSANCE"]     = 1.75 ,
    ["ERA_INDUSTRIAL"]         = 1.60 ,
    ["ERA_MODERN"]             = 1.55 ,
    ["ERA_ATOMIC"]             = 1.52 ,
    ["ERA_INFORMATION"]     = 1.50 ,
}
   
PlotEmploymentFactor     = {
    ["ERA_ANCIENT"]         = 1000 ,
    ["ERA_CLASSICAL"]         = 950 ,
    ["ERA_MEDIEVAL"]         = 900 ,
    ["ERA_RENAISSANCE"]     = 850 ,
    ["ERA_INDUSTRIAL"]         = 700 ,
    ["ERA_MODERN"]             = 600 ,
    ["ERA_ATOMIC"]             = 550 ,
    ["ERA_INFORMATION"]     = 500 ,
}

The same kind of formula is used in cities for employment size, maybe with a few difference, I need to check the code, but the table are as follow:
Code:
CityEmploymentPow     = {
    ["ERA_ANCIENT"]         = 2.00 , --1.00 ,
    ["ERA_CLASSICAL"]         = 2.05 , --1.10 ,
    ["ERA_MEDIEVAL"]         = 2.12 , --1.25 ,
    ["ERA_RENAISSANCE"]     = 2.25 , --1.50 ,
    ["ERA_INDUSTRIAL"]         = 2.65 , --2.20 ,
    ["ERA_MODERN"]             = 2.70 , --2.30 ,
    ["ERA_ATOMIC"]             = 2.75 , --2.50 ,
    ["ERA_INFORMATION"]     = 2.80 , -- 2.8 is max city population
}
   
CityEmploymentFactor     = {
    ["ERA_ANCIENT"]         = 500 ,
    ["ERA_CLASSICAL"]         = 550 ,
    ["ERA_MEDIEVAL"]         = 600 ,
    ["ERA_RENAISSANCE"]     = 650 ,
    ["ERA_INDUSTRIAL"]         = 800 ,
    ["ERA_MODERN"]             = 900 ,
    ["ERA_ATOMIC"]             = 950 ,
    ["ERA_INFORMATION"]     = 1000 ,
}

For an example, in your first screen (the second seems broken, it's not shown on my PC), you should have

Production Factor (OutputPerYield)
=
self:GetSize() * self:GetActivityFactor() * PlotOutputFactor[self:GetEraType()]
=
math.pow(29138/1000, 1/2.8) * (self:GetEmploymentSize(29138) / self:GetEmploymentSize(89254)) * PlotOutputFactor[""ERA_ANCIENT""]
=
math.pow(29138/1000, 1/2.8) * (Round(math.pow( 29138 / 1000, 1 / 1.80) / Round(math.pow( 89254/ 1000, 1 / 1/1.80)) * 0.5
= 3.33 * ( 7 / 12 ) * 0.5
= 0.97125


So I'm unsure on how to show all that in a tooltip :D

(your guess is a strange coincidence BTW)
 
No silly questions, the UI will be one of the most challenging part of the mod development as there is a lot of data and not so much place on the screen.

This part especially is a WIP, with the formula introduced in a recent patch still in a testing/development phase

The current formula is quite complex, it's this function ("self" is the plot object)

Code:
function GetOutputPerYield(self)
    if self:IsWater() then
        return PlotOutputFactor[self:GetEraType()]
    else
        return self:GetSize() * self:GetActivityFactor() * PlotOutputFactor[self:GetEraType()]
    end
end

where:
  • PlotOutputFactor is a table that contains different values per era
Code:
PlotOutputFactor     = {
    ["ERA_ANCIENT"]         = 0.50 ,
    ["ERA_CLASSICAL"]         = 0.65 ,
    ["ERA_MEDIEVAL"]         = 0.80 ,
    ["ERA_RENAISSANCE"]     = 1.00 ,
    ["ERA_INDUSTRIAL"]         = 2.00 ,
    ["ERA_MODERN"]             = 3.00 ,
    ["ERA_ATOMIC"]             = 4.00 ,
    ["ERA_INFORMATION"]     = 5.00 ,
}

  • self:GetSize() return the size of the plot based on it's population but not rounded (the screen shows "size 3" which means between 2.50000... and 3.499999...) as by the formula below (where populationPerSizepower is 2.8 as in civ4/5 IIRC)
Code:
function GetSize(self)
    return math.pow(self:GetPopulation()/1000, 1/populationPerSizepower)
end

  • and self:GetActivityFactor() is the function below, where employmentFromResources and employed are real population values. Incidentally it's the ratio that directly gives the Activity Percent shown on your screenshot
Code:
function GetActivityFactor(self)
    local employmentFromResources     = self:GetMaxEmployment()
    local employed                    = self:GetEmployed()
    if employmentFromResources > employed  then
        return (self:GetEmploymentSize(employed) / self:GetEmploymentSize(employmentFromResources))
    else
        return 1
    end
end

self:GetEmploymentSize() is another function that return a size, as shown below, but using a variable pow and factor per era (where for population size we use a fixed pow = 2.8 and fixed factor = 1000)
Code:
function GetEmploymentSize(self, num)
    return GCO.Round(math.pow( num / self:GetRuralEmploymentFactor(), 1  / self:GetRuralEmploymentPow()))
end

Here self:GetRuralEmploymentFactor() and self:GetRuralEmploymentPow() returns the values from the table below, depending on the plot's owner era or the game's average era:
Code:
PlotEmploymentPow        = {
    ["ERA_ANCIENT"]         = 1.80 , -- 1.80 = Max City pop Pow - 1.00 : this way the summation of all worked plots can't be > to the total city population (using pow 2.80) <- but this is obsolete as we use urban population only to determine city size
    ["ERA_CLASSICAL"]         = 1.79 ,
    ["ERA_MEDIEVAL"]         = 1.77 ,
    ["ERA_RENAISSANCE"]     = 1.75 ,
    ["ERA_INDUSTRIAL"]         = 1.60 ,
    ["ERA_MODERN"]             = 1.55 ,
    ["ERA_ATOMIC"]             = 1.52 ,
    ["ERA_INFORMATION"]     = 1.50 ,
}
  
PlotEmploymentFactor     = {
    ["ERA_ANCIENT"]         = 1000 ,
    ["ERA_CLASSICAL"]         = 950 ,
    ["ERA_MEDIEVAL"]         = 900 ,
    ["ERA_RENAISSANCE"]     = 850 ,
    ["ERA_INDUSTRIAL"]         = 700 ,
    ["ERA_MODERN"]             = 600 ,
    ["ERA_ATOMIC"]             = 550 ,
    ["ERA_INFORMATION"]     = 500 ,
}

The same kind of formula is used in cities for employment size, maybe with a few difference, I need to check the code, but the table are as follow:
Code:
CityEmploymentPow     = {
    ["ERA_ANCIENT"]         = 2.00 , --1.00 ,
    ["ERA_CLASSICAL"]         = 2.05 , --1.10 ,
    ["ERA_MEDIEVAL"]         = 2.12 , --1.25 ,
    ["ERA_RENAISSANCE"]     = 2.25 , --1.50 ,
    ["ERA_INDUSTRIAL"]         = 2.65 , --2.20 ,
    ["ERA_MODERN"]             = 2.70 , --2.30 ,
    ["ERA_ATOMIC"]             = 2.75 , --2.50 ,
    ["ERA_INFORMATION"]     = 2.80 , -- 2.8 is max city population
}
  
CityEmploymentFactor     = {
    ["ERA_ANCIENT"]         = 500 ,
    ["ERA_CLASSICAL"]         = 550 ,
    ["ERA_MEDIEVAL"]         = 600 ,
    ["ERA_RENAISSANCE"]     = 650 ,
    ["ERA_INDUSTRIAL"]         = 800 ,
    ["ERA_MODERN"]             = 900 ,
    ["ERA_ATOMIC"]             = 950 ,
    ["ERA_INFORMATION"]     = 1000 ,
}

For an example, in your first screen (the second seems broken, it's not shown on my PC), you should have

Production Factor (OutputPerYield)
=
self:GetSize() * self:GetActivityFactor() * PlotOutputFactor[self:GetEraType()]
=
math.pow(29138/1000, 1/2.8) * (self:GetEmploymentSize(29138) / self:GetEmploymentSize(89254)) * PlotOutputFactor[""ERA_ANCIENT""]
=
math.pow(29138/1000, 1/2.8) * (Round(math.pow( 29138 / 1000, 1 / 1.80) / Round(math.pow( 89254/ 1000, 1 / 1/1.80)) * 0.5
= 3.33 * ( 7 / 12 ) * 0.5
= 0.97125


So I'm unsure on how to show all that in a tooltip :D

(your guess is a strange coincidence BTW)
Thank you so much for answering my question, sorry if it cost you too much time. Now I understand what the 0.97 and 58.33% mean.

So I presume it will be better to work a high-pop tile like this 29138 tile, which provide 3.33 times output for its size.

But it got modified by 58.33% because 89254 is also a large number.

And if we look at this picture
Spoiler :
5baccd5d23873.jpg

12114 pop is Size 2.4, which provide 2.4 times output for its size.
But what about the max workers? I think it is related to the sum of the resource right?

So if I want to get more material from stone/wood, I should work on a tile which only have stone/wood but few other resource?
 
Max worker are not shown on "free" tiles, because with the current code, as it depend of number of resources, it could indirectly show the player where there are resources it doesn't know yet (like iron)

I'll code something to show the value based on the "local player" known resources for free tiles.

small update
Code:
- bug fix : in some case drafted units used a higher organization level that what they should have access to
 
Max worker are not shown on "free" tiles, because with the current code, as it depend of number of resources, it could indirectly show the player where there are resources it doesn't know yet (like iron)

I'll code something to show the value based on the "local player" known resources for free tiles.

small update
Code:
- bug fix : in some case drafted units used a higher organization level that what they should have access to
Thanks, how about the population already on a tile? I found the tile around where my settler start as high as 10000~20000, while other tiles around it only <5000. Is it intentionly give a higher pop to the start position? If we encourage to settle near a high pop tile, will it be possible to highlight the tile of high pop instead of checking every tile?
 
I do plan to make some new lenses to show population and migration, but I need to learn how to do so first.

Tiles are pre-populated at the beginning of the game, using a semi random value.

MaxPopulation on a plot is based on food yield (1 size per yield) , number of resources related to food on the plot (+1 size x number of resources) , civ6 appeal value (+1 size x per appeal value, so it can be negative) , and fresh water (+2 size)

The minimum MaxPopulation for any plot is size 1 (=1000 pop.)

Initial population on a plot at start is a random value between (MaxPopulation / 4) and (MaxPopulation / 8), after that there is migration from plots to plots each turn.
 
I do plan to make some new lenses to show population and migration, but I need to learn how to do so first.

Tiles are pre-populated at the beginning of the game, using a semi random value.

MaxPopulation on a plot is based on food yield (1 size per yield) , number of resources related to food on the plot (+1 size x number of resources) , civ6 appeal value (+1 size x per appeal value, so it can be negative) , and fresh water (+2 size)

The minimum MaxPopulation for any plot is size 1 (=1000 pop.)

Initial population on a plot at start is a random value between (MaxPopulation / 4) and (MaxPopulation / 8), after that there is migration from plots to plots each turn.
So in this picture, we have 2 food yield, 3 resource, +2 appeal, +2 fresh water, total as 9, and the population is 7146
Spoiler :
5bae180597e89.jpg

While in this picture,we get 2 food, 4 resoure,0 appeal, no fresh water, total as 6, and the pop is only 90
Spoiler :
5bae18059ae3b.jpg


Is it normal to have so a huge gap?

Sorry for one more question. My game will crash/freeze every time when I try to load a autosave. Is it broken? Do I have to save my game by myself?
 
Last edited:
So in this picture, we have 2 food yield, 3 resource, +2 appeal, +2 fresh water, total as 9, and the population is 7146
Spoiler :
5bae180597e89.jpg

While in this picture,we get 2 food, 4 resoure,0 appeal, no fresh water, total as 6, and the pop is only 90
Spoiler :
5bae18059ae3b.jpg


Is it normal to have so a huge gap?

Sorry for one more question. My game will crash/freeze every time when I try to load a autosave. Is it broken? Do I have to save my game by myself?
Yes, first plot is 2 (food yield) + 4 (sheep as food related resource) +2 (appeal) +2 (fresh water) = 10 total

second plot is only 2 as the resources are not food related.

what kind of autosaves, the mod's or the game's ?

the game's wont load correctly, the mod's are not fully safe, there could be desyncs for some units.
 
Yes, first plot is 2 (food yield) + 4 (sheep as food related resource) +2 (appeal) +2 (fresh water) = 10 total

second plot is only 2 as the resources are not food related.

what kind of autosaves, the mod's or the game's ?

the game's wont load correctly, the mod's are not fully safe, there could be desyncs for some units.
If I load the game's autosave, the game crash immediately. If I load the mod's autosave, the game freese and I have to halt the session. I will try to give you the log.

Well it doesn't freeze again. Instead it showed a error window
Spoiler :
5bae4752023d9.jpg
 
Last edited:
Yes, please ignore the desync error reports at the moment, unless they produce a crash or don't goes away after 2-3 turns.

Small update:
Code:
- balance : lower Barbarian units organization level
- bug fix : try to safely auto-save at the beginning and the end of the local player's turn (and save them in the "auto" folder)

The mod's auto-saves are now in the AutoSave menu, let me know if they are stable, TIA
Clipboard-1.jpg

(And never use the game's auto-saves, I can't make them safe to use with the mod)
 
By plaing more the mod, more question come out
1. What does assign a citizen to a specific tile means? I guess it means I want more pop to migrate to this tile to produce more resource that this tile has. Also it means I will get the food/production/gold/culture/science/faith already on this tile, right?

But when I change the tile which citizen work, I lost the resource on the original tile, though it has >40000pop on that, is it normal?

2. I assume we can divide resouce into 2 type
one is basic resource, which directly collected in the map by rural population and can't be used directly, and need to be processed to become other things. Like sheep, cow, rice, copper.
the other is advanced resource, which are produced from basic resource by urban population, and can be used to produce building/unit, like wooden bow, material, iron sword.
When we build a city, it has rural population around it to collect basic resource. When the population grows, the basic resource we can get grow.
So except for encouraging migration, actually it should be of no meaning to assign a citizen to a specific tile? The pop are there in work regardless of assigned a citizen or not
 
Resources are collected on plots that are either worked by the city or improved. The population on other plots work for themselves. It's a way to propose choices to the player instead of a complete automation on resources collection.

Working a plot also raise (a lot) it's value for migration, people will go there faster, giving you a way to colonize/expand territory in specific directions when culture diffusion will be relative to population/migration (last part not coded yet).
 
Resources are collected on plots that are either worked by the city or improved. The population on other plots work for themselves. It's a way to propose choices to the player instead of a complete automation on resources collection.

Working a plot also raise (a lot) it's value for migration, people will go there faster, giving you a way to colonize/expand territory in specific directions when culture diffusion will be relative to population/migration (last part not coded yet).
So if we I have a tile of sheep+hill, and I just want the stone instead of the sheep, I should not improve this tile (avoid low activity) and assign a citizen on it.
Then I will build a a quarry on a high pop hill, so it can provide me stone even though I'm not assigning citizen on it. Then assign a citizen to a low pop hill (attracting pop) and build a quarry on it. Right?

I also suggest to simplified the advanced resource.
Like we just need material to build slinger/warrior/scout, need bronze weapon to build bronze spearman/bronze swordman, and use iron weapon to build iron swordman, pikeman, knight(with war horse).
Dividing into sling/stone axe/wooden stick/bronze spear/bronze sword just makes it too complex and less of value. For example if I don't want so much spearman, the bronze spear just doesn't seem to be a resource for me.
 
The framework allows simplified or more complex equipment trees, it can be done making modmod or directly modifying the mod's files if you want (specifically Buildings.xml and Equipment.xml)

You don't require more than one specific equipment per unit type, but you need different equipment per unit types that are in the same upgrade path.

In the current version there is only one "Melee" upgrade tree which is warrior -> spearman -> swordsman -> longswordsman -> pikeman -> musketman -> ...

Each of this unit need to use a different equipment type of the other for the upgrade mechanism to work, if both swordsman and spearman use "Bronze Weapons" then the mod's code won't know when an unit is a "swordsman" and when it's a "spearman" as they are on the same upgrade path and defined on that path by the same equipment type, so you'll have to use "Bronze Weapons" for "Spearman" and "Iron Weapons" for "Swordsman" (and I suppose "Wood Weapons" and "Stone Weapons" for "Warriors").

Units on different upgrade path (the "melee" line is going to be split *soon* BTW) like knight and swordsman could share the same equipment (say "Iron Weapons"), the code is able to make the difference from the upgrade path (which is defined by the "PromotionClass")

The current equipment list is a WIP anyway, it will be reworked with the new PromotionClass that is drafted here and can be discussed here
 
The framework allows simplified or more complex equipment trees, it can be done making modmod or directly modifying the mod's files if you want (specifically Buildings.xml and Equipment.xml)

You don't require more than one specific equipment per unit type, but you need different equipment per unit types that are in the same upgrade path.

In the current version there is only one "Melee" upgrade tree which is warrior -> spearman -> swordsman -> longswordsman -> pikeman -> musketman -> ...

Each of this unit need to use a different equipment type of the other for the upgrade mechanism to work, if both swordsman and spearman use "Bronze Weapons" then the mod's code won't know when an unit is a "swordsman" and when it's a "spearman" as they are on the same upgrade path and defined on that path by the same equipment type, so you'll have to use "Bronze Weapons" for "Spearman" and "Iron Weapons" for "Swordsman" (and I suppose "Wood Weapons" and "Stone Weapons" for "Warriors").

Units on different upgrade path (the "melee" line is going to be split *soon* BTW) like knight and swordsman could share the same equipment (say "Iron Weapons"), the code is able to make the difference from the upgrade path (which is defined by the "PromotionClass")

The current equipment list is a WIP anyway, it will be reworked with the new PromotionClass that is drafted here and can be discussed here
Sorry that I didn't know spearman and swordman are of the same category, now I fully agree with your idea. Thanks again!
But now what the warrior need is blunt weapon. I guess it refered to both wooden stick and stone axe? Maybe they can be merged into blunt weapon?
Don't know what is the usage of lether or armor now, I will play more and try to discover it.
 
Sorry that I didn't know spearman and swordman are of the same category, now I fully agree with your idea. Thanks again!
But now what the warrior need is blunt weapon. I guess it refered to both wooden stick and stone axe? Maybe they can be merged into blunt weapon?
Don't know what is the usage of lether or armor now, I will play more and try to discover it.

Post number 465 in this thread helps explain about the use of armor. (https://forums.civfanatics.com/thre...velopment-thread.615222/page-24#post-15196317)
 
So my warrior will wear the armor by themselves if I have a butchershop to produce the armor?
When I discover archery, wooden bow become a available advanced resource made by wood. And I found my sling resource decrease continuely at the same time, is it just because it become obsoleted?

Yes, armor produced by the armor shop is automatically distributed to units just like the weapons. I've noticed the slings disappear too, as well as other weapons as the game progresses, and that you can't build certain units at certain points, probably due to obsolescense.
 
Thanks all for the crash & bug reports

Update:
Code:
- bug fix : do not remove to many personnel from an unit FrontLine without disbanding it, else the UpdateFrontLineData function will try to kill the unit and fail at updating the data
- bug fix : override Espionage UI files as they reference Districts removed by the mod
- bug fix : Shipyard can now produce Wooden Hulls
- balance : raise Personnel housed by Military Academy
- balance : do not allow construction of the Recruitment Centre when there is not enough Logistic Support for Melee units
- balance : City Barracks doesn't allow one more drafted unit per turn, Encampment Barracks only allows 2 (was 4)
- balance : a City need a land-path to a plot to claim it
- balance : move Armor Smith to Machinery, only make Plate and Chain Mail armors
- balance : remove Chain Mail armors from the Armorer production list

It may or may not fix some of the reported crashes, let me know in the bug report section.
 
Update
Code:
- add "Uniform" cheap resource to replace armors at Rifling
- add weight to equipment (based on <Desirability>) when determining an unit type from its equipment list, show matching percentage based on each unit's type equipment weight on the unit flag
- tweak all equipment Desirability value to give a higher weight to weapons over armor
- balance : Medieval Horsemen requires armor (any type)
 
Minor issue. Whenever I end the turn I hear a notification(?) sound. I don't know why the sound is played, but it's a bit annoying in the long run. I tried disabling the mod to listen to the unmodded game and with the mod enabled it's definately a louder and sharper noise when ending the turn.

I haven't tested for stability/crashes yet, maybe I will this weekend.
 
Back
Top Bottom