From dff55a19783134b3805f8cd405c37bea26d55f09 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Thu, 14 Jun 2018 00:12:49 +0200 Subject: [PATCH 01/18] Fixes some buggs - Fixes mapbuilder pit loading nullpointer - Fixes black main menu bg after return to main menu - Fixes skill sparkling on new game start --- data/maproombuilder.lua | 1 + src/main.c | 1 + src/skillbar.c | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/data/maproombuilder.lua b/data/maproombuilder.lua index 7343fbc..90cc197 100644 --- a/data/maproombuilder.lua +++ b/data/maproombuilder.lua @@ -188,6 +188,7 @@ local function add_pits_to_room(map) end end + matrix = matrix[random(#matrix)] for i=2,13 do for j=2,10 do if not tile_occupied(map, (i), (j)) and matrix[i][j] then diff --git a/src/main.c b/src/main.c index df37918..d2d26b2 100644 --- a/src/main.c +++ b/src/main.c @@ -250,6 +250,7 @@ goToMainMenu(void *unused) inGameMenu = NULL; initMainMenu(); Position p = { 0, 0 }; + gPlayer->sprite->pos = (Position) { 32, 32 }; map_set_current_room(gMap, &p); camera_follow_position(gCamera, &p); } diff --git a/src/skillbar.c b/src/skillbar.c index 7c2fcc6..ea20d73 100644 --- a/src/skillbar.c +++ b/src/skillbar.c @@ -222,6 +222,10 @@ render_skill_sparkles(SkillBar *bar, Player *player) return; } + if (player->stats.lvl == 1) { + return; + } + Position pos = { 0, GAME_VIEW_HEIGHT }; Dimension dim = { 32, 32 }; for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { From 53dc7e2fe62bff15cf3213ab29adeb6c94953c03 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Sat, 23 Jun 2018 14:30:29 +0200 Subject: [PATCH 02/18] Possibly more accurate scaling. --- src/main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.c b/src/main.c index d2d26b2..fafd70a 100644 --- a/src/main.c +++ b/src/main.c @@ -108,10 +108,6 @@ bool initSDL(void) if (dim.height > 1080) { info("Hi resolution screen detected (%u x %u)", dim.width, dim.height); renderScale = ((double) dim.height)/1080; - if (renderScale > 2) - renderScale = 3; - else if (renderScale > 1) - renderScale = 2; info("Scaling by %f", renderScale); } From f36a9dd2ac1f11527425a972e10397cd3852531a Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Thu, 28 Jun 2018 12:50:32 +0200 Subject: [PATCH 03/18] Sleeping state indicator is always visible. --- src/monster.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/monster.c b/src/monster.c index 9577cf7..1684691 100644 --- a/src/monster.c +++ b/src/monster.c @@ -66,7 +66,11 @@ monster_state_change(Monster *m, StateType newState) m->state.current = newState; m->state.stepsSinceChange = 0; - m->stateIndicator.displayCount = 5; + + if (newState == SLEEPING) + m->stateIndicator.displayCount = -1; + else + m->stateIndicator.displayCount = 5; monster_set_sprite_clip_for_current_state(m); } @@ -389,7 +393,9 @@ monster_update(Monster *m, UpdateData *data) return; m->stateIndicator.shownOnPlayerRoomEnter = true; - if (m->state.current != PASSIVE && m->state.current != STATIONARY) + if (m->state.current == SLEEPING) + m->stateIndicator.displayCount = -1; // Sleeping state is always shown + else if (m->state.current != PASSIVE && m->state.current != STATIONARY) m->stateIndicator.displayCount = 5; } else { m->stateIndicator.shownOnPlayerRoomEnter = false; @@ -486,7 +492,7 @@ monster_render(Monster *m, Camera *cam) return; sprite_render(m->sprite, cam); - if (m->stateIndicator.displayCount > 0) + if (m->stateIndicator.displayCount != 0) sprite_render(m->stateIndicator.sprite, cam); } From a30d501e86e0c6ae41bbf96080bc37bc5040a08d Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Thu, 28 Jun 2018 12:54:15 +0200 Subject: [PATCH 04/18] Patch version raised to 7 --- CMakeLists.txt | 2 +- build/releasenotes/early-access-v7.txt | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 build/releasenotes/early-access-v7.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e9e5dbc..4ec985e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(breakhack C) set(breakhack_GAME_TITLE "BreakHack") set(breakhack_MAJOR_VERSION 0) set(breakhack_MINOR_VERSION 1) -set(breakhack_PATCH_VERSION 6) +set(breakhack_PATCH_VERSION 7) set(breakhack_RELEASE_TYPE "(early access)") include(FindLua) diff --git a/build/releasenotes/early-access-v7.txt b/build/releasenotes/early-access-v7.txt new file mode 100644 index 0000000..22963ac --- /dev/null +++ b/build/releasenotes/early-access-v7.txt @@ -0,0 +1,18 @@ +f36a9dd Sleeping state indicator is always visible. +53dc7e2 Possibly more accurate scaling. +dff55a1 Fixes some buggs +6a9a3bd Removed some old debug output from pitlayouts. +cc229c8 Prepares pengine for more particle types. +bbe4526 Fixes colors to use defines. +2462e4c Adds sentinel monster behaviour. +a66f16d Reintroduces the pointer and mouse menu operation. +123ae90 Better mod key logic in input and mouse motion check. +821cac2 Completely separates input handling and game logic. +186cc7b Replaced state logic with behaviours instead. +b905232 ....and once again... +8573bad ...and include the SDL dll +8c58c6e And once again for windows! +6788e3c Another trywq +60114ed Hopefully fixes the build issues +e222e51 Don't test on clang and fix include problem in appveyor +138cba1 Mock test for keyboardinput and fixed the found issues From c6b643835b98b157554735de060be1d509f24ca6 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Fri, 6 Jul 2018 12:12:27 +0200 Subject: [PATCH 05/18] Added codefactor badge and fixed blank line issue. --- README.md | 1 + src/linkedlist.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64f221f..0294029 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![Build Status](https://travis-ci.org/LiquidityC/breakhack.svg?branch=master)](https://travis-ci.org/LiquidityC/breakhack) [![Build Status](https://ci.appveyor.com/api/projects/status/2nvna97cmm4cf535?svg=true)](https://ci.appveyor.com/project/LiquidityC/breakhack) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/fc02d56fa7194e61b2c7d260fd2e4186)](https://www.codacy.com/app/LiquidityC/breakhack?utm_source=github.com&utm_medium=referral&utm_content=LiquidityC/breakhack&utm_campaign=Badge_Grade) +[![CodeFactor](https://www.codefactor.io/repository/github/liquidityc/breakhack/badge/master)](https://www.codefactor.io/repository/github/liquidityc/breakhack/overview/master) Something in the ways of NETHACK diff --git a/src/linkedlist.h b/src/linkedlist.h index 919a3ea..3496bd1 100644 --- a/src/linkedlist.h +++ b/src/linkedlist.h @@ -42,6 +42,5 @@ void linkedlist_each(LinkedList **head, void (*fun)(void*)); void linkedlist_destroy(LinkedList **head); unsigned int linkedlist_size(LinkedList *head); - #endif // LINKEDLIST_H_ From c96d0b671834362412d4ab8bed5840927bccf269 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Fri, 6 Jul 2018 22:30:28 +0200 Subject: [PATCH 06/18] Removes bug that made it possible to move with daggers in air. --- src/player.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/player.c b/src/player.c index 8408fd7..b33a1a3 100644 --- a/src/player.c +++ b/src/player.c @@ -229,6 +229,11 @@ handle_next_move(UpdateData *data) static unsigned int step = 1; Player *player = data->player; + + // Don't move when projectiles are still moving + if (linkedlist_size(player->projectiles) > 0) + return; + RoomMatrix *matrix = data->matrix; Vector2d nextDir = read_direction_from(data->input); if (!vector2d_equals(nextDir, VECTOR2D_NODIR)) @@ -327,7 +332,11 @@ player_create(class_t class, SDL_Renderer *renderer) { Player *player = malloc(sizeof(Player)); player->sprite = sprite_create(); +#ifdef DEBUG + player->daggers = 10; +#else player->daggers = 0; +#endif player->stat_data.total_steps = 0; player->stat_data.steps = 0; player->stat_data.hits = 0; @@ -440,7 +449,6 @@ player_render(Player *player, Camera *cam) projectile_render(projectile->data, cam); projectile = projectile->next; } - } void From 79b08699743281b5038b11995c3d46d31970171d Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Fri, 6 Jul 2018 22:54:15 +0200 Subject: [PATCH 07/18] Adds sword swing effect that isn't horrible --- assets/Extras/sword_swing.png | Bin 0 -> 297 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/Extras/sword_swing.png diff --git a/assets/Extras/sword_swing.png b/assets/Extras/sword_swing.png new file mode 100644 index 0000000000000000000000000000000000000000..bd8a783633f4f87403e073f76bff23349b893cbc GIT binary patch literal 297 zcmV+^0oMMBP)H)Z$V6_Ii(E(>E0MSU4 zmlg7&CfrlhI=T1?x6iNeN`54Wy9h)KqKTB;RhHmoQ3t59RUazf$EdPX9HN8md13;q z4WRN>R^jLvRs+9$0}%X(4u1j84x%O?Gth2cY5xQdyak^00000NkvXXu0mjfC!mAp literal 0 HcmV?d00001 From 988d6c5cac821b85db08716b8351ad8ad79004b7 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Mon, 9 Jul 2018 19:26:06 +0200 Subject: [PATCH 08/18] Implemented the sword swing effect. This adds the animation type for future use. Not super happy with the animation png. Will look over it in the future. --- CMakeLists.txt | 1 + .../{sword_swing.png => SwordSwing.png} | Bin src/animation.c | 117 ++++++++++++++++++ src/animation.h | 75 +++++++++++ src/camera.h | 2 +- src/main.c | 2 + src/player.c | 54 ++++++++ src/player.h | 7 +- src/roommatrix.h | 2 +- src/sprite.c | 6 +- src/sprite.h | 6 +- src/timer.h | 2 +- 12 files changed, 264 insertions(+), 10 deletions(-) rename assets/Extras/{sword_swing.png => SwordSwing.png} (100%) create mode 100644 src/animation.c create mode 100644 src/animation.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ec985e..c133be0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,7 @@ add_executable(breakhack src/db src/settings src/actiontextbuilder + src/animation ) # Sqlite has some warnings that I we don't need to see diff --git a/assets/Extras/sword_swing.png b/assets/Extras/SwordSwing.png similarity index 100% rename from assets/Extras/sword_swing.png rename to assets/Extras/SwordSwing.png diff --git a/src/animation.c b/src/animation.c new file mode 100644 index 0000000..cd63542 --- /dev/null +++ b/src/animation.c @@ -0,0 +1,117 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "animation.h" +#include "timer.h" +#include "camera.h" +#include "sprite.h" +#include "util.h" + +Animation * +animation_create(unsigned int clipCount) +{ + Animation *animation = ec_malloc(sizeof(Animation) + + clipCount * sizeof(AnimationClip)); + animation->clipTimer = timer_create(); + animation->clipCount = clipCount; + animation->currentClip = 0; + animation->loop = true; + animation->running = false; + animation->sprite = sprite_create(); + return animation; +} + +void +animation_load_texture(Animation *animation, const char *path, SDL_Renderer *renderer) +{ + sprite_load_texture(animation->sprite, path, 0, renderer); +} + +void +animation_update(Animation *animation) +{ + if (!animation->running) { + return; + } + + if (!timer_started(animation->clipTimer)) { + timer_start(animation->clipTimer); + } + + if (timer_get_ticks(animation->clipTimer) + > animation->clips[animation->currentClip].renderTime) + { + animation->currentClip++; + if (animation->currentClip >= animation->clipCount) { + animation->currentClip = 0; + if (!animation->loop) { + animation_stop(animation); + return; + } + timer_start(animation->clipTimer); + } + } + + animation->sprite->clip = (SDL_Rect) { + animation->clips[animation->currentClip].x, + animation->clips[animation->currentClip].y, + animation->clips[animation->currentClip].w, + animation->clips[animation->currentClip].h + }; +} + +void +animation_render(Animation *animation, Camera *camera) +{ + if (!animation->running) { + return; + } + + sprite_render(animation->sprite, camera); +} + +void +animation_set_frames(Animation *animation, AnimationClip clips[]) +{ + for (size_t i = 0; i < animation->clipCount; i++) { + animation->clips[i] = clips[i]; + } +} + +void +animation_run(Animation *a) +{ + a->running = true; +} + +void +animation_stop(Animation *a) +{ + a->running = false; + a->currentClip = 0; + timer_stop(a->clipTimer); +} + +void +animation_destroy(Animation *animation) +{ + timer_destroy(animation->clipTimer); + sprite_destroy(animation->sprite); + free(animation); +} + diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..b6f8031 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,75 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ANIMATION_H +#define _ANIMATION_H + +#include +#include + +typedef struct Timer Timer; +typedef struct Camera Camera; +typedef struct Sprite Sprite; + +typedef struct AnimationClip +{ + unsigned int x; + unsigned int y; + unsigned int w; + unsigned int h; + unsigned int renderTime; +} AnimationClip; + +typedef struct Animation +{ + Sprite *sprite; + Timer *clipTimer; + unsigned int currentClip; + bool loop; + unsigned int clipCount; + bool running; + AnimationClip clips[]; +} Animation; + +Animation* +animation_create(unsigned int clipCount); + +void +animation_load_texture(Animation *, const char *path, SDL_Renderer*); + +void +animation_set_frames(Animation*, AnimationClip clips[]); + +void +animation_run(Animation*); + +void +animation_update(Animation*); + +void +animation_render(Animation*, Camera*); + +void +animation_stop(Animation*); + +void +animation_destroy(Animation*); + +#endif // _ANIMATION_H + + diff --git a/src/camera.h b/src/camera.h index 3dbae66..9fb876b 100644 --- a/src/camera.h +++ b/src/camera.h @@ -25,7 +25,7 @@ #include "timer.h" #include "vector2d.h" -typedef struct { +typedef struct Camera { Position pos; Position basePos; Vector2d velocity; diff --git a/src/main.c b/src/main.c index fafd70a..36e76a4 100644 --- a/src/main.c +++ b/src/main.c @@ -516,6 +516,8 @@ run_game(void) map_render_top_layer(gMap, gCamera); + player_render_toplayer(gPlayer, gCamera); + if (gPlayer->class == MAGE || gPlayer->class == PALADIN) roommatrix_render_mouse_square(gRoomMatrix, gCamera); diff --git a/src/player.c b/src/player.c index b33a1a3..fb490d7 100644 --- a/src/player.c +++ b/src/player.c @@ -33,6 +33,7 @@ #include "texturecache.h" #include "vector2d.h" #include "actiontextbuilder.h" +#include "animation.h" #define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1 } #define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1 } @@ -133,6 +134,8 @@ has_collided(Player *player, RoomMatrix *matrix, Vector2d direction) monster_hit(space->monster, hit); + animation_run(player->swordAnimation); + if (hit > 0) { gui_log("You hit %s for %u damage", space->monster->lclabel, hit); @@ -246,6 +249,27 @@ handle_next_move(UpdateData *data) ++step; step = step % 4; } + + if (!vector2d_equals(nextDir, VECTOR2D_NODIR)) + player->swordAnimation->sprite->pos = player->sprite->pos; + + if (vector2d_equals(nextDir, VECTOR2D_UP)) { + player->swordAnimation->sprite->pos.y -= 32; + player->swordAnimation->sprite->angle = -90; + player->swordAnimation->sprite->flip = SDL_FLIP_NONE; + } else if (vector2d_equals(nextDir, VECTOR2D_DOWN)) { + player->swordAnimation->sprite->pos.y += 32; + player->swordAnimation->sprite->angle = 90; + player->swordAnimation->sprite->flip = SDL_FLIP_NONE; + } else if (vector2d_equals(nextDir, VECTOR2D_LEFT)) { + player->swordAnimation->sprite->pos.x -= 32; + player->swordAnimation->sprite->angle = 0; + player->swordAnimation->sprite->flip = SDL_FLIP_HORIZONTAL; + } else if (vector2d_equals(nextDir, VECTOR2D_RIGHT)) { + player->swordAnimation->sprite->pos.x += 32; + player->swordAnimation->sprite->angle = 0; + player->swordAnimation->sprite->flip = SDL_FLIP_NONE; + } } static void @@ -327,6 +351,24 @@ check_skill_trigger(UpdateData *data) return true; } +static void +build_sword_animation(Player *p, SDL_Renderer *renderer) +{ + animation_load_texture(p->swordAnimation, "Extras/SwordSwing.png", renderer); + animation_set_frames(p->swordAnimation, (AnimationClip[]) { + { 0, 0, 16, 16, 20 }, + { 16, 0, 16, 16, 20 }, + { 32, 0, 16, 16, 20 }, + { 48, 0, 16, 16, 20 }, + { 64, 0, 16, 16, 20 } + }); + + p->swordAnimation->loop = false; + p->swordAnimation->sprite->dim = GAME_DIMENSION; + p->swordAnimation->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 }; + p->swordAnimation->sprite->rotationPoint = (SDL_Point) { 16, 16 }; +} + Player* player_create(class_t class, SDL_Renderer *renderer) { @@ -349,6 +391,9 @@ player_create(class_t class, SDL_Renderer *renderer) player->state = ALIVE; player->projectiles = linkedlist_create(); player->animationTimer = timer_create(); + player->swordAnimation = animation_create(5); + + build_sword_animation(player, renderer); for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) { player->skills[i] = NULL; @@ -451,6 +496,12 @@ player_render(Player *player, Camera *cam) } } +void +player_render_toplayer(Player *player, Camera *camera) +{ + animation_render(player->swordAnimation, camera); +} + void player_reset_steps(Player *p) { @@ -503,6 +554,8 @@ void player_update(UpdateData *data) linkedlist_destroy(&player->projectiles); player->projectiles = remaining; + + animation_update(player->swordAnimation); } void @@ -511,6 +564,7 @@ player_destroy(Player *player) if (player->sprite) sprite_destroy(player->sprite); + animation_destroy(player->swordAnimation); timer_destroy(player->animationTimer); for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) { diff --git a/src/player.h b/src/player.h index 352fc3d..03267ba 100644 --- a/src/player.h +++ b/src/player.h @@ -31,7 +31,8 @@ #define PLAYER_SKILL_COUNT 5 // Foward declare -struct UpdateData; +typedef struct UpdateData UpdateData; +typedef struct Animation Animation; typedef enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR } class_t; typedef enum PlayerState { ALIVE, DEAD, FALLING } state_t; @@ -64,6 +65,7 @@ typedef struct Player_t { state_t state; Skill *skills[PLAYER_SKILL_COUNT]; Timer *animationTimer; + Animation *swordAnimation; } Player; Player* @@ -90,6 +92,9 @@ player_update(struct UpdateData *); void player_render(Player*, Camera*); +void +player_render_toplayer(Player*, Camera*); + void player_destroy(Player*); diff --git a/src/roommatrix.h b/src/roommatrix.h index 1cdbe22..979ed57 100644 --- a/src/roommatrix.h +++ b/src/roommatrix.h @@ -26,7 +26,7 @@ #include "map_room_modifiers.h" #include "input.h" -typedef struct Sprite_t Sprite; +typedef struct Sprite Sprite; typedef struct Map_t Map; typedef struct Monster_t Monster; typedef struct Player_t Player; diff --git a/src/sprite.c b/src/sprite.c index 3ba49f9..e1a4040 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -51,7 +51,7 @@ sprite_create(void) void sprite_load_texture(Sprite *sprite, - char *path, + const char *path, int index, SDL_Renderer *renderer) { @@ -68,7 +68,7 @@ sprite_load_texture(Sprite *sprite, sprite->destroyTextures = true; } -void sprite_load_text_texture(Sprite *sprite, char * path, int index, int size, int outline) +void sprite_load_text_texture(Sprite *sprite, const char * path, int index, int size, int outline) { if (index > 1) fatal("in sprite_load_texture() index out of bounds"); @@ -122,7 +122,7 @@ sprite_render(Sprite *s, Camera *cam) cameraPos.x, cameraPos.y, s->dim.width, s->dim.height }; - if ((s->clip.w && s->clip.h) || s->angle != 0 || s->flip != SDL_FLIP_NONE) { + if (s->angle != 0 || s->flip != SDL_FLIP_NONE) { texture_render_clip_ex(s->textures[s->texture_index], &box, &s->clip, diff --git a/src/sprite.h b/src/sprite.h index bbea9ad..38b0c56 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -27,7 +27,7 @@ #include "roommatrix.h" #include "timer.h" -typedef struct Sprite_t { +typedef struct Sprite { Texture* textures[2]; SDL_Rect clip; bool destroyTextures; @@ -46,9 +46,9 @@ typedef struct Sprite_t { Sprite* sprite_create(void); -void sprite_load_texture(Sprite *, char *path, int index, SDL_Renderer *); +void sprite_load_texture(Sprite *, const char *path, int index, SDL_Renderer *); -void sprite_load_text_texture(Sprite *, char *path, int index, int size, int outline); +void sprite_load_text_texture(Sprite *, const char *path, int index, int size, int outline); void sprite_set_texture(Sprite *, Texture *, int index); diff --git a/src/timer.h b/src/timer.h index 98d2e11..86c45c1 100644 --- a/src/timer.h +++ b/src/timer.h @@ -21,7 +21,7 @@ #include -typedef struct { +typedef struct Timer { unsigned int startTime; } Timer; From 252955bc8d1be7ee3162def2f06f805d1024bd98 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Mon, 9 Jul 2018 22:53:52 +0200 Subject: [PATCH 09/18] Removes "resume" option from menu when game over. --- src/main.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main.c b/src/main.c index 36e76a4..27c2a53 100644 --- a/src/main.c +++ b/src/main.c @@ -295,6 +295,21 @@ initInGameMenu(void) createMenu(&inGameMenu, menu_items, 3); } +static void +createInGameGameOverMenu(void) +{ + struct MENU_ITEM menu_items[] = { + { "MAIN MENU", goToMainMenu }, + { "QUIT", exitGame }, + }; + + if (inGameMenu) { + menu_destroy(inGameMenu); + inGameMenu = NULL; + } + createMenu(&inGameMenu, menu_items, 2); +} + static void initMainMenu(void) { @@ -553,6 +568,7 @@ run_game(void) gui_event_message("You died!"); mixer_play_effect(SPLAT); gGameState = GAME_OVER; + createInGameGameOverMenu(); } else { check_next_level(); } From 18e70221faaf895fa7442ea30e942598ab9d0c53 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Sat, 28 Jul 2018 14:28:55 +0200 Subject: [PATCH 10/18] Restructured main game loop a bit. Reduced function size --- src/main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 27c2a53..7569d7c 100644 --- a/src/main.c +++ b/src/main.c @@ -473,7 +473,7 @@ populateUpdateData(UpdateData *data, float deltatime) } static void -run_game(void) +run_game_update(void) { static UpdateData updateData; static unsigned int playerLevel = 1; @@ -518,7 +518,11 @@ run_game(void) currentTurn = PLAYER; } } +} +static void +run_game_render(void) +{ SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0); SDL_RenderClear(gRenderer); @@ -531,7 +535,8 @@ run_game(void) map_render_top_layer(gMap, gCamera); - player_render_toplayer(gPlayer, gCamera); + if (!is_player_dead()) + player_render_toplayer(gPlayer, gCamera); if (gPlayer->class == MAGE || gPlayer->class == PALADIN) roommatrix_render_mouse_square(gRoomMatrix, gCamera); @@ -561,6 +566,14 @@ run_game(void) pointer_render(gPointer, gCamera); SDL_RenderPresent(gRenderer); +} + +static void +run_game(void) +{ + run_game_update(); + + run_game_render(); if (gGameState == PLAYING && is_player_dead()) { camera_shake(VECTOR2D_RIGHT, 800); From b3b8208b111de625d6d2da9e70755783b1f6e0d2 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 14:25:29 +0200 Subject: [PATCH 11/18] Adds complete rewrite of lua scripts Lua scripts now build an in memory structure of all the rooms and their contents before loading this data into the game. This enables better possibilities to prevent monsters from spawning in bad places. Monsters can now also spawn in coridoor rooms. --- data/mapgen.lua | 72 +++---- data/maproombuilder.lua | 411 +++++++++++++++++++++++----------------- data/menumapgen.lua | 10 +- data/monstergen.lua | 37 +++- 4 files changed, 314 insertions(+), 216 deletions(-) diff --git a/data/mapgen.lua b/data/mapgen.lua index b95ebfd..4531810 100644 --- a/data/mapgen.lua +++ b/data/mapgen.lua @@ -17,7 +17,7 @@ local function matrix_coverage (matrix) local cov = 0 for i=1,10 do for j=1,10 do - if matrix[i][j].active then cov = cov + 1 end + if matrix[i][j] then cov = cov + 1 end end end return cov @@ -36,7 +36,7 @@ local function generate_path () for i=1,10 do map_matrix[i] = {} for j=1,10 do - map_matrix[i][j] = room_builder.create_room() + map_matrix[i][j] = nil end end @@ -47,7 +47,10 @@ local function generate_path () local direction = 0 local lastDirection = 0 local coridoor_count = 0 - local coverage = 10 + local coverage = 9 + CURRENT_LEVEL + + -- Create the first room + map_matrix[cx][cy] = room_builder.create_empty_room() while matrix_coverage(map_matrix) < coverage do local direction = random(4) @@ -60,8 +63,6 @@ local function generate_path () direction = random(4) end - map_matrix[cx][cy].active = true - if coridoor_count < coverage/3 then if random(3) == 1 and (cx > 1 or cy > 1) then map_matrix[cx][cy].type = "coridoor" @@ -69,49 +70,56 @@ local function generate_path () end end + valid_direction = false if direction == UP and cy > 1 then -- UP - table.insert(map_matrix[cx][cy].exits, direction) + room_builder.add_exit(map_matrix[cx][cy], direction) map_matrix[cx][cy].path_dir = direction - cy = cy - 1; - table.insert(map_matrix[cx][cy].exits, reverse_direction(direction)) + cy = cy - 1 + valid_direction = true elseif direction == LEFT and cx > 1 then -- LEFT - table.insert(map_matrix[cx][cy].exits, direction) + room_builder.add_exit(map_matrix[cx][cy], direction) map_matrix[cx][cy].path_dir = direction - cx = cx - 1; - table.insert(map_matrix[cx][cy].exits, reverse_direction(direction)) + cx = cx - 1 + valid_direction = true elseif direction == RIGHT and cx < 10 then -- RIGHT - table.insert(map_matrix[cx][cy].exits, direction) + room_builder.add_exit(map_matrix[cx][cy], direction) map_matrix[cx][cy].path_dir = direction - cx = cx + 1; - table.insert(map_matrix[cx][cy].exits, reverse_direction(direction)) + cx = cx + 1 + valid_direction = true elseif direction == DOWN and cy < 10 then -- DOWN - table.insert(map_matrix[cx][cy].exits, direction) + room_builder.add_exit(map_matrix[cx][cy], direction) map_matrix[cx][cy].path_dir = direction - cy = cy + 1; - table.insert(map_matrix[cx][cy].exits, reverse_direction(direction)) + cy = cy + 1 + valid_direction = true + end + + -- Create the next room and add the reverse exit + -- if a valid direction was found + if valid_direction then + if not map_matrix[cx][cy] then + map_matrix[cx][cy] = room_builder.create_empty_room() + end + room_builder.add_exit(map_matrix[cx][cy], reverse_direction(direction)) end lastDirection = direction end -- Last room rules - map_matrix[cx][cy].active = true map_matrix[cx][cy].goal = true map_matrix[cx][cy].type = "room" - return map_matrix; -end - -local function print_matrix(matrix) + -- Build all the rooms for i=1,10 do for j=1,10 do - if not map_matrix[j][i].goal then - io.write(map_matrix[j][i].path_dir .. " ") - else - io.write("G ") + room = map_matrix[i][j] + if room then + room_builder.build_room(room) + monster_gen.add_monsters_to_room(room, i-1, j-1) end end - io.write("\n") end + + return map_matrix; end -- END FUNCTIONS @@ -126,14 +134,10 @@ local map_matrix = generate_path() for i=1,10 do for j=1,10 do local room = map_matrix[i][j] - if room.active then + if room then set_current_room(map, i-1, j-1); - if room.type == "room" then - room_builder.build_square_room(map, room) - monster_gen.add_monster_to_room(map, i-1, j-1); - elseif room.type == "coridoor" then - room_builder.build_coridoor_room(map, room) - end + room_builder.load_room(map, room) + monster_gen.load_monsters(map, room.monsters) end end end diff --git a/data/maproombuilder.lua b/data/maproombuilder.lua index 90cc197..c220d2c 100644 --- a/data/maproombuilder.lua +++ b/data/maproombuilder.lua @@ -61,23 +61,23 @@ local function load_decor_textures() table.insert(floorDecor, { td0, td1, 48, 13 * 16, false, false }) -- Urns - table.insert(floorDecor, { td0, td1, 0 * 16, 48, true, false }) - table.insert(floorDecor, { td0, td1, 1 * 16, 48, true, false }) - table.insert(floorDecor, { td0, td1, 2 * 16, 48, true, false }) - table.insert(floorDecor, { td0, td1, 3 * 16, 48, true, false }) - table.insert(floorDecor, { td0, td1, 4 * 16, 48, true, false }) - table.insert(floorDecor, { td0, td1, 5 * 16, 48, true, false }) - table.insert(floorDecor, { td0, td1, 6 * 16, 48, false, false }) - table.insert(floorDecor, { td0, td1, 7 * 16, 48, false, false }) + --table.insert(floorDecor, { td0, td1, 0 * 16, 48, true, false }) + --table.insert(floorDecor, { td0, td1, 1 * 16, 48, true, false }) + --table.insert(floorDecor, { td0, td1, 2 * 16, 48, true, false }) + --table.insert(floorDecor, { td0, td1, 3 * 16, 48, true, false }) + --table.insert(floorDecor, { td0, td1, 4 * 16, 48, true, false }) + --table.insert(floorDecor, { td0, td1, 5 * 16, 48, true, false }) + --table.insert(floorDecor, { td0, td1, 6 * 16, 48, false, false }) + --table.insert(floorDecor, { td0, td1, 7 * 16, 48, false, false }) -- Racks - table.insert(floorDecor, { td0, td1, 0 * 16, 11 * 16, true, false }) - table.insert(floorDecor, { td0, td1, 1 * 16, 11 * 16, true, false }) - table.insert(floorDecor, { td0, td1, 2 * 16, 11 * 16, true, false }) - table.insert(floorDecor, { td0, td1, 3 * 16, 11 * 16, true, false }) - table.insert(floorDecor, { td0, td1, 4 * 16, 11 * 16, true, false }) - table.insert(floorDecor, { td0, td1, 5 * 16, 11 * 16, true, false }) - table.insert(floorDecor, { td0, td1, 6 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 0 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 1 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 2 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 3 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 4 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 5 * 16, 11 * 16, true, false }) + --table.insert(floorDecor, { td0, td1, 6 * 16, 11 * 16, true, false }) -- Headstones table.insert(floorDecor, { td0, td1, 0 * 16, 17 * 16, true, false }) @@ -117,6 +117,20 @@ local function load_special_tiles() special.level_exit = { tt, -1, 16, 16, false, true, true } end +local function print_room(room) + print("ROOM:") + for j=0, 11 do + for i=0, 15 do + if room.tiles[i][j] then + io.write("o ") + else + io.write(". ") + end + end + print("") + end +end + local function repack(data) return { textureIndex0 = data[1], @@ -138,22 +152,31 @@ local function check_add_decoration(map, x, y, data) return true end -local function check_add_tile(map, x, y, data) - if tile_occupied(map, x, y) then - return false - end - add_tile(map, x, y, repack(data)) - return true -end - -local function add_random_decor_to_room(map) +local function add_random_decor_to_room(room) local decor_count = random(4) - 1 for i=1,decor_count do - check_add_decoration(map, random(11)+1, random(8)+1, floorDecor[random(#floorDecor)]) + x = random(11) + 1 + y = random(8) + 1 + if not room.decor[x][y] then + room.decor[x][y] = floorDecor[random(#floorDecor)] + end + end + + if random(2) == 1 then + room.decor[4][3] = lightDecor.candle2 + end + if random(2) == 1 then + room.decor[11][3] = lightDecor.candle2 + end + if random(2) == 1 then + room.decor[4][9] = lightDecor.candle2 + end + if random(2) == 1 then + room.decor[11][9] = lightDecor.candle2 end end -local function add_pits_to_room(map) +local function add_pits_to_room(room) if CURRENT_LEVEL < 2 then return @@ -171,7 +194,6 @@ local function add_pits_to_room(map) end end - local matrix = {} for i=0, #cleanData-1 do local c = cleanData:sub(i, i) @@ -191,207 +213,175 @@ local function add_pits_to_room(map) matrix = matrix[random(#matrix)] for i=2,13 do for j=2,10 do - if not tile_occupied(map, (i), (j)) and matrix[i][j] then + if matrix[i][j] then + room.decor[i][j] = nil if not matrix[i-1][j-1] and not matrix[i+1][j-1] and matrix[i-1][j] and matrix[i+1][j] and matrix[i][j-1] then - add_tile(map, i, j, repack(pits.innermid)) + room.tiles[i][j] = pits.innermid elseif not matrix[i-1][j-1] and matrix[i-1][j] and matrix[i][j-1] then - add_tile(map, i, j, repack(pits.innerleft)) + room.tiles[i][j] = pits.innerleft elseif not matrix[i+1][j-1] and matrix[i+1][j] and matrix[i][j-1] then - add_tile(map, i, j, repack(pits.innerright)) + room.tiles[i][j] = pits.innerright elseif not matrix[i-1][j] and not matrix[i][j-1] and not matrix[i+1][j] then - add_tile(map, i, j, repack(pits.topcrevice)) + room.tiles[i][j] = pits.topcrevice elseif not matrix[i-1][j] and not matrix[i+1][j] then - add_tile(map, i, j, repack(pits.bottomcrevice)) + room.tiles[i][j] = pits.bottomcrevice elseif not matrix[i-1][j] and not matrix[i][j-1] then - add_tile(map, i, j, repack(pits.topleft)) + room.tiles[i][j] = pits.topleft elseif not matrix[i+1][j] and not matrix[i][j-1] then - add_tile(map, i, j, repack(pits.topright)) + room.tiles[i][j] = pits.topright elseif not matrix[i-1][j] then - add_tile(map, i, j, repack(pits.left)) + room.tiles[i][j] = pits.left elseif not matrix[i+1][j] then - add_tile(map, i, j, repack(pits.right)) + room.tiles[i][j] = pits.right elseif not matrix[i][j-1] then - add_tile(map, i, j, repack(pits.top)) + room.tiles[i][j] = pits.top else - add_tile(map, i, j, repack(pits.center)) + room.tiles[i][j] = pits.center end end end end end -local function add_tiles_to_room (map) +local function add_tiles_to_room (room) for i=0,15 do for j=0,11 do if (i >= 1 and i <= 14 and j >= 1 and j <= 10) then if (i == 1 and j == 1) then - add_tile(map, i, j, repack(floor.topleft)) + room.tiles[i][j] = floor.topleft elseif (i == 14 and j == 1) then - add_tile(map, i, j, repack(floor.topright)) + room.tiles[i][j] = floor.topright elseif (i == 1 and j == 10) then - add_tile(map, i, j, repack(floor.bottomleft)) + room.tiles[i][j] = floor.bottomleft elseif (i == 14 and j == 10) then - add_tile(map, i, j, repack(floor.bottomright)) + room.tiles[i][j] = floor.bottomright elseif (i == 1) then - add_tile(map, i, j, repack(floor.left)) + room.tiles[i][j] = floor.left elseif (i == 14) then - add_tile(map, i, j, repack(floor.right)) + room.tiles[i][j] = floor.right elseif (j == 1) then - add_tile(map, i, j, repack(floor.top)) + room.tiles[i][j] = floor.top elseif (j == 10) then - add_tile(map, i, j, repack(floor.bottom)) + room.tiles[i][j] = floor.bottom else - add_tile(map, i, j, repack(floor.center)) + room.tiles[i][j] = floor.center end end end end - - add_random_decor_to_room(map) - add_pits_to_room(map) end -local function add_walls_to_room (map) +local function add_walls_to_room (room) for i=0,15 do for j=0,11 do if (i == 0 and j == 0) then - add_tile(map, i, j, repack(wall.topleft)) + room.tiles[i][j] = wall.topleft elseif (i == 15 and j == 0) then - add_tile(map, i, j, repack(wall.topright)) + room.tiles[i][j] = wall.topright elseif (i == 0 and j == 11) then - add_tile(map, i, j, repack(wall.bottomleft)) + room.tiles[i][j] = wall.bottomleft elseif (i == 15 and j == 11) then - add_tile(map, i, j, repack(wall.bottomright)) + room.tiles[i][j] = wall.bottomright elseif (i == 0 or i == 15) then - add_tile(map, i, j, repack(wall.vertical)) + room.tiles[i][j] = wall.vertical elseif (j == 0 or j == 11) then - add_tile(map, i, j, repack(wall.horizontal)) + room.tiles[i][j] = wall.horizontal end end end - - if random(2) == 1 then - check_add_decoration(map, 4, 3, lightDecor.candle2) - end - if random(2) == 1 then - check_add_decoration(map, 11, 3, lightDecor.candle2) - end - if random(2) == 1 then - check_add_decoration(map, 4, 9, lightDecor.candle2) - end - if random(2) == 1 then - check_add_decoration(map, 11, 9, lightDecor.candle2) - end end -local function add_exit(map, direction) - if direction > 4 then return end - - if direction == UP then - add_tile(map, 6, 0, repack(wall.bottomright)) - add_tile(map, 7, 0, repack(floor.singleleft)) - add_tile(map, 8, 0, repack(floor.singleright)) - add_tile(map, 9, 0, repack(wall.bottomleft)) - elseif direction == LEFT then - add_tile(map, 0, 4, repack(wall.bottomright)) - add_tile(map, 0, 5, repack(floor.singletop)) - add_tile(map, 0, 6, repack(floor.singlebottom)) - add_tile(map, 0, 7, repack(wall.topright)) - elseif direction == RIGHT then - add_tile(map, 15, 4, repack(wall.bottomleft)) - add_tile(map, 15, 5, repack(floor.singletop)) - add_tile(map, 15, 6, repack(floor.singlebottom)) - add_tile(map, 15, 7, repack(wall.topleft)) - elseif direction == DOWN then - add_tile(map, 6, 11, repack(wall.topright)) - add_tile(map, 7, 11, repack(floor.singleleft)) - add_tile(map, 8, 11, repack(floor.singleright)) - add_tile(map, 9, 11, repack(wall.topleft)) - end -end - -local function add_level_exit(map) - success = false - while not success do - x = random(14) - y = random(10) - success = check_add_tile(map, x, y, special.level_exit) - end -end - -local function build_vert_center_coridoor(map, offset) - for j=0,4 do - add_tile(map, 6, offset+j, repack(wall.vertical)); - add_tile(map, 7, offset+j, repack(floor.center)); - add_tile(map, 8, offset+j, repack(floor.center)); - add_tile(map, 9, offset+j, repack(wall.vertical)); +local function build_vert_center_coridoor(room, offset) + for i=0,4 do + room.tiles[6][offset+i] = wall.vertical + room.tiles[7][offset+i] = floor.center + room.tiles[8][offset+i] = floor.center + room.tiles[9][offset+i] = wall.vertical end if random(2) == 1 then - add_decoration(map, 6, offset + 2, repack(lightDecor.candle1)) + room.decor[6][offset+2] = lightDecor.candle1 end if random(2) == 1 then - add_decoration(map, 9, offset + 2, repack(lightDecor.candle1)) + room.decor[6][offset+2] = lightDecor.candle1 end end -local function build_horiz_center_coridoor(map, offset) +local function build_horiz_center_coridoor(room, offset) + info("Building horizontal corrdior: " .. offset) for i=0,6 do - add_tile(map, offset+i, 4, repack(wall.horizontal)); - add_tile(map, offset+i, 5, repack(floor.center)); - add_tile(map, offset+i, 6, repack(floor.center)); - add_tile(map, offset+i, 7, repack(wall.horizontal)); + room.tiles[offset+i][4] = wall.horizontal + room.tiles[offset+i][5] = floor.center + room.tiles[offset+i][6] = floor.center + room.tiles[offset+i][7] = wall.horizontal end if random(2) == 1 then - check_add_decoration(map, offset+3, 4, lightDecor.candle1) + room.decor[offset+3][4] = lightDecor.candle1 end if random(2) == 1 then - check_add_decoration(map, offset+3, 7, lightDecor.candle1) + room.decor[offset+3][7] = lightDecor.candle1 end end -local function build_center_corner_walls(map, exits) +local function build_center_corner_walls(room, exits) if exits.down then if exits.left then - add_tile(map, 6, 7, repack(wall.topright)) + room.tiles[6][7] = wall.topright end if exits.right then - add_tile(map, 9, 7, repack(wall.topleft)) + room.tiles[9][7] = wall.topleft end else if not exits.left then - add_tile(map, 6, 7, repack(wall.bottomleft)) + room.tiles[6][7] = wall.bottomleft end if not exits.right then - add_tile(map, 9, 7, repack(wall.bottomright)) + room.tiles[9][7] = wall.bottomright end end if exits.up then if exits.left then - add_tile(map, 6, 4, repack(wall.bottomright)) + room.tiles[6][4] = wall.bottomright end if exits.right then - add_tile(map, 9, 4, repack(wall.bottomleft)) + room.tiles[9][4] = wall.bottomleft end else if not exits.left then - add_tile(map, 6, 4, repack(wall.topleft)) + room.tiles[6][4] = wall.topleft end if not exits.right then - add_tile(map, 9, 4, repack(wall.topright)) + room.tiles[9][4] = wall.topright end end end -local module = {} - -function module.add_full_lighting(map) - check_add_decoration(map, 4, 3, lightDecor.candle2) - check_add_decoration(map, 11, 3, lightDecor.candle2) - check_add_decoration(map, 4, 9, lightDecor.candle2) - check_add_decoration(map, 11, 9, lightDecor.candle2) +local function add_exits_to_room(room) + for _,direction in ipairs(room.exits) do + if direction == UP then + room.tiles[6][0] = wall.bottomright + room.tiles[7][0] = floor.singleleft + room.tiles[8][0] = floor.singleright + room.tiles[9][0] = wall.bottomleft + elseif direction == LEFT then + room.tiles[0][4] = wall.bottomright + room.tiles[0][5] = floor.singletop + room.tiles[0][6] = floor.singlebottom + room.tiles[0][7] = wall.topright + elseif direction == RIGHT then + room.tiles[15][4] = wall.bottomleft + room.tiles[15][5] = floor.singletop + room.tiles[15][6] = floor.singlebottom + room.tiles[15][7] = wall.topleft + elseif direction == DOWN then + room.tiles[6][11] = wall.topright + room.tiles[7][11] = floor.singleleft + room.tiles[8][11] = floor.singleright + room.tiles[9][11] = wall.topleft + end + end end -function module.build_coridoor_room(map, room) +local function build_coridoor_room(room) local exits = { up = false, down = false, @@ -408,51 +398,126 @@ function module.build_coridoor_room(map, room) end -- Fill the center - add_tile(map, 6, 5, repack(wall.vertical)) - add_tile(map, 6, 6, repack(wall.vertical)) - add_tile(map, 7, 4, repack(wall.horizontal)) - add_tile(map, 7, 5, repack(floor.center)) - add_tile(map, 7, 6, repack(floor.center)) - add_tile(map, 7, 7, repack(wall.horizontal)) - add_tile(map, 8, 4, repack(wall.horizontal)) - add_tile(map, 8, 5, repack(floor.center)) - add_tile(map, 8, 6, repack(floor.center)) - add_tile(map, 8, 7, repack(wall.horizontal)) - add_tile(map, 9, 5, repack(wall.vertical)) - add_tile(map, 9, 6, repack(wall.vertical)) + room.tiles[6][5] = wall.vertical + room.tiles[6][6] = wall.vertical + room.tiles[7][4] = wall.horizontal + room.tiles[7][5] = floor.center + room.tiles[7][6] = floor.center + room.tiles[7][7] = wall.horizontal + room.tiles[8][4] = wall.horizontal + room.tiles[8][5] = floor.center + room.tiles[8][6] = floor.center + room.tiles[8][7] = wall.horizontal + room.tiles[9][5] = wall.vertical + room.tiles[9][6] = wall.vertical -- Build the coridoors - if exits.down then build_vert_center_coridoor(map, 7) end - if exits.up then build_vert_center_coridoor(map, 0) end - if exits.left then build_horiz_center_coridoor(map, 0) end - if exits.right then build_horiz_center_coridoor(map, 9) end + if exits.down then build_vert_center_coridoor(room, 7) end + if exits.up then build_vert_center_coridoor(room, 0) end + if exits.left then build_horiz_center_coridoor(room, 0) end + if exits.right then build_horiz_center_coridoor(room, 9) end - build_center_corner_walls(map, exits) + build_center_corner_walls(room, exits) end -function module.create_room () - return { - exits = {}, - active = false, - goal = false, - path_dir = 0, - type = "room" - } -end - -function module.build_square_room(map, room) - add_tiles_to_room(map); - add_walls_to_room(map); - for exit=1, #room.exits do - add_exit(map, room.exits[exit]); +local function add_level_exit(room) + success = false + while not success do + x = random(14) + y = random(10) + if not room.decor[x][y] then + success = true + room.tiles[x][y] = special.level_exit + end end +end + +local function build_normal_room(room) + add_tiles_to_room(room) + add_random_decor_to_room(room) + add_walls_to_room(room) + add_exits_to_room(room) + add_pits_to_room(room) + if room.goal then - add_level_exit(map); + add_level_exit(room) end if CURRENT_LEVEL > 3 and random(10) == 1 then directions = { "LEFT", "RIGHT", "UP", "DOWN" } - set_modifier(map, "WINDY", directions[random(#directions)]); + room.modifier.type = "WINDY" + room.modifier.arg = directions[random(#directions)] + end + + return room +end + +local module = {} + +function module.add_exit(room, direction) + if direction > 4 then + return + end + + table.insert(room.exits, direction) +end + +function module.add_full_lighting(room) + room.decor[4][3] = lightDecor.candle2 + room.decor[11][3] = lightDecor.candle2 + room.decor[4][9] = lightDecor.candle2 + room.decor[11][9] = lightDecor.candle2 +end + +function module.create_empty_room() + room = { + exits = {}, + active = false, + goal = false, + path_dir = 0, + type = "room", + tiles = {}, + decor = {}, + modifier = { + type = nil, + arg = nil + }, + monsters = {} + } + for i=0,15 do + room.tiles[i] = {} + room.decor[i] = {} + room.monsters[i] = {} + for j=0,11 do + room.tiles[i][j] = nil + room.decor[i][j] = nil + room.monsters[i][j] = nil + end + end + return room +end + +function module.build_room(room) + if room.type == "coridoor" then + build_coridoor_room(room) + else + build_normal_room(room) + end +end + +function module.load_room(map, room) + for i=0, 15 do + for j=0, 11 do + if room.tiles[i][j] then + add_tile(map, i, j, repack(room.tiles[i][j])) + end + if room.decor[i][j] then + add_decoration(map, i, j, repack(room.decor[i][j])) + end + end + end + if room.modifier.type then + set_modifier(map, room.modifier.type, room.modifier.arg) end end diff --git a/data/menumapgen.lua b/data/menumapgen.lua index 661b052..f446c6b 100644 --- a/data/menumapgen.lua +++ b/data/menumapgen.lua @@ -4,9 +4,11 @@ local monster_gen = require "monstergen" map = create_map(CURRENT_LEVEL) -- 'map' needs to be global room_builder.load_textures(map) -local room = room_builder.create_room() set_current_room(map, 0, 0) -room_builder.build_square_room(map, room) -monster_gen.add_monster_to_room(map, 0, 0); -room_builder.add_full_lighting(map); +local room = room_builder.create_empty_room() +room_builder.build_room(room) +room_builder.add_full_lighting(room) +monster_gen.add_monsters_to_room(room, 0, 0) +room_builder.load_room(map, room) +monster_gen.load_monsters(map, room.monsters) diff --git a/data/monstergen.lua b/data/monstergen.lua index 55c681a..9c596f8 100644 --- a/data/monstergen.lua +++ b/data/monstergen.lua @@ -264,15 +264,42 @@ if random(100) == 1 then enemies = concat(enemies, platino); end -function module.add_monster_to_room(map, roomx, roomy) +function module.add_monsters_to_room(room, roomx, roomy) local count = random(3) if (CURRENT_LEVEL > 3) then count = random(4) end - for i=0,count do - local x = (roomx * 512) + (random(13) + 1) * 32 - local y = (roomy * 384) + (random(9) + 1) * 32 - add_monster(map, x, y, repack(enemies[random(#enemies)])); + local i = 0 + while i < count do + local rx = random(13) + 1 + local ry = random(9) + 1 + if not room.decor[rx][ry] + and not room.monsters[rx][ry] + and (room.tiles[rx][ry] + and not room.tiles[rx][ry][5] + and not room.tiles[rx][ry][8]) + then + + local x = (roomx * 512) + rx * 32 + local y = (roomy * 384) + ry * 32 + room.monsters[rx][ry] = { + x, + y, + enemies[random(#enemies)] + } + i = i + 1 + end + end +end + +function module.load_monsters(map, monsters) + for i=0,15 do + for j=0,11 do + monster = monsters[i][j] + if monster then + add_monster(map, monster[1], monster[2], repack(monster[3])) + end + end end end From b12e5d4f7a415dd4c1df39c3227c2f95d54b85b5 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 14:30:41 +0200 Subject: [PATCH 12/18] Fixes: #26 Dagger kills should now give XP --- src/projectile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/projectile.c b/src/projectile.c index 320b8aa..3f43a56 100644 --- a/src/projectile.c +++ b/src/projectile.c @@ -100,6 +100,7 @@ projectile_update(Projectile *p, UpdateData *data) linkedlist_append(&data->map->items, item); } monster_hit(space->monster, dmg); + player_monster_kill_check(data->player, space->monster); } mixer_play_effect(SWORD_HIT); p->alive = false; From 58e9c7ed13c7d5317f29b41765b45423be51679e Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 21:08:36 +0200 Subject: [PATCH 13/18] Fixes: #21 Complex method issue in monster.c At least this is an attempt at a fix --- src/monster.c | 69 ++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/monster.c b/src/monster.c index 1684691..3c5c7c6 100644 --- a/src/monster.c +++ b/src/monster.c @@ -245,8 +245,8 @@ monster_drunk_walk(Monster *m, RoomMatrix *rm) } } -static void -monster_agressive_walk(Monster *m, RoomMatrix *rm) +static Direction +get_optimal_move_towards(Monster *m, RoomMatrix *rm, const Position *dest) { int x_dist, y_dist; Position mPos; @@ -261,21 +261,21 @@ monster_agressive_walk(Monster *m, RoomMatrix *rm) unsigned int nextScore = 0; switch (i) { - case UP: - next.y -= 1; - break; - case DOWN: - next.y += 1; - break; - case LEFT: - next.x -= 1; - break; - case RIGHT: - next.x += 1; - break; + case UP: + next.y -= 1; + break; + case DOWN: + next.y += 1; + break; + case LEFT: + next.x -= 1; + break; + case RIGHT: + next.x += 1; + break; } - if (position_equals(&next, &rm->playerRoomPos)) { + if (position_equals(&next, dest)) { chosenDirection = (Direction) i; break; } @@ -283,8 +283,8 @@ monster_agressive_walk(Monster *m, RoomMatrix *rm) if (!position_in_roommatrix(&next)) continue; - x_dist = abs(next.x - rm->playerRoomPos.x); - y_dist = abs(next.y - rm->playerRoomPos.y); + x_dist = abs(next.x - dest->x); + y_dist = abs(next.y - dest->y); if (rm->spaces[next.x][next.y].occupied || rm->spaces[next.x][next.y].lethal) { nextScore += 50; @@ -293,23 +293,31 @@ monster_agressive_walk(Monster *m, RoomMatrix *rm) nextScore += x_dist > y_dist ? x_dist : y_dist; if (nextScore < currentScore) { currentScore = nextScore; - chosenDirection = (Direction)i; + chosenDirection = (Direction) i; } } + return chosenDirection; +} + +static void +monster_agressive_walk(Monster *m, RoomMatrix *rm) +{ + unsigned int chosenDirection = get_optimal_move_towards(m, rm, &rm->playerRoomPos); + switch (chosenDirection) { - case UP: - move(m, rm, VECTOR2D_UP); - break; - case DOWN: - move(m, rm, VECTOR2D_DOWN); - break; - case LEFT: - move(m, rm, VECTOR2D_LEFT); - break; - case RIGHT: - move(m, rm, VECTOR2D_RIGHT); - break; + case UP: + move(m, rm, VECTOR2D_UP); + break; + case DOWN: + move(m, rm, VECTOR2D_DOWN); + break; + case LEFT: + move(m, rm, VECTOR2D_LEFT); + break; + case RIGHT: + move(m, rm, VECTOR2D_RIGHT); + break; } } @@ -324,7 +332,6 @@ monster_coward_walk(Monster *m, RoomMatrix *rm) x_dist = mPos.x - rm->playerRoomPos.x; y_dist = mPos.y - rm->playerRoomPos.y; - if (abs(x_dist) > abs(y_dist)) { if (x_dist > 0) move(m, rm, VECTOR2D_RIGHT); From b9a4a8002d369e9230c943d4c8a8816b3e2ead12 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 21:15:16 +0200 Subject: [PATCH 14/18] Fixes: #27 Suspicious code: sign conversion --- src/particle_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particle_engine.c b/src/particle_engine.c index dfc05a2..e052406 100644 --- a/src/particle_engine.c +++ b/src/particle_engine.c @@ -234,7 +234,7 @@ particle_engine_sparkle(Position pos, Dimension dim) alpha = get_random(155) + 100; - yv = (get_random(100) + 100) * -1; + yv = -(get_random(100) + 100); lt = get_random(20); From 4612cabe004ea4bc9972720b17dbbe15dc2a4b0d Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 21:23:01 +0200 Subject: [PATCH 15/18] Adds sword animation to flurry And XP gain to charge skill. --- src/skill.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/skill.c b/src/skill.c index bfea534..84082b8 100644 --- a/src/skill.c +++ b/src/skill.c @@ -32,6 +32,7 @@ #include "projectile.h" #include "linkedlist.h" #include "item.h" +#include "animation.h" static void set_player_clip_for_direction(Player *player, Vector2d *direction) @@ -81,6 +82,7 @@ skill_use_flurry(Skill *skill, SkillData *data) Monster *monster = data->matrix->spaces[targetPos.x][targetPos.y].monster; mixer_play_effect(TRIPPLE_SWING); + animation_run(data->player->swordAnimation); if (monster) { gui_log("You attack %s with a flurry of strikes", monster->lclabel); unsigned int hitCount = 0; @@ -294,6 +296,7 @@ skill_charge(Skill *skill, SkillData *data) data->player->stat_data.hits += 1; } monster_hit(monster, dmg); + player_monster_kill_check(data->player, monster); } return true; From 4819eda1ddd08428b4276c4466bb6a4def8ffdfc Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 23:08:34 +0200 Subject: [PATCH 16/18] Adds "NEW GAME" menu option to game over menu Also makes menu open when player dies --- src/main.c | 4 +++- src/menu.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 7569d7c..c167a14 100644 --- a/src/main.c +++ b/src/main.c @@ -299,6 +299,7 @@ static void createInGameGameOverMenu(void) { struct MENU_ITEM menu_items[] = { + { "NEW GAME", startGame }, { "MAIN MENU", goToMainMenu }, { "QUIT", exitGame }, }; @@ -307,7 +308,7 @@ createInGameGameOverMenu(void) menu_destroy(inGameMenu); inGameMenu = NULL; } - createMenu(&inGameMenu, menu_items, 2); + createMenu(&inGameMenu, menu_items, 3); } static void @@ -582,6 +583,7 @@ run_game(void) mixer_play_effect(SPLAT); gGameState = GAME_OVER; createInGameGameOverMenu(); + toggleInGameMenu(NULL); } else { check_next_level(); } diff --git a/src/menu.c b/src/menu.c index 9c9520c..e0cac1a 100644 --- a/src/menu.c +++ b/src/menu.c @@ -27,7 +27,7 @@ #include "mixer.h" #include "collisions.h" -typedef struct MenuItems_t { +typedef struct MenuItems { Sprite *sprite; Sprite *hsprite; GuiButton *button; From 1124e88df00af3d6a7007b372665c89f5982be8d Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Tue, 31 Jul 2018 23:45:09 +0200 Subject: [PATCH 17/18] Minor fixes - Make skills correctly turn the player - Don't repopulate the matrix on every frame only on turn change --- src/main.c | 17 +++++++++++----- src/player.c | 52 ++++++++++++++++++++++++++++-------------------- src/player.h | 3 +++ src/roommatrix.c | 46 +++++++++++++++++++++--------------------- src/roommatrix.h | 2 -- src/skill.c | 21 ++++--------------- 6 files changed, 72 insertions(+), 69 deletions(-) diff --git a/src/main.c b/src/main.c index c167a14..82f3002 100644 --- a/src/main.c +++ b/src/main.c @@ -328,6 +328,15 @@ initMainMenu(void) mixer_play_music(MENU_MUSIC); } +static void +repopulate_roommatrix(void) +{ + roommatrix_populate_from_map(gRoomMatrix, gMap); + roommatrix_add_lightsource(gRoomMatrix, + &gPlayer->sprite->pos); + roommatrix_build_lightmap(gRoomMatrix); +} + static void resetGame(void) { @@ -354,6 +363,7 @@ resetGame(void) map_set_current_room(gMap, &gPlayer->sprite->pos); camera_follow_position(gCamera, &gPlayer->sprite->pos); + repopulate_roommatrix(); } static bool @@ -484,11 +494,6 @@ run_game_update(void) map_clear_dead_monsters(gMap, gPlayer); map_clear_collected_items(gMap); - roommatrix_populate_from_map(gRoomMatrix, gMap); - roommatrix_add_lightsource(gRoomMatrix, - &gPlayer->sprite->pos); - - roommatrix_build_lightmap(gRoomMatrix); populateUpdateData(&updateData, deltaTime); if (playerLevel != gPlayer->stats.lvl) { @@ -513,10 +518,12 @@ run_game_update(void) if (player_turn_over(gPlayer)) { currentTurn = MONSTER; player_reset_steps(gPlayer); + repopulate_roommatrix(); } } else if (currentTurn == MONSTER) { if (map_move_monsters(gMap, gRoomMatrix)) { currentTurn = PLAYER; + repopulate_roommatrix(); } } } diff --git a/src/player.c b/src/player.c index fb490d7..c9f478d 100644 --- a/src/player.c +++ b/src/player.c @@ -186,12 +186,41 @@ set_clip_for_direction(Player *player, Vector2d *direction) player->sprite->clip.y = 0; } +void +player_turn(Player *player, Vector2d *direction) +{ + set_clip_for_direction(player, direction); + + if (!vector2d_equals(*direction, VECTOR2D_NODIR)) + player->swordAnimation->sprite->pos = player->sprite->pos; + + if (vector2d_equals(*direction, VECTOR2D_UP)) { + player->swordAnimation->sprite->pos.y -= 32; + player->swordAnimation->sprite->angle = -90; + player->swordAnimation->sprite->flip = SDL_FLIP_NONE; + } else if (vector2d_equals(*direction, VECTOR2D_DOWN)) { + player->swordAnimation->sprite->pos.y += 32; + player->swordAnimation->sprite->angle = 90; + player->swordAnimation->sprite->flip = SDL_FLIP_NONE; + } else if (vector2d_equals(*direction, VECTOR2D_LEFT)) { + player->swordAnimation->sprite->pos.x -= 32; + player->swordAnimation->sprite->angle = 0; + player->swordAnimation->sprite->flip = SDL_FLIP_HORIZONTAL; + } else if (vector2d_equals(*direction, VECTOR2D_RIGHT)) { + player->swordAnimation->sprite->pos.x += 32; + player->swordAnimation->sprite->angle = 0; + player->swordAnimation->sprite->flip = SDL_FLIP_NONE; + } +} + static void move(Player *player, RoomMatrix *matrix, Vector2d direction) { - set_clip_for_direction(player, &direction); + player_turn(player, &direction); + player->sprite->pos.x += TILE_DIMENSION * (int) direction.x; player->sprite->pos.y += TILE_DIMENSION * (int) direction.y; + if (!has_collided(player, matrix, direction)) { player_step(player); } @@ -249,27 +278,6 @@ handle_next_move(UpdateData *data) ++step; step = step % 4; } - - if (!vector2d_equals(nextDir, VECTOR2D_NODIR)) - player->swordAnimation->sprite->pos = player->sprite->pos; - - if (vector2d_equals(nextDir, VECTOR2D_UP)) { - player->swordAnimation->sprite->pos.y -= 32; - player->swordAnimation->sprite->angle = -90; - player->swordAnimation->sprite->flip = SDL_FLIP_NONE; - } else if (vector2d_equals(nextDir, VECTOR2D_DOWN)) { - player->swordAnimation->sprite->pos.y += 32; - player->swordAnimation->sprite->angle = 90; - player->swordAnimation->sprite->flip = SDL_FLIP_NONE; - } else if (vector2d_equals(nextDir, VECTOR2D_LEFT)) { - player->swordAnimation->sprite->pos.x -= 32; - player->swordAnimation->sprite->angle = 0; - player->swordAnimation->sprite->flip = SDL_FLIP_HORIZONTAL; - } else if (vector2d_equals(nextDir, VECTOR2D_RIGHT)) { - player->swordAnimation->sprite->pos.x += 32; - player->swordAnimation->sprite->angle = 0; - player->swordAnimation->sprite->flip = SDL_FLIP_NONE; - } } static void diff --git a/src/player.h b/src/player.h index 03267ba..fe5d18a 100644 --- a/src/player.h +++ b/src/player.h @@ -95,6 +95,9 @@ player_render(Player*, Camera*); void player_render_toplayer(Player*, Camera*); +void +player_turn(Player*, Vector2d *dir); + void player_destroy(Player*); diff --git a/src/roommatrix.c b/src/roommatrix.c index d63d383..a2f2ec4 100644 --- a/src/roommatrix.c +++ b/src/roommatrix.c @@ -25,6 +25,29 @@ #include "item.h" #include "update_data.h" +static void +roommatrix_reset(RoomMatrix *m) +{ + RoomSpace *space; + int i, j; + + for (i = 0; i < MAP_ROOM_WIDTH; ++i) { + for (j = 0; j < MAP_ROOM_HEIGHT; ++j) { + space = &m->spaces[i][j]; + space->occupied = false; + space->lethal = false; + space->lightsource = false; + space->light = 0; + space->monster = NULL; + space->player = NULL; + while (space->items != NULL) + linkedlist_pop(&space->items); + } + } + m->roomPos = (Position) { 0, 0 }; + m->playerRoomPos = (Position) { 1, 1 }; +} + RoomMatrix* roommatrix_create(void) { int i, j; @@ -242,29 +265,6 @@ roommatrix_render_lightmap(RoomMatrix *matrix, Camera *cam) } } -void -roommatrix_reset(RoomMatrix *m) -{ - RoomSpace *space; - int i, j; - - for (i = 0; i < MAP_ROOM_WIDTH; ++i) { - for (j = 0; j < MAP_ROOM_HEIGHT; ++j) { - space = &m->spaces[i][j]; - space->occupied = false; - space->lethal = false; - space->lightsource = false; - space->light = 0; - space->monster = NULL; - space->player = NULL; - while (space->items != NULL) - linkedlist_pop(&space->items); - } - } - m->roomPos = (Position) { 0, 0 }; - m->playerRoomPos = (Position) { 1, 1 }; -} - void roommatrix_destroy(RoomMatrix *m) { // Clear the list but don't destroy the items diff --git a/src/roommatrix.h b/src/roommatrix.h index 979ed57..e676c9b 100644 --- a/src/roommatrix.h +++ b/src/roommatrix.h @@ -67,8 +67,6 @@ void roommatrix_render_mouse_square(RoomMatrix*, Camera*); void roommatrix_render_lightmap(RoomMatrix*, Camera*); -void roommatrix_reset(RoomMatrix*); - void roommatrix_destroy(RoomMatrix*); #endif // ROOMMATRIX_H_ diff --git a/src/skill.c b/src/skill.c index 84082b8..3806c96 100644 --- a/src/skill.c +++ b/src/skill.c @@ -34,19 +34,6 @@ #include "item.h" #include "animation.h" -static void -set_player_clip_for_direction(Player *player, Vector2d *direction) -{ - if (direction->y > 0) // Down - player->sprite->clip.y = 0; - else if (direction->y < 0) // Up - player->sprite->clip.y = 48; - else if (direction->x < 0) // Left - player->sprite->clip.y = 16; - else if (direction->x > 0) // Right - player->sprite->clip.y = 32; -} - static Skill * create_default(const char *s_label, Sprite *s) { @@ -74,15 +61,15 @@ skill_use_flurry(Skill *skill, SkillData *data) targetPos.x += (int) data->direction.x; targetPos.y += (int) data->direction.y; - set_player_clip_for_direction(data->player, &data->direction); + player_turn(data->player, &data->direction); if (!position_in_roommatrix(&targetPos)) { return false; } + animation_run(data->player->swordAnimation); Monster *monster = data->matrix->spaces[targetPos.x][targetPos.y].monster; mixer_play_effect(TRIPPLE_SWING); - animation_run(data->player->swordAnimation); if (monster) { gui_log("You attack %s with a flurry of strikes", monster->lclabel); unsigned int hitCount = 0; @@ -162,7 +149,7 @@ skill_throw_dagger(Skill *skill, SkillData *data) p->sprite->angle = -270; } - set_player_clip_for_direction(data->player, &data->direction); + player_turn(data->player, &data->direction); mixer_play_effect(SWOOSH); p->sprite->pos = data->player->sprite->pos; @@ -265,7 +252,7 @@ skill_charge(Skill *skill, SkillData *data) player->sprite->pos.x += (steps * TILE_DIMENSION) * (int) data->direction.x; player->sprite->pos.y += (steps * TILE_DIMENSION) * (int) data->direction.y; Position playerDestinationPos = player->sprite->pos; - set_player_clip_for_direction(data->player, &data->direction); + player_turn(data->player, &data->direction); // Add motion particles bool horizontal = data->direction.x != 0; From 1491dfbf3e6b36266de3d973229ec1853f768166 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Wed, 1 Aug 2018 23:53:08 +0200 Subject: [PATCH 18/18] Minor dev-env change --- .vimrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vimrc b/.vimrc index 9ece217..8283bec 100644 --- a/.vimrc +++ b/.vimrc @@ -1,6 +1,6 @@ nnoremap :Make nnoremap :Make clean nnoremap :Make lint test -nnoremap :!./_build/breakhack +nnoremap :ter ++close ./_build/breakhack let g:syntastic_c_include_dirs = [ '_build', '/usr/include/SDL2' ]