A generic text-based game engine for tabletop games.
Go to file
j4nk 0323c86399 Started on lobby. Can register new client 2023-09-11 02:59:25 -04:00
.gitignore Started on server. Can listen on socket, nothing else 2023-05-21 18:47:35 -04:00
LICENSE Added license 2023-08-08 13:13:38 -04:00
Makefile Add clean target to Makefile, started using pkg-config 2023-08-13 21:37:34 -04:00
README.md Update 'README.md' 2023-08-08 23:02:53 -04:00
ball.txt First commit, old repository 2023-01-06 19:12:24 -05:00
card.txt First commit, old repository 2023-01-06 19:12:24 -05:00
demo2.lua Signal to need networking, no diff between client/server 2023-05-28 23:42:23 -04:00
incorrect_oct_init.lua Added lua scripts for testing error checking 2023-05-31 09:27:41 -04:00
incorrect_oct_loop.lua Added lua scripts for testing error checking 2023-05-31 09:27:41 -04:00
incorrect_script.lua Checks and notifies of errors in lua script now 2023-05-26 19:53:34 -04:00
json.lua json.lua, modified to warn rather than error on bad json 2023-08-14 21:33:12 -04:00
lobby.lua Started on lobby. Can register new client 2023-09-11 02:59:25 -04:00
main.c Redid networking to a queue-based system 2023-08-08 13:07:05 -04:00
oct_log.c Added logging to lua-side, logging library is complete 2023-05-23 11:26:47 -04:00
oct_log.h Added logging to lua-side, logging library is complete 2023-05-23 11:26:47 -04:00
oct_networking.c Started on lobby. Can register new client 2023-09-11 02:59:25 -04:00
oct_networking.h Redid networking to a queue-based system 2023-08-08 13:07:05 -04:00
oct_termbox_sprite.c Added option to disable termbox if not needed 2023-05-26 19:43:18 -04:00
oct_termbox_sprite.h Added option to disable termbox if not needed 2023-05-26 19:43:18 -04:00
oct_utils.lua close socket after using, remove unused forward declarations 2023-06-02 08:25:00 -04:00
paddle.txt First commit, old repository 2023-01-06 19:12:24 -05:00
pong.lua Signal to need networking, no diff between client/server 2023-05-28 23:42:23 -04:00
termbox.h Updated termbox, added scorekeeping to pong.lua 2023-01-06 20:05:34 -05:00
termbox_defs.lua First commit, old repository 2023-01-06 19:12:24 -05:00
termbox_render.h Updated termbox, added scorekeeping to pong.lua 2023-01-06 20:05:34 -05:00
test.c Updated termbox, added scorekeeping to pong.lua 2023-01-06 20:05:34 -05:00
test_client.lua Fixed bug where messages were mangled in reception 2023-09-11 02:02:18 -04:00
test_lobby_server.lua Started on lobby. Can register new client 2023-09-11 02:59:25 -04:00
test_server.lua Signal to need networking, no diff between client/server 2023-05-28 23:42:23 -04:00

README.md

Open Card Table

A text-based tabletop game engine written in C and scripted with Lua

Motivation

I originally came up with this idea for the purpose of understanding the interaction between a rendering engine, game logic, and a scripting language along with learning how to use the C-Lua interface, learning the Unix sockets API, and experiencing firsthand manual memory management on a decently-sized project. Additionally, this project fills a gap I perceive in the open source gaming community; that is, a way to play tabletop games with friends on basically any *NIX system with a CPU. Indeed, this project runs only in the terminal; as of yet there are no graphical capabilities. It should be noted that the project has only been compiled on Linux, once the game is complete I will add in the necessary code for building on MacOS, OpenBSD, and FreeBSD.

Targets

Currently, the only target is Linux. After the game is finished, it will target Mac OSX, OpenBSD, and FreeBSD. Other targets may be added after that. Windows support is not planned, however it may be possible to run this in WSL, I have no idea how well WSL works with the Unix sockets API.

Dependencies

Currently, the only dependencies are termbox2 and Lua 5.3. An older version of termbox2 is included in the repository for convenience. I used termbox2 instead of ncurses because ncurses leaks memory, and one of my goals for this project is to not leak memory at all. Also, termbox2 is much, much simpler than ncurses in my opinion. I plan on upgrading to Lua 5.4 eventually, when I began this project Lua 5.4 was already out but a tutorial I was following was using Lua 5.3.

License

This project is released under the MIT license. This means that you can basically do anything you want with it, including forking the code and releasing that under a nonfree license.

Building

cd to the directory and do make. This will almost certainly not work on a non-Linux system right now.

Usage

open_card_table [options] LUA_FILE

LUA_FILE is the file to run

