diff --git a/Toy b/Toy index 7cdb81e..185f389 160000 --- a/Toy +++ b/Toy @@ -1 +1 @@ -Subproject commit 7cdb81e0bfa846cb32ccf1935ab196628c9e25ed +Subproject commit 185f3896c52c781bcca6d22205f4be50eeaeff7f diff --git a/assets/main.toy b/assets/main.toy index a4ad7e5..9063af9 100644 --- a/assets/main.toy +++ b/assets/main.toy @@ -3,14 +3,14 @@ var frameCounter: Int = 0; var posCounter: Int = 0; fn onReady() { - loadMonsterSprite("parvati", "assets/parvati.png", 32, 32); + loadMonsterSprite("monster", "assets/parvati.png", 32, 32); } fn onStep() { frameCounter++; if (frameCounter % 100 == 0) { - spawnMonsterAt("parvati", posCounter*50, posCounter*50); + spawnMonsterAt("monster", posCounter*50, posCounter*50); posCounter++; } } @@ -21,4 +21,11 @@ fn onClose() { //example API for the game initScreen(1280, 720, "Hello raylib from Toy!"); -initLoop(onReady, onStep, onClose); \ No newline at end of file +initLoop(onReady, onStep, onClose); + +//test +fn brains(monster: Opaque) { + monster.setX(monster.x + 1); +} + +setMonsterStep(brains); diff --git a/source/main.c b/source/main.c index d80e2d2..12321c0 100644 --- a/source/main.c +++ b/source/main.c @@ -6,6 +6,7 @@ #include "toy_parser.h" #include "toy_compiler.h" #include "toy_vm.h" +#include "toy_attributes.h" #include "monster.h" @@ -86,6 +87,11 @@ void initScreen(Toy_VM* vm) { InitWindow(TOY_VALUE_AS_INTEGER(width), TOY_VALUE_AS_INTEGER(height), TOY_VALUE_AS_STRING(caption)->leaf.data); SetTargetFPS(60); + if (!IsWindowReady()) { + fprintf(stderr, TOY_CC_ERROR "ERROR: raylib failed to init the window, exiting" TOY_CC_RESET "\n"); + exit(-1); + } + Toy_freeValue(width); Toy_freeValue(height); Toy_freeValue(caption); @@ -199,8 +205,11 @@ int main() { Toy_VM vm; Toy_initVM(&vm); Toy_bindVM(&vm, entryCode, NULL); + initGameAPI(&vm); initMonsterAPI(&vm); + Toy_setOpaqueAttributeHandler(handleMonsterAttributes); + Toy_runVM(&vm); Toy_resetVM(&vm, false, false); //leave in a valid, but unset state @@ -226,6 +235,9 @@ int main() { if (IsKeyDown(KEY_LEFT)) player.position.x -= 5.0f; if (IsKeyDown(KEY_RIGHT)) player.position.x += 5.0f; + //process the monsters (if possible) + processMonsterStep(&vm); + //run the onStep function Toy_runVM(&vm); //no check needed, empty VMs are skipped diff --git a/source/monster.c b/source/monster.c index 9e2d53e..23bce6e 100644 --- a/source/monster.c +++ b/source/monster.c @@ -9,6 +9,7 @@ #include #include +#include //sprites loaded from disk typedef struct MonsterSprite { @@ -26,6 +27,7 @@ typedef struct MonsterData { //static storage static Toy_Table* spriteTable = NULL; static Toy_Array* monsterArray = NULL; +static Toy_Function* monsterStep = NULL; //callbacks static void loadMonsterSprite(Toy_VM* vm) { @@ -163,6 +165,23 @@ static void spawnMonsterAt(Toy_VM* vm) { }; } +static void setMonsterStep(Toy_VM* vm) { + Toy_Value value = Toy_popStack(&vm->stack); + + if (!TOY_VALUE_IS_FUNCTION(value) && !TOY_VALUE_IS_NULL(value)) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Bad argument type found in 'setMonsterStep', exiting" TOY_CC_RESET "\n"); + exit(-1); + } + + if (TOY_VALUE_IS_FUNCTION(value)) { + if (TOY_VALUE_AS_FUNCTION(value)->type != TOY_FUNCTION_CUSTOM) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Bad function found in 'setMonsterStep', exiting (only allows custom functions or null)" TOY_CC_RESET "\n"); + exit(-1); + } + monsterStep = TOY_VALUE_AS_FUNCTION(value); + } +} + //callback utils typedef struct CallbackPairs { const char* name; @@ -172,6 +191,7 @@ typedef struct CallbackPairs { static CallbackPairs callbackPairs[] = { {"loadMonsterSprite", loadMonsterSprite}, {"spawnMonsterAt", spawnMonsterAt}, + {"setMonsterStep", setMonsterStep}, {NULL, NULL}, }; @@ -214,6 +234,48 @@ void freeMonsterAPI(Toy_VM* vm) { monsterArray = Toy_resizeArray(monsterArray, 0); } +void processMonsterStep(Toy_VM* vm) { + //check for initialization + if (spriteTable == NULL || monsterArray == NULL) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Object pool for monster system hasn't been initialized" TOY_CC_RESET "\n"); + return; + } + + if (monsterStep == NULL) { + return; //no-op + } + + //BUG: invoking a callback with a parameter is process-heavy + + //bind a sub-vm + Toy_VM subVM; + Toy_inheritVM(vm, &subVM); + Toy_bindVM(&subVM, monsterStep->bytecode.code, monsterStep->bytecode.parentScope); + + //paramAddr is relative to the data section, and is followed by the param type + unsigned int paramAddr = ((unsigned int*)(subVM.code + subVM.paramAddr))[0]; + Toy_ValueType paramType = (Toy_ValueType)(((unsigned int*)(subVM.code + subVM.paramAddr))[1]); + + //c-string of the param's name && as a name string + const char* cstr = ((char*)(subVM.code + subVM.dataAddr)) + paramAddr; + Toy_String* name = Toy_toStringLength(&subVM.memoryBucket, cstr, strlen(cstr)); + + //load each valid monster and process them one at a time + for (unsigned int i = 0; i < monsterArray->count; i++) { + MonsterData* monster = (MonsterData*)TOY_VALUE_AS_OPAQUE(monsterArray->data[i]); + if (monster->health > 0) { + subVM.scope = Toy_pushScope(&subVM.memoryBucket, subVM.scope); + + Toy_declareScope(subVM.scope, name, paramType, Toy_copyValue(&subVM.memoryBucket, monsterArray->data[i]), true); + Toy_runVM(&subVM); + + subVM.scope = Toy_popScope(subVM.scope); + } + } + + Toy_freeVM(&subVM); +} + void drawMonsters(Toy_VM* vm) { (void)vm; @@ -230,4 +292,69 @@ void drawMonsters(Toy_VM* vm) { DrawTextureRec(monster->sprite->texture, monster->sprite->rect, monster->position, WHITE); } } +} + +static void attr_monsterSetX(Toy_VM* vm) { + Toy_Value compound = Toy_popStack(&vm->stack); + Toy_Value x = Toy_popStack(&vm->stack); + + if (!TOY_VALUE_IS_INTEGER(x)) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Bad argument type in MonsterData.setX() (expected 'Int', found '%s')" TOY_CC_RESET "\n", Toy_getValueTypeAsCString(x.type)); + } + + MonsterData* monster = (MonsterData*)TOY_VALUE_AS_OPAQUE(compound); + + monster->position.x = TOY_VALUE_AS_INTEGER(x); +} + +static void attr_monsterSetY(Toy_VM* vm) { + Toy_Value compound = Toy_popStack(&vm->stack); + Toy_Value y = Toy_popStack(&vm->stack); + + if (!TOY_VALUE_IS_INTEGER(y)) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Bad argument type in MonsterData.setY() (expected 'Int', found '%s')" TOY_CC_RESET "\n", Toy_getValueTypeAsCString(y.type)); + } + + MonsterData* monster = (MonsterData*)TOY_VALUE_AS_OPAQUE(compound); + + monster->position.y = TOY_VALUE_AS_INTEGER(y); +} + +Toy_Value handleMonsterAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { + //check for initialization + if (spriteTable == NULL || monsterArray == NULL) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Object pool for monster system hasn't been initialized" TOY_CC_RESET "\n"); + return TOY_VALUE_FROM_NULL(); + } + + //check for correct types + if (!TOY_VALUE_IS_OPAQUE(compound) || !TOY_VALUE_IS_STRING(attribute) || TOY_VALUE_AS_STRING(attribute)->info.type != TOY_STRING_LEAF) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Bad parameters found in 'handleMonsterAttributes'" TOY_CC_RESET "\n"); + return TOY_VALUE_FROM_NULL(); //do not free the params here + } + + MonsterData* monster = (MonsterData*)TOY_VALUE_AS_OPAQUE(compound); + + + if (TOY_VALUE_AS_STRING(attribute)->info.length == 1 && strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "x", 1) == 0) { + return TOY_VALUE_FROM_INTEGER(monster->position.x); + } + else if (TOY_VALUE_AS_STRING(attribute)->info.length == 1 && strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "y", 1) == 0) { + return TOY_VALUE_FROM_INTEGER(monster->position.y); + } + else if (TOY_VALUE_AS_STRING(attribute)->info.length == 4 && strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "setX", 4) == 0) { + Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_monsterSetX); + return TOY_VALUE_FROM_FUNCTION(fn); + } + else if (TOY_VALUE_AS_STRING(attribute)->info.length == 4 && strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "setY", 4) == 0) { + Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_monsterSetY); + return TOY_VALUE_FROM_FUNCTION(fn); + } + + else { + char buffer[256]; + snprintf(buffer, 256, "Unknown attribute '%s' of type MonsterData (an Opaque)", TOY_VALUE_AS_STRING(attribute)->leaf.data); + Toy_error(buffer); + return TOY_VALUE_FROM_NULL(); + } } \ No newline at end of file diff --git a/source/monster.h b/source/monster.h index d7bca39..3fd14aa 100644 --- a/source/monster.h +++ b/source/monster.h @@ -6,4 +6,7 @@ void initMonsterAPI(Toy_VM* vm); void freeMonsterAPI(Toy_VM* vm); +void processMonsterStep(Toy_VM* vm); void drawMonsters(Toy_VM* vm); + +Toy_Value handleMonsterAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); \ No newline at end of file