Since Liquid War 3 the algorithm to power Liquid War is pretty much unchanged, at least, there has been no revolution, the basic principles remain the same. This has been explained in Liquid War 5 doc, but is repeated here, along with the specific Liquid War 6 stuff.
The very important things to remember are:
randomfunctions, it also does not use any float value either, since different type of processors/contexts might give slightly different results because of rounding problems.
Nof the cursor, then in the worst case, all adjacent places are at distance
N+1. As of Liquid War 6, the corresponding code is in
src/lib/ker/ker-spread.c. The second step is to move the fighters, make them act. In Liquid War 6, the corresponding code is in
src/lib/ker/ker-move.c. One can have a look at the code source for the function
src/lib/ker/ker-gamestate.cto see how these are called.
Most of the algorithm code has something to do with the following types (which are structs):
lw6map_level_tdefined in which is used to store the level data.
src/lib/map/map.hwhich is used to store the memory data required by the algorithm, but which are immutable. There’s a difference between those data and the ones stored in the level struct. For instance, those data are “private” since
lw6ker_game_struct_tis opaque, while everything is
lw6map_level_tis “public”. Also, data in
lw6ker_game_struct_tmight be highly redundant for performance issues and is optimized for speed while data in
lw6map_level_tis just plain data and won’t change if the algorithm is updated.
src/lib/ker/ker.hwhich is used to store the level data required by the algorithm, and which changes during the game. This is typically where an information such as “there’s a red fighter in slot (3,23,1)” will be stored.
src/lib/pil/pil.hwhich is used to handle all the threading issues. It keeps a track of 3 game states. A “reference” state which is the state of the game considering all input has been received from the network, and is validated. A “draft” state which might be anticipated and updated “as if the players we did not get input from did not move there cursors”. This can give the illusion that the game is running smoothly while in reality input from other players on the network is choppy. In a local game, “draft” and “reference” are equivalent, since there’s no doubt about what’s on the network. And finally, a “backup” state which can be pulled in case of a serious flaw and is a good way to solve the “hey, someone untrusted is throwing garbage on the net”. One can always pull a backup.
Most of the time, hacking on the algorithm, changing the gameplay, does not require
to touch anything but the code in
See See libmap. See See libker. See See libpil.
One of the key functions is
lw6ker_game_state_get_fighter_id, which will return
the id of a fighter at a given position.
Then its companion function
lw6ker_game_state_get_fighter_by_id can be called,
it will return a
lw6ker_fighter_t, which contains the real data.
lw6ker_fighter_t is not opaque and can be freely accessed by the caller,
which, typically, is a graphics backend trying to display informations. Try and grep
for the string “lw6ker_game_state_get_fighter_id” withing the
src/lib/gfx source tree
One thing that is very important when hacking on
libker: you should always
lw6ker_game_state_t struct in a state that is compatible with a
correct usage of public “getters” in
src/lib/ker/ker.h. The reason is that
this code can be executed by separate threads, more precisely, in “dirty read” mode,
the rendering thread will try and display a “game state” while this very “game state” is
being updated by another thread.