Options may be

  • -p PORT: Port to listen on for connections
  • -v: Prints version
  • -h: Prints help
  • -ll LOG_LEVEL: Sets the log level for output: 0=error, 1=warning, 2=information, 3=debug
  • -lf LOG_FILE: Sets the output file for the log, stderr by default

Provided Lua scripts

The lua scripts in the repository are provided as examples and sanity checks

  • demo2.lua - I don't actually remember what this was for... some testing in the early stages of development
  • incorrect_oct_init.lua - A script that has a runtime error in the oct_init function, used for testing lua errors and memory leaks
  • incorrect_oct_loop.lua - A script that has a runtime error in the oct_loop function, used for testing lua errors and memory leaks
  • incorrect_script.lua - A script that will fail to parse successfully, used for testing lua errors and memory leaks
  • oct_utils.lua - Defines useful constants and functions specific to Open Card Table
  • pong.lua - Implements 2 player pong, with both players using the same keyboard on the same computer. Does not work very well because of n-key rollover
  • termbox_defs.lua - Contains termbox2-specific stuff needed in Lua, mainly key constants defined by termbox2
  • test_client/test_server.lua - Scripts used for testing networking. Server should listen on port 1234 and client can listen on any port; both should be on same computer. Client sends message to server every second or so and the server echoes what it received

Developing Lua scripts

The best way to learn scripting for Open Card Table is to look at the included Lua scripts, especially pong.lua as that's the only complete project as of right now. Unfortunately, pong.lua does not demonstrate networking at all but I am currently working on some projects to do this.

Includes

It is generally a good idea to include oct_utils.lua and termbox_defs.lua at the top of every script. This can be accomplished with the following lines

require("oct_utils");
require("termbox_defs");

Of course, this requires the script under development be in the same directory as these files.

Required functions

Every Open Card Table lua script must have 2 functions defined: oct_init and oct_loop. oct_init is called once at the beginning of program execution and should be used for initializing variables, initializing the environment, defining sprites, etc. oct_loop is called once per iteration of the main loop in the C part of the code, and is where all game logic should reside. open_card_table will exit with an error if either one of these is missing.

oct_init

oct_init needs to return two variables in order: a variable defining whether or not we need networking, and a variable defining whether or not we need termbox. oct_utils.lua defines some handy, self-explanatory constants for this: OCT_NOT_NEEDS_NETWORKING, OCT_NEEDS_NETWORKING, OCT_NOT_NEEDS_TERMBOX, and OCT_NEEDS_TERMBOX. Singleplayer games obviously do not need networking, and generally the only time you will not want termbox is when you are running a server program as opposed to a client.

oct_loop

This function is where the game logic resides. It generally consists of reading in keyboard input and adjusting sprites accordingly. It does not return anything.

Sprites

Sprites are the basic unit or what's drawn on screen. They should be declared in global scope, e.g. like

paddle_left = oct_tb_sprite_new();

Sprites are managed on the C side of things, and oct_tb_sprite_new allocates memory for each sprite; all sprite references are stored in a dynamically growing array so the limit of how many sprites you may have is determined only by your hardware. Sprites can only be created, not deleted. Every sprite has 3 required attributes: x, y, and shape; other attributes may be defined for game logic but these three are reserved. x and y are just the location of the top-left corner of the sprite on screen. shape is the representation of the sprite. This can be manually specified as a string, or sprites can be defined in a file and read in via the function load_termbox_sprite. Here is an example:

function oct_init()
    ...
    paddle_left["shape"] = load_termbox_sprite("paddle.txt");
    paddle_left["x"] = 1;
    paddle_left["y"] = math.floor(height/2)-2;
    ...
end

Networking

Note that at this time, networking is incomplete and only basic functionality is working. Networking consists of the oct_recv and oct_send functions. Note that in order to use networking, oct_init() had to return OCT_NEEDS_NETWORKING as the first argument, or else nothing will happen. These usually are used in the oct_loop function. I still need to add in support for broadcasting, this will come in a while. Important: Message sending is synchronous, i.e. under the hood a message and destination are placed in buffers, and at the next invocation of the main loop the message is sent to the destination. I believe that tabletop games are simple enough that this is sufficient to express games even with real-time components as the main loop is executed at a high frequency. If this turns out not to be the case, I will look into adding asynchronous message sending.

Networking examples

Receiving a message: msg,addr,port = oct_recv();

Sending a message: oct_send("MESSAGE", "IP_ADDRESS", "PORT");

Logging

I have written a convenient logging interface for Lua, it uses the logging macros I implemented in C. It can be invoked in Lua via the OCT_LOG_ERROR, OCT_LOG_INFO, OCT_LOG_WARNING, and OCT_LOG_DEBUG functions, passing the desired string as an argument. Remember that termbox2 takes over the console so it is a good idea to use the -lf switch to specify an output file if you are running a termbox-enabled program. Also remember that the log level needs to be set to a sufficient strength via -ll in order to see the messages.