Mechanics

How the original Emperor runs

Emperor has no open-source engine, so its inner workings have been a blank. Yongle, a display layer that hooks the running game, has had to learn how the loop, the clock, the screen modes and the scroll work. This page gathers what that tells us.

Applies to Emperor

Three clocks

The game does not run drawing, simulation and scrolling on one beat. Frames are presented to the screen at most every 50 milliseconds, about 20 a second, unless something forces one, such as a pressed button, a message or a screen change. The simulation has its own timer. Scrolling has a third.

The simulation timer is driven by the game speed, which runs from 10 to 100. The interval between simulation ticks comes from a table indexed by (100 - speed) / 10, with 2 milliseconds added. Scrolling moves one step, a tile width plus 2 pixels sideways or 4 half rows up and down, every ((100 - scroll speed) / 10) x 12 + 2 milliseconds, and the scroll speed also runs from 10 to 100.

Two behaviours follow. The simulation pauses while the view is scrolling. And 100 percent speed is not a fixed pace: it runs as fast as the computer can draw, which is why a large city on a big screen runs slower than a small one at the same setting.

Three screen modes

The game knows 640 by 480, 800 by 600 and 1024 by 768, stored as a mode number in Emperor.inf. About twenty places in the code choose between an 800 layout and a 1024 layout with a width comparison and do nothing for any other width. That is why the interface does not simply stretch, and why the sidebar and top bar need their own handling at other sizes. The front-end pictures are fixed 1024 by 768 frames.

Named in the hook layer

Emperor.exe 1.0.1.0, image base 0x400000, no relocations. The names are Yongle's; the original has no symbols.

game_main - 0x4754F0
WinMain.
game_loop_step - 0x475B00
One main-loop iteration that produces a frame.
sim_tick - 0x5371A0
One simulation tick.
screen_present - 0x52BE40
Frame presentation, with the 50 millisecond limit.
screen_mode_get_size - 0x52B910
Mode 1, 2 or 3 to a screen size.
viewport_init - 0x469820 and city_render - 0x46A220
The city view and its drawing.
scroll_get_direction - 0x52B310 and scroll_step_due - 0x53A210
Edge and arrow-key scrolling, and the scroll timer.

Sources