- Liquid War (v5.6.4) - Source code
- General remarks
- ===============
- Modularity
- ----------
- Liquid War 5 is basically a big C program. I've splitted the source code in
- many small files for I do not like to have to handle big monolithic
- sources, but this does not mean Liquid War is very modular. In fact Liquid
- War 5 is quite bloated with global variables and other ugly stuff 8-(
- Coding style
- ------------
- To be honest, it's a big mess. You won't find 2 files coded in the same
- maner... OK, I'm exagerating a bit. From now I try to make an effort and
- stick to basic rules such as:
- * use the GNUish-style indentation - the default Emacs mode in fact
- * prefix global functions / variables / constants / types with
- lw_<NAME_OF_THE_file>_. For instance, a "do_it" function in myfile.c will
- be called lw_myfile_do_it
- * use capitals for constants, globals and types only. All functions are in
- lowercase with "_" to separate words
- * keep on using 8.3 filenames for .c source files. This is for better DOS
- integration. DOS version of Liquid War is still maintained, you know 8-)
- * use English only for code and comments
- I might decide to rename and cleanup everything some day, for it would help
- other coders to understand what I wrote, but well, this is certainly not a
- thrilling task 8-/
- Source files organization
- =========================
- Main game code
- --------------
- Here you'll find the main() function, the main game loop, application-wide
- constants and other global stuff.
- It might be a good start if you want to hack the code.
- * base.h: contains global constants used in many different files.
- * game.c / game.h: contains the main game loop.
- * main.c / main.h: the file where the main C function is declared. Doesn't
- contain much except calling init functions and running the GUI.
- Menus
- -----
- The menus are coded using the Allegro GUI system. While this system is very
- powerfull, it's IMHO not adapted to very complex GUIs, and one of its
- drawbacks is that it's not so easy to redesign something once you've coded
- it.
- Besides, when I started coding the GUI in 1998, I did it in a rather ugly
- way, and now I'm paying for my being lazy at that time, since I spent hours
- coding when I want to change something 8-/
- * about.c / about.h: contains the code for the about menu.
- * advanced.c / advanced.h: contains the GUI advanced options menu.
- * connect.c / connect.h: contains code for the "connect" menu which
- displays which players are connected to the server, before the game
- actually starts.
- * controls.c / controls.h: contains the code for the controls menu.
- * graphics.c / graphics.h: code for the graphic options menu.
- * internet.c / internet.h: contains the code for the "Search for Internet
- games" menu, where one can pick up a running server automatically with
- the help of the meta-server.
- * language.c / language.h: contains the code for the "Language" menu.
- * level.c / level.h: contains code for the menu where the player can select
- a level and its options (texture or color).
- * menu.c / menu.h: contains the code for the main menu.
- * netgame.c / netgame.h: contains the code for the net game menu.
- * options.c / options.h: contains the code for the options menu.
- * play.c / play.h: contains the code which ties the menu to the main
- gameloop.
- * rules.c / rules.h: code for the rules menu.
- * score.c / score.h: functions to display the scores at the end of the
- game.
- * speeds.c / speeds.h: contains the code for the speeds menu.
- * team.c / team.h: code for the team menu, where one choses which teams
- will play.
- * volume.c / volume.h: code for the sound menu.
- * wave.c / wave.h: code for the wave menu.
- GUI tools
- ---------
- These files contain various utilities which are used in the menus.
- * alleg2.c / alleg2.h: contains some tweaked allegro functions. I wanted to
- use bitmaps with sevral colors for my fonts, and change some of the
- allegro default behavior. So rather than modifying the allegro source
- code right in the library I copied it in this file and then modified it.
- * back.c / back.h: this modules displays the background image.
- * dialog.c / dialog.h: contains code for standard dialog boxes.
- * error.c / error.h: contains functions to display error messages once the
- game is in graphical mode.
- * help.c / help.h: generic functions to display the various help pages.
- Core algorithm
- --------------
- Here's *the* interesting part. All the rest of the code is just sugar coat
- to display stuff, receive players commands, communicate with other
- computers, handle errors, etc... But the real thing is here!
- It's funny to note that these files have almost not been modified since
- Liquid War 5.0.
- It's also interesting to note that they represent a small percentage of the
- total amount of code in the game. This tends to prove - and I'm convinced
- of it - that game programming does not only consists in having great ideas,
- but also requires a lot of "dirty" and boring work. Honestly, coding an
- option menu is as boring as coding Liquid War algorithm is fun.
- * fighter.c / fighter.h: contains code to move the armies, once the
- gradient has been calculated.
- * grad.c / grad.h: this module calculates the gradient for each team. One
- could say it's the "kernel" of the game, since most of the CPU time is
- spent in this module (except if you have a slow display...).
- * mesh.c / mesh.h: contains code to set up a usable mesh with a map. Mesh
- are re-calculated at each time a new game is started, the reason for this
- being that meshes are *very* big so it would not be reasonnable to save
- them directly on the HD.
- * monster.s / monster.h: assembly functions to speed-up the game. It's a
- replacement for some fighter.c functions.
- * spread.s / spread.h: contains assembly replacements for some functions of
- grad.c. These replacements do the same than the original ones from
- grad.c, but faster. Could still be optimized.
- Moving cursors
- --------------
- It looks like nothing, but moving a cursor and deciding where it should go
- if there's a wall in front of it is not that easy, especially if you want
- things to work nicely.
- * autoplay.c / autoplay.h: contains the code for the computer AI. This
- module simulates keypresses from the computer, then the computer is
- handled as any other player.
- * move.c / move.h: provides an API to move the cursors.
- User input
- ----------
- Until 5.4.0, Liquid War did not have network support. As it is designed to
- be multiplayer, one needed to have several players on the same computer.
- The mouse also needed to be handled in a special way since cursors can
- *not* pass walls in Liquid War. Additionnally, I wanted all input channels
- (keyboard mouse and joystick) to be handled in a unified way.
- This explains why there's so much code for user input, when one would think
- at first sight that "polling the keyboard is enough".
- * joystick.c / joystick.h: contains code to support joystick input. It
- wraps joystick buttons to virtual keyboard keys, so that joystick and
- keyboard behave exactly the same.
- * keyboard.c / keyboard.h: contains code to handle key presses.
- * mouse.c / mouse.h: wraps the mouse movements to virtual keyboard keys.
- This way the mouse can be used to control the players.
- Initialisations
- ---------------
- These files contain functions to intialize various game components. 100%
- boring code.
- * area.c / area.h: contains functions to create the game area. Basically it
- contains functions to create the data structures in which the level is
- stored during the game.
- * army.c / army.h: functions to create the armies, and place them on the
- battlefield.
- * asm.c / asm.h: various constants, macros and utilities to ensure that
- asembly code works correctly.
- * bigdata.c / bigdata.h: I had a really hard time with the malloc function
- with DJGPP under Win95 dos box. I tried to have it working for hours and
- hours but my program kept being buggy. So I decided to allocate the
- memory myself, in a memory zone I create at startup. This is what this
- module does: create a huge memory zone and then give parts of it to the
- rest of the program.
- * config.c / config.h: contains everything that is related to the game
- configuration. This module contains in global variables all the
- parameters that are stored in the config file.
- * cursor.c / cursor.h: contains the code to init the cursors and place them
- on the battlefield at the beginning of the game.
- * decal.c / decal.h: This module makes the link between teams and players.
- Its coding is quite ugly, for some modules in LW assume that when 2 teams
- are playing they are always teams 0 and 1. So when 3 teams are playing
- are playing and the second team loses, one has to make team 2 become team
- 1. That's what this module is for.
- * exit.c / exit.h: contains code that is executed when the game ends, it
- shuts down Allegro and displays messages on the console.
- * gfxmode.c / gfxmode.h: contains code to set up the various video modes,
- and defines which modes are available for each platform.
- * init.c / init.h: contains code to initialize Allegro with proper options
- and analyze failures.
- * palette.c / palette.h: contains function to set up the current color
- palette. Liquid War uses different palettes, depending on what colors are
- chosen for teams.
- Graphics
- --------
- Here lies most of the graphic functions in Liquid War. There's not that
- much code since Liquid War's strength is not its visual effects, but rather
- its gameplay.
- The only "funny" thing is the wave effect. I'm quite happy with it, and
- honestly, I do think it is rather fast, given the fact that it uses no 3D
- hardware at all.
- * disp.c / disp.h: contains functions to display the battlefield.
- * distor.c / distor.h: this module contains code to create the "wave
- effect". It uses a lot of data tables, and is quite complicated to
- understand...
- * glouglou.s / glouglou.h: assembly module, it is a replacement for some
- functions of distor.c. It goes much faster but does the same.
- * info.c / info.h: contains code to display the info bar. The info bar is
- the bar which display the time left and the amount of players for each
- team while the game is running.
- * message.c / message.h: provides an API to display messages during the
- game. Very useful if you want to debug the game: you can trace and
- display anything.
- * pion.c / pion.h: contains code to display the cursors.
- * viewport.c / vieport.h: code to allocate and resize the zone where the
- map is displayed, also called "viewport".
- Sound and music
- ---------------
- Sound and music routines required some encapsulation, since the game must
- be able to run even if the sound and/or music did not load correctly.
- * music.c / music.h: contains the code to control MIDI playback.
- * sound.c / sound.h: functions to play sound.
- Data management
- ---------------
- These functions handle the datafile contents and also the custom data.
- Note that the various utilities such as liquidwarcol, liquidwarmap and
- liquidwartex do not share code with the main executable. This is obviously
- a design error, for liquidwarmap will handle maps in a very poor way and is
- unable to autodetect map errors, whereas the game does it rather well.
- Blame the programmer.
- * disk.c / disk.h: contains all the code to access data from the hard
- drive. In fact, all the HD access is done at startup.
- * map.c / map.h: contains code to load the maps from a datafile raw data or
- a user defined bitmap to a usable structure in RAM.
- * maptex.c / maptex.h: contains code to handle the "use default texture"
- option, and associate a map with a given texture automatically.
- * texture.c / texture.h: contains code to handle textures. Textures are
- stored in a special format which uses 5 bits per pixel.
- Random map generator
- --------------------
- Liquid War has a "generate random map" feature which is available within
- the game and also as an external program. The source code for the external
- program is in ./utils/lwmapgen in Liquid War source distribution. This
- program has been coded by David Redick, is also available on
- http://www.cs.clemson.edu/~dredick/lwmapgen/ and works on GNU/Linux.
- Compiling this program under DOS and/or Windows is untested and
- unsupported.
- The random map generator within Liquid War - which of course works on any
- platform support by LW - uses for its greater part the same source code as
- the external lwmapgen program.
- * random.c / random.h: wrapper for the map generator written by David
- Redick. It basically does the same as ./utils/lwmapgen/main.c except that
- it does it within Liquid War as it is running and not in an external
- independant program.
- Time handling
- -------------
- Time handling is fundamental in a game. Time is used for visual effects
- (waves...) during the game, it's used to generate some pseudo random stuff,
- well, it's used everywhere!
- Note that on the client, I use 2 "different" clocks. The first counts the
- "real" time, in seconds. The second one is counts "rounds" and is
- incremented by 1 at each game round.
- * srvtime.c / srvtime.h: code used to handle time on the server, where
- Allegro's functions are not available.
- * ticker.c / ticker.h: sets up a timer callback.
- * time.c / time.h: functions to know how long the game has been running,
- knowing that it can be interrupted.
- In-game utilities
- -----------------
- These are various utilities use to monitor and control the game while one's
- playing.
- * capture.c / capture.h: code used to capture the video output of the game
- and store it in .bmp files while playing.
- * checksum.c / checksum.h: utilities to generate a checksum from a given
- game state. Used in network code to make sure all the clients stay
- synchronized.
- * code.c / code.h: This file contains the code to handle key presses during
- the game. That's to say the pause key for instance.
- * profile.c / profile.h: provides tools to calculate how fast the game is
- runnning and what operations slow it down.
- * watchdog.c / watchdog.h: this module waits for "secret codes" to be typed
- while the game is running, and traps them.
- Command line handling
- ---------------------
- OK, now to all the UNIX guys, I *know* there are many ways to do things in
- a better and simple way than I did. But keep in mind that in 1998, under
- DOS, I had a rotten command line and even now I need everything to work on
- both UNIX and Microsoft platforms.
- These utilities are not perfect, but they work, that's all I ask them.
- * basicopt.c / basicopt.h: handles basic command line parameters such as
- "-v" or "-h".
- * parser.c / parser.h: contains code to parse and analyze the command line
- parameters.
- * startup.c / startup.h: analyzes the command line parameters and stores
- them into global variables.
- Locale support
- --------------
- Liquid War now has locale support. Basically, all the labels and texts in
- the UI are stored in constants. There's simply file per language.
- Note to translators: if you decide to translate the menus in another
- language, keep in mind that all the translations must fit in the various
- buttons and textboxes. The best resolution to test this - the one where
- letters take most place - is 640x480.
- * lang.c / lang.h: contains code to handle language dependant stuff.
- * langen.c / langen.h: contains code to handle English specific stuff.
- * langfr.c / langfr.h: contains code to handle French specific stuff.
- Log and various messages
- ------------------------
- OK, the API of the log routines is a piece of crap. Now I'm simply too lazy
- to change it. It works, that's all I ask.
- BTW, there's a clear advantage in using custom-made log functions instead
- of plain calls to "fprintf(stderr,...". It might not be obvious for UNIX
- users, but think about Windows. Nothing like a "tail -f" there, nor a
- proper output redirection system. When a user clicks on the Liquid War
- icon, I want "console" information to be logged in a file!
- * log.h: common header for logcli.c and logsrv.c.
- * logcli.c: contains code to display messages on the console. It's usefull
- for console may have different behaviors when the games is used on
- different platforms. This file is used to compile the client.
- * logsrv.c: contains code to display messages on the console. This file is
- used to compile the server, which does not use Allegro at all.
- * popupgen.h: common header for popup functions.
- * popupw32.c: code to handle popup on the Win32 platform. Popups are a
- must-have under Windows for error diagnostics, since the average Windows
- user never gives any look at any log file...
- Macros, utilities and string support
- ------------------------------------
- As usual, I needed to prepare a small set of usefull macros.
- * macro.h: contains basic wrappers/macros for snprintf like functions. This
- mostly to ease up string manipulation which is - as always - a nightmare
- in standard C.
- * path.c / path.h: code used to handle filenames and paths, for instance
- remove path and file extension from a filename.
- It's also important to note that Liquid War uses snprintf instead of
- sprintf, for using the latter is very likely to cause buffer overflows.
- Under Linux glibc provides this function but Microsoft does not provide it
- natively on Windows. Therefore I used a third party snprintf implementation
- by Mark Martinec: http://www.ijs.si/software/snprintf/ and its source is
- available in the ./utils directory of Liquid War source distribution.
- Byte order and endianess
- ------------------------
- As you might know, PC Intel based computers are "little-endian" while Sun
- Sparc stations and Mac computers are "big-endian". This is an issue for LW
- since in network games maps are transmitted in binary format. Therefore I
- needed to set up some (un)serialization fonctions.
- * serial.c / serial.h: code used to transform integers and map headers into
- an uniform cross-platform byte stream which is readable by both little
- and big endian machines.
- Thread support
- --------------
- Liquid War does have thread support, but it is a "limited" thread support.
- I mean that the game is generally monothreaded, but a few functions use
- threads. For instance, calls to the meta-server are done within threads.
- Basically, I do not really enjoy programming in a multithreaded
- environnement. So when possible, I chose the monothread path, and used
- threads only where I simply would not be able to find another acceptable
- solution.
- I also needed to use some mutexes to prevent crashes in the user interface.
- * mutxdos.c: provides fake mutex support under DOS. This module is here
- only to make compilation easier.
- * mutxgen.h: header for mutxdos.c, mutxunix.c and mutxw32.c.
- * mutxunix.c: provides mutex support on UNIX.
- * mutxw32.c: provides mutex support on Win32.
- * thrddos.c: provides fake thread support under DOS. This module is here
- only to make compilation easier.
- * thrdgen.h: header for thrddos.c, thrdunix.c and thrdw32.c.
- * thrdunix.c: provides thread support on UNIX.
- * thrdw32.c: provides thread support on Win32.
- Launching external programs
- ---------------------------
- Liquid War might sometimes launch external programs. This is (for security
- reason) not a default behavior and has to be activated and configured by
- yourself, using the "-callback" command line option on the server for
- instance.
- * execgen.h: header for execunix.c and execw32.c.
- * execunix.c: code to launch external programs on UNIX.
- * execw32.c: code to launch external programs on Win32.
- * exec2.c: code to launch external programs within the client, without any
- interaction with the user, ie no unwanted popping window for instance.
- Low-level network code
- ----------------------
- There are network packages for Allegro, but I decided not to use them.
- Socket support is not that hard to implement under UNIX and Win32 and
- besides, I've done it for my job recently, so I just knew how to do it.
- Another reason which decided me to code my own toolbox is that I did not
- want Liquid War to have external dependencies - except Allegro of course.
- This way, UNIX gamers to not have to set up and/or download a specific
- network library. It's also easier to integrate the game in projects like
- Debian if it has few dependencies.
- This network code is not a masterpiece, it's just a little set of tools
- that have proven to work. That's all.
- BTW, it's important to notice that when linking with Allegro, most blocking
- UNIX calls ("sleep" or "recv" for instance) stop working: they alwasys
- return immediately. This led me to implement weird ugly hacks, like calling
- "recv" in a loop until it gets what it wants... This is theorically and
- practically a performance killer, but I found no other way to fix this. And
- FYI, this is not an Allegro bug, it's a feature 8-)
- * dnsutil.c / dnsutil.h: wrapper code to issue DNS requests, without having
- to handle the hostent struct.
- * sock2cli.c: sode used to wrap low-level network function on the client.
- * sock2gen.h: header for sock2cli.c and sock2srv.c.
- * sock2srv.c: code used to wrap low-level network function on the server.
- * sockdos.c: network API for DOS.
- * sockex.c: netowrk routines shared by sockunix and sockw32.
- * sockgen.h: header for sockdos.c, sockunix.c and sockw32.c.
- * sockunix.c: network API for UNIX.
- * sockw32.c: network API for Win32.
- High-level network code
- -----------------------
- These files contains network utilities which are Liquid War specific.
- * chat.c / chat.h: functions used to handle chat messages in network games.
- * keyexch.c / keyexch.h: functions to send and receive keys to the server.
- Used on the client.
- * netconf.c / netconf.h: code to send and receive the config of the clients
- over the network.
- * netkey.c / netkey.h: contains some tools to manipulate key strokes over
- the network.
- * netmap.c / netmap.h: code to send and receive the maps over the network.
- * netmess.c / netmess.h: contains a parser to interpret plain text
- messages. Used when exhanging information over the network.
- * netplay.c / netplay.h: contains the code to set up and start network
- games.
- * network.c / network.h: contains some network related functions and
- constants used on the client.
- * ping.c / ping.h: code used on the client to estimate the average ping
- time with a server.
- * protocol.c / protocol.h: contains the sequence of messages send and
- recevied by the client when connecting on the server.
- * startinf.c / startinf.h: contains struct and tools to handle some network
- informations while starting a network game.
- Communication with the meta-server
- ----------------------------------
- The meta-server is called by both client and server. Basically, the server
- registers itself, and the client asks for a list of servers.
- The meta-server itself is just a set of simple PHP scripts with a simple
- MySQL database. I chose PHP because my provider allows execution of PHP
- pages, that's all.
- The protocol is *very* basic, and uses HTTP 1.0 for requests. Answers are
- received in plain text, with one information per line. There's no garantee
- that this would work with any HTTP server, but experience proved that it
- works with my provider 8-)
- * httputil.c / httputil.h: low level functions to handle http requests.
- * wwwcli.c / wwwcli.h: code used on the client to communicate with the
- meta-server.
- * wwwsrv.c / wwwsrv.h: code used on the server to communicate with the
- meta-server.
- Server code
- -----------
- The Liquid War server is a rather small program. The only thing it does is
- accept new players, transmit map and game parameters between them, and then
- "replicate keys".
- By "replicate keys" I mean that the server asks each client what keys have
- been pressed during the last round, and then dispatches this informations
- to all clients. This implies that the server has absolutely no idea of
- who's loosing, who's winning, etc...
- All the "logic" of the server is coded in these files, the rest is only
- utilities and helper functions.
- * server.c / server.h: main code for the server (equivalent of main.c for
- the client).
- * srvchan.c / srvchan.h: code used to handles channels on the server. A
- channel is associated to a given computer and may manage several teams.
- * srvcont.c / srvcont.h: global network controler used on the server.
- * srvteam.c / srvteam.h: code used to handle teams on the server.
Raw Paste