~melchizedek6809/WolkenWelten

45708140f30b1941a38962768339333cc371d2e5 — Ben (X13) 2 years ago ac5ad5c feature/nujel-update
Massive Update due to big Nujel update
M client/client.mk => client/client.mk +11 -1
@@ 14,7 14,7 @@ TXT_ASSETS        := $(shell find client/txt -type f -name '*')
MESHASSETS        := $(shell find client/mesh -type f -name '*')
CLIENT_NUJ        := $(shell find client/src/nujel/ -type f -name '*.nuj' | sort)
CLIENT_NO         := $(CLIENT_NUJ:.nuj=.no)
CLIENT_NUJ_ASSETS := client/src/tmp/client.no
CLIENT_NUJ_ASSETS := client/src/tmp/client.nuj
CLIENT_TMP_SRCS   := client/src/tmp/objs.c client/src/tmp/gfxAssets.c client/src/tmp/sfxAssets.c client/src/tmp/shdAssets.c client/src/tmp/txtAssets.c client/src/tmp/nujAssets.c client/src/tmp/meshAssets.c common/src/tmp/assets.c common/src/tmp/cto.c client/src/tmp/sfx.c
CLIENT_TMP_OBJS   := ${CLIENT_TMP_SRCS:.c=.o}



@@ 33,6 33,11 @@ $(CLIENT_OBJS_EXCL): | common/src/tmp/cto.c
$(CLIENT_OBJS):      | client/src/tmp/objs.h
$(CLIENT_OBJS):      | client/src/tmp/sfx.h


.PHONY: common/nujel/nujel.a
common/nujel/nujel.a:
	@$(MAKE) -C common/nujel nujel.a

$(WOLKENWELTEN): $(CLIENT_OBJS) $(ASM_OBJS) $(CLIENT_TMP_OBJS) common/nujel/nujel.a common/nujel/tmp/stdlib.o
	@$(CC) $^ -g -o $@ $(OPTIMIZATION) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_CINCLUDES) $(CINCLUDES) $(CLIENT_LIBS) $(CSTD)
	@echo "$(ANSI_BG_GREEN)" "[LD] " "$(ANSI_RESET)" $@


@@ 42,6 47,11 @@ client/src/tmp/client.no: $(CLIENT_NO)
	@cat $^ > $@
	@echo "$(ANSI_GREY)" "[CAT]" "$(ANSI_RESET)" $@

client/src/tmp/client.nuj: $(CLIENT_NUJ)
	@mkdir -p client/src/tmp
	@cat $^ > $@
	@echo "$(ANSI_GREY)" "[CAT]" "$(ANSI_RESET)" $@

%.ogg: %.aif
	@$(FFMPEG) -hide_banner -y -v panic -i $< -ac 1 -ar 22050 -acodec libvorbis $@ < /dev/null
	@echo "$(ANSI_CYAN)" "[FF] " "$(ANSI_RESET)" $@

M client/src/binding/widgetGC.c => client/src/binding/widgetGC.c +1 -1
@@ 26,7 26,7 @@
#include "../../../common/nujel/lib/exception.h"
#include "../../../common/nujel/lib/allocation/garbage-collection.h"
#include "../../../common/nujel/lib/allocation/roots.h"
#include "../../../common/nujel/lib/s-expression/writer.h"
#include "../../../common/nujel/lib/misc/pf.h"

#include <string.h>


M client/src/game/character.c => client/src/game/character.c +2 -2
@@ 348,7 348,7 @@ void characterDie(character *c){
	msgRequestPlayerSpawnPos();
	c->flags |= CHAR_SPAWNING;
	printf("Character Died\n");
	lispEval("[event-fire \"on-spawn\"]",false);
	lispCallFunc("on-spawn-fire", NULL);
}

static void updateGlide(character *c){


@@ 972,7 972,7 @@ void characterSetData(character *c, const packet *p){
	}
	connectionState = 2;
	c->flags &= ~CHAR_SPAWNING;
	lispEval("[event-fire \"on-join\"]",false);
	lispCallFunc("on-join-fire", NULL);
}

