Now that most of spell modding is complete (at least the important parts), might as well do this.
I've finished the production script for the time being, please check and confirm it looks correct. It seems to be accurate in the game but I haven't tested every single possible spell effect or modifier and there might be typos. The more people read it, the better our chance of having no bugs.
Instead of adding a new "leftovers" line, I added the rounding extras to the Terrain line. The total percentage variable is 1 = 0.5% because Omniscient uses half percentages.
Code:
: INPUT CityID, the city being processed
WORKERS, the number of workers in the city
FARMERS, the number of farmers in the city
PRODPER, the amount of percentage production bonus from terrain
Output - None.
Use the AddResLine command to add production to the total and as an individual line in the detailed view on the UI.
:
ADDRESLINE "Workers", (2*WORKERS);
RACE=CITYRACE(CITYID);
IF RACE=RCDwarf THEN {
ADDRESLINE "Dwarven Workers", WORKERS;
}
IF RACE=RCKlackon THEN {
ADDRESLINE "Klackon Workers", WORKERS;
}
I=%I((FARMERS+1)/2);
ADDRESLINE "Farmers",I;
If ISBUILT(CITYID,BSawmill) THEN {
ADDRESLINE "Sawmill",6;
}
If ISBUILT(CITYID,BSmithy) THEN {
ADDRESLINE "Smithy",2;
}
If ISBUILT(CITYID,BStables) THEN {
ADDRESLINE "Stables",2;
}
BASEPROD=SUMRESLINES();
IF CITYENCHANT(CITYID,CEDrought)=-1 THEN {
PPTOTAL=PRODPER*2;
W=CITYOWNER(CITYID);
IF RETORT(W,Omniscient) THEN {
IF BOOKS(W,Death)>0 THEN {
PP=((BOOKS(W,Death)-1)*7)+32;
ADDRESLINE "Omniscient", %I((BASEPROD * PP) /200);
PPTOTAL=PPTOTAL + PP;
}
}
If ISBUILT(CITYID,BForesterGuild) THEN {
ADDRESLINE "Forester's Guild",%I((BASEPROD * 10) /100);
PPTOTAL=PPTOTAL + 20;
}
If ISBUILT(CITYID,BMinerGuild) THEN {
ADDRESLINE "Miner's Guild",%I((BASEPROD * 25) /100);
PPTOTAL=PPTOTAL + 50;
}
If ISBUILT(CITYID,BMechaGuild) THEN {
ADDRESLINE "Mechanician's Guild",%I((BASEPROD * 35) /100);
PPTOTAL=PPTOTAL + 70;
}
IF CITYENCHANT(CITYID,CEInspirations)>-1 THEN {
ADDRESLINE "Inspiratons", BASEPROD;
PPTOTAL=PPTOTAL + 200;
}
: Test enchantment Tower of Opression
IF CITYENCHANT(CITYID,28)>-1 THEN {
ADDRESLINE "Tower of Oppression", %I (BASEPROD/2);
PPTOTAL=PPTOTAL + 100;
}
:
: Dump anything lost by fractions rounded down into the terrain modifier. :
TER=(%I((BASEPROD*(PPTOTAL+200))/200))-SUMRESLINES();
ADDRESLINE "Terrain", TER;
}
I'll probably do the gold next.
As far as I remember, power has multiplicative modifiers instead of additive percentages so there is nothing to do there. Research pretty much has no modifiers at all except Omniscient.
: Input CITYID = the city being calculated.
ROADBONUS = Total road bonus percentage
TERRAINGOLD = Total gold gained from terrain
BASEGOLD = Base gold from taxes. Equals the tax rate percentage from the tax table multiplied by the total nonrebel population.
Output - None.
Use the AddResLine command to add produced gold to the total and as an individual line in the detailed view on the UI.
:
TRADE=0;
BASEORE=0;
RACE=CITYRACE(CITYID);
IF RACE=RCNomad THEN { TRADE=50; }
TRADE=TRADE+ROADBONUS+TERRAINGOLD;
W=CITYOWNER(CityID);
POP=POPUNITS(CITYID);
IF TRADE>3*POP THEN { TRADE=3*POP; }
if RACE=RCDwarf THEN { BASEGOLD=BASEGOLD + (%I(BASEGOLD/2)); }
ADDRESLINE "Taxes",BASEGOLD;
If ISBUILT(CITYID,BMarketplace) THEN {
ADDRESLINE "Marketplace",8;
:if HASGLOBAL(W,40) THEN { ADDRESLINE "Market Mastery",8 }:
}
I=2*OREINRANGE(cityID,OreSilver);
ADDRESLINE "Silver Ore", I
BASEORE=BASEORE+I;
I=4*OREINRANGE(cityID,OreGold);
ADDRESLINE "Gold Ore", I
BASEORE=BASEORE+I;
I=6*OREINRANGE(cityID,OreGems);
ADDRESLINE "Gems", I
BASEORE=BASEORE+I;
IF ISBUILT(CITYID,BMinerGuild) THEN {
I=%I(BASEORE/2);
ADDRESLINE "Miner's Guild", I;
}
if RACE=RCDwarf THEN {
ADDRESLINE "Dwarven Miners", BASEORE;
}
BASEGOLD=SUMRESLINES()
PGTOTAL= TRADE*2;
if ISBUILT(CITYID,BBank) THEN {
ADDRESLINE "Bank", %I((BASEGOLD * 30) /100)
PGTOTAL=PGTOTAL + 60;
}
if ISBUILT(CITYID,BMerchantGuild) THEN {
ADDRESLINE "Merchant's Guild", %I((BASEGOLD * 40) /100)
PGTOTAL=PGTOTAL + 80;
}
IF CITYENCHANT(CityID,CEProsperity)>-1 THEN {
ADDRESLINE "Prosperity", %I((BASEGOLD * 77) /100)
PGTOTAL=PGTOTAL + 154;
}
IF RETORT(W,Omniscient) THEN {
IF BOOKS(W,Life)>0 THEN {
GP=((BOOKS(W,Life)-1)*7)+32;
ADDRESLINE "Omniscient", %I((BASEGOLD * GP) /200)
PGTOTAL=PGTOTAL + GP;
}
}
: Dump anything lost by fractions rounded down into the trade modifier. :
TRAD=(%I((BASEGOLD*(PGTOTAL+200))/200))-SUMRESLINES();
ADDRESLINE "Trade Bonus "+STRS(TRADE)+"%", TRAD;
Here is the gold script. This one adds the rounding fractions to the "Trade" line.
Thanks for working this.
I started a new game on v1.04.05 2022-08-02.
My understanding is that these codes you posted here are already implemented and used by default. So no manual file change is needed. I checked the EcoProd.CAS file in the new install folder and it appears to be identical to your posted code here.
Immediately at start my home city does not produce correct logic. My 1st worker produces 3 hammers. 2nd worker produces 1 hammer. This is specifically what I was trying to fix with my earlier proposal.
See B110.sav file attached.
City production bonus: 10%
2 Farmers. 2 citizens to be assigned as farmers or workers. Smithy, Sawmill. Omniscient with 1 death book: +16% production bonus. Nomad.
Hammer production breaks down as below.
If 0 workers then
Farmers: 2
Sawmill: 6
Smithy: 2
Omniscient: 1
Terrain:1
Total: 12
If 1 worker then
Workers: 2
Farmers: 2
Sawmill: 6
Smithy: 2
Omniscient: 1
Terrain: 2
Total: 15
If 2 workers then
Workers: 4
Farmers: 1
Sawmill: 6
Smithy: 2
Omniscient: 2
Terrain: 1
Total: 16
Using my math I proposed earlier it should be as follows.
If 0 workers then
Farmers: 4*0.5=2
Sawmill: 6
Smithy: 2
Omniscient: 0.16*(2+6+2)=1.6
Terrain: 0.1*(2+6+2)=1
Total: Round(2+6+2+1.6+1)=Round(12.6)=13
If 1 worker then
Workers: 1*2=2
Farmers: 3*0.5=1.5
Sawmill: 6
Smithy: 2
Omniscient: 0.16*(2+1.5+6+2)=1.84
Terrain: 0.1*(2+1.5+6+2)=1.15
Total: Round(2+1.5+6+2+1.84+1.15)=Round(14.49)=14
If 2 workers then
Workers: 2*2=4
Farmers: 2*0.5=1
Sawmill: 6
Smithy: 2
Omniscient: 0.16*(4+1+6+2)=2.08
Terrain: 0.1*(4+1+6+2)=1.3
Total: Round(4+1+6+2+2.08+1.3)=Round(16.38)=16
If you don’t like Round, Floor at the very end would work equally well.
The system does not support half of a production on any line.
So Farmers are rounded up to a whole production and btw this is an important game mechanic that allows the city with only 1 farmer and no buildings to have 1 production instead of 0.
Sorry but I can't do anything about that, if you want to change how Farmers work, you have to edit your .CAS file to make it happen.
(September 27th, 2022, 03:17)Seravy Wrote: The system does not support half of a production on any line.
So Farmers are rounded up to a whole production and btw this is an important game mechanic that allows the city with only 1 farmer and no buildings to have 1 production instead of 0.
Sorry but I can't do anything about that, if you want to change how Farmers work, you have to edit your .CAS file to make it happen.
I understand that the system does not allow half production on any line. My point I made repeatedly was to have a smooth math. So the total rounding would be always <1. Although you agreed to implement a version that would do that, the current version does not achieve this objective. There are numerous ways to do the math and code that does not break the current rules.
My example above was the math. Not the code. Again, I don’t want to change how Farmers work. I want a rounding that is always less than 1 so no jumps in total production output from 1 to 6 and then back to 1 again with individual farmer to worker change as in the past. In the current version this seems to be tamed to 1 to 4 and back to 1, but still >1 rounding.
And I already made my own .CAS file a year ago. I even sent it to you. I am trying to help the community. My version works fine already.
B112. See B112.sav. City 01Apr. Toggle Farmers to worker to see production output go up by 4 then 1 then 4 again. Same (big) problem as before. Excessive inconsistent rounding encouraging micromanagement.
And if city production must be >=1 then simply take the ceiling, not the floor.
So if I understand correctly, you want these changes?
Code:
I=%I((FARMERS+1)/2);
ADDRESLINE "Farmers",I;
becomes
Z=0;
I=%I(FARMERS/2);
ADDRESLINE "Farmers",I;
IF %F(FARMERS/2)>0 THEN { Z=1; }
---------------------------------
BASEPROD=SUMRESLINES();
becomes
BASEPROD=SUMRESLINES()+ (Z/2);
and everything else stays the same?
Wouldn't it be way too confusing for players if the half production from the farmer is added to the terrain bonus even though it's not rounding a percentage bonus but is base production itself? I'm not too happy about that. But I guess we've already went into that direction with the previous update so might as well? What does everyone else think about this?
(September 30th, 2022, 15:18)Seravy Wrote: So if I understand correctly, you want these changes?
Code:
I=%I((FARMERS+1)/2);
ADDRESLINE "Farmers",I;
becomes
Z=0;
I=%I(FARMERS/2);
ADDRESLINE "Farmers",I;
IF %F(FARMERS/2)>0 THEN { Z=1; }
---------------------------------
BASEPROD=SUMRESLINES();
becomes
BASEPROD=SUMRESLINES()+ (Z/2);
and everything else stays the same?
Wouldn't it be way too confusing for players if the half production from the farmer is added to the terrain bonus even though it's not rounding a percentage bonus but is base production itself? I'm not too happy about that. But I guess we've already went into that direction with the previous update so might as well? What does everyone else think about this?
No, because that gave me syntax error.
I changed
BASEPROD=SUMRESLINES()+ (Z/2);
to
BASEPROD=(SUMRESLINES()+Z/2);
That worked for my test case city. It lowered the rounding error. 1 to 4 jump is now 2 to 4 jump. But it still has >1 rounding error. More work is needed.
If the true math value is between x and x+1 for each farmer to worker change, then the individual workers always need to output either x or x+1 and they cycle in almost uniform intervals. x is a natural number.
I fight for the Total of <1 rounding error here that would apply to all cases. How you break it down line by line to communicate the individual productions from the various source to players is up to you. You chose to make the single rounding error wrapped into Terrain line. That line could be confusing to players due to all rounding errors would be there and not communicated why and how. Everything else should be simple, crystal clear, and easy to understand by the players. I can live with that. But I prefer your earlier proposal for a remainder line. That would be clearer, but would distract from the game immersion and becomes a math topic and not a game topic. Overall, I am OK with either of these options. Pros and cons for each and I see this as cosmetics.
I made changes to my EcoProd.cas file. Copy it into the Data folder and overwrite the old one if want to try it.
So far it worked perfectly for all test cases, but it will need additions later, such as Inspirations. Currently it has a Rounding correction line that explains the amount of rounding error for each case. For now, I recommend using this to look for possible bugs. Later, I can easily wrap into the Terrain to hide this fact from users if that is less confusing. I also attached my Excel file that has all the math and the computational formulas for production calculation. The math, the Excel formulas and the game output cell by cell should match perfectly for each case. If not, please send me bug report with save file.
This Excel file can be also used to predict the future productions. You are only supposed to change values in Green. And copy over chunks to generate new values for more cities. Add and remove columns as needed to match the number of non-rebel citizens in each of your cities. I have a few example cities there from my last game.
Updated EcoProd.cas file is attached to match the 1.05.04 version of Caster of Magic for Windows game. I stand by my earlier opinion that this solution is better due to the total production rounding error is always <1 for each town. Otherwise you may have rounding error as high as 4 and it is annoying and not intuitive when in a town Worker1 produces only 1 hammer, Worker2 produces 5 hammers then Worker3 produces 1 hammer, etc. In my version all workers produce the exact same number of hammers unique to the given town or just 1 more than the other workers.