The algorithms
for obtaining the textures of the game Caesar III © and the
drawing of the city have been dismantled, the “sweetest” part has remained, which has attracted the “ancient Roman architects” for more than 15 years - the game logic. Using various approaches to the analysis of the game, I stand in your court the result of this small study. I apologize in advance for a great article, but, as they say, you cannot throw out the words from a song. In conclusion, there will be a few words about the fate of the sources recovered from the executable file of the original game.
A bit of historyThe game is written in C, and is available for Windows and Mac. The official release took place in October 1998. Most likely for Windows, the game was compiled in Visual Studio 97, 6 the studio has not yet gained its popularity at that time. In 1999, the game was updated to version 1.0.0.3, compiled already in Visual Studio 6, which was most widely used, and patch 1.1 (c3 1.0.1.0) was later released for English versions of the game.
')
Date compiled: Fri, September 3, 1999, 7:31:17 AM
Linker version: 6.0
Machine type: Intel 386 or later processors and compatible processors
PE format: PE32
Subsystem: The Windows graphical user interface (GUI) subsystem
Min OS: Windows 95
Min OS version : 4.0
Subsystem version: 4.0
File version: 0.0
Also, fans of the game have been modified executable files to run on
high-resolution screens .

The game uses the graphic engine of the second part, there are also screenshots from the intermediate (maybe debug) version, where elements of the old graphic design are visible.
Caesar II

