Since I have not progressed far in the recent weeks (the current events put me out of mood) I can at least document some bits before I forget them completely. In this post I’d like to outline the overall game engine design.
Essentially this is a basic game engine of its era: it has some global objects that store and manage lists of certain things plus the main engine object providing a lot of functionality both for the hard-coded logic and the hard-coded logic in loadable room modules (such modules provide an interface for creating a room object with a dozen possible functions that may be called on certain events and invoke some engine functions).
Main loop looks like this:
- calculate the number of milliseconds since the last run of this loop;
- update registered timer events (e.g. for spell effects) and invoke a corresponding callback function if some timer expires;
- update possible messages or spoken lines;
- (in case this would be a network game it would receive and handle events from other players)
- play the bits of audio (background music, effects, speech);
- load new room if needed;
- check key press events for main window;
- update room lighting if needed;
- handle key press events for the optional sub-windows (e.g. inventory window, death screen and so on);
- update map or room view, the latter also contains code for printing debug information like hero position and orientation or memory usage;
- and finally handle mouse and draw GUI part (inventory, health/stamina/magic status and so on).
I described how sub-windows work in one of the previous posts so I’m not going to repeat it here. It’s trivial anyway and the way in which they are constructed is more interesting.
Scene drawing in the general case involves the following steps:
- drawing the cylindrical background panorama;
- preparing to render various objects contained in the scene;
- updating scene for the possible night effects (darker image plus blinking stars where applicable);
- rendering 2D sprites (e.g. animated water) and 3D objects (e.g. hero, enemies, some movable parts of scenery);
- and finally draw various effects.
Effects can be split into three categories: particles (small balls that appear when e.g. an attack spell hits something), auras (semi-transparent glow around the hero that hints on some spell effect) and warps (distorting the image, usually for teleporting). Spells are rendered as ordinary 3D objects even if they often look like a ball. Actually hero, NPCs, some stationary objects and projectiles are treated as the same kind of 3D objects (just using C++ base class inheritance).
Since the game was originally meant to be a multi-player one, most of the interactions are passed as messages from one object to another (yes, somewhat similar to the original SCI language and Smalltalk-80 that inspired it). These messages can be sent via network to other players as well (all that functionality is there, just disabled and the required network DLL is missing). Since those messages are essentially 32-bit message type and type-dependent amount of information, it’s rather annoying to parse them—especially since there are dozens of them. And engine-based cutscenes (e.g. Elsa running to you during fight with the Hydra) or even shorter animated scenes seem to be implemented by the game logic adding some hardcoded commands into the queue.
That’s mostly it, hopefully I’ll be able to discover and document more bits from the engine but I don’t expect it to happen any time soon.