The economy is data, not code
Balancing the game means editing a table and running a simulator, never hunting for constants scattered through the code. What it costs, and what it saves.
The problem with balancing by hunting constants
In a progression game, balancing is the work that never ends. Is the first business too cheap? Does the fifth step take too long to pay for itself? The manager costs the equivalent of how many taps on the ball? Those questions come back every week, and the answer shifts as the rest of the game shifts.
The natural way to write this is the wrong way: scatter the numbers through the code, a baseCost here, a multiplier there, a special case somewhere else. It works until the first time someone asks "why does the fourth business feel worse than the third?", and answering requires reading five files to reconstruct the sum.
Worse: when numbers live in code, testing a tweak means editing code, and editing code to test a tweak is how you end up with a balance nobody understands, made of patches that each fixed a different symptom.
The whole economy in one table
The decision was to pull everything out of the code and into a data file: starting cost of each business, how much the price grows per unit bought, how much each cycle pays, how long the cycle lasts, what the manager costs and where the milestones that multiply output sit. Ten businesses, one record each.
{
"id": "bola-de-meia",
"custoBase": "4",
"crescimento": 1.07,
"rendimento": "1",
"duracao": 3000,
"gerente": { "custo": "1000" },
"marcos": [{ "em": 25, "efeito": "velocidade", "fator": 2 }]
}With that, balancing became editing the table and running the simulator. The simulator walks the whole progression and shows how long it takes to reach each step, how much each line earns and where the curve stalls. None of those questions requires opening the game, and none requires touching code.
The trap of the unquoted value
Notice the money values in that snippet are in quotes. That is not sloppiness, it is a rule, and it exists for a specific and cruel reason.
The last business on the ladder costs around 10^10, and its manager passes 10^12. Numbers like that still fit in a float. But the ladder grows, and the day a value passes 10^308 written without quotes, the JSON reader converts it to Infinity before any validation runs. The file is valid, the game loads, and an entire business now costs infinity.
Validation cannot catch it: by the time it runs, the information has already been destroyed. With the value as text, the number is converted into the game's big-number type, and the file accepts any magnitude without losing a digit.
Validate on load, not on first use
The table is checked the moment the game loads it, not the first time someone reads a field. Milestones out of order, fractional durations, a business with no manager, a repeated identifier: all of it stops right there, with a message naming the bad record.
The alternative, which is the default when nobody decides anything, would be finding out mid-game, in the shape of a strange number on a player's screen.
And here is the rule that caused the most discussion in the project: every validator has to be tested with a knowingly bad case. The worst class of defect in this kind of code was never wrong code: it was a guard that quietly stopped guarding. A validator with a logic error finds no problems, and a validator that finds nothing returns exactly the same answer as a happy one: "all good". That is why the table validator is tested against a dozen deliberately broken tables, each broken in a different way.
What the separation costs
It costs indirection. To understand where a number on screen comes from, you now have to look in two places: the table and the formula that consumes it. That is a real cost, and newcomers to the code feel it.
What it saves is larger. Balancing stopped being about touching the game: it became touching a file that runs nothing. The simulator answers in seconds what would take hours of play to discover. And the same table that feeds the game feeds this site's content pages: the table of the ten businesses is generated from the same data, so it can never drift out of date with the real game.
That last part was not planned. It showed up for free, which is what tends to happen when data is kept apart from rules.
You can also just play.
Play free now