LIOD: 4BoD

About


This is a `big pack` with tools which contains: 4BoD emulator (4BoD-CS); 4BoD `postcompiler`; few `libraries`, which includes: `platform` settings, `binary`, few `definitions` and `40+ macros`, such as ~jump~, ~nib~, ~for~, ~ifn~, ~while~; and few `examples`. So, if you want to develop a `4-bit game`, there is `everything` you need.

(use 4BoD) (use 4BoD.IO) (nib i) (mac main (def) (disp:flip i i) (++ i) )

Download


Download from this site: 4BoD.zip.

Documentation


There is a basic documentation of all commands and definitions, but firstly, of course, read main LIOD documentation.

Creating a file

Create a file in the libs' folder. Name it and give it ~.liod~ extension. After creation just import all libraries as shown in example.

; importing libraries (use 4BoD) ; main library (use 4BoD.IO) ; this one for IO

Compile and run

To test if everything works just copy code from the top into your file. Then drag and drop your file onto the ~LIOD4BoD.exe~ and close all windows that appeared. Now you got 2 new files: one with ~.lf~ extension and one with ~.b~. To run the program just drag and drop ~.b~ file onto ~4BoD-CS.exe~. You will see a diagonal line.

Constants

Constants are defined with ~def~ macro and ~name~, ~value~ as arguments, more in main LIOD documentation. To create multiple constants at once, use ~def:~ and write all names and values after it.

; creating constatnts (def height 4) (def: tick 5 tack 9 )

Variables

Variables are defined with ~nib~ macro and ~name~ as argument. To create multiple variables at once, use ~nib:~ and write all names after it.

; creating nibbles (nib a) (nib: player:x player:y width)

Maths

There are 6 maths operators: ~=~, ~++~, ~--~, ~+=~, ~\l\l~, ~>>~. First is assignment. Using this operator you can assign variable to a constant value or to another variable. Second is incremention by 1. Third is decremention by one Fourth is incremention by a constant value, so you can't increment one variable by another. If you need to decrement by a constant value, use the same macro, but subtract this constant value from 16. Fifth operator is shifting left, but also it can be named like multiplication by 2. Sixth is shifting right, or division by 2. Also there are binary numbers, which starts with '$' character. Their maximum length is 4, but you can use with 3, 2, 1 length, so they will be same ~$10 = $0010~. But You can't use with 5, 6, 7, etc length, so ~$01111~ will cause a error.

(nib: a b) ; variables ; assignment (= a 11) ; a = 11 (= b a) ; b = a = 11 ; incremention / decremention (++ a) ; a = 12 (-- b) ; b = 10 ; 'add' and 'sub' (+= a 3) ; a = 15 (+= b 13) ; b = b - 3 = 7 ; shifting (\l\l a) ; a = 14 1111->1110 (>> b) ; b = 3 0111->0011 ; binary (= a $1000) ; a = 8 (= b $11) ; b = 3 (= a $01111) ; error

File structure

There is a ~main~ macro with no arguments, you need to define it to make your game work. Usually the structure of a file is:

  1. Using libraries
  2. Defining variables and constants.
  3. "main" macro
  4. Other macros
(use 4BoD) ; using libs (use 4BoD.IO) (def: ...) ; definitions (nib: ...) ; and vars (mac main (def) ...) ; main macro (mac renderer (def) ...) ; other macros (mac controls (def) ...)

Drawing

Library ~4BoD.IO~ includes ~disp~ (display) class and there are 3 macros: ~disp:clear~, ~disp:flip~ and ~disp:read~. Using ~disp:clear~ will clear the whole screen. Using ~disp:flip~ will "flip" a pixel on the screen, the macro uses 2 arguments: ~x~ and ~y~, x and y respectively. Using ~disp:read~ will "read" a pixel's value from the screen, it uses 3 arguments: ~var~ (variable to save in), ~x~ and ~y~.

(use 4BoD) (use 4BoD.IO) ; importing (nib: x y a) (mac main (def) (= x 5) (= y 2) (disp:clear) ; clears display (disp:flip x y) ; flips a pixel (disp:read a x y) ; reads a pixel )

Flags and jumping

To define a flag use ~flag*~ macro and give it a name as argument at the same part of code, where variables defined. Also you can define multiple flags at once, using ~flag:~ macro. To place a flag use ~flag~ macro and flag's name. To jump to a flag use ~jump~ macro, and flag's name as argument. Also you can use ~pass~ macro, to skip whole frame.

