diff --git a/data/monstergen.lua b/data/monstergen.lua index 8aea0cf..2669234 100644 --- a/data/monstergen.lua +++ b/data/monstergen.lua @@ -37,10 +37,12 @@ local texturePaths = { } -local state = { - passive = 0, - agressive = 1, - scared = 2, +local behaviour = { + pacifist = 0, + normal = 1, + hostile = 2, + guerilla = 3, + coward = 4 } local stats = { @@ -89,31 +91,31 @@ local pests = { --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 0, "A Beetle" }, --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 64, 0, "A Large Grub" }, --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 80, 0, "A Small Grub" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 96, 0, "A Slim Worm" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 112, 0, "A Fat Worm" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 96, 0, "A Slim Worm", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 112, 0, "A Fat Worm", behaviour.pacifist }, --{ texturePaths.pest0, texturePaths.pest1, 0, 16, "Female Dragonfly" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 16, "A Fly" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 16, "A Fly", behaviour.pacifist }, --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 32, 16, "A Larva" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 16, "A Moth" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 16, "A Moth", behaviour.pacifist }, --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 64, 16 }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 80, 16, "A Gnat" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 80, 16, "A Gnat", behaviour.pacifist }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 0, 32, "A Small Spider" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 32, "A Medium Spider" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 32, 32, "A Large Spider" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 32, "A Small Scorpion" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 64, 32, "A Medium Scorpion" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 80, 32, "A Large Scorpion" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 0, 32, "A Small Spider", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 32, "A Medium Spider", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 32, 32, "A Large Spider", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 32, "A Small Scorpion", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 64, 32, "A Medium Scorpion", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 80, 32, "A Large Scorpion", behaviour.pacifist }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 0, 48, "A Slug" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 48, "A Large Slug" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 0, 48, "A Slug", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 48, "A Large Slug", behaviour.pacifist }, --{ texturePaths.pest0, texturePaths.pest1, 32, 48 }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 48, "A Red Slug" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 64, 48, "A Large Red Slug" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 48, "A Red Slug", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 64, 48, "A Large Red Slug", behaviour.pacifist }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 0, 64, "A Giant Brown Ant" }, - { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 64, "A Giant Black Ant" }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 0, 64, "A Giant Brown Ant", behaviour.pacifist }, + { texturePaths.pest0, texturePaths.pest1, stats.pest, 16, 64, "A Giant Black Ant", behaviour.pacifist }, --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 32, 64, "A Giant Gold Ant" }, --{ texturePaths.pest0, texturePaths.pest1, stats.pest, 48, 64, "A Giant Silver Ant" }, @@ -134,61 +136,61 @@ local pests = { local undead = { -- UNDEAD - --{ texturePaths.undead0, texturePaths.undead1, 0, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 16, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 32, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 48, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 64, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 80, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 96, 0, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 112, 0, "", state.passive, state.agressive }; + --{ texturePaths.undead0, texturePaths.undead1, 0, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 16, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 32, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 48, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 64, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 80, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 96, 0, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 112, 0, "", behaviour.normal }; - --{ texturePaths.undead0, texturePaths.undead1, 0, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 16, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 32, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 48, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 64, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 80, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 96, 16, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 112, 16, "", state.passive, state.agressive }; + --{ texturePaths.undead0, texturePaths.undead1, 0, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 16, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 32, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 48, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 64, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 80, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 96, 16, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 112, 16, "", behaviour.normal }; - { texturePaths.undead0, texturePaths.undead1, stats.undead, 0, 32, "A Skeleton", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 16, 32, "An Umber Skeleton", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 32, 32, "A Caustic Skeleton", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, stats.undead, 48, 32, "A Black Skeleton", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, stats.undead, 64, 32, "A Zombie", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, stats.undead, 80, 32, "A Zombie", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 96, 32, "", state.passive, state.agressive }; - --{ texturePaths.undead0, texturePaths.undead1, 112, 32, "", state.passive, state.scared }; + { texturePaths.undead0, texturePaths.undead1, stats.undead, 0, 32, "A Skeleton", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 16, 32, "An Umber Skeleton", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 32, 32, "A Caustic Skeleton", behaviour.normal }; + { texturePaths.undead0, texturePaths.undead1, stats.undead, 48, 32, "A Black Skeleton", behaviour.normal }; + { texturePaths.undead0, texturePaths.undead1, stats.undead, 64, 32, "A Zombie", behaviour.normal }; + { texturePaths.undead0, texturePaths.undead1, stats.undead, 80, 32, "A Zombie", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 96, 32, "", behaviour.normal }; + --{ texturePaths.undead0, texturePaths.undead1, 112, 32, "", behaviour.normal }; } local dogs = { - { texturePaths.dog0, texturePaths.dog1, stats.dog, 0, 16, "A Rabid Dog", state.passive, state.agressive }; - { texturePaths.dog0, texturePaths.dog1, stats.dog, 16, 16, "An Angry Rabid Dog", state.agressive, state.agressive }; + { texturePaths.dog0, texturePaths.dog1, stats.dog, 0, 16, "A Rabid Dog", behaviour.normal }; + { texturePaths.dog0, texturePaths.dog1, stats.dog, 16, 16, "An Angry Rabid Dog", behaviour.hostile }; } local reptile = { - { texturePaths.reptile0, texturePaths.reptile1, stats.default, 0, 64, "A Small Brown Snake", state.passive, state.agressive }; - { texturePaths.reptile0, texturePaths.reptile1, stats.default, 16, 64, "A Medium Brown Snake", state.passive, state.agressive }; - { texturePaths.reptile0, texturePaths.reptile1, stats.default, 32, 64, "A Large Brown Snake", state.passive, state.agressive }; - { texturePaths.reptile0, texturePaths.reptile1, stats.default, 48, 64, "A Small Black Snake", state.agressive, state.agressive }; - { texturePaths.reptile0, texturePaths.reptile1, stats.default, 64, 64, "A Medium Black Snake", state.agressive, state.agressive }; - { texturePaths.reptile0, texturePaths.reptile1, stats.default, 80, 64, "A Large Black Snake", state.agressive, state.agressive }; + { texturePaths.reptile0, texturePaths.reptile1, stats.default, 0, 64, "A Small Brown Snake", behaviour.coward }; + { texturePaths.reptile0, texturePaths.reptile1, stats.default, 16, 64, "A Medium Brown Snake", behaviour.guerilla }; + { texturePaths.reptile0, texturePaths.reptile1, stats.default, 32, 64, "A Large Brown Snake", behaviour.hostile }; + { texturePaths.reptile0, texturePaths.reptile1, stats.default, 48, 64, "A Small Black Snake", behaviour.coward }; + { texturePaths.reptile0, texturePaths.reptile1, stats.default, 64, 64, "A Medium Black Snake", behaviour.guerilla }; + { texturePaths.reptile0, texturePaths.reptile1, stats.default, 80, 64, "A Large Black Snake", behaviour.hostile }; } local platino = { - { texturePaths.reptile0, texturePaths.reptile1, stats.platino, 48, 12*16, "Platino", state.agressive, state.agressive }; + { texturePaths.reptile0, texturePaths.reptile1, stats.platino, 48, 12*16, "Platino", behaviour.hostile }; } local demon = { - { texturePaths.demon0, texturePaths.demon1, stats.default, 0, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 16, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 32, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 48, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 64, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 80, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 96, 0, "A Demon", state.agressive, state.agressive }; - { texturePaths.demon0, texturePaths.demon1, stats.default, 112, 0, "A Demon", state.agressive, state.agressive }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 0, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 16, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 32, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 48, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 64, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 80, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 96, 0, "A Demon", behaviour.hostile }; + { texturePaths.demon0, texturePaths.demon1, stats.default, 112, 0, "A Demon", behaviour.hostile }; } local function concat(table1, table2) @@ -206,8 +208,7 @@ local function repack(data) clipX = data[4], clipY = data[5], label = data[6] or "", - nstate = data[7] or state.passive, - cstate = data[8] or state.scared, + behaviour = data[7] or behaviour.normal, } end diff --git a/src/map_lua.c b/src/map_lua.c index c7f3992..53fa427 100644 --- a/src/map_lua.c +++ b/src/map_lua.c @@ -281,7 +281,7 @@ l_add_monster(lua_State *L) { Monster *monster; Map *map; - int x, y, clip_x, clip_y, nstate, cstate; + int x, y, clip_x, clip_y, behaviour; const char *texture_path_1, *texture_path_2, *tmp_label; char *label; Texture *texture1, *texture2; @@ -301,17 +301,15 @@ l_add_monster(lua_State *L) lua_getfield(L, 4, "stats"); lua_getfield(L, 4, "clipX"); lua_getfield(L, 4, "clipY"); - lua_getfield(L, 4, "nstate"); - lua_getfield(L, 4, "cstate"); + lua_getfield(L, 4, "behaviour"); - tmp_label = luaL_checkstring(L, -8); - texture_path_1 = luaL_checkstring(L, -7); - texture_path_2 = luaL_checkstring(L, -6); - stats = lua_checkstats(L, -5); - clip_x = (int) luaL_checkinteger(L, -4); - clip_y = (int) luaL_checkinteger(L, -3); - nstate = (int) luaL_checkinteger(L, -2); - cstate = (int) luaL_checkinteger(L, -1); + tmp_label = luaL_checkstring(L, -7); + texture_path_1 = luaL_checkstring(L, -6); + texture_path_2 = luaL_checkstring(L, -5); + stats = lua_checkstats(L, -4); + clip_x = (int) luaL_checkinteger(L, -3); + clip_y = (int) luaL_checkinteger(L, -2); + behaviour = (int) luaL_checkinteger(L, -1); texture1 = texturecache_add(texture_path_1); texture2 = texturecache_add(texture_path_2); @@ -328,7 +326,7 @@ l_add_monster(lua_State *L) monster_update_pos(monster, (Position) { x, y }); sprite_set_texture(monster->sprite, texture1, 0); sprite_set_texture(monster->sprite, texture2, 1); - monster_set_states(monster, nstate, cstate); + monster_set_behaviour(monster, behaviour); if (strlen(label)) { monster->label = label; monster->lclabel = to_lower(label); diff --git a/src/monster.c b/src/monster.c index 28627de..1e13e18 100644 --- a/src/monster.c +++ b/src/monster.c @@ -34,6 +34,82 @@ #include "actiontextbuilder.h" #include "texturecache.h" +static void +monster_set_sprite_clip_for_current_state(Monster *m) +{ + switch (m->state.current) { + case AGRESSIVE: + m->stateIndicator.sprite->clip = CLIP16(16 * 11, 16 * 3); + break; + case STATIONARY: + case PASSIVE: + m->stateIndicator.sprite->clip = CLIP16(16 * 10, 16); + break; + case SCARED: + m->stateIndicator.sprite->clip = CLIP16(16 * 12, 16 * 3); + break; + default: + break; + } +} + +static void +monster_state_change(Monster *m, StateType newState) +{ + if (m->state.current == newState) + return; + + m->state.current = newState; + m->state.stepsSinceChange = 0; + m->stateIndicator.displayCount = 5; + + monster_set_sprite_clip_for_current_state(m); +} + +static void +monster_behaviour_check_post_hit(Monster *m) +{ + switch (m->behaviour) { + case NORMAL: + monster_state_change(m, AGRESSIVE); + break; + case PACIFIST: + case COWARD: + monster_state_change(m, SCARED); + break; + default: + break; + } +} + +static void +monster_behaviour_check_post_attack(Monster *m) +{ + switch (m->behaviour) { + case GUERILLA: + monster_state_change(m, SCARED); + break; + default: + break; + } +} + +static void +monster_behaviour_check(Monster *m, RoomMatrix *rm) +{ + UNUSED(rm); + switch (m->behaviour) { + case GUERILLA: + if (m->state.stepsSinceChange > 8 + && m->state.current == SCARED) { + monster_state_change(m, AGRESSIVE); + } + break; + default: + break; + } +} + Monster* monster_create(void) { @@ -61,7 +137,7 @@ monster_create(void) m->stateIndicator.sprite->dim = GAME_DIMENSION; m->stateIndicator.displayCount = 0; m->stateIndicator.shownOnPlayerRoomEnter = false; - monster_set_states(m, PASSIVE, AGRESSIVE); + monster_set_behaviour(m, NORMAL); return m; } @@ -98,6 +174,7 @@ has_collided(Monster *monster, RoomMatrix *matrix, Vector2d direction) } else { gui_log("%s missed you", monster->label); } + monster_behaviour_check_post_attack(monster); } return space->occupied || space->lethal; @@ -239,6 +316,8 @@ monster_move(Monster *m, RoomMatrix *rm) rm->spaces[monsterRoomPos.x][monsterRoomPos.y].occupied = false; rm->spaces[monsterRoomPos.x][monsterRoomPos.y].monster = NULL; + monster_behaviour_check(m, rm); + switch (m->state.current) { case PASSIVE: monster_drunk_walk(m, rm); @@ -249,6 +328,9 @@ monster_move(Monster *m, RoomMatrix *rm) case SCARED: monster_coward_walk(m, rm); break; + case STATIONARY: + default: + break; }; monster_update_pos(m, m->sprite->pos); @@ -261,6 +343,7 @@ monster_move(Monster *m, RoomMatrix *rm) if (m->steps >= m->stats.speed) { if (m->stateIndicator.displayCount > 0) m->stateIndicator.displayCount -= 1; + m->state.stepsSinceChange += 1; m->steps = 0; return true; } @@ -284,36 +367,6 @@ monster_update(Monster *m, UpdateData *data) } } -static void -monster_set_sprite_clip_for_current_state(Monster *m) -{ - switch (m->state.current) { - case AGRESSIVE: - m->stateIndicator.sprite->clip = CLIP16(16 * 11, 16 * 3); - break; - case PASSIVE: - m->stateIndicator.sprite->clip = CLIP16(16 * 10, 16); - break; - case SCARED: - m->stateIndicator.sprite->clip = CLIP16(16 * 12, 16 * 3); - break; - default: - break; - } -} - -static void -monster_state_change(Monster *m) -{ - if (m->state.current == m->state.challenge) - return; - - m->state.current = m->state.challenge; - m->stateIndicator.displayCount = 5; - - monster_set_sprite_clip_for_current_state(m); -} - void monster_hit(Monster *monster, unsigned int dmg) { @@ -333,8 +386,7 @@ monster_hit(Monster *monster, unsigned int dmg) C_YELLOW, &monster->sprite->pos); } - - monster_state_change(monster); + monster_behaviour_check_post_hit(monster); } void @@ -410,11 +462,21 @@ monster_render(Monster *m, Camera *cam) } void -monster_set_states(Monster *m, StateType normal, StateType challenge) +monster_set_behaviour(Monster *m, MonsterBehaviour behaviour) { - m->state.normal = normal; - m->state.current = normal; - m->state.challenge = challenge; + m->behaviour = behaviour; + switch (behaviour) { + case HOSTILE: + case GUERILLA: + case COWARD: + m->state.current = AGRESSIVE; + break; + case PACIFIST: + case NORMAL: + default: + m->state.current = PASSIVE; + break; + } monster_set_sprite_clip_for_current_state(m); } diff --git a/src/monster.h b/src/monster.h index b52479d..7df48ad 100644 --- a/src/monster.h +++ b/src/monster.h @@ -28,12 +28,24 @@ struct UpdateData_t; -typedef enum { PASSIVE, AGRESSIVE, SCARED } StateType; +typedef enum { + PACIFIST, + NORMAL, + HOSTILE, + GUERILLA, + COWARD +} MonsterBehaviour; + +typedef enum { + PASSIVE, + AGRESSIVE, + SCARED, + STATIONARY +} StateType; typedef struct { StateType current; - StateType normal; - StateType challenge; + unsigned int stepsSinceChange; } State; typedef struct MonsterStateIndicator { @@ -49,6 +61,7 @@ typedef struct Monster_t { Stats stats; State state; MonsterStateIndicator stateIndicator; + MonsterBehaviour behaviour; unsigned int steps; } Monster; @@ -76,7 +89,7 @@ void monster_drop_loot(Monster*, Map*, Player*); void -monster_set_states(Monster *, StateType normal, StateType challenge); +monster_set_behaviour(Monster *, MonsterBehaviour m); void monster_destroy(Monster*);