void characterSetName(const packet *p){

M client/src/game/throwable.c => client/src/game/throwable.c +0 -2
@@ 22,12 22,10 @@
#include "../../../common/src/misc/profiling.h"
#include "../../../common/src/network/messages.h"

#include <stdio.h>
void throwableNew(const vec pos, const vec rot, float speed, const item itm, being thrower, i8 damage, u8 flags){
	packet    *p = &packetBuffer;
	const uint counter = 0;
	const vec vel  = vecMulS(vecDegToVec(rot),speed);
	printf("Throwable new speed: %f\n",speed);

	p->v.u16[ 0] = 0;
	p->v.u16[ 1] = 0;

M client/src/main.c => client/src/main.c +2 -2
@@ 215,7 215,7 @@ void checkAutostart(){
	}
}

int main( int argc, char* argv[] ){
int main(int argc, char* argv[]){
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
	asmDetermineSupport();


@@ 248,7 248,7 @@ int main( int argc, char* argv[] ){

	itemTypeInit();
	recipeInit();
	lispCallFuncS("event-fire","on-init");
	lispCallFunc("on-init-fire", NULL);
	textureBuildBlockIcons(0);
	ropeInit();


M client/src/misc/lisp.c => client/src/misc/lisp.c +53 -40
@@ 52,7 52,7 @@
#include "../../../common/nujel/lib/nujel.h"
#include "../../../common/nujel/lib/exception.h"
#include "../../../common/nujel/lib/allocation/roots.h"
#include "../../../common/nujel/lib/s-expression/writer.h"
#include "../../../common/nujel/lib/misc/pf.h"

#include <ctype.h>
#include <stdarg.h>


@@ 61,8 61,8 @@

u8 SEvalID;

extern unsigned  int src_tmp_client_no_len;
extern unsigned char src_tmp_client_no_data[];
extern unsigned  int src_tmp_client_nuj_len;
extern unsigned char src_tmp_client_nuj_data[];

void lispInputHandler(lSymbol *input, int key, int action){
	const int SP = lRootsGet();


@@ 110,8 110,7 @@ static lVal *wwlnfSEval(lClosure *c, lVal *v){
	char buf[1<<14];
	memset(buf,0,sizeof(buf));
	const int SP = lRootsGet();
	lVal *l = RVP(lCons(RVP(lValSym("do")),v));
	lSWriteVal(l,buf,&buf[sizeof(buf)-1],0,false);
	spf(buf, &buf[sizeof(buf)-1], "%V", lCar(v));
	msgLispSExpr(-1,buf);
	lRootsRet(SP);
	return NULL;


@@ 188,47 187,59 @@ static lVal *wwlnfWindowed(lClosure *c, lVal *v){
	return NULL;
}

static lVal *wwlnfDebugInfo(lClosure *c, lVal *v){
	(void)c;
	if((v != NULL) && (v->type == ltPair)){
		optionDebugInfo = castToBool(lCar(v));
	}
static lVal *wwlnfDebugInfoGet(lClosure *c, lVal *v){
	(void)c; (void)v;
	return lValBool(optionDebugInfo);
}

static lVal *wwlnfConsMode(lClosure *c, lVal *v){
	(void)c;
	if((v != NULL) && (v->type == ltPair)){
		if(castToBool(lCar(v))){
			player->flags |=  CHAR_CONS_MODE;
		}else{
			player->flags &= ~CHAR_CONS_MODE;
		}
	}
static lVal *wwlnfDebugInfoSet(lClosure *c, lVal *v){
	(void)c; (void)v;
	optionDebugInfo = castToBool(lCar(v));
	return NULL;
}

static lVal *wwlnfConsModeGet(lClosure *c, lVal *v){
	(void)c; (void)v;
	return lValBool(player->flags & CHAR_CONS_MODE);
}

static lVal *wwlnfNoClip(lClosure *c, lVal *v){
static lVal *wwlnfConsModeSet(lClosure *c, lVal *v){
	(void)c;
	if((v != NULL) && (v->type == ltPair)){
		if(castToBool(lCar(v))){
			player->flags |=  CHAR_NOCLIP;
		}else{
			player->flags &= ~CHAR_NOCLIP;
		}
	if(castToBool(lCar(v))){
		player->flags |=  CHAR_CONS_MODE;
	}else{
		player->flags &= ~CHAR_CONS_MODE;
	}
	return NULL;
}

static lVal *wwlnfNoClipGet(lClosure *c, lVal *v){
	(void)c; (void)v;
	return lValBool(player->flags & CHAR_NOCLIP);
}

static lVal *wwlnfWireFrame(lClosure *c, lVal *v){
	(void)c;
	if((v != NULL) && (v->type == ltPair)){
		optionWireframe = castToBool(lCar(v));
		initGL();
static lVal *wwlnfNoClipSet(lClosure *c, lVal *v){
	(void)c; (void)v;
	if(castToBool(lCar(v))){
		player->flags |=  CHAR_NOCLIP;
	}else{
		player->flags &= ~CHAR_NOCLIP;
	}
	return NULL;
}

static lVal *wwlnfWireFrameGet(lClosure *c, lVal *v){
	(void)c; (void)v;
	return lValBool(optionWireframe);
}

static lVal *wwlnfWireFrameSet(lClosure *c, lVal *v){
	(void)c;
	optionWireframe = castToBool(lCar(v));
	initGL();
	return NULL;
}

static lVal *wwlnfScreenshot(lClosure *c, lVal *v){
	(void)c;(void)v;
	queueScreenshot = true;


@@ 729,7 740,7 @@ static lVal *wwlnfChatOpenSet(lClosure *c, lVal *v){
static void lispAddClientNFuncs(lClosure *c){
	lOperatorsWidget(c);

	lAddSpecialForm(c,"s",             "(...body)",         "Evaluates ...body on the serverside and returns the last result",wwlnfSEval);
	lAddNativeFunc(c,"s*",             "(form)",            "Evaluates form on the server and returns the last result",       wwlnfSEval);
	lAddNativeFunc(c,"text-focus?",    "()",                "Returns if a text input field is currently focused",             wwlnfTextInputFocusPred);
	lAddNativeFunc(c,"player-pos",     "()",                "Return players position",                                        wwlnfPlayerPos);
	lAddNativeFunc(c,"player-rot",     "()",                "Return players rotation",                                        wwlnfPlayerRot);


@@ 764,10 775,14 @@ static void lispAddClientNFuncs(lClosure *c){
	lAddNativeFunc(c,"window-height",  "()",                "Returns the height of the widow in pixels",                      wwlnfWindowHeight);
	lAddNativeFunc(c,"save-options",   "()",                "Save options to disk",                                           wwlnfSaveOptions);
	lAddNativeFunc(c,"reset-worst-f",  "()",                "Resets the worst frame counter",                                 wwlnfResetWorstFrame);
	lAddNativeFunc(c,"debug-info!",    "(b)",               "Sets debug info view to b",                                      wwlnfDebugInfo);
	lAddNativeFunc(c,"cons-mode!",     "(b)",               "Sets cons-mode to b if passed, always returns the current state",wwlnfConsMode);
	lAddNativeFunc(c,"no-clip!",       "(b)",               "Sets no clip to b if passed, always returns the current state",  wwlnfNoClip);
	lAddNativeFunc(c,"wire-frame!",    "(b)",               "Sets wireframe mode to b, always returns the current state",     wwlnfWireFrame);
	lAddNativeFunc(c,"debug-info!",    "(b)",               "Sets debug info view to b",                                      wwlnfDebugInfoSet);
	lAddNativeFunc(c,"debug-info?",    "()",                "Gets debug info view to b",                                      wwlnfDebugInfoGet);
	lAddNativeFunc(c,"cons-mode!",     "(b)",               "Sets cons-mode to b if passed, always returns the current state",wwlnfConsModeSet);
	lAddNativeFunc(c,"cons-mode?",     "()",                "Gets cons-mode to b if passed, always returns the current state",wwlnfConsModeGet);
	lAddNativeFunc(c,"no-clip!",       "(b)",               "Sets no clip to b if passed, always returns the current state",  wwlnfNoClipSet);
	lAddNativeFunc(c,"no-clip?",       "()",                "Gets no clip to b if passed, always returns the current state",  wwlnfNoClipGet);
	lAddNativeFunc(c,"wire-frame!",    "(b)",               "Sets wireframe mode to b, always returns the current state",     wwlnfWireFrameSet);
	lAddNativeFunc(c,"wire-frame?",    "()",                "Sets wireframe mode to b, always returns the current state",     wwlnfWireFrameGet);
	lAddNativeFunc(c,"send-message",   "(s)",               "Sends string s as a chat message",                               wwlnfSendMessage);
	lAddNativeFunc(c,"console-print",  "(s)",               "Prints string s to the REPL",                                    wwlnfConsolePrint);
	lAddNativeFunc(c,"sfx-play",       "(s &vol &pos)",     "Plays SFX S with volume &VOL=1.0 as if emitting from &POS.",     wwlnfSfxPlay);


@@ 812,9 827,7 @@ void *lispInitReal(void *a, void *b){
	(void)a; (void)b;

	clRoot = lispCommonRoot(lispAddClientNFuncs);
	lVal *expr = lRead((const char *)src_tmp_client_no_data);
	lnfDo(clRoot,expr);
	lGarbageCollect();
	lLoadS(clRoot, (const char *)src_tmp_client_nuj_data, src_tmp_client_nuj_len);

	return NULL;
}


@@ 833,7 846,7 @@ const char *lispEval(const char *str, bool humanReadable){
	memset(reply,0,sizeof(reply));

	lVal *v = lispCallFuncS("repl/console",str);
	lSWriteVal(v,reply,&reply[sizeof(reply)-1],0,humanReadable);
	spf(reply,&reply[sizeof(reply)-1],humanReadable ? "%v" : "%V", v);
	return reply;
}


M client/src/nujel/client.nuj => client/src/nujel/client.nuj +43 -93
@@ 2,100 2,83 @@
[def client? #t]
[def server? #f]

[test-add #t [string? OS]]
[test-add #t [and [not server?] client?]]
[event-bind on-spawn :snide-remarks [λ [] [say [ansi-yellow "Better luck next time!"]]]]
[event-bind on-join :greetings [λ []
            [yield [timeout 1000] [λ [] [say "Guten Tag!"]]]
            [yield [timeout 3000] [λ [] [say ["Press " [ansi-green "F2"] " for some equipment"]]]]
            [yield [timeout 5000] [λ [] [say ["Use your " [ansi-yellow "grappling hook"] " with " [ansi-green "E"]]]]]
            [yield [timeout 7000] [λ [] [say ["Open Inventory/Crafting panel with " [ansi-green "TAB"]]]]]]]

[test/add #t [string? OS]]
[test/add #t [and [not server?] client?]]

[defun gameplay-run []
        [event-fire on-gameplay-tick]]

[defmacro s forms
          "Run FORMS on the server"
          `[s* [quote ~[cons do forms]]]]

[defun player-active-item-id []
       "Return the Id of the currenlty selected item"
       [car [player-inventory [player-active-slot]]]
]
       [car [player-inventory [player-active-slot]]]]

[defun player-active-item-amount []
       "Return the Id of the currenlty selected item"
       [cdr [player-inventory [player-active-slot]]]
]
       [cdr [player-inventory [player-active-slot]]]]

[defun error [...args]
[defun error args
       "Print its arguments into the LISP console and might alert the user"
       [console-print ["  " [apply cat ...args]]]
]
       [console-print ["  " [apply cat args]]]]

[defun log [...args]
[defun log args
       "Print its arguments into the LISP console"
       [console-print ["  " [apply cat ...args]]]
]
       [console-print ["  " [apply cat args]]]]
[def print log]

[defun conf-v1! [@...body]
[defmacro conf-v1! body
       "Wrapper for auto generated config s-expressions, will be overwritten on every optionsave"
       [eval [cons 'begin @...body]]
]

[def help [let []
        [defun iter [l]
                [cond [[nil? l] #t]
                      [#t [log [describe [car l]]] [iter [cdr l]]
                ]]
        ]

        [λ [i]
                "Describes 10 functions at offset 1"
                [let [[off [* [int i] 10]]]
                        [iter [map cat [symbol-table off 10]]]
                        [log ["Help page " [int i] " of " [/ [symbol-count] 10]]]
                ]
                #t
        ]
]]
       `[eval [do ~@body]]]

[defun time/fast! [a]
        "Speeds up the game to about 4x"
        [mst!  1]
        [s [mst!  1]]
]
        [s [mst!  1]]]

[defun time/norm! [a]
        "Sets the game speed to the default 1x"
        [mst!  4]
        [s [mst!  4]]
]
        [s [mst!  4]]]

[defun time/slow! [a]
       "Sets the game speed to about 1/4x"
       [mst! 16]
       [s [mst! 16]]
]
       [s [mst! 16]]]

[defun time/bullet! [a]
        "Sets the game speed to about 1/16x"
        [mst! 64]
        [s [mst! 64]]
]
        [s [mst! 64]]]

[defun time/morning! []
        "Sets the Time to 8:00 AM"
        [s [time/morning!]]
]
        [s [time/morning!]]]

[defun time/noon! []
        "Sets the Time to 12:00 PM"
        [s [time/noon!]]
]
        [s [time/noon!]]]

[defun time/evening! []
       "Sets the Time to 21:30 PM"
       [s [time/evening!]]
]
       [s [time/evening!]]]

[defun time/night! []
       "Set the Time to Midnight"
       [s [time/night!]]
]
       [s [time/night!]]]

[defun animal-stress []
       "Generate a bunch of bunnies surrounding the player"
       [s [animal-stress [player-pos] 6]]
]
       [s [animal-stress [player-pos] 6]]]

[defun countdown [i]
       "Count down on the console"


@@ 104,67 87,34 @@
                             [[< i 4] [ansi-red i]]
                             [[< i 6] [ansi-yellow i]]
                             [#t i]]]
                 [yield [timeout 1000] [lambda []  [countdown [-- i]]]]]
       ]
]
                 [yield [timeout 1000] [λ []  [countdown [-- i]]]]]]]

[defun hammertime [i]
       "Spawn I countdown coroutines that run for 10 Minutes"
       [cond [[<= i 0] #t]
             [#t [countdown 600] [hammertime [-- i]]]
       ]
]
             [#t [countdown 600] [hammertime [-- i]]]]]

[defun chiseltime [i]
       "Spawn I coundown coroutines that run for 10 Seconds"
       [cond [[<= i 0] #t]
             [#t [countdown 5] [chiseltime [-- i]]]
       ]
]

[event-bind "on-spawn" [λ [] [say [ansi-yellow "Better luck next time!"]]]]
[event-bind "on-join" [λ []
        [say "Guten Tag!"]
        [say ["Press " [ansi-green "F2"] " for some equipment"]]
        [say ["Use your " [ansi-yellow "grappling hook"] " with " [ansi-green "E"]]]
        [say ["Open Inventory/Crafting panel with " [ansi-green "TAB"]]]
        ;[yield [timeout 10] [λ [] [pop]]]
]]

[defun gameplay-run []
        [event-fire "on-gameplay-tick"]
]
             [#t [countdown 5] [chiseltime [-- i]]]]]

[def inv-has-atleast? [let*
        [defun iter [id amount-goal i amount-found]
                [def slot [player-inventory i]]
                [when [eq? id [car slot]]
                 [def slot [player-inventory i]]
                [when [== id [car slot]]
                      [set! amount-found [+ amount-found [cdr slot]]]
                ]
                [if [>= amount-found amount-goal]
                    #t
                    [if [< i [player-inventory-size]]
                        [iter id amount-goal [+ 1 i] amount-found]
                        #f]]
        ]
                        #f]]]

        [λ [id amount-goal]
                [unless id [set! 0]]
                [unless amount-goal [set! 1]]
                [iter id amount-goal 0 0]
        ]
]]
                [when-not id [set! 0]]
                [when-not amount-goal [set! 1]]
                [iter id amount-goal 0 0]]]]

[defun game-active? []
       [eq? [widget/focus] w-game-screen]
]

[defun fltest []
       [fluid/box! #xFF
                   [- [vec/x [player-pos]] 4]
                   [- [vec/y [player-pos]] 4]
                   [- [vec/z [player-pos]] 4]
                   [+ [vec/x [player-pos]] 4]
                   [+ [vec/y [player-pos]] 4]
                   [+ [vec/z [player-pos]] 4]]
]
       [== [widget/focus] w-game-screen]]

M client/src/nujel/input.nuj => client/src/nujel/input.nuj +2 -2
@@ 14,7 14,7 @@
                "Make the player do a primary action"

                [let [[itemid [player-active-item-id]]]
                        [if [< itemid 256] [player-do-primary!] [unless [item-primary! itemid] [player-do-primary!]]]
                        [if [< itemid 256] [player-do-primary!] [when-not [item-primary! itemid] [player-do-primary!]]]
                ]

                [set! did-primary #t]


@@ 66,7 66,7 @@

                [when [not did-primary] [player-stop-mining!]]
                [when did-primary [set! did-primary #f]]
                [when [and [not did-throw] [ineq? throw-start 0]] [player-do-throw! [- [time/milliseconds] throw-start]]]
                [when [and [not did-throw] [!= throw-start 0]] [player-do-throw! [- [time/milliseconds] throw-start]]]
                [set! did-throw #f]
        ]]
]

M client/src/nujel/input_keyboard.nuj => client/src/nujel/input_keyboard.nuj +49 -49
@@ 1,5 1,5 @@
[def input-keyboard-handler [arr-new 256]]
[def input-keyboard-state   [arr-new 256]]
[def input-keyboard-handler [array/allocate 256]]
[def input-keyboard-state   [array/allocate 256]]

[def key-a  4]
[def key-b  5]


@@ 77,7 77,7 @@

[defun input-keyboard-handler-default [code value]
        "Default handler to be used for continuously firing actions"
        [arr-set! input-keyboard-state code [> value 0]]
        [array/set! input-keyboard-state code [> value 0]]
]

[defun toggle-chat! []


@@ 89,9 89,9 @@
        "Run FUN only once per keypress"
        [λ [code value]
           [if [zero? value]
               [arr-set! input-keyboard-state code #f]
               [array/set! input-keyboard-state code #f]
               [when [not [input-keyboard-state code]]
                     [arr-set! input-keyboard-state code #t]
                     [array/set! input-keyboard-state code #t]
                     [fun]]]
        ]
]


@@ 101,39 101,39 @@
       [λ [code value]
          [if [game-active?]
              [handler code value]
              [arr-set! input-keyboard-state code #f]]
              [array/set! input-keyboard-state code #f]]
       ]
]

[arr-set! input-keyboard-handler key-r      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-q      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-space  input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-w      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-a      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-s      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-d      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-v      input-keyboard-handler-default]
[arr-set! input-keyboard-handler key-lshift input-keyboard-handler-default]

[arr-set! input-keyboard-handler key-c     [keyboard-once-game-active [λ [] [cons-mode!  [not [cons-mode!]]]]]]
[arr-set! input-keyboard-handler key-e     [keyboard-once-game-active [λ [] [fire-hook]]]]
[arr-set! input-keyboard-handler key-m     [keyboard-once [λ [] [debug-info! [not [debug-info!]]]]]]
[arr-set! input-keyboard-handler key-n     [keyboard-once-game-active [λ [] [no-clip! [not [no-clip!]]]]]]

[arr-set! input-keyboard-handler key-f1    [keyboard-once [λ [] [third-person! #f] [save-options]]]]
[arr-set! input-keyboard-handler key-f2    [keyboard-once [λ [] [s [debug-stuff! pid]]]]]
[arr-set! input-keyboard-handler key-f3    [keyboard-once [λ [] [third-person! #t] [save-options]]]]
[arr-set! input-keyboard-handler key-f4    [keyboard-once [λ [] [widget/test-gc]]]]
[arr-set! input-keyboard-handler key-f8    [keyboard-once [λ [] [player-hp 12]]]]
[arr-set! input-keyboard-handler key-f9    [keyboard-once [λ [] [draw-boundaries! [wrap-value [++ [draw-boundaries]] 0 3]]]]]
[arr-set! input-keyboard-handler key-f10   [keyboard-once [λ [] [wire-frame! [not [wire-frame?]]]]]]
[arr-set! input-keyboard-handler key-print [keyboard-once [λ [] [screenshot]]]]
[arr-set! input-keyboard-handler key-tab   [keyboard-once [λ [] [toggle-inventory!]]]]
[arr-set! input-keyboard-handler key-t     [keyboard-once [λ [] [toggle-chat!]]]]
[arr-set! input-keyboard-handler key-y     [keyboard-once [λ [] [toggle-chat!]]]]

[unless [eq? OS "Emscripten"]
        [arr-set! input-keyboard-handler key-f11 [λ [code value]
[array/set! input-keyboard-handler key-r      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-q      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-space  input-keyboard-handler-default]
[array/set! input-keyboard-handler key-w      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-a      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-s      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-d      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-v      input-keyboard-handler-default]
[array/set! input-keyboard-handler key-lshift input-keyboard-handler-default]

[array/set! input-keyboard-handler key-c     [keyboard-once-game-active [λ [] [cons-mode! [not [cons-mode?]]]]]]
[array/set! input-keyboard-handler key-e     [keyboard-once-game-active [λ [] [fire-hook]]]]
[array/set! input-keyboard-handler key-m     [keyboard-once [λ [] [println "Consing"] [debug-info! [not [debug-info?]]]]]]
[array/set! input-keyboard-handler key-n     [keyboard-once-game-active [λ [] [no-clip! [not [no-clip?]]]]]]

[array/set! input-keyboard-handler key-f1    [keyboard-once [λ [] [third-person! #f] [save-options]]]]
[array/set! input-keyboard-handler key-f2    [keyboard-once [λ [] [s [debug-stuff! pid]]]]]
[array/set! input-keyboard-handler key-f3    [keyboard-once [λ [] [third-person! #t] [save-options]]]]
[array/set! input-keyboard-handler key-f4    [keyboard-once [λ [] [widget/test-gc]]]]
[array/set! input-keyboard-handler key-f8    [keyboard-once [λ [] [player-hp 12]]]]
[array/set! input-keyboard-handler key-f9    [keyboard-once [λ [] [draw-boundaries! [wrap-value [++ [draw-boundaries]] 0 3]]]]]
[array/set! input-keyboard-handler key-f10   [keyboard-once [λ [] [wire-frame! [not [wire-frame?]]]]]]
[array/set! input-keyboard-handler key-print [keyboard-once [λ [] [screenshot]]]]
[array/set! input-keyboard-handler key-tab   [keyboard-once [λ [] [toggle-inventory!]]]]
[array/set! input-keyboard-handler key-t     [keyboard-once [λ [] [toggle-chat!]]]]
[array/set! input-keyboard-handler key-y     [keyboard-once [λ [] [toggle-chat!]]]]

[when-not [== OS "Emscripten"]
          [array/set! input-keyboard-handler key-f11 [λ [code value]
                [when value
                        [fullscreen! [not [fullscreen?]]]
                        [save-options]


@@ 150,16 150,16 @@
        ]
]

[arr-set! input-keyboard-handler key-1 inv-active-kh]
[arr-set! input-keyboard-handler key-2 inv-active-kh]
[arr-set! input-keyboard-handler key-3 inv-active-kh]
[arr-set! input-keyboard-handler key-4 inv-active-kh]
[arr-set! input-keyboard-handler key-5 inv-active-kh]
[arr-set! input-keyboard-handler key-6 inv-active-kh]
[arr-set! input-keyboard-handler key-7 inv-active-kh]
[arr-set! input-keyboard-handler key-8 inv-active-kh]
[arr-set! input-keyboard-handler key-9 inv-active-kh]
[arr-set! input-keyboard-handler key-0 inv-active-kh]
[array/set! input-keyboard-handler key-1 inv-active-kh]
[array/set! input-keyboard-handler key-2 inv-active-kh]
[array/set! input-keyboard-handler key-3 inv-active-kh]
[array/set! input-keyboard-handler key-4 inv-active-kh]
[array/set! input-keyboard-handler key-5 inv-active-kh]
[array/set! input-keyboard-handler key-6 inv-active-kh]
[array/set! input-keyboard-handler key-7 inv-active-kh]
[array/set! input-keyboard-handler key-8 inv-active-kh]
[array/set! input-keyboard-handler key-9 inv-active-kh]
[array/set! input-keyboard-handler key-0 inv-active-kh]

[defun input-keyboard-tick []
        "Keyboard input handler"


@@ 184,7 184,7 @@
         #f]
]

[test-add #t [int? key-1]]
[test-add #t [arr? input-keyboard-handler]]
[test-add 58 key-f1]
[test-add #t [bool? [widget-focus-on-game?]]]
[test/add #t [int? key-1]]
[test/add #t [arr? input-keyboard-handler]]
[test/add 58 key-f1]
[test/add #t [bool? [widget-focus-on-game?]]]

M client/src/nujel/input_mouse.nuj => client/src/nujel/input_mouse.nuj +4 -4
@@ 1,4 1,4 @@
[def input-mouse-handler [arr-new 6]]
[def input-mouse-handler [array/allocate 6]]
[def input-mouse-tick]

[let []


@@ 10,14 10,14 @@
                [when input-mouse-button-right [player-secondary!]]
        ]]

        [arr-set! input-mouse-handler 0 [λ [code value]
        [array/set! input-mouse-handler 0 [λ [code value]
                [when [widget-focus-on-game?] [set! input-mouse-button-left [> value 0]]]
        ]]
        [arr-set! input-mouse-handler 2 [λ [code value]
        [array/set! input-mouse-handler 2 [λ [code value]
                [when [widget-focus-on-game?] [set! input-mouse-button-right [> value 0]]]
        ]]

        [arr-set! input-mouse-handler 5 [λ [code value]
        [array/set! input-mouse-handler 5 [λ [code value]
                [when [widget-focus-on-game?]
                        [let [[newvalue [- [player-active-slot] [if [> value 0] 1 -1]]]]
                                [when [< newvalue 0] [set! newvalue 9]]

D client/src/nujel/quest.nuj => client/src/nujel/quest.nuj +0 -239
@@ 1,239 0,0 @@
[def quests #nil]
[def quest/panels #nil]

[defun duration-to-clock-string [secs]
     [cat [string [/ secs 60]] [if [zero? [logand secs 1]] " " ":"] [% secs 60]]
]

[defun quest/panel/position! []
     [def y 64]
     [for-each [λ [cur-panel]
                  [widget/y! cur-panel y]
                  [set! y [+ y [widget/height cur-panel] 8]]
               ]
               quest/panels]
]

[defun quest/panel/remove! [panel]
     [set! quest/panels
           [filter [λ [cur-panel]
                      [!= cur-panel panel]]
                   quest/panels]]
]

[defun quest/panel/new! [headline bodytext wid panel-height]
     [when-not panel-height [def panel-height 120]]
     [def panel   [widget/new w-panel]]
     [def head    [widget/new w-label]]
     [def text    [widget/new w-label]]

     [def wid-height 0]
     [when wid [set! wid-height [+ 8 [widget/height wid]]]]

     [widget/parent! panel w-game-screen]
     [widget/x!      panel  -8]
     [widget/y!      panel   8]
     [widget/width!  panel 320]
     [widget/height! panel [+ panel-height wid-height]]
     [widget/val/int! panel 8]

     [widget/parent! head panel]
     [widget/width!  head  -1]
     [widget/height! head  64]
     [widget/label!  head headline]

     [widget/parent! text panel]
     [widget/y!      text  48]
     [widget/width!  text  -1]
     [widget/height! text [- -48 wid-height]]
     [widget/flags!  text wf-small]
     [widget/label!  text bodytext]

     [when wid
           [widget/parent! wid panel]
           [widget/y! 120]
           [widget/x! 8]
           [widget/width! -1]
     ]

     [set! quest/panels [cons panel quest/panels]]
     [quest/panel/position!]
     panel
]

[def quest/default [ω
        [def active #f]
        [def finished #f]
        [def name "Default Quest"]
        [def body "Placeholder for some descriptive text"]
        [def refresh! [λ [] #f]]
        [def active? [λ [] #f]]
        [def active! [δ []
                       [say [cat [ansi-yellow "New Quest: "] name]]
        ]]
        [def finish? [λ [] #f]]
        [def finish! [δ []
                       [say [cat [ansi-green "Quest finished: "] name]]
        ]]
        [def check-finished! [δ []
                [when [finish?]
                      [finish!]
                      [set! finished #t]]
        ]]
        [def check-active! [δ []
                [when [active?]
                      [active!]
                      [set! active #t]]
        ]]
]]

[defun quest/new [@...args]
        "Create a new quest object"
        [def ret [quest/default [ω]]]
        [apply ret '[[def active #f] [def finished #f]]]
        [apply ret @...args]
        [set! quests [cons ret quests]]
        ret
]

[def quest-test-time [quest/new
        [def name [cat "Staying alive for " [ansi-red "300"] " Seconds"]]
        [def body ["As your first task you have to stay alive for just " [ansi-red "300"] " seconds, hopefully you can achieve this goals and continue onwards on your adventures. Best of luck there, adventurer!"]]
        [def panel]
        [def quest-start 0]
        [def progress-widget]
        [def refresh! [λ []
                        [widget/label! progress-widget
                                       [ duration-to-clock-string[/ [[quest-start + 300000] - [time/milliseconds]] 1000]]]
                        [def progress [[[time/milliseconds] - quest-start] / 300000.0]]
                        [widget/val/int! progress-widget
                                         [int [progress * 4096.0]]]
        ]]
        [def finished #f]
        [def finish? [λ []
                       [[widget/val/int progress-widget] >= 4080]
        ]]
        [def finish! [λ []
                [[[self 1] finish!]]
                [widget/parent! panel #nil]
                [quest/panel/remove! panel]
                [set! panel #nil]
                [quest/panel/position!]
        ]]
        [def active? [λ [] #t]]
        [def active! [λ []
                [[[self 1] active!]]
                [set! quest-start [time/milliseconds]]

                [set! progress-widget [widget/new w-slider]]
                [widget/height! progress-widget 32]
                [widget/width! progress-widget -1]
                [widget/y! progress-widget -1]
                ;[widget/label! progress-widget ""]
                [set! panel [quest/panel/new! name body progress-widget]]
        ]]
]]

[defun player-inventory-fetch-string [id name goal-amount]
  [[if [>= [player-ingredient-get id] goal-amount]
       ansi-green
       cat] [int [player-ingredient-get id]] " / " goal-amount " - " name]
]

[def quest-test-fetch [quest/new
        [def name "Gather material for a Pickaxe"]
        [def body ["To help you on your journey, building a pickaxe should make mining much more convenient. To build a pickaxe you need 2 wooden boards, 4 stones and 2 plantmatter." ]]
        [def panel]
        [def progress-widget]
        [def finish! [λ []
                        [[[self 1] finish!]]
                        [widget/parent! panel #nil]
                        [quest/panel/remove! panel]
                        [quest/panel/position!]
                        [set! panel #nil]
        ]]
        [def refresh! [λ []
                        [widget/label! progress-widget
                                       [cat [player-inventory-fetch-string i-boards "Boards" 2] "\n"
                                            [player-inventory-fetch-string i-stone "Stones" 4] "\n"
                                            [player-inventory-fetch-string i-plantmatter "Plants" 2]]]
        ]]
        [def finish? [λ []
                       [and [[player-ingredient-get i-boards] >= 2]
                            [[player-ingredient-get i-stone] >= 4]
                            [[player-ingredient-get i-plantmatter] >= 2]]
        ]]
        [def active? [λ [] #t]]
        [def active! [λ []
                       [[[self 1] active!]]

                       [set! progress-widget [widget/new w-label]]
                       [widget/height! progress-widget 96]
                       [widget/width! progress-widget  -1]
                       [widget/y! progress-widget -8]
                       [widget/x! progress-widget  0]
                       [refresh!]
                       [set! panel [quest/panel/new! name body progress-widget 140]]
        ]]
]]

[def quest-test-fetch [quest/new
        [def name "Build a stone Pickaxe"]
        [def body ["Now use the gathered materials to build your first tool, a pickaxe." ]]
        [def panel]
        [def progress-widget]
        [def finish! [λ []
                        [[[self 1] finish!]]
                        [widget/parent! panel #nil]
                        [quest/panel/remove! panel]
                        [quest/panel/position!]
                        [set! panel #nil]
        ]]
        [def refresh! [λ []
                        [widget/label! progress-widget [player-inventory-fetch-string i-stone-pickaxe "Pickaxe" 1]]
        ]]
        [def finish? [λ []
                       [[player-ingredient-get i-stone-pickaxe] >= 1]
        ]]
        [def active? [λ [] #t]]
        [def active! [λ []
                       [[[self 1] active!]]

                       [set! progress-widget [widget/new w-label]]
                       [widget/height! progress-widget 48]
                       [widget/width! progress-widget  -1]
                       [widget/y! progress-widget -8]
                       [widget/x! progress-widget  0]
                       [refresh!]
                       [set! panel [quest/panel/new! name body progress-widget]]
        ]]
]]

[defun quest/refresh []
        [def l quests]
        [def cur #nil]
        [while l
               [try repl/exception-handler
                    [set! cur [car l]]
                    [if [cur active]
                        [unless [cur finished] [cur [check-finished!]] [[cur refresh!]] ]
                        [cur [check-active!]]]
               ]
               [set! l [cdr l]]
        ]
]

[event-bind "on-join" [λ []
        ;[quest/refresh]
]]

[event-bind "on-gameplay-tick" [λ []
        ;[quest/refresh]
]]

[event-bind "on-leave" [λ []
            [println "Test"]
            [for-each [λ [panel] [widget/parent! panel #nil]] quest/panels]
            [set! quests #nil]
            [set! quest/panels #nil]
]]

M common/common.mk => common/common.mk +6 -1
@@ 1,7 1,7 @@
ARCH             := $(shell uname -m)
NUJ_WWLIB        := $(shell find common/src/nuj/ -type f -name '*.nuj' | sort)
NO_WWLIB         := $(NUJ_WWLIB:.nuj=.no)
COMMON_ASSETS    := common/src/tmp/wwlib.no
COMMON_ASSETS    := common/src/tmp/wwlib.nuj
COMMON_HDRS      := $(shell find common/src -type f -name '*.h')
COMMON_SRCS      := $(shell find common/src -type f -name '*.c')
COMMON_OBJS      := ${COMMON_SRCS:.c=.o}


@@ 48,6 48,11 @@ common/src/tmp/wwlib.no: $(NO_WWLIB)
	@cat $^ > $@
	@echo "$(ANSI_GREY)" "[CAT]" "$(ANSI_RESET)" $@

common/src/tmp/wwlib.nuj: $(NUJ_WWLIB)
	@mkdir -p common/src/tmp
	@cat $^ > $@
	@echo "$(ANSI_GREY)" "[CAT]" "$(ANSI_RESET)" $@

common/src/tmp/assets.c: $(ASSET) $(COMMON_ASSETS)
	@mkdir -p common/src/tmp/
	@$(ASSET) common/src/tmp/assets $(COMMON_ASSETS)

M common/nujel => common/nujel +1 -1
@@ 1,1 1,1 @@
Subproject commit 03467bc2661b7ca3e4ba5484d88743417cc3717b
Subproject commit 51ba3c74685e68e5c5a3ebcc64901521e6f606fa

M common/src/misc/lisp.c => common/src/misc/lisp.c +51 -17
@@ 31,8 31,8 @@
#include "../../nujel/lib/exception.h"
#include "../../nujel/lib/allocation/roots.h"

extern unsigned  int src_tmp_wwlib_no_len;
extern unsigned char src_tmp_wwlib_no_data[];
extern uint src_tmp_wwlib_nuj_len;
extern u8   src_tmp_wwlib_nuj_data[];

#include <ctype.h>
#include <string.h>


@@ 183,6 183,20 @@ static lVal *wwlnfFluidSet(lClosure *c, lVal *v){
	return lCar(v);
}

static lVal *wwlnfPrint(lClosure *c, lVal *v){
	(void)c;
	if(v == NULL){return v;}
	lWriteVal(lCar(v));
	return NULL;
}

static lVal *wwlnfError(lClosure *c, lVal *v){
	(void)c;
	if(v == NULL){return v;}
	lDisplayErrorVal(lCar(v));
	return NULL;
}

void lispDefineInt(const char *symbol, int val){
	lDefineVal(clRoot,symbol,lValInt(val));
}


@@ 194,9 208,11 @@ void lispDefineString(const char *symbol, char *str){
void *lispCommonRootReal(void *a, void *b){
	(void)a; (void)b;
	lInit();
	lClosure *c = lClosureNewRoot();
	lClosure *c = lNewRoot();
	void (*specificInit)(lClosure *c) = (void (*)(lClosure *))a;

	lAddNativeFunc(c,"error",           "args",                   "Prints ...args to stderr",                                   wwlnfError);
	lAddNativeFunc(c,"print",           "args",                   "Displays ...args",                                           wwlnfPrint);
	lAddNativeFunc(c,"mst!",            "(a)",                    "Set ms per tick to s",                                       wwlnfMsPerTick);
	lAddNativeFunc(c,"prof",            "()",                     "Return profiler info",                                       wwlnfProf);
	lAddNativeFunc(c,"prof-reset!",     "()",                     "Reset performance counters",                                 wwlnfProfReset);


@@ 221,8 237,7 @@ void *lispCommonRootReal(void *a, void *b){
	itemTypeLispClosure(c);
	specificInit(c);

	lVal *expr = lRead((const char *)src_tmp_wwlib_no_data);
	lnfDo(c,expr);
	lLoadS(c,(const char *)src_tmp_wwlib_nuj_data, src_tmp_wwlib_nuj_len);

	return c;
}


@@ 237,19 252,32 @@ void *lispCallFuncReal(void *closure, void *vv){
	return lEval(c,v);
}

lVal *lispCallFunc(const char *symbol, lVal *v){
	const int SP = lRootsGet();
	lVal *form = RVP(lCons(NULL,NULL));
	form->vList.car = lValSym(symbol);
	form->vList.cdr = lCons(v, NULL);

	lVal *ret = lExceptionTry(lispCallFuncReal,clRoot,form);
	lRootsRet(SP);
	return ret;
}

lVal *lispCallFuncI(const char *symbol, int ia){
	lVal *form = lCons(NULL,NULL);
	lRootsValPush(form);
	const int SP = lRootsGet();
	lVal *form = RVP(lCons(NULL,NULL));
	form->vList.car = lValSym(symbol);
	lVal *l = form->vList.cdr = lCons(NULL,NULL);
	l->vList.car = lValInt(ia);

	return lExceptionTry(lispCallFuncReal,clRoot,form);
	lVal *ret = lExceptionTry(lispCallFuncReal,clRoot,form);
	lRootsRet(SP);
	return ret;
}

lVal *lispCallFuncIII(const char *symbol, int ia, int ib, int ic){
	lVal *form = lCons(NULL,NULL);
	lRootsValPush(form);
	const int SP = lRootsGet();
	lVal *form = RVP(lCons(NULL,NULL));
	form->vList.car = lValSym(symbol);
	lVal *l = form->vList.cdr = lCons(NULL,NULL);
	l->vList.car = lValInt(ia);


@@ 260,22 288,26 @@ lVal *lispCallFuncIII(const char *symbol, int ia, int ib, int ic){
	l = l->vList.cdr;
	l->vList.car = lValInt(ic);

	return lExceptionTry(lispCallFuncReal,clRoot,form);
	lVal *ret = lExceptionTry(lispCallFuncReal,clRoot,form);
	lRootsRet(SP);
	return ret;
}

lVal *lispCallFuncS(const char *symbol, const char *str){
	lVal *form = lCons(NULL,NULL);
	lRootsValPush(form);
	const int SP = lRootsGet();
	lVal *form = RVP(lCons(NULL,NULL));
	form->vList.car = lValSym(symbol);
	lVal *l = form->vList.cdr = lCons(NULL,NULL);
	l->vList.car = lValString(str);

	return lExceptionTry(lispCallFuncReal,clRoot,form);
	lVal *ret = lExceptionTry(lispCallFuncReal,clRoot,form);
	lRootsRet(SP);
	return ret;
}

lVal *lispCallFuncVII(const char *symbol,const vec va, int ib , int ic){
	lVal *form = lCons(NULL,NULL);
	lRootsValPush(form);
	const int SP = lRootsGet();
	lVal *form = RVP(lCons(NULL,NULL));
	form->vList.car = lValSym(symbol);
	lVal *l = form->vList.cdr = lCons(NULL,NULL);
	l->vList.car = lValVec(va);


@@ 286,7 318,9 @@ lVal *lispCallFuncVII(const char *symbol,const vec va, int ib , int ic){
	l = l->vList.cdr;
	l->vList.car = lValInt(ic);

	return lExceptionTry(lispCallFuncReal,clRoot,form);
	lVal *ret = lExceptionTry(lispCallFuncReal,clRoot,form);
	lRootsRet(SP);
	return ret;
}

void lispDefineID(const char *prefix, const char *symbol, int val){

M common/src/misc/lisp.h => common/src/misc/lisp.h +9 -8
@@ 4,12 4,13 @@

extern lClosure *clRoot;

lClosure *lispCommonRoot  ();
void      lispDefineInt   (const char *symbol, int val);
void      lispDefineString(const char *symbol, char *str);
lVal     *lispCallFuncI   (const char *symbol, int ia);
lVal     *lispCallFuncIII (const char *symbol, int ia, int ib, int ic);
lVal     *lispCallFuncS   (const char *symbol, const char *str);
lVal     *lispCallFuncVII (const char *symbol, const vec va, int ib, int ic);
lClosure *lispCommonRoot   ();
void      lispDefineInt    (const char *symbol, int val);
void      lispDefineString (const char *symbol, char *str);
lVal     *lispCallFunc     (const char *symbol, lVal *v);
lVal     *lispCallFuncI    (const char *symbol, int ia);
lVal     *lispCallFuncIII  (const char *symbol, int ia, int ib, int ic);
lVal     *lispCallFuncS    (const char *symbol, const char *str);
lVal     *lispCallFuncVII  (const char *symbol, const vec va, int ib, int ic);

void     *lispCallFuncReal(void *closure, void *vv);
void     *lispCallFuncReal (void *closure, void *vv);

M common/src/nuj/_init.nuj => common/src/nuj/_init.nuj +15 -14
@@ 1,10 1,10 @@
; Contains definitions needed in the other .nuj files

[def on-init  '[]]
[def on-spawn '[]]
[def on-join  '[]]
[def on-leave '[]]
[def on-gameplay-tick '[]]
[def on-init          @[]]
[def on-spawn         @[]]
[def on-join          @[]]
[def on-leave         @[]]
[def on-gameplay-tick @[]]

[def cat-none   0]
[def cat-dirt   1]


@@ 25,22 25,23 @@
[def anim-eat       4]
[def anim-switch    5]

[event-bind "on-init" [λ []
[defun on-init-fire  [] [event-fire on-init]]
[defun on-spawn-fire [] [event-fire on-spawn]]
[defun on-join-fire  [] [event-fire on-join]]
[defun on-leave-fire [] [event-fire on-leave]]

[event-bind on-init :test-run [λ []
	[log [ansi-blue "Let's test the Nujel Runtime"]]
	[test-run]
]]
	[test-run]]]

[def vx+ [λ [v a]
	"Return the sum of vector v and [vec a 0 0]"
	[+ v [vec a 0 0]]
]]
	[+ v [vec a 0 0]]]]

[def vy+ [λ [v a]
	"Return the sum of vector v and [vec 0 a 0]"
	[+ v [vec 0 a 0]]
]]
	[+ v [vec 0 a 0]]]]

[def vz+ [λ [v a]
	"Return the sum of vector v and [vec 0 0 a]"
	[+ v [vec 0 0 a]]
]]
	[+ v [vec 0 0 a]]]]

M common/src/nuj/beings.nuj => common/src/nuj/beings.nuj +3 -3
@@ 1,6 1,6 @@
; Contains defines having to do with all kinds of beings, mostly players

[def player-die [λ [&player]
[defun player-die [player]
	"Orders PLAYER=pid to Die"
	[player-dmg 8192 &player]
]]
	[player-dmg 8192 player]
]

M common/src/nuj/io.nuj => common/src/nuj/io.nuj +4 -30
@@ 1,30 1,4 @@
[def say [λ [...args]
	"Sends ...ARGS as a chat message"
	[send-message [apply cat ...args]]
]]

[def display/error [let*
        [def wrap [λ [i text]
                [cond [[eq? i 0] [ansi-red text]]
                      [[eq? i 1] text]
                      [[eq? i 2] [ansi-yellow text]]
                      [#t text]
                ]
        ]]

        [def iter [λ [error i]
                [if error
                    [cons [wrap i [string [car error]]]
                          [iter [cdr error] [++ i]]]
                    [cons "" #nil]]
        ]]

        [λ [error]
                "Display ERROR in a nice, human readable way"
                [say [join [iter error 0] "\n"]]
        ]
]]

[def repl/exception-handler [λ [error]
        [display/error error]
]]
[defun say args
       "Sends ...ARGS as a chat message"
       [send-message [apply cat args]]
]

M common/src/nuj/items.nuj => common/src/nuj/items.nuj +537 -791
@@ 1,73 1,60 @@
[def items [arr-new 256]]
[def items [array/allocate 256]]

[def item-new-id [let [[item-cur-id 256]]
        [λ []
                "Return an unused item ID"
                [set! item-cur-id [+ item-cur-id 1]]
                [- item-cur-id 1]
        ]
]]

[def item-sync [λ [obj] "Syncs the itemType with the ω OBJ"
        [unless [nil? obj]
                [it-name [obj id] [obj name]]
                [it-fire-health [obj id] [obj fire-health]]
                [it-fire-damage [obj id] [obj fire-dmg]]
                [it-ammunition [obj id] [resolve [obj ammunition]]]
                [it-mesh [obj id] [resolve [obj mesh]]]
                [it-damage [obj id] cat-none [obj dmg]]
                [it-damage [obj id] cat-dirt [obj dmg-dirt]]
                [it-damage [obj id] cat-stone [obj dmg-stone]]
                [it-damage [obj id] cat-wood [obj dmg-wood]]
                [it-damage [obj id] cat-leaves [obj dmg-leaves]]
                [it-inaccuracy [obj id] [obj inaccuracy]]
                [it-mag-size [obj id] [obj mag-size]]
                [it-stack-size [obj id] [obj stack-size]]
                [it-item-drop-cb [obj id] [obj drop-chance]]

                [it-sprite-id [obj id] 0 [obj sprite-id-0]]
                [it-sprite-id [obj id] 1 [obj sprite-id-1]]
                [it-sprite-id [obj id] 2 [obj sprite-id-2]]
                [it-sprite-id [obj id] 3 [obj sprite-id-3]]
                [it-sprite-color [obj id] 0 [obj sprite-color-0]]
                [it-sprite-color [obj id] 1 [obj sprite-color-1]]
                [it-sprite-color [obj id] 2 [obj sprite-color-2]]
                [it-sprite-color [obj id] 3 [obj sprite-color-3]]

                [it-weight [obj id] [obj weight]]

                [set! [obj sym] [obj id]]
                [arr-set! items [- [obj id] 256] obj]
        ]
]]

[def item-sync-all [λ [i] "Syncs all itemTypes with their respective ω"
        [cond [[> i [arr-length items]] #t]
              [#t [item-sync [items [int i]]] [item-sync-all [+ i 1]]]
        ]
]]

[def item-primary! [λ [id] "Evaluates the primary callback of item ID"
        [cond [[procedure? [[items [- id 256]] primary]] [[[items [- id 256]] primary]]]
              [#t #f]
        ]
]]
                [- item-cur-id 1]]]]

[defun item-sync [obj]
       "Syncs the itemType with the ω OBJ"
       [it-name [obj id] [obj name]]
       [it-fire-health [obj id] [obj fire-health]]
       [it-fire-damage [obj id] [obj fire-dmg]]
       [it-ammunition [obj id] [resolve [obj ammunition]]]
       [it-mesh [obj id] [resolve [obj mesh]]]
       [it-damage [obj id] cat-none [obj dmg]]
       [it-damage [obj id] cat-dirt [obj dmg-dirt]]
       [it-damage [obj id] cat-stone [obj dmg-stone]]
       [it-damage [obj id] cat-wood [obj dmg-wood]]
       [it-damage [obj id] cat-leaves [obj dmg-leaves]]
       [it-inaccuracy [obj id] [obj inaccuracy]]
       [it-mag-size [obj id] [obj mag-size]]
       [it-stack-size [obj id] [obj stack-size]]
       [it-item-drop-cb [obj id] [obj drop-chance]]

       [it-sprite-id [obj id] 0 [obj sprite-id-0]]
       [it-sprite-id [obj id] 1 [obj sprite-id-1]]
       [it-sprite-id [obj id] 2 [obj sprite-id-2]]
       [it-sprite-id [obj id] 3 [obj sprite-id-3]]
       [it-sprite-color [obj id] 0 [obj sprite-color-0]]
       [it-sprite-color [obj id] 1 [obj sprite-color-1]]
       [it-sprite-color [obj id] 2 [obj sprite-color-2]]
       [it-sprite-color [obj id] 3 [obj sprite-color-3]]

       [it-weight [obj id] [obj weight]]]

[defun item-sync-all [i]
       "Syncs all itemTypes with their respective ω"
       [for [i 0 [array/length items]]
            [def itm [array/ref items i]]
            [when itm [item-sync itm]]]]

[defun item-primary! [id]
       "Evaluates the primary callback of item ID"
       [cond [[procedure? [[items [- id 256]] primary]] [[[items [- id 256]] primary]]]
             [#t #f]]]

[def item-secondary! [λ [id] "Evaluates the secondary callback of item ID"
        [cond [[procedure? [[items [- id 256]] secondary]] [[[items [- id 256]] secondary]]]
              [#t #f]
        ]
]]
              [#t #f]]]]

[def item-tertiary! [λ [id] "Evaluates the tertiary callback of item ID"
        [cond [[procedure? [[items [- id 256]] tertiary]] [[[items [- id 256]] tertiary]]]
              [#t #f]
        ]
]]
              [#t #f]]]]

[def add-inaccuracy [λ [amt] "Increase players inaccuracy my AMT"
        [inaccuracy [+ [inaccuracy] amt]]
]]
        [inaccuracy [+ [inaccuracy] amt]]]]

[def do-eat [λ [hp itemid] "Make the player Eat and restores HP health over time"
        [cond [[ineq? itemid [player-active-item-id]] #t]


@@ 79,28 66,20 @@
                [player-hp [+ [player-hp] 1]]
                [start-anim anim-eat 800]
                [sfx-play sfx-chomp]
                #t]
        ]
]]
                #t]]]]

[def item-burn-up [λ [pos id amount] "Calls the specific burn up handler that AMOUNT ID items have burned up at POS"
     [cond [[procedure? [items [- id 256]] burn-up] [[[items [- id 256]] burn-up]]
                                                    [[[items [- id 256]] burn-up] pos id amount]]
               [#t #f]
        ]
]]
           [#t #f]]]]

[def item-drop-cb [λ [pos id amount] "Calls the specific drop handler that AMOUNT ID items are dropped at POS, only gets called when the a random value masked by chance equals 0"
        [cond [[procedure? [[items [- id 256]] drop-handler]] [[[items [- id 256]] drop-handler] pos id amount]]
              [#t 0]
        ]
]]
              [#t 0]]]]

[def shotgun-shot [λ [i] "Shoots I shots"
        [cond [[<= i 0] #t]
              [#t [projectile 0 4] [shotgun-shot [-- i]]]
        ]
]]
              [#t [projectile 0 4] [shotgun-shot [-- i]]]]]]


[def item-default [ω


@@ 120,13 99,11 @@
        [def dmg-leaves 1]
        [def inaccuracy 8.0]
        [def mag-size 0]
        [def primary [λ [] #f]]

        [def primary   [λ [] #f]]
        [def secondary [λ [] #f]]
        [def tertiary  [λ [] #f]]
        [def sync [δ []
                "Syncs the C state with the Object state"
                [item-sync [self]]
        ]]

        [def sprite-id-0 -1]
        [def sprite-id-1 -1]
        [def sprite-id-2 -1]


@@ 140,137 117,107 @@
        [def weight 1.0]
]]

[def i-grenade]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-grenade]
        [def name "Grenade"]
        [def description ["Grenade that after being\nthrown goes B" [ansi-yellow "OO"] [ansi-red "M!!!"]]]
        [def fire-health 48]
        [def fire-dmg 24]
        [def ammunition id]
        [def secondary [λ []
                [cond [[try-to-use]
                        [grenade-new [vy+ [player-pos] 0.5]]
                        [start-anim anim-hit 300] #t]
                      [#t #f]
                ]
        ]]
        [def burn-up [λ [pos id amount]
                       [explode pos [* [sqrt amount] 3]]
                       [say [ansi-red "Kabloom"]]
        ]]
        [def sprite-id-0 256]
        [def mesh 'm-grenade]

        [sync]
]]

[def i-bomb]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-bomb]
        [def name "Bomb"]
        [def fire-health 48]
        [def fire-dmg 16]
        [def ammunition id]
        [def secondary [λ []
                [cond [[try-to-use]
                       [grenade-new [vy+ [player-pos] 0.5] [player-rot] 8.0]
                       [start-anim anim-hit 300] #t]
                      [#t #f]
                ]
        ]]
        [def burn-up [λ [pos id amount]
                        [explode pos [* [sqrt amount] 6]]
                        [say [[ansi-yellow "Ka"] [ansi-red "booooom"]]]
        ]]
        [def sprite-id-0 257]
        [def mesh 'm-bomb]

        [sync]
]]

[def i-pear]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-pear]
        [def name "Pear"]
        [def fire-health 48]
        [def fire-dmg 8]
        [def ammunition id]
        [def secondary [λ []
[defmacro defitem [item-symbol . body]
          [def item-id [item-new-id]]
          `[do [array/set! items [- ~item-id 256] [item-default [ω [def id ~item-id]
                                                       [def sym [quote ~item-symbol]]
                                                       ~@[map body [\ [v] [cons 'def v]]]]]]
               [def ~item-symbol ~item-id]
               [item-sync [array/ref items [- ~item-id 256]]]]]

[defitem i-grenade
         [name "Grenade"]
         [description [cat "Grenade that after being\nthrown goes B" [ansi-yellow "OO"] [ansi-red "M!!!"]]]
         [fire-health 48]
         [fire-dmg 24]
         [ammunition id]
         [secondary [λ []
                       [if [try-to-use]
                           [do [grenade-new [vy+ [player-pos] 0.5]]
                               [start-anim anim-hit 300]
                               #t]
                           #f]]]
         [burn-up [λ [pos id amount]
                     [explode pos [* [sqrt amount] 3]]
                     [say [ansi-red "Kabloom"]]]]
         [sprite-id-0 256]
         [mesh 'm-grenade]]

[defitem i-bomb
        [name "Bomb"]
        [fire-health 48]
        [fire-dmg 16]
        [ammunition id]
        [secondary [λ []
                      [cond [[try-to-use]
                             [grenade-new [vy+ [player-pos] 0.5] [player-rot] 8.0]
                             [start-anim anim-hit 300] #t]
                            [#t #f]]]]
        [burn-up [λ [pos id amount]
                    [explode pos [* [sqrt amount] 6]]
                    [say [[ansi-yellow "Ka"] [ansi-red "booooom"]]]]]
        [sprite-id-0 257]
        [mesh 'm-bomb]]

[defitem i-pear
        [name "Pear"]
        [fire-health 48]
        [fire-dmg 8]
        [ammunition id]
        [secondary [λ []
                [cond   [[>= [player-hp] [player-maxhp]] #f]
                        [[try-to-use] [do-eat 8 id] #t]
                        [#t #f]]]]
        [def sprite-id-0 258]
        [def mesh 'm-pear]
        [def weight 0.2]

        [sync]
]]

[def i-stoneaxe]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-stoneaxe]
        [def name "Stone Axe"]
        [def stack-size 1]
        [def dmg 4]
        [def dmg-wood 3]
        [def primary [λ []
        [sprite-id-0 258]
        [mesh 'm-pear]
        [weight 0.2]]

[defitem i-stoneaxe
        [name "Stone Axe"]
        [stack-size 1]
        [dmg 4]
        [dmg-wood 3]
        [primary [λ []
                [cond [[throwing?] [throw-item [logior throw-spin throw-pierce] 0.17 3]]
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [try-to-throw]
        ]]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 259]
        [def sprite-color-1 #xFF666666]
        [def sprite-id-2 260]
        [def sprite-color-2 #xFFDDDDDD]
        [def mesh 'm-stoneaxe]
        [def weight 5.0]

        [sync]
]]

[def i-stonepickaxe]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-stonepickaxe]
        [def name "Stone Pickaxe"]
        [def stack-size 1]
        [def dmg 4]
        [def dmg-stone 3]
        [def dmg-dirt 2]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 267]
        [def sprite-color-1 #xFF666666]
        [def sprite-id-2 268]
        [def sprite-color-2 #xFFDDDDDD]
        [def mesh 'm-stonepickaxe]
        [def weight 5.0]

        [sync]
]]

[def i-blaster]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-blaster]
        [def name "Blaster"]
        [def inaccuracy 2]
        [def ammunition 'i-crystalbullet]
        [def fire-dmg 6]
        [def fire-health 64]
        [def stack-size 1]
        [def mag-size 30]
        [def primary [λ []
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 259]
        [sprite-color-1 #xFF666666]
        [sprite-id-2 260]
        [sprite-color-2 #xFFDDDDDD]
        [weight 5.0]
        [mesh 'm-stoneaxe]]

[defitem i-stonepickaxe
        [name "Stone Pickaxe"]
        [stack-size 1]
        [dmg 4]
        [dmg-stone 3]
        [dmg-dirt 2]
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 267]
        [sprite-color-1 #xFF666666]
        [sprite-id-2 268]
        [sprite-color-2 #xFFDDDDDD]
        [weight 5.0]
        [mesh 'm-stonepickaxe]]

[defitem i-blaster
        [name "Blaster"]
        [inaccuracy 2]
        [ammunition 'i-crystalbullet]
        [fire-dmg 6]
        [fire-health 64]
        [stack-size 1]
        [mag-size 30]
        [primary [λ []
                [cond [[try-to-shoot 600 6]
                        [beamblast 0.8 4.0 2]
                        [recoil 2.0]


@@ 278,7 225,7 @@
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [toggle-aim 4.0]
                        [add-inaccuracy 64.0]


@@ 286,26 233,20 @@
                      [#t #f]
                ]
        ]]
        [def tertiary [λ [] [item-reload 1200]]]
        [def burn-up [λ [pos id amount] [explode pos [* amount 0.5]]]]
        [def sprite-id-0 261]
        [def mesh 'm-blaster]

        [sync]
]]

[def i-masterblaster]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-masterblaster]
        [def name "Master Blaster"]
        [def inaccuracy 4]
        [def ammunition 'i-crystalbullet]
        [def fire-dmg 6]
        [def fire-health 64]
        [def stack-size 1]
        [def mag-size 90]
        [def primary [λ []
        [tertiary [λ [] [item-reload 1200]]]
        [burn-up [λ [pos id amount] [explode pos [* amount 0.5]]]]
        [sprite-id-0 261]
        [mesh 'm-blaster]]

[defitem i-masterblaster
        [name "Master Blaster"]
        [inaccuracy 4]
        [ammunition 'i-crystalbullet]
        [fire-dmg 6]
        [fire-health 64]
        [stack-size 1]
        [mag-size 90]
        [primary [λ []
                [cond [[try-to-shoot 1400 45]
                        [beamblast 6.0 12.0 1024]
                        [recoil 16.0]


@@ 313,7 254,7 @@
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [toggle-aim 3.0]
                        [add-inaccuracy 48.0]


@@ 321,27 262,21 @@
                      [#t #f]
                ]
        ]]
        [def tertiary [λ [] [item-reload 800]]]
        [def burn-up [λ [pos id amount] [explode pos [* amount 0.5]]]]
        [def sprite-id-0 262]
        [def mesh 'm-masterblaster]
        [def weight 3.0]

        [sync]
]]

[def i-assaultblaster]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-assaultblaster]
        [def name "Assault Blaster"]
        [def inaccuracy 8]
        [def ammunition 'i-flamebullet]
        [def fire-dmg 6]
        [def fire-health 64]
        [def stack-size 1]
        [def mag-size 60]
        [def primary [λ []
        [tertiary [λ [] [item-reload 800]]]
        [burn-up [λ [pos id amount] [explode pos [* amount 0.5]]]]
        [sprite-id-0 262]
        [weight 3.0]
        [mesh 'm-masterblaster]]

[defitem i-assaultblaster
        [name "Assault Blaster"]
        [inaccuracy 8]
        [ammunition 'i-flamebullet]
        [fire-dmg 6]
        [fire-health 64]
        [stack-size 1]
        [mag-size 60]
        [primary [λ []
                [cond [[try-to-shoot 60 1]
                        [sfx-play sfx-phaser 0.2]
                        [projectile 0 1]


@@ 351,7 286,7 @@
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [toggle-aim 2.0]
                        [add-inaccuracy 32.0]


@@ 359,280 294,197 @@
                      [#t #f]
                ]
        ]]
        [def tertiary [λ []
        [tertiary [λ []
                [item-reload 200]
        ]]
        [def burn-up [λ [pos id amount] [explode pos [* amount 0.2]]]]
        [def sprite-id-0 263]
        [def mesh 'm-assaultblaster]
        [def weight 3.0]

        [sync]
]]

[def i-shotgun]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-shotgun]
        [def name "Shotgun"]
        [def inaccuracy 48]
        [def ammunition 'i-flamebullet]
        [def fire-dmg 6]
        [def fire-health 64]
        [def stack-size 1]
        [def mag-size 60]
        [def primary [λ []
        [burn-up [λ [pos id amount] [explode pos [* amount 0.2]]]]
        [sprite-id-0 263]
        [weight 3.0]
        [mesh 'm-assaultblaster]]

[defitem i-shotgun
        [name "Shotgun"]
        [inaccuracy 48]
        [ammunition 'i-flamebullet]
        [fire-dmg 6]
        [fire-health 64]
        [stack-size 1]
        [mag-size 60]
        [primary [λ []
                [cond [[try-to-shoot 512 6] [sfx-play sfx-phaser 0.5] [shotgun-shot 64] [add-inaccuracy 96.0] [recoil 4.0] #t] [#t #f]]]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0] [toggle-aim 2.0] [add-inaccuracy 32.0] #t] [#t #f]]]]
        [def tertiary [λ [] [item-reload 256]]]
        [def burn-up [λ [pos id amount] [explode pos [* amount 0.2]]]]
        [def sprite-id-0 264]
        [def mesh 'm-shotgunblaster]
        [def weight 3.0]

        [sync]
]]

[def i-crystalbullet]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-crystalbullet]
        [def name "Crystal Bullet"]
        [def fire-dmg 8]
        [def fire-health 64]
        [def stack-size 999]
        [def burn-up [λ [pos id amount] [explode pos [* amount 0.1]]]]
        [def sprite-id-0 269]
        [def sprite-color-0 #xFFFFFFFF]
        [def sprite-id-1 270]
        [def sprite-color-1 #xFF5f32d6]
        [def mesh 'm-crystalbullet]
        [def weight 5.0]

        [sync]
]]

[def i-ironbar]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-ironbar]
        [def name "Iron Bar"]
        [def sprite-id-0 265]
        [def sprite-color-0 #xFFAAAAAA]
        [def sprite-id-1 266]
        [def sprite-color-1 #xFFEEEEEE]
        [def mesh 'm-ironbar]
        [def weight 8.0]

        [sync]
]]

[def i-ironaxe]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-ironaxe]
        [def name "Iron Axe"]
        [def stack-size 1]
        [def dmg 6]
        [def dmg-wood 5]
        [def primary [λ []
        [tertiary [λ [] [item-reload 256]]]
        [burn-up [λ [pos id amount] [explode pos [* amount 0.2]]]]
        [sprite-id-0 264]
        [weight 3.0]
        [mesh 'm-shotgunblaster]]

[defitem i-crystalbullet
        [name "Crystal Bullet"]
        [fire-dmg 8]
        [fire-health 64]
        [stack-size 999]
        [burn-up [λ [pos id amount] [explode pos [* amount 0.1]]]]
        [sprite-id-0 269]
        [sprite-color-0 #xFFFFFFFF]
        [sprite-id-1 270]
        [sprite-color-1 #xFF5f32d6]
        [weight 5.0]
        [mesh 'm-crystalbullet]]

[defitem i-ironbar
        [name "Iron Bar"]
        [sprite-id-0 265]
        [sprite-color-0 #xFFAAAAAA]
        [sprite-id-1 266]
        [sprite-color-1 #xFFEEEEEE]
        [weight 8.0]
        [mesh 'm-ironbar]]

[defitem i-ironaxe
        [name "Iron Axe"]
        [stack-size 1]
        [dmg 6]
        [dmg-wood 5]
        [primary [λ []
                [cond [[throwing?] [throw-item [logior throw-spin throw-pierce] 0.2 5]]
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [try-to-throw]
        ]]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 259]
        [def sprite-color-1 #xFFAAAAAA]
        [def sprite-id-2 260]
        [def sprite-color-2 #xFFEEEEEE]
        [def mesh 'm-ironaxe]
        [def weight 5.0]

        [sync]
]]

[def i-ironpickaxe]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-ironpickaxe]
        [def name "Iron Pickaxe"]
        [def stack-size 1]
        [def dmg 6]
        [def dmg-stone 5]
        [def dmg-dirt 3]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 267]
        [def sprite-color-1 #xFFAAAAAA]
        [def sprite-id-2 268]
        [def sprite-color-2 #xFFEEEEEE]
        [def mesh 'm-ironpickaxe]
        [def weight 5.0]

        [sync]
]]

[def i-crystalbar]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-crystalbar]
        [def name "Crystal Bar"]
        [def sprite-id-1 265]
        [def sprite-color-1 #xFF5f32d6]
        [def sprite-id-2 266]
        [def sprite-color-2 #xFFFFFFFF]
        [def mesh 'm-crystalbar]
        [def weight 2.0]

        [sync]
]]

[def i-crystalaxe]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-crystalaxe]
        [def name "Crystal Axe"]
        [def stack-size 1]
        [def dmg 8]
        [def dmg-wood 8]
        [def primary [λ []
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 259]
        [sprite-color-1 #xFFAAAAAA]
        [sprite-id-2 260]
        [sprite-color-2 #xFFEEEEEE]
        [weight 5.0]
        [mesh 'm-ironaxe]]

[defitem i-ironpickaxe
        [name "Iron Pickaxe"]
        [stack-size 1]
        [dmg 6]
        [dmg-stone 5]
        [dmg-dirt 3]
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 267]
        [sprite-color-1 #xFFAAAAAA]
        [sprite-id-2 268]
        [sprite-color-2 #xFFEEEEEE]
        [weight 5.0]
        [mesh 'm-ironpickaxe]]

[defitem i-crystalbar
        [name "Crystal Bar"]
        [sprite-id-1 265]
        [sprite-color-1 #xFF5f32d6]
        [sprite-id-2 266]
        [sprite-color-2 #xFFFFFFFF]
        [weight 2.0]
        [mesh 'm-crystalbar]]

[defitem i-crystalaxe
        [name "Crystal Axe"]
        [stack-size 1]
        [dmg 8]
        [dmg-wood 8]
        [primary [λ []
                [cond [[throwing?] [throw-item [logior throw-spin throw-pierce] 0.25 8]]
                      [#t #f]
                ]
        ]]
        [def secondary [lambda []
        [secondary [λ []
                [try-to-throw]
        ]]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 259]
        [def sprite-color-1 #xFF5f32d6]
        [def sprite-id-2 260]
        [def sprite-color-2 #xFFFFFFFF]
        [def mesh 'm-crystalaxe]
        [def weight 3.0]

        [sync]
]]

[def i-crystalpickaxe]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-crystalpickaxe]
        [def name "Crystal Pickaxe"]
        [def stack-size 1]
        [def dmg 8]
        [def dmg-stone 8]
        [def dmg-diro 8]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 267]
        [def sprite-color-1 #xFF5f32d6]
        [def sprite-id-2 268]
        [def sprite-color-2 #xFFFFFFFF]
        [def mesh 'm-crystalpickaxe]
        [def weight 3.0]

        [sync]
]]

[def i-cherry]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-cherry]
        [def name "Cherry"]
        [def fire-dmg 6]
        [def fire-health 96]
        [def secondary [λ []
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 259]
        [sprite-color-1 #xFF5f32d6]
        [sprite-id-2 260]
        [sprite-color-2 #xFFFFFFFF]
        [mesh 'm-crystalaxe]
        [weight 3.0]]

[defitem i-crystalpickaxe
        [name "Crystal Pickaxe"]
        [stack-size 1]
        [dmg 8]
        [dmg-stone 8]
        [dmg-dirt 8]
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 267]
        [sprite-color-1 #xFF5f32d6]
        [sprite-id-2 268]
        [sprite-color-2 #xFFFFFFFF]
        [weight 3.0]
        [mesh 'm-crystalpickaxe]]

[defitem i-cherry
        [name "Cherry"]
        [fire-dmg 6]
        [fire-health 96]
        [secondary [λ []
                [cond   [[>= [player-hp] [player-maxhp]] #f]
                        [[try-to-use] [do-eat 6 id] #t]
                        [#t #f]
                ]
        ]]
        [def sprite-id-0 272]
        [def mesh 'm-cherry]
        [def weight 0.1]

        [sync]
]]
        [sprite-id-0 272]
        [mesh 'm-cherry]
        [weight 0.1]]

[def i-clusterbomb]
[item-default [ω [def id [item-new-id]]
        [def sym 'i-clusterbomb]
        [def name "Cluster Bomb"]
        [def fire-dmg 12]
        [def fire-health 96]
        [def secondary [λ []
[defitem i-clusterbomb
        [name "Cluster Bomb"]
        [fire-dmg 12]
        [fire-health 96]
        [secondary [λ []
                [cond [[try-to-use]
                        [grenade-new [vy+ [player-pos] 0.5] [player-rot] 0.1 16 4.0]
                        [start-anim anim-hit 300]
                        #t]
                      [#t #f]]
        ]]
        [def burn-up [λ [pos id amount]
        [burn-up [λ [pos id amount]
                       [explode pos [* [sqrt amount] 6]]
                       [say [[ansi-yellow "Ka"] [ansi-red "bo000oom"]]]
        ]]
        [def sprite-id-0 273]
        [def mesh 'm-clusterbomb]
        [def weight 3.0]

        [sync]
]]

[def i-glider]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-glider]
        [def name "Glider"]
        [def stack-size 1]
        [def fire-dmg 8]
        [def fire-health 198]
        [def sprite-id-0 274]
        [def mesh 'm-glider]
        [def weight 3.0]

        [sync]
]]

[def i-hook]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-hook]
        [def name "Hook"]
        [def stack-size 1]
        [def fire-health 1024]
        [def sprite-id-0 275]
        [def mesh 'm-grapplinghook]
        [def weight 3.0]

        [sync]
]]

[def i-jetpack]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-jetpack]
        [def name "Jetpack"]
        [def stack-size 1]
        [def sprite-id-0 276]
        [def mesh 'm-jetpack]
        [def weight 3.0]

        [sync]
]]

[def i-poop]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-poop]
        [def name "Poop"]
        [def secondary [λ []
        [sprite-id-0 273]
        [weight 3.0]
        [mesh 'm-clusterbomb]]

[defitem i-glider
        [name "Glider"]
        [stack-size 1]
        [fire-dmg 8]
        [fire-health 198]
        [sprite-id-0 274]
        [weight 3.0]
        [mesh 'm-glider]]

[defitem i-hook
        [name "Hook"]
        [stack-size 1]
        [fire-health 1024]
        [sprite-id-0 275]
        [weight 3.0]
        [mesh 'm-grapplinghook]]

[defitem i-jetpack
        [name "Jetpack"]
        [stack-size 1]
        [sprite-id-0 276]
        [weight 3.0]
        [mesh 'm-jetpack]]

[defitem i-poop
        [name "Poop"]
        [secondary [λ []
                [cond   [[try-to-use] [start-anim anim-eat 1200] [player-hp [- [player-hp] 1]] [sfx-play sfx-chomp]
                        [yield [timeout 1000] [λ [] [say [ansi-brown "Mmmhhhh"]] [player-hp [- [player-hp] 1]]]]
                        [yield [timeout 2000] [λ [] [say [ansi-yellow "Lecker"]] [player-hp [- [player-hp] 1]]]]


@@ 640,87 492,62 @@
                        [#t #f]
                ]
        ]]
        [def drop-chance 4095]
        [drop-chance 4095]
        ; Still need to spawn in the plants/trees
        [def drop-handler [λ [pos id amount] -1]]
        [def sprite-id-0 277]
        [def mesh 'm-poop]
        ;[def weight 2.0]

        [sync]
]]

[def i-meat]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-meat]
        [def name "Meat"]
        [def ammunition id]
        [def fire-health 384]
        [def secondary [λ []
        [drop-handler [λ [pos id amount] -1]]
        [sprite-id-0 277]
        [mesh 'm-poop]]

[defitem i-meat
        [name "Meat"]
        [ammunition id]
        [fire-health 384]
        [secondary [λ []
                [cond  [[>= [player-hp] [player-maxhp]] #f]
                       [[try-to-use] [do-eat 4 id] #t]
                       [#t #f]
                ]
        ]]
        [def burn-up [λ [pos id amount]
        [burn-up [λ [pos id amount]
                       [say [ansi-rainbow [cat "Meat is done " id " " amount]]]
                       [item-drop-new pos i-cookedmeat amount]
        ]]
        [def drop-chance 65535]
        [def drop-handler [λ [pos id amount] -1]]
        [def sprite-id-0 278]
        [def sprite-id-1 279]
        [def sprite-color-1 #xFF274FF7]
        [def mesh 'm-meat]
        [def weight 2.0]

        [sync]
]]

[def i-cookedmeat]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-cookedmeat]
        [def name "Cooked Meat"]
        [def ammunition id]
        [def fire-health 192]
        [def secondary [λ []
        [drop-chance 65535]
        [drop-handler [λ [pos id amount] -1]]
        [sprite-id-0 278]
        [sprite-id-1 279]
        [sprite-color-1 #xFF274FF7]
        [weight 2.0]
        [mesh 'm-meat]]

[defitem i-cookedmeat
        [name "Cooked Meat"]
        [ammunition id]
        [fire-health 192]
        [secondary [λ []
                [cond   [[>= [player-hp] [player-maxhp]] #f]
                        [[try-to-use] [do-eat 20 id] #t]
                        [#t #f]
                ]
        ]]
        [def burn-up [λ [pos id amount] [item-drop-new pos i-burntmeat amount]]]
        [def sprite-id-0 278]
        [def sprite-id-1 279]
        [def sprite-color-1 #xFF6091D3]
        [def mesh 'm-cookedmeat]
        [def weight 2.0]

        [sync]
]]

[def i-fur]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-fur]
        [def name "Fur"]
        [def drop-chance 65535]
        [def drop-handler [λ [pos id amount] -1]]
        [def sprite-id-0 280]
        [def mesh 'm-fur]
        [def weight 2.0]

        [sync]
]]

[def i-burntmeat]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-burntmeat]
        [def name "Burnt Meat"]
        [def secondary [λ []
        [burn-up [λ [pos id amount] [item-drop-new pos i-burntmeat amount]]]
        [sprite-id-0 278]
        [sprite-id-1 279]
        [sprite-color-1 #xFF6091D3]
        [weight 2.0]
        [mesh 'm-cookedmeat]]

[defitem i-fur
        [name "Fur"]
        [drop-chance 65535]
        [drop-handler [λ [pos id amount] -1]]
        [sprite-id-0 280]
        [weight 2.0]
        [mesh 'm-fur]]

[defitem i-burntmeat
        [name "Burnt Meat"]
        [secondary [λ []
                [cond [[try-to-use]
                        [start-anim anim-eat 1800]
                        [sfx-play sfx-chomp]


@@ 728,24 555,18 @@
                      [#t #f]
                ]
        ]]
        [def drop-chance 65535]
        [def drop-handler [λ [pos id amount] -1]]
        [def sprite-id-0 278]
        [def sprite-id-1 279]
        [def sprite-color-1 #xFF606060]
        [def mesh 'm-burntmeat]
        [def weight 2.0]

        [sync]
]]

[def i-flintandsteel]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-flintandsteel]
        [def stack-size 1]
        [def name "Flint and Steel"]
        [def primary [λ []
        [drop-chance 65535]
        [drop-handler [λ [pos id amount] -1]]
        [sprite-id-0 278]
        [sprite-id-1 279]
        [sprite-color-1 #xFF606060]
        [weight 2.0]
        [mesh 'm-burntmeat]]

[defitem i-flintandsteel
        [stack-size 1]
        [name "Flint and Steel"]
        [primary [λ []
                [cond [[try-to-use 800 0]
                        [set-cooldown 800]
                        [start-anim anim-empty 600]


@@ 754,7 575,7 @@
                      [#t #t]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [set-cooldown 800]
                        [start-anim anim-empty 600]


@@ 763,25 584,19 @@
                      [#t #f]
                ]
        ]]
        [def sprite-id-0 286]
        [def mesh 'm-flintandsteel]
        [def weight 2.0]

        [sync]
]]

[def i-flamethrower]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-flamethrower]
        [def stack-size 1]
        [def mag-size 90]
        [def fire-dmg 8]
        [def fire-health 128]
        [def inaccuracy 16]
        [def ammunition 'i-flamebullet]
        [def name "Flamethrower"]
        [def primary [λ []
        [sprite-id-0 286]
        [weight 2.0]
        [mesh 'm-flintandsteel]]

[defitem i-flamethrower
        [stack-size 1]
        [mag-size 90]
        [fire-dmg 8]
        [fire-health 128]
        [inaccuracy 16]
        [ammunition 'i-flamebullet]
        [name "Flamethrower"]
        [primary [λ []
                [cond [[try-to-shoot 60 1]
                        [sfx-play sfx-phaser 0.2]
                        [projectile 0 5]


@@ 793,7 608,7 @@
                        #t]
                      [#t #f]]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [toggle-aim 2.0]
                        [add-inaccuracy 32.0]


@@ 801,80 616,56 @@
                      [#t #f]
                ]
        ]]
        [def tertiary [lambda [] [item-reload 512]]]
        [def burn-up [λ [pos id amount] [explode pos [* amount 0.2]]]]
        [def sprite-id-0 283]
        [def sprite-id-1 284]
        [def sprite-color-1 #xFF2163D4]
        [def mesh 'm-flamethrower]
        [def weight 3.0]

        [sync]
]]

[def i-flamebullet]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-flamebullet]
        [def stack-size 999]
        [def fire-dmg 8]
        [def fire-health 64]
        [def name "Flamebullet"]
        [def burn-up [λ [pos id amount]
        [tertiary [λ [] [item-reload 512]]]
        [burn-up [λ [pos id amount] [explode pos [* amount 0.2]]]]
        [sprite-id-0 283]
        [sprite-id-1 284]
        [sprite-color-1 #xFF2163D4]
        [weight 3.0]
        [mesh 'm-flamethrower]]

[defitem i-flamebullet
        [stack-size 999]
        [fire-dmg 8]
        [fire-health 64]
        [name "Flamebullet"]
        [burn-up [λ [pos id amount]
                [explode pos [* amount 0.1]]
        ]]
        [def sprite-id-0 269]
        [def sprite-color-0 #xFFFFFFFF]
        [def sprite-id-1 271]
        [def sprite-color-1 #xFF2468e0]
        [def mesh 'm-flamebullet]
        [def weight 0.2]

        [sync]
]]

[def i-irondust]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-irondust]
        [def fire-dmg 1]
        [def fire-health 256]
        [def name "Irondust"]
        [def burn-up [λ [pos id amount]
        [sprite-id-0 269]
        [sprite-color-0 #xFFFFFFFF]
        [sprite-id-1 271]
        [sprite-color-1 #xFF2468e0]
        [weight 0.2]
        [mesh 'm-flamebullet]]

[defitem i-irondust
        [fire-dmg 1]
        [fire-health 256]
        [name "Irondust"]
        [burn-up [λ [pos id amount]
                [item-drop-new pos i-ironbar amount]
        ]]
        [def sprite-id-0 285]
        [def sprite-color-0 #xFF3e3e8f]
        [def mesh 'm-irondust]
        [def weight 2.0]
        [sprite-id-0 285]
        [sprite-color-0 #xFF3e3e8f]
        [weight 2.0]
        [mesh 'm-irondust]]

        [sync]
]]

[def i-crystaldust]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-crystaldust]
        [def fire-dmg 1]
        [def fire-health 512]
        [def name "Crystaldust"]
        [def burn-up [λ [pos id amount]
[defitem i-crystaldust
        [fire-dmg 1]
        [fire-health 512]
        [name "Crystaldust"]
        [burn-up [λ [pos id amount]
                [item-drop-new pos i-crystalbar amount]
        ]]
        [def sprite-id-0 285]
        [def sprite-color-0 #xFF794DEA]
        [def mesh 'm-crystaldust]
        [sprite-id-0 285]
        [sprite-color-0 #xFF794DEA]
        [mesh 'm-crystaldust]]

        [sync]
]]

[def i-firedrill]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-firedrill]
        [def stack-size 1]
        [def name "Fire drill"]
        [def primary [λ []
[defitem i-firedrill
        [stack-size 1]
        [name "Fire drill"]
        [primary [λ []
                [cond [[try-to-use 800 0]
                        [set-cooldown 2400]
                        [start-anim anim-empty 600]


@@ 884,7 675,7 @@
                      [#t #t]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [set-cooldown 800]
                        [start-anim anim-empty 600]


@@ 893,22 684,16 @@
                       [#t #f]
                ]
        ]]
        [def sprite-id-0 287]
        [def mesh 'm-firedrill]
        [sprite-id-0 287]
        [mesh 'm-firedrill]]

        [sync]
]]

[def i-waterthrower]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-waterthrower]
        [def name "Waterthrower"]
        [def ammunition 'i-flamebullet]
        [def inaccuracy 16]
        [def mag-size 90]
        [def stack-size 1]
        [def primary [λ []
[defitem i-waterthrower
        [name "Waterthrower"]
        [ammunition 'i-flamebullet]
        [inaccuracy 16]
        [mag-size 90]
        [stack-size 1]
        [primary [λ []
                [cond [[try-to-shoot 60 1]
                        [sfx-play sfx-phaser 0.2]
                        [projectile 0 6]


@@ 921,7 706,7 @@
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [cond [[try-to-use 800 0]
                        [toggle-aim 2.0]
                        [add-inaccuracy 32.0]


@@ 929,147 714,108 @@
                      [#t #f]
                ]
        ]]
        [def tertiary [λ [] [item-reload 512]]]
        [def sprite-id-0 283]
        [def sprite-id-1 284]
        [def sprite-color-1 #xFFB36213]
        [def mesh 'm-waterthrower]

        [sync]
]]

[def i-stonespear]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-stonespear]
        [def name "Stone Spear"]
        [def stack-size 1]
        [def dmg 6]
        [def primary [λ []
        [tertiary [λ [] [item-reload 512]]]
        [sprite-id-0 283]
        [sprite-id-1 284]
        [sprite-color-1 #xFFB36213]
        [mesh 'm-waterthrower]]

[defitem i-stonespear
        [name "Stone Spear"]
        [stack-size 1]
        [dmg 6]
        [primary [λ []
                [cond [[throwing?] [throw-item [+ throw-heavy throw-pierce] 0.25 4]]
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [try-to-throw]
        ]]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 290]
        [def sprite-color-1 #xFF666666]
        [def sprite-id-2 289]
        [def sprite-color-2 #xFFDDDDDD]
        [def mesh 'm-stonespear]
        [def weight 3.0]

        [sync]
]]

[def i-ironspear]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-ironspear]
        [def name "Iron Spear"]
        [def stack-size 1]
        [def dmg 8]
        [def primary [λ []
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 290]
        [sprite-color-1 #xFF666666]
        [sprite-id-2 289]
        [sprite-color-2 #xFFDDDDDD]
        [weight 3.0]
        [mesh 'm-stonespear]]

[defitem i-ironspear
        [name "Iron Spear"]
        [stack-size 1]
        [dmg 8]
        [primary [λ []
                [cond [[throwing?] [throw-item [+ throw-heavy throw-pierce] 0.35 8]]
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [try-to-throw]
        ]]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 290]
        [def sprite-color-1 #xFFAAAAAA]
        [def sprite-id-2 289]
        [def sprite-color-2 #xFFFFFFFF]
        [def mesh 'm-ironspear]
        [def weight 3.0]

        [sync]
]]

[def i-crystalspear]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-crystalspear]
        [def name "Crystal Spear"]
        [def stack-size 1]
        [def dmg 10]
        [def primary [λ []
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 290]
        [sprite-color-1 #xFFAAAAAA]
        [sprite-id-2 289]
        [sprite-color-2 #xFFFFFFFF]
        [weight 3.0]
        [mesh 'm-ironspear]]

[defitem i-crystalspear
        [name "Crystal Spear"]
        [stack-size 1]
        [dmg 10]
        [primary [λ []
                [cond [[throwing?] [throw-item [+ throw-heavy throw-pierce] 0.4 12]]
                      [#t #f]
                ]
        ]]
        [def secondary [λ []
        [secondary [λ []
                [try-to-throw]
        ]]
        [def sprite-id-0 291]
        [def sprite-color-0 #xFF01232F]
        [def sprite-id-1 290]
        [def sprite-color-1 #xFF5f32d6]
        [def sprite-id-2 289]
        [def sprite-color-2 #xFFFFFFFF]
        [def mesh 'm-crystalspear]
        [def weight 2.0]

        [sync]
]]

[def i-plantmatter]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-plantmatter]
        [def name "Plantmatter"]
        [def fire-dmg 2]
        [def fire-health 256]
        [def drop-chance 65535]
        [def drop-handler [λ [pos id amount]
        [sprite-id-0 291]
        [sprite-color-0 #xFF01232F]
        [sprite-id-1 290]
        [sprite-color-1 #xFF5f32d6]
        [sprite-id-2 289]
        [sprite-color-2 #xFFFFFFFF]
        [mesh 'm-crystalspear]
        [weight 2.0]]

[defitem i-plantmatter
        [name "Plantmatter"]
        [fire-dmg 2]
        [fire-health 256]
        [drop-chance 65535]
        [drop-handler [λ [pos id amount]
                [say [ansi-yellow "Straw!"]]
                [item-drop-new pos i-straw 1]
                -1
        ]]
        [def sprite-id-0 292]
        [def sprite-color-0 #xFF087500]
        [def mesh 'm-plantmatter]
        [def weight 0.4]

        [sync]
]]

[def i-straw]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-straw]
        [def name "Straw"]
        [def fire-dmg 8]
        [def fire-health 256]
        [def sprite-id-0 292]
        [def sprite-color-0 #xFF48A7D3]
        [def mesh 'm-straw]
        [def weight 0.3]

        [sync]
]]

[def i-backpack]
[item-default [ω
        [def id [item-new-id]]
        [def sym 'i-backpack]
        [def name "Backpack"]
        [def stack-size 1]
        [def sprite-id-0 281]
        [def mesh 'm-backpack]
        [def weight 3.0]

        [sync]
]]

[event-bind "on-init" [λ []
        [item-sync-all 0]
        [sprite-id-0 292]
        [sprite-color-0 #xFF087500]
        [weight 0.4]
        [mesh 'm-plantmatter]]

[defitem i-straw
        [name "Straw"]
        [fire-dmg 8]
        [fire-health 256]
        [sprite-id-0 292]
        [sprite-color-0 #xFF48A7D3]
        [weight 0.3]
        [mesh 'm-straw]]

[defitem i-backpack
        [name "Backpack"]
        [stack-size 1]
        [sprite-id-0 281]
        [weight 3.0]
        [mesh 'm-backpack]]

[event-bind on-init :item-init [λ []
        [item-sync-all]
        [log [ansi-green "Items initialized"]]

        [recipe-sync-all 0]

M common/src/nuj/recipes.nuj => common/src/nuj/recipes.nuj +276 -451
@@ 1,6 1,6 @@
; All the Recipes

[def recipes [arr-new 256]]
[def recipes [array/allocate 256]]
[def recipe-new-id [let*
	[def recipe-cur-id 0]



@@ 10,472 10,297 @@
	]
]]

[def recipe-sync [λ [obj]
[defun recipe-sync [obj]
	"Syncs the Recipe with the ω OBJ"
	[when [symbol? [resolve [obj result-id]]] [log "Invalid Result ID for Recipe [:id " [obj id] [ansi-red " :result-id " [obj result-id]] " :result-amt " [obj result-amt] "]"]]
	[when [zn? [obj result-amt]] [log "Invalid Result Amount for Recipe [:id " [obj id] " :result-id " [obj result-id] [ansi-red " :result-amt " [obj result-amt]] "]"]]
	#_[when [symbol? [resolve [obj result-id]]] [println "Invalid Result ID for Recipe [:id " [obj id] [ansi-red " :result-id " [obj result-id]] " :result-amt " [obj result-amt] "]"]]
	#_[when [zero-neg? [obj result-amt]] [println "Invalid Result Amount for Recipe [:id " [obj id] " :result-id " [obj result-id] [ansi-red " :result-amt " [obj result-amt]] "]"]]

	[when [symbol? [resolve [obj ingred-id-0]]] [log "Invalid first Ingredient ID for Recipe [:id " [obj id] [ansi-red " :result-id " [obj ingred-id-0]] " :result-amt " [obj ingred-amt-0] "]"]]
	[when [zn? [obj ingred-amt-0]] [log "Invalid first Ingredient Amount for Recipe [:id " [obj id] " :result-id " [obj ingred-id-0] [ansi-red " :result-amt " [obj ingred-amt-0]] "]"]]
	#_[when [symbol? [resolve [obj ingred-id-0]]] [println "Invalid first Ingredient ID for Recipe [:id " [obj id] [ansi-red " :result-id " [obj ingred-id-0]] " :result-amt " [obj ingred-amt-0] "]"]]
	#_[when [zero-neg? [obj ingred-amt-0]] [println "Invalid first Ingredient Amount for Recipe [:id " [obj id] " :result-id " [obj ingred-id-0] [ansi-red " :result-amt " [obj ingred-amt-0]] "]"]]

	[r-result [obj id]   [resolve [obj result-id]]   [obj result-amt]]
	[r-ingred [obj id] 0 [resolve [obj ingred-id-0]] [obj ingred-amt-0]]
	[r-ingred [obj id] 1 [resolve [obj ingred-id-1]] [obj ingred-amt-1]]
	[r-ingred [obj id] 2 [resolve [obj ingred-id-2]] [obj ingred-amt-2]]
	[r-ingred [obj id] 3 [resolve [obj ingred-id-3]] [obj ingred-amt-3]]
]

	[arr-set! recipes [obj id] obj]
]]

[def recipe-sync-all [λ [i] "Syncs all Recipes with their respective ω"
	[cond [[nil? [recipes [int i]]] #t]
	      [#t [recipe-sync [recipes [int i]]] [recipe-sync-all [+ [int i] 1]]]
	]
]]


[def recipe-craft [λ [id times]
	"Crafts recipe with ID"
	[[recipes id] craft]
]]
[defun recipe-sync-all []
       "Syncs all Recipes with their respective ω"
       [for [i 0 [array/length recipes]]
	    [def cur-recipe [array/ref recipes i]]
	    [when cur-recipe [recipe-sync cur-recipe]]]]

[def recipe-default [ω
	[def id -1]
	[def type :recipe]

	[def ingred-id-0 0]
	[def ingred-id-0  0]
	[def ingred-amt-0 0]
	[def ingred-id-1 0]
	[def ingred-id-1  0]
	[def ingred-amt-1 0]
	[def ingred-id-2 0]
	[def ingred-id-2  0]
	[def ingred-amt-2 0]
	[def ingred-id-3 0]
	[def ingred-id-3  0]
	[def ingred-amt-3 0]

	[def craft [δ [] [say "I got nothing to do"]]]
	[def sync [δ [] "Syncs the C state with the Object state"
		[recipe-sync [self]]]]

	[def result-amt 0]
	[def result-id 0]
]]


[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-oak-log]
	[def ingred-amt-0 1]
	[def result-id 'i-boards]
	[def result-amt 2]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-oak-log]
	[def ingred-amt-0 4]
	[def result-id 'i-coal]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-boards]
	[def ingred-amt-0  2]
	[def ingred-id-1 'i-stone]
	[def ingred-amt-1  3]
	[def ingred-id-2 'i-plantmatter]
	[def ingred-amt-2  2]
	[def result-id 'i-stoneaxe]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-boards]
	[def ingred-amt-0  2]
	[def ingred-id-1 'i-stone]
	[def ingred-amt-1  4]
	[def ingred-id-2 'i-plantmatter]
	[def ingred-amt-2  2]
	[def result-id 'i-stonepickaxe]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-boards]
	[def ingred-amt-0  4]
	[def ingred-id-1 'i-stone]
	[def ingred-amt-1  2]
	[def ingred-id-2 'i-plantmatter]
	[def ingred-amt-2  2]
	[def result-id 'i-stonespear]
	[def result-amt 1]

	[sync]
]]


[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-boards]
	[def ingred-amt-0  2]
	[def ingred-id-1 'i-stone]
	[def ingred-amt-1  1]
	[def ingred-id-2 'i-plantmatter]
	[def ingred-amt-2  8]
	[def result-id 'i-firedrill]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-fur]
	[def ingred-amt-0  12]
	[def result-id 'i-backpack]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-boards]
	[def ingred-amt-0  16]
	[def ingred-id-1 'i-fur]
	[def ingred-amt-1  8]
	[def result-id 'i-glider]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-boards]
	[def ingred-amt-0  16]
	[def ingred-id-1 'i-straw]
	[def ingred-amt-1  32]
	[def result-id 'i-glider]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-hematite-ore]
	[def ingred-amt-0  1]
	[def result-id 'i-irondust]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironbar]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-stone]
	[def ingred-amt-1  2]
	[def result-id 'i-flintandsteel]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironbar]
	[def ingred-amt-0  8]
	[def ingred-id-1 'i-coal]
	[def ingred-amt-1  2]
	[def result-id 'i-hook]
	[def result-amt 1]

	[sync]
]]

[recipe-default
	[ω [def id [recipe-new-id]]
	[def ingred-id-0 'i-stoneaxe]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  4]
	[def ingred-id-2 'i-coal]
	[def ingred-amt-2  2]
	[def result-id 'i-ironaxe]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-stonepickaxe]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  4]
	[def ingred-id-2 'i-coal]
	[def ingred-amt-2  2]
	[def result-id 'i-ironpickaxe]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-stonespear]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  4]
	[def ingred-id-2 'i-coal]
	[def ingred-amt-2  2]
	[def result-id 'i-ironspear]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystals]
	[def ingred-amt-0  1]
	[def result-id 'i-crystaldust]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironaxe]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-crystalbar]
	[def ingred-amt-1  4]
	[def result-id 'i-crystalaxe]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironpickaxe]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-crystalbar]
	[def ingred-amt-1  4]
	[def result-id 'i-crystalpickaxe]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironspear]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-crystalbar]
	[def ingred-amt-1  4]
	[def result-id 'i-crystalspear]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironbar]
	[def ingred-amt-0  2]
	[def ingred-id-1 'i-coal]
	[def ingred-amt-1  6]
	[def ingred-id-2 'i-crystals]
	[def ingred-amt-2  1]
	[def result-id 'i-grenade]
	[def result-amt 4]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironbar]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-coal]
	[def ingred-amt-1  4]
	[def ingred-id-2 'i-crystals]
	[def ingred-amt-2  3]
	[def result-id 'i-bomb]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironbar]
	[def ingred-amt-0  4]
	[def ingred-id-1 'i-coal]
	[def ingred-amt-1  16]
	[def ingred-id-2 'i-crystals]
	[def ingred-amt-2  8]
	[def result-id 'i-clusterbomb]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-ironbar]
	[def ingred-amt-0  2]
	[def ingred-id-1 'i-coal]
	[def ingred-amt-1  4]
	[def result-id 'i-flamebullet]
	[def result-amt 30]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  8]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  6]
	[def ingred-id-2 'i-flamebullet]
	[def ingred-amt-2 24]
	[def result-id 'i-assaultblaster]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  12]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  16]
	[def ingred-id-2 'i-crystalbullet]
	[def ingred-amt-2  60]
	[def result-id 'i-shotgun]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  4]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1 16]
	[def ingred-id-2 'i-flamebullet]
	[def ingred-amt-2 12]
	[def result-id 'i-waterthrower]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  8]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  8]
	[def ingred-id-2 'i-flamebullet]
	[def ingred-amt-2 16]
	[def result-id 'i-flamethrower]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystals]
	[def ingred-amt-0  1]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  2]
	[def ingred-id-2 'i-coal]
	[def ingred-amt-2  4]
	[def result-id 'i-crystalbullet]
	[def result-amt 30]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  3]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  6]
	[def ingred-id-2 'i-crystalbullet]
	[def ingred-amt-2 12]
	[def result-id 'i-blaster]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  16]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  24]
	[def ingred-id-2 'i-crystalbullet]
	[def ingred-amt-2  90]
	[def result-id 'i-masterblaster]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-crystalbar]
	[def ingred-amt-0  16]
	[def ingred-id-1 'i-ironbar]
	[def ingred-amt-1  16]
	[def ingred-id-2 'i-coal]
	[def ingred-amt-2  32]
	[def result-id 'i-jetpack]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-marble-block]
	[def ingred-amt-0 1]
	[def result-id 'i-marble-pillar]
	[def result-amt 1]

	[sync]
]]

[recipe-default [ω
	[def id [recipe-new-id]]
	[def ingred-id-0 'i-marble-block]
	[def ingred-amt-0 1]
	[def result-id 'i-marble-blocks]
	[def result-amt 1]

	[sync]
]]
	[def result-id 0]]]

[defmacro defrecipe body
          [def r-id [recipe-new-id]]
          `[do [array/set! recipes ~r-id [recipe-default [ω [def id ~r-id]
                                                       ~@[map body [\ [v] [cons 'def v]]]]]]
               [recipe-sync [array/ref recipes ~r-id]]]]

[defrecipe [ingred-id-0 'i-oak-log]
           [ingred-amt-0 1]
	   [result-id 'i-boards]
	   [result-amt 2]]

[defrecipe [ingred-id-0 'i-oak-log]
           [ingred-amt-0 4]
	   [result-id 'i-coal]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-boards]
           [ingred-amt-0  2]
	   [ingred-id-1 'i-stone]
	   [ingred-amt-1  3]
	   [ingred-id-2 'i-plantmatter]
	   [ingred-amt-2  2]
	   [result-id 'i-stoneaxe]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-boards]
	   [ingred-amt-0  2]
	   [ingred-id-1 'i-stone]
	   [ingred-amt-1  4]
	   [ingred-id-2 'i-plantmatter]
	   [ingred-amt-2  2]
	   [result-id 'i-stonepickaxe]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-boards]
	   [ingred-amt-0  4]
	   [ingred-id-1 'i-stone]
	   [ingred-amt-1  2]
	   [ingred-id-2 'i-plantmatter]
	   [ingred-amt-2  2]
	   [result-id 'i-stonespear]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-boards]
	   [ingred-amt-0  2]
	   [ingred-id-1 'i-stone]
	   [ingred-amt-1  1]
	   [ingred-id-2 'i-plantmatter]
	   [ingred-amt-2  8]
	   [result-id 'i-firedrill]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-fur]
           [ingred-amt-0  12]
	   [result-id 'i-backpack]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-boards]
           [ingred-amt-0  16]
	   [ingred-id-1 'i-fur]
	   [ingred-amt-1  8]
	   [result-id 'i-glider]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-boards]
           [ingred-amt-0  16]
	   [ingred-id-1 'i-straw]
	   [ingred-amt-1  32]
	   [result-id 'i-glider]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-hematite-ore]
	   [ingred-amt-0  1]
	   [result-id 'i-irondust]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironbar]
           [ingred-amt-0  1]
	   [ingred-id-1 'i-stone]
	   [ingred-amt-1  2]
	   [result-id 'i-flintandsteel]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironbar]
	   [ingred-amt-0  8]
	   [ingred-id-1 'i-coal]
	   [ingred-amt-1  2]
	   [result-id 'i-hook]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-stoneaxe]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  4]
	   [ingred-id-2 'i-coal]
	   [ingred-amt-2  2]
	   [result-id 'i-ironaxe]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-stonepickaxe]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  4]
	   [ingred-id-2 'i-coal]
	   [ingred-amt-2  2]
	   [result-id 'i-ironpickaxe]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-stonespear]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  4]
	   [ingred-id-2 'i-coal]
	   [ingred-amt-2  2]
	   [result-id 'i-ironspear]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystals]
	   [ingred-amt-0  1]
	   [result-id 'i-crystaldust]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironaxe]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-crystalbar]
	   [ingred-amt-1  4]
	   [result-id 'i-crystalaxe]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironpickaxe]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-crystalbar]
	   [ingred-amt-1  4]
	   [result-id 'i-crystalpickaxe]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironspear]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-crystalbar]
	   [ingred-amt-1  4]
	   [result-id 'i-crystalspear]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironbar]
           [ingred-amt-0  2]
           [ingred-id-1 'i-coal]
           [ingred-amt-1  6]
           [ingred-id-2 'i-crystals]
           [ingred-amt-2  1]
           [result-id 'i-grenade]
           [result-amt 4]]

[defrecipe [ingred-id-0 'i-ironbar]
           [ingred-amt-0  1]
           [ingred-id-1 'i-coal]
           [ingred-amt-1  4]
           [ingred-id-2 'i-crystals]
           [ingred-amt-2  3]
           [result-id 'i-bomb]
           [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironbar]
	   [ingred-amt-0  4]
	   [ingred-id-1 'i-coal]
	   [ingred-amt-1  16]
	   [ingred-id-2 'i-crystals]
	   [ingred-amt-2  8]
	   [result-id 'i-clusterbomb]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-ironbar]
	   [ingred-amt-0  2]
	   [ingred-id-1 'i-coal]
	   [ingred-amt-1  4]
	   [result-id 'i-flamebullet]
	   [result-amt 30]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  8]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  6]
	   [ingred-id-2 'i-flamebullet]
	   [ingred-amt-2 24]
	   [result-id 'i-assaultblaster]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  12]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  16]
	   [ingred-id-2 'i-crystalbullet]
	   [ingred-amt-2  60]
	   [result-id 'i-shotgun]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  4]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1 16]
	   [ingred-id-2 'i-flamebullet]
	   [ingred-amt-2 12]
	   [result-id 'i-waterthrower]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  8]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  8]
	   [ingred-id-2 'i-flamebullet]
	   [ingred-amt-2 16]
	   [result-id 'i-flamethrower]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystals]
	   [ingred-amt-0  1]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  2]
	   [ingred-id-2 'i-coal]
	   [ingred-amt-2  4]
	   [result-id 'i-crystalbullet]
	   [result-amt 30]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  3]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  6]
	   [ingred-id-2 'i-crystalbullet]
	   [ingred-amt-2 12]
	   [result-id 'i-blaster]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  16]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  24]
	   [ingred-id-2 'i-crystalbullet]
	   [ingred-amt-2  90]
	   [result-id 'i-masterblaster]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-crystalbar]
	   [ingred-amt-0  16]
	   [ingred-id-1 'i-ironbar]
	   [ingred-amt-1  16]
	   [ingred-id-2 'i-coal]
	   [ingred-amt-2  32]
	   [result-id 'i-jetpack]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-marble-block]
	   [ingred-amt-0 1]
	   [result-id 'i-marble-pillar]
	   [result-amt 1]]

[defrecipe [ingred-id-0 'i-marble-block]
	   [ingred-amt-0 1]
	   [result-id 'i-marble-blocks]
	   [result-amt 1]]

M common/src/nuj/repl.nuj => common/src/nuj/repl.nuj +21 -29
@@ 1,35 1,27 @@
[def display/error [let*
	[def wrap [λ [i text]
		[cond [[eq? i 0] [ansi-red text]]
		      [[eq? i 1] text]
		      [[eq? i 2] [ansi-yellow text]]
		      [#t text]
		]
	]]
[def repl/display/error [let*
        [defun wrap [i text]
                  [case i
                        [0 [ansi-red text]]
                        [1 text]
                        [2 [ansi-yellow text]]
                        [otherwise text]]]

	[def iter [λ [error i]
		[if error
		    [cons [wrap i [string [car error]]]
		          [iter [cdr error] [++ i]]]
		    [cons "" #nil]]
	]]
        [defun iter [error i]
                [if error
                    [cons [wrap i [string [car error]]]
                          [iter [cdr error] [+ 1 i]]]
                    [cons "" #nil]]]

	[λ [error]
		"Display ERROR in a nice, human readable way"
		[join [iter error 0] "\n"]
	]
        [λ [error]
                "Display ERROR in a nice, human readable way"
                [join [iter error 0] "\n"]]
]]

[def repl/exception-handler [λ [error]
	[display/error error]
]]

[def repl/console [let*
	[def ctx [ω]]
        [repl/display/error error]]]

	[λ [line]
	[try repl/exception-handler
	     [def expr [read line]]
	     [apply ctx [cons do expr]]
	]]
]]
[defun repl/console [line]
        [try repl/exception-handler
             [def form [cons do [read line]]]
             [def compiled-form [list do [compile form root-closure]]]
             [apply root-closure compiled-form]]]

M server/server.mk => server/server.mk +7 -2
@@ 11,7 11,7 @@ SERVER_DEPS      := ${SERVER_SRCS:.c=.d}

SERVER_NUJ       := $(shell find server/src/nujel -type f -name '*.nuj' | sort)
SERVER_NO        := $(SERVER_NUJ:.nuj=.no)
SERVER_ASSETS    := server/src/tmp/server.no
SERVER_ASSETS    := server/src/tmp/server.nuj

$(SERVER_OBJS_EXCL): | common/src/tmp/cto.c
$(SERVER_OBJS): | server/src/tmp/assets.h


@@ 24,7 24,12 @@ $(WOLKENWELTEN_SERVER): $(SERVER_OBJS) $(ASM_OBJS) ${SERVER_TMP_OBJS} common/nuj

server/src/tmp/server.no: $(SERVER_NO)
	@mkdir -p server/src/tmp
	@cat $(SERVER_NUJ) > $@
	@cat $^ > $@
	@echo "$(ANSI_GREY)" "[CAT]" "$(ANSI_RESET)" $@

server/src/tmp/server.nuj: $(SERVER_NUJ)
	@mkdir -p server/src/tmp
	@cat $^ > $@
	@echo "$(ANSI_GREY)" "[CAT]" "$(ANSI_RESET)" $@

server/src/tmp/sfx.c: $(SFX_ASSETS)

M server/src/main.c => server/src/main.c +1 -1
@@ 179,7 179,7 @@ void mainInit(){
	lispInit();
	itemTypeInit();
	blockTypeInit();
	lispEval("[event-fire \"on-init\"]",false);
	lispCallFunc("on-init-fire", NULL);
	savegameSave();

	bigchungusInit(&world);

M server/src/misc/lisp.c => server/src/misc/lisp.c +9 -21
@@ 42,7 42,7 @@

#include "../../../common/nujel/lib/api.h"
#include "../../../common/nujel/lib/exception.h"
#include "../../../common/nujel/lib/s-expression/writer.h"
#include "../../../common/nujel/lib/misc/pf.h"
#include "../../../common/nujel/lib/allocation/roots.h"

#include <ctype.h>


@@ 52,8 52,8 @@
#include <string.h>
#include <inttypes.h>

extern unsigned  int src_tmp_server_no_len;
extern unsigned char src_tmp_server_no_data[];
extern unsigned  int src_tmp_server_nuj_len;
extern unsigned char src_tmp_server_nuj_data[];

lSymbol *lsPID;



@@ 340,14 340,6 @@ static lVal *wwlnfSendMessage(lClosure *c, lVal *v){
	return lCar(v);
}

static lVal *wwlnfConsolePrint(lClosure *c, lVal *v){
	(void)c;
	const char *msg = castToString(lCar(v),NULL);
	if(msg == NULL){return NULL;}
	printf("%s\n",msg);
	return lCar(v);
}

static lVal *wwlnfQuit(lClosure *c, lVal *v){
	(void)c;(void)v;
	quit = true;


@@ 491,7 483,6 @@ void addServerNativeFuncs(lClosure *c){
	lAddNativeFunc(c,"game/time",      "(s)",                                          "Sets the time to the time string s",                         wwlnfTime);
	lAddNativeFunc(c,"tp",             "(pos)",                                        "Teleports to pos",                                           wwlnfTp);
	lAddNativeFunc(c,"send-message",   "(s)",                                          "Send a chat message to everyone",                            wwlnfSendMessage);
	lAddNativeFunc(c,"console-print",  "(s)",                                          "Prints something to stdout",                                 wwlnfConsolePrint);
	lAddNativeFunc(c,"chunk-info",     "(pos)",                                        "Returns a description of the chunk at pos",                  wwlnfChunkInfo);
	lAddNativeFunc(c,"chungus-info",   "(pos)",                                        "Returns a description of the chungus at pos",                wwlnfChungusInfo);
	lAddNativeFunc(c,"spawn-pos",      "()",                                           "Return the current spawn position as a vec",                 wwlnfSpawnPos);


@@ 510,9 501,8 @@ static void *cmdLispReal(void *a, void *b){
	u16 pid = *((uint *)a);
	const char *str = (const char *)b;

	lVal *expr = lRead(str);
	lVal *v = lnfDo(clients[pid].cl, expr);
	lSWriteVal(v,reply,&reply[sizeof(reply)-1],0,true);
	lVal *v = lRunS(clients[pid].cl, str, strlen(str));
	spf(reply, &reply[sizeof(reply)-1], "%v", v);

	msgLispSExpr(pid, reply);



@@ 527,9 517,8 @@ static void cmdLisp(uint pid, const char *str){
static void *lispInitReal(void *a, void *b){
	(void)a; (void)b;
	clRoot = lispCommonRoot(addServerNativeFuncs);
	lVal *expr = lRead((char *)src_tmp_server_no_data);
	lnfDo(clRoot, expr);
	lsPID = lSymS("pid");
	lLoadS(clRoot,(const char *)src_tmp_server_nuj_data, src_tmp_server_nuj_len);
	lsPID = RSYMP(lSymS("pid"));

	return NULL;
}


@@ 581,9 570,8 @@ void *lispEvalReal(void *a, void *b){
	bool humanReadable = b != NULL;
	memset(reply,0,sizeof(reply));

	lVal *expr = lRead(str);
	lVal *v = lnfDo(clRoot,expr);
	lSWriteVal(v,reply,&reply[sizeof(reply)-1],0,humanReadable);
	lVal *v = lRunS(clRoot, str, strlen(str));
	spf(reply, &reply[sizeof(reply)-1], humanReadable ? "%v" : "%V", v);

	return reply;
}

M server/src/nujel/server.nuj => server/src/nujel/server.nuj +36 -72
@@ 2,79 2,49 @@
[def server? #t]

[def test-context "WolkenWelten Server"]
[test-add #t [and [not client?] server?]]
[test/add #t [and [not client?] server?]]

[def error [λ [...args]
[defun error args
	"Print its arguments into the LISP console and might alert the user"
	[say [apply cat ...args]]
]]
	[say [apply cat args]]]

[def log [λ [...args]
[defun log args
	"Print its arguments into the LISP console"
	[console-print [apply cat ...args]]
]]

[def help [let []
	[def iter [λ [l]
		[cond [[nil? l] #t]
		       [#t [say [describe [car l]]] [iter [cdr l]]
		]]
	]]

	[λ [i]
		"Describe 10 functions at offset 1"
		[let [[off [* [int i] 10]]]
		[iter [map cat [symbol-table off 10]]]
		[say ["Help page " [int i] " of " [/ [symbol-count] 10]]] #t]
	]
]]
	[print [apply cat args]]]

[def print [λ [...a]
	"Print to everyone's chat"
	[say [apply cat ...a]]
]]

[def heal [δ [a]
[defun heal [a]
	"Heals oneself by a points"
	[- [dmg [cond [a [- a]] [#t -20]]]]
]]
	[- [dmg [cond [a [- a]] [#t -20]]]]]

[def time/morning! [λ []
[defun time/morning! []
	"Sets the Time to 8:00 AM"
	[game/time "8:00"]
]]
	[game/time "8:00"]]

[def time/noon! [λ []
[defun time/noon! []
	"Sets the Time to 12:00 PM"
	[game/time "12:00"]
]]
	[game/time "12:00"]]

[def time/evening! [λ []
[defun time/evening! []
	"Sets the Time to 21:30 PM"
	[game/time "21:30"]
]]
	[game/time "21:30"]]

[def time/night! [λ []
[defun time/night! []
	"Sets the Time to Midnight"
	[game/time "24:00"]
]]
	[game/time "24:00"]]

[def player-x [δ []
[defun player-x []
	"Return the current players X Position"
	[vec/x [player-pos]]
]]
	[vec/x [player-pos]]]

[def player-y [δ []
[defun player-y []
	"Return the current players Y Position"
	[vec/y [player-pos]]
]]
	[vec/y [player-pos]]]

[def player-z [δ []
[defun player-z []
	"Return the current players Z Position"
	[vec/z [player-pos]]
]]
	[vec/z [player-pos]]]

[def item-drop-stress [let []
[def item-drop-stress [let*
	[def item-drop-stress-xz [λ [pos max x z]
		[item-drop-new [+ [vec x -6 z] pos] i-crystals 1]
		[when [< z max] [item-drop-stress-xz pos max x [+ 2 z]]]


@@ 86,10 56,9 @@
	[λ [pos max]
		"Stress test the itemDrop code by generating a lot of them"
		[item-drop-stress-x pos max -max]
	]
]]
	]]]

[def animal-stress [let []
[def animal-stress [let*
	[def stress-xz [λ [pos max x z]
		[animal-new [+ [vec x 6 z] pos] 1 1]
		[when [< z max] [stress-xz pos max x [+ 4 z]]]


@@ 101,32 70,28 @@
	[λ [pos max]
		"Generate a lot of animals"
		[stress-x pos max -max]
	]
]]
	]]]

[def rain [λ []
[defun rain []
	"Make it Rain!"
	[cloud-density 0.9]
]]
	[cloud-density 0.9]]

[def cloud-density [λ [a]
[defun cloud-density [a]
	"Set the new Goal Density to a which should be a float in the range 0.0 - 1.0."
	[- 1.0 [/ [cloud-threshold! [* [- 1.0 a] 256.0]] 256.0]]
]]
	[- 1.0 [/ [cloud-threshold! [* [- 1.0 a] 256.0]] 256.0]]]

[def countdown [λ [i]
[defun countdown [i]
	"Counts down on the console"
	[cond [[< [int i] 0] #t]
		[#t [say  [cond [[zero? i] [[ansi-green "GO!"] [ansi-yellow "!"] [ansi-red "!"]]]
				[[< i 4] [ansi-red i]]
				[[< i 6] [ansi-yellow i]] [#t i]]]
		[yield [timeout 1000] [lambda []  [countdown [-- i]]]]
	]]
]]
		[yield [timeout 1000] [lambda []  [countdown [-- i]]]]]]]

; Needs to be a dynamic function because the player's ID is only in the calling context
[def debug-stuff! [λ [pid]
[defun debug-stuff! [pid]
        "Gives the issuing player some nice stuff to get started with"
        [say [ansi-rainbow "Have some stuff!"]]
	[clear-eq! pid]
	[clear-inv! pid]



@@ 144,8 109,8 @@
	[set-inv! 6 i-crystalspear 1 pid]
	[set-inv! 7 i-pear 42 pid]
	[set-inv! 8 i-dirt 99 pid ]
	[set-inv! 9 i-clusterbomb 99 pid]
	;[set-inv! 9 i-grenade 99]
	;[set-inv! 9 i-clusterbomb 99 pid]
	[set-inv! 9 i-grenade 99 pid]

	[set-inv! 10 i-blaster 1 pid]
	[set-inv! 11 i-flamethrower 1 pid]


@@ 161,5 126,4 @@
	[set-inv! 27 i-snow-grass 99 pid]
	[set-inv! 28 i-marble 99 pid]
	[set-inv! 29 i-marble-blocks 99 pid]
        "asd"
]]
        "asd"]

M tools/tools.nuj => tools/tools.nuj +3 -3
@@ 6,7 6,7 @@
[def git-get-branch [λ []
	"Returns the currently active branch"
	[let [[cur-head [trim [file/read "./.git/HEAD"]]]]
		[cond [[eq? [substr cur-head 0 4] "ref:"] [join [list-tail [split cur-head "/"] 2] "/"]]
		[cond [[== [substr cur-head 0 4] "ref:"] [join [list-tail [split cur-head "/"] 2] "/"]]
		       [#t "UNKNOWN"]
		]
	]


@@ 19,12 19,12 @@

[def infogen-version [λ []
	"Return the infogen version"
	[cat [git-get-branch] "-" [strftime [time] "%Y-%m-%d"] "-" [uppercase [substr [git-get-head] 0 8]]]
	[cat [git-get-branch] "-" [time/strftime [time] "%Y-%m-%d"] "-" [uppercase [substr [git-get-head] 0 8]]]
]]

[def infogen-builddate [λ []
	"Return the infogen builddate"
	[strftime [time] "%Y-%m-%d %H:%M"]
	[time/strftime [time] "%Y-%m-%d %H:%M"]
]]

[def infogen-commit [λ []