(nib: x y a) (flag* skip) (mac main (def) (jump skip) (flip 0 0) (flag skip) ; no pixel drawn (pass) (flip 0 0) ; still no pixel )

Branching and conditions

There are 2 macros to create branching: ~jf~ and ~ifn~. First one jumps to a flag if condition is true, so firstly give it a condition, and then a name of a flag. The second does commands given to a macro if condition is wrong, so firstly give it a condition, and then all commands. There are 3 macros, that can be used as conditions: ~==~, ~\l~, ~>~. First checks if first var equal to second, second - if first less than second and third - if first greater than second. Also you can compare a variable with a number or a costant, but you can't compare 2 number or consts, it will give a error ~#4BoD00~

(nib: x y) (flag* skip) ; program with no significance (mac main (def) (jf (== x y) skip) (++ y) (flag skip) (ifn (== x 5) (++ x) ) )
>>> (== 5 3) Error: Redundant comparision. #4BoD00

Keyboard

Library ~4BoD.IO~ contains ~keys~ class which includes 5 properties: ~key:left~, ~key:right~, ~key:up~, ~key:down~ and ~key:any~. First four return values of a buttons which they are responsible for, value can be 0 - not pressed and 1 - pressed. The last one returns value of all keys, from 0 to 15. You can use it to simulate random.

; movement (ifn (== key:left 0) (-- player:x)) (ifn (== key:right 0) (++ player:x)) (ifn (== key:up 0) (-- player:y)) (ifn (== key:down 0) (++ player:y))

Loops

There are 2 macros to create loops: ~for~ and ~while~. Its important, that both of them check condition only after they did commands given to them. First simulates ~for~ behavior in C#, you should give it three arguments and commands. Second simulates ~while~ behavior in C#, you should give it a condition and commands.

(for (= x 0) (> x 0) (++ x) ; 16 times (for (= y 0) (> y 0) (++ y) (disp: flip x y) ) )
(while (> a 0) ; 16 times (++ a) )

Dictionary

There are all macros and definitions of the library. You shouldn't use other commands, so there are no them.

LIOD.liod

;;;; CLASS NOVA nova ; no value (nova definition) ; sets "def" to nova (nova? definition then else?) ; if def is nova then do "then" else do "else?" (nova: definitions*) ; sets "defs*" to nova
;;;; CLASS DEF (def? definition then else?) ; if "def" exist then do "then" else do "else?" (def: def-val*) ; creates new defs with vals (def:inc definition) ; increments def's value (def:dec definition) ; decrements def's value (def:equ def1 def2 then else?) ; if "def1" equal to "def2" do "then" else do "else?"
; CLASS ERROR (error name text...) ; creates new error (error* name text...) ; creates new error without "error:" prefix
;;;; OTHER (enum name def-val*) ; creates multiple definitions (con* conts) ; con analog (rpt times do) ; repeats text times (call macro args) ; calls mac with args

4BoD.liod

;;;; TEMPORARY VARIABLES tmpf ; first temporary var tmps ; second temporary var
;;;; CLASS NIB (nib name) ; creates new nibble (nib? name then else?) ; checks if the given definition is nibble (nib: names*) ; creates multiple nibbles
;;;; CLASS FLAG (flag name) ; creates new flag (flag* name) ; gives a name to a flag (flag: names) ; defines multiple flags at once (jump name) ; jumps to flag (pass) ; goes to the end of the frame
;;;; OPERATORS (= nibb value) ; sets nibble to value (++ nibb) ; increments nibble by 1 (+= nibb val) ; adds a constant value to nibble (-- nibb) ; decrements nibble by 1 (\l\l nibb) ; shifts nibble left (>> nibb) ; shifts nibble right (== nib1 nib2) ; checks if nib1 = nib2 (\l nib1 nib2) ; checks if nib1 \l nib2 (> nib1 nib2) ; checks if nib1 > nib2
;;;; BRANCHING (jf cond flg) ; conditionally jumps to flag (ifn cond conts) ; does if not cond
;;;; LOOPS (while cond do) ; simple do-while construction (for def cond inc) ; simple for loop

4BoD.IO.liod

;;;; CLASS KEY key:left ; returns 1 if left is pressed otherwise 0 key:right ; returns 1 if right is pressed otherwise 0 key:up ; returns 1 if up is pressed otherwise 0 key:down ; returns 1 if down is pressed otherwise 0 key:any ; returns btn value
;;;; CLASS DISP (disp:read nibb x y) ; gets pixel value and saves it to nib (disp:flip x y) ; flips pixel at x y (disp:clear) ; clears the screen