Caesar III (Alpha)
Pay attention to the road, fishing boats and warehouse.
Caesar III (Final)
And now more substantively.To begin with, in the game many variables are rigidly spelled out in the code in the form of “magic numbers”, the given code examples are taken from
the c3_rev directory , the source code is compiled and run in debug mode, you can step through the logic. Judging by the nick, our compatriot, who finished the source code to the working state, deals with the maintenance.
Our gallant localizers, when russified the game, edited the binary code of the executable file, replacing c3.eng with c3.rus, incidentally breaking compatibility with later patches.
Main (recovered) function codeint main(int argc, char* argv[] ) { int result; // eax@2 signed int v5; // [sp+4Ch] [bp-20h]@7 struct tagMSG Msg; // [sp+50h] [bp-1Ch]@21 HINSTANCE hInstance = GetModuleHandle(0); byte_6606BC = 0; if ( fun_loadSettings() ) { if ( fun_readLanguageTextFiles("c3.eng", "c3_mm.eng") ) { fun_loadDefaultNames(); fun_logDebugMessage("OK :Game text loaded.", 0, 0); if ( fun_setupMainWindow(hInstance) ) {} .... //some code } } }
Text resources / LocalizationMost of the text of the game, with the exception of text data for missions, is in files C3.eng / C3_mm.eng
File C3.eng contains descriptions of buildings, events, residents, etc. It consists of a header, 28 bytes long, and an index table, 8000 bytes long. The index table contains offsets, which are the text for the selected index. The algorithm for obtaining text from a localization file is such that in order to get text, for example, for the title of the adviser on education with the index TITLE_ADVISOR_EDUCATION (16), select the 16th element from the array of indices and read the characters before the final 0 by the resulting offset.
Description of the heading and element of the index table struct C3EngHeader { char tag[16]; // int numGroups ; // int numStrings ; // int unknown ; }; struct C3EngIndexEntry { int offset; // int inUse; };
User interfaceThe dimensions of the user interface elements, with the exception of the buttons, are written in the code. Therefore you cannot shuffle the info window or help. First, the window background was drawn, and then the elements associated with it.

Here, for example, the processing of pressing in the scrolbar area int fun_dialogFile_handleScrollbarClick() { signed int result; // eax@2 int v1; // ST60_4@15 int v2; // [sp+4Ch] [bp-10h]@5 int v3; // [sp+50h] [bp-Ch]@13 if ( filelist_numFiles > 12 ) { if ( mouse_isLeftClick ) { v2 = filelist_numFiles - 12; if ( mouseclick_x >= screen_640x480_x + 464 ) { if ( mouseclick_x <= screen_640x480_x + 496 ) { if ( mouseclick_y >= screen_640x480_y + 145 ) { if ( mouseclick_y <= screen_640x480_y + 300 ) { v3 = mouseclick_y - (screen_640x480_y + 145); if ( mouseclick_y - (screen_640x480_y + 145) > 130 ) v3 = 130; v1 = fun_getPercentage(v3, 130); filelist_scrollPosition = fun_adjustWithPercentage(v2, v1); window_redrawRequest = 1; result = 1; } else {result = 0;} }else{result = 0;} }else{result = 0;} }else{result = 0;} }else{result = 0;} }else {result = 0;} return result; }
The buttons in the game have a fixed height and are drawn using three textures, the average texture is repeated to fill the button body. For example, a button in the usual state.

+

+

The windows are drawn according to the following algorithm: the edges of the window are drawn with special textures, the center is filled with a seamless texture

+

+


+

+


+

+
Small details of the huge mechanismThe game consists of a large number of subsystems (availability of water, condition of buildings, education, entertainment, etc.), each of which, upon detailed examination, is very simple, and the description of its functioning fits into several paragraphs. The joint work of these "gears" gives an exciting gameplay with a good balance. It should be noted that among themselves these subsystems practically do not interact (the location of the theater does not affect the neighboring school or market, the doctors do not know anything about the actors passing by). The common point of influence are houses that accumulate the effects of subsystems: the greater their number becomes available to the house, the higher its level. The level of the house in absolute terms is reduced to the amount of taxes paid and the number of available workers.
Routes
The routes of different types of citizens differ, for example, the prefect (engineer )’s route will consist of path A1-A2-A1, even if point A2 is in the prefecture entrance area, after which it will return to the base, while the hairdresser will complete a bypass area, reaching point B2 . The attendants move exclusively along the roads (bridges, gates, barns, northern tiles of warehouses, gardens and territories at the forts). Enemies and wild animals cannot pass through the gate. Merchants and mega-porters can move on the "off-road", but prefer to move on the road to the destination, if possible. Porters cannot walk through gardens and fortified areas.

Buildings have an exit point that may not match the entry point. The appearance priority is shifted down, the input priority is up, there can be a very long way between the entry and exit points.
Below, I gave the maximum length of the routes for residents of the city, switching between the short and long routes occurs under different conditions, I haven’t yet disassembled everything. A trader, for example, includes a long route if there is a barn near the market.
Resident type | Mashrut length is long / short (in tiles) |
Prefect, Engineer | 52/43 |
Actor, Gladiator, Tamer, Tax collector | 43/35 |
Priest, Doctor, Surgeon, Teacher, Trader, Bather, Hairdresser | 35/26 |
The bypass route is calculated before leaving the area. Before starting the selection of the “optimal” route, a map of possible paths from the point of exit of the worker to all sides of the distribution of roads is constructed. Then, each received path is covered by a secret, and the buildings within the worker's reach are polled for the need for its services. For this indicator, select the route at which the services of a worker are more in demand.

For example, the prefect will go to the area with the highest level of fire risk. But the difficulty is that he will not go to small clusters of houses, even if there is a maximum level of fire, and go to a large area in which the level of fire danger is still acceptable. This is because the total level in a large area will exceed this figure in a small area. The same applies to other service workers, as algorithm for calculating the importance of the path is unified for the use of different types of service.
The exception is the behavior of the trader, which when laying the route takes into account the goods on the market. The following image shows possible paths a merchant can take, each intersection increases the number of routes to process. In the end, a white flight will be chosen, since the maximum amount of goods from the market will be sold on it. When the end point of the chosen route is reached by the merchant, if it has no goods left, it will search for the nearest route to the market, and if the goods remain, it will go back along the same route.
House evolutionHomes with a lower level insula (Insula) the size of one tile can be combined with neighbors, then it turns out a house of the same level of size 2x2 tiles. An additional condition for combining houses is the coincidence of the first three bits of pseudo-random numbers from the
byte minimap_info array [26244] , which is used when generating the minimap, so not all tiles of the city could have connected huts.

->

Further, upon reaching a certain level, when the size of the house of the next level is larger than the current one, the neighboring territory is captured.
Medium insula -> Large insula (1 × 1 -> 2 × 2)

->

Medium villa -> Large villa (2 × 2 -> 3 × 3)

->

Medium palace -> Large palace (3 × 3 -> 4 × 4)

->

The following tiles are available for expansion (empty lot, garden, single house below the level or the same level). The expansion of the house is resolved in four directions (north, west, south and east)
City populationThe population in the city is divided by age from 0 to 99 years. Each house contains an array of char peoples [100], which shows how many inhabitants and how old are in this house (the array index corresponds to the age of the inhabitants, the value of the element corresponds to the number of inhabitants of this age). At the beginning of each year, the elements of the array are shifted by one element, thus long-livers are removed and a cell for newborns is added. Called functions that are cheated the possibility of the appearance of children in the house and the natural decline in the population of the house from old age.
Hidden text void fun_gametick_population() { ...
Consumption of services and resourcesHouses consume resources (food, dishes, oil, furniture, wine) and services (religion, health, education, etc.). The consumption of food occurs once a month at the rate of 0.5 food units per inhabitant of the house, the consumption of other resources occurs 2 times a month, 1 unit per house, excluding the number of inhabitants. Consumption of services occurs every day, one 1 unit. service, the house of any level stores no more than 100 units of each service, therefore their constant updating is required. The store of food and resources, on the contrary, depends on the level of the house: the larger the house, the more resusts of different types it can store, in the game the house buys goods from a tradeswoman for the next six months.
Religion




The game has five gods (Ceres, Neptune, Mars, Mercury and Venus). Mood counting algorithm for all is the same. The city's coverage is considered by population, and not by territory, i.e. all temples can stand as anything on the attitude of the gods this will not affect. The mood of the houses that serve the priests of these temples depends on the location of the temples. The percentage of coverage is calculated using the following formula
Base_value = 100 * (500 * number_of oracles + 750 * working_highlights_hams + 1500 * working_large) / number of people.Under the concept of "working", get those temples, where there is at least one employee.
Additional factors affecting the deity relationship.
Festival_ Factor = 12 - max (40, months_from_of the last_Festival_for_this_God)
Factor_khramov = 50. That deity will receive, the number of which temples in the city is maximum, if there are several of them, then this factor is reset to all.
Factor_reference = -25. Get the deity that has the least temples in the city. If there are several such deities, then this factor is reset for everyone.
Venus is not involved in the distribution of bonuses. Probably a bug.
Summary_setting = Baseline + Festival Factor + Temple Factor + Unread Factor.Limit the minimum values of mood, depending on the population of the city.
Population | Minimal mood |
0-99 | 50 |
100-199 | 40 |
200-299 | 40 |
300-399 | thirty |
400-499 | 20 |
400-499 | ten |
> 500 | 0 |
The mood of the godsEvery game day (25 ticks), the mood of each of the gods is calculated. The deity has a current mood and true, with each update the current mood approaches the true one by 1. For example, we somehow displeased Mars and are not trying to fix it, let the current mood of Mars be 100, and the true one - 0. Every day the current mood of the god of war will decrease by 1 unit. until it reaches 0. In the gaming month of 16 days, it turns out that our city of Mars will punish through (100/16), somewhere in half a year of playing time, maybe because there is still a “sacred random” (before which not every Roman God can resist).






Under the spoiler, I described the scoring of anger points (they are displayed as lightning next to the mood of the deity in the window of the religious adviser, who played Caesar will remember)
Hidden text if( god.mood < 50 ) { god.blessing = 0 god.blessingDone = 0 } if(god.mood > 50 ) { god.small_curse = 0 god.smallCurseDone = 0 } god_id = random( 7 ); if( god_id < 5 ) { current_god = romeGods[ god_id ] // (Ceres/Neptune/Mercury/Mars/Venus) if( current_god.mood >= 50 ) current_god.wrathPoints = 0; if( current_god.mood >= 9 and current_god.mood < 10 ) current_god.wrathPoints += 5; if( current_god.mood >= 10 and current_god.mood < 20 ) current_god.wrathPoints += 2; if( current_god.mood >= 20 and current_god.mood < 40 ) current_god.wrathPoints += 1; } current_god.wrathPoints = min( current_god.wrathPoints, 50)
Each game month (16 * 25 = 900 ticks), additional logic is executed that determines the appearance of anger and / or blessings of the gods.
Hidden text if( god_id == [5, 6, 7] ) { // , 40 , current_god = find_least_happy_god(); if( current_god ) { if( current_god.mood > 100 and current_god.blessingDone == 0 ) { current_god.doBlessing() current_god.mood = 50 current_god.blessingDone = 1 } if( current_god.wrathPoints > 20 and current_god.smallCurseDone == 0 ) { current_god.doSmallCurse() current_god.smallCurseDone = 1 current_god.wrathPoints = 0 current_god.mood -= 12 } if( current_god.wrathPoints == 50 and current_god.lastFesivale > 3_months ) { current_god.doWrath() current_god.wrathPoints = 0 current_god.mood -= 30 } } }
Festivals / Mood in the city
There are 3 types of festivals available in the game: small, medium and large. The festival is dedicated to one of the gods, the festival affects the attitude of the deity to the city. Formulas for calculating the cost of the festival are shown in the table.
Type of | Cost of | Wine | Preparation time |
Small | population / 20 + 10 | - | 2 months |
Average | population / 10 + 20 | - | 3 months |
Big | population / 5 + 40 | population / 500 + 1 | 4 months |
In addition to increasing the mood of the deity, to whom the festival is dedicated, after its holding the attitude of citizens to the ruler also improves. For 12 months, you can hold 2 festivals that will bring an increase in mood, the following festivals held will not give a mood increase in the city. The table shows the values by which the mood increases in the city.
Type of | The first | Second |
Small | 7 | 2 |
Average | 9 | 3 |
Big | 12 | five |
FinanceThe maximum debt of the city, at which you can still build something is
-5000 denarii. This condition is checked at every action related to finances.
For example when building a road void fun_drawBuildingGhostRoad() { ...
The annual salary for workers, which you set on the screen of the human resources adviser is 1/10 of the specified value in denarii. The number 30 means the payment of 3 deniers to the employee per year, this is done because of the fact that in the game financial calculations are carried out in whole numbers.

Every month there is a payment of wages to workers, according to a simple formula.
__ = (number of employees at the end of the month) * (_worker) / 10/12This amount is taken from the treasury of the city to nowhere, for example in Tropico the money went into the wallets of the residents, but this is a completely different story.
If the city is in debt, i.e. the amount displayed in the top menu is less than 0, then the city starts paying interest to Rome, a kind of loan.
The interest rate on the loan is 10% and is deducted from the city’s treasury every month.
payment = (-nedeg_v_kazne) * 10/100/12When you reach 5000 debt for the first time, Rome gives a loan (depending on the mission, usually 10,000 days), the second time the amount can also be received, but it is already taken into account as a loan.
Taxes
Every month, houses in the city generate a tax, which depends on the level of the house and the number of people living in it. House tax is collected when a tax collector passes by, at the beginning of a new year the amount for the previous year is burned if it has not been collected. The level of taxes is set in the configuration file c3_model.txt, and the level of complexity in the city is also affected by the level of complexity:
Level of difficulty | Coefficient |
Very easy | 300% |
Easy | 200% |
Fine | 150% |
Complicated | 100% |
Very difficult | 75% |
The final formula for calculating taxes on a house looks like this.
Total Tax (Dn) = (tax_base / 2) * (percentage of the city) / (12 * 100 (Post empireAt the end of the year, the city sends part of the income to Rome, the payment depends on the profit and the number of inhabitants in the city. In the game, profit refers to the difference between income and spending. The tax rate is 25%, if the city is in debt, then the tax is not paid, but the emperor's favor decreases.
Income components | Cost components |
Donations | Building |
Export of goods | Import of goods |
| Loan interest |
| The ruler's salary |
| Rest |
| Salaries |
Also, the minimum value of taxes is determined by the population of the city.
Population | No profit / There is profit |
0-500 | 0/50 |
501-1000 | 0/150 |
1001-2000 | 100/225 |
2001-3000 | 200/300 |
3001-5000 | 200/400 |
5000+ | 200/500 |
Emperor's favor
An important role in the successful completion of the mission is the attitude of the emperor towards the ruler and the ratings of the city. Such parameters as the “profitability of the city” and the fulfillment / ignoring of the emperor's requests have the greatest influence on the mood of the emperor.
Gifts greatly increase the emperor's opinion of you, but their influence is seriously reduced with frequent gifts. When calculating the change of favor, all the gifts made in the last 12 months are taken into account, they are listed in the table.
Gift number | Modest | Dear | Excellent |
one | 3 | five | ten |
2 | one | 3 | five |
3 | 0 | one | 3 |
four | 0 | 0 | one |
5+ | 0 | 0 | 0 |
Fulfilling requests, at a time set by the emperor, gives a certain increase in favor. If you fulfill the request later than the time set by the Caesar, you will receive only half the reward, and if you ignore it, you will lose 8 respects: 3 units will be lost if it is impossible to complete the request within the specified period, 5 more will be removed if the request is ignored within 24 months deadline.
In addition to plot requests and gifts, the renewal of the favor value is performed at the beginning of each year and depends on the following factors:
Base change = -2
Successful payment of the tax = +1 if paid successfully, -3, -5 and -8, if you did not pay one, two or more than two years, respectively.
Salary = +1 if the salary is less than the salary of the current level of the ruler, and -1 for each rank above your level
Events = depends on missions, for example +5 when population reaches 1000 inhabitants
Culture Rating
The culture rating in the game is a collective rating, according to which one can judge the attractiveness of the city. It consists of the level of coverage of the city with theaters, temples, schools, academies and libraries. Indirectly, by the presence of the educational component (the level of culture is more than 30), one can understand that there are well-off citizens in the city.
Cultural Rating = Theatre Rating + Temple Rating + Library Rating + Schools Rating + Academy Rating
The rating of theaters corresponds to the ratio of the capacity of the theaters to the number of residents without regard to their location.
Rating_ of theaters = 500 * number of working_ theaters / population. In accordance with this coverage rating is selected.
Coating | Culture Points |
0-30% | 0 |
31-50% | 3 |
51-70% | eight |
71-85% | 12 |
86-99% | 18 |
100 +% | 25 |


The rating of theaters corresponds to the ratio of the capacity of the temples to the number of residents without regard to their location.
Rating_hams = 150 * Number_small_hams + 300 * Number_small_hams + 500 * Number_Oracle.
As with theaters, the rating value is selected from the table.
Coating | Culture Points |
0-30% | 0 |
31-50% | 3 |
51-70% | 9 |
71-85% | 14 |
86-99% | 22 |
100 +% | thirty |
Education


Schools bring a maximum of 15 culture points, the calculation is made for residents of school age, each school holds 75 students.
Academies add 10 points of culture, the calculation is made for residents of college age, the academy trains 100 students.
Libraries remain 20 points, which are calculated on the total number of residents, one library can serve up to 800 residents.
The dependence of culture points on the level of coverage of the city is shown in the table.
Coating | Schools | Academy | Libraries |
0-30% | 0 | 0 | 9 |
31-50% | one | one | 2 |
51-70% | four | 2 | four |
71-85% | 6 | four | eight |
86-99% | ten | 7 | 14 |
100 +% | 15 | ten | 20 |
Resources and production




The basis of the economy of the game are resources, some resources require processing, so there are simple production chains, for example, the iron mine -> weapon. The resources in the game are inexhaustible, with the exception of fishing places that have a finite number of fish.Wheat - the first resource with which you are introduced to the game. In the central provinces, wheat farms are more efficient than other farms, but this does not work in northern and desert areas. The farms are located on fertile soil, which is shown on the map by yellow shoots. The harvest will be taken to the barn or to the warehouse. Farms, mining buildings and workshops work in a single pattern, every 25 ticks (once a game day), the production progress is updated according to the following formula:The formula for calculating the daily production progress productionRate - 100% numberWorkers - 12 * 16 - * maximumWorkers - progress += 100 * ( productionRate * numberWorkers) / (12 * 16 * maximumWorkers )
At the end of production, a porter is created with a product that delivers it to the nearest storage facility. If it is impossible to deliver the goods, it will still stand near the production. If the porter is busy, and the new product is already produced, then production stops until the porter is released.Storage and Resource Allocation
Two types of storage are involved in the storage and distribution of resources: barns and warehouses, barns store only products and market traders receive goods from barns, warehouses store goods of any type and can sell them to merchants. Storages stop accepting goods if the number of employees is less than half, the storages do not participate in the delivery of goods, except for the special “receive goods” mode, in this case the store begins to receive goods from other storages, so you can create a chain of movement of goods from one map area in the game in another.The combination of resource extraction, processing and marketing of goods turned out to be quite elaborate. A small number of goods does not tire the player with micromanagement, and automating most of the routine activities, such as choosing warehousing and distribution, leaves the ruler room for strategic planning.At this moment I’ll, perhaps, finish the article, such topics as trade between cities and hostilities are overboard, each of them is quite large, and there is still not enough material. Thank you for your attention,ZYAt the end of the article I want to say that fans of the game can certainly add many more moments that I did not find or did not pay attention when restoring the source code of the original game. It was important for me to get a general idea of the game logic, so as not to mess with the balance, so carefully polished by the authors of the original. As for the restored sources, they did not have the patience to bring them to the normal (just to compile) view, but there was a kind person (AntonBaracuda, github.com/AntonBaracuda/opencaesar3/c3_rev ) who completed this really hard work. At the specified address, you will find the source code and the structures and some functions partially separated by files; all this is compiled and run; you can pass the first functions in the debugger.Links(, )CaesarIA: (opensource, c++, SDL)(Window,Linux,Mac,Haiku,Android)