From 969447c09fbd174a720f24522d70cc567846c008 Mon Sep 17 00:00:00 2001 From: jgabaut <109908086+jgabaut@users.noreply.github.com> Date: Thu, 22 Feb 2024 07:09:26 +0100 Subject: [PATCH] feat: 1.4.3 Solve circular dependencies, refactor (#75) - Drop rooms.h circular dependency on helapordo.h - Refactor: - Slim helapordo.h to the bare minimum - New files - New subdirectories - Improved Makefile.am configuration ambiguity (maybe) - Bump amboso to 2.0.4 - Bump invil to 0.2.8 - Rough implementation of FLOORS_H declarations for raylib build --- .github/workflows/Build-CI-make.yml | 2 +- .github/workflows/make-anviltest.yml | 6 +- .github/workflows/make-doc.yml | 4 +- Makefile.am | 19 +- README.md | 16 +- amboso | 2 +- bin/v1.4.3/.gitignore | 5 + bin/v1.4.3/static | 1 + configure.ac | 4 +- docs/helapordo.doxyfile | 13 +- format | 7 +- invil | 2 +- kazoj/bone/const.c | 4 +- kazoj/bone/const_rl.c | 4 +- kazoj/bone/const_rl.k.stderr | 0 kazoj/bone/const_rl.k.stdout | 0 src/{ => build-nc-w64}/floor_tester.c | 1 - src/{ => build-nc-w64}/floor_tester.h | 1 + src/build-nc-w64/helapordo_win.c | 328 + src/build-nc-w64/helapordo_win.h | 45 + src/{ => build-nc}/game_curses.c | 291 - src/{ => build-nc}/game_curses.h | 43 +- src/build-nc/helapordo.c | 2230 ++++ src/build-nc/helapordo.h | 51 + src/build-rl/game_rl.c | 236 + src/{ => build-rl}/game_rl.h | 36 +- src/{ => build-rl}/helapordo_raylib.c | 155 +- src/{ => build-rl}/helapordo_raylib.h | 24 +- src/core/equips.c | 41 + src/core/equips.h | 9 + src/core/game_animations.h | 25 + src/{ => core}/game_core.c | 0 src/{ => core}/game_core.h | 12 +- src/{ => core}/game_lore.c | 0 src/{ => core}/game_lore.h | 0 src/{ => core}/game_lore_alt.c | 0 src/{ => core}/game_lore_alt.h | 0 src/{ => core}/sprites.c | 0 src/{ => core}/sprites.h | 0 src/game_rl.c | 63 - src/game_utils.c | 2131 ---- src/helapordo.c | 14961 ------------------------ src/helapordo.h | 387 - src/main.c | 9 +- src/{ => utils}/artifacts.c | 49 + src/{ => utils}/artifacts.h | 4 +- src/{ => utils}/floors.c | 400 + src/{ => utils}/floors.h | 14 +- src/utils/game_debug.c | 1347 +++ src/utils/game_debug.h | 18 + src/utils/game_fight.c | 2070 ++++ src/utils/game_fight.h | 80 + src/utils/game_init.c | 1814 +++ src/utils/game_init.h | 71 + src/utils/game_utils.c | 5293 +++++++++ src/{ => utils}/game_utils.h | 180 +- src/{ => utils}/rooms.c | 189 + src/{ => utils}/rooms.h | 21 +- src/utils/saves.c | 3423 ++++++ src/utils/saves.h | 45 + src/{ => utils}/specials.c | 47 +- src/{ => utils}/specials.h | 4 +- src/utils/turn_op.c | 812 ++ src/utils/turn_op.h | 34 + stego.lock | 3 +- 65 files changed, 19065 insertions(+), 18021 deletions(-) create mode 100644 bin/v1.4.3/.gitignore create mode 120000 bin/v1.4.3/static create mode 100644 kazoj/bone/const_rl.k.stderr create mode 100644 kazoj/bone/const_rl.k.stdout rename src/{ => build-nc-w64}/floor_tester.c (99%) rename src/{ => build-nc-w64}/floor_tester.h (96%) create mode 100644 src/build-nc-w64/helapordo_win.c create mode 100644 src/build-nc-w64/helapordo_win.h rename src/{ => build-nc}/game_curses.c (94%) rename src/{ => build-nc}/game_curses.h (75%) create mode 100644 src/build-nc/helapordo.c create mode 100644 src/build-nc/helapordo.h create mode 100644 src/build-rl/game_rl.c rename src/{ => build-rl}/game_rl.h (57%) rename src/{ => build-rl}/helapordo_raylib.c (80%) rename src/{ => build-rl}/helapordo_raylib.h (67%) create mode 100644 src/core/equips.c create mode 100644 src/core/equips.h create mode 100644 src/core/game_animations.h rename src/{ => core}/game_core.c (100%) rename src/{ => core}/game_core.h (99%) rename src/{ => core}/game_lore.c (100%) rename src/{ => core}/game_lore.h (100%) rename src/{ => core}/game_lore_alt.c (100%) rename src/{ => core}/game_lore_alt.h (100%) rename src/{ => core}/sprites.c (100%) rename src/{ => core}/sprites.h (100%) delete mode 100644 src/game_rl.c delete mode 100644 src/game_utils.c delete mode 100644 src/helapordo.c delete mode 100644 src/helapordo.h rename src/{ => utils}/artifacts.c (82%) rename src/{ => utils}/artifacts.h (95%) rename src/{ => utils}/floors.c (68%) rename src/{ => utils}/floors.h (76%) create mode 100644 src/utils/game_debug.c create mode 100644 src/utils/game_debug.h create mode 100644 src/utils/game_fight.c create mode 100644 src/utils/game_fight.h create mode 100644 src/utils/game_init.c create mode 100644 src/utils/game_init.h create mode 100644 src/utils/game_utils.c rename src/{ => utils}/game_utils.h (55%) rename src/{ => utils}/rooms.c (95%) rename src/{ => utils}/rooms.h (84%) create mode 100644 src/utils/saves.c create mode 100644 src/utils/saves.h rename src/{ => utils}/specials.c (96%) rename src/{ => utils}/specials.h (98%) create mode 100644 src/utils/turn_op.c create mode 100644 src/utils/turn_op.h diff --git a/.github/workflows/Build-CI-make.yml b/.github/workflows/Build-CI-make.yml index 4c7d9037..817c33d1 100644 --- a/.github/workflows/Build-CI-make.yml +++ b/.github/workflows/Build-CI-make.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - name: Run aclocal diff --git a/.github/workflows/make-anviltest.yml b/.github/workflows/make-anviltest.yml index 3708d68a..ddc9bb80 100644 --- a/.github/workflows/make-anviltest.yml +++ b/.github/workflows/make-anviltest.yml @@ -13,15 +13,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - + - name: Run sudo apt update run: sudo apt update -y - name: Install astyle run: sudo apt install astyle -y - + - name: Run aclocal run: aclocal - name: Run autoconf diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index 56ddb415..5e5c4423 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -18,7 +18,7 @@ jobs: name: Generate ./docs/docs.pdf steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 1 @@ -31,7 +31,7 @@ jobs: - name: Install doxygen-latex run: | sudo apt install doxygen-latex -y - + - name: Run aclocal run: aclocal - name: Run autoconf diff --git a/Makefile.am b/Makefile.am index 7594cc33..98554e6b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,16 +39,23 @@ endif # Compiler flags AM_CFLAGS = $(HELAPORDO_CFLAGS) -Werror -Wpedantic -Wall -std=c11 -DHELAPORDO_BUILD_STR=\"$(HL_BUILD_STR)\" +helapordo_SOURCES = src/core/game_core.c src/utils/game_utils.c src/utils/game_init.c src/utils/game_fight.c src/utils/game_debug.c src/core/equips.c src/utils/saves.c src/utils/turn_op.c src/utils/rooms.c src/utils/artifacts.c src/utils/specials.c src/main.c src/core/sprites.c src/utils/floors.c koliseo/src/koliseo.c sprites4curses/s4c-animate/animate.c src/anvil__helapordo.c src/animations/mummy_shuffle.c src/animations/ghost_spell.c src/animations/boar_scream.c src/animations/troll_club.c src/animations/goblin_shoot.c src/animations/zombie_walk.c src/animations/imp_fireball.c src/animations/werewolf_transform.c src/animations/knight_tapis.c src/animations/mage_spark.c src/animations/archer_drop.c src/animations/assassin_poof.c src/animations/crawlingdude_crawl.c src/animations/srwarthog_square.c src/animations/headlessninja_throw.c src/animations/bluetroll_wonder.c src/animations/enter_door.c src/animations/alt_chest_opening.c src/core/game_lore.c src/core/game_lore_alt.c src/palette.c if HL_RAYLIB_BUILD AM_CFLAGS += -DHELAPORDO_RAYLIB_BUILD -helapordo_SOURCES = src/helapordo_raylib.c src/game_core.c src/game_utils.c src/game_rl.c src/artifacts.c src/specials.c src/main.c src/sprites.c src/floors.c koliseo/src/koliseo.c sprites4curses/s4c-animate/animate.c src/anvil__helapordo.c src/animations/mummy_shuffle.c src/animations/ghost_spell.c src/animations/boar_scream.c src/animations/troll_club.c src/animations/goblin_shoot.c src/animations/zombie_walk.c src/animations/imp_fireball.c src/animations/werewolf_transform.c src/animations/knight_tapis.c src/animations/mage_spark.c src/animations/archer_drop.c src/animations/assassin_poof.c src/animations/crawlingdude_crawl.c src/animations/srwarthog_square.c src/animations/headlessninja_throw.c src/animations/bluetroll_wonder.c src/animations/enter_door.c src/animations/alt_chest_opening.c src/game_lore.c src/game_lore_alt.c src/palette.c +helapordo_SOURCES += src/build-rl/helapordo_raylib.c src/build-rl/game_rl.c else AM_CFLAGS += -DHELAPORDO_CURSES_BUILD -helapordo_SOURCES = src/helapordo.c src/game_core.c src/game_utils.c src/game_curses.c src/rooms.c src/artifacts.c src/specials.c src/main.c src/sprites.c src/floors.c sprites4curses/s4c-animate/animate.c koliseo/src/koliseo.c src/anvil__helapordo.c src/animations/mummy_shuffle.c src/animations/ghost_spell.c src/animations/boar_scream.c src/animations/troll_club.c src/animations/goblin_shoot.c src/animations/zombie_walk.c src/animations/imp_fireball.c src/animations/werewolf_transform.c src/animations/knight_tapis.c src/animations/mage_spark.c src/animations/archer_drop.c src/animations/assassin_poof.c src/animations/crawlingdude_crawl.c src/animations/srwarthog_square.c src/animations/headlessninja_throw.c src/animations/bluetroll_wonder.c src/animations/enter_door.c src/animations/alt_chest_opening.c src/game_lore.c src/game_lore_alt.c src/palette.c +helapordo_SOURCES += src/build-nc/game_curses.c endif if WINDOWS_BUILD -helapordo_SOURCES += src/floor_tester.c +if !HL_RAYLIB_BUILD +helapordo_SOURCES += src/build-nc-w64/helapordo_win.c src/build-nc-w64/floor_tester.c +endif +else +if HL_CURSES_BUILD +helapordo_SOURCES += src/build-nc/helapordo.c +endif endif ./anvil: @@ -191,6 +198,9 @@ clean: -rm $(TARGET) -rm sprites4curses/s4c-animate/*.o -rm src/*.o + -rm src/build-*/*.o + -rm src/core/*.o + -rm src/utils/*.o -rm src/animations/*.o -rm src/palette.* -rm koliseo/src/*.o @@ -204,6 +214,9 @@ cleanob: -rm sprites4curses/s4c-animate/*.o -rm koliseo/src/*.o -rm src/*.o + -rm src/build-*/*.o + -rm src/core/*.o + -rm src/utils/*.o @echo -e "\033[1;33mDone.\e[0m" # Default target (builds everything) diff --git a/README.md b/README.md index de308011..22bbe58a 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ - `aarch64-apple-darwin` - `Windows` (through `x86_64-w64-mingw32`) - **DISCLAIMER:** The `Windows` build is proof-of-concept as: + **DISCLAIMER:** The `Windows` ncurses build is proof-of-concept as: - The gameplay loop is a simplified version of `Rogue` gamemode from the main build. - Work in progress on running the original gameloop. @@ -49,15 +49,15 @@ - Some source files are expected to be generated at build time, by a symlink executable named `anvil`. By default, the configuration will pick an implementation for `anvil` depending on passed host: - `darwin*`: default is `repo_invil`. This means you need the Rust build toolchain to be installed. - - `linux*`, `mingw*`: default is `repo_amboso`. This means you need `bash >=4.x`, and your `awk` should not be `mawk`. + - `linux*`, `mingw*`: default is `repo_amboso`. This means you need `bash >=4.x`, and `gawk`. - To readily override the default implementation for `anvil`, you can pass `--enable-anvilpick` to the `./configure` script: `./configure --enable-anvilpick` This will ensure you get an interactive prompt to pick an implementation (and can still use the default one by pressing Enter without typing anything), whenever `make` needs to create `./anvil`. - Needed programs, depending on chosen `ANVIL_IMPL`: - - `awk` is needed by `amboso` to generate `./src/anvil__helapordo.h`. + - `gawk` is needed by `amboso` to generate `./src/anvil__helapordo.h`. - `bash >=4` is needed to run `amboso`. - - Unfortunately, `mawk` is not compatible with `amboso`. + - Unfortunately, `nawk` and `mawk` are not compatible with `amboso`. - If you dont' have those, you can use `invil` to generate `./src/anvil__helapordo.h`. - You will need `cargo` to build `invil`. - If you want to just build the code without `./src/anvil__helapordo.h`., you can apply the patch file provided at [this link](https://github.com/jgabaut/helapordo/issues/52#issuecomment-1871877437). @@ -146,11 +146,11 @@ I try to upload precompiled binaries for the ncurses build: - - `x86_64-Linux` : [download latest](https://github.com/jgabaut/helapordo/releases/download/1.4.2/helapordo-nc-1.4.2-Linux-x86_64.zip) + - `x86_64-Linux` : [download latest](https://github.com/jgabaut/helapordo/releases/download/1.4.3/helapordo-nc-1.4.3-Linux-x86_64.zip) - `aarch64-Linux` (from [Termux](https://f-droid.org/packages/com.termux/) on Android). - - `x86_64-w64-mingw32` (*JUST A DEMO.* Any help with debugging the full game is welcome.) : [download latest](https://github.com/jgabaut/helapordo/releases/download/1.4.2/helapordo.exe-nc-1.4.2-w64-mingw32-x86_64.zip) + - `x86_64-w64-mingw32` (*JUST A DEMO.* Any help with debugging the full game is welcome.) : [download latest](https://github.com/jgabaut/helapordo/releases/download/1.4.3/helapordo.exe-nc-1.4.3-w64-mingw32-x86_64.zip) - - `darwin-arm64` : [download latest](https://github.com/jgabaut/helapordo/releases/download/1.4.1/helapordo-nc-1.4.1-darwin-arm64.zip) (Available = `1.4.1`. Latest = `1.4.2`) + - `darwin-arm64` : [download latest](https://github.com/jgabaut/helapordo/releases/download/1.4.2/helapordo-nc-1.4.2-darwin-arm64.zip) (Available = `1.4.2`. Latest = `1.4.3`) - 📦 v1.4.2 09/02/2024 + 📦 v1.4.3 22/02/2024 https://github.com/jgabaut/helapordo/releases diff --git a/amboso b/amboso index 9d68d2fb..a229a00c 160000 --- a/amboso +++ b/amboso @@ -1 +1 @@ -Subproject commit 9d68d2fb3e80a4bbb17b35a4b0b269c827904d1c +Subproject commit a229a00c8690c4527ee4eb8cc59a400f69d44cc9 diff --git a/bin/v1.4.3/.gitignore b/bin/v1.4.3/.gitignore new file mode 100644 index 00000000..9cd91fcd --- /dev/null +++ b/bin/v1.4.3/.gitignore @@ -0,0 +1,5 @@ +#amboso compliant version folder, will ignore everything inside BUT the gitignore, to keep the clean dir +#we also keep specific dependencies... +* +!.gitignore +!static diff --git a/bin/v1.4.3/static b/bin/v1.4.3/static new file mode 120000 index 00000000..382349a7 --- /dev/null +++ b/bin/v1.4.3/static @@ -0,0 +1 @@ +../../static/ \ No newline at end of file diff --git a/configure.ac b/configure.ac index 03c61fa0..111dd494 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # Define the package name and version -AC_INIT([helapordo], [1.4.2], [jgabaut@github.com]) +AC_INIT([helapordo], [1.4.3], [jgabaut@github.com]) # Verify automake version and enable foreign option AM_INIT_AUTOMAKE([foreign -Wall]) @@ -169,7 +169,7 @@ AM_CONDITIONAL([LINUX_BUILD], [test "$build_linux" = "yes"]) # Set a default version number if not specified externally AC_ARG_VAR([VERSION], [Version number]) if test -z "$VERSION"; then - VERSION="1.4.2" + VERSION="1.4.3" fi # Output variables to the config.h header diff --git a/docs/helapordo.doxyfile b/docs/helapordo.doxyfile index 4c16ebe9..120a8a4e 100644 --- a/docs/helapordo.doxyfile +++ b/docs/helapordo.doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = "helapordo" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "1.4.2" +PROJECT_NUMBER = "1.4.3" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -935,7 +935,12 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = "./src" +INPUT = "./src" \ + "./src/core" \ + "./src/utils" \ + "./src/build-nc" \ + "./src/build-rl" \ + "./src/build-nc-w64" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -1671,7 +1676,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview @@ -2439,7 +2444,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = NO +HAVE_DOT = yes # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of diff --git a/format b/format index cac3c225..2072c363 100755 --- a/format +++ b/format @@ -8,8 +8,13 @@ else exit 1 fi SRC_DIR="src" +SRC_CORE_DIR="src/core" +SRC_UTILS_DIR="src/utils" +SRC_BUILD_NC_DIR="src/build-nc" +SRC_BUILD_NC_W64_DIR="src/build-nc-w64" +SRC_BUILD_RL_DIR="src/build-rl" -hlpd_SOURCES=("$SRC_DIR"/*.c "$SRC_DIR"/*.h) +hlpd_SOURCES=("$SRC_DIR"/*.c "$SRC_DIR"/*.h "$SRC_CORE_DIR"/*.c "$SRC_CORE_DIR"/*.h "$SRC_UTILS_DIR"/*.c "$SRC_UTILS_DIR"/*.h "$SRC_BUILD_NC_DIR"/*.c "$SRC_BUILD_NC_DIR"/*.h "$SRC_BUILD_NC_W64_DIR"/*.c "$SRC_BUILD_NC_W64_DIR"/*.h "$SRC_BUILD_RL_DIR"/*.c "$SRC_BUILD_RL_DIR"/*.h ) CONFIG_FILE=".astylerc" printf "Running \033[1;34mastyle -s4 --style=linux\e[0m for all source files.\n" diff --git a/invil b/invil index 7fc7aee3..a2058f10 160000 --- a/invil +++ b/invil @@ -1 +1 @@ -Subproject commit 7fc7aee3dd0ed01c1cd224abb4b3d676c73b9416 +Subproject commit a2058f105bd82622d85b28b7e9fd3dc1a5c87934 diff --git a/kazoj/bone/const.c b/kazoj/bone/const.c index ef91f9fe..e2fe30b6 100644 --- a/kazoj/bone/const.c +++ b/kazoj/bone/const.c @@ -1,7 +1,7 @@ #include #include #define HELAPORDO_CURSES_BUILD -#include "../../src/game_core.h" +#include "../../src/core/game_core.h" void fail(char* msg, int ex, int val) { printf("[Fail] %s, expected (%i), was %i\n",msg,ex,val); @@ -9,7 +9,7 @@ void fail(char* msg, int ex, int val) { int main(void) { int check = -1; - if ( ! (( check = strcmp(VERSION, "1.4.2") ) == 0)) { + if ( ! (( check = strcmp(VERSION, "1.4.3") ) == 0)) { fail("VERSION",0,check); }; if ( ! (HLP_MAX_INDEX == 31) ) { diff --git a/kazoj/bone/const_rl.c b/kazoj/bone/const_rl.c index 1663e208..87e92584 100644 --- a/kazoj/bone/const_rl.c +++ b/kazoj/bone/const_rl.c @@ -1,7 +1,7 @@ #include #include #define HELAPORDO_RAYLIB_BUILD -#include "../../src/game_core.h" +#include "../../src/core/game_core.h" #include void fail(char* msg, int ex, int val) { @@ -10,7 +10,7 @@ void fail(char* msg, int ex, int val) { int main(void) { int check = -1; - if ( ! (( check = strcmp(VERSION, "1.4.2") ) == 0)) { + if ( ! (( check = strcmp(VERSION, "1.4.3") ) == 0)) { fail("VERSION",0,check); }; if ( ! (HLP_MAX_INDEX == 31) ) { diff --git a/kazoj/bone/const_rl.k.stderr b/kazoj/bone/const_rl.k.stderr new file mode 100644 index 00000000..e69de29b diff --git a/kazoj/bone/const_rl.k.stdout b/kazoj/bone/const_rl.k.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/floor_tester.c b/src/build-nc-w64/floor_tester.c similarity index 99% rename from src/floor_tester.c rename to src/build-nc-w64/floor_tester.c index eb4b5d65..95d4ff25 100644 --- a/src/floor_tester.c +++ b/src/build-nc-w64/floor_tester.c @@ -16,7 +16,6 @@ along with this program. If not, see . */ #include "floor_tester.h" -#include "floors.h" #ifdef HELAPORDO_CURSES_BUILD int test_floors(void) diff --git a/src/floor_tester.h b/src/build-nc-w64/floor_tester.h similarity index 96% rename from src/floor_tester.h rename to src/build-nc-w64/floor_tester.h index 860198dd..42232bcc 100644 --- a/src/floor_tester.h +++ b/src/build-nc-w64/floor_tester.h @@ -18,6 +18,7 @@ #ifndef FLOOR_TEST_H #define FLOOR_TEST_H +#include "../utils/floors.h" int test_floors(void); diff --git a/src/build-nc-w64/helapordo_win.c b/src/build-nc-w64/helapordo_win.c new file mode 100644 index 00000000..811cf746 --- /dev/null +++ b/src/build-nc-w64/helapordo_win.c @@ -0,0 +1,328 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "helapordo_win.h" + +/** + * Takes a integer and a string array (possibly from main). + * @param argc The number of argv values + 1 (0 is program name?). + * @param argv Array of strings with argc - 1 values. + */ +void gameloop_Win(int argc, char **argv) +{ + char *whoami; + char path_to_kls_debug_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Truncate "debug_log.txt" + sprintf(path_to_kls_debug_file, "%s\\%s", static_path, "kls_debug_log.txt"); + KLS_Conf default_kls_conf = { + .kls_autoset_regions = 1, + .kls_autoset_temp_regions = 1, + .kls_verbose_lvl = 1, + .kls_log_filepath = path_to_kls_debug_file, + .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, + .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, + }; + KLS_Conf temporary_kls_conf = { + .kls_autoset_regions = 1, + .kls_autoset_temp_regions = 1, + .kls_verbose_lvl = 0, + .kls_log_fp = stderr, + .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, + .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, + }; + + bool is_localexe = ( argv[0][0] == '.'); + (whoami = strrchr(argv[0], '\\')) ? ++whoami : (whoami = argv[0]); + do { + default_kls = kls_new_conf(KLS_DEFAULT_SIZE * 8, default_kls_conf); + temporary_kls = kls_new_conf(KLS_DEFAULT_SIZE * 8, temporary_kls_conf); + char *kls_progname = + (char *)KLS_PUSH_ARR_TYPED(default_kls, char *, sizeof(whoami), + KLS_None, "progname", whoami); + strcpy(kls_progname, whoami); +#ifndef HELAPORDO_DEBUG_LOG +#else + FILE *debug_file = NULL; + FILE *OPS_debug_file = NULL; +#endif + // Parse command-line options + int option; + loadInfo *load_info = + (loadInfo *) KLS_PUSH_TYPED(default_kls, loadInfo, HR_loadInfo, + "loadInfo", "loadInfo"); + + load_info->is_new_game = 1; //By default we do a new game + load_info->enemy_index = -1; + load_info->total_foes = -1; + load_info->save_type = -1; + int loaded_roomtotalenemies = -1; + int loaded_roomindex = -1; + load_info->ptr_to_roomtotalenemies = &loaded_roomtotalenemies; + load_info->ptr_to_roomindex = &loaded_roomindex; + + while ((option = getopt(argc, argv, "r:E:tTGRXQLlvdhsaV")) != -1) { + switch (option) { + case 'd': { +#ifndef HELAPORDO_DEBUG_ACCESS +#else + G_DEBUG_ON += 1; + G_LOG_ON = 1; +#endif + } + break; + case 'r': { + G_DEBUG_ROOMTYPE_ON += 1; + } + break; + case 'E': { + G_DEBUG_ENEMYTYPE_ON += 1; + } + break; + case 'L': { + G_LOG_ON = 1; + } + break; + break; + case 'G': { + G_GODMODE_ON = 1; + } + break; + case 'Q': { + G_FASTQUIT_ON = 1; + } + break; + case 'X': { + G_EXPERIMENTAL_ON = 1; + } + break; + case 'a': { + GS_AUTOSAVE_ON = 0; + } + break; + case 's': { + GAMEMODE = Story; + } + break; + case 'R': { + GAMEMODE = Rogue; + } + break; + break; + case 'h': { + usage(whoami); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 'T': { + G_DOTUTORIAL_ON = 1; + handleTutorial(); + usage(whoami); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 't': { + //Test all colors + printFormattedVersion(whoami); + printf("Using:\n"); + printf(" \'animate\' :\n s4c/animate.h "); + S4C_ECHOVERSION(); + printf("[DEBUG] Testing terminal color capabilities.\n"); + napms(800); + //TODO Win term color test? + //display_colorpairs(); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 'V': { + printf("helapordo build: %s\n", helapordo_build_string); + hlpd_dbg_features(); + printf(" using: s4c-animate v%s\n", S4C_ANIMATE_VERSION); + s4c_dbg_features(); + printf(" using: koliseo v%s\n", string_koliseo_version()); + kls_dbg_features(); + printf(" using: ncurses v%s\n", NCURSES_VERSION); +#ifdef ANVIL__helapordo__ +#ifndef INVIL__helapordo__HEADER__ + printf(" Built with: amboso v%s\n", + ANVIL__API_LEVEL__STRING); +#else + printf(" Built with: invil v%s\n", + INVIL__VERSION__STRING); + printf("Version Info: %.8s\n", + get_ANVIL__VERSION__DESC__()); + printf("Last commit: %s", get_INVIL__COMMIT__DESC__()); + const char* anvil_date = get_ANVIL__VERSION__DATE__(); + char* anvil_date_end; +#ifndef _WIN32 + time_t anvil_build_time = strtol(anvil_date, &anvil_date_end, 10); +#else + time_t anvil_build_time = strtoll(anvil_date, &anvil_date_end, 10); +#endif //_WIN32 + + if (anvil_date_end == anvil_date) { + //TODO: error + } else { + char build_time_buff[20] = {0}; + struct tm* build_time_tm = localtime(&anvil_build_time); + + if (build_time_tm == NULL) { + //TODO: error + } else { + strftime(build_time_buff, 20, "%Y-%m-%d %H:%M:%S", build_time_tm); + printf("\nDate: %s\n", build_time_buff); + } + } +#endif // INVIL__helapordo__HEADER__ +#else + printf(" Built without anvil\n"); +#endif // ANVIL__helapordo__ + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 'v': { + printVersion(); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + case '?': { + fprintf(stderr, + "Invalid option: %c\n Check your arguments.\n", + option); + usage(whoami); + // Handle invalid options + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + default: { + // Should never get here + fprintf(stderr, "Invalid option: %c\n, bad usage.\n", + option); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } + } + +#ifndef HELAPORDO_DEBUG_LOG +#else + // Open log file if log flag is set and reset it + if (G_LOG_ON == 1) { + char path_to_debug_file[600]; + char path_to_OPS_debug_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Truncate "debug_log.txt" + sprintf(path_to_debug_file, "%s\\%s", static_path, "debug_log.txt"); + debug_file = fopen(path_to_debug_file, "w"); + if (!debug_file) { + endwin(); //TODO: Can/should we check if we have to do this only in curses mode? + fprintf(stderr, + "[ERROR] Can't open debug logfile (%s\\debug_log.txt).\n", + static_path); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + fprintf(debug_file, "[DEBUGLOG] --New game-- \n"); + fprintf(debug_file, "[DEBUG] --Default kls debug info:-- \n"); + print_kls_2file(debug_file, default_kls); + fprintf(debug_file, "[DEBUG] --Temporary kls debug info:-- \n"); + print_kls_2file(debug_file, temporary_kls); + fprintf(debug_file, + "[DEBUG] --Closing header for new game.-- \n"); + fclose(debug_file); + + //Lay debug info + log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", + G_DEBUG_ON); + //FIXME we should have same behaviour as gameloop(), and actually log kls_progname... + //Doesn't matter for now, kls_progname is declared later + log_tag("debug_log.txt", "[DEBUG]", "whoami == (%s)", whoami); + log_tag("debug_log.txt", "[DEBUG]", "is_localexe == (%s)", (is_localexe ? "true" : "false")); + log_tag("debug_log.txt", "[DEBUG]", "G_LOG_ON == (%i)", G_LOG_ON); + log_tag("debug_log.txt", "[DEBUG]", "small DEBUG FLAG ASSERTED"); + log_tag("debug_log.txt", "[DEBUG]", + "[Current position in default_kls] [pos: %lli]\n", + kls_get_pos(default_kls)); + + //Truncate OPS_LOGFILE + sprintf(path_to_OPS_debug_file, "%s\\%s", static_path, OPS_LOGFILE); + OPS_debug_file = fopen(path_to_OPS_debug_file, "w"); + if (!OPS_debug_file) { + endwin(); //TODO: Can/should we check if we have to do this only in curses mode? + fprintf(stderr, "[ERROR] Can't open OPS logfile (%s\\%s).\n", + static_path, OPS_LOGFILE); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + fprintf(OPS_debug_file, "[OPLOG] --New game-- \n"); + fclose(OPS_debug_file); + log_tag("debug_log.txt", "[DEBUG]", "Truncated [%s]", OPS_LOGFILE); + log_Win_EnvVars(); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "Printing title."); + } +#endif + printTitle(); + printf("\n\n\n\n\t\t\t\tSTART\n\n"); + if (G_DEBUG_ON) { + printf("\t\t\t\t\t\t\t\tDEBUG ON\n"); + } + printf("\t\t\t\t\t\t"); + printFormattedVersion(whoami); + printf("\n\nThe Windows build of \"helapordo\" is very much WIP.\n\n"); + printf("\n Press Enter to proceed.\n"); + scanf("%*c"); + system("cls"); + printGlobVars(); + printWin_EnvVars(); + printf("\n\n Press Enter to demo a minimal rogue floor.\n"); + printf(" Quit with Ctrl+C, or explore enough of the map.\n\n"); + printf(" You move with the arrow keys.\n\n"); + scanf("%*c"); + test_floors(); + kls_free(temporary_kls); + kls_free(default_kls); + } while (retry()); + + //TODO + //What is this? + printf("\n\n\t\tTHANKS 4 PLAYING!\n\n"); + log_tag("debug_log.txt", "[DEBUG]", "End of program."); + kls_free(default_kls); + kls_free(temporary_kls); + exit(0); +} diff --git a/src/build-nc-w64/helapordo_win.h b/src/build-nc-w64/helapordo_win.h new file mode 100644 index 00000000..6b887c77 --- /dev/null +++ b/src/build-nc-w64/helapordo_win.h @@ -0,0 +1,45 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 . +*/ + +/*! \mainpage Helapordo index page + * + * \section intro_sec Intro + * + * Helapordo is roguelike terminal game, using ncurses. + * + * SPDX-License-Identifier: GPL-3.0-only + * + * Check it out on [github](https://github.com/jgabaut/helapordo). + */ + +#ifndef HELAPORDO_H +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) //We need C11 +#define HELAPORDO_H + +#include "floor_tester.h" + +#include "../utils/rooms.h" +#include "../anvil__helapordo.h" +#include "../core/game_lore.h" + +void gameloop_Win(int argc, char **argv); + +#else +#error "This code requires C11.\n _Alignof\n" +#endif +#endif //HELAPORDO_H diff --git a/src/game_curses.c b/src/build-nc/game_curses.c similarity index 94% rename from src/game_curses.c rename to src/build-nc/game_curses.c index e22cd217..73b57298 100644 --- a/src/game_curses.c +++ b/src/build-nc/game_curses.c @@ -16,7 +16,6 @@ along with this program. If not, see . */ #include "game_curses.h" -#include "helapordo.h" callback_void_t callback_func_ptrs[SPECIALSMAX]; callback_void_t callback_artifact_ptrs[ARTIFACTSMAX]; @@ -1631,276 +1630,6 @@ void boss_print_in_panel(WINDOW *win, int starty, int startx, int width, refresh(); } -/** - * Takes a WINDOW pointer and prints to it the passed string with the passed color. - * Additional parameters set coordinates for the output. - * @param win The WINDOW pointer to print to. - * @param starty The integer indicating starting y coordinate. - * @param startx The integer indicating starting x coordinate. - * @param width The integer indicating panel width. - * @param string The string to print to the window. - * @param color The color to print in. - */ -void print_label(WINDOW *win, int starty, int startx, int width, char *string, - chtype color) -{ - int length, x, y; - float temp; - - if (win == NULL) { - log_tag("debug_log.txt", "[CURSES]", - "win was NULL in boss_print_in_panel()."); - exit(EXIT_FAILURE); - } - getyx(win, y, x); - if (startx != 0) - x = startx; - if (starty != 0) - y = starty; - if (width == 0) - width = 80; - - length = strlen(string); - temp = (width - length) / 2; - x = startx + (int)temp; - wattron(win, color); - mvwprintw(win, y, x, "%s", string); - wattroff(win, color); - refresh(); -} - -/** - * Takes a WINDOW pointer to print notifications to, a fighterStatus value and a string of who's the entity to print the respective status message. - * @see fighterStatus - * @param notify_win The pointer to the window to use display_notification() on. - * @param status The fighterStatus at hand. - * @param subject A string with name of entity owning the fighterStatus. - */ -void printStatusText(WINDOW *notify_win, fighterStatus status, char *subject) -{ - char msg[500]; - switch (status) { - case Normal: { - return; - }; - break; - case Poison: - case Burned: { - sprintf(msg, "%s is hurt by its %s.", subject, - stringFromStatus(status)); - display_notification(notify_win, msg, 500); - } - break; - case Weak: - case Strong: { - sprintf(msg, "%s is feeling %s.", subject, - stringFromStatus(status)); - display_notification(notify_win, msg, 500); - } - break; - case Frozen: { - sprintf(msg, "%s is frozen cold.", subject); - display_notification(notify_win, msg, 500); - } - break; - } -} - -/** - * Takes a WINDOW pointer to print notifications to, a Fighter pointer value and applies the effect pertaining to its status value. - * @see Fighter - * @see fighterStatus - * @see printStatusText() - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param f The Fighter pointer at hand. - */ -void applyStatus(WINDOW *notify_win, Fighter *f) -{ - - switch (f->status) { - case Normal: { - break; - } - break; - case Poison: { - - //Account for penicillin perk - //ATM multiples don't stack - int penicillin = f->perks[PENICILLIN]->innerValue; - if (penicillin > 0) { - return; - } - - if (f->hp >= 4) { - f->hp -= 3; - } else { - f->hp = 1; //Will this be a problem? - } - printStatusText(notify_win, Poison, f->name); - } - break; - case Burned: { - printStatusText(notify_win, Burned, f->name); - } - break; - case Frozen: { - printStatusText(notify_win, Frozen, f->name); - } - break; - case Weak: - - break; - case Strong: - - break; - } -} - -/** - * Takes a WINDOW pointer to print notifications to, a Enemy pointer value and applies the effect pertaining to its status value. - * @see Enemy - * @see fighterStatus - * @see printStatusText() - * @see stringFromEClass() - * @param notify_win The window pointer to call display_notification() on. - * @param e The Enemy pointer at hand. - * @see display_notification() - */ -void applyEStatus(WINDOW *notify_win, Enemy *e) -{ - - wattron(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); - - switch (e->status) { - case Normal: { - break; - } - break; - case Poison: { - if (e->hp >= 4) { - e->hp -= 3; - } else { - e->hp = 1; //Will this be a problem for kills in the enemy loop? - } - printStatusText(notify_win, Poison, stringFromEClass(e->class)); - } - break; - case Burned: { - if (e->hp >= 5) { - e->hp -= 4; - } else { - e->hp = 1; //Will this be a problem for kills in the enemy loop? - } - - if (e->atk >= 3) { - e->atk -= 3; - } else { - e->atk = 1; - } - printStatusText(notify_win, Burned, stringFromEClass(e->class)); - } - break; - case Frozen: { - if (e->vel >= 3) { - e->vel -= 1; - } else { - e->vel = 1; //Will this be a problem for kills in the enemy loop? - } - printStatusText(notify_win, Frozen, stringFromEClass(e->class)); - } - - break; - case Weak: - - break; - case Strong: - - break; - } - - wattroff(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); -} - -/** - * Takes a WINDOW pointer to print notifications to, a Boss pointer value and applies the effect pertaining to its status value. - * @see Boss - * @see fighterStatus - * @see printStatusText() - * @see stringFromBossClass() - * @param notify_win The window pointer to call disaply_notification() on. - * @param b The Boss pointer at hand. - */ -void applyBStatus(WINDOW *notify_win, Boss *b) -{ - - wattron(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); - - switch (b->status) { - case Normal: { - break; - } - break; - case Poison: { - if (b->hp >= 4) { - b->hp -= 3; - } else { - b->hp = 1; //Will this be a problem for kills in the enemy loop? - } - printStatusText(notify_win, Poison, stringFromBossClass(b->class)); - } - break; - case Burned: { - if (b->hp >= 5) { - b->hp -= 4; - } else { - b->hp = 1; //Will this be a problem for kills in the enemy loop? - } - - if (b->atk >= 3) { - b->atk -= 3; - } else { - b->atk = 1; - } - printStatusText(notify_win, Burned, stringFromBossClass(b->class)); - } - break; - case Frozen: { - if (b->vel >= 3) { - b->vel -= 1; - } else { - b->vel = 1; //Will this be a problem for kills in the enemy loop? - } - printStatusText(notify_win, Frozen, stringFromBossClass(b->class)); - } - - break; - case Weak: - - break; - case Strong: - - break; - } - - wattroff(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); -} - -/** - * Takes a WINDOW pointer and prints the passed text to it ith wprintw(), before sleeping for the specified amount of milliseconds. - * @see handleRoom_Enemies() - * @see handleRoom_Boss() - * @param w The WINDOW pointer to print to. - * @param text The contents of the notification. - * @param time The display time in milliseconds - */ -void display_notification(WINDOW *w, char *text, int time) -{ - wprintw(w, "\n %s", text); - wrefresh(w); - //refresh(); - napms(time); -} - /** * Takes a Enemy pointer and prepares its sprite field by copying it line by line from enemies_sprites, defined in sprites.h header. * @see Enemy @@ -2007,26 +1736,6 @@ void setArtifactSprite(Artifact *a) } } -/** - * Takes a Equip pointer and prepares its sprite field by copying it line by line from equips_sprites, defined in sprites.h header. - * @see Equip - * @see dropEquip - * @see equips_sprites - * @param e The Equip pointer whose sprite field will be initialised. - */ -void setEquipSprite(Equip *e) -{ - if (e->class < EQUIPSMAX + 1) { - for (int i = 0; i < 8; i++) { - strcpy(e->sprite[i], equips_sprites[e->class][i]); - } - } else { - fprintf(stderr, - "[ERROR] Unexpected equipClass in setEquipSprite().\n"); - exit(EXIT_FAILURE); - } -} - /** * Takes a Equipslot pointer and prepares its sprite field by copying it line by line from equipzones_sprites, defined in sprites.h header. * @see Equipslot diff --git a/src/game_curses.h b/src/build-nc/game_curses.h similarity index 75% rename from src/game_curses.h rename to src/build-nc/game_curses.h index 8e22772f..70627a0a 100644 --- a/src/game_curses.h +++ b/src/build-nc/game_curses.h @@ -36,35 +36,10 @@ #define HLPD_MIN_SCREEN_ROWS (HLPD_DEFAULT_SCREEN_ROWS+4) /**< Defines minimum y size for game screen.*/ #define HLPD_MIN_SCREEN_COLS (HLPD_DEFAULT_SCREEN_COLS) /**< Defines minimum x size for game screen.*/ -#include #include -#include "game_core.h" -#include "game_utils.h" - -#include "palette.h" - -#include "./animations/knight_tapis.h" -#include "./animations/mage_spark.h" -#include "./animations/archer_drop.h" -#include "./animations/assassin_poof.h" - -#include "./animations/mummy_shuffle.h" -#include "./animations/ghost_spell.h" -#include "./animations/boar_scream.h" -#include "./animations/troll_club.h" -#include "./animations/goblin_shoot.h" -#include "./animations/zombie_walk.h" -#include "./animations/imp_fireball.h" -#include "./animations/werewolf_transform.h" - -#include "./animations/crawlingdude_crawl.h" -#include "./animations/srwarthog_square.h" -#include "./animations/headlessninja_throw.h" -#include "./animations/bluetroll_wonder.h" - -#include "./animations/enter_door.h" -#include "./animations/alt_chest_opening.h" +#include "../utils/turn_op.h" +#include "../core/game_animations.h" int display_colorpairs(void); void print_encoded_char(WINDOW * w, int y, int x, char c); @@ -85,22 +60,8 @@ void boss_win_show(WINDOW * win, Boss * b, Fighter * f, int isBoss, int border); void boss_print_in_panel(WINDOW * win, int starty, int startx, int width, Boss * b, Fighter * f, int isBoss); -void print_label(WINDOW * win, int starty, int startx, int width, char *string, - chtype color); - -void printStatusText(WINDOW * notify_win, fighterStatus status, char *subject); - -void applyStatus(WINDOW * notify_win, Fighter * f); - -void applyEStatus(WINDOW * notify_win, Enemy * e); - -void applyBStatus(WINDOW * notify_win, Boss * b); - -void display_notification(WINDOW * w, char *text, int time); - void setConsumableSprite(Consumable * c); void setArtifactSprite(Artifact * a); -void setEquipSprite(Equip * e); void setEquipslotSprite(Equipslot * s); void setEnemySprite(Enemy * e); void setBossSprite(Boss * b); diff --git a/src/build-nc/helapordo.c b/src/build-nc/helapordo.c new file mode 100644 index 00000000..0fdb1602 --- /dev/null +++ b/src/build-nc/helapordo.c @@ -0,0 +1,2230 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "helapordo.h" + +//TODO Drop dead code +/* + * Takes an integer, a callback_void_t pointer function and a Fighter holding the array for the callback registration. + * Not working as of v0.5.2. + * Registers the pointer to the function pointer array for counter callback. + * @see Turncounter + * @param index An integer. + * @param ptr A pointer to function of type callback_void_t. + * @param f The fighter pointer holding the callback array. + * +void register_counter_callback(int index, callback_void_t ptr, Fighter* f) { + f->callback_counter_ptrs[index] = ptr; +} +*/ + +/** + * Takes a integer and a string array (possibly from main). + * Initialises a Path pointer and a Fighter pointer, before looping for each oom in path length by calling the correct room function. + * If all the rooms are cleared, prints a victory message and exits the program. + * Then getParams() is called to initialise a Fighter pointer's name and class fields. + * Takes an integer seed and frees path pointer. + * Notably, player pointer is not freed here. + * @see Path + * @see Fighter + * @see getParams() + * @see initPlayerStats() + * @see room() + * @see handleStats() + * @see printStats() + * @param argc The number of argv values + 1 (0 is program name?). + * @param argv Array of strings with argc - 1 values. + */ +void gameloop(int argc, char **argv) +{ + + char *whoami; // This will reference argv[0] at basename, it's the same string in memory, just starting later + char path_to_kls_debug_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Truncate "debug_log.txt" + sprintf(path_to_kls_debug_file, "%s/%s", static_path, "kls_debug_log.txt"); + KLS_Conf default_kls_conf = { + .kls_autoset_regions = 1, + .kls_autoset_temp_regions = 1, + .kls_verbose_lvl = 1, + .kls_log_filepath = path_to_kls_debug_file, + .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, + .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, + }; + KLS_Conf temporary_kls_conf = { + .kls_autoset_regions = 1, + .kls_autoset_temp_regions = 1, + .kls_verbose_lvl = 0, + .kls_log_fp = stderr, + .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, + .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, + }; + + do { + //Init default_kls + default_kls = kls_new_conf(KLS_DEFAULT_SIZE * 16, default_kls_conf); + temporary_kls = kls_new_conf(KLS_DEFAULT_SIZE * 32, temporary_kls_conf); + +#ifndef _WIN32 + (whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]); +#else + (whoami = strrchr(argv[0], '\\')) ? ++whoami : (whoami = argv[0]); +#endif + bool is_localexe = ( argv[0][0] == '.'); + + char *kls_progname = + (char *)KLS_PUSH_ARR_TYPED(default_kls, char *, sizeof(whoami), + KLS_None, "progname", whoami); + strcpy(kls_progname, whoami); + +#ifndef HELAPORDO_DEBUG_LOG +#else + FILE *debug_file = NULL; + FILE *OPS_debug_file = NULL; +#endif + // Parse command-line options + int option; + loadInfo *load_info = + (loadInfo *) KLS_PUSH_TYPED(default_kls, loadInfo, HR_loadInfo, + "loadInfo", "loadInfo"); + + load_info->is_new_game = 1; //By default we do a new game + load_info->enemy_index = -1; + load_info->total_foes = -1; + load_info->save_type = -1; + int loaded_roomtotalenemies = -1; + int loaded_roomindex = -1; + load_info->ptr_to_roomtotalenemies = &loaded_roomtotalenemies; + load_info->ptr_to_roomindex = &loaded_roomindex; + + while ((option = getopt(argc, argv, "f:r:E:tTGRXQLlvdhsaV")) != -1) { + switch (option) { + case 'd': { +#ifndef HELAPORDO_DEBUG_ACCESS +#else + G_DEBUG_ON += 1; + G_LOG_ON = 1; +#endif + } + break; + case 'r': { + G_DEBUG_ROOMTYPE_ON += 1; + G_DEBUG_ROOMTYPE_ARG = optarg; + } + break; + case 'E': { + G_DEBUG_ENEMYTYPE_ON += 1; + G_DEBUG_ENEMYTYPE_ARG = optarg; + } + break; + case 'L': { + G_LOG_ON = 1; + } + break; + case 'l': { + load_info->is_new_game = 0; + } + break; + case 'G': { + G_GODMODE_ON = 1; + } + break; + case 'Q': { + G_FASTQUIT_ON = 1; + } + break; + case 'X': { + G_EXPERIMENTAL_ON = 1; + } + break; + case 'a': { + GS_AUTOSAVE_ON = 0; + } + break; + case 's': { + GAMEMODE = Story; + } + break; + case 'R': { + GAMEMODE = Rogue; + } + break; + case 'f': { + //filename = optarg; + } + break; + case 'h': { + usage(whoami); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 'T': { + G_DOTUTORIAL_ON = 1; + handleTutorial(); + usage(whoami); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 't': { + //Test all colors + printFormattedVersion(whoami); + printf("Using:\n"); + printf(" \'animate\' :\n s4c/animate.h "); + S4C_ECHOVERSION(); + printf("[DEBUG] Testing terminal color capabilities.\n"); + napms(200); + display_colorpairs(); + napms(200); + WINDOW *test_win; + initscr(); + start_color(); + for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { + init_s4c_color_pair(&palette[i], 9 + i); + } + clear(); + refresh(); + cbreak(); + noecho(); + test_win = newwin(9, 7, 1, 1); + keypad(test_win, TRUE); + box(test_win, 0, 0); + + refresh(); + + test_game_color_pairs(test_win, 5); + + napms(200); + delwin(test_win); + endwin(); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 'V': { + printf("helapordo build: %s\n", helapordo_build_string); + hlpd_dbg_features(); + printf(" using: s4c-animate v%s\n", S4C_ANIMATE_VERSION); + s4c_dbg_features(); + printf(" using: koliseo v%s\n", string_koliseo_version()); + kls_dbg_features(); + printf(" using: ncurses v%s\n", NCURSES_VERSION); +#ifdef ANVIL__helapordo__ +#ifndef INVIL__helapordo__HEADER__ + printf(" Built with: amboso v%s\n", + ANVIL__API_LEVEL__STRING); +#else + printf(" Built with: invil v%s\n", + INVIL__VERSION__STRING); + printf("Last commit: %s", get_INVIL__COMMIT__DESC__()); +#endif // INVIL__helapordo__HEADER__ + printf("Version Info: %.8s\n", + get_ANVIL__VERSION__DESC__()); + const char* anvil_date = get_ANVIL__VERSION__DATE__(); + char* anvil_date_end; +#ifndef _WIN32 + time_t anvil_build_time = strtol(anvil_date, &anvil_date_end, 10); +#else + time_t anvil_build_time = strtoll(anvil_date, &anvil_date_end, 10); +#endif //_WIN32 + + if (anvil_date_end == anvil_date) { + //TODO: error + } else { + char build_time_buff[20] = {0}; + struct tm* build_time_tm = localtime(&anvil_build_time); + + if (build_time_tm == NULL) { + //TODO: error + } else { + strftime(build_time_buff, 20, "%Y-%m-%d %H:%M:%S", build_time_tm); + printf("\nDate: %s\n", build_time_buff); + } + } + const char* headergen_date = get_ANVIL__HEADER__GENTIME__(); + char* headergen_date_end; +#ifndef _WIN32 + time_t headergen_time = strtol(headergen_date, &headergen_date_end, 10); +#else + time_t headergen_time = strtoll(headergen_date, &headergen_date_end, 10); +#endif //_WIN32 + + if (headergen_date_end == headergen_date) { + //TODO: error + } else { + char headergen_time_buff[20] = {0}; + struct tm* headergen_time_tm = localtime(&headergen_time); + + if (headergen_time_tm == NULL) { + //TODO: error + } else { + strftime(headergen_time_buff, 20, "%Y-%m-%d %H:%M:%S", headergen_time_tm); + printf("Anvil Gen Date: %s\n", headergen_time_buff); + } + } +#else + printf(" Built without anvil\n"); +#endif // ANVIL__helapordo__ + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case 'v': { + printVersion(); + /* + printf("Using:\n"); + printf(" \'animate\' :\n s4c/animate.h "); + S4C_ECHOVERSION(); + printf("\n \'anvil\' :\n"); + int status = system("echo \" $( anvil -vv 2>/dev/null ) \""); + int exitcode = status / 256; + if (exitcode != 0) { + printf("\033[1;31m[DEBUG]\e[0m \"anvil -vv\" failed.\n\n Maybe amboso is not installed globally?\n"); + exit(exitcode); + } + exit(exitcode); + */ + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + break; + case '?': { + fprintf(stderr, + "Invalid option: %c\n Check your arguments.\n", + option); + usage(whoami); + // Handle invalid options + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + default: { + // Should never get here + fprintf(stderr, "Invalid option: %c\n, bad usage.\n", + option); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } + } + +#ifndef HELAPORDO_DEBUG_LOG +#else + // Open log file if log flag is set and reset it + if (G_LOG_ON == 1) { + char path_to_debug_file[600]; + char path_to_OPS_debug_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Truncate "debug_log.txt" + sprintf(path_to_debug_file, "%s/%s", static_path, "debug_log.txt"); + debug_file = fopen(path_to_debug_file, "w"); + if (!debug_file) { + endwin(); //TODO: Can/should we check if we have to do this only in curses mode? + fprintf(stderr, + "[ERROR] Can't open debug logfile (%s/debug_log.txt).\n", + static_path); + exit(EXIT_FAILURE); + } + fprintf(debug_file, "[DEBUGLOG] --New game-- \n"); + if (NCURSES_VERSION_MAJOR < EXPECTED_NCURSES_VERSION_MAJOR + && NCURSES_VERSION_MINOR < EXPECTED_NCURSES_VERSION_MINOR + && NCURSES_VERSION_PATCH < EXPECTED_NCURSES_VERSION_PATCH) { + fprintf(debug_file, + "[WARN] ncurses version is lower than expected {%s: %i.%i.%i} < {%i.%i.%i}\n", + NCURSES_VERSION, NCURSES_VERSION_MAJOR, + NCURSES_VERSION_MINOR, NCURSES_VERSION_PATCH, + EXPECTED_NCURSES_VERSION_MAJOR, + EXPECTED_NCURSES_VERSION_MINOR, + EXPECTED_NCURSES_VERSION_PATCH); + } + fprintf(debug_file, "[DEBUG] --Default kls debug info:-- \n"); + print_kls_2file(debug_file, default_kls); + fprintf(debug_file, "[DEBUG] --Temporary kls debug info:-- \n"); + print_kls_2file(debug_file, temporary_kls); + fprintf(debug_file, + "[DEBUG] --Closing header for new game.-- \n"); + fclose(debug_file); + + //Lay debug info + log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", + G_DEBUG_ON); + log_tag("debug_log.txt", "[DEBUG]", "kls_progname == (%s)", + kls_progname); + log_tag("debug_log.txt", "[DEBUG]", "is_localexe == (%s)", (is_localexe ? "true" : "false")); + log_tag("debug_log.txt", "[DEBUG]", "G_LOG_ON == (%i)", G_LOG_ON); + log_tag("debug_log.txt", "[DEBUG]", "small DEBUG FLAG ASSERTED"); + log_tag("debug_log.txt", "[DEBUG]", + "[Current position in default_kls] [pos: %li]\n", + kls_get_pos(default_kls)); + + //Truncate OPS_LOGFILE + sprintf(path_to_OPS_debug_file, "%s/%s", static_path, OPS_LOGFILE); + OPS_debug_file = fopen(path_to_OPS_debug_file, "w"); + if (!OPS_debug_file) { + endwin(); //TODO: Can/should we check if we have to do this only in curses mode? + fprintf(stderr, "[ERROR] Can't open OPS logfile (%s/%s).\n", + static_path, OPS_LOGFILE); + exit(EXIT_FAILURE); + } + fprintf(OPS_debug_file, "[OPLOG] --New game-- \n"); + fclose(OPS_debug_file); + log_tag("debug_log.txt", "[DEBUG]", "Truncated [%s]", OPS_LOGFILE); + } +#endif + + if (G_DEBUG_ENEMYTYPE_ON == 1) { + log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ENEMYTYPE_ON == (%i)", + G_DEBUG_ENEMYTYPE_ON); + log_tag("debug_log.txt", "[DEBUG]", "ENEMY DEBUG FLAG ASSERTED"); + if ((G_DEBUG_ON > 0)) { + G_DEBUG_ON += 1; + log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", + G_DEBUG_ON); + log_tag("debug_log.txt", "[DEBUG]", "Forcing enemy type: (%s)", + G_DEBUG_ENEMYTYPE_ARG); + int setenemy_debug = 0; + for (int ec = 0; ec < ENEMYCLASSESMAX && (setenemy_debug == 0); + ec++) { + log_tag("debug_log.txt", "[DEBUG]", + "Checking optarg for -E: (%s)", + stringFromEClass(ec)); + if ((strcmp(G_DEBUG_ENEMYTYPE_ARG, stringFromEClass(ec)) == + 0)) { + log_tag("debug_log.txt", "[DEBUG]", + "Match on optarg (%s), setting G_DEBUG_ENEMYTYPE to (%i).", + stringFromEClass(ec), ec); + G_DEBUG_ENEMYTYPE = ec; + setenemy_debug = 1; + } + } + if (setenemy_debug == 0) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid optarg for -E flag: {%s}.\n", + G_DEBUG_ENEMYTYPE_ARG); + fprintf(stderr, + "[ERROR] Incorrect -E \"enemyType\" arg: {%s}.\n", + G_DEBUG_ENEMYTYPE_ARG); + fprintf(stderr, "[ERROR] Run \"%s -h\" for help.\n", + kls_progname); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + }; + } + } + if (G_DEBUG_ROOMTYPE_ON == 1) { + log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ROOMTYPE_ON == (%i)", + G_DEBUG_ROOMTYPE_ON); + log_tag("debug_log.txt", "[DEBUG]", "ROOM DEBUG FLAG ASSERTED"); + if ((G_DEBUG_ON > 0)) { + G_DEBUG_ON += 1; + log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", + G_DEBUG_ON); + log_tag("debug_log.txt", "[DEBUG]", + "Forcing room type: optarg was (%s)", + G_DEBUG_ROOMTYPE_ARG); + int setroom_debug = 0; + for (int rc = 0; + (rc < ROOM_CLASS_MAX + 1) && (setroom_debug == 0); rc++) { + log_tag("debug_log.txt", "[DEBUG]", + "Checking optarg (%s) for -R: (%s)", optarg, + stringFromRoom(rc)); + if ((strcmp(G_DEBUG_ROOMTYPE_ARG, stringFromRoom(rc)) == 0)) { + log_tag("debug_log.txt", "[DEBUG]", + "Match on optarg (%s), setting G_DEBUG_ROOMTYPE to (%i).", + stringFromRoom(rc), rc); + G_DEBUG_ROOMTYPE = rc; + setroom_debug = 1; + } + } + if (setroom_debug == 0) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid optarg for -R flag: {%s}.", + G_DEBUG_ROOMTYPE_ARG); + fprintf(stderr, + "[ERROR] Incorrect -R \"roomType\" arg: {%s}.\n", + G_DEBUG_ROOMTYPE_ARG); + fprintf(stderr, "[ERROR] Run \"%s -h\" for help.\n", + kls_progname); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + }; + } + + } + log_tag("debug_log.txt", "[DEBUG]", "Done getopt."); + + // Clear screen and print title, wait for user to press enter + int clearres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() system(\"clear\") res was (%i)", clearres); + printTitle(); + char c; + yellow(); + printf("\n\n\n\n\t\t\tPRESS ENTER TO START\n\n"); + white(); + + if (G_DEBUG_ON) { + lightCyan(); + printf("\t\t\t\t\t\t\t\tDEBUG ON\n"); + white(); + } + printf("\t\t\t\t\t\t\tncurses build\n"); + printf("\t\t\t\t\t\t"); + printFormattedVersion(whoami); + int scanfres = scanf("%c", &c); + log_tag("debug_log.txt", "[DEBUG]", "gameloop() scanf() res was (%i)", + scanfres); + + // Parse positional arguments + //for (int i = optind; i < argc; i++) { + // Handle positional arguments + Path *path = NULL; + Fighter *player = NULL; + + clock_t start_time = clock(), diff_time; + + // Prepare the fighter frames + char fighter_sprites[CLASSESMAX + 1][MAXFRAMES][MAXROWS][MAXCOLS]; + + char static_path[500]; + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + /* + * Legacy code for loading animations from an s4c-file. + char fighter_filename[600]; + FILE* fighter_sprite_file; + */ + for (int i = 0; i < CLASSESMAX + 1; i++) { + + int n_load_frames = 60; + int n_load_rows = 17; + int n_load_cols = 17; + + switch (i) { + case Knight: { + s4c_copy_animation(knight_tapis, fighter_sprites[i], + n_load_frames, n_load_rows, n_load_cols); + } + break; + case Mage: { + s4c_copy_animation(mage_spark, fighter_sprites[i], + n_load_frames, n_load_rows, n_load_cols); + } + break; + case Archer: { + s4c_copy_animation(archer_drop, fighter_sprites[i], + n_load_frames, n_load_rows, n_load_cols); + } + break; + case Assassin: { + s4c_copy_animation(assassin_poof, fighter_sprites[i], + n_load_frames, n_load_rows, n_load_cols); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected fighterclass index while loading animation for class (%i): [%s]", + i, stringFromClass(i)); + exit(EXIT_FAILURE); + } + break; + } + + /* + * Legacy code for loading animations from an s4c-file + fighter_sprite_file = fopen(fighter_filename, "r"); + if (!fighter_sprite_file) { + fprintf(stderr,"Error opening animation file at (%s).\n",fighter_filename); + fprintf(stderr,"Static path was (%s).\n",static_path); + exit(EXIT_FAILURE); + } + int fighter_loadCheck = load_sprites(fighter_sprites[i], fighter_sprite_file, 17, 17); + sprintf(load_msg,"Loaded animation for %s, load result was %i.", stringFromClass(i), fighter_loadCheck); + log_tag("debug_log.txt","[PREP]",load_msg); + */ + + log_tag("debug_log.txt", "[PREP]", + "Copied animation from default matrix vector for: [%s] with dimensions: [%i][%i][%i].", + stringFromClass(i), n_load_frames, n_load_rows, + n_load_cols); + + //Massive log of all loaded lines + /* + for (int k=0; k= HLPD_MIN_SCREEN_ROWS && screen_cols >= HLPD_MIN_SCREEN_COLS) { + screen_is_big_enough = true; + clear(); + refresh(); + } else if (screen_rows >= HLPD_DEFAULT_SCREEN_ROWS && screen_cols >= HLPD_MIN_SCREEN_COLS) { + mvwprintw(screen, 0, 0, "%s", "Current screen is too small to see battle notifications."); + mvwprintw(screen, 1, 0, "%s", "Enlarge vertically to fit it."); + refresh(); + } else { + mvwprintw(screen, 0, 0, "%s", "Screen too small, please resize."); + refresh(); + } + } + GameScreen* gamescreen = (GameScreen*) KLS_PUSH_TYPED(default_kls, GameScreen, HR_Gamescreen, "Main GameScreen", "Wrap stdscr"); + gamescreen->colors = COLORS; + gamescreen->color_pairs = COLOR_PAIRS; + gamescreen->cols = COLS; + gamescreen->rows = LINES; + gamescreen->escape_delay = ESCDELAY; + gamescreen->tabsize = TABSIZE; + + gamescreen->win = screen; + ITEM **savepick_items; + MENU *savepick_menu; + WINDOW *savepick_menu_win; + WINDOW *savepick_side_win; + char current_save_path[300]; //Will hold picked path + + Koliseo_Temp *savepick_kls = kls_temp_start(temporary_kls); + + //Declare turnOP_args + Room *fakeroom = NULL; + Enemy *fakeenemy = NULL; + Boss *fakeboss = NULL; + FILE *fakesavefile = NULL; + WINDOW *fakenotifywin = NULL; + Gamestate *fakegmst = NULL; + foeTurnOption_OP fake_foe_op = FOE_OP_INVALID; + skillType fake_skill = -1; + turnOP_args *savepick_turn_args = + init_turnOP_args(fakegmst, player, path, fakeroom, load_info, + fakeenemy, fakeboss, fakesavefile, fakenotifywin, + savepick_kls, fake_foe_op, fake_skill); + char *savepick_choices[] = { + "New game", + "Load save", + "Tutorial", + "Quit", + (char *)NULL, + }; + int savepick_n_choices = ARRAY_SIZE(savepick_choices); + //FIXME: remove magic numbers + turnOption savepick_choice = 999; + + /* Create menu items */ + savepick_items = (ITEM **) calloc(savepick_n_choices, sizeof(ITEM *)); + for (int i = 0; i < savepick_n_choices; i++) { + savepick_items[i] = + new_item(savepick_choices[i], savepick_choices[i]); + } + savepick_items[savepick_n_choices - 1] = (ITEM *) NULL; + + /* Create menu */ + savepick_menu = new_menu((ITEM **) savepick_items); + + /* Set description off */ + menu_opts_off(savepick_menu, O_SHOWDESC); + + /* Create the window to be associated with the menu */ + savepick_menu_win = newwin(11, 16, 5, 35); + keypad(savepick_menu_win, TRUE); + + /* Set main window and sub window */ + set_menu_win(savepick_menu, savepick_menu_win); + set_menu_sub(savepick_menu, derwin(savepick_menu_win, 4, 14, 4, 1)); + set_menu_format(savepick_menu, 4, 1); + + /* Set menu mark to the string " > " */ + set_menu_mark(savepick_menu, " > "); + + /* Print a border around main menu window */ + box(savepick_menu_win, 0, 0); + print_label(savepick_menu_win, 1, 0, 16, "Select save", COLOR_PAIR(6)); + mvwaddch(savepick_menu_win, 2, 0, ACS_LTEE); + mvwhline(savepick_menu_win, 2, 1, ACS_HLINE, 16); + mvwaddch(savepick_menu_win, 2, 15, ACS_RTEE); + + /* Post the menu */ + post_menu(savepick_menu); + wrefresh(savepick_menu_win); + + //Handle side window for welcome info + savepick_side_win = newwin(12, 32, 2, 2); + scrollok(savepick_side_win, TRUE); + wprintw(savepick_side_win, " \nhelapordo"); + wprintw(savepick_side_win, " \n build: %s", helapordo_build_string); + wprintw(savepick_side_win, " \n using: s4c-animate v%s", + S4C_ANIMATE_VERSION); + wprintw(savepick_side_win, " \n using: koliseo v%s", + KOLISEO_API_VERSION_STRING); + wprintw(savepick_side_win, " \n using: ncurses v%s", NCURSES_VERSION); +#ifdef ANVIL__helapordo__ +#ifndef INVIL__helapordo__HEADER__ + wprintw(savepick_side_win, " \nBuilt with: amboso v%s", + ANVIL__API_LEVEL__STRING); +#else + wprintw(savepick_side_win, " \nBuilt with: invil v%s", + INVIL__VERSION__STRING); + wprintw(savepick_side_win, " \nVersion Info: %.8s", + get_ANVIL__VERSION__DESC__()); + const char* anvil_date = get_ANVIL__VERSION__DATE__(); + char* anvil_date_end; +#ifndef _WIN32 + time_t anvil_build_time = strtol(anvil_date, &anvil_date_end, 10); +#else + time_t anvil_build_time = strtoll(anvil_date, &anvil_date_end, 10); +#endif //_WIN32 + + if (anvil_date_end == anvil_date) { + log_tag("debug_log.txt", "ERROR", "anvil date was invalid"); + } else { + char build_time_buff[20] = {0}; + struct tm* build_time_tm = localtime(&anvil_build_time); + + if (build_time_tm == NULL) { + log_tag("debug_log.txt", "ERROR", "localtime() failed"); + } else { + strftime(build_time_buff, 20, "%Y-%m-%d %H:%M:%S", build_time_tm); + wprintw(savepick_side_win, " \nDate: %s", build_time_buff); + } + } +#endif // INVIL__helapordo__HEADER__ +#else + wprintw(savepick_side_win, " \nBuilt without anvil"); +#endif // ANVIL__helapordo__ + //wprintw(savepick_side_win," \n %s",get_ANVIL__VERSION__DESC__()); + wrefresh(savepick_side_win); + refresh(); + + int savepick_picked = 0; + + /* + //We set the colors to use s4c's palette file... + FILE* palette_file; + char path_to_palette[600]; + char palette_name[50] = "palette.gpl"; + */ + int pickchar = -1; + + /* + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + sprintf(path_to_palette,"%s/%s",static_path,palette_name); + + palette_file = fopen(path_to_palette, "r"); + + init_s4c_color_pairs(palette_file); + */ + + for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { + init_s4c_color_pair(&palette[i], 9 + i); + } + log_tag("debug_log.txt","[DEBUG]","%s(): Updating gamescreen->colors and colorpairs after init_s4c_color_pair() loop.", __func__); + gamescreen->colors = COLORS; + gamescreen->color_pairs = COLOR_PAIRS; + + while (!savepick_picked + && (pickchar = wgetch(savepick_menu_win)) != KEY_F(1)) { + switch (pickchar) { + case KEY_DOWN: { + menu_driver(savepick_menu, REQ_DOWN_ITEM); + } + break; + case KEY_UP: { + menu_driver(savepick_menu, REQ_UP_ITEM); + } + break; + case KEY_LEFT: { /*Left option pick */ + ITEM *cur; + cur = current_item(savepick_menu); + savepick_choice = getTurnChoice((char *)item_name(cur)); + log_tag("debug_log.txt", "[DEBUG]", + "Left on choice: [ %s ] value (%i)", item_name(cur), + savepick_choice); + if (savepick_choice == NEW_GAME) { + log_tag("debug_log.txt", "[DEBUG]", + "Should do something"); + } + } + break; + case KEY_RIGHT: { /*Right option pick */ + ITEM *cur; + cur = current_item(savepick_menu); + savepick_choice = getTurnChoice((char *)item_name(cur)); + log_tag("debug_log.txt", "[DEBUG]", + "Right on choice: [ %s ] value (%i)", + item_name(cur), savepick_choice); + if (savepick_choice == NEW_GAME) { + log_tag("debug_log.txt", "[DEBUG]", + "Should do something"); + } + } + break; + case KEY_NPAGE: { + menu_driver(savepick_menu, REQ_SCR_DPAGE); + } + break; + case KEY_PPAGE: { + menu_driver(savepick_menu, REQ_SCR_UPAGE); + } + break; + case 10: { /* Enter */ + savepick_picked = 1; + ITEM *cur; + + //move(18,47); + //clrtoeol(); + cur = current_item(savepick_menu); + //mvprintw(18, 47, "Item selected is : %s", item_name(cur)); + savepick_choice = getTurnChoice((char *)item_name(cur)); + pos_menu_cursor(savepick_menu); + refresh(); + } + break; + case 'q': { + log_tag("debug_log.txt", "[DEBUG]", + "Player used q to quit from savepick menu."); + //TODO: take some variable to disable quick quitting with q + savepick_picked = 1; + savepick_choice = getTurnChoice("Quit"); + pos_menu_cursor(savepick_menu); + refresh(); + } + break; + default: { + break; + } + } + wrefresh(savepick_menu_win); + if (savepick_choice == NEW_GAME) { + int picked_saveslot_index = get_saveslot_index(); + log_tag("debug_log.txt", "[DEBUG]", + "Saveslot index picked: [%i]", picked_saveslot_index); + sprintf(current_save_path, "%s", default_saveslots[picked_saveslot_index].save_path); //Update saveslot_path value + //TODO + //Get picked_slot with a curses menu. + //int picked_slot = handle_pickSave(); + //sprintf(current_save_path,default_saveslots[picked_slot].save_path); + //TODO + //By default we expect the user to press new game, no action needed? + log_tag("debug_log.txt", "[DEBUG]", + "Running new game from savepick menu"); + turnOP(OP_NEW_GAME, savepick_turn_args, default_kls, + savepick_kls); + } else if (savepick_choice == LOAD_GAME) { + int picked_saveslot_index = get_saveslot_index(); + log_tag("debug_log.txt", "[DEBUG]", + "Saveslot index picked: [%i]", picked_saveslot_index); + sprintf(current_save_path, "%s", default_saveslots[picked_saveslot_index].save_path); //Update saveslot_path value + //TODO + //Get picked_slot with a curses menu. + //int picked_slot = handle_pickSave(); + //sprintf(current_save_path,default_saveslots[picked_slot].save_path); + //ATM we expect a single save. + //Setting this to 0 is the only thing we expect here, the actual load is done later. + load_info->is_new_game = 0; + log_tag("debug_log.txt", "[DEBUG]", + "Set load value: load_info->is_new_game == (%i)", + load_info->is_new_game); + turnOP(OP_LOAD_GAME, savepick_turn_args, default_kls, + savepick_kls); + //TODO + //Select which game to load, by preparing the necessary handles to code below (correct savefile/name, for now) + } else if (savepick_choice == QUIT) { + //TODO + //We can quit, I guess. + log_tag("debug_log.txt", "[DEBUG]", + "Savepick menu: doing exit(%i)", EXIT_SUCCESS); + // Unpost menu and free all the memory taken up + unpost_menu(savepick_menu); + free_menu(savepick_menu); + log_tag("debug_log.txt", "[FREE]", "Freed savepick menu"); + for (int k = 0; k < savepick_n_choices; k++) { + free_item(savepick_items[k]); + log_tag("debug_log.txt", "[FREE]", + "Freed %i savepick menu item", k); + } + + delwin(savepick_menu_win); + endwin(); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } else if (savepick_choice == TUTORIAL) { + log_tag("debug_log.txt", "[DEBUG]", "Doing tutorial."); + handleTutorial(); + exit(EXIT_SUCCESS); + } + } //End while !savepick_picked + + //Free turnOP_args + //free(savepick_turn_args); + + // Unpost menu and free all the memory taken up + unpost_menu(savepick_menu); + free_menu(savepick_menu); + log_tag("debug_log.txt", "[FREE]", "Freed savepick menu"); + for (int k = 0; k < savepick_n_choices; k++) { + free_item(savepick_items[k]); + log_tag("debug_log.txt", "[FREE]", "Freed %i savepick menu item", + k); + } + + delwin(savepick_menu_win); + endwin(); + log_tag("debug_log.txt", "[DEBUG]", + "Ended window mode for savepick menu"); + + kls_temp_end(savepick_kls); + + //Flush the terminal + int clrres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() system(\"clear\") after savepick res was (%i)", + clrres); + + //By now, we expect load_info->is_new_game to be set to 0 or 1. + log_tag("debug_log.txt", "[DEBUG]", + " Checking is_new_game: load_info->is_new_game == (%i)", + load_info->is_new_game); + + Koliseo_Temp *gamestate_kls = kls_temp_start(temporary_kls); + + if (load_info->is_new_game) { // We prepare path and fighter + path = randomise_path(rand(), default_kls, current_save_path); + path->loreCounter = -1; + + kls_log(default_kls, "DEBUG", "Prepping Fighter"); + player = + (Fighter *) KLS_PUSH_TYPED(default_kls, Fighter, HR_Fighter, + "Fighter", "Fighter"); + + int optTot = optind; + + getParams(argc, argv, player, path, optTot, default_kls); + initPlayerStats(player, path, default_kls); + } else { //Handle loading of gamestate + + //Declar turnOP_args + Room *fakeroom = NULL; + Enemy *fakeenemy = NULL; + Boss *fakeboss = NULL; + FILE *fakesavefile = NULL; + WINDOW *fakenotifywin = NULL; + Gamestate *fakegmst = NULL; + foeTurnOption_OP fake_foe_op = FOE_OP_INVALID; + skillType fake_skill = -1; + turnOP_args *loading_room_turn_args = + init_turnOP_args(fakegmst, player, path, fakeroom, load_info, + fakeenemy, fakeboss, fakesavefile, + fakenotifywin, gamestate_kls, fake_foe_op, + fake_skill); + FILE *save_file; + char path_to_savefile[1000]; + char static_path[500]; + char savefile_name[300]; + + //Copy current_save_path + sprintf(savefile_name, "%s", current_save_path); + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + sprintf(path_to_savefile, "%s/%s", static_path, savefile_name); + + save_file = fopen(path_to_savefile, "r"); + if (!save_file) { + //User error + fprintf(stderr, + "[ERROR] Can't open savefile for loading game.\n"); + fprintf(stderr, "[ERROR] Expected at path [%s].\n", + path_to_savefile); + //Debug error + log_tag("debug_log.txt", "[ERROR]", + "Could not load savefile at (%s)", path_to_savefile); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + //Update loading_room_turn_args->save_file pointer + loading_room_turn_args->save_file = save_file; + log_tag("debug_log.txt", "[TURNOP]", + "Assigned loading_room_turn_args->save_file: path [%s]", + path_to_savefile); + + //Read save type + // + saveType loaded_save_type = -1; + loaded_save_type = read_saveType(save_file); + log_tag("debug_log.txt", "[TURNOP]", "Read saveType, was [%s].", + stringFrom_saveType(loaded_save_type)); + + if (loaded_save_type == -1) { + log_tag("debug_log.txt", "[ERROR]", + "Failed setting loaded_save_type. Quitting."); + fprintf(stderr, "[ERROR] Failed setting a save type."); + + exit(EXIT_FAILURE); + } + + load_info->save_type = loaded_save_type; + + log_tag("debug_log.txt", "[TURNOP]", + "Assigned load_info->save_type: [%s]", + stringFrom_saveType(load_info->save_type)); + + path = randomise_path(rand(), default_kls, current_save_path); + kls_log(default_kls, "DEBUG", "Prepping Loady Fighter"); + player = + (Fighter *) KLS_PUSH_TYPED(default_kls, Fighter, HR_Fighter, + "Fighter", "Loady Fighter"); + player->class = Knight; + + strcpy(player->name, "Loady"); + + //Update loading_room_turn_args->actor pointer + loading_room_turn_args->actor = player; + log_tag("debug_log.txt", "[TURNOP]", + "Assigned Fighter [%s]. loading_room_turn_args->actor->name: [%s]", + player->name, loading_room_turn_args->actor->name); + + kls_log(default_kls, "DEBUG", "Prepping Loady Wincon"); + Wincon *w = + (Wincon *) KLS_PUSH_TYPED(default_kls, Wincon, HR_Wincon, + "Wincon", "Loady Wincon"); + w->class = FULL_PATH; + initWincon(w, path, w->class); + initPlayerStats(player, path, default_kls); + path->win_condition = w; + + if (load_info->save_type == ENEMIES_SAVE) { + + kls_log(default_kls, "DEBUG", "Prepping Loady Enemy"); + load_info->loaded_enemy = + (Enemy *) KLS_PUSH_TYPED(default_kls, Enemy, HR_Enemy, + "Enemy", "Loaded Enemy"); + //FIXME: the structs related to loaded enemy are not loaded on default_kls + prepareRoomEnemy(load_info->loaded_enemy, 1, 3, 1, + gamestate_kls); + + //Update loading_room_turn_args->enemy pointer + loading_room_turn_args->enemy = load_info->loaded_enemy; + log_tag("debug_log.txt", "[TURNOP]", + "Assigned load_info->loaded_enemy->class == [%s]. loading_room_turn_args->loaded_enemy->class == [%s]", + stringFromEClass(load_info->loaded_enemy->class), + stringFromEClass(loading_room_turn_args->enemy->class)); + } + //Update loading_room_turn_args->path pointer + loading_room_turn_args->path = path; + log_tag("debug_log.txt", "[TURNOP]", + "Assigned loading_room_turn_args->path == [path] (len %i)", + path->length); + + switch (load_info->save_type) { + case ENEMIES_SAVE: { + log_tag("debug_log.txt", "[TURNOP]", + "Doing OP_LOAD_ENEMYROOM."); + //int* loadinfo_totfoes = &(load_info->total_foes); + //FIXME: the structs related to loaded enemy are not loaded on default_kls + OP_res load_op_result = + turnOP(OP_LOAD_ENEMYROOM, loading_room_turn_args, + default_kls, gamestate_kls); + log_tag("debug_log.txt", "[TURNOP]", + "OP_LOAD_ENEMYROOM: result was [%s].", + stringFrom_OP_res(load_op_result)); + log_tag("debug_log.txt", "[FREE]", + "Freed loading_room_turn_args. Load result was [%s].", + stringFrom_OP_res(load_op_result)); + //free(loading_room_turn_args); + } + break; + case HOME_SAVE: { + log_tag("debug_log.txt", "[TURNOP]", + "Doing OP_LOAD_HOMEROOM."); + //int* loadinfo_totfoes = &(load_info->total_foes); + //FIXME: the structs related to loaded enemy are not loaded on default_kls + OP_res load_op_result = + turnOP(OP_LOAD_HOMEROOM, loading_room_turn_args, + default_kls, gamestate_kls); + log_tag("debug_log.txt", "[TURNOP]", + "OP_LOAD_HOMEROOM: result was [%s].", + stringFrom_OP_res(load_op_result)); + //log_tag("debug_log.txt","[FREE]","Freed loading_room_turn_args. Load result was [%s].",stringFrom_OP_res(load_op_result)); + load_info->done_loading = 1; + log_tag("debug_log.txt", "[PREP]", + "Set load_info->done_loading to 1."); + //free(loading_room_turn_args); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "gameloop(): Unexpected save type, value was (%i).", + (int)load_info->save_type); + exit(EXIT_FAILURE); + } + break; + } + + //e_death(loaded_enemy); + //death(player); + //exit(0); + } + + /* + * TODO + * Remove me + * Legacy code to load lores from a text file. + for (int i=0; i<5; i++) { + sprintf(msg,"Prepping lore (%i)",i); + kls_log("DEBUG",msg); + lore_strings[i] = (char*) KLS_PUSH_NAMED(default_kls, char, 300, "Lore", msg); + } + */ + + int *loreCounter = &(path->loreCounter); + log_tag("debug_log.txt", "[DEBUG]", "loreCounter == (%i)", + *loreCounter); + + if (GAMEMODE == Story) { + + /* + * TODO + * Remove me + * Legacy code to load lores from a text file. + int loreKind = 0; //rand() % LORES_MAX; + */ + + if (load_info->is_new_game) { + log_tag("debug_log.txt", "[FIXME]", + "loreCounter was (%i), setting it to 0.", *loreCounter); + *loreCounter = 0; //We must set the counter before going forward + //FIXME: + //loreCounter should not start from 0 again. + } + + /* + * TODO + *Remove me + *Legacy code for loading lores from a text file. + loadLore(lore_strings,loreKind); + */ + + } else { + log_tag("debug_log.txt", "[WARN]", + "GAMEMODE is not Story. Value was: (%i)", GAMEMODE); + } + + //Set consumables sprites + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + setConsumableSprite((Consumable *) player->consumablesBag[i]); + log_tag("debug_log.txt", "[PREP]", "Set sprite for %s", + stringFromConsumables(i)); + } + log_tag("debug_log.txt", "[DEBUG-PREP]", + "Done setting sprites for Consumables."); + //Set artifact sprites + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + setArtifactSprite(player->artifactsBag[i]); + log_tag("debug_log.txt", "[PREP]", "Set sprite for %s", + stringFromArtifacts(i)); + } + log_tag("debug_log.txt", "[PREP]", + "Done setting sprites for Artifacts."); + //Set base equips sprites... + for (int i = 0; i < EQUIPSMAX + 1; i++) { + setEquipSprite(&equips[i]); + log_tag("debug_log.txt", "[PREP]", "Set sprite for %s", + stringFromEquips(i)); + } + log_tag("debug_log.txt", "[PREP]", "Done setting sprites for Equips."); + + if (load_info->is_new_game) { + log_tag("debug_log.txt", "[PREP]", "New game from scratch."); + } else { + log_tag("debug_log.txt", "[PREP]", "New game from loading."); + } + log_tag("debug_log.txt", "[DEBUG]", "Name: %s", player->name); + log_tag("debug_log.txt", "[DEBUG]", "Class: %s", + stringFromClass(player->class)); + log_tag("debug_log.txt", "[DEBUG]", "Gamemode: %s", + stringFromGamemode(GAMEMODE)); + + //purple(); + //printStats(player); + //white(); + + int roomsDone = load_info->is_new_game ? 1 : loaded_roomindex; + OP_res res = OP_RES_NO_DMG; + int roadFork_value = -1; //0 may be used as a value, so + + Wincon *win_con = path->win_condition; + log_tag("debug_log.txt", "[DEBUG]", "Wincon: %s\n", + stringFromWinconClass(win_con->class)); + + //int refresh_artifact_wincon = 0; + if (load_info->save_type == ENEMIES_SAVE) { + load_info->done_loading = 0; + log_tag("debug_log.txt", "[DEBUG-PREP]", + "Set load_info->done_loading to 0."); + } + log_tag("debug_log.txt", "[DEBUG-PREP]", "Prepping done.\n"); + log_tag("debug_log.txt", "[DEBUG]", "Starting wincon loop.\n"); + + diff_time = clock() - start_time; + int time_spent = diff_time * 1000 / CLOCKS_PER_SEC; + //sprintf(msg,"[DEBUG] Prep took %0.7f seconds.\n",time_spent); + log_tag("debug_log.txt", "[DEBUG]", "Prep took %d s, %d ms.", + time_spent / 1000, time_spent % 1000); + + Gamestate *gamestate = + KLS_PUSH_TYPED(default_kls, Gamestate, HR_Gamestate, "Gamestate", + "Gamestate"); + init_Gamestate(gamestate, start_time, player->stats, path->win_condition, path, + player, GAMEMODE, gamescreen, is_localexe); + if (gamestate->gamemode == Rogue) { + //Note: different lifetime than gamestate + //NO. The update_gamestate call is instead performed later. + //Floor* current_floor = KLS_PUSH_T_TYPED(gamestate_kls,Floor,1,HR_Floor,"Floor","Init Curr floor"); + //NO. We pass NULL now. + update_Gamestate(gamestate, 1, HOME, roomsDone, -1, NULL); + } else { + update_Gamestate(gamestate, 1, HOME, roomsDone, -1, NULL); + } + log_tag("debug_log.txt", "[DEBUG]", "Initialised Gamestate."); + dbg_Gamestate(gamestate); + + if (GAMEMODE == Story || GAMEMODE == Standard) { + + //Loop till wincon reached + + while (win_con->current_val < win_con->target_val) { + + //Flush the terminal + int loop_clrres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() system(\"clear\") in wincon loop, res: (%i)", + loop_clrres); + + //Check if we have to update the wincon value + if (path->win_condition->class == ALL_ARTIFACTS) { + path->win_condition->current_val = + player->stats->artifactsfound; + //Are we forced to do one more room? + } + + int enemyTotal = -1; + roomClass room_type = -1; + + if (!(load_info->is_new_game) && !(load_info->done_loading) + && (load_info->save_type == ENEMIES_SAVE)) { + enemyTotal = loaded_roomtotalenemies; + } + + kls_log(temporary_kls, "DEBUG", + "Prepping Room for Story Gamemode. roomsDone=(%i)", + roomsDone); + Room *current_room = + (Room *) KLS_PUSH_T_TYPED(gamestate_kls, Room, HR_Room, + "Room", "Story Room"); + + current_room->index = roomsDone; + setRoomType(path, &roadFork_value, &room_type, roomsDone); + log_tag("debug_log.txt", "[ROOM]", + "Set Room #%i type: (%s)\n", roomsDone, + stringFromRoom(room_type)); + + initRoom(current_room, player, roomsDone, room_type, enemyTotal, + load_info, gamestate_kls); + log_tag("debug_log.txt", "[ROOM]", "Init Room #%i: (%s)\n", + roomsDone, stringFromRoom(room_type)); + + start_color(); + int colorCheck = has_colors(); + + if (colorCheck == FALSE) { + fprintf(stderr, "Terminal can't use colors, abort.\n"); + exit(S4C_ERR_TERMCOLOR); + } + + colorCheck = can_change_color(); + + if (colorCheck == FALSE) { + fprintf(stderr, "Terminal can't change colors, abort.\n"); + exit(S4C_ERR_TERMCHANGECOLOR); + } + for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { + init_s4c_color_pair(&palette[i], 9 + i); + } + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + //Check if we need to display a story prompt + if (GAMEMODE == Story && (roomsDone == 1 || room_type == BOSS)) { + displayLore(lore_strings, *loreCounter); + (*loreCounter)++; + } + //Play room animation + + /* + FILE* palette_file; + char path_to_palette[600]; + char static_path[500]; + char palette_name[50] = "palette.gpl" ; + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + sprintf(path_to_palette,"%s/%s",static_path,palette_name); + + palette_file = fopen(path_to_palette, "r"); + if (palette_file == NULL) { + fprintf(stderr, "Error: could not open palette file (%s/%s).\n",static_path, palette_name); + exit(EXIT_FAILURE); + } + */ + + WINDOW *door_win; + //initscr(); + clear(); + refresh(); + + int reps = 1; + int frametime = 27; + int num_frames = 60; + int frame_height = 22; + int frame_width = 22; + door_win = newwin(frame_height + 1, frame_width + 1, 0, 25); + + char door_sprites[MAXFRAMES][MAXROWS][MAXCOLS]; + + s4c_copy_animation(enter_door, door_sprites, num_frames, + frame_height, frame_width); + + log_tag("debug_log.txt", "[PREP]", + "Copied animation from matrix vector for enter_door with dimensions: [%i][%i][%i].", + num_frames, frame_height, frame_width); + + /* + * TODO + * Remove me + * Legacy code for loading animation from an s4c-file. + * + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + char door_file_path[600]; + + sprintf(door_file_path,"%s/animations/enter_door.txt",static_path); + + FILE* door_file = fopen(door_file_path,"r"); + if (!door_file) { + fprintf(stderr,"[ERROR] Can't open enter_door file.\n"); + exit(EXIT_FAILURE); + } + int loadCheck = load_sprites(door_sprites, door_file, frame_height-1, frame_width-1); + + // Check for possible loadCheck() errors and in this case we return early if we couldn't load + if (loadCheck < 0) { + endwin(); + switch (loadCheck) { + case S4C_ERR_FILEVERSION: { + fprintf(stderr,"S4C_ERR_FILEVERSION : Failed file version check.\n"); + } + break; + case S4C_ERR_LOADSPRITES: { + fprintf(stderr,"S4C_ERR_LOADSPRITES : Failed loading the sprites.\n"); + } + break; + } + exit(loadCheck); + } + */ + + // We make sure we have the background correcly set up and expect animate_sprites to refresh it + wclear(door_win); + wrefresh(door_win); + + int result = + s4c_animate_sprites_at_coords(door_sprites, door_win, reps, + frametime, num_frames, + frame_height, frame_width, 0, + 0); + log_tag("debug_log.txt", "[DEBUG]", "animate() result was (%i)", + result); + wclear(door_win); + wrefresh(door_win); + delwin(door_win); + endwin(); + + update_Gamestate(gamestate, 1, current_room->class, roomsDone, + -1, NULL); + + if (current_room->class == HOME) { + res = + handleRoom_Home(gamestate, current_room, roomsDone, + path, player, load_info, + fighter_sprites, default_kls, + gamestate_kls); + } else if (current_room->class == ENEMIES) { + res = + handleRoom_Enemies(gamestate, current_room, roomsDone, + path, player, load_info, + enemy_sprites, fighter_sprites, + default_kls, gamestate_kls); + } else if (current_room->class == SHOP) { + //FIXME: does shop require usage of gameloop kls? + res = + handleRoom_Shop(current_room, roomsDone, path, player, + default_kls, gamestate_kls); + } else if (current_room->class == BOSS) { + res = + handleRoom_Boss(gamestate, current_room, roomsDone, + path, player, load_info, boss_sprites, + fighter_sprites, default_kls, + gamestate_kls); + } else if (current_room->class == TREASURE) { + res = + handleRoom_Treasure(current_room, roomsDone, path, + player, default_kls, gamestate_kls); + } else if (current_room->class == ROADFORK) { + res = + handleRoom_Roadfork(current_room, &roadFork_value, + roomsDone, path, player); + } else { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected current_room->class value: [%i] [%s]", + current_room->class, + stringFromRoom(current_room->class)); + //freeRoom(current_room); + log_tag("debug_log.txt", "[ERROR]", + "Freed current room, quitting program."); + exit(EXIT_FAILURE); + } + + if (res == OP_RES_DEATH) { + log_tag("debug_log.txt", "[DEBUG]", + "Room resulted in DEATH.\n"); + //Free room memory + //freeRoom(current_room); + break; + } else { + //Flush the terminal + int clrres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() system(\"clear\") res was (%i)", + clrres); + + if (roadFork_value > 0) { + //TODO + //What is this? + lightYellow(); + printStats(player); + lightGreen(); + log_tag("debug_log.txt", "[ROADFORK?]", + "You completed room %i.", roomsDone); + white(); + } + roomsDone++; + + //Update stats + player->stats->roomscompleted++; + + //Check if we need to update the win condition + if (win_con->class == FULL_PATH) { + win_con->current_val++; + } + //Free room memory + //freeRoom(current_room); + // Reset gamestate_kls + kls_temp_end(gamestate_kls); + gamestate_kls = kls_temp_start(temporary_kls); + } + } // Win condition loop + + // Clear default_kls + //kls_clear(default_kls); + + //Got out of the loop with res not being DEATH; so i won + if (res != OP_RES_DEATH) { //I guess player and enemy were freed already? + int clrres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() 2 system(\"clear\") res was (%i)", clrres); + handleStats(player); + printf("\n\n\tYOU WON!\n\n"); + log_tag("debug_log.txt", "[DEBUG]", "Game won."); + //Free default kls + kls_log(default_kls, "DEBUG", "Freeing default KLS"); + kls_free(default_kls); + log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed default KLS"); + + //Free temporary kls + kls_log(temporary_kls, "DEBUG", "Freeing temporary KLS"); + kls_free(temporary_kls); + log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed temporary KLS"); + } + + /* + //Free lore strings if they were loaded + if (GAMEMODE == Story) { + for (int i=0; i<5; i++) { + char msg[1000]; + sprintf(msg,"Freed lore string %i",i); + log_tag("debug_log.txt","[FREE]",msg); + sprintf(msg,"%s",lore_strings[i]); + log_tag("debug_log.txt","[FREE]",msg); + free(lore_strings[i]); + } + } + */ + //free(path->win_condition); + //free(path); + log_tag("debug_log.txt", "[DEBUG]", "End of wincon loop.\n"); + + } else { //Gamemode is not Story or Standard + log_tag("debug_log.txt", "[DEBUG]", "Gamemode was [%i]", GAMEMODE); + + if (GAMEMODE == Rogue) { + log_tag("debug_log.txt", "[DEBUG]", "Doing a Rogue run."); + char static_path[500]; + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + /** + * Legacy code for reading palette.gpl. Was it ever needed at runtime? + * TODO check which tags may use the palette.gpl at runtime (other than trying to read it pointlessly). + * + char path_to_palette[600]; + FILE* palette_file = NULL; + char palette_name[50] = "palette.gpl"; + sprintf(path_to_palette, "%s/%s", static_path, palette_name); + palette_file = fopen(path_to_palette, "r"); + if (palette_file == NULL) { + fprintf(stderr, + "Error: could not open palette file (%s/%s).\n", + static_path, palette_name); + exit(EXIT_FAILURE); + } + */ + + WINDOW *floor_win; + //TODO: store if we have done initsrc() or endwin(). Am sure we can get this from ncurses with some MACRO + //initscr(); + clear(); + refresh(); + start_color(); + + int colorCheck = has_colors(); + + if (colorCheck == FALSE) { + fprintf(stderr, "Terminal can't use colors, abort.\n"); + exit(S4C_ERR_TERMCOLOR); + } + + colorCheck = can_change_color(); + + if (colorCheck == FALSE) { + fprintf(stderr, "Terminal can't change colors, abort.\n"); + exit(S4C_ERR_TERMCHANGECOLOR); + } + for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { + init_s4c_color_pair(&palette[i], 9 + i); + } + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + // Create the window + floor_win = newwin(23, 24, 1, 2); + wclear(floor_win); + wrefresh(floor_win); + keypad(floor_win, TRUE); + + /* Print a border around the windows and print a title */ + box(floor_win, 0, 0); + wrefresh(floor_win); + refresh(); + int res = -1; + char msg[500]; + + log_tag("debug_log.txt", "[DEBUG]", "Prepping current_floor."); + kls_log(default_kls, "DEBUG", "Prepping current_floor."); + Floor *current_floor = + (Floor *) KLS_PUSH_T_TYPED(gamestate_kls, Floor, + HR_Floor, "Floor", "Floor"); + update_Gamestate(gamestate, 1, HOME, roomsDone, -1, + current_floor); + // Start the random walk from the center of the dungeon + int center_x = FLOOR_MAX_COLS / 2; + int center_y = FLOOR_MAX_ROWS / 2; + + // Init dbg_floor + init_floor_layout(current_floor); + + //Set center as filled + current_floor->floor_layout[center_x][center_y] = 1; + + //Init floor rooms + init_floor_rooms(current_floor); + + //Random walk #1 + floor_random_walk(current_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reset floor_layout if needed. + //Random walk #2 + floor_random_walk(current_floor, center_x, center_y, 100, 0); // Perform 100 more steps of random walk, DON'T reset floor_layout if needed. + + //Set floor explored matrix + load_floor_explored(current_floor); + + //Set room types + floor_set_room_types(current_floor); + + int current_x = center_x; + int current_y = center_y; + + //TODO: handle finishing all floors + path->length = MAX_ROGUE_FLOORS; + + int floors_done = 0; + + //Loop till wincon reached + + //while (dbg_floor->explored_area*1.0 < (dbg_floor->area*0.8)) { + while (win_con->current_val < win_con->target_val) { + + //Check if we have to update the wincon value + if (path->win_condition->class == ALL_ARTIFACTS) { + path->win_condition->current_val = + player->stats->artifactsfound; + //Are we forced to do one more room? + } + + int enemyTotal = -1; + roomClass room_type = -1; + + if (!(load_info->is_new_game) && !(load_info->done_loading) + && (load_info->save_type == ENEMIES_SAVE)) { + enemyTotal = loaded_roomtotalenemies; + } + + Room *current_room = NULL; + + //Check if current room needs to be played + if (current_floor->roomclass_layout[current_x][current_y] != + BASIC) { + kls_log(temporary_kls, "DEBUG", + "Prepping Room for Rogue Gamemode. roomsDone=(%i)", + roomsDone); + current_room = + (Room *) KLS_PUSH_T_TYPED(gamestate_kls, Room, + HR_Room, "Room", msg); + + current_room->index = roomsDone; + //setRoomType(path, &roadFork_value, &room_type, roomsDone); + + room_type = + current_floor-> + roomclass_layout[current_x][current_y]; + log_tag("debug_log.txt", "[ROOM]", + "Set Room #%i type: (%s)\n", roomsDone, + stringFromRoom(room_type)); + + initRoom(current_room, player, roomsDone, room_type, + enemyTotal, load_info, gamestate_kls); + log_tag("debug_log.txt", "[ROOM]", + "Init Room #%i: (%s)\n", roomsDone, + stringFromRoom(room_type)); + + /* + //Check if we need to display a story prompt + if (GAMEMODE == Story && (roomsDone == 1 || room_type == BOSS)) { + displayLore(lore_strings,*loreCounter); + (*loreCounter)++; + } + */ + + //Play room animation + + WINDOW *door_win; + //initscr(); + clear(); + refresh(); + start_color(); + + int reps = 1; + int frametime = 27; + int num_frames = 60; + int frame_height = 22; + int frame_width = 22; + door_win = + newwin(frame_height + 1, frame_width + 1, 0, 25); + + char door_sprites[MAXFRAMES][MAXROWS][MAXCOLS]; + + s4c_copy_animation(enter_door, door_sprites, num_frames, + frame_height, frame_width); + + log_tag("debug_log.txt", "[PREP]", + "Copied animation from matrix vector for enter_door with dimensions: [%i][%i][%i].", + num_frames, frame_height, frame_width); + + /* + * TODO + * Remove me + * Legacy code for loading animation from an s4c-file. + * + // Set static_path value to the correct static dir path + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + char door_file_path[600]; + + sprintf(door_file_path,"%s/animations/enter_door.txt",static_path); + + FILE* door_file = fopen(door_file_path,"r"); + if (!door_file) { + fprintf(stderr,"[ERROR] Can't open enter_door file.\n"); + exit(EXIT_FAILURE); + } + int loadCheck = load_sprites(door_sprites, door_file, frame_height-1, frame_width-1); + + // Check for possible loadCheck() errors and in this case we return early if we couldn't load + if (loadCheck < 0) { + endwin(); + switch (loadCheck) { + case S4C_ERR_FILEVERSION: { + fprintf(stderr,"S4C_ERR_FILEVERSION : Failed file version check.\n"); + } + break; + case S4C_ERR_LOADSPRITES: { + fprintf(stderr,"S4C_ERR_LOADSPRITES : Failed loading the sprites.\n"); + } + break; + } + exit(loadCheck); + } + */ + + // We make sure we have the background correcly set up and expect animate_sprites to refresh it + wclear(door_win); + wrefresh(door_win); + + int result = + s4c_animate_sprites_at_coords(door_sprites, + door_win, reps, + frametime, num_frames, + frame_height, + frame_width, 0, 0); + log_tag("debug_log.txt", "[DEBUG]", + "animate() result was (%i)", result); + wclear(door_win); + wrefresh(door_win); + delwin(door_win); + endwin(); + + update_Gamestate(gamestate, 1, current_room->class, + current_room->index, -1, + current_floor); + + if (current_room->class == HOME) { + res = + handleRoom_Home(gamestate, current_room, + roomsDone, path, player, + load_info, fighter_sprites, + default_kls, gamestate_kls); + } else if (current_room->class == ENEMIES) { + res = + handleRoom_Enemies(gamestate, current_room, + roomsDone, path, player, + load_info, enemy_sprites, + fighter_sprites, default_kls, + gamestate_kls); + } else if (current_room->class == SHOP) { + res = + handleRoom_Shop(current_room, roomsDone, path, + player, default_kls, + gamestate_kls); + } else if (current_room->class == BOSS) { + res = + handleRoom_Boss(gamestate, current_room, + roomsDone, path, player, + load_info, boss_sprites, + fighter_sprites, default_kls, + gamestate_kls); + } else if (current_room->class == TREASURE) { + res = + handleRoom_Treasure(current_room, roomsDone, + path, player, default_kls, + gamestate_kls); + } else if (current_room->class == ROADFORK) { + res = + handleRoom_Roadfork(current_room, + &roadFork_value, roomsDone, + path, player); + } else { + sprintf(msg, + "Unexpected current_room->class value: [%i] [%s]", + current_room->class, + stringFromRoom(current_room->class)); + log_tag("debug_log.txt", "[ERROR]", msg); + //freeRoom(current_room); + log_tag("debug_log.txt", "[ERROR]", + "Freed current room, quitting program."); + exit(EXIT_FAILURE); + } + + if (res == OP_RES_DEATH) { + log_tag("debug_log.txt", "[DEBUG]", + "Room resulted in DEATH."); + //Free room memory + //freeRoom(current_room); + break; + } else { + //Flush the terminal + int clrres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() system(\"clear\") res was (%i)", + clrres); + + if (roadFork_value > 0) { + //lightYellow(); + //TODO + //What is this? + printStats(player); + //lightGreen(); + log_tag("debug_logx.txt", "[ROADFORK?]", + "You completed room %i.", roomsDone); + //white(); + } + roomsDone++; + + //Update stats + player->stats->roomscompleted++; + + //Free room memory + //freeRoom(current_room); + + //Update floor's roomclass layout for finished rooms which should not be replayed + switch (current_floor-> + roomclass_layout[current_x][current_y]) { + case ENEMIES: { + current_floor-> + roomclass_layout[current_x][current_y] = + BASIC; + } + break; + case BOSS: { + current_floor-> + roomclass_layout[current_x][current_y] = + BASIC; + floors_done++; + player->stats->floorscompleted++; + log_tag("debug_log.txt", "[DEBUG]", + "Floors done: [%i]", floors_done); + //Check if we need to update the win condition + if (win_con->class == FULL_PATH) { + win_con->current_val++; + } + // Reset gamestate_kls + kls_temp_end(gamestate_kls); + gamestate_kls = + kls_temp_start(temporary_kls); + + current_floor = + (Floor *) + KLS_PUSH_T_TYPED(gamestate_kls, Floor, + HR_Floor, "Floor", + "Floor"); + update_Gamestate(gamestate, 1, HOME, + roomsDone, -1, + current_floor); + + //Regenerate floor + log_tag("debug_log.txt", "[DEBUG]", + "Beaten a boss, regenerating current floor."); + // Init + init_floor_layout(current_floor); + //Set center as filled + current_floor-> + floor_layout[center_x][center_y] = 1; + //Init floor rooms + init_floor_rooms(current_floor); + //Random walk #1 + floor_random_walk(current_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reset floor_layout if needed. + //Random walk #2 + floor_random_walk(current_floor, center_x, center_y, 100, 0); // Perform 100 more steps of random walk, DON'T reset floor_layout if needed. + //Set floor explored matrix + load_floor_explored(current_floor); + //Set room types + floor_set_room_types(current_floor); + + //Center current coords + current_x = center_x; + current_y = center_y; + continue; //Check win condition for loop + + } + break; + case SHOP: { + current_floor-> + roomclass_layout[current_x][current_y] = + BASIC; + } + break; + case TREASURE: { + current_floor-> + roomclass_layout[current_x][current_y] = + BASIC; + } + break; + case HOME: { + //We leave it available + log_tag("debug_log.txt", "[DEBUG]", + "Skipping reset of roomclass for HOME room"); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected roomclass value in Rogue loop: [%i] [%s]", + current_floor-> + roomclass_layout[current_x] + [current_y], + stringFromRoom(current_floor-> + roomclass_layout + [current_x] + [current_y])); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } + } + } else { + log_tag("debug_log.txt", "[DEBUG]", + "Current room class was [%s] (val: %i), not playable.", + stringFromRoom(current_floor-> + roomclass_layout[current_x] + [current_y]), + current_floor-> + roomclass_layout[current_x][current_y]); + } + + //Draw current FOV + draw_floor_view(current_floor, current_x, current_y, + floor_win); + //Take a step and update screen + move_update(gamestate, current_floor, ¤t_x, + ¤t_y, floor_win, path, player, + current_room, load_info, default_kls, + gamestate_kls); + } // Win condition loop + + //FIXME: do we need this? + //kls_temp_end(gamestate_kls); + // Clear default_kls + //kls_clear(default_kls); + + //Got out of the loop with res not being DEATH; so i won + if (res != OP_RES_DEATH) { //I guess player and enemy were freed already? + int clrres = system("clear"); + //TODO + //What is this? + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() 2 system(\"clear\") res was (%i)", + clrres); + handleStats(player); + printf("\n\n\tYOU WON!\n\n"); + log_tag("debug_log.txt", "[DEBUG]", "Game won."); + //Free default kls + kls_log(default_kls, "DEBUG", "Freeing default KLS"); + kls_free(default_kls); + log_tag("debug_log.txt", "[DEBUG-KLS]", + "Freed default KLS"); + + //Free temporary kls + kls_log(temporary_kls, "DEBUG", "Freeing temporary KLS"); + kls_free(temporary_kls); + log_tag("debug_log.txt", "[DEBUG-KLS]", + "Freed temporary KLS"); + } else { + //TODO + //What is this? + int clrres = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "gameloop() 3 system(\"clear\") res was (%i)", + clrres); + printf("\n\n\tYOU DIED.\n\n"); + log_tag("debug_log.txt", "[DEBUG]", "Game lost."); + } + + /* + //Free lore strings if they were loaded + if (GAMEMODE == Story) { + for (int i=0; i<5; i++) { + char msg[1000]; + sprintf(msg,"Freed lore string %i",i); + log_tag("debug_log.txt","[FREE]",msg); + sprintf(msg,"%s",lore_strings[i]); + log_tag("debug_log.txt","[FREE]",msg); + //free(lore_strings[i]); + } + } + */ + + //free(path->win_condition); + //free(path); + log_tag("debug_log.txt", "[DEBUG]", "End of wincon loop."); + + //free(current_floor); + + endwin(); + } else { + log_tag("debug_log.txt", "[ERROR]", "Error in gameloop()."); + exit(EXIT_FAILURE); + } + } + //kls_temp_end(gamestate_kls); + } while (retry()); + + //TODO + //What is this? + purple(); + printf("\n\n\t\tTHANKS 4 PLAYING!\n\n"); + white(); + log_tag("debug_log.txt", "[DEBUG]", "End of program."); + exit(EXIT_SUCCESS); +} diff --git a/src/build-nc/helapordo.h b/src/build-nc/helapordo.h new file mode 100644 index 00000000..ab82b7a9 --- /dev/null +++ b/src/build-nc/helapordo.h @@ -0,0 +1,51 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 . +*/ + +/*! \mainpage Helapordo index page + * + * \section intro_sec Intro + * + * Helapordo is roguelike terminal game, using ncurses. + * + * SPDX-License-Identifier: GPL-3.0-only + * + * Check it out on [github](https://github.com/jgabaut/helapordo). + */ + +#ifndef HELAPORDO_H +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) //We need C11 +#define HELAPORDO_H + +#ifndef _WIN32 +#define _POSIX_C_SOURCE 200809L +#endif // _WIN32 + +#include "../utils/rooms.h" +#include "../anvil__helapordo.h" +#include "../core/game_lore.h" + +/* +void register_counter_callback(int index, callback_void_t ptr, Fighter*); +*/ + +void gameloop(int argc, char **argv); + +#else +#error "This code requires C11.\n _Alignof\n" +#endif +#endif //HELAPORDO_H diff --git a/src/build-rl/game_rl.c b/src/build-rl/game_rl.c new file mode 100644 index 00000000..18708a07 --- /dev/null +++ b/src/build-rl/game_rl.c @@ -0,0 +1,236 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "game_rl.h" + +callback_void_t callback_func_ptrs[SPECIALSMAX]; +callback_void_t callback_artifact_ptrs[ARTIFACTSMAX]; +callback_void_t callback_counter_ptrs[COUNTERSMAX]; + +/** + * Shows tutorial info. + * @see gameloop_rl() + */ +void handleTutorial(S4C_Color* palette) +{ + Rectangle rc = {0}; + + //If we get to this function straight from getopts, we need to do raylib init + + /* Initialize raylib */ + if (G_DOTUTORIAL_ON == 1) { + //TODO: prepare windowed mode + //framesCounter++; // Count frames + BeginDrawing(); + ClearBackground(ColorFromS4CPalette(palette,S4C_GREY)); + } + rc = CLITERAL(Rectangle) { + 1, 2, 20, 70 + }; + + int fontSize = 20; + const char* label = "Tutorial";; + DrawText(label, rc.x, rc.y, fontSize, ColorFromS4CPalette(palette,S4C_CYAN)); + + Color tut_color = ColorFromS4CPalette(palette, S4C_LIGHT_YELLOW); + DrawText("You can use the arrow keys and Enter to do everything needed for the game.", 14, 3*fontSize, fontSize, tut_color); + DrawText("Buying things from a Shop may be tricky: you have to select one, then choose Buy.\nTo select one, First go up/down to 'View Item', then press Enter,\nthen you can scroll them with left/right. Press Enter to confirm your selection,\nthen go back up to Buy.", 14, 6*fontSize, fontSize, tut_color); + DrawText("When running in Rogue mode, you can change floors by killing a Boss.", 14, 12*fontSize, fontSize, tut_color); + DrawText("When in floor map, you can open the menu with the \"m\" key.", 14, 15*fontSize, fontSize, tut_color); + DrawText("Rememeber, you can't really save in Rogue mode ! Run with \"-s\" to try Story mode.", 14, 18*fontSize, fontSize, tut_color); + + DrawText("[ Press ENTER or TAP to quit ]", 14, 21*fontSize, fontSize, ColorFromS4CPalette(palette,S4C_RED)); + + if (G_DOTUTORIAL_ON == 1) { + EndDrawing(); + //TODO: update win??? + } +} + +/** + * Takes a Enemy pointer and prepares its sprite field by copying it line by line from enemies_sprites, defined in sprites.h header. + * @see Enemy + * @see initEnemyStats + * @see enemies_sprites + * @param e The Enemy pointer whose sprite field will be initialised. + */ +void setEnemySprite(Enemy *e) +{ + if (e->class < ENEMYCLASSESMAX + 1) { + for (int i = 0; i < 8; i++) { + strcpy(e->sprite[i], enemies_sprites[e->class][i]); + } + } else { + fprintf(stderr, + "[ERROR] Unexpected enemyClass in setEnemySprite().\n"); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a Equip pointer and prepares its sprite field by copying it line by line from equips_sprites, defined in sprites.h header. + * @see Equip + * @see dropEquip + * @see equips_sprites + * @param e The Equip pointer whose sprite field will be initialised. + */ +void setEquipSprite(Equip *e) +{ + if (e->class < EQUIPSMAX + 1) { + for (int i = 0; i < 8; i++) { + strcpy(e->sprite[i], equips_sprites[e->class][i]); + } + } else { + fprintf(stderr, + "[ERROR] Unexpected equipClass in setEquipSprite().\n"); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a Consumable pointer and prepares its sprite field by copying it line by line from consumables_sprites, defined in sprites.h header. + * @see Consumable + * @see initPlayerStats + * @see consumables_sprites + * @param c The Consumable pointer whose sprite field will be initialised. + */ +void setConsumableSprite(Consumable *c) +{ + if (c->class < CONSUMABLESMAX + 1) { + for (int i = 0; i < 8; i++) { + strcpy(c->sprite[i], consumables_sprites[c->class][i]); + } + } else { + fprintf(stderr, + "[ERROR] Unexpected consumableClass in setConsumableSprite().\n"); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a Boss pointer and prepares its sprite field by copying it line by line from bosses_sprites, defined in sprites.h header. + * @see Boss + * @see initBossStats + * @see bosses_sprites + * @param b The Boss pointer whose sprite field will be initialised. + */ +void setBossSprite(Boss *b) +{ + if (b->class < BOSSCLASSESMAX + 1) { + for (int i = 0; i < 8; i++) { + strcpy(b->sprite[i], bosses_sprites[b->class][i]); + } + } else { + fprintf(stderr, + "[ERROR] Unexpected bossclass in setBossSprite().\n"); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a Fighter pointer and prepares its sprite field by copying it line by line. + * @see Fighter + * @see initPlayerStats + * @param f The Fighter pointer whose sprite field will be initialised. + */ +void setFighterSprite(Fighter *f) +{ + //TODO: this sprite is also present in misc_sprites, defined in sprites.h + //Should follow suit as the other setter functions and grab from there, not from this local copy. + switch (f->class) { + default: { + strcpy(f->sprite[0], "I yy I"); + strcpy(f->sprite[1], "I yy I"); + strcpy(f->sprite[2], "I yyyy y I"); + strcpy(f->sprite[3], "I yy yy y I"); + strcpy(f->sprite[4], "I yy I"); + strcpy(f->sprite[5], "I y y I"); + strcpy(f->sprite[6], "I y y I"); + strcpy(f->sprite[7], "I y y I"); + } + break; + + }; +} + +/** + * Takes a Equipslot pointer and prepares its sprite field by copying it line by line from equipzones_sprites, defined in sprites.h header. + * @see Equipslot + * @see initEquipSlots() + * @see equipzones_sprites + * @param s The Equipslot pointer whose sprite field will be initialised. + */ +void setEquipslotSprite(Equipslot *s) +{ + if (s->type < EQUIPZONES + 1) { + for (int i = 0; i < 8; i++) { + strcpy(s->sprite[i], equipzones_sprites[s->type][i]); + } + } else { + fprintf(stderr, + "[ERROR] Unexpected Equipslot type in setEquipslotSprite().\n"); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a Chest pointer and prepares its sprite field by copying it line by line. + * @see Chest + * @see initChest + * @param c The Chest pointer whose sprite field will be initialised. + */ +void setChestSprite(Chest *c) +{ + + switch (c->class) { + case CHEST_BASE: { + strcpy(c->sprite[0], " "); + strcpy(c->sprite[1], " bbbbbbb "); + strcpy(c->sprite[2], " bbcccccbb "); + strcpy(c->sprite[3], " bcccccccb "); + strcpy(c->sprite[4], " bbbbbbbbb "); + strcpy(c->sprite[5], " bcccrcccb "); + strcpy(c->sprite[6], " bcccccccb "); + strcpy(c->sprite[7], " bbbbbbbbb "); + } + break; + case CHEST_BEAST: { + strcpy(c->sprite[0], " "); + strcpy(c->sprite[1], " rrrrrrr "); + strcpy(c->sprite[2], " rryyyyyrr "); + strcpy(c->sprite[3], " ryyyyyyyr "); + strcpy(c->sprite[4], " rrrrrrrrr "); + strcpy(c->sprite[5], " ryyymyyyr "); + strcpy(c->sprite[6], " ryyyyyyyr "); + strcpy(c->sprite[7], " rrrrrrrrr "); + } + break; + default: { + strcpy(c->sprite[0], "I yy I"); + strcpy(c->sprite[1], "I yy I"); + strcpy(c->sprite[2], "I yyyyyyyy I"); + strcpy(c->sprite[3], "I yy I"); + strcpy(c->sprite[4], "I yy I"); + strcpy(c->sprite[5], "I yyyy I"); + strcpy(c->sprite[6], "I y y I"); + strcpy(c->sprite[7], "I y y I"); + } + break; + + }; + +} diff --git a/src/game_rl.h b/src/build-rl/game_rl.h similarity index 57% rename from src/game_rl.h rename to src/build-rl/game_rl.h index eab4b158..53c7b445 100644 --- a/src/game_rl.h +++ b/src/build-rl/game_rl.h @@ -19,36 +19,20 @@ #ifndef GAMECURSES_RL_H #define GAMECURSES_RL_H -#include -#include "game_core.h" -#include "game_utils.h" -#include "palette.h" - -#include "./animations/knight_tapis.h" -#include "./animations/mage_spark.h" -#include "./animations/archer_drop.h" -#include "./animations/assassin_poof.h" - -#include "./animations/mummy_shuffle.h" -#include "./animations/ghost_spell.h" -#include "./animations/boar_scream.h" -#include "./animations/troll_club.h" -#include "./animations/goblin_shoot.h" -#include "./animations/zombie_walk.h" -#include "./animations/imp_fireball.h" -#include "./animations/werewolf_transform.h" - -#include "./animations/crawlingdude_crawl.h" -#include "./animations/srwarthog_square.h" -#include "./animations/headlessninja_throw.h" -#include "./animations/bluetroll_wonder.h" - -#include "./animations/enter_door.h" -#include "./animations/alt_chest_opening.h" +#include "../utils/game_utils.h" +#include "../core/sprites.h" +#include "../core/game_animations.h" #define EXPECTED_RAYLIB_VERSION_MAJOR 4 /**< Defines min expected major ncurses version.*/ #define EXPECTED_RAYLIB_VERSION_MINOR 5 /**< Defines min expected minor ncurses version.*/ #define EXPECTED_RAYLIB_VERSION_PATCH 0 /**< Defines min expected patch ncurses version.*/ void handleTutorial(S4C_Color* palette); +void setEnemySprite(Enemy * e); +void setEquipSprite(Equip * e); +void setEquipslotSprite(Equipslot * s); +void setConsumableSprite(Consumable * c); +void setBossSprite(Boss * b); +void setFighterSprite(Fighter * f); +void setChestSprite(Chest * c); #endif // GAMECURSES_RL_H diff --git a/src/helapordo_raylib.c b/src/build-rl/helapordo_raylib.c similarity index 80% rename from src/helapordo_raylib.c rename to src/build-rl/helapordo_raylib.c index 02327360..1f14710a 100644 --- a/src/helapordo_raylib.c +++ b/src/build-rl/helapordo_raylib.c @@ -87,6 +87,8 @@ void gameloop_rl(int argc, char** argv) (whoami = strrchr(argv[0], '\\')) ? ++whoami : (whoami = argv[0]); #endif + bool is_localexe = ( argv[0][0] == '.'); + char *kls_progname = (char *)KLS_PUSH_ARR_TYPED(default_kls, char *, sizeof(whoami), KLS_None, "progname", whoami); strcpy(kls_progname, whoami); @@ -367,6 +369,7 @@ void gameloop_rl(int argc, char** argv) G_DEBUG_ON); log_tag("debug_log.txt", "[DEBUG]", "kls_progname == (%s)", kls_progname); + log_tag("debug_log.txt", "[DEBUG]", "is_localexe == (%s)", (is_localexe ? "true" : "false")); log_tag("debug_log.txt", "[DEBUG]", "G_LOG_ON == (%i)", G_LOG_ON); log_tag("debug_log.txt", "[DEBUG]", "small DEBUG FLAG ASSERTED"); log_tag("debug_log.txt", "[DEBUG]", @@ -542,6 +545,38 @@ void gameloop_rl(int argc, char** argv) log_tag("debug_log.txt", "[DEBUG]", "gameloop() scanf() res was (%i)", scanfres); + log_tag("debug_log.txt", "[DEBUG]", "Prepping current_floor."); + kls_log(default_kls, "DEBUG", "Prepping current_floor."); + Floor *current_floor = + (Floor *) KLS_PUSH_TYPED(temporary_kls, Floor, + HR_Floor, "Floor", "Floor"); + // Start the random walk from the center of the dungeon + int center_x = FLOOR_MAX_COLS / 2; + int center_y = FLOOR_MAX_ROWS / 2; + + int current_x = center_x; + int current_y = center_y; + + // Init dbg_floor + init_floor_layout(current_floor); + + //Set center as filled + current_floor->floor_layout[center_x][center_y] = 1; + + //Init floor rooms + init_floor_rooms(current_floor); + + //Random walk #1 + floor_random_walk(current_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reset floor_layout if needed. + //Random walk #2 + floor_random_walk(current_floor, center_x, center_y, 100, 0); // Perform 100 more steps of random walk, DON'T reset floor_layout if needed. + + //Set floor explored matrix + load_floor_explored(current_floor); + + //Set room types + floor_set_room_types(current_floor); + int screenWidth = 800; int screenHeight = 450; @@ -615,6 +650,69 @@ void gameloop_rl(int argc, char** argv) if (IsKeyPressed(KEY_P)) { pause_animation = !pause_animation; } + if (IsKeyPressed(KEY_R)) { + fprintf(stderr,"%s\n", "Regenerating current floor"); + kls_free(temporary_kls); + temporary_kls = kls_new_conf(KLS_DEFAULT_SIZE * 32, temporary_kls_conf); + current_floor = + (Floor *) KLS_PUSH_TYPED(temporary_kls, Floor, + HR_Floor, "Floor", "Floor"); + // Init dbg_floor + init_floor_layout(current_floor); + + //Set center as filled + current_floor->floor_layout[center_x][center_y] = 1; + + //Init floor rooms + init_floor_rooms(current_floor); + + //Random walk #1 + floor_random_walk(current_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reset floor_layout if needed. + //Random walk #2 + floor_random_walk(current_floor, center_x, center_y, 100, 0); // Perform 100 more steps of random walk, DON'T reset floor_layout if needed. + + //Set floor explored matrix + load_floor_explored(current_floor); + + //Set room types + floor_set_room_types(current_floor); + } + if (IsKeyPressed(KEY_UP)) { + step_floor(current_floor, ¤t_x, + ¤t_y, KEY_UP); + if (current_floor->roomclass_layout[current_x][current_y] != BASIC) { + currentScreen = DOOR_ANIM; + current_anim_frame = 0; + break; + } + } + if (IsKeyPressed(KEY_DOWN)) { + step_floor(current_floor, ¤t_x, + ¤t_y, KEY_DOWN); + if (current_floor->roomclass_layout[current_x][current_y] != BASIC) { + currentScreen = DOOR_ANIM; + current_anim_frame = 0; + break; + } + } + if (IsKeyPressed(KEY_LEFT)) { + step_floor(current_floor, ¤t_x, + ¤t_y, KEY_LEFT); + if (current_floor->roomclass_layout[current_x][current_y] != BASIC) { + currentScreen = DOOR_ANIM; + current_anim_frame = 0; + break; + } + } + if (IsKeyPressed(KEY_RIGHT)) { + step_floor(current_floor, ¤t_x, + ¤t_y, KEY_RIGHT); + if (current_floor->roomclass_layout[current_x][current_y] != BASIC) { + currentScreen = DOOR_ANIM; + current_anim_frame = 0; + break; + } + } if (!pause_animation) { current_anim_frame = framesCounter%60; } @@ -629,6 +727,17 @@ void gameloop_rl(int argc, char** argv) } } break; + case DOOR_ANIM: { + // TODO: Update DOOR_ANIM screen variables here! + framesCounter++; // Count frames + // Press enter to return to gameplay screen + if (current_anim_frame == 59 || IsKeyPressed(KEY_ENTER) || IsGestureDetected(GESTURE_TAP)) { + currentScreen = GAMEPLAY; + break; + } + current_anim_frame++; + } + break; default: break; } @@ -719,6 +828,25 @@ void gameloop_rl(int argc, char** argv) DrawRectangleRec(stats_label_r, ColorFromS4CPalette(palette, S4C_GREY)); int pl_res = DrawSpriteRect(mage_spark[current_anim_frame], pl_r, pl_frame_H, pl_frame_W, sprite_w_factor, palette, PALETTE_S4C_H_TOTCOLORS); int en_res = DrawSpriteRect(zombie_walk[current_anim_frame], en_r, en_frame_H, en_frame_W, sprite_w_factor, palette, PALETTE_S4C_H_TOTCOLORS); + + Rectangle floor_r = CLITERAL(Rectangle) { + screenWidth / 2 - (5 * sprite_w_factor), + //screenHeight / 2, + stats_label_r.y + (13 * sprite_w_factor), + FLOOR_MAX_COLS * sprite_w_factor, + FLOOR_MAX_ROWS * sprite_w_factor, + }; + + draw_floor_view(current_floor, current_x, current_y, sprite_w_factor, &floor_r); + + /* + int center_x = FLOOR_MAX_COLS / 2; + int center_y = FLOOR_MAX_ROWS / 2; + draw_floor_view(current_floor, center_x, center_y, sprite_w_factor, &floor_r); + */ + //display_roomclass_layout(current_floor, &floor_r, sprite_w_factor); + //display_floor_layout(current_floor, &floor_r, sprite_w_factor); + //display_explored_layout(current_floor, &floor_r, sprite_w_factor); /* Rectangle en_pl_coll = GetCollisionRec(en_r,pl_r); Rectangle st_pl_coll = GetCollisionRec(stats_label_r,pl_r); @@ -752,7 +880,32 @@ void gameloop_rl(int argc, char** argv) DrawText("ENDING SCREEN", 20, 20, 40, DARKBLUE); DrawText("WIP", 20, screenHeight - (10 * sprite_w_factor), 40, ColorFromS4CPalette(palette, S4C_SALMON)); DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, DARKBLUE); - + } + break; + case DOOR_ANIM: { + // TODO: Draw ENDING screen here! + DrawRectangle(0, 0, screenWidth, screenHeight, ColorFromS4CPalette(palette,S4C_TEAL)); + DrawText("DOOR SCREEN", 20, 20, 40, DARKBLUE); + DrawText("WIP", 20, screenHeight - (10 * sprite_w_factor), 40, ColorFromS4CPalette(palette, S4C_SALMON)); + DrawText("PRESS ENTER or TAP to RETURN to GAMEPLAY SCREEN", 120, 220, 20, DARKBLUE); + + int door_frame_W = 21; + int door_frame_H = 21; + int door_rect_X = (screenWidth/2) - ((door_frame_W * sprite_w_factor * 1.5) /2); + int door_rect_Y = (screenHeight/2) - ((door_frame_H * sprite_w_factor * 1.5) /2); + Rectangle door_r = CLITERAL(Rectangle) { + door_rect_X, + door_rect_Y, + door_frame_W * sprite_w_factor * 1.5, + door_frame_H * sprite_w_factor * 1.5, + }; + int door_res = DrawSpriteRect(enter_door[current_anim_frame], door_r, door_frame_H, door_frame_W, sprite_w_factor*1.5, palette, PALETTE_S4C_H_TOTCOLORS); + if (door_res != 0 ) { + DrawRectangle(0, 0, screenWidth, screenHeight, ColorFromS4CPalette(palette, S4C_RED)); + DrawText("Window too small.", 20, 20, 20, RAYWHITE); + DrawText("Please resize.", 20, 50, 20, RAYWHITE); + current_anim_frame--; + } } break; default: diff --git a/src/helapordo_raylib.h b/src/build-rl/helapordo_raylib.h similarity index 67% rename from src/helapordo_raylib.h rename to src/build-rl/helapordo_raylib.h index 94e4558f..ff660916 100644 --- a/src/helapordo_raylib.h +++ b/src/build-rl/helapordo_raylib.h @@ -22,28 +22,10 @@ #define _POSIX_C_SOURCE 200809L #endif -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -#else -#endif -#include -#include -#include "game_core.h" -#include "game_utils.h" -#include "specials.h" -#include "artifacts.h" #include "game_rl.h" -#include "sprites.h" -#include "floors.h" -#include "anvil__helapordo.h" -#include "game_lore.h" -#include "game_lore_alt.h" +#include "../utils/rooms.h" +#include "../anvil__helapordo.h" +#include "../core/game_lore.h" void gameloop_rl(int argc, char** argv); #endif diff --git a/src/core/equips.c b/src/core/equips.c new file mode 100644 index 00000000..fd0db7b2 --- /dev/null +++ b/src/core/equips.c @@ -0,0 +1,41 @@ +#include "equips.h" + +/** + * Takes a Equip and a Fighter pointers. + * Iterates over the equip's perks and adds them to the fighter perks. + * @see Perk + * @see Equip + * @see Fighter + * @param e An Equip pointer. + * @param f A Fighter pointer. + */ +void applyEquipPerks(Equip *e, Fighter *f) +{ + + for (int i = 0; i < (e->perksCount); i++) { + Perk *p = e->perks[i]; + + Perk *fighterPerk = f->perks[p->class]; + fighterPerk->innerValue += 1; + } +} + +/** + * Takes a Equip and a Fighter pointers. + * Iterates over the equip's perks and removes them to the fighter perks. + * @see Perk + * @see Equip + * @see Fighter + * @param e An Equip pointer. + * @param f A Fighter pointer. + */ +void removeEquipPerks(Equip *e, Fighter *f) +{ + + for (int i = 0; i < (e->perksCount); i++) { + Perk *p = e->perks[i]; + + Perk *fighterPerk = f->perks[p->class]; + fighterPerk->innerValue -= 1; + } +} diff --git a/src/core/equips.h b/src/core/equips.h new file mode 100644 index 00000000..ba86262c --- /dev/null +++ b/src/core/equips.h @@ -0,0 +1,9 @@ +#ifndef EQUIPS_H_ +#define EQUIPS_H_ + +#include "game_core.h" + +void applyEquipPerks(Equip * e, Fighter * f); +void removeEquipPerks(Equip * e, Fighter * f); + +#endif // EQUIPS_H_ diff --git a/src/core/game_animations.h b/src/core/game_animations.h new file mode 100644 index 00000000..16d91224 --- /dev/null +++ b/src/core/game_animations.h @@ -0,0 +1,25 @@ +#ifndef GAME_ANIMATIONS_H_ +#define GAME_ANIMATIONS_H_ +#include "../animations/knight_tapis.h" +#include "../animations/mage_spark.h" +#include "../animations/archer_drop.h" +#include "../animations/assassin_poof.h" + +#include "../animations/mummy_shuffle.h" +#include "../animations/ghost_spell.h" +#include "../animations/boar_scream.h" +#include "../animations/troll_club.h" +#include "../animations/goblin_shoot.h" +#include "../animations/zombie_walk.h" +#include "../animations/imp_fireball.h" +#include "../animations/werewolf_transform.h" + +#include "../animations/crawlingdude_crawl.h" +#include "../animations/srwarthog_square.h" +#include "../animations/headlessninja_throw.h" +#include "../animations/bluetroll_wonder.h" + +#include "../animations/enter_door.h" +#include "../animations/alt_chest_opening.h" + +#endif // GAME_ANIMATIONS_H_ diff --git a/src/game_core.c b/src/core/game_core.c similarity index 100% rename from src/game_core.c rename to src/core/game_core.c diff --git a/src/game_core.h b/src/core/game_core.h similarity index 99% rename from src/game_core.h rename to src/core/game_core.h index edd94adf..82556546 100644 --- a/src/game_core.h +++ b/src/core/game_core.h @@ -57,7 +57,7 @@ typedef struct GameScreen { /** * Defines GameScreen type, as an enum. */ -typedef enum GameScreen { LOGO = 0, TITLE, GAMEPLAY, ENDING } GameScreen; +typedef enum GameScreen { LOGO = 0, TITLE, GAMEPLAY, ENDING, DOOR_ANIM } GameScreen; // Add more includes for rl-build here #ifdef _WIN32 /** @@ -74,8 +74,8 @@ typedef enum GameScreen { LOGO = 0, TITLE, GAMEPLAY, ENDING } GameScreen; #endif // HELAPORDO_RAYLIB_BUILD #endif // HELAPORDO_CURSES_BUILD -#include "../koliseo/src/koliseo.h" -#include "../sprites4curses/s4c-animate/animate.h" +#include "../../koliseo/src/koliseo.h" +#include "../palette.h" /**< Defines the color palette used for the s4c functions, includes animate.h.*/ extern const char* helapordo_title_string; /**< Defines a formatted string for title output to FILE.*/ @@ -204,12 +204,12 @@ extern int G_DOTUTORIAL_ON; /** * Current patch release. */ -#define HELAPORDO_PATCH_VERSION 2 +#define HELAPORDO_PATCH_VERSION 3 /** * Current version string identifier, with MAJOR.MINOR.PATCH format. */ -#define VERSION "1.4.2" +#define VERSION "1.4.3" #define HELAPORDO_SAVEFILE_VERSION "0.1.7" @@ -1735,6 +1735,8 @@ typedef struct { #else #endif // HELAPORDO_RAYLIB_BUILD #endif // HELAPORDO_CURSES_BUILD + + bool is_localexe; /**< Denotes if the current game was started from a relative path.*/ } Gamestate; /** diff --git a/src/game_lore.c b/src/core/game_lore.c similarity index 100% rename from src/game_lore.c rename to src/core/game_lore.c diff --git a/src/game_lore.h b/src/core/game_lore.h similarity index 100% rename from src/game_lore.h rename to src/core/game_lore.h diff --git a/src/game_lore_alt.c b/src/core/game_lore_alt.c similarity index 100% rename from src/game_lore_alt.c rename to src/core/game_lore_alt.c diff --git a/src/game_lore_alt.h b/src/core/game_lore_alt.h similarity index 100% rename from src/game_lore_alt.h rename to src/core/game_lore_alt.h diff --git a/src/sprites.c b/src/core/sprites.c similarity index 100% rename from src/sprites.c rename to src/core/sprites.c diff --git a/src/sprites.h b/src/core/sprites.h similarity index 100% rename from src/sprites.h rename to src/core/sprites.h diff --git a/src/game_rl.c b/src/game_rl.c deleted file mode 100644 index 384ed0b2..00000000 --- a/src/game_rl.c +++ /dev/null @@ -1,63 +0,0 @@ -// jgabaut @ github.com/jgabaut -// SPDX-License-Identifier: GPL-3.0-only -/* - Copyright (C) 2022-2024 jgabaut - - 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, version 3 of the License. - - 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 "game_rl.h" -#include "helapordo_raylib.h" - -callback_void_t callback_func_ptrs[SPECIALSMAX]; -callback_void_t callback_artifact_ptrs[ARTIFACTSMAX]; -callback_void_t callback_counter_ptrs[COUNTERSMAX]; - -/** - * Shows tutorial info. - * @see gameloop_rl() - */ -void handleTutorial(S4C_Color* palette) -{ - Rectangle rc = {0}; - - //If we get to this function straight from getopts, we need to do raylib init - - /* Initialize raylib */ - if (G_DOTUTORIAL_ON == 1) { - //TODO: prepare windowed mode - //framesCounter++; // Count frames - BeginDrawing(); - ClearBackground(ColorFromS4CPalette(palette,S4C_GREY)); - } - rc = CLITERAL(Rectangle) { - 1, 2, 20, 70 - }; - - int fontSize = 20; - const char* label = "Tutorial";; - DrawText(label, rc.x, rc.y, fontSize, ColorFromS4CPalette(palette,S4C_CYAN)); - - Color tut_color = ColorFromS4CPalette(palette, S4C_LIGHT_YELLOW); - DrawText("You can use the arrow keys and Enter to do everything needed for the game.", 14, 3*fontSize, fontSize, tut_color); - DrawText("Buying things from a Shop may be tricky: you have to select one, then choose Buy.\nTo select one, First go up/down to 'View Item', then press Enter,\nthen you can scroll them with left/right. Press Enter to confirm your selection,\nthen go back up to Buy.", 14, 6*fontSize, fontSize, tut_color); - DrawText("When running in Rogue mode, you can change floors by killing a Boss.", 14, 12*fontSize, fontSize, tut_color); - DrawText("When in floor map, you can open the menu with the \"m\" key.", 14, 15*fontSize, fontSize, tut_color); - DrawText("Rememeber, you can't really save in Rogue mode ! Run with \"-s\" to try Story mode.", 14, 18*fontSize, fontSize, tut_color); - - DrawText("[ Press ENTER or TAP to quit ]", 14, 21*fontSize, fontSize, ColorFromS4CPalette(palette,S4C_RED)); - - if (G_DOTUTORIAL_ON == 1) { - EndDrawing(); - //TODO: update win??? - } -} diff --git a/src/game_utils.c b/src/game_utils.c deleted file mode 100644 index 7274eef5..00000000 --- a/src/game_utils.c +++ /dev/null @@ -1,2131 +0,0 @@ -// jgabaut @ github.com/jgabaut -// SPDX-License-Identifier: GPL-3.0-only -/* - Copyright (C) 2022-2024 jgabaut - - 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, version 3 of the License. - - 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 "game_utils.h" -//Functions useful in many areas -// - -/** - * Prints global vars to stdout. - */ -void printGlobVars(void) -{ - printf("\nGlobal vars:\n"); - printf(" G_PRELOAD_ANIMATIONS_ON: { %i }\n", G_PRELOAD_ANIMATIONS_ON); - printf(" G_DEBUG_ON: { %i }\n", G_DEBUG_ON); - printf(" G_LOG_ON: { %i }\n", G_LOG_ON); - printf(" G_EXPERIMENTAL_ON: { %i }\n", G_EXPERIMENTAL_ON); - printf(" G_FASTQUIT_ON: { %i }\n", G_FASTQUIT_ON); - printf(" G_GODMODE_ON: { %i }\n", G_GODMODE_ON); - printf(" G_DEBUG_ROOMTYPE_ON: { %i }\n", G_DEBUG_ROOMTYPE_ON); - printf(" G_ROOMTYPE_ON: { %s } [ %i ]\n", stringFromRoom(G_DEBUG_ROOMTYPE), - G_DEBUG_ROOMTYPE); - printf(" G_ENEMYTYPE_ON: { %i }\n", G_DEBUG_ENEMYTYPE_ON); - printf(" G_DEBUG_ENEMYTYPE { %s } [ %i ]\n", - stringFromEClass(G_DEBUG_ENEMYTYPE), G_DEBUG_ENEMYTYPE); - printf(" G_DOTUTORIAL_ON: { %i }\n", G_DOTUTORIAL_ON); -} - -#ifdef _WIN32 -/** - * Prints Windows envvars to stdout. - */ -void printWin_EnvVars(void) -{ - printf("\nWindows Environment vars:\n"); - printf(" UserProfile: { %s }\n", getenv("UserProfile")); - printf(" HomeDrive: { %s }\n", getenv("HomeDrive")); - printf(" HomePath: { %s }\n", getenv("HomePath")); - printf(" ComputerName: { %s }\n", getenv("ComputerName")); - printf(" Processor_Revision: { %s }\n", getenv("Processor_Revision")); - printf(" Processor_Identifier: { %s }\n", getenv("Processor_Identifier")); - printf(" Processor_Level: { %s }\n", getenv("Processor_Level")); - printf(" Number_Of_Processors: { %s }\n", getenv("Number_Of_Processors")); - printf(" OS: { %s }\n", getenv("OS")); -} - -/** - * Logs Windows envvars to debug log file. - */ -void log_Win_EnvVars(void) -{ - log_tag("debug_log.txt", "[WIN32-DEBUG]", "Windows Environment vars:"); - log_tag("debug_log.txt", "[WIND32-DEBUG", "UserProfile: { %s }", - getenv("UserProfile")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "HomeDrive: { %s }", - getenv("HomeDrive")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "HomePath: { %s }", - getenv("HomePath")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "ComputerName: { %s }", - getenv("ComputerName")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "Processor_Revision: { %s }", - getenv("Processor_Revision")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "Processor_Identifier: { %s }", - getenv("Processor_Identifier")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "Processor_Level: { %s }", - getenv("Processor_Level")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "Number_Of_Processors: { %s }", - getenv("Number_Of_Processors")); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "OS: { %s }", getenv("OS")); -} -#endif - -#ifdef HELAPORDO_CURSES_BUILD -bool set_Saveslot_name(FILE *file, Saveslot *sv) -{ - - //printf("\nLoading game...\n"); - log_tag("debug_log.txt", "[LOAD]", "Starting loading from text file."); - -// FILE* file = fopen("save.txt", "r"); - if (file == NULL) { - endwin(); - printf("Error with file while trying to load!\n"); - return false; - } - char buf[500]; - char comment[300]; - int num_value = -1; - const char version[] = "v0.1.6"; - - int scanres = -1; - /* File version scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, - 1, scanres); - endwin(); - fprintf(stderr, "Error while loading game."); - return false; - } - - int check = -1; - if (!((check = strcmp(buf, version)) == 0)) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "Failed save format version check. Was [%s]. Quitting.", buf); - endwin(); - fprintf(stderr, "[ERROR] File version mismatch on load.\n"); - return false; - }; - log_tag("debug_log.txt", "[LOAD]", "Loaded save format version: (%s).", - buf); - - /* Save type scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, - 1, scanres); - endwin(); - fprintf(stderr, "Error while loading game."); - return false; - } - - check = -1; - if (! - (((check = strcmp(buf, stringFrom_saveType(ENEMIES_SAVE)) == 0)) - || ((check = strcmp(buf, stringFrom_saveType(HOME_SAVE))) == 0))) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "%s(): Failed save type check, was [%s]. Quitting.", buf); - endwin(); - fprintf(stderr, "[ERROR] Save type version mismatch on load.\n"); - return false; - }; - log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s).", buf); - - /* Gamemode scanning */ - scanres = fscanf(file, "%200[^#]# %s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, - 2, scanres); - endwin(); - fprintf(stderr, "Error while loading game."); - return false; - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - int gmd = num_value; - log_tag("debug_log.txt", "[LOAD]", "Gamemode was: {%i}", gmd); - - /* Fighter scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, - 1, scanres); - endwin(); - fprintf(stderr, "Error while loading game."); - return false; - } - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, - 2, scanres); - endwin(); - fprintf(stderr, "Error while loading game."); - return false; - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - strncpy(sv->name, buf, 50); - sv->name[49] = '\0'; - return true; -} -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." -#else -bool set_Saveslot_name(FILE *file, Saveslot *sv) -{ - (void) file; - (void) sv; - printf("%s(): TODO - implement set_Saveslot_namefor rl-build.\n", __func__); - return false; -} -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -/** - * Debugs the passed (preallocated) Fighter with log_tag(). - * @param fighter The allocated Fighter to debug. - */ -void dbg_Fighter(Fighter *fighter) -{ - if (fighter == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Fighter was NULL in dbg_Fighter()"); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[FIGHTER]", "Fighter name: { %s }", - fighter->name); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter class: { %s } [ %i ]", - stringFromClass(fighter->class), fighter->class); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter hp: { %i }", fighter->hp); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter atk: { %i }", fighter->atk); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter def: { %i }", fighter->def); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter vel: { %i }", fighter->vel); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter level: { %i }", - fighter->level); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter luck: { %i }", - fighter->luck); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalxp: { %i }", - fighter->totalxp); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter currentlevelxp: { %i }", - fighter->currentlevelxp); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter totallevelxp: { %i }", - fighter->totallevelxp); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalhp: { %i }", - fighter->totalhp); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter status: { %s } [ %i ]", - stringFromStatus(fighter->status), fighter->status); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter energy: { %i }", - fighter->energy); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalenergy: { %i }", - fighter->totalenergy); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter stamina: { %i }", - fighter->stamina); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalstamina: { %i }", - fighter->totalstamina); - - //Specialslot* specials[SPECIALSMAX+1]; /**< Array with all the Specialslot*/ - - //struct Turncounter* counters[COUNTERSMAX+1]; /**< Array with all the Turncounter pointers*/ - log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_atk: { %i }", - fighter->turnboost_atk); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_def: { %i }", - fighter->turnboost_def); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_vel: { %i }", - fighter->turnboost_vel); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_enr: { %i }", - fighter->turnboost_enr); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter perksCount: { %i }", - fighter->perksCount); - - //Perk* perks[PERKSMAX+1]; /**< Array with all the Perk*/ - - //struct Equipslot* equipslots[EQUIPZONES+1]; /**< Array with all the Equipslot*/ - //struct Equip* equipsBag[EQUIPSBAGSIZE+1]; /**< Array with all the Equip found*/ - //struct Consumable* consumablesBag[CONSUMABLESMAX+1]; /**< Array with all the Consumables found*/ - //struct Artifact* artifactsBag[ARTIFACTSMAX+1]; /**< Array with all the Artifacts found*/ - - log_tag("debug_log.txt", "[FIGHTER]", - "Fighter used equipsBag slots: { %i }", - fighter->equipsBagOccupiedSlots); - log_tag("debug_log.txt", "[FIGHTER]", - "Fighter earliest equipsBag slot: { %i }", - fighter->earliestBagSlot); - - log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_atk: { %i }", - fighter->permboost_atk); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_def: { %i }", - fighter->permboost_def); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_vel: { %i }", - fighter->permboost_vel); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_enr: { %i }", - fighter->permboost_enr); - - log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_atk: { %i }", - fighter->equipboost_atk); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_def: { %i }", - fighter->equipboost_def); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_vel: { %i }", - fighter->equipboost_vel); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_enr: { %i }", - fighter->equipboost_enr); - - //dbg_countStats(fighter->stats); - - log_tag("debug_log.txt", "[FIGHTER]", "Fighter coins balance: { %i }", - fighter->balance); - log_tag("debug_log.txt", "[FIGHTER]", "Fighter keys balance: { %i }", - fighter->keys_balance); -} - -/** - * Debugs the passed (preallocated) Saveslot with log_tag(). - * @param saveslot The allocated Saveslot to debug. - */ -void dbg_Saveslot(Saveslot *saveslot) -{ - if (saveslot == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Saveslot was NULL in dbg_Saveslot()"); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[SAVESLOT]", "Saveslot name: { %s }", - saveslot->name); - log_tag("debug_log.txt", "[SAVESLOT]", "Saveslot save_path: { %s }", - saveslot->save_path); -} - -/** - * Debugs the passed (preallocated) Path with log_tag(). - * @param path The allocated Path to debug. - */ -void dbg_Path(Path *path) -{ - if (path == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Path was NULL in dbg_Path()"); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[PATH]", "Path length: { %i }", path->length); - log_tag("debug_log.txt", "[PATH]", "Path luck: { %i }", path->luck); - log_tag("debug_log.txt", "[PATH]", "Path prize: { %i }", path->prize); - log_tag("debug_log.txt", "[PATH]", "Path loreCounter: { %i }", - path->loreCounter); - log_tag("debug_log.txt", "[PATH]", "Path loreCounter: { %i }", - path->loreCounter); - dbg_Wincon(path->win_condition); - dbg_Saveslot(path->current_saveslot); -} - -/** - * Debugs the passed (preallocated) Wincon with log_tag(). - * @param gmst The allocated countStats to debug. - */ -void dbg_Wincon(Wincon *wc) -{ - if (wc == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Wincon was NULL in dbg_Wincon()"); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[WINCON]", "Wincon class: { %s } [ %i ]", - stringFromWinconClass(wc->class), wc->class); - log_tag("debug_log.txt", "[WINCON]", "Wincon current value: { %i }", - wc->current_val); - log_tag("debug_log.txt", "[WINCON]", "Wincon target value: { %i }", - wc->target_val); -} - -/** - * Debugs the passed (preallocated) countStats with log_tag(). - * @param gmst The allocated countStats to debug. - */ -void dbg_countStats(countStats *stats) -{ - if (stats == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "countStats was NULL in dbg_countStats()"); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[countStats]", "Enemies killed: { %i }", - stats->enemieskilled); - log_tag("debug_log.txt", "[countStats]", "Consumables found: { %i }", - stats->consumablesfound); - log_tag("debug_log.txt", "[countStats]", "Equips found: { %i }", - stats->equipsfound); - log_tag("debug_log.txt", "[countStats]", "Artifacts found: { %i }", - stats->artifactsfound); - log_tag("debug_log.txt", "[countStats]", "Critical hits done: { %i }", - stats->criticalhits); - log_tag("debug_log.txt", "[countStats]", "Rooms completed: { %i }", - stats->roomscompleted); - log_tag("debug_log.txt", "[countStats]", "Floors completed: { %i }", - stats->floorscompleted); - log_tag("debug_log.txt", "[countStats]", "Specials unlocked: { %i }", - stats->specialsunlocked); - log_tag("debug_log.txt", "[countStats]", "Coins found: { %i }", - stats->coinsfound); - log_tag("debug_log.txt", "[countStats]", "Bosses killed: { %i }", - stats->bosseskilled); - log_tag("debug_log.txt", "[countStats]", "Unique Boss kills: { %i }", - stats->unique_bosseskilled); - for (int i = 0; i < BOSSCLASSESMAX + 1; i++) { - log_tag("debug_log.txt", "[countStats]", "Boss [%i] { %s }: { %s }", i, - stringFromBossClass(i), - (stats->killed_bosses[i] == 1 ? "Killed" : "Not Killed")); - } - log_tag("debug_log.txt", "[countStats]", "Keys found: { %i }", - stats->keysfound); -} - -/** - * Logs floor layout for passed Floor. - */ -void dbg_print_floor_layout(Floor *floor) -{ - if (floor == NULL) { - fprintf(stderr, "[ERROR] at %s(): passed floor was NULL.\n", - __func__); - log_tag("debug_log.txt", "[ERROR]", "at %s(): passed floor was NULL.", - __func__); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - for (int y = 0; y < FLOOR_MAX_ROWS; y++) { - char rowbuf[FLOOR_MAX_COLS + 1] = { 0 }; - for (int x = 0; x < FLOOR_MAX_COLS; x++) { - rowbuf[x] = (floor->floor_layout[x][y] == 1 ? '1' : ' '); - } - log_tag("debug_log.txt", "[Floor_row]", "{%s} - %i", rowbuf, y); - } - log_tag("debug_log.txt", "[DEBUG]", "Logged floor layout."); -} - -/** - * Logs explored layout for passed Floor. - */ -void dbg_print_explored_layout(Floor *floor) -{ - if (floor == NULL) { - fprintf(stderr, "[ERROR] at %s(): passed floor was NULL.\n", - __func__); - log_tag("debug_log.txt", "[ERROR]", "at %s(): passed floor was NULL.", - __func__); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - for (int y = 0; y < FLOOR_MAX_ROWS; y++) { - char rowbuf[FLOOR_MAX_COLS + 1] = { 0 }; - for (int x = 0; x < FLOOR_MAX_COLS; x++) { - rowbuf[x] = (floor->explored_matrix[x][y] == 1 ? '1' : ' '); - } - log_tag("debug_log.txt", "[Floor_row]", "{%s} - %i", rowbuf, y); - } - log_tag("debug_log.txt", "[DEBUG]", "Logged explored layout."); -} - -/** - * Logs roomclass layout for passed Floor. - */ -void dbg_print_roomclass_layout(Floor *floor) -{ - if (floor == NULL) { - fprintf(stderr, "[ERROR] at %s(): passed floor was NULL.\n", - __func__); - log_tag("debug_log.txt", "[ERROR]", "at %s(): passed floor was NULL.", - __func__); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - for (int y = 0; y < FLOOR_MAX_ROWS; y++) { - char rowbuf[FLOOR_MAX_COLS + 1] = { 0 }; - for (int x = 0; x < FLOOR_MAX_COLS; x++) { - char ch = '.'; - switch (floor->roomclass_layout[x][y]) { - case HOME: { - ch = 'H'; - } - break; - case ENEMIES: { - ch = 'E'; - } - break; - case BOSS: { - ch = 'B'; - } - break; - case SHOP: { - ch = '$'; - } - break; - case TREASURE: { - ch = '*'; - } - break; - case WALL: { - ch = '#'; - } - break; - case BASIC: { - ch = ' '; - } - break; - default: { - ch = '?'; - } - break; - } - rowbuf[x] = ch; - } - log_tag("debug_log.txt", "[Floor_row]", "{%s} - %i", rowbuf, y); - } - log_tag("debug_log.txt", "[DEBUG]", "Logged roomclass layout."); -} - -/** - * Debugs the passed (preallocated) Gamestate with log_tag(). - * @param gmst The allocated Gamestate to debug. - */ -void dbg_Gamestate(Gamestate *gmst) -{ - if (gmst == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Gamestate was NULL in dbg_Gamestate()"); - exit(EXIT_FAILURE); - } -#ifdef HELAPORDO_CURSES_BUILD - if (gmst->screen == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Screen was NULL in dbg_Gamestate()"); - } else { - dbg_GameScreen(gmst->screen); - } -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - log_tag("debug_log.txt", "[DEBUG]", "Gamestate:{"); - log_tag("debug_log.txt", "[GAMESTATE]", "Current Gamemode: { %s } [ %i ]", - stringFromGamemode(gmst->gamemode), gmst->gamemode); - log_tag("debug_log.txt", "[GAMESTATE]", "Start time: {%llu}", - (unsigned long long) gmst->start_time); - clock_t run_time = clock() - gmst->start_time; - int time_spent = run_time * 1000 / CLOCKS_PER_SEC; - log_tag("debug_log.txt", "[GAMESTATE]", "Current run time: %d s, %d ms.", - time_spent / 1000, time_spent % 1000); - log_tag("debug_log.txt", "[GAMESTATE]", "Current fighters: { %i }", - gmst->current_fighters); - log_tag("debug_log.txt", "[GAMESTATE]", "Current room index: { %i }", - gmst->current_room_index); - log_tag("debug_log.txt", "[GAMESTATE]", "Current room type: { %s } [ %i ]", - stringFromRoom(gmst->current_roomtype), gmst->current_roomtype); - log_tag("debug_log.txt", "[GAMESTATE]", "Current enemy index: { %i }", - gmst->current_enemy_index); - dbg_countStats(gmst->stats); - dbg_Path(gmst->path); - dbg_Fighter(gmst->player); - //TODO: print out current floor - if (gmst->current_floor == NULL) { - log_tag("debug_log.txt", "[GAMESTATE]", "Current floor was NULL."); - } else { - log_tag("debug_log.txt", "[GAMESTATE]", "Current floor: {"); - log_tag("debug_log.txt", "[Floor]", "index: {%i}", - gmst->current_floor->index); - if (gmst->current_floor->desc != NULL) { - log_tag("debug_log.txt", "[Floor]", "desc: {%s}", - gmst->current_floor->desc); - } - log_tag("debug_log.txt", "[Floor]", "floorClass: {%i} {%s}", - gmst->current_floor->class, - stringFromFloorclass(gmst->current_floor->class)); - log_tag("debug_log.txt", "[Floor]", "area: {%i}", - gmst->current_floor->area); - log_tag("debug_log.txt", "[Floor]", "explorea area: {%i}", - gmst->current_floor->explored_area); - dbg_print_floor_layout(gmst->current_floor); - dbg_print_explored_layout(gmst->current_floor); - dbg_print_roomclass_layout(gmst->current_floor); - log_tag("debug_log.txt", "[GAMESTATE]", " }"); - } - log_tag("debug_log.txt", "[GAMESTATE]", "}"); -} - -/** - * Debugs the passed (preallocated) GameScreen with log_tag(). - * @param scr The allocated GameScreen to debug. - */ -void dbg_GameScreen(GameScreen * scr) -{ -#ifdef HELAPORDO_CURSES_BUILD - int y = 0; - int x = 0; - if (scr->win == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "win was NULL in %s()", __func__); - } else { - getmaxyx(scr->win, y, x); - log_tag("debug_log.txt", "[GAMESCREEN]", - "Screen size: y->(%i), x->(%i)", - y, x); - } - log_tag("debug_log.txt", "[GAMESCREEN]", - "Cols: {%i}", scr->cols); - log_tag("debug_log.txt", "[GAMESCREEN]", - "Rows: {%i}", scr->rows); - log_tag("debug_log.txt", "[GAMESCREEN]", - "Colors: {%i}", scr->colors); - log_tag("debug_log.txt", "[GAMESCREEN]", - "Color pairs: {%i}", scr->color_pairs); - log_tag("debug_log.txt", "[GAMESCREEN]", - "Escape delay: {%i}", scr->escape_delay); - log_tag("debug_log.txt", "[GAMESCREEN]", - "Tab size: {%i}", scr->tabsize); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else - printf("TODO: implement %s().\n", __func__); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD -} - -/** - * Updates the passed (preallocated) Gamestate with the passed int values. - * @param gmst The allocated Gamestate to update. - * @param current_fighters Number of current Fighters. - * @param current_roomtype roomClass for current Room. - * @param current_room_index Index for current Room. - * @param current_enemy_index Index for current Enemy. - * @param current_floor Pointer to current Floor, initialised if gmst->gamemode == Rogue. - */ -void update_Gamestate(Gamestate *gmst, int current_fighters, - roomClass current_roomtype, int current_room_index, - int current_enemy_index, Floor *current_floor) -{ - if (gmst == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Gamestate was NULL in %s().", - __func__); - exit(EXIT_FAILURE); - } - gmst->current_fighters = current_fighters; - gmst->current_roomtype = current_roomtype; - gmst->current_room_index = current_room_index; - gmst->current_enemy_index = current_enemy_index; - if (gmst->gamemode == Rogue) { - if (current_floor == NULL) { - log_tag("debug_log.txt", "[WARN]", - "Passed current floor was NULL in %s().", __func__); - } else { - gmst->current_floor = current_floor; - } - } -} - -#ifdef HELAPORDO_CURSES_BUILD -/** - * Inits the passed (preallocated) Gamestate with the passed pointers. - * @param gmst The allocated Gamestate to init. - * @param start_time The start time for current game. - * @param stats Game stats. - * @param wincon Game Wincon. - * @param path Game Path. - * @param player Game main player. - * @param gamemode Picked gamemode. - * @param screen The main screen from initscr(). - */ -void init_Gamestate(Gamestate *gmst, clock_t start_time, countStats *stats, Wincon *wincon, - Path *path, Fighter *player, Gamemode gamemode, GameScreen* screen) -{ - if (gmst == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Gamestate was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (stats == NULL) { - log_tag("debug_log.txt", "[ERROR]", "countStats was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (wincon == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Wincon was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (path == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Path was NULL in %s()", __func__); - exit(EXIT_FAILURE); - } - if (player == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Player was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (gamemode != Story && gamemode != Rogue) { - log_tag("debug_log.txt", "[ERROR]", "Invalid gamemode requested: [%i]", - gamemode); - exit(EXIT_FAILURE); - } - if (screen == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Screen was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - gmst->start_time = start_time; - gmst->stats = stats; - gmst->current_fighters = -1; - gmst->current_roomtype = -1; - gmst->current_room_index = -1; - gmst->current_enemy_index = -1; - gmst->wincon = wincon; - gmst->path = path; - gmst->player = player; - gmst->gamemode = gamemode; - gmst->screen = screen; -} - -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -/** - * Inits the passed (preallocated) Gamestate with the passed pointers. - * @param gmst The allocated Gamestate to init. - * @param start_time The start time for current game. - * @param stats Game stats. - * @param wincon Game Wincon. - * @param path Game Path. - * @param player Game main player. - * @param gamemode Picked gamemode. - */ -void init_Gamestate(Gamestate *gmst, clock_t start_time, countStats *stats, Wincon *wincon, - Path *path, Fighter *player, Gamemode gamemode) -{ - if (gmst == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Gamestate was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (stats == NULL) { - log_tag("debug_log.txt", "[ERROR]", "countStats was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (wincon == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Wincon was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (path == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Path was NULL in %s()", __func__); - exit(EXIT_FAILURE); - } - if (player == NULL) { - log_tag("debug_log.txt", "[ERROR]", "Player was NULL in %s()", - __func__); - exit(EXIT_FAILURE); - } - if (gamemode != Story && gamemode != Rogue) { - log_tag("debug_log.txt", "[ERROR]", "Invalid gamemode requested: [%i]", - gamemode); - exit(EXIT_FAILURE); - } - gmst->start_time = start_time; - gmst->stats = stats; - gmst->current_fighters = -1; - gmst->current_roomtype = -1; - gmst->current_room_index = -1; - gmst->current_enemy_index = -1; - gmst->wincon = wincon; - gmst->path = path; - gmst->player = player; - gmst->gamemode = gamemode; -} -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -#ifdef HELAPORDO_CURSES_BUILD -/** - * Allocates and prepares a turnOP_args and returns a pointer to it. - * @see turnOP_args - * @see turnOption_OP - * @see turnOption - * @see turnOP() - * @param gmst The Gamestate pointer to assign to turnOP_args->gmst. - * @param actor The Fighter pointer to assign to turnOP_args->actor. - * @param path The Path pointer to assign to turnOP_args->path. - * @param room The Room pointer to assign to turnOP_args->room. - * @param Enemy The Enemy pointer to assign to turnOP_args->enemy. - * @param Boss The Boss pointer to assign to turnOP_args->boss. - * @param save_file The FILE pointer to assign to turnOP_args->save_file. - * @param notify_win The WINDOW pointer to assign to turnOP_args->notify_win. - * @param t_kls The Koliseo_Temp pointer to assign to turnOP_args->t_kls. - * @param foe_op The foeTurnOption_OP to assign to turnOP_args->foe_op. - * @param picked_skill The skillType to assign to turnOP_args->picked_skill. - */ -turnOP_args *init_turnOP_args(Gamestate *gmst, Fighter *actor, Path *path, - Room *room, loadInfo *load_info, Enemy *enemy, - Boss *boss, FILE *save_file, WINDOW *notify_win, - Koliseo_Temp *t_kls, foeTurnOption_OP foe_op, - skillType picked_skill) -{ - log_tag("debug_log.txt", "[TURNOP]", - "Allocated size %lu for new turnOP_args", sizeof(turnOP_args)); - kls_log(t_kls->kls, "DEBUG", "[TURNOP]", - "Allocated size %lu for new turnOP_args", sizeof(turnOP_args)); - turnOP_args *res = - (turnOP_args *) KLS_PUSH_T_TYPED(t_kls, turnOP_args, HR_turnOP_args, - "turnOP_args", "turnOP_args"); - - res->gmst = gmst; - res->actor = actor; - res->path = path; - res->room = room; - res->load_info = load_info; - res->enemy = enemy; - res->boss = boss; - res->save_file = save_file; - res->notify_win = notify_win; - res->t_kls = t_kls; - res->foe_op = foe_op; - res->picked_skill = picked_skill; - - return res; -} -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -turnOP_args *init_turnOP_args(Gamestate *gmst, Fighter *actor, Path *path, - Room *room, loadInfo *load_info, Enemy *enemy, - Boss *boss, FILE *save_file, Rectangle *notification_area, - Koliseo_Temp *t_kls, foeTurnOption_OP foe_op, - skillType picked_skill) -{ - printf("%s(): TODO - implement turnOP init for rl-build\n", __func__); - return NULL; -} -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -/** - * Takes a string and returns the corresponding saveType. - * Will return -1 if no match is found. - * @param s The string to convert. - */ -saveType saveTypeFrom_string(char *s) -{ - int check = -1; - - for (int i = 0; i < SAVETYPE_MAX + 1; i++) { - if ((check = strcmp(s, stringFrom_saveType(i))) == 0) { - log_tag("debug_log.txt", "[DEBUG]", - "Matched saveType string [%s] to (%i).", s, i); - return (saveType) i; - } - } - - log_tag("debug_log.txt", "[ERROR]", - "No match found for saveType string [%s].", s); - return -1; -} - -/** - * Logs a turnOption_OP to "$STATICDIR/OPS_log.txt". - * @param op The turnOption_OP to log. - */ -void log_OP(turnOption_OP op) -{ - log_tag(OPS_LOGFILE, "[LOG]", "[OP_code: %i, value: %s]", op, - stringFromTurnOP(op)); - log_tag("debug_log.txt", "[LOG_TURNOP]", "[OP_code: %i, value: %s]", op, - stringFromTurnOP(op)); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick red color. - */ -void red(void) -{ - printf("\033[1;31m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light red color. - */ -void lightRed(void) -{ - printf("\033[0;31m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick white color. - */ -void strongWhite(void) -{ - printf("\033[1;37m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light white color. - */ -void white(void) -{ - printf("\033[0;37m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick green color. - */ -void green(void) -{ - printf("\033[1;32m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light green color. - */ -void lightGreen(void) -{ - printf("\033[0;32m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick yellow color. - */ -void yellow(void) -{ - printf("\033[1;33m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light yellow color. - */ -void lightYellow(void) -{ - printf("\033[0;33m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick blue color. - */ -void blue(void) -{ - printf("\033[1;34m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light blue color. - */ -void lightBlue(void) -{ - printf("\033[0;34m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick purple color. - */ -void purple(void) -{ - printf("\033[1;35m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light purple color. - */ -void lightPurple(void) -{ - printf("\033[0;35m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a thick cyan color. - */ -void cyan(void) -{ - printf("\033[1;36m"); -} - -/** - * Prints an ASCII escape code that makes subsequent output a light cyan color. - */ -void lightCyan(void) -{ - printf("\033[0;36m"); -} - -#ifdef HELAPORDO_CURSES_BUILD -/** - * Initialises color pairs for the game. - */ -void init_game_color_pairs(void) -{ - - // Initialize all the colors - init_pair(1, COLOR_RED, COLOR_BLACK); - init_pair(2, COLOR_GREEN, COLOR_BLACK); - init_pair(3, COLOR_BLUE, COLOR_BLACK); - init_pair(4, COLOR_CYAN, COLOR_BLACK); - init_pair(5, COLOR_WHITE, COLOR_BLACK); - init_pair(6, COLOR_YELLOW, COLOR_BLACK); - init_pair(7, COLOR_BLACK, COLOR_WHITE); - init_pair(8, COLOR_MAGENTA, COLOR_BLACK); - init_pair(9, COLOR_WHITE, COLOR_RED); - init_pair(10, COLOR_WHITE, COLOR_MAGENTA); - -} -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." -#else -void init_game_color_pairs(void) -{ - printf("%s(): TODO - Implement color pair init for rl-build\n", __func__); - return; -} -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -#ifdef HELAPORDO_CURSES_BUILD -/** - * Demoes color pairs from palette.c to the passed WINDOW. - * @param win The Window pointer to print to. - * @param colors_per_row How many colors to print in each row. - */ -void test_game_color_pairs(WINDOW *win, int colors_per_row) -{ - if (win == NULL) { - fprintf(stderr, "[%s]: Passed Window was NULL.", __func__); - log_tag("debug_log.txt", "[ERROR]", "[%s]: Passed Window was NULL.", - __func__); - exit(EXIT_FAILURE); - } - - int x = 1; - int y = 1; - int x_offset = 0; - - for (int i = S4C_MIN_COLOR_INDEX; i < S4C_MAX_COLOR_INDEX + 1; i++) { - int color_index = i; - if (color_index >= 0) { - wattron(win, COLOR_PAIR(color_index)); - mvwaddch(win, y, x + x_offset, ' ' | A_REVERSE); - wattroff(win, COLOR_PAIR(color_index)); - } - x_offset++; - if ((color_index - S4C_MIN_COLOR_INDEX + 1) % colors_per_row == 0) { - x = 1; - x_offset = 0; - y++; - } - } - - int picked = 0; - int c = -1; - wrefresh(win); - refresh(); - - while (!picked && (c = wgetch(win)) != 'q') { - switch (c) { - case 10: { /*Enter */ - picked = 1; - - }; - break; - } - } -} -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." -#else -void test_game_color_pairs(Rectangle * win, int colors_per_row) -{ - (void) win; - (void) colors_per_row; - printf("%s(): TODO - Implement game color pairs test for rl-build\n", __func__); - return; -} -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -/** - * Sets the passed char array to the expected path for /static/ folder. - * @param static_path The array that will hold path to static folder. - */ -void resolve_staticPath(char static_path[500]) -{ - char homedir_path[200]; -#ifndef _WIN32 - sprintf(homedir_path, "%s", getenv("HOME")); -#else - sprintf(homedir_path, "%s", getenv("UserProfile")); -#endif - -#ifndef _WIN32 - const char *static_folder_path_wd = "./"; -#else - const char *static_folder_path_wd = ".\\"; -#endif - -#ifndef _WIN32 - const char *local_install_static_folder_path = "/helapordo-local/"; -#else - const char *local_install_static_folder_path = "\\helapordo-local\\"; -#endif - char static_folder_path_global[500]; - sprintf(static_folder_path_global, "%s", homedir_path); - strncat(static_folder_path_global, local_install_static_folder_path, 50); - struct stat sb; - - if (stat(static_folder_path_wd, &sb) == 0 && S_ISDIR(sb.st_mode)) { - //sprintf(msg, "[DEBUG] resolve_staticPath(): Found \"/static/\" dir in working directory (%s).\n",static_folder_path_wd); - strcpy(static_path, static_folder_path_wd); - } else { - //sprintf(msg, "[DEBUG] resolve_staticPath(): Can't find \"/static/\" dir in working directory (%s). Will try \"%s/helapordo-local/static/\".\n", static_folder_path_wd, homedir_path); - if (stat(static_folder_path_global, &sb) == 0 && S_ISDIR(sb.st_mode)) { - //sprintf(msg, "[DEBUG] resolve_staticPath(): Found \"/static/\" dir in global directory: \"%s/helapordo-local/static/\".\n", homedir_path); - strcpy(static_path, static_folder_path_global); - } else { - //sprintf(msg,"[DEBUG] resolve_staticPath(): Can't find \"/static/\" dir in \"%s/helapordo-local/static/\". Quitting.\n", homedir_path); - fprintf(stderr, "\n[ERROR] Can't find static dir. Quitting.\n"); - fprintf(stderr, "\nHome dir at: (%s).\n", homedir_path); - fprintf(stderr, "\nGlobal static dir at: (%s).\n", - static_folder_path_global); - fprintf(stderr, "\nWorking static dir at: (%s).\n", - static_folder_path_wd); - exit(EXIT_FAILURE); - } - } -} - -/** - * Loads the lore strings from the appropriate lore file. - * @param lore_strings The string array to copy to. - * @param loreKind The kind of lore, used to open the corresponding lore file. - * @see gameloop() - */ -void loadLore(char **lore_strings, int loreKind) -{ - - char static_path[500]; - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - char lore_filename[1000]; - - sprintf(lore_filename, "%s/lore/lore%i.txt", static_path, loreKind); - - FILE *lorefile = fopen(lore_filename, "r"); - if (!lorefile) { - fprintf(stderr, "\nCan't open %s\n", lore_filename); - exit(EXIT_FAILURE); - } - - char *line = NULL; - //size_t len = 0; - //ssize_t read; - //int i = 0; - - // FIXME - // If we ever need this again, we'd have to not depend on getline() for mingw32 - /* - while ((read = getline(&line, &len, lorefile)) != -1) { - log_tag("debug_log.txt","[LORE-LOAD]","Retrieved line of length %zu:", read); - log_tag("debug_log.txt","[LORE-LOAD]","%s", line); - strcpy(lore_strings[i],line); - i++; - } - */ - fclose(lorefile); - if (line) - free(line); -} - -/** - * Takes a path pointer, a roadFork value pointer, a room type pointer, and an integer. - * Depending on GAMEMODE (and eventually roadFork value), sets the room type pointer to a roomClass value. - * @param roadFork_value The pointer value of the roadfork that we must use as result. - * @param room_type The pointer value of the room type to set. - * @param roomsDone The total of rooms completed. - */ -void setRoomType(Path *path, int *roadFork_value, roomClass *room_type, - int roomsDone) -{ - log_tag("debug_log.txt", "[DEBUG]", - "setRoomType(): room type (%i) rooms done (%i)", (int)*room_type, - roomsDone); - switch (GAMEMODE) { - case Standard: { - if ((*roadFork_value >= 0)) { - *room_type = *roadFork_value; - *roadFork_value = -1; - log_tag("debug_log.txt", "[TEST]", - "setRoomType() for ROADFORK"); - } else if ((roomsDone == 1) || (roomsDone % HOMEROOM == 0)) { //Only the first and every nth room will be a HOME room. - //FIXME: why the hell does roomsDone need to start from 1? - *room_type = HOME; - log_tag("debug_log.txt", "[TEST]", "setRoomType() for HOME"); - } else if (roomsDone % BOSSROOM == 0) { - *room_type = BOSS; - } else if (roomsDone % SHOPROOM == 0) { - *room_type = SHOP; - } else if (rand() % 5 == 0) { - *room_type = TREASURE; - } else if (rand() % 4 == 0 && (roomsDone + 2 < path->length)) { - *room_type = ROADFORK; - } else if (*room_type == -1) { - *room_type = ENEMIES; - } - if (G_DEBUG_ON && G_DEBUG_ROOMTYPE_ON > 0) { - log_tag("debug_log.txt", "[DEBUG]", - "setRoomType(): Room debug flag asserted in standard gamemode, room type will always be equal to G_DEBUG_ROOMTYPE (%s).", - stringFromRoom(G_DEBUG_ROOMTYPE)); - *room_type = G_DEBUG_ROOMTYPE; - } - } - break; - case Story: { - if (*roadFork_value >= 0) { //Is this branch needed here? - *room_type = *roadFork_value; - *roadFork_value = -1; - } else if ((roomsDone == 1) || (roomsDone % HOMEROOM == 0)) { //Only the first and every nth room will be a HOME room. - //FIXME: why the hell does roomsDone need to start from 1? - *room_type = HOME; - log_tag("debug_log.txt", "[TEST]", - "story mode, setRoomType() for HOME"); - } else if (roomsDone % BOSSROOM == 0) { - *room_type = BOSS; - } else if (roomsDone % 4 == 0) { - *room_type = SHOP; - } else if (rand() % 20 == 0) { - *room_type = TREASURE; - } else if (*room_type == -1) { - *room_type = ENEMIES; - } - if (G_DEBUG_ON && G_DEBUG_ROOMTYPE_ON > 0) { - log_tag("debug_log.txt", "[DEBUG]", - "setRoomType(): Room debug flag asserted in standard gamemode, room type will always be equal to G_DEBUG_ROOMTYPE (%s).", - stringFromRoom(G_DEBUG_ROOMTYPE)); - *room_type = G_DEBUG_ROOMTYPE; - } - } - break; - default: { - fprintf(stderr, "Unexpected GAMEMODE value: %i\n", GAMEMODE); - exit(EXIT_FAILURE); - } - break; - } - log_tag("debug_log.txt", "[DEBUG]", - "setRoomType(): room type (%i) rooms done (%i)", (int)*room_type, - roomsDone); -} - -/** - * Frees the memory allocated for the passed room pointer. - * @param room The Room pointer to free. - * @see Room - */ -void freeRoom(Room *room) -{ - int room_type = room->class; - - log_tag("debug_log.txt", "[DEBUG-FREE]", "Freeing room desc: (%s).", - room->desc); - //Free room memory - //FIXME: do we have all room descs handled ? - //free(room->desc); - - if (room_type == SHOP) { - /* - for (int i = 0 ; i < room->shop->equipsCount; i++) { - Equip* e = room->shop->equips[i]; - if (e->perksCount > 0) { - for (int j = 0 ; j < e->perksCount; j++) { - Perk* p = e->perks[j]; - free(p); - sprintf(msg,"Freeing %s room (index %i), freed Perk %i for Equip %s.", stringFromRoom(room_type), room->index, j, stringFromEquips(e->class)); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done freeing perks.\n"); - } - sprintf(msg,"Freeing %s room (index %i), freed Equip %s.", stringFromRoom(room_type), room->index, stringFromEquips(e->class)); - free(e); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - } - for (int i = 0 ; i < room->shop->consumablesCount; i++) { - Consumable* c = room->shop->consumables[i]; - free(c); - sprintf(msg,"Freeing %s room (index %i), freed Consumable %i.", stringFromRoom(room_type), room->index, i); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - } - */ - //FIXME: remove all the commented out bs - log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); - } else if (room_type == TREASURE) { - if (room->treasure->class == TREASURE_CONSUMABLE) { - - /* - Consumable* dele = room->treasure->consumable; - sprintf(msg,"Freeing %s room (index %i), freed Consumable %s.\n", stringFromRoom(room_type), room->index, stringFromConsumables(dele->class)); - free(dele); - */ - //FIXME: remove all the commented out bs - log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); - } else if (room->treasure->class == TREASURE_ARTIFACT) { - /* - Artifact* dele = room->treasure->artifact; - sprintf(msg,"Freeing %s room (index %i), freed Artifact %s.\n", stringFromRoom(room_type), room->index, stringFromArtifacts(dele->class)); - free(dele); - */ - log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); - } else if (room->treasure->class == TREASURE_CHEST) { - log_tag("debug_log.txt", "[FIXME]", - "freeRoom: freeing Treasure room, CHEST"); - /* - //FIXME: freeing Treasure Chest here - Chest* chest = room->treasure->chest; - for (int eq_i = 0; eq_i < chest->equipsCount; eq_i++) { - Equip* equip = chest->equips[eq_i]; - for (int p_i = 0 ; p_i < equip->perksCount; p_i++) { - Perk* pk = equip->perks[p_i]; - free(pk); - sprintf(msg,"Freeing %s room (index %i), CHEST: freed Perk %i for Equip %s (%i).", stringFromRoom(room_type), room->index, p_i, stringFromEquips(equip->class), eq_i); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - } - sprintf(msg,"Freeing %s room (index %i), CHEST: freed Equip %s (%i).", stringFromRoom(room_type), room->index, stringFromEquips(equip->class), eq_i); - free(equip); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - } - - for (int i = 0 ; i < chest->consumablesCount; i++) { - Consumable* c = chest->consumables[i]; - free(c); - sprintf(msg,"Freeing %s room (index %i), CHEST: freed Consumable %i.", stringFromRoom(room_type), room->index, i); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - } - sprintf(msg,"Freeing %s room (index %i), freed Chest.\n", stringFromRoom(room_type), room->index); - //free(chest); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - */ - log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); - } - } else if (room_type == ROADFORK) { - /* - Roadfork* rfk = room->roadfork; - free(rfk); - sprintf(msg,"Freeing %s room (index %i), freed Roadfork.\n", stringFromRoom(room_type), room->index); - log_tag("debug_log.txt","[DEBUG-FREE]",msg); - */ - log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); - } - - log_tag("debug_log.txt", "[DEBUG-FREE]", "Freed %s room, index %i.\n", - stringFromRoom(room->class), room->index); - log_tag("debug_log.txt", "[FIXME]", "freeRoom(): done fake free()."); - //free(room); -} - -/** - * Prints an hardcoded title screen. - * @see helapordo_title_string - */ -void printTitle(void) -{ - printf("\n\n\n\n\n"); -#ifndef _WIN32 - red(); -#endif - printf("%s\n", helapordo_title_string); -#ifndef _WIN32 - white(); -#endif -} - -/** - * Prints version string. - */ -void printVersion(void) -{ - printf("%s\n", VERSION); -} - -/** - * Prints formatted version string. - * @param progName The program name string. - */ -void printFormattedVersion(char *progName) -{ - printf("%s v. %s\n", progName, VERSION); -} - -/** - * Prints configuration info. - */ -void hlpd_dbg_features(void) -{ - -#ifdef HELAPORDO_DEBUG_ACCESS - fprintf(stderr,"[HLP] Debug access in enabled\n"); -#else - fprintf(stderr,"[HLP] Debug access in not enabled\n"); -#endif - -#ifdef HELAPORDO_DEBUG_LOG - fprintf(stderr,"[HLP] Debug log is enabled\n"); -#else - fprintf(stderr,"[HLP] Debug log is off\n"); -#endif - -#ifdef ANVIL__helapordo__ -#ifdef INVIL__helapordo__HEADER__ - fprintf(stderr,"[HLP] Built with invil\n"); -#else - fprintf(stderr,"[HLP] Built with amboso\n"); -#endif // INVIL -#else - fprintf(stderr,"[HLP] Built without anvil\n"); -#endif // ANVIL - -#ifdef HELAPORDO_CURSES_BUILD - fprintf(stderr,"[HLP] ncurses build enabled\n"); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else - fprintf(stderr,"[HLP] raylib build enabled\n"); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD -} - -/** - * Prints correct argument syntax for command line invocation. - */ -void usage(char *progname) -{ - fprintf(stderr, "\nUsage: %s [...options] [name] [class]\n", - progname); - fprintf(stderr, "\n [class]\n\n [Knight|Archer|Mage|Assassin]\n"); - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, "\n -R Enable rogue mode\n"); - fprintf(stderr, "\n -s Enable story mode. Deprecated.\n"); - fprintf(stderr, " -l Load a game.\n"); -#ifndef HELAPORDO_DEBUG_ACCESS -#else - fprintf(stderr, "\n -d Enable debug mode\n"); - fprintf(stderr, " -dr Enable forced room.\n"); - fprintf(stderr, " -dE Enable forced enemy.\n"); -#endif - fprintf(stderr, "\n -h Print this help message\n"); - fprintf(stderr, " -T Show a brief tutorial.\n"); - fprintf(stderr, " -G Enable godmode.\n"); - fprintf(stderr, " -X Enable experimental features.\n"); - fprintf(stderr, " -v Prints %s version.\n", progname); - fprintf(stderr, " -V Prints %s build info.\n", progname); - fprintf(stderr, " -a Disable autosave.\n"); - fprintf(stderr, " -L Enable logging.\n"); - fprintf(stderr, " -Q Enable fast quit.\n"); - fprintf(stderr, " -t Test color codes.\n"); -} - -/** - * Takes a filename string, a string headear and a format string. - * Tries logging the message to the passed file if global var G_DEBUG_ON is set. - * @param filename The filename to open. - * @param header The string header for the message to log. - * @param format The format string for message. - */ -void log_tag(char *filename, char *header, const char *format, ...) -{ -#ifndef HELAPORDO_DEBUG_LOG -#else - // Open log file if log flag is set and append to it - if (G_LOG_ON == 1) { - char path_to_debug_file[500]; - char static_path[500]; - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - sprintf(path_to_debug_file, "%s", static_path); - -#ifndef _WIN32 - strncat(path_to_debug_file, "/", 2); -#else - strncat(path_to_debug_file, "\\", 2); -#endif - - strncat(path_to_debug_file, filename, 200); - - //fprintf(stderr, "Using %s as path to debug log.\n", path_to_debug_file); - - FILE *logfile = fopen(path_to_debug_file, "a"); - if (!logfile) { - fprintf(stderr, - "Error opening log file.\n Static path: (%s) Filename : (%s).\n", - static_path, filename); - fprintf(stderr, "Path to debug file was: (%s).", - path_to_debug_file); - fprintf(stderr, "Format was: %s", format); - exit(EXIT_FAILURE); - } - va_list args; - va_start(args, format); - time_t now = time(0); - struct tm *mytime = localtime(&now); - char timeheader[500]; - if (strftime(timeheader, sizeof timeheader, "%X", mytime)) { - fprintf(logfile, "[ %s ] [ %-12.12s ] [", timeheader, header); - vfprintf(logfile, format, args); - fprintf(logfile, "]\n"); - } - va_end(args); - fclose(logfile); - } -#endif -} - -/** - * Takes a OP_res and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see OP_res - * @param r The OP_res. - * @return String corresponding to the OP result. - */ -char *stringFrom_OP_res(OP_res r) -{ - - return opresstrings[r]; -} - -/** - * Takes a saveType and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see saveType - * @param s The saveType value. - * @return String corresponding to the save type. - */ -char *stringFrom_saveType(saveType s) -{ - - return savetypestrings[s]; -} - -/** - * Takes a turnOption_OP and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see turnOption_OP - * @param t The turn choice. - * @return String corresponding to the turn choice. - */ -char *stringFromTurnOP(turnOption_OP t) -{ - - return turnopstrings[t]; -} - -/** - * Takes a foeTurnOption_OP and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see foeTurnOption_OP - * @param ft The turn choice. - * @return String corresponding to the turn choice. - */ -char *stringFromFoeTurnOP(foeTurnOption_OP ft) -{ - return foeturnopstrings[ft]; -} - -/** - * Takes a fightResult fr and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fightResult - * @param fr The fight result value. - * @return String corresponding to the fight result value. - */ -char *stringFrom_fightResult(fightResult fr) -{ - - return fightresultstrings[fr]; -} - -/** - * Takes a fighterStatus and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fighterStatus - * @param s The status. - * @return String corresponding to the status. - */ -char *stringFromStatus(fighterStatus s) -{ - static char *strings[] = { - "Normal", - "Poison", - "Frozen", - "Burned", - "Weak", - "Strong" - }; - - return strings[s]; -} - -/** - * Takes a winconClass and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see winconClass - * @param w The class. - * @return String corresponding to the class. - */ -char *stringFromWinconClass(winconClass w) -{ - - return winconstrings[w]; -} - -/** - * Takes a fighterClass and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fighterClass - * @param f The class. - * @return String corresponding to the class. - */ -char *stringFromClass(fighterClass f) -{ - - return classesstrings[f]; -} - -/** - * Takes a enemyClass and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see enemyClass - * @param e The class. - * @return String corresponding to the class. - */ -char *stringFromEClass(enemyClass e) -{ - - return classenemystrings[e]; -} - -/** - * Takes a bossClass and returns the corresponding string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see bossClass - * @param b The class. - * @return String corresponding to the class. - */ -char *stringFromBossClass(bossClass b) -{ - - return classbossstrings[b]; -} - -/** - * Takes a integer and returns the corresponding consumable string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see consumableClass - * @param c The integer/consumableClass. - * @return String corresponding to the consumable. - */ -char *stringFromConsumables(int c) -{ - - return consumablestrings[c]; -} - -/** - * Takes a integer and returns the corresponding equip string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see equipClass - * @param e The integer/equipClass. - * @return String corresponding to the equip. - */ -char *stringFromEquips(int e) -{ - - return equipstrings[e]; -} - -/** - * Takes a integer and returns the corresponding equipzone string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see Equipzone - * @param z The integer/Equipzone. - * @return String corresponding to the equipzone. - */ -char *stringFromEquipzones(int z) -{ - - return equipzonestrings[z]; -} - -/** - * Takes a integer and returns the corresponding quality string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see quality - * @param q The integer/quality - * @return String corresponding to the quality. - */ -char *stringFromQuality(int q) -{ - - return qualitytrings[q]; -} - -/** - * Takes a integer and returns the corresponding artifact string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see artifactClass - * @param a The integer/artifactClass. - * @return String corresponding to the artifact. - */ -char *stringFromArtifacts(int a) -{ - - return artifactstrings[a]; -} - -/** - * Takes a fighterClass and a specialMove and returns the corresponding name string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fighterClass - * @see specialMove - * @param class The fighterClass. - * @param move The specialMove. - * @return String corresponding to the special move. - */ -char *nameStringFromSpecial(fighterClass class, specialMove move) -{ - return specialsnamestrings[class][(move % (SPECIALSMAX + 1))]; -} - -/** - * Takes a fighterClass and a specialMove and returns the corresponding desc string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fighterClass - * @see specialMove - * @param class The fighterClass. - * @param move The specialMove. - * @return String corresponding to the special move. - */ -char *descStringFromSpecial(fighterClass class, specialMove move) -{ - return specialsdescstrings[class][(move % (SPECIALSMAX + 1))]; -} - -/** - * Takes a fighterClass and a specialMove and returns the corresponding cost by the inner array position, as an integer. - * Correct result is only possible by having the enum values in a consistent order with the integer array. - * @see fighterClass - * @see specialMove - * @param class The fighterClass. - * @param move The specialMove. - * @return int Cost of the corresponding special move. - */ -int costFromSpecial(fighterClass class, specialMove move) -{ - return specialscosts[class][(move % (SPECIALSMAX + 1))]; -} - -/** - * Takes a skillType and returns the corresponding name string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fighterClass - * @see specialMove - * @param class The skillType. - * @return String corresponding to the skillType. - */ -char *nameStringFromSkill(skillType class) -{ - return skillsnamestrings[class]; -} - -/** - * Takes a fighterClass and a specialMove and returns the corresponding desc string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see fighterClass - * @see skillType - * @param class The skillType. - * @return String corresponding to the skillType. - */ -char *descStringFromSkill(skillType class) -{ - return skillsdescstrings[class]; -} - -/** - * Takes a skillType and returns the corresponding cost by the inner array position, as an integer. - * Correct result is only possible by having the enum values in a consistent order with the integer array. - * @see fighterClass - * @see skillType - * @param class The skillType. - * @return int Cost of the corresponding skillType. - */ -int costFromSkill(skillType class) -{ - return skillscosts[class]; -} - -/** - * Takes a integer and returns the corresponding perk name string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see perkClass - * @see Perk - * @param p The integer/perkClass. - * @return String corresponding to the perk name. - */ -char *nameStringFromPerk(int p) -{ - - return perksnamestrings[p]; -} - -/** - * Takes a integer and returns the corresponding perk desc string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see perkClass - * @see Perk - * @param p The integer/perkClass. - * @return String corresponding to the perk desc. - */ -char *descStringFromPerk(int p) -{ - - return perksdescstrings[p]; -} - -/** - * Takes a integer and returns the corresponding treasure desc string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see treasureClass - * @param t The integer/treasureClass. - * @return String corresponding to the treasure desc. - */ -char *descStringFromTreasure(int t) -{ - - return treasuredescstrings[t]; -} - -/** - * Takes a integer and returns the corresponding chest desc string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see chestClass - * @param c The integer/chestClass. - * @return String corresponding to the chest desc. - */ -char *descStringFromChest(int c) -{ - return chestdescstrings[c]; -} - -/** - * Takes a integer and returns the corresponding FoeParty desc string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see foePartyClass - * @param c The integer/foePartyClass. - * @return String corresponding to the FoeParty desc. - */ -char *stringFromFoePartyClass(foePartyClass fp) -{ - return foepartystrings[fp]; -} - -/** - * Takes a integer and returns the corresponding HLP_Region_Type string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see HLP_Region_Type - * @param t The HLP type. - * @return String corresponding to the HLP_Region_Type name. - */ -char *stringFrom_HLP_Region_Type(HLP_Region_Type t) -{ - return hlp_regiontype_strings[t]; -} - -/** - * Takes a integer and returns the corresponding room name string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see roomClass - * @param r The integer/roomClass. - * @return String corresponding to the room name. - */ -char *stringFromRoom(roomClass r) -{ - return roomnamestrings[r]; -} - -/** - * Takes a integer and returns the corresponding gamemode string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see Gamemode - * @param g The integer/Gamemode. - * @return String corresponding to the gamemode. - */ -char *stringFromGamemode(Gamemode g) -{ - return gamemodenamestrings[g]; -} - -/** - * Takes a integer and returns the corresponding floorClass string by the inner array position. - * Correct result is only possible by having the enum values in a consistent order with the string array. - * @see floorClass - * @param fc The integer/floorClass. - * @return String corresponding to the floorClass. - */ -char *stringFromFloorclass(floorClass fc) -{ - return floornamestrings[fc]; -} - -/** - * Takes a Fighter pointer and sets its name value to the string provided on stdin. - * @param player The pointer whose name value will be set. - */ -void scanName(Fighter *player) -{ - char name[50]; - int f; - do { - printf("\n\n\tWhat's your name?\n\n"); - f = scanf("%20s", name); - } while (f >= 21 || f <= 0); - strcpy(player->name, name); -} - -/** - * Prints all the fighterClass values as integers and as strings. - * @see fighterClass - */ -void printClasses(void) -{ - printf("["); - for (int i = 0; i <= CLASSESMAX; i++) { - printf("\t%d)\t%s", i, stringFromClass(i)); - if (i != CLASSESMAX) { - printf("\n"); - } - }; - printf("\t]\n"); -} - -/** - * Asks for an integer on stdin and returns it if it's a valid fighterClass index. - * @see fighterClass - * @see CLASSESMAX - * @return The selected integer, negative for unvalid choices. - */ -int scanClass(void) -{ - int pick = -1; - char c; - while (pick < 0 || pick > CLASSESMAX) { - printf("\nPick a class: (0-%i)\n", CLASSESMAX); - int res = scanf("%1i", &pick); - log_tag("debug_log.txt", "[DEBUG]", "scanClass scanf() res was %i", - res); - res = scanf("%c", &c); - log_tag("debug_log.txt", "[DEBUG]", "scanClass 2 scanf() res was %i", - res); - }; - return pick; -} - -/** - * Takes a Fighter pointer and sets the class value after asking the user for input. - * @see fighterClass - * @see scanClass() - * @param player The pointer whose class value will be set. - */ -void pickClass(Fighter *player) -{ - int pick = -1; - do { - int res = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "pickClass() system(\"clear\") res was (%i)", res); - printf("\nPick a class.\n"); - printClasses(); - pick = scanClass(); - } while (pick < 0); - - player->class = pick; - green(); - printf("\n\n\tClass: %s\n\n", stringFromClass(player->class)); - white(); -} - -/** - * Prints all the winconClass values as integers and as strings. - * @see winconClass - */ -void printWincons(void) -{ - printf("["); - for (int i = 0; i <= WINCON_CLASS_MAX; i++) { - printf("\t%d)\t%s", i, stringFromWinconClass(i)); - if (i != WINCON_CLASS_MAX) { - printf("\n"); - } - }; - printf("\t]\n"); -} - -/** - * Asks for an integer on stdin and returns it if it's a valid winconClass index. - * @see winconClass - * @see WINCON_CLASS_MAX - * @return The selected integer, negative for unvalid choices. - */ -int scanWincon(void) -{ - int pick = -1; - char c; - while (pick < 0 || pick > WINCON_CLASS_MAX) { - printf("\nPick a win condition: (0-%i)\n", WINCON_CLASS_MAX); - int res = scanf("%1i", &pick); - log_tag("debug_log.txt", "[DEBUG]", "scanWincon() scanf() res was (%i)", - res); - res = scanf("%c", &c); - log_tag("debug_log.txt", "[DEBUG]", - "scanWincon() 2 scanf() res was (%i)", res); - }; - return pick; -} - -/** - * Takes a Fighter pointer and sets the name value after asking the user for input. - * @see fighterClass - * @see scanName() - * @param player The pointer whose name value will be set. - */ -void pickName(Fighter *player) -{ - scanName(player); - red(); - printf("\n\n\tName: %s\n\n", player->name); - white(); -} - -/** - * Takes a Wincon pointer and sets its class after asking the user for input. - * @see winconClass - * @see scanWincon() - * @param w The wincon pointer whose class value will be set. - */ -void pickWincon(Wincon *w) -{ - int pick = -1; - do { - int res = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "pickWincon() system(\"clear\") res was (%i)", res); - printf("\nPick a win condition.\n"); - printWincons(); - pick = scanWincon(); - } while (pick < 0); - - w->class = pick; - green(); - printf("\n\n\tWincon: %s\n\n", stringFromWinconClass(w->class)); - white(); -} - -/** - * Takes two Fighter pointers, with all their fields already allocated, and copies all valaues from source to dest. - * @see Fighter - * @param source The Fighter pointer to be copied. - * @param dest The Fighter pointer to copy to. - */ -void copy_fighter(Fighter *source, Fighter *dest) -{ - - strcpy(source->name, dest->name); - dest->class = source->class; - dest->hp = source->hp; - dest->atk = source->atk; - dest->def = source->def; - dest->vel = source->vel; - dest->level = source->level; - dest->luck = source->luck; - dest->totalxp = source->totalxp; - dest->currentlevelxp = source->currentlevelxp; - dest->totallevelxp = source->totallevelxp; - dest->totalhp = source->totalhp; - dest->status = source->status; - - dest->energy = source->energy; - dest->totalenergy = source->totalenergy; - for (int i = 0; i < SPECIALSMAX + 1; i++) { - dest->specials[i] = source->specials[i]; - } - - for (int i = 0; i < COUNTERSMAX + 1; i++) { - dest->counters[i] = source->counters[i]; - } - dest->turnboost_atk = source->turnboost_atk; - dest->turnboost_def = source->turnboost_def; - dest->turnboost_vel = source->turnboost_vel; - dest->turnboost_enr = source->turnboost_enr; - - dest->perksCount = source->perksCount; - for (int i = 0; i < PERKSMAX + 1; i++) { - dest->perks[i] = source->perks[i]; - } - - for (int i = 0; i < EQUIPZONES + 1; i++) { - dest->equipslots[i] = source->equipslots[i]; - } - for (int i = 0; i < EQUIPSBAGSIZE + 1; i++) { - dest->equipsBag[i] = source->equipsBag[i]; - } - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - dest->consumablesBag[i] = source->consumablesBag[i]; - } - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - dest->artifactsBag[i] = source->artifactsBag[i]; - } - - dest->equipsBagOccupiedSlots = source->equipsBagOccupiedSlots; - dest->earliestBagSlot = source->earliestBagSlot; - - dest->permboost_atk = source->permboost_atk; - dest->permboost_def = source->permboost_def; - dest->permboost_vel = source->permboost_vel; - dest->permboost_enr = source->permboost_enr; - - dest->equipboost_atk = source->equipboost_atk; - dest->equipboost_def = source->equipboost_def; - dest->equipboost_vel = source->equipboost_vel; - dest->equipboost_enr = source->equipboost_enr; - - dest->stats = source->stats; - dest->balance = source->balance; -} diff --git a/src/helapordo.c b/src/helapordo.c deleted file mode 100644 index 5e90286c..00000000 --- a/src/helapordo.c +++ /dev/null @@ -1,14961 +0,0 @@ -// jgabaut @ github.com/jgabaut -// SPDX-License-Identifier: GPL-3.0-only -/* - Copyright (C) 2022-2024 jgabaut - - 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, version 3 of the License. - - 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 "helapordo.h" - -/** - * Takes a turnOption_OP and a pointer to a turnOP_args struct. - * Logs a warning for any NULL field in the struct. - * Performs the defined turn operation, before returning an OP_res. - * @param op The kind of operation to do. - * @param args Struct containing needed args for current operation. Can have some fields uninitialised, if not relevant to requested turnOP. - * @param kls The Koliseo used for allocations. - * @param t_kls The Koliseo_Temp used for temporary allocations. - * @return An OP_res representing result of turn option operation. - * @see turnOP_args - * @see turnOption_OP - * @see OP_res - */ -OP_res turnOP(turnOption_OP op, turnOP_args *args, Koliseo *kls, - Koliseo_Temp *t_kls) -{ - - OP_res res = INVALID_OP; - - Gamestate *gmst = args->gmst; - if (gmst == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(gmst) was NULL"); - Fighter *actor = args->actor; - if (actor == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(actor) was NULL"); - Path *path = args->path; - if (path == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(path) was NULL"); - Room *room = args->room; - if (room == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(room) was NULL"); - loadInfo *load_info = args->load_info; - if (load_info == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(load_info) was NULL"); - Enemy *enemy = args->enemy; - if (enemy == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(enemy) was NULL"); - Boss *boss = args->boss; - if (boss == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(boss) was NULL"); - FILE *save_file = args->save_file; - if (save_file == NULL) - log_tag("debug_log.txt", "[WARN]", "turnOP_args->(save_file) was NULL"); -#ifdef HELAPORDO_CURSES_BUILD - WINDOW *notify_win = args->notify_win; -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else - Rectangle *notify_win = args->notify_win; -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - if (notify_win == NULL) - log_tag("debug_log.txt", "[WARN]", - "turnOP_args->(notify_win) was NULL"); - foeTurnOption_OP foe_op = args->foe_op; - if (foe_op == FOE_OP_INVALID) { - log_tag("debug_log.txt", "[WARN]", - "turnOP_args->(foe_op) was FOE_OP_INVALID"); - } else if (foe_op < 0 || foe_op > FOETURNOP_MAX) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(foe_op) was invalid: [%i]", foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - skillType skill = args->picked_skill; - if (skill < 0 || skill >= SKILLSTOTAL) { - log_tag("debug_log.txt", "[WARN]", - "turnOP_args->(picked_skill) was invalid: [%i]", skill); - } - - int isBoss = -1; - int room_index = -1; - int enemy_index = -1; - - //Log operation code - log_OP(op); - switch (op) { - case OP_INVALID: { - //No_OP, but unexpected - log_tag("debug_log.txt", "[ERROR]", - "Done turnOP() on an OP_INVALID opcode."); - } - break; - case OP_NEW_GAME: { - res = NO_OP; - } - break; - case OP_LOAD_GAME: { - if (load_info == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(load_info) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - load_info->is_new_game = 0; - res = OP_OK; - } - break; - case OP_LOAD_ENEMYROOM: { - if (load_info == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(load_info) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - load_info = args->load_info; - if (load_info == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "load_info was NULL after load_info = args->load_info: in turnOP(OP_LOAD_ENEMYROOM"); - return res; - } - save_file = args->save_file; - - if (save_file == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(save_file) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - int *ptr_to_loaded_enemy_index = &(load_info->enemy_index); - log_tag("debug_log.txt", "[TURNOP]", - "*(ptr_to_loaded_enemy_index) == [%i]", - *ptr_to_loaded_enemy_index); - int *ptr_to_loaded_roomtotalenemies = - (load_info->ptr_to_roomtotalenemies); - log_tag("debug_log.txt", "[TURNOP]", - "*(ptr_to_loaded_roomtotalenemies) == [%i]", - *ptr_to_loaded_roomtotalenemies); - int *ptr_to_loaded_roomindex = (load_info->ptr_to_roomindex); - log_tag("debug_log.txt", "[TURNOP]", - "*(ptr_to_loaded_roomindex) == [%i]", - *ptr_to_loaded_roomindex); - int *tot_foes = &(load_info->total_foes); - log_tag("debug_log.txt", "[TURNOP]", "*(tot_foes) == [%i]", - *tot_foes); - int *ptr_to_done_loading = &(load_info->done_loading); - log_tag("debug_log.txt", "[TURNOP]", "*(done_loading) == [%i]", - *ptr_to_done_loading); - res = - handleLoadgame_Enemies(save_file, actor, path, - load_info->loaded_enemy, - ptr_to_loaded_enemy_index, - ptr_to_loaded_roomtotalenemies, - ptr_to_loaded_roomindex, tot_foes, - ptr_to_done_loading, kls); - //Log end of operation - log_tag("debug_log.txt", "[TURNOP]", - "Done operation: [%s] res: [%s (%i)]", stringFromTurnOP(op), - stringFrom_OP_res(res), res); - - log_tag(OPS_LOGFILE, "[RES]", "res: [%s (%i)]", - stringFrom_OP_res(res), res); - - return res; - } - break; - case OP_LOAD_HOMEROOM: { - if (load_info == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(load_info) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - load_info = args->load_info; - if (load_info == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "load_info was NULL after load_info = args->load_info: in turnOP(OP_LOAD_HOMEROOM"); - return res; - } - save_file = args->save_file; - - if (save_file == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(save_file) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - if (load_info->ptr_to_roomindex == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "load_info->ptr_to_roomindex was NULL in turnOP(OP_LOAD_HOMEROOM"); - return res; - } - int *ptr_to_loaded_roomindex = (load_info->ptr_to_roomindex); - if (ptr_to_loaded_roomindex == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "ptr_to_loaded_roomindex was NULL in turnOP(OP_LOAD_HOMEROOM"); - return res; - } - log_tag("debug_log.txt", "[TURNOP]", - "*(ptr_to_loaded_roomindex) == [%i]", - *ptr_to_loaded_roomindex); - - int *ptr_to_done_loading = &(load_info->done_loading); - log_tag("debug_log.txt", "[TURNOP]", "*(done_loading) == [%i]", - *ptr_to_done_loading); - res = - handleLoadgame_Home(save_file, actor, path, - ptr_to_loaded_roomindex, - ptr_to_done_loading, kls); - //Log end of operation - log_tag("debug_log.txt", "[TURNOP]", - "Done operation: [%s] res: [%s (%i)]", stringFromTurnOP(op), - stringFrom_OP_res(res), res); - - log_tag(OPS_LOGFILE, "[RES]", "res: [%s (%i)]", - stringFrom_OP_res(res), res); - - return res; - } - break; - case OP_FIGHT: { - if (notify_win == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Notification WINDOW pointer was null in turnOP(OP_FIGHT)"); - exit(EXIT_FAILURE); - } - if (room == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Room pointer was null in turnOP(OP_FIGHT)"); - exit(EXIT_FAILURE); - } - if (foe_op == FOE_OP_INVALID) { - log_tag("debug_log.txt", "[CRITICAL]", - "foe_op was FOE_OP_INVALID in turnOP(OP_FIGHT)"); - exit(EXIT_FAILURE); - } else if (foe_op < 0 || foe_op > FOETURNOP_MAX) { - log_tag("debug_log.txt", "[CRITICAL]", - "foe_op was invalid in turnOP(OP_FIGHT): [%i]", foe_op); - exit(EXIT_FAILURE); - } - room_index = room->index; - if (room->class == ENEMIES && enemy == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Enemy pointer was null in turnOP(OP_FIGHT) for ENEMIES room."); - exit(EXIT_FAILURE); - } else if (room->class == BOSS && boss == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Boss pointer was null in turnOP(OP_FIGHT) for BOSS room."); - exit(EXIT_FAILURE); - } else if (room->class != ENEMIES && room->class != BOSS) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid room class in turnOP(OP_FIGHT): (%s [%i])", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - } - switch (room->class) { - case ENEMIES: { - enemy_index = enemy->index; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_FIGHT), isBoss == 0", - enemy->index); - isBoss = 0; - res = - OP_res_from_fightResult(defer_fight_enemy - (actor, enemy, foe_op, - notify_win, kls)); - } - break; - case BOSS: { - enemy_index = 0; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (0) (OP_FIGHT), isBoss == 1"); - isBoss = 1; - res = - OP_res_from_fightResult(defer_fight_boss - (actor, boss, path, foe_op, - notify_win, kls)); - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid room value in turnOP(OP_FIGHT): [%s (%i)]", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - - } - break; - } - } - break; - case OP_SPECIAL: { - if (room == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Room pointer was null in turnOP(OP_SPECIAL)"); - exit(EXIT_FAILURE); - } - room_index = room->index; - if (room->class == ENEMIES && enemy == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Enemy pointer was null in turnOP(OP_SPECIAL) for ENEMIES room."); - exit(EXIT_FAILURE); - } else if (room->class == BOSS && boss == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Boss pointer was null in turnOP(OP_SPECIAL) for BOSS room."); - exit(EXIT_FAILURE); - } else if (room->class != ENEMIES && room->class != BOSS) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid room class in turnOP(OP_SPECIAL): (%s [%i])", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - } - switch (room->class) { - case ENEMIES: { - enemy_index = enemy->index; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_SPECIAL), isBoss == 0", - enemy->index); - isBoss = 0; - } - break; - case BOSS: { - enemy_index = 0; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (0) (OP_SPECIAL), isBoss == 1"); - isBoss = 1; - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid room value in turnOP(OP_SPECIAL): [%s (%i)]", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - - } - } - handleSpecials(actor, enemy, boss, path, room_index, enemy_index, - isBoss); - res = OP_OK; - } - break; - case OP_CONSUMABLE: { - if (room == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Room pointer was null in turnOP(OP_CONSUMABLE)"); - exit(EXIT_FAILURE); - } - room_index = room->index; - if (room->class == ENEMIES && enemy == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Enemy pointer was null in turnOP(OP_CONSUMABLE) for ENEMIES room."); - exit(EXIT_FAILURE); - } else if (room->class == BOSS && boss == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Boss pointer was null in turnOP(OP_CONSUMABLE) for BOSS room."); - exit(EXIT_FAILURE); - } else if (room->class != ENEMIES && room->class != BOSS) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid room class in turnOP(OP_CONSUMABLE): (%s [%i])", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - } - switch (room->class) { - case ENEMIES: { - enemy_index = enemy->index; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_CONSUMABLE), isBoss == 0", - enemy->index); - isBoss = 0; - } - break; - case BOSS: { - enemy_index = 0; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (0) (OP_CONSUMABLE), isBoss == 1"); - isBoss = 1; - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid room value in turnOP(OP_CONSUMABLE): [%s (%i)]", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - - } - } - handleConsumables(actor, enemy, boss, isBoss); - res = OP_OK; - } - break; - case OP_SAVE: { - if (GAMEMODE == Rogue) { - log_tag("debug_log.txt", "[WARN]", - "GAMEMODE was [Rogue] in turnOP(OP_SAVE)"); - res = NO_OP; - break; - } - if (save_file == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "save_file pointer was null in turnOP(OP_SAVE)"); - exit(EXIT_FAILURE); - } - if (load_info == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(load_info) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - if (room == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Room pointer was null in turnOP(OP_SAVE)"); - exit(EXIT_FAILURE); - } - room_index = room->index; - if (room->class == ENEMIES && enemy == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Enemy pointer was null in turnOP(OP_SAVE) for ENEMIES room."); - exit(EXIT_FAILURE); - } else if (room->class == BOSS && boss == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Boss pointer was null in turnOP(OP_SAVE) for BOSS room."); - exit(EXIT_FAILURE); - } - - if ((room->class != ENEMIES) && (room->class != HOME)) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid room class in turnOP(OP_SAVE): (%s [%i])", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - } - - switch (room->class) { - case ENEMIES: { - enemy_index = enemy->index; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_SAVE), isBoss == 0", - enemy->index); - isBoss = 0; - load_info->save_type = ENEMIES_SAVE; - log_tag("debug_log.txt", "[TURNOP]", - "Setting save_type to ENEMIES_SAVE. [%s]", - stringFrom_saveType(load_info->save_type)); - } - break; - case BOSS: { - enemy_index = 0; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (0) (OP_SAVE), isBoss == 1"); - isBoss = 1; - } - break; - case HOME: { - enemy_index = -1; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (-1) (OP_SAVE), isBoss == -1"); - isBoss = -1; - load_info->save_type = HOME_SAVE; - log_tag("debug_log.txt", "[TURNOP]", - "Setting save_type to HOME_SAVE. [%s]", - stringFrom_saveType(load_info->save_type)); - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid room value in turnOP(OP_SAVE): [%s (%i)]", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - - } - } - switch (load_info->save_type) { - case ENEMIES_SAVE: { - res = - handleSave_Enemies(save_file, actor, path, enemy, - enemy_index, room->enemyTotal, - room_index); - } - break; - case HOME_SAVE: { - res = handleSave_Home(save_file, actor, path, room_index); - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid save_type value in turnOP(OP_SAVE): (%i)", - (int)load_info->save_type); - exit(EXIT_FAILURE); - } - break; - } - } - break; - case OP_DEBUG: { - if (gmst == NULL) { - log_tag("debug_log.txt", "[WARN]", - "Gamestate pointer was null in turnOP(OP_DEBUG)"); - exit(EXIT_FAILURE); - } - if (room == NULL) { - log_tag("debug_log.txt", "[WARN]", - "Room pointer was null in turnOP(OP_DEBUG)"); - exit(EXIT_FAILURE); - } - room_index = room->index; - if (room->class == ENEMIES && enemy == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Enemy pointer was null in turnOP(OP_DEBUG) for ENEMIES room."); - exit(EXIT_FAILURE); - } else if (room->class == BOSS && boss == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Boss pointer was null in turnOP(OP_DEBUG) for BOSS room."); - exit(EXIT_FAILURE); - } - - switch (room->class) { - case HOME: { - enemy_index = -1; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_DEBUG), isBoss == -1", - enemy_index); - isBoss = -1; - log_tag("debug_log.txt", "[TURNOP]", - "Doing endwin() before debug_generic()"); - endwin(); - debug_generic(gmst, actor, path, room_index, kls, t_kls); - res = OP_OK; - } - break; - case ENEMIES: { - enemy_index = enemy->index; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_DEBUG), isBoss == 0", - enemy->index); - isBoss = 0; - debug_enemies_room(gmst, room, actor, enemy, path, - room_index, enemy_index, kls, t_kls); - res = OP_OK; - } - break; - case BOSS: { - enemy_index = 0; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (0) (OP_DEBUG), isBoss == 1"); - isBoss = 1; - log_tag("debug_log.txt", "[TURNOP]", - "Doing endwin() before debug_generic()"); - endwin(); - debug_generic(gmst, actor, path, room_index, kls, t_kls); - res = OP_OK; - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid room value in turnOP(OP_DEBUG): [%s (%i)]", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - } - } - } - break; - case OP_EQUIPS: { - if (actor == NULL || path == NULL) { - if (actor == NULL) - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(actor) was NULL"); - if (path == NULL) - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(path) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - handleEquips(actor, path); - res = OP_OK; - }; - break; - case OP_PERKS: { - if (actor == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(actor) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - printActivePerks(actor); - res = OP_OK; - } - break; - case OP_STATS: { - if (actor == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(actor) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - handleStats(actor); - res = OP_OK; - } - break; - case OP_ARTIFACTS: { - if (actor == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "turnOP_args->(actor) was NULL"); - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - return res; - } - handleArtifacts(actor); - res = OP_OK; - } - break; - case OP_EXPLORE: { - log_tag("debug_log.txt", "[DEBUG]", "Going to explore!"); - //The free of args should be done after the OP; in handleRoom_Home() - res = NO_OP; - } - break; - case OP_QUIT: { - quit(actor, room, load_info, t_kls); - //FIXME - //We can't free the turnOP_args, can we? - //free(args); - log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); - } - break; - case OP_SKILL: { - - log_tag("debug_log.txt", "[DEBUG]", "OP_SKILL"); - - res = NO_OP; - - if (notify_win == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Notification WINDOW pointer was null in turnOP(OP_SKILL)"); - exit(EXIT_FAILURE); - } - if (room == NULL) { - log_tag("debug_log.txt", "[CRITICAL]", - "Room pointer was null in turnOP(OP_SKILL)"); - exit(EXIT_FAILURE); - } - if (foe_op == FOE_OP_INVALID) { - log_tag("debug_log.txt", "[CRITICAL]", - "foe_op was FOE_OP_INVALID in turnOP(OP_SKILL)"); - exit(EXIT_FAILURE); - } else if (foe_op < 0 || foe_op > FOETURNOP_MAX) { - log_tag("debug_log.txt", "[CRITICAL]", - "foe_op was invalid in turnOP(OP_SKILL): [%i]", foe_op); - exit(EXIT_FAILURE); - } - if (skill < 0 || skill > SKILLSTOTAL) { - log_tag("debug_log.txt", "[CRITICAL]", - "skill was invalid in turnOP(OP_SKILL): [%i]", skill); - exit(EXIT_FAILURE); - } - room_index = room->index; - if (room->class == ENEMIES && enemy == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Enemy pointer was null in turnOP(OP_SKILL) for ENEMIES room."); - exit(EXIT_FAILURE); - } else if (room->class == BOSS && boss == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "Boss pointer was null in turnOP(OP_SKILL) for BOSS room."); - exit(EXIT_FAILURE); - } else if (room->class != ENEMIES && room->class != BOSS) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid room class in turnOP(OP_SKILL): (%s [%i])", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - } - switch (room->class) { - case ENEMIES: { - enemy_index = enemy->index; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (%i) (OP_SKILL), isBoss == 0", - enemy->index); - isBoss = 0; - //TODO - //Implement the missing function to wrap skill usage and foe op - res = OP_res_from_fightResult(defer_skill_enemy(actor, enemy, skill, foe_op, notify_win, kls)); - } - break; - case BOSS: { - enemy_index = 0; - log_tag("debug_log.txt", "[TURNOP]", - "Setting enemy_index to (0) (OP_SKILL), isBoss == 1"); - isBoss = 1; - //TODO - //Implement the missing function to wrap skill usage and foe op - res = OP_res_from_fightResult(defer_skill_boss(actor, boss, skill, path, foe_op, notify_win, kls)); - } - break; - default: { - log_tag("debug_log.txt", "[TURNOP]", - "Invalid room value in turnOP(OP_FIGHT): [%s (%i)]", - stringFromRoom(room->class), room->class); - exit(EXIT_FAILURE); - - } - break; - } - } - break; - default: { - log_tag(OPS_LOGFILE, "[ERROR]", "Invalid OP in turnOP()"); - log_tag("debug_log.txt", "[ERROR]", "Invalid OP in turnOP()"); - } - break; - } - - //Log end of operation - log_tag("debug_log.txt", "[TURNOP]", "Done operation: [%s] res: [%s (%i)]", - stringFromTurnOP(op), stringFrom_OP_res(res), res); - - log_tag(OPS_LOGFILE, "[RES]", "res: [%s (%i)]", stringFrom_OP_res(res), - res); - - return res; -} - -fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, WINDOW * notify_win, Koliseo * kls) -{ - - return FIGHTRES_NO_DMG; -} - -fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, WINDOW * notify_win, Koliseo * kls) -{ - - return FIGHTRES_NO_DMG; -} - -//TODO Drop dead code -/* - * Takes an integer, a callback_void_t pointer function and a Fighter holding the array for the callback registration. - * Not working as of v0.5.2. - * Registers the pointer to the function pointer array for counter callback. - * @see Turncounter - * @param index An integer. - * @param ptr A pointer to function of type callback_void_t. - * @param f The fighter pointer holding the callback array. - * -void register_counter_callback(int index, callback_void_t ptr, Fighter* f) { - f->callback_counter_ptrs[index] = ptr; -} -*/ - -//Status effect functions - -/** - * Takes a Fighter pointer and resets its status value to Normal. - * @see Fighter - * @see fighterStatus - * @param f The pointer whose status value will be reset. - */ -void resetFighterStatus(Fighter *f) -{ - f->status = Normal; -} - -/** - * Takes a Enemy pointer and resets its status value to Normal. - * @see Enemy - * @see fighterStatus - * @param e The pointer whose status value will be reset. - */ -void resetEnemyStatus(Enemy *e) -{ - e->status = Normal; -} - -/** - * Takes a Boss pointer and resets its status value to Normal. - * @see Boss - * @see fighterStatus - * @param b The pointer whose status value will be reset. - */ -void resetBossStatus(Boss *b) -{ - b->status = Normal; -} - -/** - * Takes a fighterStatus and returns the corresponding effect_fun pointer for the function relating to the status. - * @see fighterStatus - * @see effect_fun - * @param status The fighterStatus that the caller needs to match to a effect_fun pointer. - * @return The effect_fun pointer related to the status. - */ -effect_fun getStatusCounterFun(fighterStatus status) -{ - switch (status) { - //case Normal: { - default: { - return &resetFighterStatus; - } - break; - }; -} - -/** - * Takes a fighterStatus and returns the corresponding effect_e_fun pointer for the function relating to the status. - * @see fighterStatus - * @see effect_e_fun - * @param status The fighterStatus that the caller needs to match to a effect_e_fun pointer. - * @return The effect_e_fun pointer related to the status. - */ -effect_e_fun getStatusCounterEnemyFun(fighterStatus status) -{ - switch (status) { - //case Normal: { - default: { - return &resetEnemyStatus; - } - break; - }; -} - -/** - * Takes a fighterStatus and returns the corresponding effect_e_fun pointer for the function relating to the status. - * @see fighterStatus - * @see effect_e_fun - * @param status The fighterStatus that the caller needs to match to a effect_e_fun pointer. - * @return The effect_e_fun pointer related to the status. - */ -effect_b_fun getStatusCounterBossFun(fighterStatus status) -{ - switch (status) { - //case Normal: { - default: { - return &resetBossStatus; - } - break; - }; -} - -//Stat boost functions - -/** - * Takes a Fighter pointer and an integer, used to set the turnboost_atk value at the pointer. - * @see Fighter - * @see Turncounter - * @param f The Fighter pointer whose turnboost_atk value will be set. - * @param boost The value that will be set. - */ -void set_turnboost_atk(Fighter *f, int boost) -{ - //Straight addition of the boost - f->turnboost_atk = boost; -} - -/** - * Takes a Fighter pointer and an integer, used to set the turnboost_def value at the pointer. - * @see Fighter - * @see Turncounter - * @param f The Fighter pointer whose turnboost_def value will be set. - * @param boost The value that will be set. - */ -void set_turnboost_def(Fighter *f, int boost) -{ - //Straight addition of the boost - f->turnboost_def = boost; -} - -/** - * Takes a Fighter pointer and an integer, used to set the turnboost_vel value at the pointer. - * @see Fighter - * @see Turncounter - * @param f The Fighter pointer whose turnboost_vel value will be set. - * @param boost The value that will be set. - */ -void set_turnboost_vel(Fighter *f, int boost) -{ - //Straight addition of the boost - f->turnboost_vel = boost; -} - -/** - * Takes a Fighter pointer and an integer, used to set the turnboost_enr value at the pointer. - * @see Fighter - * @see Turncounter - * @param f The Fighter pointer whose turnboost_enr value will be set. - * @param boost The value that will be set. - */ -void set_turnboost_enr(Fighter *f, int boost) -{ - //Straight addition of the boost - f->turnboost_enr = boost; -} - -/** - * Takes a Enemy pointer and an integer, used to set the turnboost_atk value at the pointer. - * @see Enemy - * @see Turncounter - * @param e The Enemy pointer whose turnboost_atk value will be set. - * @param boost The value that will be set. - */ -void set_enemy_turnboost_atk(Enemy *e, int boost) -{ - //Straight addition of the boost - e->turnboost_atk = boost; -} - -/** - * Takes a Enemy pointer and an integer, used to set the turnboost_def value at the pointer. - * @see Enemy - * @see Turncounter - * @param e The Enemy pointer whose turnboost_def value will be set. - * @param boost The value that will be set. - */ -void set_enemy_turnboost_def(Enemy *e, int boost) -{ - //Straight addition of the boost - e->turnboost_def = boost; -} - -/** - * Takes a Enemy pointer and an integer, used to set the turnboost_vel value at the pointer. - * @see Enemy - * @see Turncounter - * @param e The Enemy pointer whose turnboost_vel value will be set. - * @param boost The value that will be set. - */ -void set_enemy_turnboost_vel(Enemy *e, int boost) -{ - //Straight addition of the boost - e->turnboost_vel = boost; -} - -/** - * Takes a Enemy pointer and an integer, used to set the turnboost_enr value at the pointer. - * @see Enemy - * @see Turncounter - * @param e The Enemy pointer whose turnboost_enr value will be set. - * @param boost The value that will be set. - */ -void set_enemy_turnboost_enr(Enemy *e, int boost) -{ - //Straight addition of the boost - e->turnboost_enr = boost; -} - -/** - * Takes a Boss pointer and an integer, used to set the turnboost_atk value at the pointer. - * @see Boss - * @see Turncounter - * @param b The Boss pointer whose turnboost_atk value will be set. - * @param boost The value that will be set. - */ -void set_boss_turnboost_atk(Boss *b, int boost) -{ - //Straight addition of the boost - b->turnboost_atk = boost; -} - -/** - * Takes a Boss pointer and an integer, used to set the turnboost_def value at the pointer. - * @see Boss - * @see Turncounter - * @param b The Boss pointer whose turnboost_def value will be set. - * @param boost The value that will be set. - */ -void set_boss_turnboost_def(Boss *b, int boost) -{ - //Straight addition of the boost - b->turnboost_def = boost; -} - -/** - * Takes a Boss pointer and an integer, used to set the turnboost_vel value at the pointer. - * @see Boss - * @see Turncounter - * @param b The Boss pointer whose turnboost_vel value will be set. - * @param boost The value that will be set. - */ -void set_boss_turnboost_vel(Boss *b, int boost) -{ - //Straight addition of the boost - b->turnboost_vel = boost; -} - -/** - * Takes a Boss pointer and an integer, used to set the turnboost_enr value at the pointer. - * @see Boss - * @see Turncounter - * @param b The Boss pointer whose turnboost_enr value will be set. - * @param boost The value that will be set. - */ -void set_boss_turnboost_enr(Boss *b, int boost) -{ - //Straight addition of the boost - b->turnboost_enr = boost; -} - -/** - * Takes a FoeParty pointer and an integer, used to set the turnboost_atk value at the pointer. - * @see FoeParty - * @see Turncounter - * @param fp The FoeParty pointer whose turnboost_atk value will be set. - * @param boost The value that will be set. - */ -void set_foeparty_turnboost_atk(FoeParty *fp, int boost) -{ - //Straight addition of the boost - fp->turnboost_atk = boost; -} - -/** - * Takes a FoeParty pointer and an integer, used to set the turnboost_def value at the pointer. - * @see FoeParty - * @see Turncounter - * @param fp The FoeParty pointer whose turnboost_def value will be set. - * @param boost The value that will be set. - */ -void set_foeparty_turnboost_def(FoeParty *fp, int boost) -{ - //Straight addition of the boost - fp->turnboost_def = boost; -} - -/** - * Takes a FoeParty pointer and an integer, used to set the turnboost_vel value at the pointer. - * @see FoeParty - * @see Turncounter - * @param fp The FoeParty pointer whose turnboost_vel value will be set. - * @param boost The value that will be set. - */ -void set_foeparty_turnboost_vel(FoeParty *fp, int boost) -{ - //Straight addition of the boost - fp->turnboost_vel = boost; -} - -/** - * Takes a FoeParty pointer and an integer, used to set the turnboost_enr value at the pointer. - * @see FoeParty - * @see Turncounter - * @param fp The FoeParty pointer whose turnboost_enr value will be set. - * @param boost The value that will be set. - */ -void set_foeparty_turnboost_enr(FoeParty *fp, int boost) -{ - //Straight addition of the boost - fp->turnboost_atk = boost; -} - -//Counter callback getters - -/** - * Takes a Stat and returns the corresponding boost_fun pointer for the function relating to the stat. - * @see Stat - * @see boost_fun - * @param s The Stat that the caller needs to match to a boost_fun pointer. - * @return The boost_fun pointer related to the stat. - */ -boost_fun getStatBoostCounterFun(Stat s) -{ - - switch (s) { - case ATK: { - return &set_turnboost_atk; - } - break; - case DEF: { - return &set_turnboost_def; - } - break; - case VEL: { - return &set_turnboost_vel; - } - break; - case ENR: { - return &set_turnboost_enr; - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Invalid stat value in getStatBoostCounterFun()"); - exit(EXIT_FAILURE); - } - break; - }; -} - -/** - * Takes a Stat and returns the corresponding boost_e_fun pointer for the function relating to the stat. - * @see Stat - * @see boost_e_fun - * @param s The Stat that the caller needs to match to a boost_e_fun pointer. - * @return The boost_e_fun pointer related to the stat. - */ -boost_e_fun getStatBoostCounterEnemyFun(Stat s) -{ - - switch (s) { - case ATK: { - return &set_enemy_turnboost_atk; - } - break; - case DEF: { - return &set_enemy_turnboost_def; - } - break; - case VEL: { - return &set_enemy_turnboost_vel; - } - break; - case ENR: { - return &set_enemy_turnboost_enr; - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Invalid stat value in getStatBoostCounterEnemyFun()"); - exit(EXIT_FAILURE); - } - break; - }; -} - -/** - * Takes a Stat and returns the corresponding boost_b_fun pointer for the function relating to the stat. - * @see Stat - * @see boost_b_fun - * @param s The Stat that the caller needs to match to a boost_b_fun pointer. - * @return The boost_b_fun pointer related to the stat. - */ -boost_b_fun getStatBoostCounterBossFun(Stat s) -{ - - switch (s) { - case ATK: { - return &set_boss_turnboost_atk; - } - break; - case DEF: { - return &set_boss_turnboost_def; - } - break; - case VEL: { - return &set_boss_turnboost_vel; - } - break; - case ENR: { - return &set_boss_turnboost_enr; - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Invalid stat value in getStatBoostCounterBossFun()"); - exit(EXIT_FAILURE); - } - break; - }; -} - -/** - * Takes a Stat and returns the corresponding boost_fp_fun pointer for the function relating to the stat. - * @see Stat - * @see boost_fp_fun - * @param s The Stat that the caller needs to match to a boost_fp_fun pointer. - * @return The boost_fp_fun pointer related to the stat. - */ -boost_fp_fun get_StatBoostCounter_FoeParty_Fun(Stat s) -{ - - switch (s) { - case ATK: { - return &set_foeparty_turnboost_atk; - } - break; - case DEF: { - return &set_foeparty_turnboost_def; - } - break; - case VEL: { - return &set_foeparty_turnboost_vel; - } - break; - case ENR: { - return &set_foeparty_turnboost_enr; - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Invalid stat value in getStatBoostCounter_FoeParty_Fun()"); - exit(EXIT_FAILURE); - } - break; - }; -} - -/** - * Takes a Fighter pointer and prepares its perks field by allocating all the Perk accounted in perkClass. - * Perks are initialised using the ordering of perkClass. - * @see Fighter - * @see Perk - * @see perkClass - * @see PERKSMAX - * @param f The Fighter pointer whose perks field will be initialised. - * @param kls The Koliseo used for allocation. - */ -void initPerks(Fighter *f, Koliseo *kls) -{ - f->perksCount = 0; - //Ordering of i corresponds to perksClass enum - int total = (PERKSMAX + 1); - for (int i = 0; i < total; i++) { - kls_log(kls, "DEBUG", "Prepping Perk (%i)", i); - Perk *p = - (Perk *) KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); - p->class = i; - char *name = nameStringFromPerk(i); - char *desc = descStringFromPerk(i); - - //p->name = name; //(char*)malloc(sizeof(name)); - strcpy(p->name, name); - - //p->desc = (char*)malloc(sizeof(desc)); - strcpy(p->desc, desc); - - p->innerValue = 0; - - f->perks[i] = p; - } -} - -/** - * Takes a Equip and a Fighter pointers. - * Iterates over the equip's perks and adds them to the fighter perks. - * @see Perk - * @see Equip - * @see Fighter - * @param e An Equip pointer. - * @param f A Fighter pointer. - */ -void applyEquipPerks(Equip *e, Fighter *f) -{ - - for (int i = 0; i < (e->perksCount); i++) { - Perk *p = e->perks[i]; - - Perk *fighterPerk = f->perks[p->class]; - fighterPerk->innerValue += 1; - } -} - -/** - * Takes a Equip and a Fighter pointers. - * Iterates over the equip's perks and removes them to the fighter perks. - * @see Perk - * @see Equip - * @see Fighter - * @param e An Equip pointer. - * @param f A Fighter pointer. - */ -void removeEquipPerks(Equip *e, Fighter *f) -{ - - for (int i = 0; i < (e->perksCount); i++) { - Perk *p = e->perks[i]; - - Perk *fighterPerk = f->perks[p->class]; - fighterPerk->innerValue -= 1; - } -} - -/** - * Takes a Figher pointer and prints all of its active perks formatted. - * @see Fighter - * @see Perk - * @see Equip - * @param f The Fighter pointer with perks to print. - */ -void printActivePerks(Fighter *f) -{ - - WINDOW *win; - - /* Initialize curses */ - //initscr(); - clear(); - refresh(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - /* Create the windows for player stats and lifetime counters */ - win = newwin(22, 65, 1, 2); - keypad(win, TRUE); - - /* Print a border around the windows and print a title */ - box(win, 0, 0); - print_label(win, 1, 0, 35, "Perks", COLOR_PAIR(S4C_BRIGHT_YELLOW)); - mvwaddch(win, 2, 0, ACS_LTEE); - mvwhline(win, 2, 1, ACS_HLINE, 63); - mvwaddch(win, 2, 64, ACS_RTEE); - - wrefresh(win); - - //attron(COLOR_PAIR(3)); - mvprintw(23, 0, "(Press q or Enter to Exit)"); - //attroff(COLOR_PAIR(3)); - - int y = 4; - int x = 2; - //int startx = 2; - //int width = 65; - - int empty = 1; - - int count = PERKSMAX + 1; - - for (int i = 0; i < count; i++) { - Perk *p = f->perks[i]; - if (p->innerValue > 0) { - empty = 0; - - wattron(win, COLOR_PAIR(S4C_CYAN)); - mvwprintw(win, y, x, " x%i %s ", p->innerValue, - nameStringFromPerk(p->class)); - wattroff(win, COLOR_PAIR(S4C_CYAN)); - char s[250]; - sprintf(s, " x%i %s", p->innerValue, nameStringFromPerk(p->class)); - int l = strlen(s); - wattron(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); - mvwprintw(win, y, x + l + 2, "\"%s\"", - descStringFromPerk(p->class)); - wattroff(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); - y++; - } - }; - - if (empty) { //No perks are active - wattron(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); - mvwprintw(win, y, x, "You don't have any special power yet."); - wattroff(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); - } - - refresh(); - - int picked = 0; - int c = -1; - wrefresh(win); - - while (!picked && (c = wgetch(win)) != 'q') { - switch (c) { - case 10: { /*Enter */ - picked = 1; - - }; - break; - } - } - delwin(win); - endwin(); -} - -//Counter functions - -/** - * Takes a Fighter pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. - * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. - * For a given Counter, only the correct pointer field is assigned and the others are left untouched. - * @see Fighter - * @see Turncounter - * @see Countertype - * @see COUNTERSMAX - * @see counterIndexes - * @see getStatBoostCounterFun() - * @see getStatusCounterFun() - * @param f The Fighter pointer whose counters field will be initialised. - * @param kls The Koliseo used for allocation. - */ -void initCounters(Fighter *f, Koliseo *kls) -{ - //Ordering of i corresponds to counterIndexes enum - int total = (COUNTERSMAX + 1); - for (int i = 0; i < total; i++) { - log_tag("debug_log.txt", "[DEBUG]", "Prepping Turncounter (%i)", i); - kls_log(kls, "DEBUG", "Prepping Turncounter (%i)", i); - Turncounter *c = - (Turncounter *) KLS_PUSH_TYPED(kls, Turncounter, HR_Turncounter, - "Turncounter", "Turncounter"); - - //First, prepare counters for statuses - if (i < STATUSMAX + 1) { - c->desc = - (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof(stringFromStatus(i)), - HR_Turncounter_desc, "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, stringFromStatus(i)); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - kls_log(kls, "DEBUG", "Allocated size %lu for status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - - c->effect_fun = getStatusCounterFun(i); - //sprintf(msg,"Status function pointer is: (%i)", (int) *(c->effect_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - c->type = CNT_STATUS; - - //Register function for the specific status counter - // - //REGISTER_COUNTER_CALLBACK(i,resetFighterStatus); - // - //Why does uncommenting this cause problems to special moves callback? - //More specific, ONLY MAGE MOVES - //debug - //printf("%s",stringFromStatus(j)); - } else { //Then, counters for boosts to (all?) stats - - switch (i) { - case TURNBOOST_ATK: { - c->desc = - (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("ATK boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ATK boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("ATK boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("ATK boost"), c->desc); - - c->boost_fun = getStatBoostCounterFun(ATK); - c->type = CNT_ATKBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_DEF: { - c->desc = - (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("DEF boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "DEF boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("DEF boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("DEF boost"), c->desc); - - c->boost_fun = getStatBoostCounterFun(DEF); - c->type = CNT_DEFBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_VEL: { - c->desc = - (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("VEL boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "VEL boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("VEL boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("VEL boost"), c->desc); - - c->boost_fun = getStatBoostCounterFun(VEL); - c->type = CNT_VELBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_ENR: { - c->desc = - (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("ENR boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ENR boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("ENR boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("ENR boost"), c->desc); - - c->boost_fun = getStatBoostCounterFun(ENR); - c->type = CNT_ENRBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - default: { - printf - ("\n\nERROR in initCounters(): unexpected i: %i value \n\n", - i); - exit(EXIT_FAILURE); - } - } - } //End else - c->count = 0; - c->innerValue = 0; - f->counters[i] = (struct Turncounter *)c; - }; //End for all counters -} - -/** - * Takes a Enemy pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. - * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. - * For a given Counter, only the correct pointer field is assigned and the others are left untouched. - * @see Enemy - * @see Turncounter - * @see Countertype - * @see COUNTERSMAX - * @see counterIndexes - * @see getStatBoostCounterEnemyFun() - * @see getStatusCounterEnemyFun() - * @param e The Enemy pointer whose counters field will be initialised. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initECounters(Enemy *e, Koliseo_Temp *t_kls) -{ - //Ordering of i corresponds to counterIndexes enum - int total = (COUNTERSMAX + 1); - Koliseo *kls = t_kls->kls; - for (int i = 0; i < total; i++) { - log_tag("debug_log.txt", "[DEBUG]", "Prepping enemy Turncounter (%i)", - i); - kls_log(kls, "DEBUG", "Prepping enemy Turncounter (%i)", i); - Turncounter *c = - (Turncounter *) KLS_PUSH_T_TYPED(t_kls, Turncounter, - HR_Turncounter, "Turncounter", - "Turncounter"); - - //First, prepare counters for statuses - if (i < STATUSMAX + 1) { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof(stringFromStatus(i)), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, stringFromStatus(i)); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for enemy status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for enemy status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - - c->effect_e_fun = getStatusCounterEnemyFun(i); - //sprintf(msg,"[DEBUG] Enemy status function pointer is: (%i)", *(c->effect_e_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - c->type = CNT_STATUS; - - } else { //Then, counters for boosts to (all?) stats - - switch (i) { - case TURNBOOST_ATK: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("ATK boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ATK boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("ATK boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("ATK boost"), c->desc); - - c->boost_e_fun = getStatBoostCounterEnemyFun(ATK); - c->type = CNT_ATKBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_DEF: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("DEF boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "DEF boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("DEF boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("DEF boost"), c->desc); - - c->boost_e_fun = getStatBoostCounterEnemyFun(DEF); - c->type = CNT_DEFBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_VEL: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("VEL boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "VEL boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("VEL boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("VEL boost"), c->desc); - - c->boost_e_fun = getStatBoostCounterEnemyFun(VEL); - c->type = CNT_VELBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_ENR: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("ENR boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ENR boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("ENR boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("ENR boost"), c->desc); - - c->boost_e_fun = getStatBoostCounterEnemyFun(ENR); - c->type = CNT_ENRBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "ERROR INITALISING TURNCOUNTER in initECounters()\n"); - exit(EXIT_FAILURE); - } - } - } //End else - c->count = 0; - c->innerValue = 0; - e->counters[i] = (struct Turncounter *)c; - }; -} - -/** - * Takes a Boss pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. - * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. - * For a given Counter, only the correct pointer field is assigned and the others are left untouched. - * @see Boss - * @see Turncounter - * @see Countertype - * @see COUNTERSMAX - * @see counterIndexes - * @see getStatBoostCounterBossFun() - * @see getStatusCounterBossFun() - * @param b The Boss pointer whose counters field will be initialised. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initBCounters(Boss *b, Koliseo_Temp *t_kls) -{ - //Ordering of i corresponds to counterIndexes enum - int total = (COUNTERSMAX + 1); - Koliseo *kls = t_kls->kls; - for (int i = 0; i < total; i++) { - log_tag("debug_log.txt", "[DEBUG]", "Prepping boss counter %i", i); - kls_log(kls, "DEBUG", "Prepping boss counter %i", i); - Turncounter *c = - (Turncounter *) KLS_PUSH_T_TYPED(t_kls, Turncounter, - HR_Turncounter, "Turncounter", - "Turncounter"); - - //First, prepare counters for statuses - if (i < STATUSMAX + 1) { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof(stringFromStatus(i)), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, stringFromStatus(i)); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for boss status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for boss status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - - c->effect_b_fun = getStatusCounterBossFun(i); - //sprintf(msg,"Boss status function pointer is: (%i)", *(c->effect_b_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - c->type = CNT_STATUS; - - } else { //Then, counters for boosts to (all?) stats - - switch (i) { - case TURNBOOST_ATK: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("ATK boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ATK boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("ATK boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("ATK boost"), c->desc); - - c->boost_b_fun = getStatBoostCounterBossFun(ATK); - c->type = CNT_ATKBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_DEF: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("DEF boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "DEF boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("DEF boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("DEF boost"), c->desc); - - c->boost_b_fun = getStatBoostCounterBossFun(DEF); - c->type = CNT_DEFBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_VEL: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("VEL boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "VEL boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("VEL boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("VEL boost"), c->desc); - - c->boost_b_fun = getStatBoostCounterBossFun(VEL); - c->type = CNT_VELBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_ENR: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("ENR boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ENR boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("ENR boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for boss stat counter: (%s)", - sizeof("ENR boost"), c->desc); - - c->boost_b_fun = getStatBoostCounterBossFun(ENR); - c->type = CNT_ENRBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "ERROR INITALISING TURNCOUNTER in initBCounters()\n"); - exit(EXIT_FAILURE); - } - } - } //End else - c->count = 0; - c->innerValue = 0; - b->counters[i] = (struct Turncounter *)c; - }; -} - -/** - * Takes a FoeParty pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. - * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. - * For a given Counter, only the correct pointer field is assigned and the others are left untouched. - * @see FoeParty - * @see Turncounter - * @see Countertype - * @see COUNTERSMAX - * @see counterIndexes - * @see get_StatBoostCounter_FoeParty_Fun() - * @see get_StatusCounter_FoeParty_Fun() - * @param fp The FoeParty pointer whose counters field will be initialised. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initFoePartyCounters(FoeParty *fp, Koliseo_Temp *t_kls) -{ - //Ordering of i corresponds to counterIndexes enum - int total = (COUNTERSMAX + 1); - Koliseo *kls = t_kls->kls; - for (int i = 0; i < total; i++) { - log_tag("debug_log.txt", "[DEBUG]", "Prepping foeparty counter %i", i); - kls_log(kls, "DEBUG", "Prepping foeparty counter %i", i); - Turncounter *c = - (Turncounter *) KLS_PUSH_T_TYPED(t_kls, Turncounter, - HR_Turncounter, "Turncounter", - "Turncounter"); - - //First, prepare counters for statuses - if (i < STATUSMAX + 1) { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof(stringFromStatus(i)), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, stringFromStatus(i)); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for foeparty status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for foeparty status counter: (%s)", - sizeof(stringFromStatus(i)), c->desc); - - //c->effect_fp_fun = get_StatusCounter_FoeParty_Fun(i); - //sprintf(msg,"Foeparty status function pointer is: (%i)", *(c->effect_b_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - c->type = CNT_STATUS; - - } else { //Then, counters for boosts to (all?) stats - - switch (i) { - case TURNBOOST_ATK: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("ATK boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ATK boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("ATK boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("ATK boost"), c->desc); - - c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(ATK); - c->type = CNT_ATKBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_DEF: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("DEF boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "DEF boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("DEF boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("DEF boost"), c->desc); - - c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(DEF); - c->type = CNT_DEFBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_VEL: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("VEL boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "VEL boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("VEL boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("VEL boost"), c->desc); - - c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(VEL); - c->type = CNT_VELBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - case TURNBOOST_ENR: { - c->desc = - (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, - sizeof("ENR boost"), - HR_Turncounter_desc, - "Turncounter desc", - "Turncounter desc"); - strcpy(c->desc, "ENR boost"); - log_tag("debug_log.txt", "[DEBUG]", - "Allocated size %lu for status counter: (%s)", - sizeof("ENR boost"), c->desc); - kls_log(kls, "DEBUG", - "Allocated size %lu for status counter: (%s)", - sizeof("ENR boost"), c->desc); - - c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(ENR); - c->type = CNT_ENRBOOST; - //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); - //log_tag("debug_log.txt","[DEBUG]",msg); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Invalid counter in initFoePartyCounters"); - exit(EXIT_FAILURE); - } - } - } //End else - c->count = 0; - c->innerValue = 0; - fp->counters[i] = (struct Turncounter *)c; - }; -} - -//TODO update this to actually handle different types of counters and reliably print them, maybe to a ncurses window -/** - * Takes a Turncounter array. - * For every Turncounter in the array, the values of count, innerVal, type and all the function pointers fields are printed. - * @see Turncounter - * @param counters The Turncounter array to be printed. - */ -void printCounters(Turncounter *counters[]) -{ - yellow(); - printf - ("%-10.10s\t%-10.10s\t%-3.3s\t%-3.3s\t%-11.11s\t%-11.11s\t%-11.11s\t%-11.11s\n", - "Count", "Desc", "Val", "Typ", "*(eff())", "*(eff_e())", "*(boost())", - "*(boost_e())"); - for (int i = 0; i < (COUNTERSMAX + 1); i++) { - Turncounter *c = counters[i]; - lightBlue(); - printf("%-10.10i\t%-10.10s\t", c->count, c->desc); - strongWhite(); - printf("(%-3.3i)\t(%-3.3i)\t", c->innerValue, c->type); - purple(); - //printf("[%-11.11i]\t[%-11.11i]\t",*(c->effect_fun),*(c->effect_e_fun)); - cyan(); - //printf("[%-11.11i]\t[%-11.11i]\n",*(c->boost_fun), *(c->boost_e_fun)); - }; - white(); -} - -/** - * Takes a Turncounter array, an integer, a Fighter pointer and an Enemy pointer. - * For every Turncounter in the array count value is checked, and when it's equal to 1, the function pointer relevant to the type value of the Counter is called. Depending on the isEnemy input value, the function call will be for the Fighter or Enemy version (and the according pointer from the input will be passed to the called function). - * When the count value is 0, counters are considered inactive, so when the count value is not 1, it is lowered by 1 if it's positive. - * @see Fighter - * @see Enemy - * @see Turncounter - * @see Countertype - * @see COUNTERSMAX - * @see counterIndexes - * @param counters The Turncounter array to be updated. - * @param isEnemy Dictates if the check is done for an Enemy or a Fighter. - * @param f The Fighter pointer whose counters field will be updated if isEnemy is false. - * @param e The Enemy pointer whose counters field will be updated if isEnemy is true. - */ -void updateCounters(Turncounter *counters[], int isEnemy, Fighter *f, Enemy *e) -{ - for (int i = 0; i < COUNTERSMAX + 1; i++) { - - Turncounter *c = counters[i]; - if (c->count == 1) { //Counter is about to expire so we call the correct function: - switch (c->type) { - case CNT_STATUS: { //Callback for status counters - - if (!isEnemy) { - (c->effect_fun) (f); - //green(); - //printf("\t%s status returned to normal.\n",f->name); - //white(); - } else { //Enemy function - (c->effect_e_fun) (e); - //lightRed(); - //printf("\t%s status returned to normal.\n",stringFromEClass(e->class)); - //white(); - //TODO - //Display notification to win - log_tag("debug_log.txt", "[DEBUG-COUNTER]", - "Status reset for %s.", - stringFromEClass(e->class)); - } - } - break; - case CNT_ATKBOOST: - case CNT_DEFBOOST: - case CNT_VELBOOST: - case CNT_ENRBOOST: { //Callback for stat boosts - if (!isEnemy) { - (c->boost_fun) (f, 0); //Call ~setPermBoost(STAT)~ with value 0 - log_tag("debug_log.txt", "[DEBUG-COUNTER]", - "Applied boost function for Fighter."); - } else { - assert(0 && "UNACCESSIBLE CALL.\n"); - (c->boost_e_fun) (e, 0); //Call ~setPermBoost(STAT)~ with value 0 - } - } - break; - } - - //Set counter to zero - c->count = 0; - c->innerValue = 0; - } else if (c->count > 1) { //We simply advance the count - log_tag("debug_log.txt", "[DEBUG-COUNTER]", - "Advancing counter %i for %s.", i, - (isEnemy ? "Enemy" : "Fighter")); - c->count -= 1; - } - }; -} - -/** - * Takes a Turncounter array, an integer, a Fighter pointer and a Boss pointer. - * For every Turncounter in the array count value is checked, and when it's equal to 1, the function pointer relevant to the type value of the Counter is called. Depending on the isBoss input value, the function call will be for the Fighter or Boss version (and the according pointer from the input will be passed to the called function). - * When the count value is 0 Counters are considered inactive, so when the count value is not 1, it is lowered by 1 if it's positive. - * @see Fighter - * @see Boss - * @see Turncounter - * @see Countertype - * @see COUNTERSMAX - * @see counterIndexes - * @param counters The Turncounter array to be updated. - * @param isBoss Dictates if the check is done for a Boss or a Fighter. - * @param f The Fighter pointer whose counters field will be updated if isBoss is false. - * @param b The Boss pointer whose counters field will be updated if isBoss is true. - */ -void updateCounters_Boss(Turncounter *counters[], int isBoss, Fighter *f, - Boss *b) -{ - for (int i = 0; i < COUNTERSMAX + 1; i++) { - - Turncounter *c = counters[i]; - if (c->count == 1) { //Counter is about to expire so we call the correct function: - switch (c->type) { - case CNT_STATUS: { //Callback for status counters - - //TODO - //Add notification to window - if (!isBoss) { - (c->effect_fun) (f); - //green(); - //printf("\t%s status returned to normal.\n",f->name); - //white(); - } else { //Boss function - (c->effect_b_fun) (b); - //lightRed(); - //printf("\t%s status returned to normal.\n",stringFromBossClass(b->class)); - //white(); - } - } - break; - case CNT_ATKBOOST: - case CNT_DEFBOOST: - case CNT_VELBOOST: - case CNT_ENRBOOST: { //Callback for stat boosts - if (!isBoss) { - (c->boost_fun) (f, 0); //Invoke ~setPermBoost(STAT)~ with value 0 - } else { - assert(0 && "UNACCESSIBLE CALL.\n"); - (c->boost_b_fun) (b, 0); //Call ~setPermBoost(STAT)~ with value 0 - } - } - break; - } - - //Set counter to zero - c->count = 0; - c->innerValue = 0; - } else if (c->count > 1) { //We simply advance the count - c->count -= 1; - } - }; -} - -/** - * Takes a Turncounter pointer and an integer. - * If the count value at the pointer is 0 (counter is inactive), the turns valueis assigned. - * @see Turncounter - * @param c The Turncounter whose count value will be set. - * @param turns The value to be assigned. - */ -void setCounter(Turncounter *c, int turns) -{ - - if (c->count == 0) { // Counter is NOT already active - c->count = turns; - } else { - //Handle counters already activ - } -} - -/** - * Takes a Fighter pointer and prepares its specialSlot fields by allocating SPECIALSMAX slots. - * Special slots are initialised. - * The specific move assigned is determined using the ordering of both fighterClass values and SPECIALSMAX. - * @see Fighter - * @see Specialslot - * @see SPECIALSMAX - * @see REGISTER_CALLBACK() - * @see costFromSpecial() - * @see stringFromSpecial() - * @param kls The Koliseo used for allocations. - * @param f The Fighter pointer whose special slots will be initialised. - */ -void setSpecials(Fighter *f, Koliseo *kls) -{ - char movename[80]; - char movedesc[80]; - for (int i = 0; i <= SPECIALSMAX; i++) { - kls_log(kls, "DEBUG", "Prepping Specialslot (%i)", i); - Specialslot *s = - (Specialslot *) KLS_PUSH_TYPED(kls, Specialslot, HR_Specialslot, - "Specialslot", "Specialslot"); - s->enabled = 0; - s->move = i + (f->class * (SPECIALSMAX + 1)); // Assign the i-th move offsetting by classNum * specialsMax - s->cost = costFromSpecial(f->class, i); - strcpy(movename, nameStringFromSpecial(f->class, i)); - strcpy(movedesc, descStringFromSpecial(f->class, i)); - //printf("DEBUG\n%i\t%s\n",(i+ (f->class * (SPECIALSMAX + 1))),stringFromSpecial(f->class,i)); - strcpy(s->name, movename); - strcpy(s->desc, movedesc); - f->specials[i] = s; - }; -} - -/** - * Takes a Fighter pointer and prepares its skillSlot fields by allocating FIGHTER_SKILL_SLOTS slots. - * Skill slots are initialised. - * @see Fighter - * @see Skilllot - * @see FIGHTER_SKILL_SLOTS - * @see SKILL_TYPE_LAST_UNLOCKABLE - * @see costFromSkill() - * @see stringFromSkill() - * @param kls The Koliseo used for allocations. - * @param f The Fighter pointer whose skill slots will be initialised. - */ -void setSkills(Fighter *f, Koliseo *kls) -{ - char movename[80]; - char movedesc[80]; - for (int i = 0; i <= FIGHTER_SKILL_SLOTS; i++) { - kls_log(kls, "DEBUG", "Prepping Skillslot (%i)", i); - Skillslot *s = - (Skillslot *) KLS_PUSH_TYPED(kls, Skillslot, HR_Skillslot, - "Skillslot", "Skillslot"); - s->enabled = 0; - s->class = i; - s->cost = costFromSkill(i); - strcpy(movename, nameStringFromSkill(i)); - strcpy(movedesc, descStringFromSkill(i)); - //printf("DEBUG\n%i\t%s\n",(i),stringFromSkill(i)); - strcpy(s->name, movename); - strcpy(s->desc, movedesc); - f->skills[i] = s; - }; -} - -/** - * Takes a Enemy pointer and prepares its skillSlot fields by allocating ENEMY_SKILL_SLOTS slots. - * Skill slots are initialised. - * @see Enemy - * @see Skilllot - * @see ENEMY_SKILL_SLOTS - * @see SKILLSTOTAL - * @see costFromSkill() - * @see stringFromSkill() - * @param t_kls The Koliseo_Temp used for allocations. - * @param e The Enemy pointer whose skill slots will be initialised. - */ -void setEnemySkills(Enemy *e, Koliseo_Temp *t_kls) -{ - char movename[80]; - char movedesc[80]; - for (int i = 0; i < ENEMY_SKILL_SLOTS; i++) { - kls_log(t_kls->kls, "DEBUG", "Prepping Enemy Skillslot (%i)", i); - Skillslot *s = - (Skillslot *) KLS_PUSH_T_TYPED(t_kls, Skillslot, HR_Skillslot, - "Enemy Skillslot", "Enemy Skillslot"); - s->enabled = 0; - s->class = i; - s->cost = costFromSkill(i); - strcpy(movename, nameStringFromSkill(i)); - strcpy(movedesc, descStringFromSkill(i)); - //printf("DEBUG\n%i\t%s\n",(i),stringFromSkill(i)); - strcpy(s->name, movename); - strcpy(s->desc, movedesc); - e->skills[i] = s; - }; -} - -/** - * Takes a Boss pointer and prepares its skillSlot fields by allocating BOSS_SKILL_SLOTS slots. - * Skill slots are initialised. - * @see Boss - * @see Skilllot - * @see Boss_SKILL_SLOTS - * @see SKILLSTOTAL - * @see costFromSkill() - * @see stringFromSkill() - * @param t_kls The Koliseo_Temp used for allocations. - * @param b The Boss pointer whose skill slots will be initialised. - */ -void setBossSkills(Boss *b, Koliseo_Temp *t_kls) -{ - char movename[80]; - char movedesc[80]; - for (int i = 0; i < BOSS_SKILL_SLOTS; i++) { - kls_log(t_kls->kls, "DEBUG", "Prepping Boss Skillslot (%i)", i); - Skillslot *s = - (Skillslot *) KLS_PUSH_T_TYPED(t_kls, Skillslot, HR_Skillslot, - "Boss Skillslot", "Boss Skillslot"); - s->enabled = 0; - s->class = i; - s->cost = costFromSkill(i); - strcpy(movename, nameStringFromSkill(i)); - strcpy(movedesc, descStringFromSkill(i)); - //printf("DEBUG\n%i\t%s\n",(i),stringFromSkill(i)); - strcpy(s->name, movename); - strcpy(s->desc, movedesc); - b->skills[i] = s; - }; -} - -/** - * Takes a Fighter pointer and resets all of its permboost_STAT values to 0, also correctly updating the current stat values. - * @see Fighter - * @param f The fighter pointer whose permboosts will be reset. - */ -void resetPermboosts(Fighter *f) -{ - for (int i = 0; i < STATMAX + 1; i++) { - switch (i) { - case ATK: { - f->atk -= f->permboost_atk; - if (f->atk < 0) { - f->atk = 0; - }; - f->permboost_atk = 0; - } - break; - case DEF: { - f->def -= f->permboost_def; - if (f->def < 0) { - f->def = 0; - }; - f->permboost_def = 0; - } - break; - case VEL: { - f->vel -= f->permboost_vel; - if (f->vel < 0) { - f->vel = 0; - }; - f->permboost_vel = 0; - } - break; - case ENR: { - f->totalenergy -= f->permboost_enr; - f->energy -= f->permboost_enr; - if (f->energy < 0) { - f->energy = 0; - }; - f->permboost_enr = 0; - } - break; - }; - }; -} - -/** - * Takes a Fighter pointer and applies all of its permboost_STAT values by adding them to the current stat values. - * @see Fighter - * @param f The fighter pointer whose permboosts will be applied. - */ -void applyPermboosts(Fighter *f) -{ - for (int i = 0; i < STATMAX + 1; i++) { - switch (i) { - case ATK: { - f->atk += f->permboost_atk; - } - break; - case DEF: { - f->def += f->permboost_def; - } - break; - case VEL: { - f->vel += f->permboost_vel; - } - break; - case ENR: { - f->totalenergy += f->permboost_enr; - f->energy += f->permboost_enr; - } - break; - }; - }; -} - -/** - * Takes a Fighter pointer and Resets the active value for each Artifact in the fighter's artifactsBag array that doesn't have an always active trait. - * At the moment, this only excludes CHAOSORB. - * @see Artifact - * @see artifactClass - * @see Fighter - */ -void resetArtifactsState(Fighter *f) -{ - for (int i = 0; i < (ARTIFACTSMAX + 1); i++) { - - //if (i == CHAOSORB) { //Chaosorb never gets reset - // continue; - //}; - - if (f->artifactsBag[i]->qty != 0) { //We only reset the ones we have - f->artifactsBag[i]->active = 0; - }; - }; -} - -/** - * Takes a Fighter, a Enemy and a Boss pointer; plus an integer indicating if effects should be applied to enemy (==0) or boss (==1=. - * Iterates over artifacts bag and calls the inner function pointer if an artifact has positive qty and its active member is false. - * @see Artifact - * @param f A Fighter pointer. - * @param e An Enemy pointer. - * @param b The Boss pointer. - * @param isBoss The integer defining who is receiving the effect. - */ -void applyArtifacts(Fighter *f, Enemy *e, Boss *b, int isBoss) -{ - - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - Artifact *a = f->artifactsBag[i]; - if (a->qty != 0 && !(a->active)) { //We only apply the ones we have unlocked && aren't active already - switch (a->class) { - case THKSKULL: { - artifact_thinkingskull(f, e, b, isBoss); - } - break; - case TWINKIE: { - artifact_twinkie(f, e, b, isBoss); - } - break; - case WRISTBAND: { - artifact_wristband(f, e, b, isBoss); - } - break; - case BOARTAIL: { - artifact_boartail(f, e, b, isBoss); - } - break; - case CHAOSORB: { - artifact_chaosorb(f, e, b, isBoss); - } - break; - case POWERSYPHON: { - artifact_powersyphon(f, e, b, isBoss); - } - break; - case GIANTFOSSILE: { - artifact_giantfossile(f, e, b, isBoss); - } - break; - }; - }; - }; -} - -/** - * Takes a Fighter pointer and prepares its equipslots field by allocating an Equipslot for each Equipzone. - * @see Fighter - * @see Equipslot - * @see Equipzone - * @see counterIndexes - * @see EQUIPZONES - * @param f The Fighter pointer whose equipslots field will be initialised. - * @param kls The Koliseo used for allocations. - */ -void initEquipSlots(Fighter *f, Koliseo *kls) -{ - for (int i = 0; i <= EQUIPZONES; i++) { - kls_log(kls, "DEBUG", "Prepping Equipslot (%i)", i); - Equipslot *s = - (Equipslot *) KLS_PUSH_TYPED(kls, Equipslot, HR_Equipslot, - "Equipslot", "Equipslot"); - s->active = 0; - s->type = i; - setEquipslotSprite(s); - f->equipslots[i] = (struct Equipslot *)s; - }; -} - -/** - * Takes a Fighter pointer and prepares its consumablesBag field by allocating a Consumable for each consumableClass. - * @see Fighter - * @see Consumable - * @see consumableClass - * @see CONSUMABLESMAX - * @param f The Fighter pointer whose consumablesBag field will be initialised. - * @param kls The Koliseo to do allocations. - */ -void initConsumableBag(Fighter *f, Koliseo *kls) -{ - - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - kls_log(kls, "DEBUG", "Prepping Consumable (%i)", i); - Consumable *c = - (Consumable *) KLS_PUSH_TYPED(kls, Consumable, HR_Consumable, - "Consumable", "Consumable"); - c->class = i; - - Consumable *base = &consumablesBase[i]; - - strcpy(c->name, base->name); - strcpy(c->desc, base->desc); - for (int j = 0; j < 8; j++) { - strcpy(c->sprite[j], base->sprite[j]); - } - c->qty = 0; - - f->consumablesBag[i] = (struct Consumable *)c; - } - -} - -/** - * Takes a Fighter pointer and prepares its artifactsBag field by allocating a Artifact for each artifactClass. - * @see Fighter - * @see Artifact - * @see artifactClass - * @see ARTIFACTSMAX - * @param kls The Koliseo used for allocations. - * @param f The Fighter pointer whose artifactsBag field will be initialised. - */ -void initArtifactsBag(Fighter *f, Koliseo *kls) -{ - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - kls_log(kls, "DEBUG", "Prepping Artifact (%i)", i); - Artifact *a = - (Artifact *) KLS_PUSH_TYPED(kls, Artifact, HR_Artifact, - "Artifact", "Artifact"); - a->class = i; - - Artifact *base = &artifactsBase[i]; - - strcpy(a->name, base->name); - strcpy(a->desc, base->desc); - for (int j = 0; j < 8; j++) { - strcpy(a->sprite[j], base->sprite[j]); - } - a->qty = 0; - - f->artifactsBag[i] = (struct Artifact *)a; - } -} - -/** - * Takes one Fighter and one Path pointers and initialises the fighter fields. - * Luck value is set as path luck value modulo MAXPLAYERLUCK. - * The BaseStats pointer for the fighter's figtherClass is loaded. - * The stats field is initalised with all inner values at 0. - * setSpecials(), initCounters() are called to init the specialslots and counters fields. - * initEquipSlots() is called to init the equipslots field, and the relative int field are set to 0. - * initArtifactsFun() is called to init all the Artifact effect_fun field. - * All the tempboost_STAT and permboost_STAT fields are set to 0. - * All the fields common to BaseStats are initialised with the base value. - * The status field is set to Normal. - * @see Fighter - * @see fighterClass - * @see Path - * @see BaseStats - * @see countStats - * @see MAXPLAYERLUCK - * @see setSpecials() - * @see initCounters() - * @see initEquipSlots() - * @see initArtifactsFun() - * @see fighterStatus - * @param player The Fighter whose fields will be initialised. - * @param path The Path pointer of the current game. - * @param kls The Koliseo used for allocation. - */ -void initPlayerStats(Fighter *player, Path *path, Koliseo *kls) -{ - - //player luck : MAXPLAYERLUCK = path luck : MAXLUCK - - player->luck = (path->luck * MAXPLAYERLUCK) / MAXLUCK; - - BaseStats *base = &basestats[player->class]; - - kls_log(kls, "DEBUG", "Prepping countStats"); - countStats *s = - (countStats *) KLS_PUSH_TYPED(kls, countStats, HR_countStats, - "countStats", "countStats"); - - s->enemieskilled = 0; - s->criticalhits = 0; - s->consumablesfound = 0; - s->equipsfound = 0; - s->artifactsfound = 0; - s->roomscompleted = 0; - s->floorscompleted = 0; - s->specialsunlocked = 0; - s->coinsfound = 0; - s->bosseskilled = 0; - s->unique_bosseskilled = 0; - for (int i = 0; i < BOSSCLASSESMAX + 1; i++) { - s->killed_bosses[i] = 0; - } - s->keysfound = 0; - - setSpecials(player, kls); - setSkills(player, kls); - initCounters(player, kls); - initPerks(player, kls); - - initConsumableBag(player, kls); - initArtifactsBag(player, kls); - - initEquipSlots(player, kls); - player->equipsBagOccupiedSlots = 0; //Keeps track of how many slots are occupied. - player->earliestBagSlot = 0; //To alwasy use the array efficiently (???) I sense linked lists may be better - - player->permboost_atk = 0; - player->permboost_def = 0; - player->permboost_vel = 0; - player->permboost_enr = 0; - - player->equipboost_atk = 0; - player->equipboost_def = 0; - player->equipboost_vel = 0; - player->equipboost_enr = 0; - - player->balance = 0; - player->keys_balance = 0; - - player->stats = s; - player->hp = base->hp; - player->totalhp = base->totalhp; - player->atk = base->atk; - player->def = base->def; - player->vel = base->vel; - player->level = base->level; - player->totalxp = base->totalxp; - player->currentlevelxp = base->currentlevelxp; - player->totallevelxp = base->totallevelxp; - player->status = Normal; - player->totalenergy = base->totalenergy; - player->energy = player->totalenergy; - player->totalstamina = base->totalstamina; - player->stamina = player->totalstamina; - - setFighterSprite(player); -} - -/** - * Takes one Enemy pointer and initialises the enemy fields. - * The EnemyBaseStats pointer for the enemy's enemyClass is loaded. - * If the beast field at the pointer is already set before this call, atk def vel and hp of the enemy will receive a multiplicative boost equal to BSTFACTOR . Also, Xp value will be multiplied by 3. - * Notably, the level field is not set at all by this function and needs to be set by the caller. - * All the fields common to EnemyBaseStats are initialised with the base value and eventual beast boost. - * initECounters() is called to init the counters field. - * The status field is set to Normal. - * @see Enemy - * @see enemyClass - * @see EnemyBaseStats - * @see initECounters() - * @see fighterStatus - * @param e The Enemy whose fields will be initialised. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initEnemyStats(Enemy *e, Koliseo_Temp *t_kls) -{ - EnemyBaseStats *base = &baseenemystats[e->class]; - log_tag("debug_log.txt", "[DEBUG]", "Init stats for enemy (%s)", - stringFromEClass(e->class)); - - float beastf = 1; - - if (e->beast) { - beastf = BSTFACTOR; - } - - e->hp = round(beastf * base->hp); - e->totalhp = round(beastf * base->totalhp); - e->atk = round(beastf * base->atk); - e->def = round(beastf * base->def); - e->vel = round(beastf * base->vel); - e->status = Normal; - - //Level should be set by caller - //Index should be set by caller - - e->totalenergy = base->totalenergy; - e->energy = e->totalenergy; - e->totalstamina = base->totalstamina; - e->stamina = e->totalstamina; - - //Set prize, double for beasts - float prize = 2.8 * e->level; - - e->prize = floor((e->beast) ? 2 * prize : prize); - - initECounters(e, t_kls); - - //Triple xp for beasts - e->xp = (e->beast) ? 3 * base->xp : base->xp; - - setEnemySprite(e); -} - -/** - * Takes one Boss pointer and initialises the boss fields. - * The BossBaseStats pointer for the boss's bossClass is loaded. - * If the beast field at the pointer is already set before this call, atk def vel and hp of the enemy will receive a multiplicative boost equal to BSTFACTOR . Xp value will also be multiplie by 3. - * Notably, the level field is not set at all by this function and needs to be set by the caller. - * All the fields common to BossBaseStats are initialised with the base value and eventual beast boost. - * initBCounters() is called to init the counters field. - * The status field is set to Normal. - * @see Boss - * @see bossClass - * @see BossBaseStats - * @see initBCounters() - * @see fighterStatus - * @param b The Boss whose fields will be initialised. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initBossStats(Boss *b, Koliseo_Temp *t_kls) -{ - //Class should be set by caller - BossBaseStats *base = &basebossstats[b->class]; - - float beastf = 1; - - if (b->beast) { - beastf = BSTFACTOR; - } - - b->hp = round(beastf * base->hp); - b->totalhp = round(beastf * base->totalhp); - b->atk = round(beastf * base->atk); - b->def = round(beastf * base->def); - b->vel = round(beastf * base->vel); - b->status = Normal; - - //Level should be set by caller - - b->totalenergy = base->totalenergy; - b->energy = b->totalenergy; - - b->totalstamina = base->totalstamina; - b->stamina = b->totalstamina; - - //Set prize, double for beasts - float prize = 4.5 * b->level; - - b->prize = (b->beast) ? 2 * prize : prize; - - initBCounters(b, t_kls); - - //Triple xp for beasts - b->xp = (b->beast) ? 3 * base->xp : base->xp; - - setBossSprite(b); -} - -/** - * Takes one FoeParty pointer and initialises the party fields. - * The FoePartyBaseStats pointer for the FoeParty's foePartyClass is loaded. - * All the fields common to FoePartyBaseStats are initialised with the base value. - * initFoePartyCounters() is called to init the counters field. - * @see FoeParty - * @see foePartyClass - * @see FoePartyBaseStats - * @see initFoePartyCounters() - * @param fp The FoeParty whose fields will be initialised. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initFoePartyStats(FoeParty *fp, Koliseo_Temp *t_kls) -{ - //Class should be set by caller - //FoePartyBaseStats* base = &basefoepartystats[fp->class]; - //TODO: add loading of more base stats not expected in prepareFoeParty() - - //Level should be set by caller - - //Zero the alive_enemies values - for (int i = 0; i < ROOM_ENEMIES_MAX + 1; i++) { - fp->alive_enemies[i] = 0; - }; - //Zero the alive_bosses values - for (int i = 0; i < FOES_BOSSES_MAX + 1; i++) { - fp->alive_bosses[i] = 0; - }; - - //Zero the turnboost_STAT values - fp->turnboost_atk = 0; - fp->turnboost_def = 0; - fp->turnboost_vel = 0; - fp->turnboost_enr = 0; - - //Zero current enemy index - fp->current_index = 0; - - //Size value should be set by caller - fp->tot_alive = fp->size; - - switch (fp->class) { - case Enemies: { - //Set alive_enemies values - for (int i = 0; i < fp->tot_alive + 1; i++) { - fp->alive_enemies[i] = 1; - }; - } - break; - case Bosses: { - //Set alive_bosses values - for (int i = 0; i < fp->tot_alive + 1; i++) { - fp->alive_bosses[i] = 1; - }; - } - break; - default: { - fprintf(stderr, "UNEXPECTED FOEPARTY CLASS VALUE %i", fp->class); - log_tag("debug_log.txt", "[PANIC]", - "Invalid class value in initFoePartyStats()"); - exit(EXIT_FAILURE); - } - break; - }; - - //Init party counters - initFoePartyCounters(fp, t_kls); -} - -/** - * Takes a FoeParty pointer, a size for complete party, and an integer for the current room index, and initialises all the fields making the FoeParty ready for use in battle. - * Calls initFoePartyStats() after setting class and level - * @see FoeParty - * @see initFoePartyStats() - * @param fp The allocated FoeParty pointer to initialise. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void prepareFoeParty(FoeParty *fp, int partysize, int roomindex, - Koliseo_Temp *t_kls) -{ - - //Class must be set by caller - - FoePartyBaseStats *base = &basefoepartystats[fp->class]; - - fp->level = base->level; - //Set size value - fp->size = partysize; - - //FoeParty's get 1 level every 2 rooms - //fp->level += floor(roomindex / 2) ; - - //Load foeparty stats - initFoePartyStats(fp, t_kls); - - log_tag("debug_log.txt", "[DEBUG]", - "Prepared FoeParty with size (%i), room #%i.", partysize, - roomindex); -} - -/** - * Takes one integer and a bossClass and returns the boost relative to the level delta with base boss stats, as an integer. - * The EnemyBossStats pointer for the boss's bossClass is loaded. - * If the boost is negative, returns 0. - * @see Boss - * @see bossClass - * @see BossBaseStats - * @param lvl The level to check the boost against. - * @param bclass The bossClass used to determine base level. - * @return int The boost for any given stat, at the level passed as argument. - */ -int getBossBoost(int lvl, bossClass bclass) -{ - - BossBaseStats *base = &basebossstats[bclass]; - - float boost = ((lvl - base->level) * 1.25); - if (boost <= 0) { - boost = 0; - } - - return (int)boost; -} - -/** - * Takes a Boss pointer and an integer used to force execution. - * If the force parameter is true, all checks are ignored. - * If boss's hp value is at least 40% of total, and none of atk, def or vel is 0 or less, nothing happens with an early return. - * Otherwise, getBossBoost() is called to calc the level stat boost for each stat. - * The BossBaseStats pointer for the boss's bossClass is loaded and each one of atk, def and vel is checked accounting for level boost. - * If none of them is below the respective treshold of 30, 30 and 20 % of total, nothing happens. - * Otherwise, all of them are reset to full amount accounting for beast boost and level boost. - * @see Boss - * @see bossClass - * @see getBossBoost() - * @see BSTFACTOR - * @see BossBaseStats - * @param b The Boss pointer to check the stats for. - * @param force The integer to bypass all checks if true. - */ -void statResetBoss(Boss *b, int force) -{ - if (!force && (b->hp >= 0.4 * b->totalhp) - && !(b->atk <= 0 || b->def <= 0 || b->vel <= 0)) { - return; - } - int boost = getBossBoost(b->level, b->class); - - float beastf = 1; - - if (b->beast) { - beastf = BSTFACTOR; - } - BossBaseStats *base = &basebossstats[b->class]; - - if (force) { //We also update hp values - int hpBoost = - boost + round(base->level * 0.75) + (base->hp / 10) + - ((base->def / 4) % 10); - b->hp = round(beastf * (base->hp + hpBoost)); - b->totalhp = b->hp; - } - - if (force || b->vel <= (0.3 * (base->vel + boost)) - || (b->atk <= (0.3 * (base->atk + boost))) - || b->def <= (0.2 * (base->def + boost))) { - b->vel = round(beastf * (base->vel + boost)); - b->atk = round(beastf * (base->atk + boost)); - b->def = round(beastf * (base->def + boost)); - //Reset stats - if (!force) { - //yellow(); - //printf("\n\n\t%s's stats reset.\n",stringFromEClass(e->class)); - //white(); - } - } -} - -/** - * Takes a Boss pointer and initialises all the fields making it ready for use in battle. - * Calls initBossStats() after setting class and level, then forces a stat reset to update the stats - * with the level boost. - * @see Boss - * @see initBossStats() - * @param b The allocated Boss pointer to initialise. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void prepareBoss(Boss *b, Koliseo_Temp *t_kls) -{ - - //Randomise boss class - b->class = rand() % (BOSSCLASSESMAX + 1); - - b->beast = 0; - BossBaseStats *base = &basebossstats[b->class]; - - b->level = base->level; - - //Enemies get 1 level every 2 rooms - //e->level += floor(roomindex / 2) ; - - //Load boss stats - initBossStats(b, t_kls); - - //Set skill slots - setBossSkills(b, t_kls); - - //Force load of level bonuses - statResetBoss(b, 1); - -} - -/** - * Takes one integer and an enemyClass and returns the boost relative to the level delta with base enemy stats, as an integer. - * The EnemyBaseStats pointer for the enemy's enemyClass is loaded. - * If the boost is negative, returns 0. - * @see Enemy - * @see enemyClass - * @see EnemyBaseStats - * @param lvl The level to check the boost against. - * @param eclass The enemyClass used to determine base level. - * @return int The boost for any given stat, at the level passed as argument. - */ -int getEnemyBoost(int lvl, enemyClass eclass) -{ - - EnemyBaseStats *base = &baseenemystats[eclass]; - - float boost = ((lvl - base->level) * 1.25); - if (boost <= 0) { - boost = 0; - } - - return (int)boost; -} - -/** - * Takes an Enemy pointer and an integer used to force execution. - * If the force parameter is true, all checks are ignored. - * If enemy's hp value is at least 40% of total, and none of atk, def or vel is 0 or less, nothing happens with an early return. - * Otherwise, getEnemyBoost() is called to calc the level stat boost for each stat. - * The EnemyBaseStats pointer for the enemy's enemyClass is loaded and each one of atk, def and vel is checked accounting for level boost. - * If none of them is below the respective treshold of 30, 30 and 20 % of total, nothing happens. - * Otherwise, all of them are reset to full amount accounting for beast boost and level boost. - * @see Enemy - * @see enemyClass - * @see getEnemyBoost() - * @see BSTFACTOR - * @see EnemyBaseStats - * @param e The Enemy pointer to check the stats for. - * @param force The integer to bypass all checks if true. - */ -void statResetEnemy(Enemy *e, int force) -{ - log_tag("debug_log.txt", "[DEBUG]", - "Call to statResetEnemy() with ($force) == (%i)", force); - if (!force && (e->hp >= 0.4 * e->totalhp) - && !(e->atk <= 0 || e->def <= 0 || e->vel <= 0)) { - return; - } - int boost = getEnemyBoost(e->level, e->class); - - float beastf = 1; - - if (e->beast) { - beastf = BSTFACTOR; - } - EnemyBaseStats *base = &baseenemystats[e->class]; - - if (force) { //We also update hp values - int hpBoost = - floor(0.5 * boost + round(base->level * 0.75) + (base->hp / 10) + - ((base->def / 4) % 10)); - e->hp = round(beastf * (base->hp + hpBoost)); - e->totalhp = e->hp; - } - - if (force || e->vel <= (0.3 * (base->vel + boost)) - || (e->atk <= (0.3 * (base->atk + boost))) - || e->def <= (0.2 * (base->def + boost))) { - e->vel = round(beastf * (base->vel + boost)); - e->atk = round(beastf * (base->atk + boost)); - e->def = round(beastf * (base->def + boost)); - //Reset stats - if (!force) { - //yellow(); - //printf("\n\n\t%s's stats reset.\n",stringFromEClass(e->class)); - //white(); - } - } -} - -/** - * Takes a Enemy and three integers denoting current room index, how many enemies are in the room and current enemy index. - * The class field of the enemy is randomised according to ENEMYCLASSESMAX. - * If the room index is multiple of BEASTROOM and the enemy is the last one in he room, its beast field is set to 1. - * The EnemyBaseStats pointer for the enemy's enemyClass is loaded and the level field for the enemy is set to base level, before increasing. - * initEnemyStats() is called to set all stat fields and statResetEnemy() is called with force=true to apply the boosted stats to leveled enemies. - * @see Enemy - * @see enemyClass - * @see ENEMYCLASSESMAX - * @see BEASTROOM - * @see BSTFACTOR - * @see ENEMYLVLRATIO - * @see EnemyBaseStats - * @see initEnemyStats() - * @see statResetEnemy() - * @param e The Enemy pointer to prepare. - * @param roomindex The index of current room. - * @param enemiesInRoom The number of enemies in current room. - * @param enemyindex The index of current enemy. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void prepareRoomEnemy(Enemy *e, int roomindex, int enemiesInRoom, - int enemyindex, Koliseo_Temp *t_kls) -{ - - //Randomise enemy class - e->class = rand() % (ENEMYCLASSESMAX + 1); - - if (G_DEBUG_ON && G_DEBUG_ENEMYTYPE_ON && (GAMEMODE != Rogue)) { //Debug flag has a fixed enemy class when used outside of Rogue gamemode - log_tag("debug_log.txt", "[DEBUG]", - "prepareRoomEnemy(): Enemy debug flag was asserted outside of story mode, will always spawn a G_DEBUG_ENEMYTYPE (%s).", - stringFromEClass(G_DEBUG_ENEMYTYPE)); - e->class = G_DEBUG_ENEMYTYPE; - } - - //Check for spawning beast enemies - if ((roomindex % BEASTROOM == 0) && (enemyindex == (enemiesInRoom - 1))) { - //TODO: better mechanic for spawning beast enemies - if (((rand() % 5) == 0)) { - log_tag("debug_log.txt", "[DEBUG]", "Setting e->beast to 1."); - e->beast = 1; - } - } else { - e->beast = 0; - }; - - EnemyBaseStats *base = &baseenemystats[e->class]; - - e->level = base->level; - - //Enemies get 1 level every 2 rooms - e->level += floor(roomindex / 2); - - //Set current enemy index - e->index = enemyindex; - - //Load enemy stats - initEnemyStats(e, t_kls); - - //Load enemy skills - // - setEnemySkills(e, t_kls); - - //Force load of level bonuses - statResetEnemy(e, 1); -} - -/** - * Takes a size int and a pointer to integer array, initialises all the prices, depending on stats from the Equips array pointer. - * @see initShop() - * @see Equip - * @param size Size of both arrays. - * @param equipPrices Pointer to integer array for prices. - * @param equips Pointer to Equip pointer to influence pricing. - */ -void setEquipPrices(int size, int *equipPrices, Equip *equips[]) -{ - - for (int i = 0; i < size; i++) { - int *cur_price = &equipPrices[i]; - Equip *e = equips[i]; - - int baseprice = e->cost; - int price = baseprice; - - *cur_price = price; - } - -} - -/** - * Takes a size int and a pointer to integer array, initialises all the prices. - * @see initShop() - * @param size Size of both arrays. - * @param consumablePrices Pointer to integer array for prices. - * @param consumables Pointer to Consumable pointer to influence pricing. - */ -void setConsumablePrices(int size, int *consumablePrices, - Consumable **consumables) -{ - - for (int i = 0; i < size; i++) { - int *cur_price = &consumablePrices[i]; - //Consumable* c = consumables[i]; - - //Price evaluation - int baseprice = 4; - int price = baseprice + (rand() % 5) - 1; - - *cur_price = price; - } -} - -/** - * Takes one Shop pointer and initialises all the fields, depeding on stats from the Fighter pointer passed. - * @see Shop - * @param s The Shop whose fields will be initialised. - * @param indexWeight The integer for room index weight. - * @param player The Fighter player to influence item generation. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initShop(Shop *s, int indexWeight, Fighter *player, Koliseo_Temp *t_kls) -{ - - int equipsCount = (rand() % EQUIP_SHOP_MAX) + 1; - Koliseo *kls = t_kls->kls; - - if (equipsCount != 0) { - - for (int equip_index = 0; equip_index < equipsCount; equip_index++) { - int curr = (rand() % (EQUIPSMAX + 1)); - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Equip (%i/%i) for Shop", equip_index, - equipsCount); - kls_log(kls, "DEBUG", "Prepping Equip (%i/%i) for Shop", - equip_index, equipsCount); - Equip *e = - (Equip *) KLS_PUSH_T_TYPED(t_kls, Equip, HR_Equip, "Equip", - "Equip"); - - //Randomise quality - quality q = rand() % (QUALITIESMAX + 1); - - //Get the base item and copy the stats to the current equip - Equip *base = &equips[curr]; - - e->class = base->class; - e->type = base->type; - e->qual = q; - - setEquipSprite(e); - strcpy(e->name, base->name); - strcpy(e->desc, base->desc); - - e->qty = 1; - e->equipped = 0; - e->perksCount = 0; - - //Calc drop level - e->level = base->level + round(player->level / EQUIPLVLBOOSTRATIO); - - //Chance for better leveled item - if ((rand() % 8) - (player->luck / 10) <= 0) { //Should use a defined constant - e->level += 1; //At least a simple +1 - if ((rand() % 25) - (player->luck / 10) <= 0) { //Should use a defined constant - e->level += 1; //A bonus roll for another +1 - - } - } - - float boostFactor = 0.7; - - float lvlBoost = boostFactor * (e->level - 1); - - e->atk = round((base->atk * 1.0) + lvlBoost); - e->def = round((base->def * 1.0) + lvlBoost); - e->vel = round((base->vel * 1.0) + lvlBoost); - e->enr = round((base->enr * 1.0) + lvlBoost); - - //Bonus stats on better quality items? Simple for now - // - if (q == Good) { - e->atk += (rand() % 3); //Should use a defined constant - e->def += (rand() % 3); //Should use a defined constant - e->vel += (rand() % 3); //Should use a defined constant - e->enr += (rand() % 2); //Should use a defined constant - } else if (q == Bad) { - e->atk -= (rand() % 3); //Should use a defined constant - e->def -= (rand() % 3); //Should use a defined constant - e->vel -= (rand() % 3); //Should use a defined constant - e->enr -= (rand() % 2); //Should use a defined constant - if (e->atk < 0) { - e->atk = 0; - }; - if (e->def < 0) { - e->def = 0; - }; - if (e->vel < 0) { - e->vel = 0; - }; - if (e->enr < 0) { - e->enr = 0; - }; - } - //Possible perks for the Equip - - for (int i = 0; i < (EQUIPPERKSMAX); i++) { - int chance = 35; - - if (q == Good) { - chance *= 1.5; - } - - if ((rand() % 100) < chance) { - - e->perksCount += 1; - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Perk (%i) for Shop Equip (%i/%i)", i, - equip_index, equipsCount); - kls_log(kls, "DEBUG", - "Prepping Perk (%i) for Shop Equip (%i/%i)", i, - equip_index, equipsCount); - Perk *p = - (Perk *) KLS_PUSH_T_TYPED(t_kls, Perk, HR_Perk, - "Perk", "Perk"); - p->class = rand() % (PERKSMAX + 1); - //p->name = (char*)malloc(sizeof(nameStringFromPerk(p->class))); - strcpy(p->name, nameStringFromPerk(p->class)); - //p->desc = (char*)malloc(sizeof(descStringFromPerk(p->class))); - strcpy(p->desc, descStringFromPerk(p->class)); - p->innerValue = 1; - e->perks[(e->perksCount - 1)] = p; - } - } - - //Set value of how many bonuses we have. Although Equip only has ONE function pointer field for now - e->bonus = base->bonus; - //Randomise if the item will have an effect function. - //Not yet implemented - //Initialisation of function happens here - // - //e->equip_fun = ; - - //Calc cost value - - float cost = 3; - - cost += 4.5 * (e->qual + 1); - cost += 7.5 * (e->perksCount); - - cost += 10.2 * (e->level); - - e->cost = floor(cost); - - s->equips[equip_index] = e; - s->equipsCount++; - - } //End for all equips - } - s->equipsCount = equipsCount; - setEquipPrices(s->equipsCount, s->equipPrices, s->equips); - - int uniqueConsumablesCount = (rand() % SINGLE_CONSUMABLE_SHOP_MAX) + 1; - int uniques = 0; - //int not_uniques = 0; - if (uniqueConsumablesCount != 0) { - int already_rolled[CONSUMABLESMAX + 1]; - for (int i = 0; i < (CONSUMABLESMAX + 1); i++) { - already_rolled[i] = 0; - } - int cons_prepared = 0; - while (cons_prepared < uniqueConsumablesCount) { - - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - if (cons_prepared < uniqueConsumablesCount) { - int curr = rand() % (CONSUMABLESMAX + 1); - if (!(already_rolled[curr])) { - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Consumable (%i/%i) for Shop", - cons_prepared, uniqueConsumablesCount); - kls_log(kls, "DEBUG", - "Prepping Consumable (%i/%i) for Shop", - cons_prepared, uniqueConsumablesCount); - Consumable *cur = - (Consumable *) KLS_PUSH_T_TYPED(t_kls, Consumable, - HR_Consumable, - "Consumable", - "Consumable"); - cur->class = curr; - already_rolled[curr] = 1; - if (uniqueConsumablesCount - cons_prepared > 0) { - cur->qty = (rand() % 4) + 1; - } else { - cur->qty = 1; - //cur->qty = (rand() % (consumablesCount - cons_index)) +1; - } - setConsumableSprite(cur); - //not_uniques += cur->qty; - cons_prepared++; //= cur->qty; - s->consumables[uniques] = cur; - uniques++; - } - } - }; - } - } - s->consumablesCount = uniqueConsumablesCount; - setConsumablePrices(s->consumablesCount, s->consumablePrices, - s->consumables); - - s->itemCount = s->consumablesCount + s->equipsCount; -} - -/** - * Takes a Chest and Fighter pointers and initialises all the fields in chest based on chest class and fighter stats. - * @see Chest - * @param c The allocated Chest pointer with already set class to initialise. - * @param f The Fighter pointer with stats. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initChest(Chest *c, Fighter *f, Koliseo_Temp *t_kls) -{ - - setChestSprite(c); - - strcpy(c->desc, descStringFromChest(c->class)); - int cons_cnt, equip_cnt; - Koliseo *kls = t_kls->kls; - - switch (c->class) { - case CHEST_BASE: { - cons_cnt = rand() % (CHEST_CONSUMABLES_MAX - 1); - equip_cnt = rand() % (CHEST_EQUIPS_MAX - 1); - } - break; - case CHEST_BEAST: { - cons_cnt = (rand() % (CHEST_CONSUMABLES_MAX)) + 1; - equip_cnt = (rand() % (CHEST_EQUIPS_MAX)) + 1; - - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "%i is not a valid chest class.", c->class); - exit(EXIT_FAILURE); - } - break; - - } - - c->consumablesCount = cons_cnt; - c->equipsCount = equip_cnt; - - if (c->consumablesCount > 0) { - for (int i = 0; i < c->consumablesCount; i++) { - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Consumable (%i/%i) for Chest", i, - c->consumablesCount); - kls_log(kls, "DEBUG", "Prepping Consumable (%i/%i) for Chest", i, - c->consumablesCount); - Consumable *cns = - (Consumable *) KLS_PUSH_T_TYPED(t_kls, Consumable, - HR_Consumable, "Consumable", - "Consumable"); - int drop = rand() % (CONSUMABLESMAX + 1); - - cns->class = drop; - - Consumable *base = &consumablesBase[drop]; - - strcpy(cns->name, base->name); - strcpy(cns->desc, base->desc); - for (int j = 0; j < 8; j++) { - strcpy(cns->sprite[j], base->sprite[j]); - } - cns->qty = 1; - - c->consumables[i] = cns; - } - } - - if (c->equipsCount > 0) { - for (int i = 0; i < c->equipsCount; i++) { - - //Select a basic item from the list - int drop = rand() % (EQUIPSMAX + 1); - //Randomise quality - quality q = rand() % (QUALITIESMAX + 1); - - //Prepare the item - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Equip (%i/%i) for Chest", i, c->equipsCount); - kls_log(kls, "DEBUG", "Prepping Equip (%i/%i) for Chest", i, - c->equipsCount); - Equip *e = - (Equip *) KLS_PUSH_T_TYPED(t_kls, Equip, HR_Equip, "Equip", - "Equip"); - - //Get the base item and copy the stats to the drop - Equip *base = &equips[drop]; - - e->class = base->class; - e->type = base->type; - e->qual = q; - - setEquipSprite(e); - strcpy(e->name, base->name); - strcpy(e->desc, base->desc); - - e->qty = 1; - e->equipped = 0; - - e->perksCount = 0; - - //Calc drop level - e->level = base->level + round(f->level / EQUIPLVLBOOSTRATIO); - - //Chance for better leveled item - if ((rand() % 8) - (f->luck / 10) <= 0) { //Should use a defined constant - e->level += 1; //At least a simple +1 - if ((rand() % 25) - (f->luck / 10) <= 0) { //Should use a defined constant - e->level += 1; //A bonus roll for another +1 - - } - } - - float boostFactor = 0.7; - - float lvlBoost = boostFactor * (e->level - 1); - - e->atk = round((base->atk * 1.0) + lvlBoost); - e->def = round((base->def * 1.0) + lvlBoost); - e->vel = round((base->vel * 1.0) + lvlBoost); - e->enr = round((base->enr * 1.0) + lvlBoost); - - //Bonus stats on better quality items? Simple for now - - if (q == Good) { - e->atk += (rand() % 3); //Should use a defined constant - e->def += (rand() % 3); //Should use a defined constant - e->vel += (rand() % 3); //Should use a defined constant - e->enr += (rand() % 2); //Should use a defined constant - } else if (q == Bad) { - e->atk -= (rand() % 3); //Should use a defined constant - e->def -= (rand() % 3); //Should use a defined constant - e->vel -= (rand() % 3); //Should use a defined constant - e->enr -= (rand() % 2); //Should use a defined constant - if (e->atk < 0) { - e->atk = 0; - }; - if (e->def < 0) { - e->def = 0; - }; - if (e->vel < 0) { - e->vel = 0; - }; - if (e->enr < 0) { - e->enr = 0; - }; - } - //Possible perks for the Equip - - for (int j = 0; j < (EQUIPPERKSMAX); j++) { - int chance = 20; - - if (q == Good) { - chance *= 1.5; - } - - if ((rand() % 100) < chance - || (c->class == CHEST_BEAST && e->perksCount == 0)) { - - e->perksCount += 1; - - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Perk (%i/%i) for Equip (%i/%i) for Chest", - j, e->perksCount, i, c->equipsCount); - kls_log(kls, "DEBUG", - "Prepping Perk (%i/%i) for Equip (%i/%i) for Chest", - j, e->perksCount, i, c->equipsCount); - Perk *p = - (Perk *) KLS_PUSH_T_TYPED(t_kls, Perk, HR_Perk, - "Perk", "Perk"); - p->class = rand() % (PERKSMAX + 1); - //p->name = (char*)malloc(sizeof(nameStringFromPerk(p->class))); - strcpy(p->name, nameStringFromPerk(p->class)); - //p->desc = (char*)malloc(sizeof(descStringFromPerk(p->class))); - strcpy(p->desc, descStringFromPerk(p->class)); - p->innerValue = 1; - e->perks[(e->perksCount - 1)] = p; - } - } - - //Set value of how many bonuses we have. Although Equip only has ONE function pointer field for now - e->bonus = base->bonus; - //Randomise if the item will have an effect function. - //Not yet implemented - //Initialisation of function happens here - // - //e->equip_fun = ; - - //Calc cost value - - float cost = 5; - - cost += 2.5 * (e->qual); - cost += 3.5 * (e->perksCount); - - cost += 7.2 * (e->level); - - e->cost = floor(cost); - - c->equips[i] = e; - } //End for all equips - } //End if equipsCount > 0 -} - -/** - * Takes a Chest and Fighter pointers and initialises all the fields in chest making it ready for use in battle, using fighter stats to influence init. - * Calls initChest() after setting class. - * @see Chest - * @see initChest() - * @param c The allocated Chest pointer to initialise. - * @param f The Fighter pointer to influence item generation. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void prepareChest(Chest *c, Fighter *f, Koliseo_Temp *t_kls) -{ - - //Init chest class - int drop = (rand() % 100) + 1; - - if (drop > 70) { - c->class = CHEST_BASE; - } else { - c->class = CHEST_BEAST; - } - - //Load Chest stats - initChest(c, f, t_kls); - -} - -/** - * Takes a Treasure and Fighter pointers and initialises all the treasure fields based on its class and fighter's stats. - * @see Treasure - * @param t The allocated Treasure pointer with already set class to initialise. - * @param f The Fighter pointer to influence item generation. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void initTreasure(Treasure *t, Fighter *f, Koliseo_Temp *t_kls) -{ - - Koliseo *kls = t_kls->kls; - strcpy(t->desc, descStringFromTreasure(t->class)); - - switch (t->class) { - case TREASURE_CHEST: { - - log_tag("debug_log.txt", "[DEBUG]", - "Allocated %lu for Treasure [Chest]:", sizeof(Chest)); - kls_log(kls, "DEBUG", "Allocated %lu for Treasure [Chest]:", - sizeof(Chest)); - Chest *c = - (Chest *) KLS_PUSH_T_TYPED(t_kls, Chest, HR_Chest, "Chest", - "Chest"); - prepareChest(c, f, t_kls); - t->chest = c; - - } - break; - case TREASURE_CONSUMABLE: { - log_tag("debug_log.txt", "[DEBUG]", - "Allocated %lu for Treasure [Consumable]:", - sizeof(Consumable)); - kls_log(kls, "DEBUG", "Allocated %lu for Treasure [Consumable]:", - sizeof(Consumable)); - Consumable *cns = - (Consumable *) KLS_PUSH_T_TYPED(t_kls, Consumable, - HR_Consumable, "Consumable", - "Consumable"); - int drop = rand() % (CONSUMABLESMAX + 1); - - cns->class = drop; - - Consumable *base = (Consumable *) f->consumablesBag[drop]; - - strcpy(cns->name, base->name); - strcpy(cns->desc, base->desc); - for (int j = 0; j < 8; j++) { - strcpy(cns->sprite[j], base->sprite[j]); - } - cns->qty = 1; - - t->consumable = cns; - } - break; - case TREASURE_ARTIFACT: { - log_tag("debug_log.txt", "[DEBUG]", - "Allocated %lu for Treasure [Artifact]:", sizeof(Artifact)); - kls_log(kls, "DEBUG", "Allocated %lu for Treasure [Artifact]:", - sizeof(Artifact)); - Artifact *a = - (Artifact *) KLS_PUSH_T_TYPED(t_kls, Artifact, HR_Artifact, - "Artifact", "Artifact"); - int drop = -1; - do { - drop = rand() % (ARTIFACTSMAX + 1); - } while (f->artifactsBag[drop]->qty > 0); - - a->class = drop; - - Artifact *base = f->artifactsBag[drop]; - - strcpy(a->name, base->name); - strcpy(a->desc, base->desc); - for (int j = 0; j < 8; j++) { - strcpy(a->sprite[j], base->sprite[j]); - } - a->qty = 0; - - t->artifact = a; - - } - break; - } -} - -/** - * Takes a Treasure and Fighter pointer and initialises all the treasure fields making it ready for use in battle, based on the fighter stats. - * Calls initTreasure() after setting class. - * @see Treasure - * @see initTreasure() - * @param t The allocated Treasure pointer to initialise. - * @param f The Fighter pointer to influence item generation. - * @param t_kls The Koliseo_Temp used for allocations. - */ -void prepareTreasure(Treasure *t, Fighter *f, Koliseo_Temp *t_kls) -{ - - //Init treasure class - - int roll = (rand() % 100) + 1; - - if (roll > 70) { - t->class = TREASURE_CHEST; - } else if (roll > 50) { - t->class = TREASURE_ARTIFACT; - } else { - t->class = TREASURE_CONSUMABLE; - } - - //Load Treasure stats - initTreasure(t, f, t_kls); - -} - -/** - * Takes a Roadfork pointer and initialises all the fields making it ready for use in battle. - * Calls initRoadfork() after setting class. - * @see Roadfork - * @see initRoadfork() - * @param r The allocated Roadfork pointer to initialise. - */ -void prepareRoadfork(Roadfork *r) -{ - - //Randomise options - r->options[0] = rand() % (ROADFORK_OPTIONS_MAX + 1); - int previous = r->options[0]; - int new = -1; - - do { - new = rand() % (ROADFORK_OPTIONS_MAX + 1); - - } while (new == previous); - - previous = new; - r->options[1] = new; - -} - -/** - * Takes a Fighter pointer and prints most of its values formatted. - * @see Fighter - * @see stringFromClass() - * @see stringFromStatus() - * @param f The Fighter pointer with stats to print. - */ -void printStats(Fighter *f) -{ - - printf("\t%s's stats:\n\n", f->name); - printf("\t\tClass:\t%s\n", stringFromClass(f->class)); - printf("\t\tHp:\t%i/%i\n", f->hp, f->totalhp); - printf("\t\tEnergy:\t%i/%i\n", f->energy, f->totalenergy); - printf("\t\tAtk:\t%i\n", f->atk); - printf("\t\tDef:\t%i\n", f->def); - printf("\t\tVel:\t%i\n", f->vel); - printf("\t\tLvl:\t%i\n", f->level); - printf("\t\tCurrent Level exp:\t%i/%i\n", f->currentlevelxp, - f->totallevelxp); - printf("\t\tTotal exp:\t%i\n", f->totalxp); - printf("\t\tStatus:\t%s\n", stringFromStatus(f->status)); -} - -/** - * Takes a Enemy pointer and prints most of its values formatted. - * @see Enemy - * @see stringFromEClass() - * @see stringFromStatus() - * @param e The Enemy pointer with stats to print. - */ -void printEStats(Enemy *e) -{ - if (e->beast) { - lightRed(); - } - printf("\t%s's stats:\n", stringFromEClass(e->class)); - if (e->beast) { - white(); - } - printf("\tHp:\t%i/%i\n", e->hp, e->totalhp); - printf("\tEnergy:\t%i/%i\n", e->energy, e->totalenergy); - printf("\tAtk:\t%i\n", e->atk); - printf("\tDef:\t%i\n", e->def); - printf("\tVel:\t%i\n", e->vel); - printf("\tLvl:\t%i\n", e->level); - printf("\tXp:\t%i\n", e->xp); - printf("\tStatus:\t%s\n", stringFromStatus(e->status)); -} - -/** - * Takes a Enemy pointer and returns its xp gain as sum of xp field value and level. - * @see Enemy - * @param e The Enemy pointer. - * @return int The xp gain. - */ -int getEnemyXpGain(Enemy *e) -{ - - int xp = e->xp + e->level; - return xp; -} - -/** - * Takes a Boss pointer and returns its xp gain as sum of xp field value and level. - * @see Boss - * @param b The Boss pointer. - * @return int The xp gain. - */ -int getBossXpGain(Boss *b) -{ - - int xp = b->xp + b->level; - return xp; -} - -/** - * Takes a Consumable pointer and prints most of its values formatted. - * @see Consumable - * @param c The Consumable pointer with stats to print. - */ -void printConsumablesStats(Consumable *c) -{ - printf(" (%i)\t%i\t%s\t\"%s\"\n", c->class, c->qty, c->name, c->desc); -} - -/** - * Takes a Artifact pointer and prints most of its values formatted. - * @see Artifact - * @param a The Artifact pointer with stats to print. - */ -void printArtifactStats(Artifact *a) -{ - printf(" (%i)\t\t", a->class); - purple(); - printf("%s\t", a->name); - yellow(); - printf("\"%s\"\n", a->desc); - white(); -} - -/** - * Takes a quality value and calls the respective color function without actually printing text. - * @see quality - * @param q The quality value we want to set text color for. - */ -void printQualityColor(quality q) -{ - switch (q) { - case Bad: { - lightRed(); - } - break; - case Average: { - strongWhite(); - } - break; - case Good: { - lightCyan(); - } - break; - }; -} - -/** - * Takes a Equip pointer and prints most of its values formatted. - * The beginning of the format assumes the caller prepended "(x" on the output before calling, where x is the index of the equip. - * @see Equip - * @see stringFromQuality() - * @param e The Equip pointer with stats to print. - */ -void printEquipStats(Equip *e) -{ - printf(")\t"); //This completes the print started in the calling loop, which supplies the index ATM - - //Quality color - printQualityColor(e->qual); - printf("%s ", stringFromQuality(e->qual)); - - printf("%s ", e->name); - white(); - - printf("\"%s\" (L%i)\t", e->desc, e->level); - - lightCyan(); - printf("%s ", stringFromEquipzones(e->type)); - - lightGreen(); - //Stats, will be then printed only if != 0 - if (e->atk != 0) { - printf("A: %i ", e->atk); - }; - if (e->def != 0) { - printf("D: %i ", e->def); - }; - if (e->vel != 0) { - printf("V: %i ", e->vel); - }; - if (e->enr != 0) { - printf("E: %i", e->enr); - }; - - printf("\n"); - white(); - - //Perks, will be then printed only if perksCount != 0 - - for (int i = 0; i < e->perksCount; i++) { - lightPurple(); - printf("\t\t%s\n", e->perks[i]->name); - }; - white(); -} - -/** - * Takes a Enemy pointer and two integers for current room index and current enemy index, and prints the spawn message formatted. - * @see Enemy - * @see stringFromEClass() - * @param e The Enemy pointer to print. - * @param roomIndex The index of current room. - * @param enemyIndex The index of current enemy. - */ -void printSpawnMessage(Enemy *e, int roomIndex, int enemyIndex) -{ - if (!e->beast) { - //TODO: - //Where to print a windowed spawn message? - log_tag("debug_log.txt", "[ROOM]", "Room %i)\t\t%s\t\tEnemy #%i", - roomIndex, stringFromEClass(e->class), enemyIndex + 1); - } else { - log_tag("debug_log.txt", "[ROOM]", - "Room %i)\t\t%s\t\tEnemy #%i IS BEAST", roomIndex, - stringFromEClass(e->class), enemyIndex + 1); - //lightBlue(); - //printf("\nYou feel at discomfort.\n\nRoom %i)\t\t",roomIndex); - //lightRed(); - //printf("Enemy #%i:\t%s",enemyIndex+1,stringFromEClass(e->class)); - //white(); - } -} - -/** - * Takes a Wincon and a Path pointers and a winconClass and initialises the passed Wincon. - * @see Wincon - * @see Path - * @see winconClass - * @see WINCON_CLASS_MAX - * @param w The Wincon pointer to initialise. - * @param p The Path to use to initialise Wincon. - * @param class The winconClass to use to initialise. - */ -void initWincon(Wincon *w, Path *p, winconClass class) -{ - - w->class = class; - - switch (w->class) { - case ALL_BOSSES: { - w->current_val = 0; - w->target_val = BOSSCLASSESMAX + 1; - - }; - break; - case ALL_ARTIFACTS: { - w->current_val = 0; - w->target_val = ARTIFACTSMAX + 1; - - }; - break; - case FULL_PATH: { - w->current_val = 0; - w->target_val = p->length; - }; - break; - default: { - fprintf(stderr, "\nUnexpected Wincon Class %i\n", w->class); - w->class = -1; - w->current_val = 0; - w->target_val = 1; - } - - } - -} - -/** - * Takes a integer and a string array (possibly from main), a Fighter pointer and a Path pointer to set some values. - * Depending on argc value, the arguments in argv may be used instead of calling the functions to get user input. - * @see Fighter - * @see pickName() - * @see pickClass() - * @see pickWincon() - * @param argc The number of argv values + 1 (0 is program name?). - * @param argv Array of strings with argc - 1 values. - * @param player The Fighter of which we set name and class. - * @param path The Path pointer used for the game. - * @param kls The Koliseo used for allocation. - */ -void getParams(int argc, char **argv, Fighter *player, Path *path, int optTot, - Koliseo *kls) -{ - - int argTot = argc - optTot; - if (argTot == 0) { - pickName(player); - pickClass(player); - kls_log(kls, "DEBUG", "Prepping Wincon"); - Wincon *w = - (Wincon *) KLS_PUSH_TYPED(kls, Wincon, HR_Wincon, "Wincon", - "Wincon"); - if (GAMEMODE == Story) { - //Path length must be already initialised before getting here. - initWincon(w, path, FULL_PATH); - } else if (GAMEMODE == Rogue) { - //Path length must be already initialised before getting here. - initWincon(w, path, ALL_ARTIFACTS); - } else { - pickWincon(w); - initWincon(w, path, w->class); - } - path->win_condition = w; - } else if (argTot == 1 || argTot == 2) { - char read_name[25]; - int i = 0, len = 0; - len = strlen(argv[optTot]); - if (len < 20) { - for (; i < len; i++) { - read_name[i] = argv[optTot][i]; - } - read_name[i] = '\0'; - strcpy(player->name, read_name); - } else { - pickName(player); - } - } else { - usage(argv[0]); - exit(EXIT_FAILURE); - } - if (argTot == 1) { - pickClass(player); - kls_log(kls, "DEBUG", "Prepping Wincon"); - Wincon *w = - (Wincon *) KLS_PUSH_TYPED(kls, Wincon, HR_Wincon, "Wincon", - "Wincon"); - if (GAMEMODE == Story) { - //Path length must be already initialised before getting here. - initWincon(w, path, FULL_PATH); - } else if (GAMEMODE == Rogue) { - //Path length must be already initialised before getting here. - initWincon(w, path, ALL_ARTIFACTS); - } else { - pickWincon(w); - initWincon(w, path, w->class); - } - path->win_condition = w; - } - - if (argTot == 2) { - int c = -1; - int i = 0; - for (i = 0; i <= CLASSESMAX; i++) { - if (strcmp(argv[optTot + 1], classesstrings[i]) == 0) { - c = 1; - player->class = i; - break; - } - } - if (c < 0) { - pickClass(player); - } - kls_log(kls, "DEBUG", "Prepping Wincon"); - Wincon *w = - (Wincon *) KLS_PUSH_TYPED(kls, Wincon, HR_Wincon, "Wincon", - "Wincon"); - if (GAMEMODE == Story) { - //Path length must be already initialised before getting here. - initWincon(w, path, FULL_PATH); - } else if (GAMEMODE == Rogue) { - //TODO: what do we set as path length? Number of floors? - //Path length must be already initialised before getting here. - initWincon(w, path, ALL_ARTIFACTS); - } else { - pickWincon(w); - initWincon(w, path, w->class); - } - path->win_condition = w; - } -} - -/** - * Returns the chosen option as a turnOption. - * @param ch A string representing the turn choice. - * @return The chosen turnOption value representing turn action. - */ -turnOption getTurnChoice(char *ch) -{ - int comp = 999; - - log_tag("debug_log.txt", "[TURNPICK]", "Turnchoice string was (%s)", ch); - turnOption pick = INVALID; - - while (pick == INVALID) { - if ((comp = strcmp(ch, "Fight")) == 0) { - pick = FIGHT; - } else if ((comp = strcmp(ch, "New game")) == 0) { - pick = NEW_GAME; - } else if ((comp = strcmp(ch, "Load save")) == 0) { - pick = LOAD_GAME; - } else if ((comp = strcmp(ch, "Special")) == 0) { - pick = SPECIAL; - } else if ((comp = strcmp(ch, "Consumables")) == 0) { - pick = CONSUMABLE; - } else if ((comp = strcmp(ch, "Artifacts")) == 0) { - pick = ARTIFACTS; - } else if ((comp = strcmp(ch, "Equips")) == 0) { - pick = EQUIPS; - } else if ((comp = strcmp(ch, "Perks")) == 0) { - pick = PERKS; - } else if ((comp = strcmp(ch, "Stats")) == 0) { - pick = STATS; - } else if ((comp = strcmp(ch, "Save")) == 0) { - pick = SAVE; - } else if ((comp = strcmp(ch, "Debug")) == 0) { - pick = DEBUG; - } else if ((comp = strcmp(ch, "Quit")) == 0) { - pick = QUIT; - } else if ((comp = strcmp(ch, "Explore")) == 0) { - pick = EXPLORE; - } else if ((comp = strcmp(ch, "Tutorial")) == 0) { - pick = TUTORIAL; - } else if ((comp = strcmp(ch, "Close")) == 0) { - pick = CLOSE_MENU; - } else { - pick = INVALID; - } - } - - log_tag("debug_log.txt", "[TURNOPT]", "Pick was: (%i)", pick); - - if (pick == INVALID) { - fprintf(stderr, "Error: unexpected turn choice value"); - log_tag("debug_log.txt", "[ERROR]", - "Unexpected turn choice in getTurnChoice(), quitting"); - exit(EXIT_FAILURE); - } - return pick; -} - -/** - * Returns a randomised pick as foeTurnOption. - * @param e Pointer to the enemy to pick for. - * @param f Pointer to the target fighter. - * @return The chosen foeturnOption value representing turn action. - */ -foeTurnOption enemyTurnPick(Enemy *e, Fighter *f) -{ - if (e == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "enemyTurnPick(): Enemy was NULL."); - exit(EXIT_FAILURE); - } - if (f == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "enemyTurnPick(): Fighter was NULL."); - exit(EXIT_FAILURE); - } - foeTurnOption pick = FOE_INVALID; - - while (pick == FOE_INVALID) { - int rn = rand() % 101; - /* - if (rn > 80) { - //TODO - //pick = FOE_SPECIAL; - pick = FOE_IDLE; - - } else - */ - if (rn > 40) { - pick = FOE_FIGHT; - } else { - pick = FOE_IDLE; - } - } - - log_tag("debug_log.txt", "[FOETURNOPTION]", "Pick was: ( %i ) [ %s ]", pick, - stringFromFoeTurnOP(foeTurnOP_from_foeTurnOption(pick))); - - if (pick == FOE_INVALID) { - fprintf(stderr, "Error: unexpected turn choice value"); - log_tag("debug_log.txt", "[ERROR]", - "Unexpected turn choice in enemyTurnPick(), quitting"); - exit(EXIT_FAILURE); - } - return pick; -} - -/** - * Returns a randomised pick as foeTurnOption. - * @param b Pointer to the boss to pick for. - * @param f Pointer to the target fighter. - * @return The chosen foeturnOption value representing turn action. - */ -foeTurnOption bossTurnPick(Boss *b, Fighter *f) -{ - if (b == NULL) { - log_tag("debug_log.txt", "[ERROR]", "bossTurnPick(): Boss was NULL."); - exit(EXIT_FAILURE); - } - if (f == NULL) { - log_tag("debug_log.txt", "[ERROR]", - "bossTurnPick(): Fighter was NULL."); - exit(EXIT_FAILURE); - } - foeTurnOption pick = FOE_INVALID; - - while (pick == FOE_INVALID) { - int rn = rand() % 101; - /* - if (rn > 80) { - //TODO - //pick = FOE_SPECIAL; - pick = FOE_IDLE; - } else - */ - if (rn > 40) { - pick = FOE_FIGHT; - } else { - pick = FOE_IDLE; - } - } - - log_tag("debug_log.txt", "[FOETURNOPTION]", "Pick was: ( %i ) [ %s ]", pick, - stringFromFoeTurnOP(foeTurnOP_from_foeTurnOption(pick))); - - if (pick == FOE_INVALID) { - fprintf(stderr, "Error: unexpected turn choice value"); - log_tag("debug_log.txt", "[ERROR]", - "Unexpected turn choice in enemyTurnPick(), quitting"); - exit(EXIT_FAILURE); - } - return pick; -} - -/** - * Takes two integers for level to calc against and luck, and returns the boost relative to the level with luck variations, as an integer. - * At level 1, returns 0. - * @param lvl The level to check the boost against. - * @param luck The luck value to influence calcs. - * @return int The boost for any given stat, at the level passed as argument. - */ -int getBoost(int lvl, int luck) -{ - - float boost = (lvl * 1.25F) + ((luck % 2) * 2); - - if (lvl < 2) { - boost = 1.0; // Evitare conflitti - } - - return (int)boost; -} - -/** - * Takes a Fighter pointer and asks the user to select a specialMove to unlock with a formatted text menu. - * From the specials field of fighter, only the SpecialSlot with the enabled falg not set are printed and selectable by user. - * For the Fighter, the equipboost values are also displayed. - * @see Fighter - * @see SpecialSlot - * @see SPECIALSMAX - * @see setSpecials() - * @see stringFromSpecial() - * @param f The Fighter pointer that get one of his not yet unlocked specials. - */ -void unlockSpecial(Fighter *f) -{ - - //Thanks to u/skeeto for the suggestions. - ITEM *my_items[SPECIALSMAX + 2] = { 0 }; - MENU *my_menu; - WINDOW *my_menu_win; - WINDOW *display_win; - - int n_choices = 0; - int selection = -1; - int currentIndexed = -1; - ITEM *cur; - - /* Initialize curses */ - //initscr(); - clear(); - refresh(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - /* Create menu items */ - for (int i = 0; i < SPECIALSMAX + 1; i++) { - if (!(f->specials[i]->enabled)) { - my_items[n_choices++] = - new_item(nameStringFromSpecial(f->class, i), " "); - } - } - - /* Create menu */ - my_menu = new_menu(my_items); - - /* Set description off */ - menu_opts_off(my_menu, O_SHOWDESC); - - /* Create the window to be associated with the menu */ - my_menu_win = newwin(18, 28, 2, 2); - keypad(my_menu_win, TRUE); - - /* Set main window and sub window */ - set_menu_win(my_menu, my_menu_win); - set_menu_sub(my_menu, derwin(my_menu_win, 12, 26, 4, 2)); - set_menu_format(my_menu, 12, 1); - - /* Set menu mark to the string " > " */ - set_menu_mark(my_menu, " > "); - - /* Print a border around the main window and print a title */ - box(my_menu_win, 0, 0); - print_label(my_menu_win, 1, 0, 20, "New move unlocked", - COLOR_PAIR(S4C_CYAN)); - mvwaddch(my_menu_win, 2, 0, ACS_LTEE); - mvwhline(my_menu_win, 2, 1, ACS_HLINE, 26); - mvwaddch(my_menu_win, 2, 27, ACS_RTEE); - - /* Post the menu */ - post_menu(my_menu); - wrefresh(my_menu_win); - - //attron(COLOR_PAIR(2)); - //mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items"); - mvprintw(23, 0, "Select a new special move to learn."); - //attroff(COLOR_PAIR(2)); - //refresh(); - - refresh(); - - /* Prepare selection display window */ - display_win = newwin(18, 40, 3, 32); - box(display_win, 0, 0); - //Update selected window - cur = current_item(my_menu); - for (int i = 0; i < SPECIALSMAX + 1; i++) { - int check = -1; - if ((check = - strcmp(nameStringFromSpecial(f->class, i), item_name(cur))) == 0) { - currentIndexed = i; - break; - } - } - mvwprintw(display_win, 2, 2, "%s", - descStringFromSpecial(f->class, - f->specials[currentIndexed]->move)); - mvwprintw(display_win, 4, 2, "Energy Cost %i", - f->specials[currentIndexed]->cost); - wrefresh(my_menu_win); - wrefresh(display_win); - - int picked = 0; - int c; - - while (!picked && (c = wgetch(my_menu_win))) { - switch (c) { - case KEY_DOWN: { - menu_driver(my_menu, REQ_DOWN_ITEM); - cur = current_item(my_menu); - //Update selected window - for (int i = 0; i < SPECIALSMAX + 1; i++) { - int check = -1; - if ((check = - strcmp(nameStringFromSpecial(f->class, i), - item_name(cur))) == 0) { - currentIndexed = i; - break; - } - } - } - break; - case KEY_UP: { - menu_driver(my_menu, REQ_UP_ITEM); - cur = current_item(my_menu); - for (int i = 0; i < SPECIALSMAX + 1; i++) { - int check = -1; - if ((check = - strcmp(nameStringFromSpecial(f->class, i), - item_name(cur))) == 0) { - currentIndexed = i; - break; - } - } - } - break; - case KEY_NPAGE: { - menu_driver(my_menu, REQ_SCR_DPAGE); - cur = current_item(my_menu); - //Update selected window - for (int i = 0; i < SPECIALSMAX + 1; i++) { - int check = -1; - if ((check = - strcmp(nameStringFromSpecial(f->class, i), - item_name(cur))) == 0) { - currentIndexed = i; - break; - } - } - } - break; - case KEY_PPAGE: { - menu_driver(my_menu, REQ_SCR_UPAGE); - cur = current_item(my_menu); - for (int i = 0; i < SPECIALSMAX + 1; i++) { - int check = -1; - if ((check = - strcmp(nameStringFromSpecial(f->class, i), - item_name(cur))) == 0) { - currentIndexed = i; - break; - } - } - } - break; - case 10: { /*Enter */ - picked = 1; - cur = current_item(my_menu); - for (int i = 0; i < SPECIALSMAX + 1; i++) { - int check = -1; - if ((check = - strcmp(nameStringFromSpecial(f->class, i), - item_name(cur))) == 0) { - selection = i; - break; - } - - pos_menu_cursor(my_menu); - refresh(); - }; - break; - } - } - wclear(display_win); - wrefresh(display_win); - box(display_win, 0, 0); - mvwprintw(display_win, 2, 2, "%s", - descStringFromSpecial(f->class, - f->specials[currentIndexed]->move)); - mvwprintw(display_win, 4, 2, "Energy Cost %i", - f->specials[currentIndexed]->cost); - wrefresh(my_menu_win); - wrefresh(display_win); - refresh(); - } - /* Unpost and free all the memory taken up */ - unpost_menu(my_menu); - free_menu(my_menu); - for (int k = 0; k <= n_choices; k++) { - free_item(my_items[k]); - } - delwin(my_menu_win); - delwin(display_win); - endwin(); - - int num = selection; - - if (num < SPECIALSMAX + 1) { //Check if selected move number is lower than the maximum - Specialslot *selected = f->specials[num]; - - //Check if the selected move is NOT enabled - if (!(selected->enabled)) { - //Enable the move - selected->enabled = 1; - } - } - f->stats->specialsunlocked += 1; -} - -/** - * Takes a Fighter pointer and updated its stats. - * getBoost() is called to get the stat boost for current level, which is then applyed to atk, def and vel; while hp gets first multiplied by 1.13 and then gets the boost added. - * The totalenergy value is increased by player level over 5. - * Hp and energy are replenished. - * If the level is multiple of SPECIALLVLRATIO and the player still has at least one SpecialSlot not enabled, unlockSpecial() is called. - * @see Fighter - * @see getBoost() - * @see BaseStats - * @see SpecialSlot - * @see SPECIALSMAX - * @see SPECIALLVLRATIO - * @see unlockSpecial() - * @param player The Fighter pointer that levels up. - */ -void onLevelUp(Fighter *player) -{ - int boost = getBoost(player->level, player->luck); - - BaseStats *base = &basestats[player->class]; - - player->atk = (base->atk + boost); - player->def = (base->def + boost); - player->vel = (base->vel + boost); - player->totalhp = (base->hp * 1.13) + boost; - - int energyboost = player->level / 5; //Energy grows by lvl/5 on each lvl up - player->totalenergy = - base->totalenergy + energyboost + player->permboost_enr; - - player->hp = player->totalhp; //Cure on level up - player->energy = player->totalenergy; //Refill energy on level up - - //Check if you get a new special move - if (player->level % SPECIALLVLRATIO == 0 - && (player->stats->specialsunlocked < (SPECIALSMAX + 1))) { - unlockSpecial(player); - } - - log_tag("debug_log.txt", "[LEVELUP]", "Player leveled up."); - - /* - lightCyan(); - printf("\n\n\tYour wounds were healed."); - printf("\n\tYour energy is replenished."); - white(); - */ -} - -/** - * Takes a Fighter pointer and the amount of xp to add. - * Current level xp is managed by this function, including how much xp is needed to level up again. The values are stored in the fighter struct. - * Thresholds for each level are checked and eventually onLevelUp() is called, with recursion on this function after. - * @see Fighter - * @see onLevelUp() - * @param player The Fighter pointer that gets xp. - * @param xp The amount of xp. - */ -void checkremainder(Fighter *player, int xp) -{ - int curr = player->currentlevelxp; - int tot = player->totallevelxp; - - //TODO: Print notifications to a passed WINDOW - - if (curr + xp >= tot) { - player->totalxp += xp; - //if (xp !=0) printf("\n\t%s obtained %i xp.", player->name, xp); - player->level++; - - //cyan(); - //printf("\n\t%s reached Lvl. %i !", player->name, player->level); - //white(); - - //Stats gains on level up - onLevelUp(player); - - player->currentlevelxp = abs((tot - curr - xp)); - int nextLevelMoreXp = - round(1.75 * (player->level + 1)) + player->level + 1; - player->totallevelxp = (tot / player->level) + nextLevelMoreXp; - checkremainder(player, 0); - } else { - player->currentlevelxp += xp; - player->totalxp += xp; - if (xp != 0) { - //printf("\n\t%s obtained %i xp.", player->name, xp); - } - } -} - -/** - * Takes a Fighter and a Enemy pointers and handles xp gain by fighter. - * @see Fighter - * @see Enemy - * @see getEnemyXpGain() - * @see checkremainder() - * @param player The Fighter pointer that gets xp. - * @param e The Enemy pointer that gives xp. - */ -void giveXp(Fighter *player, Enemy *e) -{ - - int xp = getEnemyXpGain(e); - - checkremainder(player, xp); -} - -/** - * Takes a Fighter and a Boss pointers and handles xp gain by fighter. - * @see Fighter - * @see Boss - * @see getBossXpGain() - * @see checkremainder() - * @param player The Fighter pointer that gets xp. - * @param b The Boss pointer that gives xp. - */ -void giveXp_Boss(Fighter *player, Boss *b) -{ - - int xp = getBossXpGain(b); - - checkremainder(player, xp); -} - -/** - * Takes a Fighter pointer and an integer used to force execution. - * If the force parameter is true, all checks are ignored. - * If enemy's hp value is at least 50% of total, and none of atk, def or vel is 0 or less, nothing happens with an early return. - * Otherwise, getBoost() is called to calc the level stat boost for each stat. - * The BaseStats pointer for the fighter's fighterClass is loaded and each one of atk, def and vel is checked accounting for level boost. - * If none of them is below the respective treshold of 35, 18 and 30 % of total, nothing happens. - * Otherwise, all of them are reset to full amount accounting for permboosts and level boost. - * @see Fighter - * @see fighterClass - * @see getBoost() - * @param player The Fighter pointer to check the stats for. - * @param force The integer to bypass all checks if true. - */ -void statReset(Fighter *player, int force) -{ - log_tag("debug_log.txt", "[DEBUG]", - "Call to statReset() with ($force) == (%i)", force); - if (!force && (player->hp >= 0.5 * player->totalhp) - && !(player->atk <= 0 || player->def <= 0 || player->vel <= 0)) { - return; - } - - int boost = getBoost(player->level, player->luck); - - BaseStats *base = &basestats[player->class]; - if (force || player->vel <= 0.3 * (base->vel + boost) - || player->atk <= 0.35 * (base->atk + boost) - || player->def <= 0.18 * (base->def + boost)) { - player->vel = base->vel + boost + player->permboost_vel; - player->atk = base->atk + boost + player->permboost_atk; - player->def = base->def + boost + player->permboost_def; - //Reset stats - if (!force) { - //yellow(); - //printf("\n\n\t%s's stats reset.\n",player->name); - //white(); - } - } -} - -/** - * Takes a Fighter pointer value and adds a random Consumable to consumablesBag. - * @see Fighter - * @see Consumable - * @see consumableClass - * @see CONSUMABLESMAX - * @see stringFromConsumables() - * @param player The Fighter pointer at hand. - * @return int Returns the enum value of the drop as an integer. - */ -int dropConsumable(Fighter *player) -{ - int drop = rand() % (CONSUMABLESMAX + 1); - - //Special drop chances. Maybe a function for this? - if (drop == Powergem) { - if (rand() % 3 == 0) { - drop = rand() % (CONSUMABLESMAX + 1); - } - } - // Powergem has 33% chance to be rerolled - - Consumable *c = (Consumable *) player->consumablesBag[drop]; - c->qty++; - - //Update stats - player->stats->consumablesfound++; - - return drop; -} - -/** - * Takes a Fighter pointer value and an integer indicating if the drop was from a beast enemy, and adds a random Equip to the fighter's equipsBag. - * Prints notifications to the passed WINDOW pointer. - * The Equip dropped is initalised here, including stat variations for quality and level boosts (stat increase from base level by adding player level over EQUIPLVLBOOSTRATIO. - * The values of earliestBagSlot and equipsBagOccupiedSlots are managed. - * If equipsBag is full (EQUIPSBAGSIZE), user has to choose one Equip not currently equipped to be deleted and replaced by the new one. - * Special Equip functions are also set up here. - * @see Fighter - * @see Equip - * @see equipClass - * @see quality - * @see EQUIPLVLBOOSTRATIO - * @see EQUIPSBAGSIZE - * @see stringFromQuality() - * @see stringFromEquips() - * @param player The Fighter pointer at hand. - * @param beast The integer for drops coming from a beast kill if true. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - */ -void dropEquip(Fighter *player, int beast, WINDOW *notify_win, Koliseo *kls) -{ - - //Select a basic item from the list - int drop = rand() % (EQUIPSMAX + 1); - //Randomise quality - quality q = rand() % (QUALITIESMAX + 1); - - //Prepare the item - kls_log(kls, "DEBUG", "Prepping dropped Equip"); - Equip *e = - (Equip *) KLS_PUSH_TYPED(kls, Equip, HR_Equip, "Equip", "Equip"); - - //Get the base item and copy the stats to the drop - Equip *base = &equips[drop]; - - e->class = base->class; - e->type = base->type; - e->qual = q; - - setEquipSprite(e); - strcpy(e->name, base->name); - strcpy(e->desc, base->desc); - - e->qty = 1; - e->equipped = 0; - - e->perksCount = 0; - - //Calc drop level - e->level = base->level + round(player->level / EQUIPLVLBOOSTRATIO); - - //Chance for better leveled item - if ((rand() % 8) - (player->luck / 10) <= 0) { //Should use a defined constant - e->level += 1; //At least a simple +1 - if ((rand() % 25) - (player->luck / 10) <= 0) { //Should use a defined constant - e->level += 1; //A bonus roll for another +1 - - } - } - - float boostFactor = 0.7; - - float lvlBoost = boostFactor * (e->level - 1); - - e->atk = round((base->atk * 1.0) + lvlBoost); - e->def = round((base->def * 1.0) + lvlBoost); - e->vel = round((base->vel * 1.0) + lvlBoost); - e->enr = round((base->enr * 1.0) + lvlBoost); - - //Bonus stats on better quality items? Simple for now - // - if (q == Good) { - e->atk += (rand() % 3); //Should use a defined constant - e->def += (rand() % 3); //Should use a defined constant - e->vel += (rand() % 3); //Should use a defined constant - e->enr += (rand() % 2); //Should use a defined constant - } else if (q == Bad) { - e->atk -= (rand() % 3); //Should use a defined constant - e->def -= (rand() % 3); //Should use a defined constant - e->vel -= (rand() % 3); //Should use a defined constant - e->enr -= (rand() % 2); //Should use a defined constant - if (e->atk < 0) { - e->atk = 0; - }; - if (e->def < 0) { - e->def = 0; - }; - if (e->vel < 0) { - e->vel = 0; - }; - if (e->enr < 0) { - e->enr = 0; - }; - } - //Possible perks for the Equip - - for (int i = 0; i < (EQUIPPERKSMAX); i++) { - int chance = 20; - - if (q == Good) { - chance *= 1.5; - } - - if ((rand() % 100) < chance || (beast && e->perksCount == 0)) { - - e->perksCount += 1; - - log_tag("debug_log.txt", "[DEBUG]", - "Prepping Perk (%i) for dropped Equip)", e->perksCount); - kls_log(kls, "DEBUG", "Prepping Perk (%i) for dropped Equip)", - e->perksCount); - Perk *p = - (Perk *) KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); - p->class = rand() % (PERKSMAX + 1); - //p->name = (char*)malloc(sizeof(nameStringFromPerk(p->class))); - strcpy(p->name, nameStringFromPerk(p->class)); - //p->desc = (char*)malloc(sizeof(descStringFromPerk(p->class))); - strcpy(p->desc, descStringFromPerk(p->class)); - p->innerValue = 1; - e->perks[(e->perksCount - 1)] = p; - } - } - - //Set value of how many bonuses we have. Although Equip only has ONE function pointer field for now - e->bonus = base->bonus; - //Randomise if the item will have an effect function. - //Not yet implemented - //Initialisation of function happens here - // - //e->equip_fun = ; - - //Calc cost value - - float cost = 5; - - cost += 2.5 * (e->qual); - cost += 3.5 * (e->perksCount); - - cost += 7.2 * (e->level); - - e->cost = floor(cost); - - char msg[500]; - - wattron(notify_win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); - sprintf(msg, "You found %s %s!", stringFromQuality(q), - stringFromEquips(drop)); - display_notification(notify_win, msg, 800); - wattroff(notify_win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); - log_tag("debug_log.txt", "[DEBUG-DROPS]", "Found Equip: %s.", - stringFromEquips(drop)); - - if (player->equipsBagOccupiedSlots >= EQUIPSBAGSIZE) { //Handle full bag by asking player if we throw something away - //FIXME: The handling of full bag event is a mess as it does not support curses. - lightRed(); - printf("\tYour bag is full. Want to throw something away?\n"); - white(); - log_tag("debug_log.txt", "[DEBUG-EQUIPS]", - "Bag full, need to make space.\n"); - - for (int i = 0; i < player->equipsBagOccupiedSlots; i++) { - Equip *current = (Equip *) player->equipsBag[i]; - if (current->equipped) { - green(); - printf("ON "); - white(); - }; - - printf("(%i", i); //This starts lines with the item index. - printEquipStats(current); - }; - - int selected = -1; - int c = -1; - Equip *s = NULL; - - while (selected < 0 || selected >= player->equipsBagOccupiedSlots - || c != 1) { - - c = scanf("%i", &selected); - int res = scanf("%*c"); - log_tag("debug_log.txt", "[DEBUG]", - "dropEquip() scanf() res was (%i)", res); - - if (c == 1) { - s = (Equip *) player->equipsBag[selected]; - if (s->equipped) { - printf("You can't delete an equipped item!"); - selected = -1; - } - } - } - - printf - ("\tAre you sure you want to delete %s %s ?\n\t\t[0 to confirm, 1 to go back]\n", - stringFromQuality(s->qual), s->name); - - int n = -1; - c = -1; - while (n < 0 || c != 1) { - c = scanf("%i", &n); - int res = scanf("%*c"); - log_tag("debug_log.txt", "[DEBUG]", - "dropEquip() scanf() res was (%i)", res); - } - - if (n != 0) { //Abort deletion, drop will not be awared. - - /* - int perkscount = e->perksCount; - if (perkscount > 0) { - for (int i=0; i < perkscount; i++) { - free(e->perks[i]); - } - } - free(e); - */ - log_tag("debug_log.txt", "[DEBUG-EQUIPS]", - "Equip was not taken.\n"); - return; - }; - - Equip *toDelete = (Equip *) player->equipsBag[selected]; - int perkscount = toDelete->perksCount; - /* - if (perkscount > 0) { - for (int i=0; i < perkscount; i++) { - free(toDelete->perks[i]); - } - } - */ - log_tag("debug_log.txt", "[DEBUG-EQUIPS]", - "Equip %s (%i Perks) was taken by deleting %s.\n", - stringFromEquips(e->class), perkscount, - stringFromEquips(toDelete->class)); - /* - free(toDelete); - */ - - //Add drop to player bag replacing the one at the selected index - player->equipsBag[selected] = (struct Equip *)e; - - //Update stats - player->stats->equipsfound++; - - napms(500); - return; - }; //End if bag is full - - //Add drop to player bag - player->equipsBag[player->earliestBagSlot] = (struct Equip *)e; - - player->earliestBagSlot += 1; //Advance equips bage pointer - player->equipsBagOccupiedSlots += 1; //Advance equips bage size counter - - //Update stats - player->stats->equipsfound++; -} - -/** - * Takes a Fighter pointer value and adds a random Artifact to artifactsBag. - * The Artifact is randomised according to ARTIFACTSMAX until one which was not found yet drops. - * Special Equip functions are also set up here. - * @see Fighter - * @see Artifact - * @see artifactClass - * @see stringFromArtifacts() - * @param player The Fighter pointer at hand. - * @return int Returns the enum value of the drop as an integer. - */ -int dropArtifact(Fighter *player) -{ - int drop = 0; - do { - drop = rand() % (ARTIFACTSMAX + 1); - } while (player->artifactsBag[drop]->qty != 0); //We reroll to get one we don't have - - player->artifactsBag[drop]->qty++; - - //Update stats - player->stats->artifactsfound++; - - return drop; -} - -/** - * Takes a Fighter and a Enemy pointers and compares their stats to determine who gets damaged and returns the fightStatus value. - * Prints notifications to the passed WINDOW pointer. - * On enemy death, there's a chance to call dropConsumable, dropEquip or dropArtifact (guaranteed for beast enemies). - * @see Fighter - * @see Enemy - * @see statReset() - * @see statResetEnemy() - * @see stringFromEClass() - * @see dropConsumable() - * @see dropEquip() - * @see dropArtifact() - * @param player The Fighter pointer at hand. - * @param e The Enemy pointer at hand. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - * @see display_notification() - */ -int fight(Fighter *player, Enemy *e, WINDOW *notify_win, Koliseo *kls) -{ - - fightResult res = FIGHTRES_NO_DMG; - char msg[200]; - //Stat comparisons - // - - int atkdelta = (player->atk + player->equipboost_atk) - e->atk - (rand() % 3) - 1; //Skewed with defender - int defdelta = (player->def + player->equipboost_def) - e->def + (rand() % 2) + 1; //Skewed with attacker - int veldelta = - (player->vel + player->equipboost_vel) - e->vel + (rand() % 3) + 1; - - int atkOnPlayer = - e->atk - (player->def + player->equipboost_def + (player->vel / 6)); - int atkOnEnemy = - (player->atk + player->equipboost_atk) - (e->def + (e->vel / 6)); - - if (G_GODMODE_ON == 1) { - log_tag("debug_log.txt", "[DEBUG]", "fight(): G_GODMODE_ON == 1"); - atkdelta = 100; - defdelta = 100; - veldelta = 100; - atkOnPlayer = 1; - atkOnEnemy = 100; - } - - int damageDealt = -1; - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkdelta %i", atkdelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "defdelta %i", defdelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "veldelta %i", veldelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnEnemy %i", atkOnEnemy); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnPlayer %i", atkOnPlayer); - - if (veldelta >= 0) { - - if (atkOnEnemy > 3) { - damageDealt = atkOnEnemy; - e->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result A WIN (faster, great atk)."); - } else if (atkOnEnemy >= 0) { - damageDealt = abs(atkOnEnemy - atkdelta); - e->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result B WIN (faster, ok atk)."); - } else { - if (atkOnEnemy > -3) { - damageDealt = - fabsf(atkOnPlayer - - 0.75F * (player->vel + player->equipboost_vel)); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result C1 LOST (faster, atk > -3)."); - } else { - damageDealt = abs(atkOnPlayer - 1); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result C2 LOST (faster, atk < -3)."); - } - player->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - } - } else { - atkdelta = -atkdelta; - if (atkOnPlayer > 3) { - damageDealt = atkOnPlayer; - player->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result D LOST (slower, great enemy atk)."); - } else if (atkOnPlayer >= 0) { - damageDealt = abs(atkOnPlayer - atkdelta); - player->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result E LOST (slower, ok enemy atk)."); - } else { - if (atkOnPlayer > -3) { - damageDealt = fabsf(atkOnEnemy - 0.75F * e->vel); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result F1 WIN (slower, enemy atk > -3)."); - } else { - damageDealt = abs(atkOnEnemy - 1); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result F2 WIN (slower, enemy atk < -3)."); - } - e->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - } - } - log_tag("debug_log.txt", "[FIGHT]", "damageCalc %i", damageDealt); - - int yourhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; - char victim[25]; - - if (!yourhit) { - - e->vel--; - e->atk--; - e->def -= 2; - - //Check if someone earned a stat reset after the fight - statReset(player, 0); - statResetEnemy(e, 0); - - strcpy(victim, player->name); - } else { - - player->vel--; - player->atk--; - player->def -= 2; - - //Account for vampirism perk - int vampire_perks = player->perks[VAMPIRISM]->innerValue; - if (vampire_perks > 0) { - int recovery = floor(damageDealt * (0.1 * vampire_perks)); - player->hp += recovery; - log_tag("debug_log.txt", "[PERKS]", "Vampirism proc for +%i HP.", - recovery); - if (player->hp >= player->totalhp) { - player->hp = player->totalhp; - }; - } - //Account for burn on touch perk - int hotbody_perks = player->perks[HOT_BODY]->innerValue; - if (hotbody_perks > 0) { - int burnchance = 11 - hotbody_perks; - if (rand() % burnchance == 0) { - //TODO - //Handle multiple statuses - e->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once - setCounter((Turncounter *) e->counters[Burned], 2); //Give 2 turns of Burned status - log_tag("debug_log.txt", "[PERKS]", - "Hotbody proc on 1/%i chance.", burnchance); - } - } - //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? - int biohazard_perks = player->perks[BIOHAZARD]->innerValue; - if (biohazard_perks > 0) { - int poisonchance = 11 - biohazard_perks; - if (rand() % poisonchance == 0) { - e->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once - setCounter((Turncounter *) e->counters[POISON], 2); //Give 2 turns of Poison status - log_tag("debug_log.txt", "[PERKS]", - "Biohazard proc on 1/%i chance.", poisonchance); - } - } - //Check if someone earned a stat reset after the fight - statResetEnemy(e, 0); - statReset(player, 0); - - strcpy(victim, stringFromEClass(e->class)); - } - - int color = -1; - if (yourhit) { - color = S4C_WHITE; - } else { - color = S4C_RED; - } - - sprintf(msg, "%s was hit. (%i DMG)", victim, - damageDealt > 0 ? damageDealt : 1); - wattron(notify_win, COLOR_PAIR(color)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - - //Rolls - // - //Critical hit roll - - //Account for critboost_chance perks - int critboost_value = 1.5 * player->perks[CRITBOOST_CHANCE]->innerValue; - int critMax = round(10.0 - floor(player->luck / 5) - (critboost_value)); - - int critRes = (rand() % critMax); - - if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { - - //Account for critboost_dmg perks - int dmgboost_perks = player->perks[CRITBOOST_DMG]->innerValue; - damageDealt *= (0.30 + (0.12 * dmgboost_perks)); - e->hp -= (damageDealt > 0 ? damageDealt : 1); - log_tag("debug_log.txt", "[FIGHT]", - "Critical hit for %i dmg, proc on 1/%i chance.", damageDealt, - critMax); - log_tag("debug_log.txt", "[PERKS]", "Critical hit, critboost was %i.", - critboost_value); - - sprintf(msg, "A critical hit! (%i DMG)", - damageDealt > 0 ? damageDealt : 1); - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - //Update stats - player->stats->criticalhits++; - } - //Check for deaths -> exit condition from loop - // - // - // - if (e->hp <= 0) { - res = FIGHTRES_KILL_DONE; - - //Account for runic circle perk - int runic_perks = player->perks[RUNIC_MAGNET]->innerValue; - if (runic_perks > 0) { - int recovery = round(0.51 * runic_perks); - player->energy += recovery; - log_tag("debug_log.txt", "[PERKS]", - "Runicmagnet proc for %i energy.", recovery); - } - if (e->beast) { - color = S4C_MAGENTA; - } else { - color = S4C_RED; - } - wattron(notify_win, COLOR_PAIR(color)); - sprintf(msg, "%s fainted.", stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - - log_tag("debug_log.txt", "[FIGHT]", "Killed %s.", - stringFromEClass(e->class)); - - //Update stats - player->stats->enemieskilled++; - } else { - //Apply status effects to enemy - if (e->status != Normal) { - applyEStatus(notify_win, e); - log_tag("debug_log.txt", "[STATUS]", "Applied %s to %s.", - stringFromStatus(e->status), stringFromEClass(e->class)); - } - } - - if (player->hp <= 0) { - res = FIGHTRES_DEATH; - } else { - //Apply status effects to player - if (player->status != Normal) { - applyStatus(notify_win, player); - } - } - - //Consumable drop, guaranteed on killing a beast - if (res == FIGHTRES_KILL_DONE - && (e->beast || ((rand() % 9) - (player->luck / 10) <= 0))) { - int drop = dropConsumable(player); - sprintf(msg, "You found a %s!", stringFromConsumables(drop)); - wattron(notify_win, COLOR_PAIR(S4C_CYAN)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); - log_tag("debug_log.txt", "[DROPS]", "Found Consumable: %s.", - stringFromConsumables(drop)); - } - - //Artifact drop (if we don't have all of them), guaranteed on killing a beast - if ((player->stats->artifactsfound != ARTIFACTSMAX + 1) - && res == FIGHTRES_KILL_DONE && (e->beast - || - ((rand() % ENEMY_ARTIFACTDROP_CHANCE) - - (player->luck / 10) <= 0))) { - int artifact_drop = dropArtifact(player); - sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - log_tag("debug_log.txt", "[DROPS]", "Found Artifact: %s.", - stringFromArtifacts(artifact_drop)); - if (!e->beast) - log_tag("debug_log.txt", "[.1%% CHANCE]", - "\nNORMAL ENEMY DROPPED ARTIFACT! 0.1%% chance??\n"); - } - - //Equip drop, guaranteed on killing a beast - if (res == FIGHTRES_KILL_DONE - && (e->beast || ((rand() % 15) - (player->luck / 10) <= 0))) { - dropEquip(player, e->beast, notify_win, kls); - } - return res; -} - -/** - * Takes an Enemy and a Fighter pointer and compares their stats to determine who gets damaged and returns the fightStatus value. - * Prints notifications to the passed WINDOW pointer. - * On enemy death, there's a chance to call dropConsumable, dropEquip or dropArtifact (guaranteed for beast enemies). - * NOTE: that the return values are always from the POV of the Fighter: FIGHTRES_DMG_DEALT means the Enemy was damaged! - * @see defer_fight_enemy() - * @see Fighter - * @see Enemy - * @see statReset() - * @see statResetEnemy() - * @see stringFromEClass() - * @see dropConsumable() - * @see dropEquip() - * @see dropArtifact() - * @param player The Fighter pointer at hand. - * @param e The Enemy pointer at hand. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - * @see display_notification() - */ -int enemy_attack(Enemy *e, Fighter *target, WINDOW *notify_win, Koliseo *kls) -{ - //Implementation similar to fight(), as a base idea - //Should return fightResult values, while keeping the perspective on the Fighter, as in: - // - // FIGHTRES_DEATH means the Fighter died - // FIGHTRES_KILL_DONE means the Enemy died - // FIGHTRES_DMG_DEALT means the Fighter inflicted damage - // FIGHRES_DMG_TAKEN means the Fighter received damage - - fightResult res = FIGHTRES_NO_DMG; - char msg[200]; - //Stat comparisons - // - - int atkdelta = (e->atk + e->turnboost_atk) - (target->atk + target->equipboost_atk + target->turnboost_atk - (rand() % 3)) - 1; //Skewed with defender - int defdelta = (e->def + e->turnboost_def) - (target->def + target->equipboost_def + target->turnboost_def) + (rand() % 2) + 1; //Skewed with attacker - int veldelta = - (e->vel + e->turnboost_vel) - (target->vel + target->equipboost_vel + - target->turnboost_vel) + (rand() % 3) + - 1; - - int atkOnPlayer = - (e->atk + e->turnboost_atk) - (target->def + target->equipboost_def + - target->turnboost_def + - (target->vel / 6)); - int atkOnEnemy = - (target->atk + target->equipboost_atk + target->turnboost_atk) - - (e->def + e->turnboost_def + (e->vel / 6)); - - if (G_GODMODE_ON == 1) { - log_tag("debug_log.txt", "[DEBUG]", "[%s]: G_GODMODE_ON == 1", - __func__); - atkdelta = -100; - defdelta = -100; - veldelta = -100; - atkOnPlayer = 1; - atkOnEnemy = 100; - } - - int damageDealt = -1; - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkdelta %i", atkdelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "defdelta %i", defdelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "veldelta %i", veldelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnEnemy %i", atkOnEnemy); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnPlayer %i", atkOnPlayer); - - if (veldelta >= 0) { //Enemy has a non-negative veldelta - if (atkOnPlayer > 3) { - damageDealt = atkOnPlayer; - target->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result D LOST (slower, great enemy atk).", - __func__); - } else if (atkOnPlayer >= 0) { - damageDealt = abs(atkOnPlayer - atkdelta); - target->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result E LOST (slower, ok enemy atk).", - __func__); - } else { - if (atkOnPlayer > -3) { - damageDealt = fabsf(atkOnEnemy - 0.75F * e->vel); - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result F1 WIN (slower, enemy atk > -3).", - __func__); - } else { - damageDealt = abs(atkOnEnemy - 1); - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result F2 WIN (slower, enemy atk < -3).", - __func__); - } - e->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - } - } else { //Enemy veldelta is not strictly positive - atkdelta = -atkdelta; - if (atkOnEnemy > 3) { - damageDealt = atkOnEnemy; - e->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result A WIN (faster, great atk).", __func__); - } else if (atkOnEnemy >= 0) { - damageDealt = abs(atkOnEnemy - atkdelta); - e->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result B WIN (faster, ok atk).", __func__); - } else { - if (atkOnEnemy > -3) { - damageDealt = - fabsf(atkOnPlayer - - 0.75F * (target->vel + target->equipboost_vel)); - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result C1 LOST (faster, atk > -3).", - __func__); - } else { - damageDealt = abs(atkOnPlayer - 1); - log_tag("debug_log.txt", "[FIGHT]", - "[%s]: Fight result C2 LOST (faster, atk < -3).", - __func__); - } - target->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - } - } - log_tag("debug_log.txt", "[FIGHT]", "[%s]: damageCalc %i", __func__, - damageDealt); - - int playerhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; - char victim[25]; - - if (!playerhit) { - - e->vel--; - e->atk--; - e->def -= 2; - - //Check if someone earned a stat reset after the fight - statReset(target, 0); - statResetEnemy(e, 0); - - strcpy(victim, target->name); - } else { - - target->vel--; - target->atk--; - target->def -= 2; - - //Account for vampirism perk - int vampire_perks = target->perks[VAMPIRISM]->innerValue; - if (vampire_perks > 0) { - int recovery = floor(damageDealt * (0.1 * vampire_perks)); - target->hp += recovery; - log_tag("debug_log.txt", "[PERKS]", "Vampirism proc for +%i HP.", - recovery); - if (target->hp >= target->totalhp) { - target->hp = target->totalhp; - }; - } - //Account for burn on touch perk - int hotbody_perks = target->perks[HOT_BODY]->innerValue; - if (hotbody_perks > 0) { - int burnchance = 11 - hotbody_perks; - if (rand() % burnchance == 0) { - //TODO - //Handle multiple statuses - e->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once - setCounter((Turncounter *) e->counters[Burned], 2); //Give 2 turns of Burned status - log_tag("debug_log.txt", "[PERKS]", - "Hotbody proc on 1/%i chance.", burnchance); - } - } - //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? - int biohazard_perks = target->perks[BIOHAZARD]->innerValue; - if (biohazard_perks > 0) { - int poisonchance = 11 - biohazard_perks; - if (rand() % poisonchance == 0) { - e->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once - setCounter((Turncounter *) e->counters[POISON], 2); //Give 2 turns of Poison status - log_tag("debug_log.txt", "[PERKS]", - "Biohazard proc on 1/%i chance.", poisonchance); - } - } - //Check if someone earned a stat reset after the fight - statResetEnemy(e, 0); - statReset(target, 0); - - strcpy(victim, stringFromEClass(e->class)); - } - - int color = -1; - if (playerhit) { - color = S4C_WHITE; - } else { - color = S4C_RED; - } - - sprintf(msg, "%s was hit. (%i DMG)", victim, - damageDealt > 0 ? damageDealt : 1); - wattron(notify_win, COLOR_PAIR(color)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - - //Rolls - // - //Critical hit roll - - //Account for critboost_chance perks - int critboost_value = 1.5 * target->perks[CRITBOOST_CHANCE]->innerValue; - int critMax = round(10.0 - floor(target->luck / 5) - (critboost_value)); - - int critRes = (rand() % critMax); - - if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { - - //Account for critboost_dmg perks - int dmgboost_perks = target->perks[CRITBOOST_DMG]->innerValue; - damageDealt *= (0.30 + (0.12 * dmgboost_perks)); - e->hp -= (damageDealt > 0 ? damageDealt : 1); - log_tag("debug_log.txt", "[FIGHT]", - "Critical hit for %i dmg, proc on 1/%i chance.", damageDealt, - critMax); - log_tag("debug_log.txt", "[PERKS]", "Critical hit, critboost was %i.", - critboost_value); - - sprintf(msg, "A critical hit! (%i DMG)", - damageDealt > 0 ? damageDealt : 1); - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - //Update stats - target->stats->criticalhits++; - } - //Check for deaths -> exit condition from loop - // - // - // - if (e->hp <= 0) { - res = FIGHTRES_KILL_DONE; - - //Account for runic circle perk - int runic_perks = target->perks[RUNIC_MAGNET]->innerValue; - if (runic_perks > 0) { - int recovery = round(0.51 * runic_perks); - target->energy += recovery; - log_tag("debug_log.txt", "[PERKS]", - "Runicmagnet proc for %i energy.", recovery); - } - if (e->beast) { - color = S4C_MAGENTA; - } else { - color = S4C_RED; - } - wattron(notify_win, COLOR_PAIR(color)); - sprintf(msg, "%s fainted.", stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - - log_tag("debug_log.txt", "[FIGHT]", "Killed %s.", - stringFromEClass(e->class)); - - //Update stats - target->stats->enemieskilled++; - } else { - //Apply status effects to enemy - if (e->status != Normal) { - applyEStatus(notify_win, e); - log_tag("debug_log.txt", "[STATUS]", "Applied %s to %s.", - stringFromStatus(e->status), stringFromEClass(e->class)); - } - } - - if (target->hp <= 0) { - log_tag("debug_log.txt", "[DEBUG]", "[%s]: Target died. Hp: (%i)", - __func__, target->hp); - res = FIGHTRES_DEATH; - } else { - //Apply status effects to target - if (target->status != Normal) { - applyStatus(notify_win, target); - } - } - - //Consumable drop, guaranteed on killing a beast - if (res == FIGHTRES_KILL_DONE - && (e->beast || ((rand() % 9) - (target->luck / 10) <= 0))) { - int drop = dropConsumable(target); - sprintf(msg, "You found a %s!", stringFromConsumables(drop)); - wattron(notify_win, COLOR_PAIR(S4C_CYAN)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); - log_tag("debug_log.txt", "[DROPS]", "Found Consumable: %s.", - stringFromConsumables(drop)); - } - - //Artifact drop (if we don't have all of them), guaranteed on killing a beast - if ((target->stats->artifactsfound != ARTIFACTSMAX + 1) - && res == FIGHTRES_KILL_DONE && (e->beast - || - ((rand() % ENEMY_ARTIFACTDROP_CHANCE) - - (target->luck / 10) <= 0))) { - int artifact_drop = dropArtifact(target); - sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - log_tag("debug_log.txt", "[DROPS]", "Found Artifact: %s.", - stringFromArtifacts(artifact_drop)); - if (!e->beast) - log_tag("debug_log.txt", "[.1%% CHANCE]", - "\nNORMAL ENEMY DROPPED ARTIFACT! 0.1%% chance??\n"); - } - - //Equip drop, guaranteed on killing a beast - if (res == FIGHTRES_KILL_DONE - && (e->beast || ((rand() % 15) - (target->luck / 10) <= 0))) { - dropEquip(target, e->beast, notify_win, kls); - } - return res; -} - -/** - * Takes a Fighter and a Enemy pointers and calls fight(). - * @see Fighter - * @see Enemy - * @see fight() - * @param player The Fighter pointer at hand. - * @param e The Enemy pointer at hand. - * @param foe_op The foeTurnOption_OP for the foe. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - */ -int defer_fight_enemy(Fighter *player, Enemy *e, foeTurnOption_OP foe_op, - WINDOW *notify_win, Koliseo *kls) -{ - char msg[200]; - //FIXME - //Is it okay to return just one result, when having 2 interactions that could go differently? - // - //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. - fightResult res = FIGHTRES_NO_DMG; - - int player_goes_first = (player->vel >= e->vel ? 1 : 0); - - int first_act_res = FIGHTRES_NO_DMG; - - if (player_goes_first) { - - res = fight(player, e, notify_win, kls); - - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - first_act_res = res; - - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromEClass(e->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromEClass(e->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is angry!", stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - - res = enemy_attack(e, player, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", - __func__, stringFromEClass(e->class)); - //TODO - //Implement enemy special function - //res = enemy_attack_special(e,player,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", - __func__, foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was not a clash...", __func__); - } else if ((res == FIGHTRES_DMG_TAKEN - && first_act_res == FIGHTRES_DMG_DEALT) - || (res == FIGHTRES_DMG_DEALT - && first_act_res == FIGHTRES_DMG_TAKEN)) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was a clash!", __func__); - res = FIGHTRES_CLASH; - } - - return res; - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } else { - //Foe acts first - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromEClass(e->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromEClass(e->class)); - res = enemy_attack(e, player, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", __func__, - stringFromEClass(e->class)); - //TODO - //Implement enemy special function - //res = enemy_attack_special(e,player,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - first_act_res = res; - - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - res = fight(player, e, notify_win, kls); - - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was not a clash...", __func__); - } else if ((res == FIGHTRES_DMG_TAKEN - && first_act_res == FIGHTRES_DMG_DEALT) - || (res == FIGHTRES_DMG_DEALT - && first_act_res == FIGHTRES_DMG_TAKEN)) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was a clash!", __func__); - res = FIGHTRES_CLASH; - } - - return res; - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } - return res; -} - -/** - * Takes a Fighter and a Enemy pointers and calls do_Skill(). - * @see Fighter - * @see Enemy - * @see do_Skill() - * @param player The Fighter pointer at hand. - * @param e The Enemy pointer at hand. - * @param picked_skill The picked skill by Fighter. - * @param foe_op The foeTurnOption_OP for the foe. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - */ -int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, - WINDOW *notify_win, Koliseo *kls) -{ - char msg[200]; - //FIXME - //Is it okay to return just one result, when having 2 interactions that could go differently? - // - //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. - fightResult res = FIGHTRES_NO_DMG; - - int player_goes_first = (player->vel >= e->vel ? 1 : 0); - - int first_act_res = FIGHTRES_NO_DMG; - - if (player_goes_first) { - - res = do_Skill(player, e, picked_skill, notify_win, kls); - - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - first_act_res = res; - - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromEClass(e->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromEClass(e->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is angry!", stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - - res = enemy_attack(e, player, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", - __func__, stringFromEClass(e->class)); - //TODO - //Implement enemy special function - //res = enemy_attack_special(e,player,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", - __func__, foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was not a clash...", __func__); - } else if ((res == FIGHTRES_DMG_TAKEN - && first_act_res == FIGHTRES_DMG_DEALT) - || (res == FIGHTRES_DMG_DEALT - && first_act_res == FIGHTRES_DMG_TAKEN)) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was a clash!", __func__); - res = FIGHTRES_CLASH; - } - - return res; - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } else { - //Foe acts first - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromEClass(e->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromEClass(e->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromEClass(e->class)); - res = enemy_attack(e, player, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", __func__, - stringFromEClass(e->class)); - //TODO - //Implement enemy special function - //res = enemy_attack_special(e,player,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - first_act_res = res; - - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - res = do_Skill(player, e, picked_skill, notify_win, kls); - - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was not a clash...", __func__); - } else if ((res == FIGHTRES_DMG_TAKEN - && first_act_res == FIGHTRES_DMG_DEALT) - || (res == FIGHTRES_DMG_DEALT - && first_act_res == FIGHTRES_DMG_TAKEN)) { - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Deferred fight was a clash!", __func__); - res = FIGHTRES_CLASH; - } - - return res; - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } - return res; -} - -/** - * Takes a Fighter, a Boss and a Path pointers and compares fighters stats to determine who gets damaged and returns the fightStatus value. - * Prints notifications to the passed WINDOW pointer. - * On boss death, we call dropConsumable, dropEquip and dropArtifact. - * @see Fighter - * @see Boss - * @see statReset() - * @see statResetBoss() - * @see stringFromBossClass() - * @see dropConsumable() - * @see dropEquip() - * @see dropArtifact() - * @param player The Fighter pointer at hand. - * @param b The Enemy pointer at hand. - * @param p The Path pointer for the game. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - * @see display_notification() - */ -int boss_fight(Fighter *player, Boss *b, Path *p, WINDOW *notify_win, - Koliseo *kls) -{ - - fightResult res = FIGHTRES_NO_DMG; - //Stat comparisons - // - char msg[200]; - - int atkdelta = (player->atk + player->equipboost_atk) - b->atk - (rand() % 3) - 1; //Skewed with defender - int defdelta = (player->def + player->equipboost_def) - b->def + (rand() % 2) + 1; //Skewed with attacker - int veldelta = - (player->vel + player->equipboost_vel) - b->vel + (rand() % 3) + 1; - - int atkOnPlayer = - b->atk - (player->def + player->equipboost_def + (player->vel / 6)); - int atkOnEnemy = - (player->atk + player->equipboost_atk) - (b->def + (b->vel / 6)); - if (G_GODMODE_ON == 1) { - log_tag("debug_log.txt", "[DEBUG]", "boss_fight(): G_GODMODE_ON == 1"); - atkdelta = 100; - defdelta = 100; - veldelta = 100; - atkOnPlayer = 1; - atkOnEnemy = 100; - } - sprintf(msg, "atkdelta %i", atkdelta); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - sprintf(msg, "defdelta %i", defdelta); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - sprintf(msg, "veldelta %i", veldelta); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - sprintf(msg, "atkOnEnemy %i", atkOnEnemy); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - sprintf(msg, "atkOnPlayer %i\n", atkOnPlayer); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - - int damageDealt = -1; - - if (veldelta >= 0) { - - if (atkOnEnemy > 3) { - damageDealt = atkOnEnemy; - b->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result A WIN (faster, great atk).\n"); - } else if (atkOnEnemy >= 0) { - damageDealt = abs(atkOnEnemy - atkdelta); - b->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result B WIN (faster, ok atk).\n"); - } else { - if (atkOnEnemy < -3) { - damageDealt = - fabsf(atkOnPlayer - - 0.75F * (player->vel + player->equipboost_vel)); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result C1 LOST (faster, atk < -3).\n"); - } else { - damageDealt = abs(atkOnPlayer - 1); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result C2 LOST (faster, atk > -3).\n"); - } - player->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - } - } else { - atkdelta = -atkdelta; - if (atkOnPlayer > 3) { - damageDealt = atkOnPlayer; - player->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result D LOST (slower, great enemy atk.\n"); - } else if (atkOnPlayer >= 0) { - damageDealt = abs(atkOnPlayer - atkdelta); - player->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result E LOST (slower, ok enemy atk.\n"); - } else { - if (atkOnPlayer < -3) { - damageDealt = fabsf(atkOnEnemy - 0.75F * b->vel); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result F1 WIN (slower, enemy atk < -3.\n"); - } else { - damageDealt = abs(atkOnEnemy - 1); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result F2 WIN (slower, enemy atk > -3.\n"); - } - b->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - } - } - - log_tag("debug_log.txt", "[FIGHT]", "damageCalc %i", damageDealt); - - int yourhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; - char victim[25]; - - if (!yourhit) { - - b->vel--; - b->atk--; - b->def -= 2; - - //Check if someone earned a stat reset after the fight - statReset(player, 0); - statResetBoss(b, 0); - - strcpy(victim, player->name); - } else { - - player->vel--; - player->atk--; - player->def -= 2; - - //Account for vampirism perk - int vampire_perks = player->perks[VAMPIRISM]->innerValue; - if (vampire_perks > 0) { - int recovery = floor(damageDealt * (0.1 * vampire_perks)); - player->hp += recovery; - sprintf(msg, "Vampirism proc for +%i HP.\n", recovery); - log_tag("debug_log.txt", "[PERKS]", msg); - if (player->hp >= player->totalhp) { - player->hp = player->totalhp; - }; - } - //Account for burn on touch perk - int hotbody_perks = player->perks[HOT_BODY]->innerValue; - if (hotbody_perks > 0) { - int burnchance = 11 - hotbody_perks; - if (rand() % burnchance == 0) { - b->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once - setCounter((Turncounter *) b->counters[Burned], 2); //Give 2 turns of Burned status - sprintf(msg, "Hotbody proc on 1/%i chance.\n", burnchance); - log_tag("debug_log.txt", "[PERKS]", msg); - } - } - //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? - int biohazard_perks = player->perks[BIOHAZARD]->innerValue; - if (biohazard_perks > 0) { - int poisonchance = 11 - biohazard_perks; - if (rand() % poisonchance == 0) { - b->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once - setCounter((Turncounter *) b->counters[POISON], 2); //Give 2 turns of Poison status - sprintf(msg, "Biohazard proc on 1/%i chance.\n", poisonchance); - log_tag("debug_log.txt", "[PERKS]", msg); - } - } - //Check if someone earned a stat reset after the fight - statResetBoss(b, 0); - statReset(player, 0); - - strcpy(victim, stringFromBossClass(b->class)); - } - - int color = -1; - if (yourhit) { - color = S4C_WHITE; - } else { - color = S4C_RED; - } - - wattron(notify_win, COLOR_PAIR(color)); - sprintf(msg, "%s was hit. (%i DMG)", victim, - damageDealt > 0 ? damageDealt : 1); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - - //Rolls - // - //Critical hit roll - - //Account for critboost_chance perks - int critMax = - round(10.0 - floor(player->luck / 5) - - (1.5 * player->perks[CRITBOOST_CHANCE]->innerValue)); - - int critRes = (rand() % critMax); - - if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { - - //Account for critboost_dmg perks - int dmgboost_perks = player->perks[CRITBOOST_DMG]->innerValue; - damageDealt *= (0.30 + (0.12 * dmgboost_perks)); - b->hp -= damageDealt > 0 ? damageDealt : 1; - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - sprintf(msg, "A critical hit! (%i DMG)", - damageDealt > 0 ? damageDealt : 1); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - sprintf(msg, "Critical hit for %i dmg, proc on 1/%i chance.\n", - damageDealt, critMax); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - - //Update stats - player->stats->criticalhits++; - } - //Check for deaths -> exit condition from loop - // - // - // - if (b->hp <= 0) { - res = FIGHTRES_KILL_DONE; - - //Account for runic circle perk - int runic_perks = player->perks[RUNIC_MAGNET]->innerValue; - if (runic_perks > 0) { - int recovery = round(0.51 * runic_perks); - player->energy += recovery; - sprintf(msg, "Runicmagnet proc for %i energy.\n", recovery); - log_tag("debug_log.txt", "[PERKS]", msg); - } - if (b->beast) { - color = S4C_MAGENTA; - } else { - color = S4C_RED; - } - wattron(notify_win, COLOR_PAIR(color)); - sprintf(msg, "%s fainted.", stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - sprintf(msg, "Killed %s.", stringFromBossClass(b->class)); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - - //Update stats - player->stats->bosseskilled++; - - //Check if we killed this boss before - if (player->stats->killed_bosses[b->class] == 0) { - //Update stats - player->stats->unique_bosseskilled++; - player->stats->killed_bosses[b->class] += 1; - //Check if we have to update the wincon value - if (p->win_condition->class == ALL_BOSSES) { - p->win_condition->current_val++; - } - sprintf(msg, "Killed new boss %s.\n", - stringFromBossClass(b->class)); - log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); - } - } else { - //Apply status effects to boss - if (b->status != Normal) { - applyBStatus(notify_win, b); - sprintf(msg, "Applied %s to %s.", stringFromStatus(b->status), - stringFromBossClass(b->class)); - log_tag("debug_log.txt", "[STATUS]", msg); - } - } - - if (player->hp <= 0) { - res = FIGHTRES_DEATH; - } else { - //Apply status effects to player - if (player->status != Normal) { - applyStatus(notify_win, player); - } - } - - //Consumable drop, guaranteed on killing a beast - if (res == FIGHTRES_KILL_DONE) { - int drop = dropConsumable(player); - wattron(notify_win, COLOR_PAIR(S4C_CYAN)); - sprintf(msg, "You found a %s!", stringFromConsumables(drop)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); - sprintf(msg, "Found Consumable: %s.", stringFromConsumables(drop)); - log_tag("debug_log.txt", "[DROPS]", msg); - } - - //Artifact drop (if we don't have all of them) - if (res == FIGHTRES_KILL_DONE - && (player->stats->artifactsfound != ARTIFACTSMAX + 1)) { - int artifact_drop = dropArtifact(player); - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - sprintf(msg, "Found Artifact: %s.", - stringFromArtifacts(artifact_drop)); - log_tag("debug_log.txt", "[DROPS]", msg); - } - //Equip drop - if (res == FIGHTRES_KILL_DONE) { - //We give 1 to obtain the better equip generation used for beasts - dropEquip(player, 1, notify_win, kls); - } - - return res; -} - -int boss_attack(Boss *b, Fighter *target, Path *p, WINDOW *notify_win, - Koliseo *kls) -{ - - //TODO - //Implementation similar to boss_fight(), as a base idea - //Should return fightResult values, while keeping the perspective on the Fighter, as in: - // - // FIGHTRES_DEATH means the Fighter died - // FIGHTRES_KILL_DONE means the Boss died - // FIGHTRES_DMG_DEALT means the Fighter inflicted damage - // FIGHRES_DMG_TAKEN means the Fighter received damage - fightResult res = FIGHTRES_NO_DMG; - //Stat comparisons - // - char msg[200]; - - int atkdelta = (b->atk + b->turnboost_atk) - (target->atk + target->equipboost_atk + target->turnboost_atk - (rand() % 3)) - 1; //Skewed with defender - int defdelta = (b->def + b->turnboost_def) - (target->def + target->equipboost_def + target->turnboost_def) + (rand() % 2) + 1; //Skewed with attacker - int veldelta = - (b->vel + b->turnboost_vel) - (target->vel + target->equipboost_vel + - target->turnboost_vel) + (rand() % 3) + - 1; - - int atkOnPlayer = - (b->atk + b->turnboost_atk) - (target->def + target->equipboost_def + - target->turnboost_def + - (target->vel / 6)); - int atkOnEnemy = - (target->atk + target->equipboost_atk + target->turnboost_atk) - - (b->def + b->turnboost_def + (b->vel / 6)); - if (G_GODMODE_ON == 1) { - log_tag("debug_log.txt", "[DEBUG]", "[%s]: G_GODMODE_ON == 1", - __func__); - atkdelta = -100; - defdelta = -100; - veldelta = -100; - atkOnPlayer = 1; - atkOnEnemy = 100; - } - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkdelta %i", atkdelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "defdelta %i", defdelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "veldelta %i", veldelta); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnEnemy %i", atkOnEnemy); - log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnPlayer %i", atkOnPlayer); - - int damageDealt = -1; - - if (veldelta >= 0) { //Boss was faster - if (atkOnPlayer > 3) { - damageDealt = atkOnPlayer; - target->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result D LOST (slower, great enemy atk."); - } else if (atkOnPlayer >= 0) { - damageDealt = abs(atkOnPlayer - atkdelta); - target->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result E LOST (slower, ok enemy atk."); - } else { - if (atkOnPlayer < -3) { - damageDealt = fabsf(atkOnEnemy - 0.75F * b->vel); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result F1 WIN (slower, enemy atk < -3."); - } else { - damageDealt = abs(atkOnEnemy - 1); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result F2 WIN (slower, enemy atk > -3."); - } - b->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - } - } else { //Target was faster - atkdelta = -atkdelta; - if (atkOnEnemy > 3) { - damageDealt = atkOnEnemy; - b->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result A WIN (faster, great atk)."); - } else if (atkOnEnemy >= 0) { - damageDealt = abs(atkOnEnemy - atkdelta); - b->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_DEALT; - log_tag("debug_log.txt", "[FIGHT]", - "Fight result B WIN (faster, ok atk)."); - } else { - if (atkOnEnemy < -3) { - damageDealt = - fabsf(atkOnPlayer - - 0.75F * (target->vel + target->equipboost_vel)); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result C1 LOST (faster, atk < -3)."); - } else { - damageDealt = abs(atkOnPlayer - 1); - log_tag("debug_log.txt", "[FIGHT]", - "Fight result C2 LOST (faster, atk > -3)."); - } - target->hp -= damageDealt > 0 ? damageDealt : 1; - res = FIGHTRES_DMG_TAKEN; - } - } - - log_tag("debug_log.txt", "[FIGHT]", "damageCalc %i", damageDealt); - - int yourhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; - char victim[25]; - - if (!yourhit) { - - b->vel--; - b->atk--; - b->def -= 2; - - //Check if someone earned a stat reset after the fight - statReset(target, 0); - statResetBoss(b, 0); - - strcpy(victim, target->name); - } else { - - target->vel--; - target->atk--; - target->def -= 2; - - //Account for vampirism perk - int vampire_perks = target->perks[VAMPIRISM]->innerValue; - if (vampire_perks > 0) { - int recovery = floor(damageDealt * (0.1 * vampire_perks)); - target->hp += recovery; - log_tag("debug_log.txt", "[PERKS]", "Vampirism proc for +%i HP.", - recovery); - if (target->hp >= target->totalhp) { - target->hp = target->totalhp; - }; - } - //Account for burn on touch perk - int hotbody_perks = target->perks[HOT_BODY]->innerValue; - if (hotbody_perks > 0) { - int burnchance = 11 - hotbody_perks; - if (rand() % burnchance == 0) { - b->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once - setCounter((Turncounter *) b->counters[Burned], 2); //Give 2 turns of Burned status - log_tag("debug_log.txt", "[PERKS]", - "Hotbody proc on 1/%i chance.", burnchance); - } - } - //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? - int biohazard_perks = target->perks[BIOHAZARD]->innerValue; - if (biohazard_perks > 0) { - int poisonchance = 11 - biohazard_perks; - if (rand() % poisonchance == 0) { - b->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once - setCounter((Turncounter *) b->counters[POISON], 2); //Give 2 turns of Poison status - log_tag("debug_log.txt", "[PERKS]", - "Biohazard proc on 1/%i chance.", poisonchance); - } - } - //Check if someone earned a stat reset after the fight - statResetBoss(b, 0); - statReset(target, 0); - - strcpy(victim, stringFromBossClass(b->class)); - } - - int color = -1; - if (yourhit) { - color = S4C_WHITE; - } else { - color = S4C_RED; - } - - wattron(notify_win, COLOR_PAIR(color)); - sprintf(msg, "%s was hit. (%i DMG)", victim, - damageDealt > 0 ? damageDealt : 1); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - - //Rolls - // - //Critical hit roll - - //Account for critboost_chance perks - int critMax = - round(10.0 - floor(target->luck / 5) - - (1.5 * target->perks[CRITBOOST_CHANCE]->innerValue)); - - int critRes = (rand() % critMax); - - if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { - - //Account for critboost_dmg perks - int dmgboost_perks = target->perks[CRITBOOST_DMG]->innerValue; - damageDealt *= (0.30 + (0.12 * dmgboost_perks)); - b->hp -= damageDealt > 0 ? damageDealt : 1; - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - sprintf(msg, "A critical hit! (%i DMG)", - damageDealt > 0 ? damageDealt : 1); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - log_tag("debug_log.txt", "[FIGHT-BOSS]", - "Critical hit for %i dmg, proc on 1/%i chance.", damageDealt, - critMax); - - //Update stats - target->stats->criticalhits++; - } - //Check for deaths -> exit condition from loop - // - // - // - if (b->hp <= 0) { - res = FIGHTRES_KILL_DONE; - - //Account for runic circle perk - int runic_perks = target->perks[RUNIC_MAGNET]->innerValue; - if (runic_perks > 0) { - int recovery = round(0.51 * runic_perks); - target->energy += recovery; - log_tag("debug_log.txt", "[PERKS]", - "Runicmagnet proc for %i energy.", recovery); - } - if (b->beast) { - color = S4C_MAGENTA; - } else { - color = S4C_RED; - } - wattron(notify_win, COLOR_PAIR(color)); - sprintf(msg, "%s fainted.", stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(color)); - log_tag("debug_log.txt", "[FIGHT-BOSS]", "Killed %s.", - stringFromBossClass(b->class)); - - //Update stats - target->stats->bosseskilled++; - - //Check if we killed this boss before - if (target->stats->killed_bosses[b->class] == 0) { - //Update stats - target->stats->unique_bosseskilled++; - target->stats->killed_bosses[b->class] += 1; - //Check if we have to update the wincon value - if (p->win_condition->class == ALL_BOSSES) { - p->win_condition->current_val++; - } - log_tag("debug_log.txt", "[FIGHT-BOSS]", "Killed new boss %s.", - stringFromBossClass(b->class)); - } - } else { - //Apply status effects to boss - if (b->status != Normal) { - applyBStatus(notify_win, b); - log_tag("debug_log.txt", "[STATUS]", "Applied %s to %s.", - stringFromStatus(b->status), stringFromBossClass(b->class)); - } - } - - if (target->hp <= 0) { - res = FIGHTRES_DEATH; - } else { - //Apply status effects to target - if (target->status != Normal) { - applyStatus(notify_win, target); - } - } - - //Consumable drop, guaranteed on killing a beast - if (res == FIGHTRES_KILL_DONE) { - int drop = dropConsumable(target); - wattron(notify_win, COLOR_PAIR(S4C_CYAN)); - sprintf(msg, "You found a %s!", stringFromConsumables(drop)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); - log_tag("debug_log.txt", "[DROPS]", "Found Consumable: %s.", - stringFromConsumables(drop)); - } - - //Artifact drop (if we don't have all of them) - if (res == FIGHTRES_KILL_DONE - && (target->stats->artifactsfound != ARTIFACTSMAX + 1)) { - int artifact_drop = dropArtifact(target); - wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); - sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); - log_tag("debug_log.txt", "[DROPS]", "Found Artifact: %s.", - stringFromArtifacts(artifact_drop)); - } - //Equip drop - if (res == FIGHTRES_KILL_DONE) { - //We give 1 to obtain the better equip generation used for beasts - dropEquip(target, 1, notify_win, kls); - } - - return res; -} - -/** - * Takes a Fighter and a Boss pointers and calls boss_fight(). - * @see Fighter - * @see Boss - * @see boss_fight() - * @param player The Fighter pointer at hand. - * @param b The Boss pointer at hand. - * @param foe_op The foeTurnOption_OP for the foe. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - */ -int defer_fight_boss(Fighter *player, Boss *b, Path *p, foeTurnOption_OP foe_op, - WINDOW *notify_win, Koliseo *kls) -{ - char msg[200]; - //FIXME - //Is it okay to return just one result, when having 2 interactions that could go differently? - // - //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. - fightResult res = FIGHTRES_NO_DMG; - - int player_goes_first = (player->vel >= b->vel ? 1 : 0); - - if (player_goes_first) { - res = boss_fight(player, b, p, notify_win, kls); - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - res = boss_attack(b, player, p, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", - __func__, stringFromBossClass(b->class)); - //TODO - //Implement boss special function - //res = boss_attack_special(b,player,p,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", - __func__, foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - //TODO - //Check second turn act res? - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - - return res; - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } else { - //Foe acts first - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s()]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - res = boss_attack(b, player, p, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", __func__, - stringFromBossClass(b->class)); - //TODO - //Implement boss special function - //res = boss_attack_special(b,player,p,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - res = boss_fight(player, b, p, notify_win, kls); - - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - //TODO - //Check second turn act res? - return res; - - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } - - return res; -} - -/** - * Takes a Fighter and a Boss pointers and calls do_Skill_boss(). - * @see Fighter - * @see Boss - * @see do_Skill_boss() - * @param player The Fighter pointer at hand. - * @param b The Boss pointer at hand. - * @param picked_skill The skill picked by Fighter. - * @param foe_op The foeTurnOption_OP for the foe. - * @param notify_win The WINDOW pointer to call display_notification() on. - * @param kls The Koliseo used for allocations. - */ -int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, - WINDOW *notify_win, Koliseo *kls) -{ - char msg[200]; - //FIXME - //Is it okay to return just one result, when having 2 interactions that could go differently? - // - //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. - fightResult res = FIGHTRES_NO_DMG; - - int player_goes_first = (player->vel >= b->vel ? 1 : 0); - - if (player_goes_first) { - res = do_Skill_boss(player, b, picked_skill, p, notify_win, kls); - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - res = boss_attack(b, player, p, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", - __func__, stringFromBossClass(b->class)); - //TODO - //Implement boss special function - //res = boss_attack_special(b,player,p,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", - __func__, foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - //TODO - //Check second turn act res? - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - - return res; - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } else { - //Foe acts first - switch (foe_op) { - case FOE_OP_INVALID: { - log_tag("debug_log.txt", "[ERROR]", - "foe_op was FOE_OP_INVALID in [%s()]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - case FOE_OP_IDLE: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } was idle.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is loafing around.", - stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - } - break; - case FOE_OP_FIGHT: { - log_tag("debug_log.txt", "[DEFER]", - "[%s()]: Foe { %s } wants to fight.", __func__, - stringFromBossClass(b->class)); - wattron(notify_win, COLOR_PAIR(S4C_GREY)); - sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); - display_notification(notify_win, msg, 500); - wattroff(notify_win, COLOR_PAIR(S4C_GREY)); - res = boss_attack(b, player, p, notify_win, kls); - } - break; - case FOE_OP_SPECIAL: { - log_tag("debug_log.txt", "[TODO]", - "[%s()]: Foe { %s } wants to use a special.", __func__, - stringFromBossClass(b->class)); - //TODO - //Implement boss special function - //res = boss_attack_special(b,player,p,notify_win,kls); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, - foe_op); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } // End foe_op switch - - //Check res and apply second action if needed - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: First act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - - if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { - res = do_Skill_boss(player, b, picked_skill, p, notify_win, kls); - - log_tag("debug_log.txt", "[DEBUG]", - "[%s()]: Second act res was [%s]: [%i]", __func__, - stringFrom_fightResult(res), res); - //TODO - //Check second turn act res? - return res; - - } else if (res == FIGHTRES_DEATH) { - return res; - } else if (res == FIGHTRES_KILL_DONE) { - return res; - } - } - - return res; -} -/** - * Takes a Fighter, an Enemy and a Boss pointers, a string denoting the consumableClass and an int for use on enemy or boss. - * If qty value for the Consumable is 0, we have an early return. Otherise effect is applied and qty is decreased. - * @see Fighter - * @see Enemy - * @see Boss - * @see Consumable - * @see consumableClass - * @param f The Fighter pointer at hand. - * @param e The Enemy pointer at hand. - * @param b The Boss pointer at hand. - * @param string The string value of consumable to use. - * @param isBoss The mode of use (on boss if == 1) - */ -void useConsumable(Fighter *f, Enemy *e, Boss *b, char *string, int isBoss) -{ - //Mountain of ifs? Where are my damn maps - - int i = 0; - int check; - for (int j = 0; j < CONSUMABLESMAX + 1; j++) { - if ((check = strcmp(consumablestrings[j], string)) == 0) { - i = j; - } - }; - - Consumable *c = (Consumable *) f->consumablesBag[i]; - - if (c->qty == 0) { - return; - } - if (c->class == Potion) { - f->hp = f->totalhp; - //green(); - //printf("\n\n\n\tYour health was restored.\n\n"); - //white(); - } else if (c->class == Rock) { - if (isBoss) { - b->def -= 8; - b->hp -= 2; - //printf("\n\n\n\t%s got smacked.",stringFromBossClass(b->class)); - } else { - e->def -= 8; - e->hp -= 2; - //printf("\n\n\n\t%s got smacked.",stringFromEClass(e->class)); - } - //red(); - //printf("\t-8 DEF and -2 HP.\n\n"); - //white(); - } else if (c->class == Bread) { - f->vel -= 1; - f->def += 6; - f->atk += 4; - //printf("\n\n\n\tYou ate elvish bread."); - //green(); - //printf("\t+6 DEF , +4 ATK, "); - //yellow(); - //printf("-1 VEL\n\n"); - //white(); - } else if (c->class == Coffee) { - f->vel += 6; - f->atk += 2; - f->def -= 2; - //printf("\n\n\n\tYou drank hot coffee."); - //green(); - //printf("\t+6 SPE , +2 ATK, "); - //yellow(); - //printf("-2 DEF\n\n"); - //white(); - } else if (c->class == Powergem) { - //printf("\n\n\n\tYou became wiser."); - //green(); - //printf("\t+25 XP\n\n"); - //white(); - checkremainder(f, 25); - } else if (c->class == Magicbean) { - //printf("\n\n\n\tYou aren't tired anymore."); - //green(); - //printf("\tEnergy was restored\n\n"); - //white(); - f->energy = f->totalenergy; //Refill energy - } else { - return; - } - - c->qty--; -} - -/** - * Takes a Fighter pointer and an integer denoting the consumableClass and returns the respective qty value from player's consumablesBag at the provided index. - * @see Fighter - * @see Consumable - * @see consumableClass - * @param f The Fighter pointer. - * @param n The consumableClass value. - * @return int The qty value in consumablesBag for selected consumableClass. - */ -int getConsumableQty(Fighter *f, int n) -{ - Consumable *c = (Consumable *) f->consumablesBag[n]; - return c->qty; -} - -/** - * Sets the qty value to 0 for all Consumable in f's consumablesBag with positive qty. - * @see Consumable - * @see consumableClass - * @see CONSUMABLESMAX - * @see getConsumableQty() - * @param f The Fighter pointer at hand. - */ -void emptyConsumables(Fighter *f) -{ - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - if (getConsumableQty(f, i) > 0) { - Consumable *c = (Consumable *) f->consumablesBag[i]; - c->qty = 0; - } - }; -} - -/** - * Takes a Fighter pointer and sets the qty value to 0 and the active flag to false for all Artifacts in the fighter's artifactsBag with positive qty. - * @see Artifact - * @see artifactClass - * @see ARTIFACTSMAX - * @param f The Fighter pointer at hand. - */ -void emptyArtifacts(Fighter *f) -{ - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - if (f->artifactsBag[i]->qty > 0) { - f->artifactsBag[i]->qty = 0; - f->artifactsBag[i]->active = 0; - } - }; -} - -/** - * Takes a Fighter pointer and, for all Equip in equipsBag field with positive qty, sets qty to 0 and frees the Equip pointer. - * @see Fighter - * @see Equip - * @param player The fighter pointer whose equipsbag will be emptied. - */ -void emptyEquips(Fighter *player) -{ - //We REALLY need to be sure the items are in successive cells - //Still thinking linked lists would be better than an array - int occupied = player->equipsBagOccupiedSlots; - - for (int i = 0; i < occupied; i++) { - - Equip *e = (Equip *) player->equipsBag[i]; - if (e->qty > 0) { - //free(e); - e->qty = 0; - log_tag("debug_log.txt", "[FIXME]", - "emptyEquips(): how do I empty them semantically?"); - } - }; -} - -/** - * Takes a FILE pointer to which the gamestate from the passed args will be saved. - * Fighter, Path and an integer for room index. - * Saves the state of the game. - * @see Fighter - * @see Path - * @see gameloop() - * @param file The FILE pointer struct to write to. - * @param f The player struct. - * @param p The path struct. - * @param roomIndex Current room index. - */ -OP_res handleSave_Home(FILE *file, Fighter *f, Path *p, int roomIndex) -{ - const char* version = HELAPORDO_SAVEFILE_VERSION; - //FILE *file = fopen("save.txt", "w"); - log_tag("debug_log.txt", "[DEBUG]", "Saving with version %s", version); - - if (file == NULL) { - fprintf(stderr, "[ERROR] Can't open save file!\n"); - return OP_CANNOT_OPEN_SAVEFILE; - } - - /* File version printing */ - fprintf(file, "%s\n", version); - - /* Save type printing */ - fprintf(file, "%s\n", stringFrom_saveType(HOME_SAVE)); - - /* Gamemode printing */ - fprintf(file, "%i# gamemode\n", GAMEMODE); - - /* Fighter printing */ - fprintf(file, "Fighter{\n"); - fprintf(file, "%s# name\n", f->name); - fprintf(file, "%s# class\n", stringFromClass(f->class)); - fprintf(file, "%i# hp\n", f->hp); - fprintf(file, "%i# totalhp\n", f->totalhp); - fprintf(file, "%i# atk\n", f->atk); - fprintf(file, "%i# def\n", f->def); - fprintf(file, "%i# vel\n", f->vel); - fprintf(file, "%i# level\n", f->level); - fprintf(file, "%i# luck\n", f->luck); - fprintf(file, "%i# totxp\n", f->totalxp); - fprintf(file, "%i# currlevxp\n", f->currentlevelxp); - fprintf(file, "%i# totlevxp\n", f->totallevelxp); - fprintf(file, "%i# energy\n", f->energy); - fprintf(file, "%i# totenergy\n", f->totalenergy); - fprintf(file, "%i# stamina\n", f->stamina); - fprintf(file, "%i# totstamina\n", f->totalstamina); - fprintf(file, "%i# coinbalance\n", f->balance); - fprintf(file, "%s# status\n", stringFromStatus(f->status)); - fprintf(file, " Specials{\n"); - for (int i = 0; i < SPECIALSMAX + 1; i++) { - fprintf(file, "%i# %i_special_enabled_flag\n", f->specials[i]->enabled, - i); - } - fprintf(file, " },\n"); - fprintf(file, " Skills{\n"); - for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { - fprintf(file, "%i# %i_skill_enabled_flag\n", f->skills[i]->enabled, - i); - } - fprintf(file, " },\n"); - fprintf(file, " Counters{\n"); - for (int i = 0; i < COUNTERSMAX + 1; i++) { - fprintf(file, "%i# innervalue\n", f->counters[i]->innerValue); - fprintf(file, "%i# count\n", f->counters[i]->count); - } - fprintf(file, " },\n"); - fprintf(file, "%i# tb_atk\n", f->turnboost_atk); - fprintf(file, "%i# tb_def\n", f->turnboost_def); - fprintf(file, "%i# tb_vel\n", f->turnboost_vel); - fprintf(file, "%i# tb_enr\n", f->turnboost_enr); - fprintf(file, "%i# eqpbag_occupied_slots\n", f->equipsBagOccupiedSlots); - fprintf(file, "%i# earliestbagslot\n", f->earliestBagSlot); - fprintf(file, " EquipsBag{\n"); - for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { - Equip *eq = f->equipsBag[i]; - fprintf(file, " Equip_%i{\n", i); - - fprintf(file, "%s# equipclass\n", stringFromEquips(eq->class)); - fprintf(file, "%s# equipzone\n", stringFromEquipzones(eq->type)); - fprintf(file, "%i# qty\n", eq->qty); - fprintf(file, "%i# equipped\n", eq->equipped); - fprintf(file, "%i# lvl\n", eq->level); - fprintf(file, "%i# atk\n", eq->atk); - fprintf(file, "%i# def\n", eq->def); - fprintf(file, "%i# vel\n", eq->vel); - fprintf(file, "%i# enr\n", eq->enr); - fprintf(file, "%i# bonus\n", eq->bonus); - fprintf(file, "%i# perkscount\n", eq->perksCount); - fprintf(file, "%i# cost\n", eq->cost); - fprintf(file, "%s# quality\n", stringFromQuality(eq->type)); - fprintf(file, " Perks{\n"); - for (int j = 0; j < eq->perksCount; j++) { - Perk *pk = eq->perks[j]; - fprintf(file, "%i# class\n", pk->class); - fprintf(file, "%i# innervalue\n", pk->innerValue); - } - fprintf(file, " }\n"); - fprintf(file, " }\n"); - } - fprintf(file, " }\n"); - fprintf(file, "%i# pbst_atk\n", f->permboost_atk); - fprintf(file, "%i# pbst_def\n", f->permboost_def); - fprintf(file, "%i# pbst_vel\n", f->permboost_vel); - fprintf(file, "%i# pbst_enr\n", f->permboost_enr); - fprintf(file, "%i# ebst_atk\n", f->equipboost_atk); - fprintf(file, "%i# ebst_atk\n", f->equipboost_def); - fprintf(file, "%i# ebst_atk\n", f->equipboost_vel); - fprintf(file, "%i# ebst_atk\n", f->equipboost_enr); - fprintf(file, " Stats{\n"); - fprintf(file, "%i# enemieskilled\n", f->stats->enemieskilled); - fprintf(file, "%i# consumablesfound\n", f->stats->consumablesfound); - fprintf(file, "%i# equipsfound\n", f->stats->equipsfound); - fprintf(file, "%i# artifactsfound\n", f->stats->artifactsfound); - fprintf(file, "%i# crits\n", f->stats->criticalhits); - fprintf(file, "%i# roomsdone\n", f->stats->roomscompleted); - fprintf(file, "%i# specialsunlocked\n", f->stats->specialsunlocked); - fprintf(file, "%i# coinsfound\n", f->stats->coinsfound); - fprintf(file, "%i# bosseskilled\n", f->stats->bosseskilled); - fprintf(file, "%i# uniquebosseskilled\n", f->stats->unique_bosseskilled); - fprintf(file, " Bosses_killed{\n"); - for (int b_i = 0; b_i < BOSSCLASSESMAX + 1; b_i++) { - fprintf(file, "%i# boss_%iwas_%s_killed\n", - f->stats->killed_bosses[b_i], b_i, - f->stats->killed_bosses[b_i] ? "" : "not"); - } - fprintf(file, " },\n"); - fprintf(file, "%i# keysfound\n", f->stats->keysfound); - fprintf(file, " },\n"); - fprintf(file, "},\n"); - - /* Path and current room indexes printing */ - fprintf(file, "Path{\n"); - fprintf(file, "%i# luck\n", p->luck); - fprintf(file, "%i# length\n", p->length); - fprintf(file, "%i# prize\n", p->prize); - fprintf(file, "%i# lorecounter\n", (p->loreCounter) - 1); //We want to see the last message again when the game is loaded. This might need investigation. TODO - fprintf(file, " Wincon{\n"); - fprintf(file, "%i# winconclass\n", p->win_condition->class); - fprintf(file, "%i# current_val\n", p->win_condition->current_val); - fprintf(file, "%i# target_val\n", p->win_condition->target_val); - fprintf(file, " },\n"); - fprintf(file, "},\n"); - fprintf(file, "%i# roomindex\n", roomIndex); - - /* Consumables bag printing */ - fprintf(file, "ConsumableBag{\n"); - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - Consumable *cn = (Consumable *) f->consumablesBag[i]; - fprintf(file, "%i# qty_for_consumable_%i\n", cn->qty, i); - } - fprintf(file, "},\n"); - - /* Artifacts bag printing */ - fprintf(file, "ArtifactsBag{\n"); - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - Artifact *a = f->artifactsBag[i]; - fprintf(file, "%i# qty_for_artifact_%i\n", a->qty, i); - } - fprintf(file, "},\n"); - - log_tag("debug_log.txt", "[DEBUG]", "Done saving"); - - return OP_OK; -} - -/** - * Takes a FILE pointer to which the gamestate from the passed args will be saved. - * Fighter, Path and Enemy pointers, and integers for room / path progression indexes. - * Saves the state of the game. - * @see Fighter - * @see Enemy - * @see Path - * @see room() - * @see gameloop() - * @param file The FILE pointer struct to write to. - * @param f The player struct. - * @param p The path struct. - * @param e The current enemy struct. - * @param enemyIndex Index in current room for current enemy. - * @param roomTotalEnemies Total enemies for current room. - * @param roomIndex Current room index. - */ -OP_res handleSave_Enemies(FILE *file, Fighter *f, Path *p, Enemy *e, - int enemyIndex, int roomTotalEnemies, int roomIndex) -{ - const char * version = HELAPORDO_SAVEFILE_VERSION; - //FILE *file = fopen("save.txt", "w"); - log_tag("debug_log.txt", "[DEBUG]", "Saving with version %s", version); - - if (file == NULL) { - fprintf(stderr, "[ERROR] Can't open save file!\n"); - return OP_CANNOT_OPEN_SAVEFILE; - } - - /* File version printing */ - fprintf(file, "%s\n", version); - - /* Save type printing */ - fprintf(file, "%s\n", stringFrom_saveType(ENEMIES_SAVE)); - - /* Gamemode printing */ - fprintf(file, "%i# gamemode\n", GAMEMODE); - - /* Fighter printing */ - fprintf(file, "Fighter{\n"); - fprintf(file, "%s# name\n", f->name); - fprintf(file, "%s# class\n", stringFromClass(f->class)); - fprintf(file, "%i# hp\n", f->hp); - fprintf(file, "%i# totalhp\n", f->totalhp); - fprintf(file, "%i# atk\n", f->atk); - fprintf(file, "%i# def\n", f->def); - fprintf(file, "%i# vel\n", f->vel); - fprintf(file, "%i# level\n", f->level); - fprintf(file, "%i# luck\n", f->luck); - fprintf(file, "%i# totxp\n", f->totalxp); - fprintf(file, "%i# currlevxp\n", f->currentlevelxp); - fprintf(file, "%i# totlevxp\n", f->totallevelxp); - fprintf(file, "%i# energy\n", f->energy); - fprintf(file, "%i# totenergy\n", f->totalenergy); - fprintf(file, "%i# stamina\n", f->stamina); - fprintf(file, "%i# totstamina\n", f->totalstamina); - fprintf(file, "%i# coinbalance\n", f->balance); - fprintf(file, "%s# status\n", stringFromStatus(f->status)); - fprintf(file, " Specials{\n"); - for (int i = 0; i < SPECIALSMAX + 1; i++) { - fprintf(file, "%i# %i_special_enabled_flag\n", f->specials[i]->enabled, - i); - } - fprintf(file, " },\n"); - fprintf(file, " Skills{\n"); - for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { - fprintf(file, "%i# %i_skill_enabled_flag\n", f->skills[i]->enabled, - i); - } - fprintf(file, " },\n"); - fprintf(file, " Counters{\n"); - for (int i = 0; i < COUNTERSMAX + 1; i++) { - fprintf(file, "%i# innervalue\n", f->counters[i]->innerValue); - fprintf(file, "%i# count\n", f->counters[i]->count); - } - fprintf(file, " },\n"); - fprintf(file, "%i# tb_atk\n", f->turnboost_atk); - fprintf(file, "%i# tb_def\n", f->turnboost_def); - fprintf(file, "%i# tb_vel\n", f->turnboost_vel); - fprintf(file, "%i# tb_enr\n", f->turnboost_enr); - fprintf(file, "%i# eqpbag_occupied_slots\n", f->equipsBagOccupiedSlots); - fprintf(file, "%i# earliestbagslot\n", f->earliestBagSlot); - fprintf(file, " EquipsBag{\n"); - for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { - Equip *eq = f->equipsBag[i]; - fprintf(file, " Equip_%i{\n", i); - - fprintf(file, "%s# equipclass\n", stringFromEquips(eq->class)); - fprintf(file, "%s# equipzone\n", stringFromEquipzones(eq->type)); - fprintf(file, "%i# qty\n", eq->qty); - fprintf(file, "%i# equipped\n", eq->equipped); - fprintf(file, "%i# lvl\n", eq->level); - fprintf(file, "%i# atk\n", eq->atk); - fprintf(file, "%i# def\n", eq->def); - fprintf(file, "%i# vel\n", eq->vel); - fprintf(file, "%i# enr\n", eq->enr); - fprintf(file, "%i# bonus\n", eq->bonus); - fprintf(file, "%i# perkscount\n", eq->perksCount); - fprintf(file, "%i# cost\n", eq->cost); - fprintf(file, "%s# quality\n", stringFromQuality(eq->type)); - fprintf(file, " Perks{\n"); - for (int j = 0; j < eq->perksCount; j++) { - Perk *pk = eq->perks[j]; - fprintf(file, "%i# class\n", pk->class); - fprintf(file, "%i# innervalue\n", pk->innerValue); - } - fprintf(file, " }\n"); - fprintf(file, " }\n"); - } - fprintf(file, " }\n"); - fprintf(file, "%i# pbst_atk\n", f->permboost_atk); - fprintf(file, "%i# pbst_def\n", f->permboost_def); - fprintf(file, "%i# pbst_vel\n", f->permboost_vel); - fprintf(file, "%i# pbst_enr\n", f->permboost_enr); - fprintf(file, "%i# ebst_atk\n", f->equipboost_atk); - fprintf(file, "%i# ebst_atk\n", f->equipboost_def); - fprintf(file, "%i# ebst_atk\n", f->equipboost_vel); - fprintf(file, "%i# ebst_atk\n", f->equipboost_enr); - fprintf(file, " Stats{\n"); - fprintf(file, "%i# enemieskilled\n", f->stats->enemieskilled); - fprintf(file, "%i# consumablesfound\n", f->stats->consumablesfound); - fprintf(file, "%i# equipsfound\n", f->stats->equipsfound); - fprintf(file, "%i# artifactsfound\n", f->stats->artifactsfound); - fprintf(file, "%i# crits\n", f->stats->criticalhits); - fprintf(file, "%i# roomsdone\n", f->stats->roomscompleted); - fprintf(file, "%i# specialsunlocked\n", f->stats->specialsunlocked); - fprintf(file, "%i# coinsfound\n", f->stats->coinsfound); - fprintf(file, "%i# bosseskilled\n", f->stats->bosseskilled); - fprintf(file, "%i# uniquebosseskilled\n", f->stats->unique_bosseskilled); - fprintf(file, " Bosses_killed{\n"); - for (int b_i = 0; b_i < BOSSCLASSESMAX + 1; b_i++) { - fprintf(file, "%i# boss_%iwas_%s_killed\n", - f->stats->killed_bosses[b_i], b_i, - f->stats->killed_bosses[b_i] ? "" : "not"); - } - fprintf(file, " },\n"); - fprintf(file, "%i# keysfound\n", f->stats->keysfound); - fprintf(file, " },\n"); - fprintf(file, "},\n"); - - /* Current enemy printing */ - fprintf(file, "Enemy{\n"); - fprintf(file, "%s# class\n", stringFromEClass(e->class)); - fprintf(file, "%i# hp\n", e->hp); - fprintf(file, "%i# totalhp\n", e->totalhp); - fprintf(file, "%i# atk\n", e->atk); - fprintf(file, "%i# def\n", e->def); - fprintf(file, "%i# vel\n", e->vel); - fprintf(file, "%i# level\n", e->level); - fprintf(file, "%i# xp\n", e->xp); - fprintf(file, "%i# energy\n", e->energy); - fprintf(file, "%i# totenergy\n", e->totalenergy); - fprintf(file, "%i# stamina\n", e->stamina); - fprintf(file, "%i# totstamina\n", e->totalstamina); - fprintf(file, "%i# beast\n", e->beast); - fprintf(file, "%i# prize\n", e->prize); - fprintf(file, "%s# status\n", stringFromStatus(e->status)); - fprintf(file, " Skills{\n"); - for (int i = 0; i < ENEMY_SKILL_SLOTS; i++) { - fprintf(file, "%i# %i_skill_enabled_flag\n", e->skills[i]->enabled, - i); - } - fprintf(file, " },\n"); - fprintf(file, " Counters{\n"); - for (int i = 0; i < COUNTERSMAX + 1; i++) { - fprintf(file, "%i# innervalue\n", e->counters[i]->innerValue); - fprintf(file, "%i# count\n", e->counters[i]->count); - } - fprintf(file, " },\n"); - fprintf(file, "},\n"); - - /* Path and current room indexes printing */ - fprintf(file, "Path{\n"); - fprintf(file, "%i# luck\n", p->luck); - fprintf(file, "%i# length\n", p->length); - fprintf(file, "%i# prize\n", p->prize); - fprintf(file, "%i# lorecounter\n", (p->loreCounter) - 1); //We want to see the last message again when the game is loaded. This might need investigation. TODO - fprintf(file, " Wincon{\n"); - fprintf(file, "%i# winconclass\n", p->win_condition->class); - fprintf(file, "%i# current_val\n", p->win_condition->current_val); - fprintf(file, "%i# target_val\n", p->win_condition->target_val); - fprintf(file, " },\n"); - fprintf(file, "},\n"); - fprintf(file, "%i# enemyindex\n", enemyIndex); - fprintf(file, "%i# roomtotalenemies\n", roomTotalEnemies); - fprintf(file, "%i# roomindex\n", roomIndex); - - /* Consumables bag printing */ - fprintf(file, "ConsumableBag{\n"); - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - Consumable *cn = (Consumable *) f->consumablesBag[i]; - fprintf(file, "%i# qty_for_consumable_%i\n", cn->qty, i); - } - fprintf(file, "},\n"); - - /* Artifacts bag printing */ - fprintf(file, "ArtifactsBag{\n"); - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - Artifact *a = f->artifactsBag[i]; - fprintf(file, "%i# qty_for_artifact_%i\n", a->qty, i); - } - fprintf(file, "},\n"); - - log_tag("debug_log.txt", "[DEBUG]", "Done saving"); - - return OP_OK; -} - -/** - * Takes a FILE pointer from which the save type will be loaded. - * Returns the read savetype value or -1 if an invalid value is found. - * @see saveType - * @see gameloop() - * @param file The FILE pointer to load from. - * @return The saveType read from the file. - */ -saveType read_saveType(FILE *file) -{ - log_tag("debug_log.txt", "[DEBUG]", "Reading save type from text file."); - - if (file == NULL) { - endwin(); - printf("Error with file while trying to read save type!\n"); - return -1; - } - char buf[500]; - const char* version = HELAPORDO_SAVEFILE_VERSION; - - int scanres = -1; - /* File version scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in read_saveType(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while reading save type."); - exit(EXIT_FAILURE); - } - - int check = -1; - if (!((check = strcmp(buf, version)) == 0)) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "Failed save format version check. Quitting."); - fprintf(stderr, - "[ERROR] File version mismatch on save type reading.\n"); - exit(EXIT_FAILURE); - }; - log_tag("debug_log.txt", "[LOAD]", "Read save format version: (%s).\n", - buf); - - /* Save type scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in read_saveType(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while reading save type."); - exit(EXIT_FAILURE); - } - - saveType result = saveTypeFrom_string(buf); - - if (result == -1) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "read_saveType(): Failed save type reading. Read string Was [%s]. Quitting.", - buf); - fprintf(stderr, "[ERROR] Save type version error.\n"); - exit(EXIT_FAILURE); - - }; - - log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s) --> [%s].\n", - buf, stringFrom_saveType(result)); - - log_tag("debug_log.txt", "[LOAD]", - "Doing rewind(save_file) before returning from read_saveType()!"); - rewind(file); - return result; -} - -/** - * Takes a FILE pointer from which the gamestate will be loaded. - * Gets the pointers to relevant game structures, sets all the values by reading the save file. - * Fighter, Path pointers, and an integer for room index. - * Saves the state of the game. - * @see Fighter - * @see Path - * @see gameloop() - * @param file The FILE pointer to load from. - * @param f The player struct. - * @param p The path struct. - * @param roomIndex Current room index. - * @param done_loading Flag to check if loading ended. - * @param kls The Koliseo used for allocations. - * @return The OP_res corresponding to loading result. - */ -OP_res handleLoadgame_Home(FILE *file, Fighter *f, Path *p, int *roomIndex, - int *done_loading, Koliseo *kls) -{ - - //printf("\nLoading game...\n"); - log_tag("debug_log.txt", "[LOAD]", "Starting loading from text file."); - -// FILE* file = fopen("save.txt", "r"); - if (file == NULL) { - printf("Error with file while trying to load!\n"); - return OP_CANNOT_OPEN_SAVEFILE; - } - char buf[500]; - char comment[300]; - int num_value = -1; - const char * version = HELAPORDO_SAVEFILE_VERSION; - - int scanres = -1; - /* File version scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - int check = -1; - if (!((check = strcmp(buf, version)) == 0)) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "Failed save format version check. Was [%s]. Quitting.\n", buf); - fprintf(stderr, "[ERROR] File version mismatch on load.\n"); - exit(EXIT_FAILURE); - }; - log_tag("debug_log.txt", "[LOAD]", "Loaded save format version: (%s).", - buf); - - /* Save type scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - check = -1; - if (!((check = strcmp(buf, stringFrom_saveType(HOME_SAVE))) == 0)) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "handleLoadGame_Home(): Failed save type check, was [%s]. Quitting.", - buf); - fprintf(stderr, "[ERROR] Save type version mismatch on load.\n"); - exit(EXIT_FAILURE); - }; - log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s).", buf); - - /* Gamemode scanning */ - scanres = fscanf(file, "%200[^#]# %s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - GAMEMODE = num_value; - - /* Fighter scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - strcpy(f->name, buf); - - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int i = 0; i < CLASSESMAX + 1; i++) { - int check = -1; - if ((check = strcmp(buf, stringFromClass(i))) == 0) { - f->class = i; - break; - } - }; - - //We have to reload the specials callbacks after setting fighter class - setSpecials(f, kls); - - //HP - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->hp = num_value; - //TotalHP - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->totalhp = num_value; - //Atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->atk = num_value; - //Def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - sscanf(buf, "%3i", &num_value); - f->def = num_value; - //Vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->vel = num_value; - //Level - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->level = num_value; - //Luck - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->luck = num_value; - //Totxp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->totalxp = num_value; - //Current level xp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->currentlevelxp = num_value; - //Totallevelxp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->totallevelxp = num_value; - //Energy - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->energy = num_value; - //Totenergy - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->totalenergy = num_value; - //Stamina - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stamina = num_value; - //Totstamina - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->totalstamina = num_value; - //Coin balance - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->balance = num_value; - - //Status - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int i = 0; i < STATUSMAX + 1; i++) { - int check = -1; - if ((check = strcmp(buf, stringFromStatus(i))) == 0) { - f->status = i; - break; - } - }; - //Specials - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < SPECIALSMAX + 1; i++) { - //Enabled flag - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->specials[i]->enabled = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Skills - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { - //Enabled flag - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->skills[i]->enabled = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Fighter counters - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < COUNTERSMAX + 1; i++) { - //innerValue - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->counters[i]->innerValue = num_value; - //count - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->counters[i]->count = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - - //turnboost_atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_atk = num_value; - //turnboost_def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_def = num_value; - //turnboost_vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_vel = num_value; - //turnboost_enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_enr = num_value; - - //equipsbag occupied slots - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipsBagOccupiedSlots = num_value; - //equipsbag earliest slot - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->earliestBagSlot = num_value; - - //Equipsbag - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { - log_tag("debug_log.txt", "[DEBUG]", - "Loadgame_Home(): Prepping Equip (%i)", i); - kls_log(kls, "DEBUG", "Loadgame_Home(): Prepping Equip (%i)", i); - Equip *eq = KLS_PUSH_TYPED(kls, Equip, HR_Equip, "Equip", "Equip"); - scanres = fscanf(file, "%200s\n", buf); //Skip equip_i heading - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - //equipClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int j = 0; j < EQUIPSMAX + 1; j++) { - int check = -1; - if ((check = strcmp(buf, stringFromEquips(j))) == 0) { - eq->class = j; - break; - } - }; - //equipzoneClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int j = 0; j < EQUIPZONES + 1; j++) { - int check = -1; - if ((check = strcmp(buf, stringFromEquipzones(j))) == 0) { - eq->type = j; - break; - } - }; - - //qty - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->qty = num_value; - //equipped - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->equipped = num_value; - //level - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->level = num_value; - //atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->atk = num_value; - //def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->def = num_value; - //vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->vel = num_value; - //enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->enr = num_value; - //bonus - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->bonus = num_value; - //perksCount - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->perksCount = num_value; - //cost - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - eq->cost = num_value; - - //Quality - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int j = 0; j < QUALITIESMAX + 1; j++) { - int check = -1; - if ((check = strcmp(buf, stringFromQuality(j))) == 0) { - eq->qual = j; - break; - } - }; - - //perks - scanres = fscanf(file, "%200s\n", buf); //Skip perks heading - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int j = 0; j < eq->perksCount; j++) { - log_tag("debug_log.txt", "[DEBUG]", - "Loadgame_Home(): Prepping Perk (%i)", j); - kls_log(kls, "DEBUG", "Loadgame_Home(): Prepping Perk (%i)", j); - Perk *pk = - (Perk *) KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); - //perkClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - pk->class = num_value; - char *name = nameStringFromPerk(pk->class); - char *desc = descStringFromPerk(pk->class); - //p->name = name; //(char*)malloc(sizeof(name)); - strcpy(pk->name, name); - //p->desc = (char*)malloc(sizeof(desc)); - strcpy(pk->desc, desc); - pk->innerValue = 0; - eq->perks[j] = pk; - - //innerValue - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - pk->innerValue = num_value; - } - - scanres = fscanf(file, "%200s\n", buf); //Skip closing perks breacket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - scanres = fscanf(file, "%200s\n", buf); //Skip closing current equip bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Get the base item and copy the stats to the loading item - Equip *base = &equips[eq->class]; - setEquipSprite(eq); - strcpy(eq->name, base->name); - strcpy(eq->desc, base->desc); - - if (eq->equipped) { - Equipslot *slot = f->equipslots[eq->type]; - //We equip the item - slot->item = eq; - applyEquipPerks(eq, f); - slot->active = 1; - } - f->equipsBag[i] = eq; - } //End for Equips bag - - scanres = fscanf(file, "%200s\n", buf); //Skip closing equipsbag bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - //Fighter boosts - //permboost_atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_atk = num_value; - //permboost_def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_def = num_value; - //permboost_vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_vel = num_value; - //permboost_enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_enr = num_value; - //equipboost_atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_atk = num_value; - //equipboost_def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_def = num_value; - //equipboost_vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_vel = num_value; - //equipboost_enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_enr = num_value; - - //Stats - scanres = fscanf(file, "%200s\n", buf); //Skip Stats bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //enemieskilled - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->enemieskilled = num_value; - //consumablesfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->consumablesfound = num_value; - //equipsfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->equipsfound = num_value; - //artifactsfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->artifactsfound = num_value; - //crits - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->criticalhits = num_value; - //roomsdone - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->roomscompleted = num_value; - //specials unlocked - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->specialsunlocked = num_value; - //coinsfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->stats->coinsfound = num_value; - //bosseskilled - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->bosseskilled = num_value; - - //Unique boss kills - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->unique_bosseskilled = num_value; - - scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int boss_index = 0; boss_index < BOSSCLASSESMAX + 1; boss_index++) { - //boss %i was killed - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->killed_bosses[boss_index] = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //keysfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->keysfound = num_value; - scanres = fscanf(file, "%200s\n", buf); //Skip Stats closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - scanres = fscanf(file, "%200s\n", buf); //Skip Fighter closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Fighter."); - - //Path - scanres = fscanf(file, "%200s\n", buf); //Skip Path bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Luck - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->luck = num_value; - //Length - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->length = num_value; - //Prize - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - p->prize = num_value; - //loreCounter - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->loreCounter = num_value; - - //Wincon - scanres = fscanf(file, "%200s\n", buf); //Skip Wincon bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //winconClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->win_condition->class = num_value; - //current_val - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->win_condition->current_val = num_value; - //target_val - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->win_condition->target_val = num_value; - - scanres = fscanf(file, "%200s\n", buf); //Skip Wincon closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Wincon."); - - scanres = fscanf(file, "%200s\n", buf); //Skip Path closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Path."); - - //roomindex - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - *roomIndex = num_value; - - log_tag("debug_log.txt", "[LOAD]", "Done loading room info."); - - //Consumables bag - scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - initConsumableBag(f, kls); - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - Consumable *cn = (Consumable *) f->consumablesBag[i]; - //qty - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - cn->qty = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Consumable bag."); - - //Artifacts bag - scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - Artifact *a = f->artifactsBag[i]; - //qty - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - a->qty = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Artifacts bag."); - - fclose(file); - log_tag("debug_log.txt", "[LOAD]", "Done loading from text file!"); - //printf("[INFO] Done loading!\n"); - //TODO: - //Notification win for load status - - return OP_OK; -} - -/** - * Takes a FILE pointer from which the gamestate will be loaded. - * Gets the pointers to relevant game structures, sets all the values by reading the save file. - * Fighter, Path and Enemy pointers, and integers for room / path progression indexes. - * Saves the state of the game. - * @see Fighter - * @see Enemy - * @see Path - * @see gameloop() - * @param file The FILE pointer to load from. - * @param f The player struct. - * @param p The path struct. - * @param e The current enemy struct. - * @param enemyIndex Index in current room for current enemy. - * @param roomTotalEnemies Total enemies for current room. - * @param roomIndex Current room index. - * @param total_foes Total foes in current room. - * @param done_loading Flag to check if loading ended. - * @param kls The Koliseo used for allocations. - * @return The OP_res corresponding to loading result. - */ -OP_res handleLoadgame_Enemies(FILE *file, Fighter *f, Path *p, Enemy *e, - int *enemyIndex, int *roomTotalEnemies, - int *roomIndex, int *total_foes, - int *done_loading, Koliseo *kls) -{ - - //printf("\nLoading game...\n"); - log_tag("debug_log.txt", "[LOAD]", "Starting loading from text file."); - -// FILE* file = fopen("save.txt", "r"); - if (file == NULL) { - printf("Error with file while trying to load!\n"); - return OP_CANNOT_OPEN_SAVEFILE; - } - char buf[500]; - char comment[300]; - int num_value = -1; - const char version[] = HELAPORDO_SAVEFILE_VERSION; - - int scanres = -1; - /* File version scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - int check = -1; - if (!((check = strcmp(buf, version)) == 0)) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "Failed save format version check. Was [%s]. Quitting.\n", buf); - fprintf(stderr, "[ERROR] File version mismatch on load.\n"); - exit(EXIT_FAILURE); - }; - log_tag("debug_log.txt", "[LOAD]", "Loaded save format version: (%s).\n", - buf); - - /* Save type scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - check = -1; - if (!((check = strcmp(buf, stringFrom_saveType(ENEMIES_SAVE))) == 0)) { - log_tag("debug_log.txt", "[LOAD-ERROR]", - "handleLoadGame_Enemies(): Failed save type check, was [%s]. Quitting.\n", - buf); - fprintf(stderr, "[ERROR] Save type version mismatch on load.\n"); - exit(EXIT_FAILURE); - }; - log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s).\n", buf); - - /* Gamemode scanning */ - scanres = fscanf(file, "%200[^#]# %s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.\n", comment, buf); - sscanf(buf, "%3i", &num_value); - GAMEMODE = num_value; - - /* Fighter scanning */ - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - strcpy(f->name, buf); - - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int i = 0; i < CLASSESMAX + 1; i++) { - int check = -1; - if ((check = strcmp(buf, stringFromClass(i))) == 0) { - f->class = i; - break; - } - }; - - //We have to reload the specials callbacks after setting fighter class - setSpecials(f, kls); - - //HP - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->hp = num_value; - //TotalHP - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->totalhp = num_value; - //Atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->atk = num_value; - //Def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - sscanf(buf, "%3i", &num_value); - f->def = num_value; - //Vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->vel = num_value; - //Level - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->level = num_value; - //Luck - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->luck = num_value; - //Totxp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->totalxp = num_value; - //Current level xp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->currentlevelxp = num_value; - //Totallevelxp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->totallevelxp = num_value; - //Energy - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->energy = num_value; - //Totenergy - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->totalenergy = num_value; - //Stamina - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stamina = num_value; - //Totstamina - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->totalstamina = num_value; - //Coin balance - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->balance = num_value; - - //Status - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int i = 0; i < STATUSMAX + 1; i++) { - int check = -1; - if ((check = strcmp(buf, stringFromStatus(i))) == 0) { - f->status = i; - break; - } - }; - //Specials - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < SPECIALSMAX + 1; i++) { - //Enabled flag - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->specials[i]->enabled = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Skills - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { - //Enabled flag - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->skills[i]->enabled = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Fighter counters - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < COUNTERSMAX + 1; i++) { - //innerValue - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->counters[i]->innerValue = num_value; - //count - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->counters[i]->count = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - - //turnboost_atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_atk = num_value; - //turnboost_def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_def = num_value; - //turnboost_vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_vel = num_value; - //turnboost_enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->turnboost_enr = num_value; - - //equipsbag occupied slots - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipsBagOccupiedSlots = num_value; - //equipsbag earliest slot - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->earliestBagSlot = num_value; - - //Equipsbag - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { - log_tag("debug_log.txt", "[DEBUG]", - "Loadgame_Enemies(): Prepping Equip (%i)", i); - kls_log(kls, "DEBUG", "Loadgame_Enemies(): Prepping Equip (%i)", i); - Equip *eq = KLS_PUSH_TYPED(kls, Equip, HR_Equip, "Equip", "Equip"); - scanres = fscanf(file, "%200s\n", buf); //Skip equip_i heading - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - //equipClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int j = 0; j < EQUIPSMAX + 1; j++) { - int check = -1; - if ((check = strcmp(buf, stringFromEquips(j))) == 0) { - eq->class = j; - break; - } - }; - //equipzoneClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int j = 0; j < EQUIPZONES + 1; j++) { - int check = -1; - if ((check = strcmp(buf, stringFromEquipzones(j))) == 0) { - eq->type = j; - break; - } - }; - - //qty - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->qty = num_value; - //equipped - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->equipped = num_value; - //level - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->level = num_value; - //atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->atk = num_value; - //def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->def = num_value; - //vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->vel = num_value; - //enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->enr = num_value; - //bonus - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->bonus = num_value; - //perksCount - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - eq->perksCount = num_value; - //cost - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - eq->cost = num_value; - - //Quality - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int j = 0; j < QUALITIESMAX + 1; j++) { - int check = -1; - if ((check = strcmp(buf, stringFromQuality(j))) == 0) { - eq->qual = j; - break; - } - }; - - //perks - scanres = fscanf(file, "%200s\n", buf); //Skip perks heading - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int j = 0; j < eq->perksCount; j++) { - log_tag("debug_log.txt", "[DEBUG]", - "Loadgame_Enemies(): Prepping Perk (%i/%i)", j, - eq->perksCount); - kls_log(kls, "DEBUG", "Loadgame_Enemies(): Prepping Perk (%i/%i)", - j, eq->perksCount); - Perk *pk = KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); - //perkClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - pk->class = num_value; - char *name = nameStringFromPerk(pk->class); - char *desc = descStringFromPerk(pk->class); - //p->name = name; //(char*)malloc(sizeof(name)); - strcpy(pk->name, name); - //p->desc = (char*)malloc(sizeof(desc)); - strcpy(pk->desc, desc); - pk->innerValue = 0; - eq->perks[j] = pk; - - //innerValue - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - pk->innerValue = num_value; - } - - scanres = fscanf(file, "%200s\n", buf); //Skip closing perks breacket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - scanres = fscanf(file, "%200s\n", buf); //Skip closing current equip bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Get the base item and copy the stats to the loading item - Equip *base = &equips[eq->class]; - setEquipSprite(eq); - strcpy(eq->name, base->name); - strcpy(eq->desc, base->desc); - - if (eq->equipped) { - Equipslot *slot = f->equipslots[eq->type]; - //We equip the item - slot->item = eq; - applyEquipPerks(eq, f); - slot->active = 1; - } - f->equipsBag[i] = eq; - } //End for Equips bag - - scanres = fscanf(file, "%200s\n", buf); //Skip closing equipsbag bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - //Fighter boosts - //permboost_atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_atk = num_value; - //permboost_def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_def = num_value; - //permboost_vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_vel = num_value; - //permboost_enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->permboost_enr = num_value; - //equipboost_atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_atk = num_value; - //equipboost_def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_def = num_value; - //equipboost_vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_vel = num_value; - //equipboost_enr - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->equipboost_enr = num_value; - - //Stats - scanres = fscanf(file, "%200s\n", buf); //Skip Stats bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //enemieskilled - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->enemieskilled = num_value; - //consumablesfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->consumablesfound = num_value; - //equipsfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->equipsfound = num_value; - //artifactsfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->artifactsfound = num_value; - //crits - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->criticalhits = num_value; - //roomsdone - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->roomscompleted = num_value; - //specials unlocked - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->specialsunlocked = num_value; - //coinsfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - f->stats->coinsfound = num_value; - //bosseskilled - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->bosseskilled = num_value; - - //Unique boss kills - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->unique_bosseskilled = num_value; - - scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int boss_index = 0; boss_index < BOSSCLASSESMAX + 1; boss_index++) { - //boss %i was killed - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->killed_bosses[boss_index] = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //keysfound - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - f->stats->keysfound = num_value; - scanres = fscanf(file, "%200s\n", buf); //Skip Stats closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - scanres = fscanf(file, "%200s\n", buf); //Skip Fighter closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Fighter."); - - //Current enemy - scanres = fscanf(file, "%200s\n", buf); //Skip Enemy bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Enemy class - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int i = 0; i < ENEMYCLASSESMAX + 1; i++) { - int check = -1; - if ((check = strcmp(buf, stringFromEClass(i))) == 0) { - e->class = i; - break; - }; - } - //We have to reload the sprite after setting enemy class - setEnemySprite(e); - - //hp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->hp = num_value; - //totalhp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->totalhp = num_value; - //atk - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->atk = num_value; - //def - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->def = num_value; - //vel - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->vel = num_value; - //level - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->level = num_value; - //xp - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - e->xp = num_value; - //energy - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->energy = num_value; - //totalenergy - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->totalenergy = num_value; - //Stamina - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->stamina = num_value; - //Totstamina - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->totalstamina = num_value; - //beast value - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->beast = num_value; - //prize - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->prize = num_value; - - //status - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - for (int i = 0; i < STATUSMAX + 1; i++) { - int check = -1; - if ((check = strcmp(buf, stringFromStatus(i))) == 0) { - e->status = i; - break; - } - }; - - //Skills - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < ENEMY_SKILL_SLOTS; i++) { - //Enabled flag - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->skills[i]->enabled = num_value; - } - scanres = fscanf(file, "%200s\n", buf); - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Enemy counters - scanres = fscanf(file, "%200s\n", buf); //Skip Enemy counters bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < COUNTERSMAX + 1; i++) { - //innerValue - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->counters[i]->innerValue = num_value; - //count - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - e->counters[i]->count = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip Enemy counters closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - scanres = fscanf(file, "%200s\n", buf); //Skip Enemy closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading current Enemy."); - - //Path - scanres = fscanf(file, "%200s\n", buf); //Skip Path bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //Luck - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->luck = num_value; - //Length - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->length = num_value; - //Prize - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - p->prize = num_value; - //loreCounter - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->loreCounter = num_value; - - //Wincon - scanres = fscanf(file, "%200s\n", buf); //Skip Wincon bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - //winconClass - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->win_condition->class = num_value; - //current_val - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->win_condition->current_val = num_value; - //target_val - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - p->win_condition->target_val = num_value; - - scanres = fscanf(file, "%200s\n", buf); //Skip Wincon closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Wincon."); - - scanres = fscanf(file, "%200s\n", buf); //Skip Path closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Path."); - - //enemyindex - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - *enemyIndex = num_value; - //roomtotalenemies - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - *roomTotalEnemies = num_value; - *total_foes = num_value; - log_tag("debug_log.txt", "[LOAD]", - "Also Loaded %s: %s. Additional assignment to pointer for foes, see handleLoadGame(_Enemies)", - "total_foes", buf); - //roomindex - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%8i", &num_value); - *roomIndex = num_value; - - log_tag("debug_log.txt", "[LOAD]", "Done loading room info."); - - //Consumables bag - scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - initConsumableBag(f, kls); - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - Consumable *cn = (Consumable *) f->consumablesBag[i]; - //qty - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - cn->qty = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Consumable bag."); - - //Artifacts bag - scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - Artifact *a = f->artifactsBag[i]; - //qty - scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); - if (scanres != 2) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 2, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); - sscanf(buf, "%3i", &num_value); - a->qty = num_value; - } - scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag closing bracket - if (scanres != 1) { - log_tag("debug_log.txt", "[DEBUG]", - "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", - 1, scanres); - fprintf(stderr, "Error while loading game."); - exit(EXIT_FAILURE); - } - - log_tag("debug_log.txt", "[LOAD]", "Done loading Artifacts bag."); - - fclose(file); - log_tag("debug_log.txt", "[LOAD]", "Done loading from text file!"); - //printf("[INFO] Done loading!\n"); - //TODO: - //Notification win for load status - - return OP_OK; -} - -/** - * Takes a Fighter and loadInfo pointers and prints fighter stats and a game over message. - * Consumables and Artifacts are emptied before freeing the player's specials, counters, perks and stats field. - * At last, the player pointer is freed. - * @see Fighter - * @see handleStats() - * @see emptyConsumables() - * @see emptyArtifacts() - * @param player The Fighter pointer to free. - * @param load_info The loadInfo pointer to free. - */ -void death(Fighter *player, loadInfo *load_info) -{ - - //FIXME: - //dropping out of the Koliseo scope might render stat pointer invalid. - //handleStats(player); - - //Free default kls - kls_free(default_kls); - //kls_log(kls,"DEBUG","Freed default KLS"); - log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed default KLS"); - - //Free temporary kls - kls_free(temporary_kls); - //kls_log(kls,"DEBUG","Freed temporary KLS"); - log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed temporary KLS"); - - /* - free(load_info); - sprintf(msg,"Freed loadInfo.\n"); - log_tag("debug_log.txt","[FREE]",msg); - */ - - //emptyConsumables(player); - //emptyArtifacts(player); - /* - //Free player special slots - for (int i=0; i < (SPECIALSMAX + 1) ; i++) { - free(player->specials[i]); - sprintf(msg,"Freed player special %i.",i); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - /* - //Free player equipbag - int total = player->equipsBagOccupiedSlots; - for (int i=0; i < (total ) ; i++) { - Equip* e = (Equip*) player->equipsBag[i]; - int perkscount = e->perksCount; - if (perkscount > 0) { - for (int j=0; j < perkscount; j++) { - free(e->perks[j]); - sprintf(msg,"Freed equip %i perk %i.", i, j); - log_tag("debug_log.txt","[FREE]",msg); - } - } - free(e); - sprintf(msg,"Freed equip %i.\n", i); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - /* - //Free player consumablebag - int cons_total = CONSUMABLESMAX+1; - for (int i=0; i < cons_total ; i++) { - Consumable* c = (Consumable*) player->consumablesBag[i]; - sprintf(msg,"Freed consumable %i.", i); - log_tag("debug_log.txt","[FREE]",msg); - free(c); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - /* - //Free player equip slots - for (int i=0; i < (EQUIPZONES + 1) ; i++) { - Equipslot* s = (Equipslot*) player->equipslots[i]; - - int perkscount = -1; - - if (s->active) { perkscount = s->item->perksCount;}; - if (perkscount > 0) { - for (int i=0; i < perkscount; i++) { - free(s->item->perks[i]); - } - free(s->item); - } - - free(s); - sprintf(msg,"Freed equipslot %i.", i); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - /* - //Free player artifactsbag - int art_total = CONSUMABLESMAX+1; - for (int i=0; i < art_total ; i++) { - Artifact* a = (Artifact*) player->artifactsBag[i]; - free(a); - sprintf(msg,"Freed artifact %i.", i); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - /* - //Free player turnCounters - for (int i=0; i < (COUNTERSMAX + 1) ; i++) { - Turncounter* c = (Turncounter*) player->counters[i]; - free(c->desc); - sprintf(msg,"Freed turncounter %i desc.", i); - log_tag("debug_log.txt","[FREE]",msg); - free(c); - sprintf(msg,"Freed turncounter %i.\n", i); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - /* - //Free player perks - for (int i=0; i < (PERKSMAX + 1) ; i++) { - free(player->perks[i]); - sprintf(msg,"Freed player perk %i.", i); - log_tag("debug_log.txt","[FREE]",msg); - } - log_tag("debug_log.txt","[FREE]","Done.\n"); - */ - - //free(player->stats); - //log_tag("debug_log.txt","[FREE]","Freed player stats.\n"); -} - -/** - * Takes a Enemy pointer and frees its allocated memory. - * The counters field is freed before the enemy pointer. - * @see Enemy - * @param e The Enemy pointer to free. - */ -void e_death(Enemy *e) -{ - - //Free enemy special slots - //for (int i=0; i < SPECIALSMAX + 1 ; i++) { - // free(player->specials[i]); - //} - - /* - //Free enemy turnCounters - for (int i=0; i < (COUNTERSMAX + 1) ; i++) { - Turncounter* c = (Turncounter*) e->counters[i]; - sprintf(msg,"Freed enemy turncounter %i desc: %s.",i, c->desc); - log_tag("debug_log.txt","[FREE]",msg); - if (c->desc == NULL) { - log_tag("debug_log.txt","[ERROR]", "Enemy turncounter desc was null.\n"); - } else { - char* desc_to_free = c->desc; - free(desc_to_free); - } - free(c); - sprintf(msg,"Freed enemy turncounter %i.\n",i); - log_tag("debug_log.txt","[FREE]",msg); - } - */ - - //sprintf(msg,"Freeing enemy %s",stringFromEClass(e->class)); - //log_tag("debug_log.txt","[FREE]",msg); - //free(e); - log_tag("debug_log.txt", "[TODO]", "[%s]: remove this empty function.", - __func__); -} - -/** - * Takes a Boss pointer and frees its allocated memory. - * The counters field is freed before the boss pointer. - * @see Boss - * @param b The Boss pointer to free. - */ -void b_death(Boss *b) -{ - - //TODO - //Remove this bs - log_tag("debug_log.txt", "[DEBUG]", "b_death(): I'm doing nothing."); - - //Free boss special slots - //for (int i=0; i < SPECIALSMAX + 1 ; i++) { - // free(player->specials[i]); - //} - //Free boss turnCounters - /* - for (int i=0; i < (COUNTERSMAX + 1) ; i++) { - Turncounter* c = (Turncounter*) b->counters[i]; - sprintf(msg,"Freed boss turncounter %i desc: %s.",i, c->desc); - log_tag("debug_log.txt","[FREE]",msg); - free(c->desc); - free(c); - sprintf(msg,"Freed boss turncounter %i.\n",i); - log_tag("debug_log.txt","[FREE]",msg); - } - */ - //free(b); -} - -/** - * Asks the user is they want to continue and returns the choice. - * @return int True for trying again, false otherwise. - */ -int retry(void) -{ - lightGreen(); - printf("\n\nYou died. Want to try again?\n\n\t\t[type no / yes]\n\n"); - white(); - char c[25] = { 0 }; - if (fgets(c, sizeof(c), stdin) != NULL) { - log_tag("debug_log.txt", "[DEBUG]", "Read input for %s().", __func__); - if (c[strlen(c) - 1] == '\n') { - c[strlen(c) - 1] = '\0'; - } - - for (char *ptr = c; *ptr; ++ptr) { - *ptr = tolower(*ptr); - } - - if (c[0] == '\0' || strcmp(c, "no") == 0) { - log_tag("debug_log.txt", "[DEBUG]", "%s(): input was no.", - __func__); - return 0; - } else if (strcmp(c, "yes") == 0) { - log_tag("debug_log.txt", "[DEBUG]", "%s(): input was yes.", - __func__); - return 1; - } else { - log_tag("debug_log.txt", "[DEBUG]", - "%s(): Invalid input, defaulting to 0.", __func__); - - return 0; - } - } else { - log_tag("debug_log.txt", "[DEBUG]", "Failed reading input for %s.", - __func__); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } -} - -/** - * Takes a Fighter and a Path pointers (and an integer for current room index) and asks user input to execute debug actions. - * @see Fighter - * @see Path - * @see statReset() - * @see GET_CALLBACK() - * @see unlock_special() - * @param gmst The Gamestate pointer. - * @param player The Fighter pointer at hand. - * @param p The Path pointer of the current game. - * @param roomIndex The index of current room. - * @param The Koliseo to debug. - * @param The Koliseo_Temp used for allocations. - */ -void debug_generic(Gamestate *gmst, Fighter *player, Path *p, int roomIndex, - Koliseo *kls, Koliseo_Temp *t_kls) -{ - - char msg[200]; - char ch[25]; - int picked_debug_proc = 0; -#ifndef _WIN32 - struct utsname uts; - uname(&uts); - sprintf(msg, "debug_generic() loaded utsname using uname().\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "System is %s\n", uts.sysname); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "OS Release is %s\n", uts.release); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "OS Version is %s\n", uts.version); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "Machine is %s\n", uts.machine); - log_tag("debug_log.txt", "[DEBUG]", msg); -#endif - - int res = system("clear"); - sprintf(msg, "debug_generic() system(\"clear\") res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - - int c = 0, n = -1; - while (!picked_debug_proc) { - int res = system("clear"); - sprintf(msg, "debug_generic() 2 system(\"clear\") res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - printf("\n\ - What do you want to do? ('q' to quit)\n\ - [\n\ - '0': Give xp points\t'1': Give consumable\n\ - '2': Reset stats\t'3': Alter luck\n\ - '4': Give coins\t'5': Unlock special\n\ - '6': Unlock Artifact\t'7': Print turnCounter\n\ - 's': Sprites slideshow\t'd': Dump debug symbols\n\ - 'g': Toggle godmode\t'A': Toggle autosave\n\ - 'L': Toggle logging\t'F': Try Floor functionality\n\ - 'Q': Toggle fast quit\t'k': Log passed kls state to debug log file.\n\ - 't': Log global temporary_kls state to debug log file.\n\ - 'K': Log usage stats for passed kls to debug log file.\n\ - 'T': Log usage stats for temporary_kls to debug log file.\n\ - 'G': Log Gamestate to debug log file.\n\ - {Return} Process your input line.\t'q': Quit\n\ - ]\n\n\ - [%s@debug-func]$ ", player->name); - - char *fgetsres = fgets(ch, sizeof ch, stdin); - sprintf(msg, "debug_generic() fgets() res was (%s)", fgetsres); - log_tag("debug_log.txt", "[DEBUG]", msg); - switch (ch[0]) { - case '0': { - picked_debug_proc = 1; - int xp; - do { - printf("\nHow much?\n"); - } while ((c = scanf("%i", &xp)) != 1 || xp < 0); - int res = scanf("%*c"); - sprintf(msg, "debug_generic() scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - checkremainder(player, xp); - } - break; - case '1': { - picked_debug_proc = 1; - int q = -1; - do { - printf("\nInsert consumable number:\n"); - } while ((c = scanf("%i", &n)) != 1 || n > CONSUMABLESMAX - || n < 0); - int res = scanf("%*c"); - sprintf(msg, "debug_generic() scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - do { - printf("\nInsert quantity:\n"); - } while ((c = scanf("%i", &q)) != 1 && q <= 0); - res = scanf("%*c"); - sprintf(msg, "debug_generic() 2 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - Consumable *c = (Consumable *) player->consumablesBag[n]; - c->qty += q; - player->stats->consumablesfound += q; - } - break; - case '2': { - picked_debug_proc = 1; - statReset(player, 1); - } - break; - case '3': { - picked_debug_proc = 1; - printf("\nCurrent luck: %i\tRL: %i\n", player->luck, p->luck); - - do { - printf("\nInsert new luck:\n"); - } while ((c = scanf("%i", &n)) != 1 && n > 0); - int res = scanf("%*c"); - sprintf(msg, "debug_generic() 3 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - //FIXME: - //Copy-pasted the calc for player luck... might need a function - p->luck = n; - - player->luck = (p->luck * MAXPLAYERLUCK) / MAXLUCK; - } - break; - case '4': { - picked_debug_proc = 1; - /* Old code invoking the macro for special moves directly. Used for testing. - * int s = -1; - * printf("Insert special num:\n"); - * scanf("%i",&s); - * scanf("%*c"); - * printf("Read: %i\n",s); - * GET_CALLBACK(s,callback_special_t)(player,e,p,roomIndex,currentEnemyNum); - */ - - //printActivePerks(player); - int c; - int n = -1; - do { - printf("\nInsert coin number (0 3 || n < 0 - || n > 100); - int res = scanf("%*c"); - sprintf(msg, "debug_generic() 4 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - player->balance += n; - } - break; - case '5': { - picked_debug_proc = 1; - unlockSpecial(player); - } - break; - case '6': { - picked_debug_proc = 1; - int n = -1; - do { - printf("\nInsert artifact number (0 ARTIFACTSMAX - || n < 0); - - int res = scanf("%*c"); - sprintf(msg, "debug_generic() scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - player->artifactsBag[n]->qty += 1; - player->artifactsBag[n]->active = 0; - player->stats->artifactsfound += 1; - } - break; - case '7': { - picked_debug_proc = 1; - int res = system("clear"); - sprintf(msg, "debug_generic() 3 system(\"clear\") res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - printf("\nPlayer Counters:\n"); - printCounters((Turncounter **) player->counters); - printf("\nPress Enter to resume game"); - res = scanf("%*c"); - sprintf(msg, "debug_generic() 5 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'd': { - picked_debug_proc = 1; - printf("\nVERSION: %s\n", VERSION); -#ifndef _WIN32 - printf("\nSystem: %s\n", uts.sysname); - printf("\nOS Release: %s\n", uts.release); - printf("\nOS Version: %s\n", uts.version); - printf("\nMachine: %s\n", uts.machine); -#endif - printf("\nGAMEMODE: %s\n", stringFromGamemode(GAMEMODE)); - printf("\nPath->current_saveslot->save_path: %s\n", - p->current_saveslot->save_path); - printf("\nGS_AUTOSAVE_ON: %i\n", GS_AUTOSAVE_ON); - printf("\nG_FASTQUIT_ON: %i\n", G_FASTQUIT_ON); - printf("\nG_DEBUG_ON: %i\n", G_DEBUG_ON); - printf("\nG_LOG_ON: %i\n", G_LOG_ON); - printf("\nG_GODMODE_ON: %i\n", G_GODMODE_ON); - printf("\nG_EXPERIMENTAL_ON: %i\n", G_EXPERIMENTAL_ON); - printf("\nG_DEBUG_ROOMTYPE_ON: %i\n", G_DEBUG_ROOMTYPE_ON); - if (G_DEBUG_ROOMTYPE_ON == 1) { - printf("\nG_DEBUG_ROOMTYPE: %i\n", G_DEBUG_ROOMTYPE); - } - printf("\nG_DEBUG_ENEMYTYPE_ON: %i\n", G_DEBUG_ENEMYTYPE_ON); - if (G_DEBUG_ENEMYTYPE_ON == 1) { - printf("\nG_DEBUG_ENEMYTYPE: %i\n", G_DEBUG_ENEMYTYPE); - } - printf("\nPress Enter to resume game.\n"); - int res = scanf("%*c"); - sprintf(msg, "debug_generic() 7 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'F': { - sprintf(msg, "Trying out Floor functionality."); - log_tag("debug_log.txt", "[DEBUG]", msg); - // Declare dbg_floor - sprintf(msg, "Pushing dbg_floor to tkls."); - log_tag("debug_log.txt", "[DEBUG]", msg); - kls_log(kls, "DEBUG", msg); - Floor *dbg_floor = - (Floor *) KLS_PUSH_T_TYPED(t_kls, Floor, HR_Floor, - "Floor", msg); - // Start the random walk from the center of the dungeon - int center_x = FLOOR_MAX_COLS / 2; - int center_y = FLOOR_MAX_ROWS / 2; - // Init dbg_floor - init_floor_layout(dbg_floor); - //Set center as filled - dbg_floor->floor_layout[center_x][center_y] = 1; - - init_floor_rooms(dbg_floor); - - floor_random_walk(dbg_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reload floor_layout if needed - load_floor_explored(dbg_floor); - - floor_set_room_types(dbg_floor); - - /* - debug_print_floor_layout(dbg_floor); - - printf("\nPress Enter to see room layout.\n"); - int res = scanf("%*c"); - sprintf(msg,"debug_generic() 7 scanf() res was (%i)", res); - log_tag("debug_log.txt","[DEBUG]",msg); - */ - debug_print_roomclass_layout(dbg_floor, stdout); - printf("\nPress Enter to return to game.\n"); - res = scanf("%*c"); - sprintf(msg, "debug_generic() 8 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - //free(dbg_floor); - } - break; - case 'A': { - GS_AUTOSAVE_ON = (GS_AUTOSAVE_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_AUTOSAVE_ON, new value: (%i)", - GS_AUTOSAVE_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'G': { - log_tag("debug_log.txt", "[DEBUG]", "Logging Gamestate"); - dbg_Gamestate(gmst); - log_tag("debug_log.txt", "[DEBUG]", "Done logging Gamestate"); - } - break; - case 'T': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - - fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); - for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { - ptrdiff_t usage = kls_type_usage(i, temporary_kls); -#ifndef _WIN32 - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#else - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#endif - } - fprintf(kls_file, "--END debug of temporary_kls--\n\n"); - - fclose(kls_file); - } - break; - case 't': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); - print_kls_2file(kls_file, temporary_kls); - kls_showList_toFile(temporary_kls->regs, kls_file); - kls_usageReport_toFile(temporary_kls, kls_file); - fprintf(kls_file, "--END debug of temporary_kls--\n\n"); - WINDOW *win = NULL; - /* Initialize curses */ - clear(); - refresh(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - win = newwin(20, 50, 1, 2); - keypad(win, TRUE); - wclear(win); - wrefresh(win); - kls_showList_toWin(temporary_kls, win); - delwin(win); - endwin(); - - fclose(kls_file); - } - break; - case 'K': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - - fprintf(kls_file, "--BEGIN debug of passed kls--\n"); - for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { - ptrdiff_t usage = kls_type_usage(i, kls); -#ifndef _WIN32 - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#else - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#endif - } - fprintf(kls_file, "--END debug of passed kls--\n\n"); - - fclose(kls_file); - } - break; - case 'k': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - fprintf(kls_file, "--BEGIN debug of passed kls--\n"); - print_kls_2file(kls_file, kls); - kls_showList_toFile(kls->regs, kls_file); - kls_usageReport_toFile(kls, kls_file); - fprintf(kls_file, "--END debug of passed kls--\n\n"); - WINDOW *win = NULL; - /* Initialize curses */ - clear(); - refresh(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - win = newwin(20, 50, 1, 2); - keypad(win, TRUE); - wclear(win); - wrefresh(win); - kls_showList_toWin(kls, win); - delwin(win); - endwin(); - - fclose(kls_file); - } - break; - case 'Q': { - G_FASTQUIT_ON = (G_FASTQUIT_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_FASTQUIT_ON, new value: (%i)", - G_FASTQUIT_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'g': { - G_GODMODE_ON = (G_GODMODE_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_GODMODE_ON, new value: (%i)", - G_GODMODE_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'L': { - G_LOG_ON = (G_LOG_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_LOG_ON, new value: (%i)", G_LOG_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - case 's': { //Query sprites slideshow - picked_debug_proc = 1; - int res = system("clear"); - sprintf(msg, "debug_generic() 4 system(\"clear\") res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - int comm_len = -1; - int picked_comm = 0; - char comm[15] = "empty"; - char *desc = NULL; - int sprite_total = -1; - int tot_cons = CONSUMABLESMAX + 1; - int tot_enemy = ENEMYCLASSESMAX + 1; - int tot_boss = BOSSCLASSESMAX + 1; - int tot_art = ARTIFACTSMAX + 1; - int tot_eq = EQUIPSMAX + 1; - int tot_eqzones = EQUIPZONES + 1; - int tot_misc = MISC_SPRITES_MAX + 1; - int allsprites = - tot_cons + - tot_enemy + - tot_boss + tot_art + tot_eq + tot_eqzones + tot_misc; - - printf("\nConsumables sprites: \t%d\ -\nArtifacts sprites: \t%d\ -\nEquips sprites: \t%d\ -\nEquip zone sprites: \t%d\ -\nEnemies sprites: \t%d\ -\nBosses sprites: \t%d\ -\nOther misc sprites: \t%d\n", tot_cons, tot_art, tot_eq, tot_eqzones, tot_enemy, tot_boss, tot_misc); - printf("--------------------------"); - printf("\nTotal sprites: \t\t%d\n", allsprites); - printf - ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", - player->name); - while (!picked_comm && (comm_len = scanf("%10s", comm)) > -1) { - int res = scanf("%*c"); - sprintf(msg, "debug_generic() 7 scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - if (strcmp(comm, "q") == 0) { - return; - } else if (strcmp(comm, "boss") == 0) { - picked_comm = 1; - sprite_total = BOSSCLASSESMAX + 1; - } else if (strcmp(comm, "cons") == 0) { - picked_comm = 1; - sprite_total = CONSUMABLESMAX + 1; - } else if (strcmp(comm, "equip") == 0) { - picked_comm = 1; - sprite_total = EQUIPSMAX + 1; - } else if (strcmp(comm, "eqzone") == 0) { - picked_comm = 1; - sprite_total = EQUIPZONES + 1; - } else if (strcmp(comm, "artf") == 0) { - picked_comm = 1; - sprite_total = ARTIFACTSMAX + 1; - } else if (strcmp(comm, "enemy") == 0) { - picked_comm = 1; - sprite_total = ENEMYCLASSESMAX + 1; - } else if (strcmp(comm, "misc") == 0) { - picked_comm = 1; - sprite_total = MISC_SPRITES_MAX + 1; - } else { - printf - ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", - player->name); - } - } - int sprite_count = -1; - int c = -1; - char s[20]; - int startx = 0; - int x, y; - WINDOW *spriteshow_win; - /* Initialize curses */ - //initscr(); - start_color(); - clear(); - refresh(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - spriteshow_win = newwin(19, 19, 2, 2); - keypad(spriteshow_win, TRUE); - for (sprite_count = 0; sprite_count < sprite_total; - sprite_count++) { - if (strcmp(comm, "boss") == 0) { - desc = stringFromBossClass(sprite_count); - } else if (strcmp(comm, "cons") == 0) { - desc = stringFromConsumables(sprite_count); - } else if (strcmp(comm, "equip") == 0) { - desc = stringFromEquips(sprite_count); - } else if (strcmp(comm, "eqzone") == 0) { - desc = stringFromEquipzones(sprite_count); - } else if (strcmp(comm, "artf") == 0) { - desc = stringFromArtifacts(sprite_count); - } else if (strcmp(comm, "enemy") == 0) { - desc = stringFromEClass(sprite_count); - } else if (strcmp(comm, "misc") == 0) { - desc = "Misc"; - } - wclear(spriteshow_win); - wrefresh(spriteshow_win); - wclear(stdscr); - wrefresh(stdscr); - sprintf(msg, "Showing sprite n.%d, class is: %s\n", - sprite_count, desc); - log_tag("debug_log.txt", "[DEBUG]", msg); - mvwprintw(stdscr, 5, 20, "Sprite for: \'%s\'", desc); - mvwprintw(stdscr, 7, 20, "(%i/%i)", sprite_count + 1, - sprite_total); - refresh(); - for (int i = 0; i < 8; i++) { - if (strcmp(comm, "boss") == 0) { - strcpy(s, bosses_sprites[sprite_count][i]); - } else if (strcmp(comm, "cons") == 0) { - strcpy(s, consumables_sprites[sprite_count][i]); - } else if (strcmp(comm, "equip") == 0) { - strcpy(s, equips_sprites[sprite_count][i]); - } else if (strcmp(comm, "eqzone") == 0) { - strcpy(s, equipzones_sprites[sprite_count][i]); - } else if (strcmp(comm, "artf") == 0) { - strcpy(s, artifacts_sprites[sprite_count][i]); - } else if (strcmp(comm, "enemy") == 0) { - strcpy(s, enemies_sprites[sprite_count][i]); - } else if (strcmp(comm, "misc") == 0) { - strcpy(s, misc_sprites[sprite_count][i]); - } - //sprintf(msg,"[DEBUG] Copied string: \'%s\'\n", s); - //debug_log("debug_log.txt",msg); - - for (int j = 0; j < 13; j++) { - x = startx + 1 + j; - y = 1 + i; - - print_encoded_char(spriteshow_win, y, x, s[j]); - } //End for line print - } //End for sprite print - - wrefresh(spriteshow_win); - //printf("\nPress Enter for next, q to quit.\n"); - int picked = 0; - int go_previous = 0; - int quit_show = 0; - while (!picked - && ((c = wgetch(spriteshow_win)) != KEY_F(1))) { - if (c == 10 || c == KEY_RIGHT) { //Enter, right - sprintf(msg, "Going to next sprite.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - wclear(spriteshow_win); - wrefresh(spriteshow_win); - picked = 1; - continue; //Go to next sprite - } else if (c == 'q') { //Quit - sprintf(msg, "Stopping query sprite show.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - picked = 1; - quit_show = 1; - } else if (c == KEY_LEFT) { //Go to previous sprite - go_previous = 1; - sprintf(msg, "Going to previous sprite.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - picked = 1; - } else { //Unexpected char - sprintf(msg, - "Wrong operation. Continuing with next sprite.\n"); - log_tag("debug_log.txt", "\033[1;31m[ERROR]", msg); - picked = 1; - continue; //We still go to next sprite - } - } //End while wait for user input - if (go_previous) { - sprite_count--; - sprite_count--; - if (sprite_count < -1) - sprite_count = -1; - go_previous = 0; - } - if (quit_show) { - break; - } - } //End for all sprites - sprintf(msg, "End of sprite show.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - - delwin(spriteshow_win); - endwin(); - } - break; - case 'q': { - return; - } - default: { //Echo the passed char and ask for one more. - char cmd[50]; - sprintf(cmd, "\necho \"%c\\n\"\n%c\n\n", ch[0], ch[0]); - printf("%s", cmd); - napms(500); - } - break; - } //Close switch on ch[0] - } //Close while !picked_debug_proc - - res = system("clear"); - sprintf(msg, "debug_generic() final system(\"clear\") res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); -} - -/** - * Takes a Room, a Fighter, a Enemy and a Path pointers (and integers for current room and enemy indexes) and asks user input to execute debug actions. - * @see Room - * @see Fighter - * @see Enemy - * @see Path - * @see checkremainder() - * @see statReset() - * @see statResetEnemy() - * @see GET_CALLBACK() - * @see unlock_special() - * @see printCounters() - * @see dropEquip() - * @param gmst The Gamestate pointer. - * @param player The Fighter pointer at hand. - * @param e The Enemy pointer for current enemy. - * @param p The Path pointer of the current game. - * @param roomIndex The index of current room. - * @param currentEnemyNum The index of current enemy. - * @param kls The Koliseo used for allocations. - * @param t_kls The Koliseo_Temp used for temporary allocations. - */ -void debug_enemies_room(Gamestate *gmst, Room *room, Fighter *player, Enemy *e, - Path *p, int roomIndex, int currentEnemyNum, - Koliseo *kls, Koliseo_Temp *t_kls) -{ - - char msg[200]; - char ch[25]; - int picked_debug_proc = 0; -#ifndef _WIN32 - struct utsname uts; - uname(&uts); - sprintf(msg, "debug_enemies_room() loaded utsname using uname().\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "System is %s\n", uts.sysname); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "OS Release is %s\n", uts.release); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "OS Version is %s\n", uts.version); - log_tag("debug_log.txt", "[DEBUG]", msg); - sprintf(msg, "Machine is %s\n", uts.machine); - log_tag("debug_log.txt", "[DEBUG]", msg); -#endif - - int res = system("clear"); - sprintf(msg, "debug_enemies_room() system(\"clear\") res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - - int c = 0, n = -1; - while (!picked_debug_proc) { - int res = system("clear"); - sprintf(msg, "debug_enemies_room() 2 system(\"clear\") res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - printf("\n\ - What do you want to do? ('q' to quit)\n\ - [\n\ - '0': Give xp points\t'1': Give consumable\n\ - '2': Reset stats\t'3': Reset Enemy\n\ - '4': Alter luck\t'5': Give coins\n\ - '6': Unlock special\t'7': Unlock Artifact\n\ - '8': Print counters\t'9': Give Equip\n\ - 's': Sprites slideshow\t'd': Dump debug symbols\n\ - 'f': Show foes info\t'g': Toggle godmode\n\ - 'A': Toggle autosave\t'Q': Toggle fast quit\n\ - 'L': Toggle logging\t'k': Log passed Koliseo info\n\ - 't': Log global temporary_kls Koliseo info\n\ - 'K': Log usage stats for passed kls to debug log file.\n\ - 'T': Log usage stats for temporary_kls to debug log file.\n\ - 'G': Log Gamestate to debug log file.\n\ - 'q': Quit\t{Return} Process your input line.\n\ - ]\n\n\ - [%s@debug-func]$ ", player->name); - - char *fgetsres = fgets(ch, sizeof ch, stdin); - sprintf(msg, "debug_enemies_room() fgets() res was (%s)", fgetsres); - log_tag("debug_log.txt", "[DEBUG]", msg); - switch (ch[0]) { - case '0': { - picked_debug_proc = 1; - int xp; - do { - printf("\nHow much?\n"); - } while ((c = scanf("%i", &xp)) != 1 || xp < 0); - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - checkremainder(player, xp); - } - break; - case '1': { - picked_debug_proc = 1; - int q = -1; - do { - printf("\nInsert consumable number:\n"); - } while ((c = scanf("%i", &n)) != 1 || n > CONSUMABLESMAX - || n < 0); - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - do { - printf("\nInsert quantity:\n"); - } while ((c = scanf("%i", &q)) != 1 && q <= 0); - res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 2 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - Consumable *c = (Consumable *) player->consumablesBag[n]; - c->qty += q; - player->stats->consumablesfound += q; - } - break; - case '2': { - picked_debug_proc = 1; - statReset(player, 1); - } - break; - case '3': { - picked_debug_proc = 1; - statResetEnemy(e, 1); - } - break; - case '4': { - picked_debug_proc = 1; - printf("\nCurrent luck: %i\tRL: %i\n", player->luck, p->luck); - - do { - printf("\nInsert new luck:\n"); - } while ((c = scanf("%i", &n)) != 1 && n > 0); - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 3 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - //FIXME: - //Copy-pasted the calc for player luck... might need a function - p->luck = n; - - player->luck = (p->luck * MAXPLAYERLUCK) / MAXLUCK; - } - break; - case '5': { - picked_debug_proc = 1; - /* Old code invoking the macro for special moves directly. Used for testing. - * int s = -1; - * printf("Insert special num:\n"); - * scanf("%i",&s); - * scanf("%*c"); - * printf("Read: %i\n",s); - * GET_CALLBACK(s,callback_special_t)(player,e,p,roomIndex,currentEnemyNum); - */ - - //printActivePerks(player); - int c; - int n = -1; - do { - printf("\nInsert coin number (0 3 || n < 0 - || n > 100); - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 4 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - player->balance += n; - } - break; - case '6': { - picked_debug_proc = 1; - unlockSpecial(player); - } - break; - case '7': { - picked_debug_proc = 1; - int n = -1; - do { - printf("\nInsert artifact number (0 ARTIFACTSMAX - || n < 0); - - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() scanf() res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - player->artifactsBag[n]->qty += 1; - player->artifactsBag[n]->active = 0; - player->stats->artifactsfound += 1; - } - break; - case '8': { - picked_debug_proc = 1; - int res = system("clear"); - sprintf(msg, - "debug_enemies_room() 3 system(\"clear\") res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - printf("\nPlayer Counters:\n"); - printCounters((Turncounter **) player->counters); - printf("\nEnemy (%s) Counters:\n", stringFromEClass(e->class)); - printCounters((Turncounter **) e->counters); - printf("\nPress Enter to resume game"); - res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 5 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case '9': { - picked_debug_proc = 1; - int q = -1; - int c = -1; - do { - printf("\nInsert quantity:\n"); - } while ((c = scanf("%i", &q)) != 1 && q <= 0); - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 6 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - - //TODO: handle dropping an equip with a new notification window - //for (int i=0; icurrent_saveslot->save_path: %s\n", - p->current_saveslot->save_path); - printf("\nGS_AUTOSAVE_ON: %i\n", GS_AUTOSAVE_ON); - printf("\nG_FASTQUIT_ON: %i\n", G_FASTQUIT_ON); - printf("\nG_DEBUG_ON: %i\n", G_DEBUG_ON); - printf("\nG_LOG_ON: %i\n", G_LOG_ON); - printf("\nG_GODMODE_ON: %i\n", G_GODMODE_ON); - printf("\nG_EXPERIMENTAL_ON: %i\n", G_EXPERIMENTAL_ON); - printf("\nG_DEBUG_ROOMTYPE_ON: %i\n", G_DEBUG_ROOMTYPE_ON); - if (G_DEBUG_ROOMTYPE_ON == 1) { - printf("\nG_DEBUG_ROOMTYPE: %i\n", G_DEBUG_ROOMTYPE); - } - printf("\nG_DEBUG_ENEMYTYPE_ON: %i\n", G_DEBUG_ENEMYTYPE_ON); - if (G_DEBUG_ENEMYTYPE_ON == 1) { - printf("\nG_DEBUG_ENEMYTYPE: %i\n", G_DEBUG_ENEMYTYPE); - } - printf("\nPress Enter to resume game.\n"); - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 7 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'f': { - clear(); - refresh(); - debug_printFoeParty(room->foes); - } - break; - case 'G': { - log_tag("debug_log.txt", "[DEBUG]", "Logging Gamestate"); - dbg_Gamestate(gmst); - log_tag("debug_log.txt", "[DEBUG]", "Done logging Gamestate"); - } - break; - case 'T': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - - fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); - for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { - ptrdiff_t usage = kls_type_usage(i, temporary_kls); -#ifndef _WIN32 - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#else - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#endif - } - fprintf(kls_file, "--END debug of temporary_kls--\n\n"); - - fclose(kls_file); - } - break; - case 't': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); - print_kls_2file(kls_file, temporary_kls); - kls_showList_toFile(temporary_kls->regs, kls_file); - kls_usageReport_toFile(temporary_kls, kls_file); - fprintf(kls_file, "--END debug of temporary_kls--\n\n"); - WINDOW *win = NULL; - /* Initialize curses */ - clear(); - refresh(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - win = newwin(20, 50, 1, 2); - keypad(win, TRUE); - wclear(win); - wrefresh(win); - kls_showList_toWin(temporary_kls, win); - delwin(win); - endwin(); - - fclose(kls_file); - } - break; - case 'K': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - - fprintf(kls_file, "--BEGIN debug of passed kls--\n"); - for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { - ptrdiff_t usage = kls_type_usage(i, kls); -#ifndef _WIN32 - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#else - fprintf(kls_file, - "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", - stringFrom_HLP_Region_Type(i - 101 + - KLS_REGIONTYPE_MAX), i, - usage); -#endif - } - fprintf(kls_file, "--END debug of passed kls--\n\n"); - - fclose(kls_file); - } - break; - case 'k': { - char path_to_kls_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Append to "kls_log.txt" - sprintf(path_to_kls_file, "%s/%s", static_path, - "debug_log.txt"); - FILE *kls_file = NULL; - kls_file = fopen(path_to_kls_file, "a"); - if (kls_file == NULL) { - fprintf(stderr, - "debug_generic(): failed opening debug logfile.\n"); - exit(EXIT_FAILURE); - } - if (kls == NULL) { - fprintf(stderr, "debug_generic(): kls was NULL.\n"); - exit(EXIT_FAILURE); - } - fprintf(kls_file, "--BEGIN debug of passed kls--\n"); - print_kls_2file(kls_file, kls); - kls_showList_toFile(kls->regs, kls_file); - kls_usageReport_toFile(kls, kls_file); - fprintf(kls_file, "--END debug of passed kls--\n\n"); - WINDOW *win = NULL; - /* Initialize curses */ - clear(); - refresh(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - win = newwin(20, 50, 1, 2); - keypad(win, TRUE); - wclear(win); - wrefresh(win); - kls_showList_toWin(kls, win); - delwin(win); - endwin(); - fclose(kls_file); - } - break; - case 'A': { - GS_AUTOSAVE_ON = (GS_AUTOSAVE_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_AUTOSAVE_ON, new value: (%i)", - GS_AUTOSAVE_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'Q': { - G_FASTQUIT_ON = (G_FASTQUIT_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_FASTQUIT_ON, new value: (%i)", - G_FASTQUIT_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'L': { - G_LOG_ON = (G_LOG_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_LOG_ON, new value: (%i)", G_LOG_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 'g': { - G_GODMODE_ON = (G_GODMODE_ON == 1 ? 0 : 1); - sprintf(msg, "Toggled G_GODMODE_ON, new value: (%i)", - G_GODMODE_ON); - log_tag("debug_log.txt", "[DEBUG]", msg); - } - break; - case 's': { //Query sprites slideshow - picked_debug_proc = 1; - int res = system("clear"); - sprintf(msg, - "debug_enemies_room() 4 system(\"clear\") res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - int comm_len = -1; - int picked_comm = 0; - char comm[15] = "empty"; - char *desc = NULL; - int sprite_total = -1; - int tot_cons = CONSUMABLESMAX + 1; - int tot_enemy = ENEMYCLASSESMAX + 1; - int tot_boss = BOSSCLASSESMAX + 1; - int tot_art = ARTIFACTSMAX + 1; - int tot_eq = EQUIPSMAX + 1; - int tot_eqzones = EQUIPZONES + 1; - int tot_misc = MISC_SPRITES_MAX + 1; - int allsprites = - tot_cons + - tot_enemy + - tot_boss + tot_art + tot_eq + tot_eqzones + tot_misc; - - printf("\nConsumables sprites: \t%d\ -\nArtifacts sprites: \t%d\ -\nEquips sprites: \t%d\ -\nEquip zone sprites: \t%d\ -\nEnemies sprites: \t%d\ -\nBosses sprites: \t%d\ -\nOther misc sprites: \t%d\n", tot_cons, tot_art, tot_eq, tot_eqzones, tot_enemy, tot_boss, tot_misc); - printf("--------------------------"); - printf("\nTotal sprites: \t\t%d\n", allsprites); - printf - ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", - player->name); - while (!picked_comm && (comm_len = scanf("%10s", comm)) > -1) { - int res = scanf("%*c"); - sprintf(msg, "debug_enemies_room() 7 scanf() res was (%i)", - res); - log_tag("debug_log.txt", "[DEBUG]", msg); - if (strcmp(comm, "q") == 0) { - return; - } else if (strcmp(comm, "boss") == 0) { - picked_comm = 1; - sprite_total = BOSSCLASSESMAX + 1; - } else if (strcmp(comm, "cons") == 0) { - picked_comm = 1; - sprite_total = CONSUMABLESMAX + 1; - } else if (strcmp(comm, "equip") == 0) { - picked_comm = 1; - sprite_total = EQUIPSMAX + 1; - } else if (strcmp(comm, "eqzone") == 0) { - picked_comm = 1; - sprite_total = EQUIPZONES + 1; - } else if (strcmp(comm, "artf") == 0) { - picked_comm = 1; - sprite_total = ARTIFACTSMAX + 1; - } else if (strcmp(comm, "enemy") == 0) { - picked_comm = 1; - sprite_total = ENEMYCLASSESMAX + 1; - } else if (strcmp(comm, "misc") == 0) { - picked_comm = 1; - sprite_total = MISC_SPRITES_MAX + 1; - } else { - printf - ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", - player->name); - } - } - int sprite_count = -1; - int c = -1; - char s[20]; - int startx = 0; - int x, y; - WINDOW *spriteshow_win; - /* Initialize curses */ - //initscr(); - start_color(); - clear(); - refresh(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - spriteshow_win = newwin(19, 19, 2, 2); - keypad(spriteshow_win, TRUE); - for (sprite_count = 0; sprite_count < sprite_total; - sprite_count++) { - if (strcmp(comm, "boss") == 0) { - desc = stringFromBossClass(sprite_count); - } else if (strcmp(comm, "cons") == 0) { - desc = stringFromConsumables(sprite_count); - } else if (strcmp(comm, "equip") == 0) { - desc = stringFromEquips(sprite_count); - } else if (strcmp(comm, "eqzone") == 0) { - desc = stringFromEquipzones(sprite_count); - } else if (strcmp(comm, "artf") == 0) { - desc = stringFromArtifacts(sprite_count); - } else if (strcmp(comm, "enemy") == 0) { - desc = stringFromEClass(sprite_count); - } else if (strcmp(comm, "misc") == 0) { - desc = "Misc"; - } - wclear(spriteshow_win); - wrefresh(spriteshow_win); - wclear(stdscr); - wrefresh(stdscr); - sprintf(msg, "Showing sprite n.%d, class is: %s\n", - sprite_count, desc); - log_tag("debug_log.txt", "[DEBUG]", msg); - mvwprintw(stdscr, 5, 20, "Sprite for: \'%s\'", desc); - mvwprintw(stdscr, 7, 20, "(%i/%i)", sprite_count + 1, - sprite_total); - refresh(); - for (int i = 0; i < 8; i++) { - if (strcmp(comm, "boss") == 0) { - strcpy(s, bosses_sprites[sprite_count][i]); - } else if (strcmp(comm, "cons") == 0) { - strcpy(s, consumables_sprites[sprite_count][i]); - } else if (strcmp(comm, "equip") == 0) { - strcpy(s, equips_sprites[sprite_count][i]); - } else if (strcmp(comm, "eqzone") == 0) { - strcpy(s, equipzones_sprites[sprite_count][i]); - } else if (strcmp(comm, "artf") == 0) { - strcpy(s, artifacts_sprites[sprite_count][i]); - } else if (strcmp(comm, "enemy") == 0) { - strcpy(s, enemies_sprites[sprite_count][i]); - } else if (strcmp(comm, "misc") == 0) { - strcpy(s, misc_sprites[sprite_count][i]); - } - //sprintf(msg,"[DEBUG] Copied string: \'%s\'\n", s); - //debug_log("debug_log.txt",msg); - - for (int j = 0; j < 13; j++) { - x = startx + 1 + j; - y = 1 + i; - - print_encoded_char(spriteshow_win, y, x, s[j]); - } //End for line print - } //End for sprite print - - wrefresh(spriteshow_win); - //printf("\nPress Enter for next, q to quit.\n"); - int picked = 0; - int go_previous = 0; - int quit_show = 0; - while (!picked - && ((c = wgetch(spriteshow_win)) != KEY_F(1))) { - if (c == 10 || c == KEY_RIGHT) { //Enter, right - sprintf(msg, "Going to next sprite.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - wclear(spriteshow_win); - wrefresh(spriteshow_win); - picked = 1; - continue; //Go to next sprite - } else if (c == 'q') { //Quit - sprintf(msg, "Stopping query sprite show.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - picked = 1; - quit_show = 1; - } else if (c == KEY_LEFT) { //Go to previous sprite - go_previous = 1; - sprintf(msg, "Going to previous sprite.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - picked = 1; - } else { //Unexpected char - sprintf(msg, - "Wrong operation. Continuing with next sprite.\n"); - log_tag("debug_log.txt", "\033[1;31m[ERROR]", msg); - picked = 1; - continue; //We still go to next sprite - } - } //End while wait for user input - if (go_previous) { - sprite_count--; - sprite_count--; - if (sprite_count < -1) - sprite_count = -1; - go_previous = 0; - } - if (quit_show) { - break; - } - } //End for all sprites - sprintf(msg, "End of sprite show.\n"); - log_tag("debug_log.txt", "[DEBUG]", msg); - - delwin(spriteshow_win); - endwin(); - } - break; - case 'q': { - return; - } - default: { //Echo the passed char and ask for one more. - char cmd[50]; - sprintf(cmd, "\necho \"%c\\n\"\n%c\n\n", ch[0], ch[0]); - printf("%s", cmd); - napms(500); - } - break; - } //Close switch on ch[0] - } //Close while !picked_debug_proc - -} - -/** - * Takes a Fighter, a Room and a loadInfo pointers, and prints fighter stats and a quitting message, before quitting the program and freeing Room. - * - * @see Fighter - * @see printStats() - * @see death() - * @param p The Fighter pointer at hand. - * @param room The Room pointer at hand. - * @param load_info The loadInfo pointer at hand. - * @param t_kls The Koliseo_Temp to end if possible. - */ -void quit(Fighter *p, Room *room, loadInfo *load_info, Koliseo_Temp *t_kls) -{ - char msg[500]; - Koliseo *kls = t_kls->kls; - endwin(); - int res = system("reset"); - sprintf(msg, "quit() system(\"reset\") res was (%i)", res); - log_tag("debug_log.txt", "[DEBUG]", msg); - //printf("\n\n\tTHANKS 4 PLAYING\n"); - //FIXME - //dropping out of the Koliseo scope might render stat pointer invalid. - //Can't we print stats and clear the kls? - //printStats(p); - //printf("\n"); -#ifndef _WIN32 - sprintf(msg, "Resetting Koliseo_Temp from: (%li)", t_kls->kls->offset); -#else - sprintf(msg, "Resetting Koliseo_Temp from: (%lli)", t_kls->kls->offset); -#endif - kls_log(kls, "DEBUG", msg); - death(p, load_info); - //FIXME - //I think we should free those? - //May cause a crash? - //kls_free(default_kls); - //kls_free(temporary_kls); - //FIXME: - //Calling this segfaults? - //freeRoom(room); - log_tag("debug_log.txt", "[DEBUG]", "Quitting program."); - exit(EXIT_SUCCESS); -} - -/** - * Takes a Fighter pointer and deleted all the equips not in use, granting a payment to the Fighter balance. - * @see Shop - * @see handleRoom_Shop() - * @see Fighter - * @param f The Fighter pointer at hand. - */ -void sell_all_equips(Fighter *f, Koliseo_Temp *t_kls) -{ - char msg[200]; - - Equip *saved_equips[EQUIPZONES + 1]; - int saved_count = 0; - Koliseo *kls = t_kls->kls; - - for (int i = 0; i < EQUIPZONES + 1; i++) { - if (f->equipslots[i]->active) { - sprintf(msg, - "sell_all_equips(): Prepping Equip to save f->equipslot[%i]", - i); - log_tag("debug_log.txt", "[DEBUG]", msg); - kls_log(kls, "DEBUG", msg); - Equip *saved = - (Equip *) KLS_PUSH_T_TYPED(t_kls, Equip, HR_Equip, "Equip", - msg); - Equip *to_save = f->equipslots[i]->item; - - saved->class = to_save->class; - saved->type = to_save->type; - strcpy(saved->name, to_save->name); - strcpy(saved->desc, to_save->desc); - saved->qty = to_save->qty; - saved->equipped = 0; //Will be set after when re-equipped - saved->level = to_save->level; - saved->atk = to_save->atk; - saved->def = to_save->def; - saved->vel = to_save->vel; - saved->enr = to_save->enr; - saved->bonus = to_save->bonus; - saved->perksCount = 0; //Will be set during perks copy - saved->qual = to_save->qual; - saved->equip_fun = to_save->equip_fun; - - for (int j = 0; j < to_save->perksCount; j++) { - sprintf(msg, - "sell_all_equips(): Prepping Perk (%i) to save f->equipslot[%i]", - j, i); - log_tag("debug_log.txt", "[DEBUG]", msg); - kls_log(kls, "DEBUG", msg); - Perk *save_pk = - (Perk *) KLS_PUSH_T_TYPED(t_kls, Perk, HR_Perk, "Perk", - msg); - save_pk->class = to_save->perks[j]->class; - strcpy(save_pk->name, to_save->perks[j]->name); - strcpy(save_pk->desc, to_save->perks[j]->desc); - save_pk->innerValue = to_save->perks[j]->innerValue; - saved->perks[saved->perksCount] = save_pk; - saved->perksCount++; - } - - for (int j = 0; j < 8; j++) { - strcpy(saved->sprite[j], to_save->sprite[j]); - } - - saved_equips[saved_count] = saved; - saved_count++; - } - } - - int deleted_count = 0; - int pay = 0; - - for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { - Equip *toDel = f->equipsBag[i]; - pay += toDel->cost / 2; - //int perksTot = toDel->perksCount; - /* - for (int j = 0; j < perksTot; j++) { - Perk* pk = toDel->perks[j]; - free(pk); - } - */ - //FIXME: are we deleting this correctly? - //free(toDel); - deleted_count++; - } - - f->equipsBagOccupiedSlots -= deleted_count; - - for (int i = 0; i < saved_count; i++) { - f->equipsBag[i] = saved_equips[i]; - f->equipslots[i]->item = saved_equips[i]; - saved_equips[i]->equipped = 1; - f->equipsBagOccupiedSlots++; - } - f->earliestBagSlot = f->equipsBagOccupiedSlots; - - f->balance += pay; - -} - -/** - * Takes a Room pointer and a Fighter pointer, displays a choice for the next room and sets it at *roadFork_value. - * @see Roadfork - * @see Fighter - * @param room The pointer to current room. - * @param roadFork_value The pointer to the value for next room's class. - * @param roomsDone The total of rooms completed. - * @param path The Path pointer. - * @param f The Fighter pointer at hand. - * @return When room is exited, should return NO_DMG. - */ -int handleRoom_Roadfork(Room *room, int *roadFork_value, int roomsDone, - Path *path, Fighter *f) -{ - //Strings for turn menu choices - char choices[ROADFORK_OPTIONS_MAX + 1][80] = { - "One", - "Two" - }; - //TODO: the choices array had a '(char) NULL' value which was giving a obvious warning about pointer to integer casting. - //Was it needed as a sentinel value?? - - char msg[200]; - - for (int i = 0; i < 2; i++) { - char c[80]; - switch (room->roadfork->options[i]) { - case ROADFORK_BOSS: { - strcpy(c, "Boss Room"); - } - break; - case ROADFORK_SHOP: { - strcpy(c, "Shop Room"); - } - break; - case ROADFORK_TREASURE: { - strcpy(c, "Treasure Room"); - } - break; - case ROADFORK_ENEMIES: { - strcpy(c, "Enemies"); - } - break; - case ROADFORK_ROADFORK: { - strcpy(c, "Roadfork"); - } - break; - } - strcpy(choices[i], c); - } - sprintf(msg, "Entered Roadfork with %s and %s.\n", choices[0], choices[1]); - log_tag("debug_log.txt", "[ROADFORK]", msg); - - ITEM **my_items; - MENU *my_menu; - WINDOW *my_menu_win; - int n_choices, c; - - /* Initialize curses */ - //initscr(); - start_color(); - clear(); - refresh(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - /* Create items */ - n_choices = ARRAY_SIZE(choices); - sprintf(msg, "n_choices size was: (%i)\n", n_choices); - log_tag("debug_log.txt", "[ROADFORK]", msg); - my_items = (ITEM **) calloc(n_choices, sizeof(ITEM *)); - for (int k = 0; k < n_choices; k++) { - my_items[k] = new_item(choices[k], choices[k]); - /* Set the user pointer */ - //set_item_userptr(my_items[i]); - } - - /* Create menu */ - my_menu = new_menu((ITEM **) my_items); - - /* Set description off */ - menu_opts_off(my_menu, O_SHOWDESC); - - /* Create the window to be associated with the menu */ - my_menu_win = newwin(12, 28, 1, 1); - keypad(my_menu_win, TRUE); - - /* Set main window and sub window */ - set_menu_win(my_menu, my_menu_win); - set_menu_sub(my_menu, derwin(my_menu_win, 4, 26, 3, 2)); - set_menu_format(my_menu, 3, 1); - - /* Set menu mark to the string " > " */ - set_menu_mark(my_menu, " > "); - - char label[25]; - sprintf(label, "Road Fork"); - - /* Print a border around the main window and print a title */ - box(my_menu_win, 0, 0); - print_label(my_menu_win, 1, 0, 28, label, COLOR_PAIR(S4C_MAGENTA)); - mvwaddch(my_menu_win, 2, 0, ACS_LTEE); - mvwhline(my_menu_win, 2, 1, ACS_HLINE, 26); - mvwaddch(my_menu_win, 2, 27, ACS_RTEE); - - /* Post the menu */ - post_menu(my_menu); - wrefresh(my_menu_win); - - /* Create the items window */ - //win = newwin(22, 54, 1, 23); - //keypad(win, TRUE); - //box(win, 0, 0); - - //print_label(win, 1, 0, 54, "Option", COLOR_PAIR(6)); - //mvwaddch(win, 2, 0, ACS_LTEE); - //mvwhline(win, 2, 1, ACS_HLINE, 52); - //mvwaddch(win, 2, 53, ACS_RTEE); - - attron(COLOR_PAIR(S4C_CYAN)); - mvprintw(20, 2, "Arrows to move"); - mvprintw(21, 2, "(q to Exit)"); - attroff(COLOR_PAIR(S4C_CYAN)); - refresh(); - - int end_room = 0; - int check = -1; - - while (!end_room && (c = wgetch(my_menu_win)) != KEY_F(1)) { - switch (c) { - case KEY_DOWN: - menu_driver(my_menu, REQ_DOWN_ITEM); - break; - case KEY_UP: - menu_driver(my_menu, REQ_UP_ITEM); - break; - case KEY_NPAGE: - menu_driver(my_menu, REQ_SCR_DPAGE); - break; - case KEY_PPAGE: - menu_driver(my_menu, REQ_SCR_UPAGE); - break; - case 10: { // Enter - ITEM *cur; - - cur = current_item(my_menu); - sprintf(msg, "Picked %s.\n", item_name(cur)); - log_tag("debug_log.txt", "[ROADFORK]", msg); - if ((check = strcmp("Boss Room", item_name(cur))) == 0) { - *roadFork_value = BOSS; - end_room = 1; - } else if ((check = strcmp("Shop Room", item_name(cur)) == 0)) { - *roadFork_value = SHOP; - end_room = 1; - } else if ((check = - strcmp("Treasure Room", item_name(cur)) == 0)) { - *roadFork_value = TREASURE; - end_room = 1; - } else if ((check = strcmp("Enemies", item_name(cur)) == 0)) { - *roadFork_value = ENEMIES; - end_room = 1; - } else if ((check = strcmp("Roadfork", item_name(cur)) == 0)) { - *roadFork_value = ROADFORK; - end_room = 1; - } - pos_menu_cursor(my_menu); - refresh(); - }; - break; - } - wrefresh(my_menu_win); - } - /* Unpost and free all the memory taken up */ - unpost_menu(my_menu); - free_menu(my_menu); - for (int k = 0; k < n_choices; k++) { - free_item(my_items[k]); - } - endwin(); - - //FIXME - //Why are we relying on this? - return FIGHTRES_NO_DMG; -} - -/** - * Takes an integer seed and returns a Path pointer. - * The seed provided is used to set the random seed and initialise the path values. - * @see Path - * @see MAXLENGTH - * @see MAXLUCK - * @param seed An integer seed. - * @param kls The Koliseo used for allocation. - * @param current_saveslot The Saveslot used to init the Path. - * @return A Path pointer with stats. - */ -Path *randomise_path(int seed, Koliseo *kls, const char *path_to_savefile) -{ - char msg[200]; - sprintf(msg, "Prepping Path"); - kls_log(kls, "DEBUG", msg); - Path *p = (Path *) KLS_PUSH_TYPED(kls, Path, HR_Path, "Path", msg); - srand(seed); - sprintf(msg, "Prepping Saveslot"); - kls_log(kls, "DEBUG", msg); - sprintf(msg, "save_path: [%s]", path_to_savefile); - Saveslot *save = - (Saveslot *) KLS_PUSH_TYPED(kls, Saveslot, HR_Saveslot, "Saveslot", - msg); - sprintf(msg, "Seed: %i", seed); - strcpy(save->name, msg); - sprintf(msg, "%s", path_to_savefile); - strcpy(save->save_path, msg); - p->current_saveslot = save; - kls_log(kls, "DEBUG", - "Prepped Saveslot: path->current_saveslot->save_path == [%s]", - p->current_saveslot->save_path); - log_tag("debug_log.txt", "[SAVESLOT]", - "Prepped Saveslot: path->current_saveslot->save_path == [%s]", - p->current_saveslot->save_path); - - switch (GAMEMODE) { - case Standard: { - p->length = (rand() % MAXLENGTH) + 1; - p->luck = (rand() % MAXLUCK) + 1; - p->prize = 15 / p->luck * (rand() % 150) + 500; - } - break; - case Story: { - p->length = 41; - p->luck = (rand() % MAXLUCK) + 1; - p->prize = 15 / p->luck * (rand() % 150) + 500; - } - break; - case Rogue: { - p->length = 1; - p->luck = (rand() % MAXLUCK) + 1; - p->prize = 15 / p->luck * (rand() % 150) + 500; - } - break; - default: { - fprintf(stderr, "\nUnexpected GAMEMODE value %i.\n", GAMEMODE); - exit(EXIT_FAILURE); - } - } - return p; -} - -/** - * Takes a integer and a string array (possibly from main). - * Initialises a Path pointer and a Fighter pointer, before looping for each oom in path length by calling the correct room function. - * If all the rooms are cleared, prints a victory message and exits the program. - * Then getParams() is called to initialise a Fighter pointer's name and class fields. - * Takes an integer seed and frees path pointer. - * Notably, player pointer is not freed here. - * @see Path - * @see Fighter - * @see getParams() - * @see initPlayerStats() - * @see room() - * @see handleStats() - * @see printStats() - * @param argc The number of argv values + 1 (0 is program name?). - * @param argv Array of strings with argc - 1 values. - */ -void gameloop(int argc, char **argv) -{ - - char *whoami; // This will reference argv[0] at basename, it's the same string in memory, just starting later - char path_to_kls_debug_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Truncate "debug_log.txt" - sprintf(path_to_kls_debug_file, "%s/%s", static_path, "kls_debug_log.txt"); - KLS_Conf default_kls_conf = { - .kls_autoset_regions = 1, - .kls_autoset_temp_regions = 1, - .kls_verbose_lvl = 1, - .kls_log_filepath = path_to_kls_debug_file, - .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, - .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, - }; - KLS_Conf temporary_kls_conf = { - .kls_autoset_regions = 1, - .kls_autoset_temp_regions = 1, - .kls_verbose_lvl = 0, - .kls_log_fp = stderr, - .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, - .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, - }; - - do { - //Init default_kls - default_kls = kls_new_conf(KLS_DEFAULT_SIZE * 16, default_kls_conf); - temporary_kls = kls_new_conf(KLS_DEFAULT_SIZE * 32, temporary_kls_conf); - -#ifndef _WIN32 - (whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]); -#else - (whoami = strrchr(argv[0], '\\')) ? ++whoami : (whoami = argv[0]); -#endif - - char *kls_progname = - (char *)KLS_PUSH_ARR_TYPED(default_kls, char *, sizeof(whoami), - KLS_None, "progname", whoami); - strcpy(kls_progname, whoami); - -#ifndef HELAPORDO_DEBUG_LOG -#else - FILE *debug_file = NULL; - FILE *OPS_debug_file = NULL; -#endif - // Parse command-line options - int option; - loadInfo *load_info = - (loadInfo *) KLS_PUSH_TYPED(default_kls, loadInfo, HR_loadInfo, - "loadInfo", "loadInfo"); - - load_info->is_new_game = 1; //By default we do a new game - load_info->enemy_index = -1; - load_info->total_foes = -1; - load_info->save_type = -1; - int loaded_roomtotalenemies = -1; - int loaded_roomindex = -1; - load_info->ptr_to_roomtotalenemies = &loaded_roomtotalenemies; - load_info->ptr_to_roomindex = &loaded_roomindex; - - while ((option = getopt(argc, argv, "f:r:E:tTGRXQLlvdhsaV")) != -1) { - switch (option) { - case 'd': { -#ifndef HELAPORDO_DEBUG_ACCESS -#else - G_DEBUG_ON += 1; - G_LOG_ON = 1; -#endif - } - break; - case 'r': { - G_DEBUG_ROOMTYPE_ON += 1; - G_DEBUG_ROOMTYPE_ARG = optarg; - } - break; - case 'E': { - G_DEBUG_ENEMYTYPE_ON += 1; - G_DEBUG_ENEMYTYPE_ARG = optarg; - } - break; - case 'L': { - G_LOG_ON = 1; - } - break; - case 'l': { - load_info->is_new_game = 0; - } - break; - case 'G': { - G_GODMODE_ON = 1; - } - break; - case 'Q': { - G_FASTQUIT_ON = 1; - } - break; - case 'X': { - G_EXPERIMENTAL_ON = 1; - } - break; - case 'a': { - GS_AUTOSAVE_ON = 0; - } - break; - case 's': { - GAMEMODE = Story; - } - break; - case 'R': { - GAMEMODE = Rogue; - } - break; - case 'f': { - //filename = optarg; - } - break; - case 'h': { - usage(whoami); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 'T': { - G_DOTUTORIAL_ON = 1; - handleTutorial(); - usage(whoami); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 't': { - //Test all colors - printFormattedVersion(whoami); - printf("Using:\n"); - printf(" \'animate\' :\n s4c/animate.h "); - S4C_ECHOVERSION(); - printf("[DEBUG] Testing terminal color capabilities.\n"); - napms(200); - display_colorpairs(); - napms(200); - WINDOW *test_win; - initscr(); - start_color(); - for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { - init_s4c_color_pair(&palette[i], 9 + i); - } - clear(); - refresh(); - cbreak(); - noecho(); - test_win = newwin(9, 7, 1, 1); - keypad(test_win, TRUE); - box(test_win, 0, 0); - - refresh(); - - test_game_color_pairs(test_win, 5); - - napms(200); - delwin(test_win); - endwin(); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 'V': { - printf("helapordo build: %s\n", helapordo_build_string); - hlpd_dbg_features(); - printf(" using: s4c-animate v%s\n", S4C_ANIMATE_VERSION); - s4c_dbg_features(); - printf(" using: koliseo v%s\n", string_koliseo_version()); - kls_dbg_features(); - printf(" using: ncurses v%s\n", NCURSES_VERSION); -#ifdef ANVIL__helapordo__ -#ifndef INVIL__helapordo__HEADER__ - printf(" Built with: amboso v%s\n", - ANVIL__API_LEVEL__STRING); -#else - printf(" Built with: invil v%s\n", - INVIL__VERSION__STRING); - printf("Version Info: %.8s\n", - get_ANVIL__VERSION__DESC__()); - printf("Last commit: %s", get_INVIL__COMMIT__DESC__()); - const char* anvil_date = get_ANVIL__VERSION__DATE__(); - char* anvil_date_end; -#ifndef _WIN32 - time_t anvil_build_time = strtol(anvil_date, &anvil_date_end, 10); -#else - time_t anvil_build_time = strtoll(anvil_date, &anvil_date_end, 10); -#endif //_WIN32 - - if (anvil_date_end == anvil_date) { - //TODO: error - } else { - char build_time_buff[20] = {0}; - struct tm* build_time_tm = localtime(&anvil_build_time); - - if (build_time_tm == NULL) { - //TODO: error - } else { - strftime(build_time_buff, 20, "%Y-%m-%d %H:%M:%S", build_time_tm); - printf("\nDate: %s\n", build_time_buff); - } - } - const char* headergen_date = get_INVIL__HEADERGEN__TIME__(); - char* headergen_date_end; -#ifndef _WIN32 - time_t headergen_time = strtol(headergen_date, &headergen_date_end, 10); -#else - time_t headergen_time = strtoll(headergen_date, &headergen_date_end, 10); -#endif //_WIN32 - - if (headergen_date_end == headergen_date) { - //TODO: error - } else { - char headergen_time_buff[20] = {0}; - struct tm* headergen_time_tm = localtime(&headergen_time); - - if (headergen_time_tm == NULL) { - //TODO: error - } else { - strftime(headergen_time_buff, 20, "%Y-%m-%d %H:%M:%S", headergen_time_tm); - printf("Anvil Gen Date: %s\n", headergen_time_buff); - } - } -#endif // INVIL__helapordo__HEADER__ -#else - printf(" Built without anvil\n"); -#endif // ANVIL__helapordo__ - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 'v': { - printVersion(); - /* - printf("Using:\n"); - printf(" \'animate\' :\n s4c/animate.h "); - S4C_ECHOVERSION(); - printf("\n \'anvil\' :\n"); - int status = system("echo \" $( anvil -vv 2>/dev/null ) \""); - int exitcode = status / 256; - if (exitcode != 0) { - printf("\033[1;31m[DEBUG]\e[0m \"anvil -vv\" failed.\n\n Maybe amboso is not installed globally?\n"); - exit(exitcode); - } - exit(exitcode); - */ - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case '?': { - fprintf(stderr, - "Invalid option: %c\n Check your arguments.\n", - option); - usage(whoami); - // Handle invalid options - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - default: { - // Should never get here - fprintf(stderr, "Invalid option: %c\n, bad usage.\n", - option); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } - } - -#ifndef HELAPORDO_DEBUG_LOG -#else - // Open log file if log flag is set and reset it - if (G_LOG_ON == 1) { - char path_to_debug_file[600]; - char path_to_OPS_debug_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Truncate "debug_log.txt" - sprintf(path_to_debug_file, "%s/%s", static_path, "debug_log.txt"); - debug_file = fopen(path_to_debug_file, "w"); - if (!debug_file) { - endwin(); //TODO: Can/should we check if we have to do this only in curses mode? - fprintf(stderr, - "[ERROR] Can't open debug logfile (%s/debug_log.txt).\n", - static_path); - exit(EXIT_FAILURE); - } - fprintf(debug_file, "[DEBUGLOG] --New game-- \n"); - if (NCURSES_VERSION_MAJOR < EXPECTED_NCURSES_VERSION_MAJOR - && NCURSES_VERSION_MINOR < EXPECTED_NCURSES_VERSION_MINOR - && NCURSES_VERSION_PATCH < EXPECTED_NCURSES_VERSION_PATCH) { - fprintf(debug_file, - "[WARN] ncurses version is lower than expected {%s: %i.%i.%i} < {%i.%i.%i}\n", - NCURSES_VERSION, NCURSES_VERSION_MAJOR, - NCURSES_VERSION_MINOR, NCURSES_VERSION_PATCH, - EXPECTED_NCURSES_VERSION_MAJOR, - EXPECTED_NCURSES_VERSION_MINOR, - EXPECTED_NCURSES_VERSION_PATCH); - } - fprintf(debug_file, "[DEBUG] --Default kls debug info:-- \n"); - print_kls_2file(debug_file, default_kls); - fprintf(debug_file, "[DEBUG] --Temporary kls debug info:-- \n"); - print_kls_2file(debug_file, temporary_kls); - fprintf(debug_file, - "[DEBUG] --Closing header for new game.-- \n"); - fclose(debug_file); - - //Lay debug info - log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", - G_DEBUG_ON); - log_tag("debug_log.txt", "[DEBUG]", "kls_progname == (%s)", - kls_progname); - log_tag("debug_log.txt", "[DEBUG]", "G_LOG_ON == (%i)", G_LOG_ON); - log_tag("debug_log.txt", "[DEBUG]", "small DEBUG FLAG ASSERTED"); - log_tag("debug_log.txt", "[DEBUG]", - "[Current position in default_kls] [pos: %li]\n", - kls_get_pos(default_kls)); - - //Truncate OPS_LOGFILE - sprintf(path_to_OPS_debug_file, "%s/%s", static_path, OPS_LOGFILE); - OPS_debug_file = fopen(path_to_OPS_debug_file, "w"); - if (!OPS_debug_file) { - endwin(); //TODO: Can/should we check if we have to do this only in curses mode? - fprintf(stderr, "[ERROR] Can't open OPS logfile (%s/%s).\n", - static_path, OPS_LOGFILE); - exit(EXIT_FAILURE); - } - fprintf(OPS_debug_file, "[OPLOG] --New game-- \n"); - fclose(OPS_debug_file); - log_tag("debug_log.txt", "[DEBUG]", "Truncated [%s]", OPS_LOGFILE); - } -#endif - - if (G_DEBUG_ENEMYTYPE_ON == 1) { - log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ENEMYTYPE_ON == (%i)", - G_DEBUG_ENEMYTYPE_ON); - log_tag("debug_log.txt", "[DEBUG]", "ENEMY DEBUG FLAG ASSERTED"); - if ((G_DEBUG_ON > 0)) { - G_DEBUG_ON += 1; - log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", - G_DEBUG_ON); - log_tag("debug_log.txt", "[DEBUG]", "Forcing enemy type: (%s)", - G_DEBUG_ENEMYTYPE_ARG); - int setenemy_debug = 0; - for (int ec = 0; ec < ENEMYCLASSESMAX && (setenemy_debug == 0); - ec++) { - log_tag("debug_log.txt", "[DEBUG]", - "Checking optarg for -E: (%s)", - stringFromEClass(ec)); - if ((strcmp(G_DEBUG_ENEMYTYPE_ARG, stringFromEClass(ec)) == - 0)) { - log_tag("debug_log.txt", "[DEBUG]", - "Match on optarg (%s), setting G_DEBUG_ENEMYTYPE to (%i).", - stringFromEClass(ec), ec); - G_DEBUG_ENEMYTYPE = ec; - setenemy_debug = 1; - } - } - if (setenemy_debug == 0) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid optarg for -E flag: {%s}.\n", - G_DEBUG_ENEMYTYPE_ARG); - fprintf(stderr, - "[ERROR] Incorrect -E \"enemyType\" arg: {%s}.\n", - G_DEBUG_ENEMYTYPE_ARG); - fprintf(stderr, "[ERROR] Run \"%s -h\" for help.\n", - kls_progname); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - }; - } - } - if (G_DEBUG_ROOMTYPE_ON == 1) { - log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ROOMTYPE_ON == (%i)", - G_DEBUG_ROOMTYPE_ON); - log_tag("debug_log.txt", "[DEBUG]", "ROOM DEBUG FLAG ASSERTED"); - if ((G_DEBUG_ON > 0)) { - G_DEBUG_ON += 1; - log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", - G_DEBUG_ON); - log_tag("debug_log.txt", "[DEBUG]", - "Forcing room type: optarg was (%s)", - G_DEBUG_ROOMTYPE_ARG); - int setroom_debug = 0; - for (int rc = 0; - (rc < ROOM_CLASS_MAX + 1) && (setroom_debug == 0); rc++) { - log_tag("debug_log.txt", "[DEBUG]", - "Checking optarg (%s) for -R: (%s)", optarg, - stringFromRoom(rc)); - if ((strcmp(G_DEBUG_ROOMTYPE_ARG, stringFromRoom(rc)) == 0)) { - log_tag("debug_log.txt", "[DEBUG]", - "Match on optarg (%s), setting G_DEBUG_ROOMTYPE to (%i).", - stringFromRoom(rc), rc); - G_DEBUG_ROOMTYPE = rc; - setroom_debug = 1; - } - } - if (setroom_debug == 0) { - log_tag("debug_log.txt", "[ERROR]", - "Invalid optarg for -R flag: {%s}.", - G_DEBUG_ROOMTYPE_ARG); - fprintf(stderr, - "[ERROR] Incorrect -R \"roomType\" arg: {%s}.\n", - G_DEBUG_ROOMTYPE_ARG); - fprintf(stderr, "[ERROR] Run \"%s -h\" for help.\n", - kls_progname); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - }; - } - - } - log_tag("debug_log.txt", "[DEBUG]", "Done getopt."); - - // Clear screen and print title, wait for user to press enter - int clearres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() system(\"clear\") res was (%i)", clearres); - printTitle(); - char c; - yellow(); - printf("\n\n\n\n\t\t\tPRESS ENTER TO START\n\n"); - white(); - - if (G_DEBUG_ON) { - lightCyan(); - printf("\t\t\t\t\t\t\t\tDEBUG ON\n"); - white(); - } - printf("\t\t\t\t\t\t\tncurses build\n"); - printf("\t\t\t\t\t\t"); - printFormattedVersion(whoami); - int scanfres = scanf("%c", &c); - log_tag("debug_log.txt", "[DEBUG]", "gameloop() scanf() res was (%i)", - scanfres); - - // Parse positional arguments - //for (int i = optind; i < argc; i++) { - // Handle positional arguments - Path *path = NULL; - Fighter *player = NULL; - - clock_t start_time = clock(), diff_time; - - // Prepare the fighter frames - char fighter_sprites[CLASSESMAX + 1][MAXFRAMES][MAXROWS][MAXCOLS]; - - char static_path[500]; - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - /* - * Legacy code for loading animations from an s4c-file. - char fighter_filename[600]; - FILE* fighter_sprite_file; - */ - for (int i = 0; i < CLASSESMAX + 1; i++) { - - int n_load_frames = 60; - int n_load_rows = 17; - int n_load_cols = 17; - - switch (i) { - case Knight: { - s4c_copy_animation(knight_tapis, fighter_sprites[i], - n_load_frames, n_load_rows, n_load_cols); - } - break; - case Mage: { - s4c_copy_animation(mage_spark, fighter_sprites[i], - n_load_frames, n_load_rows, n_load_cols); - } - break; - case Archer: { - s4c_copy_animation(archer_drop, fighter_sprites[i], - n_load_frames, n_load_rows, n_load_cols); - } - break; - case Assassin: { - s4c_copy_animation(assassin_poof, fighter_sprites[i], - n_load_frames, n_load_rows, n_load_cols); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected fighterclass index while loading animation for class (%i): [%s]", - i, stringFromClass(i)); - exit(EXIT_FAILURE); - } - break; - } - - /* - * Legacy code for loading animations from an s4c-file - fighter_sprite_file = fopen(fighter_filename, "r"); - if (!fighter_sprite_file) { - fprintf(stderr,"Error opening animation file at (%s).\n",fighter_filename); - fprintf(stderr,"Static path was (%s).\n",static_path); - exit(EXIT_FAILURE); - } - int fighter_loadCheck = load_sprites(fighter_sprites[i], fighter_sprite_file, 17, 17); - sprintf(load_msg,"Loaded animation for %s, load result was %i.", stringFromClass(i), fighter_loadCheck); - log_tag("debug_log.txt","[PREP]",load_msg); - */ - - log_tag("debug_log.txt", "[PREP]", - "Copied animation from default matrix vector for: [%s] with dimensions: [%i][%i][%i].", - stringFromClass(i), n_load_frames, n_load_rows, - n_load_cols); - - //Massive log of all loaded lines - /* - for (int k=0; k= HLPD_MIN_SCREEN_ROWS && screen_cols >= HLPD_MIN_SCREEN_COLS) { - screen_is_big_enough = true; - clear(); - refresh(); - } else if (screen_rows >= HLPD_DEFAULT_SCREEN_ROWS && screen_cols >= HLPD_MIN_SCREEN_COLS) { - mvwprintw(screen, 0, 0, "%s", "Current screen is too small to see battle notifications."); - mvwprintw(screen, 1, 0, "%s", "Enlarge vertically to fit it."); - refresh(); - } else { - mvwprintw(screen, 0, 0, "%s", "Screen too small, please resize."); - refresh(); - } - } - GameScreen* gamescreen = (GameScreen*) KLS_PUSH_TYPED(default_kls, GameScreen, HR_Gamescreen, "Main GameScreen", "Wrap stdscr"); - gamescreen->colors = COLORS; - gamescreen->color_pairs = COLOR_PAIRS; - gamescreen->cols = COLS; - gamescreen->rows = LINES; - gamescreen->escape_delay = ESCDELAY; - gamescreen->tabsize = TABSIZE; - - gamescreen->win = screen; - ITEM **savepick_items; - MENU *savepick_menu; - WINDOW *savepick_menu_win; - WINDOW *savepick_side_win; - char current_save_path[300]; //Will hold picked path - - Koliseo_Temp *savepick_kls = kls_temp_start(temporary_kls); - - //Declare turnOP_args - Room *fakeroom = NULL; - Enemy *fakeenemy = NULL; - Boss *fakeboss = NULL; - FILE *fakesavefile = NULL; - WINDOW *fakenotifywin = NULL; - Gamestate *fakegmst = NULL; - foeTurnOption_OP fake_foe_op = FOE_OP_INVALID; - skillType fake_skill = -1; - turnOP_args *savepick_turn_args = - init_turnOP_args(fakegmst, player, path, fakeroom, load_info, - fakeenemy, fakeboss, fakesavefile, fakenotifywin, - savepick_kls, fake_foe_op, fake_skill); - char *savepick_choices[] = { - "New game", - "Load save", - "Tutorial", - "Quit", - (char *)NULL, - }; - int savepick_n_choices = ARRAY_SIZE(savepick_choices); - //FIXME: remove magic numbers - turnOption savepick_choice = 999; - - /* Create menu items */ - savepick_items = (ITEM **) calloc(savepick_n_choices, sizeof(ITEM *)); - for (int i = 0; i < savepick_n_choices; i++) { - savepick_items[i] = - new_item(savepick_choices[i], savepick_choices[i]); - } - savepick_items[savepick_n_choices - 1] = (ITEM *) NULL; - - /* Create menu */ - savepick_menu = new_menu((ITEM **) savepick_items); - - /* Set description off */ - menu_opts_off(savepick_menu, O_SHOWDESC); - - /* Create the window to be associated with the menu */ - savepick_menu_win = newwin(11, 16, 5, 35); - keypad(savepick_menu_win, TRUE); - - /* Set main window and sub window */ - set_menu_win(savepick_menu, savepick_menu_win); - set_menu_sub(savepick_menu, derwin(savepick_menu_win, 4, 14, 4, 1)); - set_menu_format(savepick_menu, 4, 1); - - /* Set menu mark to the string " > " */ - set_menu_mark(savepick_menu, " > "); - - /* Print a border around main menu window */ - box(savepick_menu_win, 0, 0); - print_label(savepick_menu_win, 1, 0, 16, "Select save", COLOR_PAIR(6)); - mvwaddch(savepick_menu_win, 2, 0, ACS_LTEE); - mvwhline(savepick_menu_win, 2, 1, ACS_HLINE, 16); - mvwaddch(savepick_menu_win, 2, 15, ACS_RTEE); - - /* Post the menu */ - post_menu(savepick_menu); - wrefresh(savepick_menu_win); - - //Handle side window for welcome info - savepick_side_win = newwin(12, 32, 2, 2); - scrollok(savepick_side_win, TRUE); - wprintw(savepick_side_win, " \nhelapordo"); - wprintw(savepick_side_win, " \n build: %s", helapordo_build_string); - wprintw(savepick_side_win, " \n using: s4c-animate v%s", - S4C_ANIMATE_VERSION); - wprintw(savepick_side_win, " \n using: koliseo v%s", - KOLISEO_API_VERSION_STRING); - wprintw(savepick_side_win, " \n using: ncurses v%s", NCURSES_VERSION); -#ifdef ANVIL__helapordo__ -#ifndef INVIL__helapordo__HEADER__ - wprintw(savepick_side_win, " \nBuilt with: amboso v%s", - ANVIL__API_LEVEL__STRING); -#else - wprintw(savepick_side_win, " \nBuilt with: invil v%s", - INVIL__VERSION__STRING); - wprintw(savepick_side_win, " \nVersion Info: %.8s", - get_ANVIL__VERSION__DESC__()); - const char* anvil_date = get_ANVIL__VERSION__DATE__(); - char* anvil_date_end; -#ifndef _WIN32 - time_t anvil_build_time = strtol(anvil_date, &anvil_date_end, 10); -#else - time_t anvil_build_time = strtoll(anvil_date, &anvil_date_end, 10); -#endif //_WIN32 - - if (anvil_date_end == anvil_date) { - log_tag("debug_log.txt", "ERROR", "anvil date was invalid"); - } else { - char build_time_buff[20] = {0}; - struct tm* build_time_tm = localtime(&anvil_build_time); - - if (build_time_tm == NULL) { - log_tag("debug_log.txt", "ERROR", "localtime() failed"); - } else { - strftime(build_time_buff, 20, "%Y-%m-%d %H:%M:%S", build_time_tm); - wprintw(savepick_side_win, " \nDate: %s", build_time_buff); - } - } -#endif // INVIL__helapordo__HEADER__ -#else - wprintw(savepick_side_win, " \nBuilt without anvil"); -#endif // ANVIL__helapordo__ - //wprintw(savepick_side_win," \n %s",get_ANVIL__VERSION__DESC__()); - wrefresh(savepick_side_win); - refresh(); - - int savepick_picked = 0; - - /* - //We set the colors to use s4c's palette file... - FILE* palette_file; - char path_to_palette[600]; - char palette_name[50] = "palette.gpl"; - */ - int pickchar = -1; - - /* - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - sprintf(path_to_palette,"%s/%s",static_path,palette_name); - - palette_file = fopen(path_to_palette, "r"); - - init_s4c_color_pairs(palette_file); - */ - - for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { - init_s4c_color_pair(&palette[i], 9 + i); - } - log_tag("debug_log.txt","[DEBUG]","%s(): Updating gamescreen->colors and colorpairs after init_s4c_color_pair() loop.", __func__); - gamescreen->colors = COLORS; - gamescreen->color_pairs = COLOR_PAIRS; - - while (!savepick_picked - && (pickchar = wgetch(savepick_menu_win)) != KEY_F(1)) { - switch (pickchar) { - case KEY_DOWN: { - menu_driver(savepick_menu, REQ_DOWN_ITEM); - } - break; - case KEY_UP: { - menu_driver(savepick_menu, REQ_UP_ITEM); - } - break; - case KEY_LEFT: { /*Left option pick */ - ITEM *cur; - cur = current_item(savepick_menu); - savepick_choice = getTurnChoice((char *)item_name(cur)); - log_tag("debug_log.txt", "[DEBUG]", - "Left on choice: [ %s ] value (%i)", item_name(cur), - savepick_choice); - if (savepick_choice == NEW_GAME) { - log_tag("debug_log.txt", "[DEBUG]", - "Should do something"); - } - } - break; - case KEY_RIGHT: { /*Right option pick */ - ITEM *cur; - cur = current_item(savepick_menu); - savepick_choice = getTurnChoice((char *)item_name(cur)); - log_tag("debug_log.txt", "[DEBUG]", - "Right on choice: [ %s ] value (%i)", - item_name(cur), savepick_choice); - if (savepick_choice == NEW_GAME) { - log_tag("debug_log.txt", "[DEBUG]", - "Should do something"); - } - } - break; - case KEY_NPAGE: { - menu_driver(savepick_menu, REQ_SCR_DPAGE); - } - break; - case KEY_PPAGE: { - menu_driver(savepick_menu, REQ_SCR_UPAGE); - } - break; - case 10: { /* Enter */ - savepick_picked = 1; - ITEM *cur; - - //move(18,47); - //clrtoeol(); - cur = current_item(savepick_menu); - //mvprintw(18, 47, "Item selected is : %s", item_name(cur)); - savepick_choice = getTurnChoice((char *)item_name(cur)); - pos_menu_cursor(savepick_menu); - refresh(); - } - break; - case 'q': { - log_tag("debug_log.txt", "[DEBUG]", - "Player used q to quit from savepick menu."); - //TODO: take some variable to disable quick quitting with q - savepick_picked = 1; - savepick_choice = getTurnChoice("Quit"); - pos_menu_cursor(savepick_menu); - refresh(); - } - break; - default: { - break; - } - } - wrefresh(savepick_menu_win); - if (savepick_choice == NEW_GAME) { - int picked_saveslot_index = get_saveslot_index(); - log_tag("debug_log.txt", "[DEBUG]", - "Saveslot index picked: [%i]", picked_saveslot_index); - sprintf(current_save_path, "%s", default_saveslots[picked_saveslot_index].save_path); //Update saveslot_path value - //TODO - //Get picked_slot with a curses menu. - //int picked_slot = handle_pickSave(); - //sprintf(current_save_path,default_saveslots[picked_slot].save_path); - //TODO - //By default we expect the user to press new game, no action needed? - log_tag("debug_log.txt", "[DEBUG]", - "Running new game from savepick menu"); - turnOP(OP_NEW_GAME, savepick_turn_args, default_kls, - savepick_kls); - } else if (savepick_choice == LOAD_GAME) { - int picked_saveslot_index = get_saveslot_index(); - log_tag("debug_log.txt", "[DEBUG]", - "Saveslot index picked: [%i]", picked_saveslot_index); - sprintf(current_save_path, "%s", default_saveslots[picked_saveslot_index].save_path); //Update saveslot_path value - //TODO - //Get picked_slot with a curses menu. - //int picked_slot = handle_pickSave(); - //sprintf(current_save_path,default_saveslots[picked_slot].save_path); - //ATM we expect a single save. - //Setting this to 0 is the only thing we expect here, the actual load is done later. - load_info->is_new_game = 0; - log_tag("debug_log.txt", "[DEBUG]", - "Set load value: load_info->is_new_game == (%i)", - load_info->is_new_game); - turnOP(OP_LOAD_GAME, savepick_turn_args, default_kls, - savepick_kls); - //TODO - //Select which game to load, by preparing the necessary handles to code below (correct savefile/name, for now) - } else if (savepick_choice == QUIT) { - //TODO - //We can quit, I guess. - log_tag("debug_log.txt", "[DEBUG]", - "Savepick menu: doing exit(%i)", EXIT_SUCCESS); - // Unpost menu and free all the memory taken up - unpost_menu(savepick_menu); - free_menu(savepick_menu); - log_tag("debug_log.txt", "[FREE]", "Freed savepick menu"); - for (int k = 0; k < savepick_n_choices; k++) { - free_item(savepick_items[k]); - log_tag("debug_log.txt", "[FREE]", - "Freed %i savepick menu item", k); - } - - delwin(savepick_menu_win); - endwin(); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } else if (savepick_choice == TUTORIAL) { - log_tag("debug_log.txt", "[DEBUG]", "Doing tutorial."); - handleTutorial(); - exit(EXIT_SUCCESS); - } - } //End while !savepick_picked - - //Free turnOP_args - //free(savepick_turn_args); - - // Unpost menu and free all the memory taken up - unpost_menu(savepick_menu); - free_menu(savepick_menu); - log_tag("debug_log.txt", "[FREE]", "Freed savepick menu"); - for (int k = 0; k < savepick_n_choices; k++) { - free_item(savepick_items[k]); - log_tag("debug_log.txt", "[FREE]", "Freed %i savepick menu item", - k); - } - - delwin(savepick_menu_win); - endwin(); - log_tag("debug_log.txt", "[DEBUG]", - "Ended window mode for savepick menu"); - - kls_temp_end(savepick_kls); - - //Flush the terminal - int clrres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() system(\"clear\") after savepick res was (%i)", - clrres); - - //By now, we expect load_info->is_new_game to be set to 0 or 1. - log_tag("debug_log.txt", "[DEBUG]", - " Checking is_new_game: load_info->is_new_game == (%i)", - load_info->is_new_game); - - Koliseo_Temp *gamestate_kls = kls_temp_start(temporary_kls); - - if (load_info->is_new_game) { // We prepare path and fighter - path = randomise_path(rand(), default_kls, current_save_path); - path->loreCounter = -1; - - kls_log(default_kls, "DEBUG", "Prepping Fighter"); - player = - (Fighter *) KLS_PUSH_TYPED(default_kls, Fighter, HR_Fighter, - "Fighter", "Fighter"); - - int optTot = optind; - - getParams(argc, argv, player, path, optTot, default_kls); - initPlayerStats(player, path, default_kls); - } else { //Handle loading of gamestate - - //Declar turnOP_args - Room *fakeroom = NULL; - Enemy *fakeenemy = NULL; - Boss *fakeboss = NULL; - FILE *fakesavefile = NULL; - WINDOW *fakenotifywin = NULL; - Gamestate *fakegmst = NULL; - foeTurnOption_OP fake_foe_op = FOE_OP_INVALID; - skillType fake_skill = -1; - turnOP_args *loading_room_turn_args = - init_turnOP_args(fakegmst, player, path, fakeroom, load_info, - fakeenemy, fakeboss, fakesavefile, - fakenotifywin, gamestate_kls, fake_foe_op, - fake_skill); - FILE *save_file; - char path_to_savefile[1000]; - char static_path[500]; - char savefile_name[300]; - - //Copy current_save_path - sprintf(savefile_name, "%s", current_save_path); - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - sprintf(path_to_savefile, "%s/%s", static_path, savefile_name); - - save_file = fopen(path_to_savefile, "r"); - if (!save_file) { - //User error - fprintf(stderr, - "[ERROR] Can't open savefile for loading game.\n"); - fprintf(stderr, "[ERROR] Expected at path [%s].\n", - path_to_savefile); - //Debug error - log_tag("debug_log.txt", "[ERROR]", - "Could not load savefile at (%s)", path_to_savefile); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - //Update loading_room_turn_args->save_file pointer - loading_room_turn_args->save_file = save_file; - log_tag("debug_log.txt", "[TURNOP]", - "Assigned loading_room_turn_args->save_file: path [%s]", - path_to_savefile); - - //Read save type - // - saveType loaded_save_type = -1; - loaded_save_type = read_saveType(save_file); - log_tag("debug_log.txt", "[TURNOP]", "Read saveType, was [%s].", - stringFrom_saveType(loaded_save_type)); - - if (loaded_save_type == -1) { - log_tag("debug_log.txt", "[ERROR]", - "Failed setting loaded_save_type. Quitting."); - fprintf(stderr, "[ERROR] Failed setting a save type."); - - exit(EXIT_FAILURE); - } - - load_info->save_type = loaded_save_type; - - log_tag("debug_log.txt", "[TURNOP]", - "Assigned load_info->save_type: [%s]", - stringFrom_saveType(load_info->save_type)); - - path = randomise_path(rand(), default_kls, current_save_path); - kls_log(default_kls, "DEBUG", "Prepping Loady Fighter"); - player = - (Fighter *) KLS_PUSH_TYPED(default_kls, Fighter, HR_Fighter, - "Fighter", "Loady Fighter"); - player->class = Knight; - - strcpy(player->name, "Loady"); - - //Update loading_room_turn_args->actor pointer - loading_room_turn_args->actor = player; - log_tag("debug_log.txt", "[TURNOP]", - "Assigned Fighter [%s]. loading_room_turn_args->actor->name: [%s]", - player->name, loading_room_turn_args->actor->name); - - kls_log(default_kls, "DEBUG", "Prepping Loady Wincon"); - Wincon *w = - (Wincon *) KLS_PUSH_TYPED(default_kls, Wincon, HR_Wincon, - "Wincon", "Loady Wincon"); - w->class = FULL_PATH; - initWincon(w, path, w->class); - initPlayerStats(player, path, default_kls); - path->win_condition = w; - - if (load_info->save_type == ENEMIES_SAVE) { - - kls_log(default_kls, "DEBUG", "Prepping Loady Enemy"); - load_info->loaded_enemy = - (Enemy *) KLS_PUSH_TYPED(default_kls, Enemy, HR_Enemy, - "Enemy", "Loaded Enemy"); - //FIXME: the structs related to loaded enemy are not loaded on default_kls - prepareRoomEnemy(load_info->loaded_enemy, 1, 3, 1, - gamestate_kls); - - //Update loading_room_turn_args->enemy pointer - loading_room_turn_args->enemy = load_info->loaded_enemy; - log_tag("debug_log.txt", "[TURNOP]", - "Assigned load_info->loaded_enemy->class == [%s]. loading_room_turn_args->loaded_enemy->class == [%s]", - stringFromEClass(load_info->loaded_enemy->class), - stringFromEClass(loading_room_turn_args->enemy->class)); - } - //Update loading_room_turn_args->path pointer - loading_room_turn_args->path = path; - log_tag("debug_log.txt", "[TURNOP]", - "Assigned loading_room_turn_args->path == [path] (len %i)", - path->length); - - switch (load_info->save_type) { - case ENEMIES_SAVE: { - log_tag("debug_log.txt", "[TURNOP]", - "Doing OP_LOAD_ENEMYROOM."); - //int* loadinfo_totfoes = &(load_info->total_foes); - //FIXME: the structs related to loaded enemy are not loaded on default_kls - OP_res load_op_result = - turnOP(OP_LOAD_ENEMYROOM, loading_room_turn_args, - default_kls, gamestate_kls); - log_tag("debug_log.txt", "[TURNOP]", - "OP_LOAD_ENEMYROOM: result was [%s].", - stringFrom_OP_res(load_op_result)); - log_tag("debug_log.txt", "[FREE]", - "Freed loading_room_turn_args. Load result was [%s].", - stringFrom_OP_res(load_op_result)); - //free(loading_room_turn_args); - } - break; - case HOME_SAVE: { - log_tag("debug_log.txt", "[TURNOP]", - "Doing OP_LOAD_HOMEROOM."); - //int* loadinfo_totfoes = &(load_info->total_foes); - //FIXME: the structs related to loaded enemy are not loaded on default_kls - OP_res load_op_result = - turnOP(OP_LOAD_HOMEROOM, loading_room_turn_args, - default_kls, gamestate_kls); - log_tag("debug_log.txt", "[TURNOP]", - "OP_LOAD_HOMEROOM: result was [%s].", - stringFrom_OP_res(load_op_result)); - //log_tag("debug_log.txt","[FREE]","Freed loading_room_turn_args. Load result was [%s].",stringFrom_OP_res(load_op_result)); - load_info->done_loading = 1; - log_tag("debug_log.txt", "[PREP]", - "Set load_info->done_loading to 1."); - //free(loading_room_turn_args); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "gameloop(): Unexpected save type, value was (%i).", - (int)load_info->save_type); - exit(EXIT_FAILURE); - } - break; - } - - //e_death(loaded_enemy); - //death(player); - //exit(0); - } - - /* - * TODO - * Remove me - * Legacy code to load lores from a text file. - for (int i=0; i<5; i++) { - sprintf(msg,"Prepping lore (%i)",i); - kls_log("DEBUG",msg); - lore_strings[i] = (char*) KLS_PUSH_NAMED(default_kls, char, 300, "Lore", msg); - } - */ - - int *loreCounter = &(path->loreCounter); - log_tag("debug_log.txt", "[DEBUG]", "loreCounter == (%i)", - *loreCounter); - - if (GAMEMODE == Story) { - - /* - * TODO - * Remove me - * Legacy code to load lores from a text file. - int loreKind = 0; //rand() % LORES_MAX; - */ - - if (load_info->is_new_game) { - log_tag("debug_log.txt", "[FIXME]", - "loreCounter was (%i), setting it to 0.", *loreCounter); - *loreCounter = 0; //We must set the counter before going forward - //FIXME: - //loreCounter should not start from 0 again. - } - - /* - * TODO - *Remove me - *Legacy code for loading lores from a text file. - loadLore(lore_strings,loreKind); - */ - - } else { - log_tag("debug_log.txt", "[WARN]", - "GAMEMODE is not Story. Value was: (%i)", GAMEMODE); - } - - //Set consumables sprites - for (int i = 0; i < CONSUMABLESMAX + 1; i++) { - setConsumableSprite((Consumable *) player->consumablesBag[i]); - log_tag("debug_log.txt", "[PREP]", "Set sprite for %s", - stringFromConsumables(i)); - } - log_tag("debug_log.txt", "[DEBUG-PREP]", - "Done setting sprites for Consumables."); - //Set artifact sprites - for (int i = 0; i < ARTIFACTSMAX + 1; i++) { - setArtifactSprite(player->artifactsBag[i]); - log_tag("debug_log.txt", "[PREP]", "Set sprite for %s", - stringFromArtifacts(i)); - } - log_tag("debug_log.txt", "[PREP]", - "Done setting sprites for Artifacts."); - //Set base equips sprites... - for (int i = 0; i < EQUIPSMAX + 1; i++) { - setEquipSprite(&equips[i]); - log_tag("debug_log.txt", "[PREP]", "Set sprite for %s", - stringFromEquips(i)); - } - log_tag("debug_log.txt", "[PREP]", "Done setting sprites for Equips."); - - if (load_info->is_new_game) { - log_tag("debug_log.txt", "[PREP]", "New game from scratch."); - } else { - log_tag("debug_log.txt", "[PREP]", "New game from loading."); - } - log_tag("debug_log.txt", "[DEBUG]", "Name: %s", player->name); - log_tag("debug_log.txt", "[DEBUG]", "Class: %s", - stringFromClass(player->class)); - log_tag("debug_log.txt", "[DEBUG]", "Gamemode: %s", - stringFromGamemode(GAMEMODE)); - - //purple(); - //printStats(player); - //white(); - - int roomsDone = load_info->is_new_game ? 1 : loaded_roomindex; - OP_res res = OP_RES_NO_DMG; - int roadFork_value = -1; //0 may be used as a value, so - - Wincon *win_con = path->win_condition; - log_tag("debug_log.txt", "[DEBUG]", "Wincon: %s\n", - stringFromWinconClass(win_con->class)); - - //int refresh_artifact_wincon = 0; - if (load_info->save_type == ENEMIES_SAVE) { - load_info->done_loading = 0; - log_tag("debug_log.txt", "[DEBUG-PREP]", - "Set load_info->done_loading to 0."); - } - log_tag("debug_log.txt", "[DEBUG-PREP]", "Prepping done.\n"); - log_tag("debug_log.txt", "[DEBUG]", "Starting wincon loop.\n"); - - diff_time = clock() - start_time; - int time_spent = diff_time * 1000 / CLOCKS_PER_SEC; - //sprintf(msg,"[DEBUG] Prep took %0.7f seconds.\n",time_spent); - log_tag("debug_log.txt", "[DEBUG]", "Prep took %d s, %d ms.", - time_spent / 1000, time_spent % 1000); - - Gamestate *gamestate = - KLS_PUSH_TYPED(default_kls, Gamestate, HR_Gamestate, "Gamestate", - "Gamestate"); - init_Gamestate(gamestate, start_time, player->stats, path->win_condition, path, - player, GAMEMODE, gamescreen); - if (gamestate->gamemode == Rogue) { - //Note: different lifetime than gamestate - //NO. The update_gamestate call is instead performed later. - //Floor* current_floor = KLS_PUSH_T_TYPED(gamestate_kls,Floor,1,HR_Floor,"Floor","Init Curr floor"); - //NO. We pass NULL now. - update_Gamestate(gamestate, 1, HOME, roomsDone, -1, NULL); - } else { - update_Gamestate(gamestate, 1, HOME, roomsDone, -1, NULL); - } - log_tag("debug_log.txt", "[DEBUG]", "Initialised Gamestate."); - dbg_Gamestate(gamestate); - - if (GAMEMODE == Story || GAMEMODE == Standard) { - - //Loop till wincon reached - - while (win_con->current_val < win_con->target_val) { - - //Flush the terminal - int loop_clrres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() system(\"clear\") in wincon loop, res: (%i)", - loop_clrres); - - //Check if we have to update the wincon value - if (path->win_condition->class == ALL_ARTIFACTS) { - path->win_condition->current_val = - player->stats->artifactsfound; - //Are we forced to do one more room? - } - - int enemyTotal = -1; - roomClass room_type = -1; - - if (!(load_info->is_new_game) && !(load_info->done_loading) - && (load_info->save_type == ENEMIES_SAVE)) { - enemyTotal = loaded_roomtotalenemies; - } - - kls_log(temporary_kls, "DEBUG", - "Prepping Room for Story Gamemode. roomsDone=(%i)", - roomsDone); - Room *current_room = - (Room *) KLS_PUSH_T_TYPED(gamestate_kls, Room, HR_Room, - "Room", "Story Room"); - - current_room->index = roomsDone; - setRoomType(path, &roadFork_value, &room_type, roomsDone); - log_tag("debug_log.txt", "[ROOM]", - "Set Room #%i type: (%s)\n", roomsDone, - stringFromRoom(room_type)); - - initRoom(current_room, player, roomsDone, room_type, enemyTotal, - load_info, gamestate_kls); - log_tag("debug_log.txt", "[ROOM]", "Init Room #%i: (%s)\n", - roomsDone, stringFromRoom(room_type)); - - start_color(); - int colorCheck = has_colors(); - - if (colorCheck == FALSE) { - fprintf(stderr, "Terminal can't use colors, abort.\n"); - exit(S4C_ERR_TERMCOLOR); - } - - colorCheck = can_change_color(); - - if (colorCheck == FALSE) { - fprintf(stderr, "Terminal can't change colors, abort.\n"); - exit(S4C_ERR_TERMCHANGECOLOR); - } - for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { - init_s4c_color_pair(&palette[i], 9 + i); - } - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - //Check if we need to display a story prompt - if (GAMEMODE == Story && (roomsDone == 1 || room_type == BOSS)) { - displayLore(lore_strings, *loreCounter); - (*loreCounter)++; - } - //Play room animation - - /* - FILE* palette_file; - char path_to_palette[600]; - char static_path[500]; - char palette_name[50] = "palette.gpl" ; - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - sprintf(path_to_palette,"%s/%s",static_path,palette_name); - - palette_file = fopen(path_to_palette, "r"); - if (palette_file == NULL) { - fprintf(stderr, "Error: could not open palette file (%s/%s).\n",static_path, palette_name); - exit(EXIT_FAILURE); - } - */ - - WINDOW *door_win; - //initscr(); - clear(); - refresh(); - - int reps = 1; - int frametime = 27; - int num_frames = 60; - int frame_height = 22; - int frame_width = 22; - door_win = newwin(frame_height + 1, frame_width + 1, 0, 25); - - char door_sprites[MAXFRAMES][MAXROWS][MAXCOLS]; - - s4c_copy_animation(enter_door, door_sprites, num_frames, - frame_height, frame_width); - - log_tag("debug_log.txt", "[PREP]", - "Copied animation from matrix vector for enter_door with dimensions: [%i][%i][%i].", - num_frames, frame_height, frame_width); - - /* - * TODO - * Remove me - * Legacy code for loading animation from an s4c-file. - * - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - char door_file_path[600]; - - sprintf(door_file_path,"%s/animations/enter_door.txt",static_path); - - FILE* door_file = fopen(door_file_path,"r"); - if (!door_file) { - fprintf(stderr,"[ERROR] Can't open enter_door file.\n"); - exit(EXIT_FAILURE); - } - int loadCheck = load_sprites(door_sprites, door_file, frame_height-1, frame_width-1); - - // Check for possible loadCheck() errors and in this case we return early if we couldn't load - if (loadCheck < 0) { - endwin(); - switch (loadCheck) { - case S4C_ERR_FILEVERSION: { - fprintf(stderr,"S4C_ERR_FILEVERSION : Failed file version check.\n"); - } - break; - case S4C_ERR_LOADSPRITES: { - fprintf(stderr,"S4C_ERR_LOADSPRITES : Failed loading the sprites.\n"); - } - break; - } - exit(loadCheck); - } - */ - - // We make sure we have the background correcly set up and expect animate_sprites to refresh it - wclear(door_win); - wrefresh(door_win); - - int result = - s4c_animate_sprites_at_coords(door_sprites, door_win, reps, - frametime, num_frames, - frame_height, frame_width, 0, - 0); - log_tag("debug_log.txt", "[DEBUG]", "animate() result was (%i)", - result); - wclear(door_win); - wrefresh(door_win); - delwin(door_win); - endwin(); - - update_Gamestate(gamestate, 1, current_room->class, roomsDone, - -1, NULL); - - if (current_room->class == HOME) { - res = - handleRoom_Home(gamestate, current_room, roomsDone, - path, player, load_info, - fighter_sprites, default_kls, - gamestate_kls); - } else if (current_room->class == ENEMIES) { - res = - handleRoom_Enemies(gamestate, current_room, roomsDone, - path, player, load_info, - enemy_sprites, fighter_sprites, - default_kls, gamestate_kls); - } else if (current_room->class == SHOP) { - //FIXME: does shop require usage of gameloop kls? - res = - handleRoom_Shop(current_room, roomsDone, path, player, - default_kls, gamestate_kls); - } else if (current_room->class == BOSS) { - res = - handleRoom_Boss(gamestate, current_room, roomsDone, - path, player, load_info, boss_sprites, - fighter_sprites, default_kls, - gamestate_kls); - } else if (current_room->class == TREASURE) { - res = - handleRoom_Treasure(current_room, roomsDone, path, - player, default_kls, gamestate_kls); - } else if (current_room->class == ROADFORK) { - res = - handleRoom_Roadfork(current_room, &roadFork_value, - roomsDone, path, player); - } else { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected current_room->class value: [%i] [%s]", - current_room->class, - stringFromRoom(current_room->class)); - //freeRoom(current_room); - log_tag("debug_log.txt", "[ERROR]", - "Freed current room, quitting program."); - exit(EXIT_FAILURE); - } - - if (res == OP_RES_DEATH) { - log_tag("debug_log.txt", "[DEBUG]", - "Room resulted in DEATH.\n"); - //Free room memory - //freeRoom(current_room); - break; - } else { - //Flush the terminal - int clrres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() system(\"clear\") res was (%i)", - clrres); - - if (roadFork_value > 0) { - //TODO - //What is this? - lightYellow(); - printStats(player); - lightGreen(); - log_tag("debug_log.txt", "[ROADFORK?]", - "You completed room %i.", roomsDone); - white(); - } - roomsDone++; - - //Update stats - player->stats->roomscompleted++; - - //Check if we need to update the win condition - if (win_con->class == FULL_PATH) { - win_con->current_val++; - } - //Free room memory - //freeRoom(current_room); - // Reset gamestate_kls - kls_temp_end(gamestate_kls); - gamestate_kls = kls_temp_start(temporary_kls); - } - } // Win condition loop - - // Clear default_kls - //kls_clear(default_kls); - - //Got out of the loop with res not being DEATH; so i won - if (res != OP_RES_DEATH) { //I guess player and enemy were freed already? - int clrres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() 2 system(\"clear\") res was (%i)", clrres); - handleStats(player); - printf("\n\n\tYOU WON!\n\n"); - log_tag("debug_log.txt", "[DEBUG]", "Game won."); - //Free default kls - kls_log(default_kls, "DEBUG", "Freeing default KLS"); - kls_free(default_kls); - log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed default KLS"); - - //Free temporary kls - kls_log(temporary_kls, "DEBUG", "Freeing temporary KLS"); - kls_free(temporary_kls); - log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed temporary KLS"); - } - - /* - //Free lore strings if they were loaded - if (GAMEMODE == Story) { - for (int i=0; i<5; i++) { - char msg[1000]; - sprintf(msg,"Freed lore string %i",i); - log_tag("debug_log.txt","[FREE]",msg); - sprintf(msg,"%s",lore_strings[i]); - log_tag("debug_log.txt","[FREE]",msg); - free(lore_strings[i]); - } - } - */ - //free(path->win_condition); - //free(path); - log_tag("debug_log.txt", "[DEBUG]", "End of wincon loop.\n"); - - } else { //Gamemode is not Story or Standard - log_tag("debug_log.txt", "[DEBUG]", "Gamemode was [%i]", GAMEMODE); - - if (GAMEMODE == Rogue) { - log_tag("debug_log.txt", "[DEBUG]", "Doing a Rogue run."); - char static_path[500]; - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - /** - * Legacy code for reading palette.gpl. Was it ever needed at runtime? - * TODO check which tags may use the palette.gpl at runtime (other than trying to read it pointlessly). - * - char path_to_palette[600]; - FILE* palette_file = NULL; - char palette_name[50] = "palette.gpl"; - sprintf(path_to_palette, "%s/%s", static_path, palette_name); - palette_file = fopen(path_to_palette, "r"); - if (palette_file == NULL) { - fprintf(stderr, - "Error: could not open palette file (%s/%s).\n", - static_path, palette_name); - exit(EXIT_FAILURE); - } - */ - - WINDOW *floor_win; - //TODO: store if we have done initsrc() or endwin(). Am sure we can get this from ncurses with some MACRO - //initscr(); - clear(); - refresh(); - start_color(); - - int colorCheck = has_colors(); - - if (colorCheck == FALSE) { - fprintf(stderr, "Terminal can't use colors, abort.\n"); - exit(S4C_ERR_TERMCOLOR); - } - - colorCheck = can_change_color(); - - if (colorCheck == FALSE) { - fprintf(stderr, "Terminal can't change colors, abort.\n"); - exit(S4C_ERR_TERMCHANGECOLOR); - } - for (int i = 0; i < PALETTE_S4C_H_TOTCOLORS; i++) { - init_s4c_color_pair(&palette[i], 9 + i); - } - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - // Create the window - floor_win = newwin(23, 24, 1, 2); - wclear(floor_win); - wrefresh(floor_win); - keypad(floor_win, TRUE); - - /* Print a border around the windows and print a title */ - box(floor_win, 0, 0); - wrefresh(floor_win); - refresh(); - int res = -1; - char msg[500]; - - log_tag("debug_log.txt", "[DEBUG]", "Prepping current_floor."); - kls_log(default_kls, "DEBUG", "Prepping current_floor."); - Floor *current_floor = - (Floor *) KLS_PUSH_T_TYPED(gamestate_kls, Floor, - HR_Floor, "Floor", "Floor"); - update_Gamestate(gamestate, 1, HOME, roomsDone, -1, - current_floor); - // Start the random walk from the center of the dungeon - int center_x = FLOOR_MAX_COLS / 2; - int center_y = FLOOR_MAX_ROWS / 2; - - // Init dbg_floor - init_floor_layout(current_floor); - - //Set center as filled - current_floor->floor_layout[center_x][center_y] = 1; - - //Init floor rooms - init_floor_rooms(current_floor); - - //Random walk #1 - floor_random_walk(current_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reset floor_layout if needed. - //Random walk #2 - floor_random_walk(current_floor, center_x, center_y, 100, 0); // Perform 100 more steps of random walk, DON'T reset floor_layout if needed. - - //Set floor explored matrix - load_floor_explored(current_floor); - - //Set room types - floor_set_room_types(current_floor); - - int current_x = center_x; - int current_y = center_y; - - //TODO: handle finishing all floors - path->length = MAX_ROGUE_FLOORS; - - int floors_done = 0; - - //Loop till wincon reached - - //while (dbg_floor->explored_area*1.0 < (dbg_floor->area*0.8)) { - while (win_con->current_val < win_con->target_val) { - - //Check if we have to update the wincon value - if (path->win_condition->class == ALL_ARTIFACTS) { - path->win_condition->current_val = - player->stats->artifactsfound; - //Are we forced to do one more room? - } - - int enemyTotal = -1; - roomClass room_type = -1; - - if (!(load_info->is_new_game) && !(load_info->done_loading) - && (load_info->save_type == ENEMIES_SAVE)) { - enemyTotal = loaded_roomtotalenemies; - } - - Room *current_room = NULL; - - //Check if current room needs to be played - if (current_floor->roomclass_layout[current_x][current_y] != - BASIC) { - kls_log(temporary_kls, "DEBUG", - "Prepping Room for Rogue Gamemode. roomsDone=(%i)", - roomsDone); - current_room = - (Room *) KLS_PUSH_T_TYPED(gamestate_kls, Room, - HR_Room, "Room", msg); - - current_room->index = roomsDone; - //setRoomType(path, &roadFork_value, &room_type, roomsDone); - - room_type = - current_floor-> - roomclass_layout[current_x][current_y]; - log_tag("debug_log.txt", "[ROOM]", - "Set Room #%i type: (%s)\n", roomsDone, - stringFromRoom(room_type)); - - initRoom(current_room, player, roomsDone, room_type, - enemyTotal, load_info, gamestate_kls); - log_tag("debug_log.txt", "[ROOM]", - "Init Room #%i: (%s)\n", roomsDone, - stringFromRoom(room_type)); - - /* - //Check if we need to display a story prompt - if (GAMEMODE == Story && (roomsDone == 1 || room_type == BOSS)) { - displayLore(lore_strings,*loreCounter); - (*loreCounter)++; - } - */ - - //Play room animation - - WINDOW *door_win; - //initscr(); - clear(); - refresh(); - start_color(); - - int reps = 1; - int frametime = 27; - int num_frames = 60; - int frame_height = 22; - int frame_width = 22; - door_win = - newwin(frame_height + 1, frame_width + 1, 0, 25); - - char door_sprites[MAXFRAMES][MAXROWS][MAXCOLS]; - - s4c_copy_animation(enter_door, door_sprites, num_frames, - frame_height, frame_width); - - log_tag("debug_log.txt", "[PREP]", - "Copied animation from matrix vector for enter_door with dimensions: [%i][%i][%i].", - num_frames, frame_height, frame_width); - - /* - * TODO - * Remove me - * Legacy code for loading animation from an s4c-file. - * - // Set static_path value to the correct static dir path - - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - char door_file_path[600]; - - sprintf(door_file_path,"%s/animations/enter_door.txt",static_path); - - FILE* door_file = fopen(door_file_path,"r"); - if (!door_file) { - fprintf(stderr,"[ERROR] Can't open enter_door file.\n"); - exit(EXIT_FAILURE); - } - int loadCheck = load_sprites(door_sprites, door_file, frame_height-1, frame_width-1); - - // Check for possible loadCheck() errors and in this case we return early if we couldn't load - if (loadCheck < 0) { - endwin(); - switch (loadCheck) { - case S4C_ERR_FILEVERSION: { - fprintf(stderr,"S4C_ERR_FILEVERSION : Failed file version check.\n"); - } - break; - case S4C_ERR_LOADSPRITES: { - fprintf(stderr,"S4C_ERR_LOADSPRITES : Failed loading the sprites.\n"); - } - break; - } - exit(loadCheck); - } - */ - - // We make sure we have the background correcly set up and expect animate_sprites to refresh it - wclear(door_win); - wrefresh(door_win); - - int result = - s4c_animate_sprites_at_coords(door_sprites, - door_win, reps, - frametime, num_frames, - frame_height, - frame_width, 0, 0); - log_tag("debug_log.txt", "[DEBUG]", - "animate() result was (%i)", result); - wclear(door_win); - wrefresh(door_win); - delwin(door_win); - endwin(); - - update_Gamestate(gamestate, 1, current_room->class, - current_room->index, -1, - current_floor); - - if (current_room->class == HOME) { - res = - handleRoom_Home(gamestate, current_room, - roomsDone, path, player, - load_info, fighter_sprites, - default_kls, gamestate_kls); - } else if (current_room->class == ENEMIES) { - res = - handleRoom_Enemies(gamestate, current_room, - roomsDone, path, player, - load_info, enemy_sprites, - fighter_sprites, default_kls, - gamestate_kls); - } else if (current_room->class == SHOP) { - res = - handleRoom_Shop(current_room, roomsDone, path, - player, default_kls, - gamestate_kls); - } else if (current_room->class == BOSS) { - res = - handleRoom_Boss(gamestate, current_room, - roomsDone, path, player, - load_info, boss_sprites, - fighter_sprites, default_kls, - gamestate_kls); - } else if (current_room->class == TREASURE) { - res = - handleRoom_Treasure(current_room, roomsDone, - path, player, default_kls, - gamestate_kls); - } else if (current_room->class == ROADFORK) { - res = - handleRoom_Roadfork(current_room, - &roadFork_value, roomsDone, - path, player); - } else { - sprintf(msg, - "Unexpected current_room->class value: [%i] [%s]", - current_room->class, - stringFromRoom(current_room->class)); - log_tag("debug_log.txt", "[ERROR]", msg); - //freeRoom(current_room); - log_tag("debug_log.txt", "[ERROR]", - "Freed current room, quitting program."); - exit(EXIT_FAILURE); - } - - if (res == OP_RES_DEATH) { - log_tag("debug_log.txt", "[DEBUG]", - "Room resulted in DEATH."); - //Free room memory - //freeRoom(current_room); - break; - } else { - //Flush the terminal - int clrres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() system(\"clear\") res was (%i)", - clrres); - - if (roadFork_value > 0) { - //lightYellow(); - //TODO - //What is this? - printStats(player); - //lightGreen(); - log_tag("debug_logx.txt", "[ROADFORK?]", - "You completed room %i.", roomsDone); - //white(); - } - roomsDone++; - - //Update stats - player->stats->roomscompleted++; - - //Free room memory - //freeRoom(current_room); - - //Update floor's roomclass layout for finished rooms which should not be replayed - switch (current_floor-> - roomclass_layout[current_x][current_y]) { - case ENEMIES: { - current_floor-> - roomclass_layout[current_x][current_y] = - BASIC; - } - break; - case BOSS: { - current_floor-> - roomclass_layout[current_x][current_y] = - BASIC; - floors_done++; - player->stats->floorscompleted++; - log_tag("debug_log.txt", "[DEBUG]", - "Floors done: [%i]", floors_done); - //Check if we need to update the win condition - if (win_con->class == FULL_PATH) { - win_con->current_val++; - } - // Reset gamestate_kls - kls_temp_end(gamestate_kls); - gamestate_kls = - kls_temp_start(temporary_kls); - - current_floor = - (Floor *) - KLS_PUSH_T_TYPED(gamestate_kls, Floor, - HR_Floor, "Floor", - "Floor"); - update_Gamestate(gamestate, 1, HOME, - roomsDone, -1, - current_floor); - - //Regenerate floor - log_tag("debug_log.txt", "[DEBUG]", - "Beaten a boss, regenerating current floor."); - // Init - init_floor_layout(current_floor); - //Set center as filled - current_floor-> - floor_layout[center_x][center_y] = 1; - //Init floor rooms - init_floor_rooms(current_floor); - //Random walk #1 - floor_random_walk(current_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reset floor_layout if needed. - //Random walk #2 - floor_random_walk(current_floor, center_x, center_y, 100, 0); // Perform 100 more steps of random walk, DON'T reset floor_layout if needed. - //Set floor explored matrix - load_floor_explored(current_floor); - //Set room types - floor_set_room_types(current_floor); - - //Center current coords - current_x = center_x; - current_y = center_y; - continue; //Check win condition for loop - - } - break; - case SHOP: { - current_floor-> - roomclass_layout[current_x][current_y] = - BASIC; - } - break; - case TREASURE: { - current_floor-> - roomclass_layout[current_x][current_y] = - BASIC; - } - break; - case HOME: { - //We leave it available - log_tag("debug_log.txt", "[DEBUG]", - "Skipping reset of roomclass for HOME room"); - } - break; - default: { - log_tag("debug_log.txt", "[ERROR]", - "Unexpected roomclass value in Rogue loop: [%i] [%s]", - current_floor-> - roomclass_layout[current_x] - [current_y], - stringFromRoom(current_floor-> - roomclass_layout - [current_x] - [current_y])); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } - } - } else { - log_tag("debug_log.txt", "[DEBUG]", - "Current room class was [%s] (val: %i), not playable.", - stringFromRoom(current_floor-> - roomclass_layout[current_x] - [current_y]), - current_floor-> - roomclass_layout[current_x][current_y]); - } - - //Draw current FOV - draw_floor_view(current_floor, current_x, current_y, - floor_win); - //Take a step and update screen - move_update(gamestate, current_floor, ¤t_x, - ¤t_y, floor_win, path, player, - current_room, load_info, default_kls, - gamestate_kls); - } // Win condition loop - - //FIXME: do we need this? - //kls_temp_end(gamestate_kls); - // Clear default_kls - //kls_clear(default_kls); - - //Got out of the loop with res not being DEATH; so i won - if (res != OP_RES_DEATH) { //I guess player and enemy were freed already? - int clrres = system("clear"); - //TODO - //What is this? - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() 2 system(\"clear\") res was (%i)", - clrres); - handleStats(player); - printf("\n\n\tYOU WON!\n\n"); - log_tag("debug_log.txt", "[DEBUG]", "Game won."); - //Free default kls - kls_log(default_kls, "DEBUG", "Freeing default KLS"); - kls_free(default_kls); - log_tag("debug_log.txt", "[DEBUG-KLS]", - "Freed default KLS"); - - //Free temporary kls - kls_log(temporary_kls, "DEBUG", "Freeing temporary KLS"); - kls_free(temporary_kls); - log_tag("debug_log.txt", "[DEBUG-KLS]", - "Freed temporary KLS"); - } else { - //TODO - //What is this? - int clrres = system("clear"); - log_tag("debug_log.txt", "[DEBUG]", - "gameloop() 3 system(\"clear\") res was (%i)", - clrres); - printf("\n\n\tYOU DIED.\n\n"); - log_tag("debug_log.txt", "[DEBUG]", "Game lost."); - } - - /* - //Free lore strings if they were loaded - if (GAMEMODE == Story) { - for (int i=0; i<5; i++) { - char msg[1000]; - sprintf(msg,"Freed lore string %i",i); - log_tag("debug_log.txt","[FREE]",msg); - sprintf(msg,"%s",lore_strings[i]); - log_tag("debug_log.txt","[FREE]",msg); - //free(lore_strings[i]); - } - } - */ - - //free(path->win_condition); - //free(path); - log_tag("debug_log.txt", "[DEBUG]", "End of wincon loop."); - - //free(current_floor); - - endwin(); - } else { - log_tag("debug_log.txt", "[ERROR]", "Error in gameloop()."); - exit(EXIT_FAILURE); - } - } - //kls_temp_end(gamestate_kls); - } while (retry()); - - //TODO - //What is this? - purple(); - printf("\n\n\t\tTHANKS 4 PLAYING!\n\n"); - white(); - log_tag("debug_log.txt", "[DEBUG]", "End of program."); - exit(EXIT_SUCCESS); -} - -#ifdef _WIN32 -/** - * Takes a integer and a string array (possibly from main). - * @param argc The number of argv values + 1 (0 is program name?). - * @param argv Array of strings with argc - 1 values. - */ -void gameloop_Win(int argc, char **argv) -{ - char *whoami; - char path_to_kls_debug_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Truncate "debug_log.txt" - sprintf(path_to_kls_debug_file, "%s\\%s", static_path, "kls_debug_log.txt"); - KLS_Conf default_kls_conf = { - .kls_autoset_regions = 1, - .kls_autoset_temp_regions = 1, - .kls_verbose_lvl = 1, - .kls_log_filepath = path_to_kls_debug_file, - .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, - .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, - }; - KLS_Conf temporary_kls_conf = { - .kls_autoset_regions = 1, - .kls_autoset_temp_regions = 1, - .kls_verbose_lvl = 0, - .kls_log_fp = stderr, - .kls_reglist_kls_size = KLS_DEFAULT_SIZE * 16, - .kls_reglist_alloc_backend = KLS_REGLIST_ALLOC_KLS_BASIC, - }; - - (whoami = strrchr(argv[0], '\\')) ? ++whoami : (whoami = argv[0]); - do { - default_kls = kls_new_conf(KLS_DEFAULT_SIZE * 8, default_kls_conf); - temporary_kls = kls_new_conf(KLS_DEFAULT_SIZE * 8, temporary_kls_conf); - char *kls_progname = - (char *)KLS_PUSH_ARR_TYPED(default_kls, char *, sizeof(whoami), - KLS_None, "progname", whoami); - strcpy(kls_progname, whoami); -#ifndef HELAPORDO_DEBUG_LOG -#else - FILE *debug_file = NULL; - FILE *OPS_debug_file = NULL; -#endif - // Parse command-line options - int option; - loadInfo *load_info = - (loadInfo *) KLS_PUSH_TYPED(default_kls, loadInfo, HR_loadInfo, - "loadInfo", "loadInfo"); - - load_info->is_new_game = 1; //By default we do a new game - load_info->enemy_index = -1; - load_info->total_foes = -1; - load_info->save_type = -1; - int loaded_roomtotalenemies = -1; - int loaded_roomindex = -1; - load_info->ptr_to_roomtotalenemies = &loaded_roomtotalenemies; - load_info->ptr_to_roomindex = &loaded_roomindex; - - while ((option = getopt(argc, argv, "r:E:tTGRXQLlvdhsaV")) != -1) { - switch (option) { - case 'd': { -#ifndef HELAPORDO_DEBUG_ACCESS -#else - G_DEBUG_ON += 1; - G_LOG_ON = 1; -#endif - } - break; - case 'r': { - G_DEBUG_ROOMTYPE_ON += 1; - } - break; - case 'E': { - G_DEBUG_ENEMYTYPE_ON += 1; - } - break; - case 'L': { - G_LOG_ON = 1; - } - break; - break; - case 'G': { - G_GODMODE_ON = 1; - } - break; - case 'Q': { - G_FASTQUIT_ON = 1; - } - break; - case 'X': { - G_EXPERIMENTAL_ON = 1; - } - break; - case 'a': { - GS_AUTOSAVE_ON = 0; - } - break; - case 's': { - GAMEMODE = Story; - } - break; - case 'R': { - GAMEMODE = Rogue; - } - break; - break; - case 'h': { - usage(whoami); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 'T': { - G_DOTUTORIAL_ON = 1; - handleTutorial(); - usage(whoami); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 't': { - //Test all colors - printFormattedVersion(whoami); - printf("Using:\n"); - printf(" \'animate\' :\n s4c/animate.h "); - S4C_ECHOVERSION(); - printf("[DEBUG] Testing terminal color capabilities.\n"); - napms(800); - //TODO Win term color test? - //display_colorpairs(); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 'V': { - printf("helapordo build: %s\n", helapordo_build_string); - hlpd_dbg_features(); - printf(" using: s4c-animate v%s\n", S4C_ANIMATE_VERSION); - s4c_dbg_features(); - printf(" using: koliseo v%s\n", string_koliseo_version()); - kls_dbg_features(); - printf(" using: ncurses v%s\n", NCURSES_VERSION); -#ifdef ANVIL__helapordo__ -#ifndef INVIL__helapordo__HEADER__ - printf(" Built with: amboso v%s\n", - ANVIL__API_LEVEL__STRING); -#else - printf(" Built with: invil v%s\n", - INVIL__VERSION__STRING); - printf("Version Info: %.8s\n", - get_ANVIL__VERSION__DESC__()); - printf("Last commit: %s", get_INVIL__COMMIT__DESC__()); - const char* anvil_date = get_ANVIL__VERSION__DATE__(); - char* anvil_date_end; -#ifndef _WIN32 - time_t anvil_build_time = strtol(anvil_date, &anvil_date_end, 10); -#else - time_t anvil_build_time = strtoll(anvil_date, &anvil_date_end, 10); -#endif //_WIN32 - - if (anvil_date_end == anvil_date) { - //TODO: error - } else { - char build_time_buff[20] = {0}; - struct tm* build_time_tm = localtime(&anvil_build_time); - - if (build_time_tm == NULL) { - //TODO: error - } else { - strftime(build_time_buff, 20, "%Y-%m-%d %H:%M:%S", build_time_tm); - printf("\nDate: %s\n", build_time_buff); - } - } -#endif // INVIL__helapordo__HEADER__ -#else - printf(" Built without anvil\n"); -#endif // ANVIL__helapordo__ - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - break; - case 'v': { - printVersion(); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_SUCCESS); - } - case '?': { - fprintf(stderr, - "Invalid option: %c\n Check your arguments.\n", - option); - usage(whoami); - // Handle invalid options - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - default: { - // Should never get here - fprintf(stderr, "Invalid option: %c\n, bad usage.\n", - option); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - break; - } - } - -#ifndef HELAPORDO_DEBUG_LOG -#else - // Open log file if log flag is set and reset it - if (G_LOG_ON == 1) { - char path_to_debug_file[600]; - char path_to_OPS_debug_file[600]; - char static_path[500]; - // Set static_path value to the correct static dir path - resolve_staticPath(static_path); - - //Truncate "debug_log.txt" - sprintf(path_to_debug_file, "%s\\%s", static_path, "debug_log.txt"); - debug_file = fopen(path_to_debug_file, "w"); - if (!debug_file) { - endwin(); //TODO: Can/should we check if we have to do this only in curses mode? - fprintf(stderr, - "[ERROR] Can't open debug logfile (%s\\debug_log.txt).\n", - static_path); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - fprintf(debug_file, "[DEBUGLOG] --New game-- \n"); - fprintf(debug_file, "[DEBUG] --Default kls debug info:-- \n"); - print_kls_2file(debug_file, default_kls); - fprintf(debug_file, "[DEBUG] --Temporary kls debug info:-- \n"); - print_kls_2file(debug_file, temporary_kls); - fprintf(debug_file, - "[DEBUG] --Closing header for new game.-- \n"); - fclose(debug_file); - - //Lay debug info - log_tag("debug_log.txt", "[DEBUG]", "G_DEBUG_ON == (%i)", - G_DEBUG_ON); - //FIXME we should have same behaviour as gameloop(), and actually log kls_progname... - //Doesn't matter for now, kls_progname is declared later - log_tag("debug_log.txt", "[DEBUG]", "whoami == (%s)", whoami); - log_tag("debug_log.txt", "[DEBUG]", "G_LOG_ON == (%i)", G_LOG_ON); - log_tag("debug_log.txt", "[DEBUG]", "small DEBUG FLAG ASSERTED"); - log_tag("debug_log.txt", "[DEBUG]", - "[Current position in default_kls] [pos: %lli]\n", - kls_get_pos(default_kls)); - - //Truncate OPS_LOGFILE - sprintf(path_to_OPS_debug_file, "%s\\%s", static_path, OPS_LOGFILE); - OPS_debug_file = fopen(path_to_OPS_debug_file, "w"); - if (!OPS_debug_file) { - endwin(); //TODO: Can/should we check if we have to do this only in curses mode? - fprintf(stderr, "[ERROR] Can't open OPS logfile (%s\\%s).\n", - static_path, OPS_LOGFILE); - kls_free(default_kls); - kls_free(temporary_kls); - exit(EXIT_FAILURE); - } - fprintf(OPS_debug_file, "[OPLOG] --New game-- \n"); - fclose(OPS_debug_file); - log_tag("debug_log.txt", "[DEBUG]", "Truncated [%s]", OPS_LOGFILE); - log_Win_EnvVars(); - log_tag("debug_log.txt", "[WIN32-DEBUG]", "Printing title."); - } -#endif - printTitle(); - printf("\n\n\n\n\t\t\t\tSTART\n\n"); - if (G_DEBUG_ON) { - printf("\t\t\t\t\t\t\t\tDEBUG ON\n"); - } - printf("\t\t\t\t\t\t"); - printFormattedVersion(whoami); - printf("\n\nThe Windows build of \"helapordo\" is very much WIP.\n\n"); - printf("\n Press Enter to proceed.\n"); - scanf("%*c"); - system("cls"); - printGlobVars(); - printWin_EnvVars(); - printf("\n\n Press Enter to demo a minimal rogue floor.\n"); - printf(" Quit with Ctrl+C, or explore enough of the map.\n\n"); - printf(" You move with the arrow keys.\n\n"); - scanf("%*c"); - test_floors(); - kls_free(temporary_kls); - kls_free(default_kls); - } while (retry()); - - //TODO - //What is this? - printf("\n\n\t\tTHANKS 4 PLAYING!\n\n"); - log_tag("debug_log.txt", "[DEBUG]", "End of program."); - kls_free(default_kls); - kls_free(temporary_kls); - exit(0); -} -#endif //End gameloop_Win() diff --git a/src/helapordo.h b/src/helapordo.h deleted file mode 100644 index 6c43cc5b..00000000 --- a/src/helapordo.h +++ /dev/null @@ -1,387 +0,0 @@ -// jgabaut @ github.com/jgabaut -// SPDX-License-Identifier: GPL-3.0-only -/* - Copyright (C) 2022-2024 jgabaut - - 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, version 3 of the License. - - 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 HELAPORDO_H -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) //We need C11 -#define HELAPORDO_H - -#ifndef _WIN32 -#define _POSIX_C_SOURCE 200809L -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HELAPORDO_CURSES_BUILD -#ifdef _WIN32 -#include -#include -#include "floor_tester.h" -#else -#include -#include -#include -#endif // _WIN32 -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined" -#else -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -#include -#include -#include "game_core.h" -#include "game_utils.h" -#include "rooms.h" -#include "specials.h" -#include "artifacts.h" - -#ifdef HELAPORDO_CURSES_BUILD -#include "game_curses.h" -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined" -#else -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -#include "sprites.h" -#include "floors.h" -#include "anvil__helapordo.h" -#include "game_lore.h" -#include "game_lore_alt.h" - -/*! \mainpage Helapordo index page - * - * \section intro_sec Intro - * - * Helapordo is roguelike terminal game, using ncurses. - * - * SPDX-License-Identifier: GPL-3.0-only - * - * Check it out on [github](https://github.com/jgabaut/helapordo). - */ - -/** - * Call function associated with the passed turnOption_OP. - * @param op The turnOption_OP to execute. - * @param args Pointer to turnOP_args object. - * @param kls The Koliseo used for allocations. - */ -OP_res turnOP(turnOption_OP op, turnOP_args * args, Koliseo * kls, - Koliseo_Temp * t_kls); - -#ifdef HELAPORDO_CURSES_BUILD -fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, WINDOW * notify_win, Koliseo * kls); -fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, WINDOW * notify_win, Koliseo * kls); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, Rectangle * notification_area, Koliseo * kls); -fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, Rectangle * notification_area, Koliseo * kls); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -/* -void register_counter_callback(int index, callback_void_t ptr, Fighter*); -*/ - -void resetFighterStatus(Fighter * f); - -void resetEnemyStatus(Enemy * e); - -void resetBossStatus(Boss * b); - -effect_fun getStatusCounterFun(fighterStatus status); - -effect_e_fun getStatusCounterEnemyFun(fighterStatus status); - -effect_b_fun getStatusCounterBossFun(fighterStatus status); - -effect_fp_fun get_StatusCounter_FoeParty_Fun(fighterStatus status); - -void set_turnboost_atk(Fighter * f, int boost); -void set_turnboost_def(Fighter * f, int boost); -void set_turnboost_vel(Fighter * f, int boost); -void set_turnboost_enr(Fighter * f, int boost); - -void set_enemy_turnboost_atk(Enemy * e, int boost); -void set_enemy_turnboost_def(Enemy * e, int boost); -void set_enemy_turnboost_vel(Enemy * e, int boost); -void set_enemy_turnboost_enr(Enemy * e, int boost); - -void set_boss_turnboost_atk(Boss * b, int boost); -void set_boss_turnboost_def(Boss * b, int boost); -void set_boss_turnboost_vel(Boss * b, int boost); -void set_boss_turnboost_enr(Boss * b, int boost); - -void set_foeparty_turnboost_atk(FoeParty * fp, int boost); -void set_foeparty_turnboost_def(FoeParty * fp, int boost); -void set_foeparty_turnboost_vel(FoeParty * fp, int boost); -void set_foeparty_turnboost_enr(FoeParty * fp, int boost); - -boost_fun getStatBoostCounterFun(Stat s); -boost_e_fun getStatBoostCounterEnemyFun(Stat s); -boost_b_fun getStatBoostCounterBossFun(Stat s); -boost_fp_fun get_StatBoostCounter_FoeParty_Fun(Stat s); - -void initPerks(Fighter * f, Koliseo * kls); -void applyEquipPerks(Equip * e, Fighter * f); -void removeEquipPerks(Equip * e, Fighter * f); -void printActivePerks(Fighter * f); - -void initCounters(Fighter * f, Koliseo * kls); - -void initECounters(Enemy * e, Koliseo_Temp * t_kls); - -void initBCounters(Boss * b, Koliseo_Temp * t_kls); - -void initFoePartyCounters(FoeParty * fp, Koliseo_Temp * t_kls); - -void printCounters(Turncounter * counters[]); - -void updateCounters(Turncounter * counters[], int isEnemy, Fighter * f, - Enemy * e); -void updateCounters_Boss(Turncounter * counters[], int isBoss, Fighter * f, - Boss * b); -void setCounter(Turncounter * c, int turns); - -void setSpecials(Fighter * f, Koliseo * kls); - -void setSkills(Fighter *f, Koliseo *kls); -void setEnemySkills(Enemy *e, Koliseo_Temp *t_kls); -void setBossSkills(Boss *b, Koliseo_Temp *t_kls); - -void resetPermboosts(Fighter * f); -void applyPermboosts(Fighter * f); - -void resetArtifactsState(Fighter * f); -void applyArtifacts(Fighter * f, Enemy * e, Boss * b, int isBoss); - -void initEquipSlots(Fighter * f, Koliseo * kls); - -void initConsumableBag(Fighter * f, Koliseo * kls); -void initArtifactsBag(Fighter * f, Koliseo * kls); - -void initWincon(Wincon * w, Path * p, winconClass class); - -void initPlayerStats(Fighter * player, Path * path, Koliseo * kls); - -void initEnemyStats(Enemy * e, Koliseo_Temp * t_kls); - -int getBossBoost(int lvl, bossClass bclass); - -void statResetBoss(Boss * b, int force); - -void initBossStats(Boss * b, Koliseo_Temp * t_kls); -void prepareBoss(Boss * b, Koliseo_Temp * t_kls); - -void initFoePartyStats(FoeParty * fp, Koliseo_Temp * t_kls); -void prepareFoeParty(FoeParty * fp, int total_foes, int roomindex, - Koliseo_Temp * t_kls); - -int getEnemyBoost(int lvl, enemyClass eclass); - -void statResetEnemy(Enemy * e, int force); - -void prepareRoomEnemy(Enemy * e, int roomindex, int enemiesInRoom, - int enemyindex, Koliseo_Temp * t_kls); - -void setEquipPrices(int size, int *equipPrices, Equip * equips[]); -void setConsumablePrices(int size, int *consumablePrices, - Consumable ** consumables); -void initShop(Shop * s, int indexWeight, Fighter * player, - Koliseo_Temp * t_kls); -void initChest(Chest * c, Fighter * f, Koliseo_Temp * t_kls); -void prepareChest(Chest * c, Fighter * f, Koliseo_Temp * t_kls); - -void initTreasure(Treasure * t, Fighter * f, Koliseo_Temp * t_kls); -void prepareTreasure(Treasure * t, Fighter * f, Koliseo_Temp * t_kls); - -void prepareRoadfork(Roadfork * r); - -void printStats(Fighter * f); - -void printEStats(Enemy * e); - -int getEnemyXpGain(Enemy * e); - -int getBossXpGain(Boss * b); - -void printConsumablesStats(Consumable * c); - -void printArtifactStats(Artifact * a); - -void printQualityColor(quality q); - -void printEquipStats(Equip * e); - -void printSpawnMessage(Enemy * e, int roomIndex, int enemyIndex); - -void getParams(int argc, char **argv, Fighter * player, Path * path, int optTot, - Koliseo * kls); - -turnOption getTurnChoice(char *ch); - -foeTurnOption enemyTurnPick(Enemy * e, Fighter * f); - -foeTurnOption bossTurnPick(Boss * b, Fighter * f); - -int getBoost(int lvl, int luck); - -void unlockSpecial(Fighter * f); - -void onLevelUp(Fighter * player); - -void checkremainder(Fighter * player, int xp); - -void giveXp(Fighter * player, Enemy * e); -void giveXp_Boss(Fighter * player, Boss * b); - -void statReset(Fighter * player, int force); - -int dropConsumable(Fighter * player); -int dropArtifact(Fighter * player); - -#ifdef HELAPORDO_CURSES_BUILD -void dropEquip(Fighter * player, int beast, WINDOW * notify_win, Koliseo * kls); - -int defer_fight_enemy(Fighter * player, Enemy * e, foeTurnOption_OP foe_op, - WINDOW * notify_win, Koliseo * kls); -int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, - WINDOW * notify_win, Koliseo * kls); - -int fight(Fighter * player, Enemy * e, WINDOW * notify_win, Koliseo * kls); - -int enemy_attack(Enemy * e, Fighter * target, WINDOW * notify_win, - Koliseo * kls); - -int defer_fight_boss(Fighter * player, Boss * b, Path * p, - foeTurnOption_OP foe_op, WINDOW * notify_win, - Koliseo * kls); - -int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, - WINDOW *notify_win, Koliseo *kls); - -int boss_fight(Fighter * player, Boss * b, Path * p, WINDOW * notify_win, - Koliseo * kls); - -int boss_attack(Boss * b, Fighter * target, Path * p, WINDOW * notify_win, - Koliseo * kls); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -void dropEquip(Fighter * player, int beast, Rectangle * notification_area, Koliseo * kls); - -int defer_fight_enemy(Fighter * player, Enemy * e, foeTurnOption_OP foe_op, - Rectangle * notification_area, Koliseo * kls); -int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, - Rectangle * notification_area, Koliseo * kls); - -int fight(Fighter * player, Enemy * e, Rectangle * notification_area, Koliseo * kls); - -int enemy_attack(Enemy * e, Fighter * target, Rectangle * notification_area, - Koliseo * kls); - -int defer_fight_boss(Fighter * player, Boss * b, Path * p, - foeTurnOption_OP foe_op, Rectangle * notification_area, - Koliseo * kls); - -int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, - Rectangle * notification_area, Koliseo *kls); - -int boss_fight(Fighter * player, Boss * b, Path * p, Rectangle * notification_area, - Koliseo * kls); - -int boss_attack(Boss * b, Fighter * target, Path * p, Rectangle * notification_area, - Koliseo * kls); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -void useConsumable(Fighter * f, Enemy * e, Boss * b, char *string, int isBoss); - -int getConsumableQty(Fighter * f, int n); - -void emptyConsumables(Fighter * player); - -void emptyArtifacts(Fighter * player); - -void emptyEquips(Fighter * player); - -OP_res handleSave_Enemies(FILE * file, Fighter * f, Path * p, Enemy * e, - int enemyIndex, int roomTotalEnemies, int roomIndex); -OP_res handleSave_Home(FILE * file, Fighter * f, Path * p, int roomIndex); - -OP_res handleLoadgame_Enemies(FILE * file, Fighter * f, Path * p, Enemy * e, - int *enemyIndex, int *roomTotalEnemies, - int *roomIndex, int *total_foes, - int *done_loading, Koliseo * kls); -OP_res handleLoadgame_Home(FILE * file, Fighter * f, Path * p, int *roomIndex, - int *done_loading, Koliseo * kls); -saveType read_saveType(FILE * file); - -void death(Fighter * player, loadInfo * load_info); - -void e_death(Enemy * e); - -void b_death(Boss * b); - -int retry(void); - -void debug_generic(Gamestate * gmst, Fighter * player, Path * p, int roomIndex, - Koliseo * kls, Koliseo_Temp * t_kls); -void debug_enemies_room(Gamestate * gmst, Room * room, Fighter * player, - Enemy * e, Path * p, int roomIndex, int currentEnemyNum, - Koliseo * kls, Koliseo_Temp * t_kls); - -void quit(Fighter * p, Room * room, loadInfo * load_info, Koliseo_Temp * t_kls); - -void sell_all_equips(Fighter * f, Koliseo_Temp * t_kls); - -#ifdef HELAPORDO_CURSES_BUILD -void open_chest(WINDOW * w, Chest * c, Fighter * f, Koliseo * kls, - Koliseo_Temp * t_kls); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -void open_chest(Rectangle * notification_area, Chest * c, Fighter * f, Koliseo * kls, - Koliseo_Temp * t_kls); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - -Path *randomise_path(int seed, Koliseo * kls, const char *path_to_savefile); - -void gameloop(int argc, char **argv); - -#ifdef _WIN32 -void gameloop_Win(int argc, char **argv); -#endif - -#else -#error "This code requires C11.\n _Alignof\n" -#endif -#endif //HELAPORDO_H diff --git a/src/main.c b/src/main.c index e4cf1e85..5a545b15 100644 --- a/src/main.c +++ b/src/main.c @@ -16,13 +16,16 @@ along with this program. If not, see . */ #ifdef HELAPORDO_CURSES_BUILD -#include "helapordo.h" -#include "floor_tester.h" +#ifndef _WIN32 +#include "build-nc/helapordo.h" +#else +#include "build-nc-w64/helapordo_win.h" +#endif // _WIN32 #else #ifndef HELAPORDO_RAYLIB_BUILD #error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." #else -#include "helapordo_raylib.h" +#include "build-rl/helapordo_raylib.h" #endif //HELAPORDO_RAYLIB_BUILD #endif //HELAPORDO_CURSES_BUILD diff --git a/src/artifacts.c b/src/utils/artifacts.c similarity index 82% rename from src/artifacts.c rename to src/utils/artifacts.c index 5c3fe1f6..5ff1e442 100644 --- a/src/artifacts.c +++ b/src/utils/artifacts.c @@ -192,3 +192,52 @@ void artifact_giantfossile(Fighter *f, Enemy *e, Boss *b, int isBoss) f->artifactsBag[GIANTFOSSILE]->active = 1; } } + +/** + * Takes a Fighter, a Enemy and a Boss pointer; plus an integer indicating if effects should be applied to enemy (==0) or boss (==1=. + * Iterates over artifacts bag and calls the inner function pointer if an artifact has positive qty and its active member is false. + * @see Artifact + * @param f A Fighter pointer. + * @param e An Enemy pointer. + * @param b The Boss pointer. + * @param isBoss The integer defining who is receiving the effect. + */ +void applyArtifacts(Fighter *f, Enemy *e, Boss *b, int isBoss) +{ + + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + Artifact *a = f->artifactsBag[i]; + if (a->qty != 0 && !(a->active)) { //We only apply the ones we have unlocked && aren't active already + switch (a->class) { + case THKSKULL: { + artifact_thinkingskull(f, e, b, isBoss); + } + break; + case TWINKIE: { + artifact_twinkie(f, e, b, isBoss); + } + break; + case WRISTBAND: { + artifact_wristband(f, e, b, isBoss); + } + break; + case BOARTAIL: { + artifact_boartail(f, e, b, isBoss); + } + break; + case CHAOSORB: { + artifact_chaosorb(f, e, b, isBoss); + } + break; + case POWERSYPHON: { + artifact_powersyphon(f, e, b, isBoss); + } + break; + case GIANTFOSSILE: { + artifact_giantfossile(f, e, b, isBoss); + } + break; + }; + }; + }; +} diff --git a/src/artifacts.h b/src/utils/artifacts.h similarity index 95% rename from src/artifacts.h rename to src/utils/artifacts.h index bdc7949f..7481a57f 100644 --- a/src/artifacts.h +++ b/src/utils/artifacts.h @@ -19,10 +19,7 @@ #ifndef ARTIFACTS_H #define ARTIFACTS_H -#include "game_core.h" #include "game_utils.h" -#include -#include void artifact_thinkingskull(Fighter * f, Enemy * e, Boss * b, int mode); void artifact_twinkie(Fighter * f, Enemy * e, Boss * b, int mode); @@ -32,4 +29,5 @@ void artifact_chaosorb(Fighter * f, Enemy * e, Boss * b, int mode); void artifact_powersyphon(Fighter * f, Enemy * e, Boss * b, int mode); void artifact_giantfossile(Fighter * f, Enemy * e, Boss * b, int mode); +void applyArtifacts(Fighter * f, Enemy * e, Boss * b, int isBoss); #endif diff --git a/src/floors.c b/src/utils/floors.c similarity index 68% rename from src/floors.c rename to src/utils/floors.c index 704adee3..7749fdf7 100644 --- a/src/floors.c +++ b/src/utils/floors.c @@ -980,4 +980,404 @@ void move_update(Gamestate *gamestate, Floor *floor, int *current_x, } } +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + +/** + * Takes a Floor pointer and prints its roomClass layout using the passed Rectangle as reference position. + * @see Floor + * @see floorClass + * @see roomClass + */ +void display_roomclass_layout(Floor *floor, Rectangle *win, float pixelSize) +{ + if (win == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "display_roomclass_layout: win was NULL"); + exit(EXIT_FAILURE); + } + for (int y = 0; y < FLOOR_MAX_ROWS; y++) { + for (int x = 0; x < FLOOR_MAX_COLS; x++) { + char ch = '.'; + int isColored = -1; + switch (floor->roomclass_layout[x][y]) { + case HOME: { + ch = 'H'; + isColored = S4C_BRIGHT_GREEN; + } + break; + case ENEMIES: { + ch = 'E'; + isColored = S4C_PURPLE; + } + break; + case BOSS: { + ch = 'B'; + isColored = S4C_RED; + } + break; + case SHOP: { + ch = '$'; + isColored = S4C_CYAN; + } + break; + case TREASURE: { + ch = '*'; + isColored = S4C_ORANGE; + } + break; + case WALL: { + ch = '#'; + isColored = S4C_BRIGHT_YELLOW; + } + break; + case BASIC: { + ch = ' '; + isColored = S4C_LIGHT_BROWN; + } + break; + default: { + ch = '?'; + } + break; + } + + Color color = {0}; + if (isColored >= 0) { + color = ColorFromS4CPalette(palette, isColored); + } + DrawRectangle(win->x + (x * ((int)pixelSize) ), win->y + (y * ((int)pixelSize)), pixelSize, pixelSize, color); + if (isColored >= 0) { + isColored = -1; + }; + (void) ch; + } + } + +} + +/** + * Takes a Floor pointer and prints its floor layout using the passed Rectangle as reference position. + * @see Floor + * @see floorClass + */ +void display_floor_layout(Floor * floor, Rectangle * win, float pixelSize) +{ + if (win == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "display_floor_layout(): win was NULL."); + exit(EXIT_FAILURE); + } + int isFull = -1; + int isColored = -1; + for (int y = 0; y < FLOOR_MAX_ROWS; y++) { + for (int x = 0; x < FLOOR_MAX_COLS; x++) { + isFull = (floor->floor_layout[x][y] == 1 ? 1 : 0); + isColored = isFull; + Color color = {0}; + if (isColored > 0) { + color = ColorFromS4CPalette(palette, S4C_BRIGHT_YELLOW); + } + DrawRectangle(win->x + (x * ((int)pixelSize) ), win->y + (y * ((int)pixelSize)), pixelSize, pixelSize, color); + //mvwprintw(win, y + 3, x + 3, "%c", (isFull == 1 ? 'X' : ' ')); + } + } +} + +/** + * Takes a Floor pointer and prints its explored layout using the passed Rectangle as reference position. + * @see Floor + * @see floorClass + */ +void display_explored_layout(Floor *floor, Rectangle *win, float pixelSize) +{ + if (win == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "display_explored_layout(): win was NULL."); + exit(EXIT_FAILURE); + } + int isWalkable = -1; + int isExplored = -1; + for (int y = 0; y < FLOOR_MAX_ROWS; y++) { + for (int x = 0; x < FLOOR_MAX_COLS; x++) { + isWalkable = (floor->explored_matrix[x][y] >= 0 ? 1 : 0); + isExplored = (floor->explored_matrix[x][y] > 0 ? 1 : 0); + Color color = {0}; + if (isWalkable > 0) { + if (isExplored == 1) { + color = ColorFromS4CPalette(palette, S4C_BRIGHT_YELLOW); + } else { + color = ColorFromS4CPalette(palette, S4C_PURPLE); + } + DrawRectangle(win->x + (x * ((int)pixelSize) ), win->y + (y * ((int)pixelSize)), pixelSize, pixelSize, color); + } + } + } +} + +/** + * Takes a Floor pointer and cell x and y position. Draws render using the passed Rectangle as reference position. + * @see Floor + * @see floorClass + */ +void draw_cell(Floor *floor, int cell_x, int cell_y, Rectangle *win, + int drawcorner_x, int drawcorner_y, int x_size, int y_size, float pixelSize, + int recurse) +{ + if (win == NULL) { + log_tag("debug_log.txt", "[ERROR]", "draw_cell(): win was NULL."); + exit(EXIT_FAILURE); + } + int xSize = x_size; + int ySize = y_size; + + if (floor->floor_layout[cell_x][cell_y] == 0) { + if (floor->roomclass_layout[cell_x][cell_y] != WALL) { + log_tag("debug_log.txt", "[DEBUG]", + "draw_cell(): floor->floor_layout[%i][%i] was (%i).", + cell_x, cell_y, floor->floor_layout[cell_x][cell_y]); + log_tag("debug_log.txt", "[DEBUG]", + "draw_cell(): floor->roomclass_layout[%i][%i] was (%s).", + cell_x, cell_y, + stringFromRoom(floor->roomclass_layout[cell_x][cell_y])); + } + for (int i = 0; i < xSize; i++) { + for (int j = 0; j < ySize; j++) { + char ch = '?'; + int isWall = -1; + int isColored = -1; + Color color = {0}; + isWall = + floor->roomclass_layout[cell_x][cell_y] == WALL ? 1 : 0; + if (isWall > 0) { + ch = '#'; + isColored = S4C_PURPLE; + } else { + ch = '?'; + } + if (isColored >= 0) { + color = ColorFromS4CPalette(palette, isColored); + }; + DrawRectangle(win->x + ((j + drawcorner_x) * ((int)pixelSize) ), win->y + ((i + drawcorner_y) * ((int)pixelSize)), pixelSize, pixelSize, color); + if (isColored >= 0) { + isColored = -1; + }; + if (isWall > 0) { + isWall = -1; + ch = '?'; + }; + (void) ch; + } + } + } else if (floor->floor_layout[cell_x][cell_y] == 1) { + for (int i = 0; i < xSize; i++) { + for (int j = 0; j < ySize; j++) { + char ch = '?'; + int isColored = -1; + Color color = {0}; + switch (floor->roomclass_layout[cell_x][cell_y]) { + case WALL: { + ch = '#'; + isColored = S4C_BLUE; + } + break; + case BASIC: { + ch = '.'; + isColored = S4C_LIGHT_BROWN; + } + break; + case HOME: { + ch = 'H'; + isColored = S4C_WHITE; + } + break; + case BOSS: { + ch = 'B'; + isColored = S4C_RED; + } + break; + case TREASURE: { + ch = '*'; + isColored = S4C_ORANGE; + } + break; + case SHOP: { + ch = '$'; + isColored = S4C_MAGENTA; + } + break; + case ENEMIES: { + ch = '^'; + isColored = S4C_CYAN; + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "draw_cell(): tried drawing an invalid cell for floor->roomclass_layout[%i][%i].", + cell_x, cell_y); + ch = '?'; + isColored = S4C_DARK_GREEN; + } + break; + } + if (isColored >= 0) { + color = ColorFromS4CPalette(palette, isColored); + }; + DrawRectangle(win->x + ((j + drawcorner_x) * ((int)pixelSize) ), win->y + ((i + drawcorner_y) * ((int)pixelSize)), pixelSize, pixelSize, color); + if (isColored >= 0) { + isColored = -1; + }; + (void) ch; + } + } + if (recurse > 0 && cell_x < FLOOR_MAX_COLS - 1) + draw_cell(floor, cell_x + 1, cell_y, win, drawcorner_x + 3, + drawcorner_y, x_size, y_size, pixelSize, recurse - 1); + if (recurse > 0 && cell_x > 0) + draw_cell(floor, cell_x - 1, cell_y, win, drawcorner_x - 3, + drawcorner_y, x_size, y_size, pixelSize, recurse - 1); + if (recurse > 0 && cell_y < FLOOR_MAX_ROWS - 1) + draw_cell(floor, cell_x, cell_y + 1, win, drawcorner_x, + drawcorner_y + 3, x_size, y_size, pixelSize, recurse - 1); + if (recurse > 0 && cell_y > 0) + draw_cell(floor, cell_x, cell_y - 1, win, drawcorner_x, + drawcorner_y - 3, x_size, y_size, pixelSize, recurse - 1); + } else { + log_tag("debug_log.txt", "[ERROR]", + "draw_cell(): floor->floor_layout[%i][%i] was (%i).", cell_x, + cell_y, floor->floor_layout[cell_x][cell_y]); + log_tag("debug_log.txt", "[ERROR]", + "draw_cell(): floor->roomclass_layout[%i][%i] was (%s).", + cell_x, cell_y, + stringFromRoom(floor->roomclass_layout[cell_x][cell_y])); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a Floor pointer and current x and y position. Draws render using the passed Rectangle as reference position. + * @see Floor + * @see floorClass + */ +void draw_floor_view(Floor *floor, int current_x, int current_y, float pixelSize, Rectangle *win) +{ + if (win == NULL) { + log_tag("debug_log.txt", "[ERROR]", "draw_view(): win was NULL."); + exit(EXIT_FAILURE); + } + int xSize = 3; + int ySize = 3; + + //Center + draw_cell(floor, current_x, current_y, win, 10, 10, xSize, ySize, pixelSize, 3); + + //Draw player char + DrawRectangle( win->x + ((FLOOR_MAX_COLS/2 -1) * pixelSize), win->y + ((FLOOR_MAX_COLS / 2 - 1) * pixelSize), pixelSize, pixelSize, ColorFromS4CPalette(palette, S4C_BLUE)); +} + +/** + * Takes a Floor pointer and cell x and y position. Move one square update passed Rectangle window pointer. + * TODO: add handleRogueMenu() args + * @see Floor + * @see floorClass + */ +void step_floor(Floor *floor, int *current_x, + int *current_y, int control) +{ + + int picked = 0; + int target_x = *current_x; + int target_y = *current_y; + while (!picked && control > 0) { + target_x = *current_x; + target_y = *current_y; + switch (control) { + //TODO + //Implement a working menu for the raylib build + case KEY_DOWN: { + picked = 1; + target_y += 1; + } + break; + case KEY_UP: { + picked = 1; + target_y -= 1; + } + break; + case KEY_LEFT: { + picked = 1; + target_x -= 1; + } + break; + case KEY_RIGHT: { + picked = 1; + target_x += 1; + } + break; + default: { + log_tag("debug_log.txt", "[FLOOR]", + "move_update(): Player char ( %c ) was not accounted for. Target (x=%i,y=%i) class (%s).", + control, target_x, target_y, + stringFromRoom(floor-> + roomclass_layout[target_x][target_y])); + fprintf(stderr, "Invalid char: {%c}\n", control); + return; + } + } + if (floor->floor_layout[target_x][target_y] != 1) { + fprintf(stderr, "%s\n", "floor->floor_layout[target_x][target_y] was not 1."); + return; + } else { + if (floor->roomclass_layout[target_x][target_y] != WALL + && floor->floor_layout[target_x][target_y] > 0) { + if (floor->explored_matrix[target_x][target_y] == 0) { + floor->explored_matrix[target_x][target_y] = 1; + (floor->explored_area)++; + log_tag("debug_log.txt", "[FLOOR]", + "move_update(): target x[%i],y[%i] was not walked before. Class: (%s).", + target_x, target_y, + stringFromRoom(floor-> + roomclass_layout[target_x] + [target_y])); + log_tag("debug_log.txt", "[FLOOR]", + "move_update(): explored area [%i].", + floor->explored_area); + } else { + log_tag("debug_log.txt", "[FLOOR]", + "move_update(): target x[%i],y[%i] was walked before. Class: (%s).", + target_x, target_y, + stringFromRoom(floor-> + roomclass_layout[target_x] + [target_y])); + log_tag("debug_log.txt", "[FLOOR]", + "move_update(): explored area [%i], tot area [%i].", + floor->explored_area, floor->area); + } + *current_x = target_x; + *current_y = target_y; + //draw_floor_view(floor, *current_x, *current_y, pixelSize, win); + } else { + picked = 0; + log_tag("debug_log.txt", "[DEBUG]", + "Bonked in a wall in move_update()."); + fprintf(stderr, "%s\n", "BONK!"); + return; + } + + switch (floor->roomclass_layout[target_x][target_y]) { + default: { + log_tag("debug_log.txt", "[FLOOR]", + "move_update(): target x[%i],y[%i] was of class (%s).", + target_x, target_y, + stringFromRoom(floor-> + roomclass_layout[target_x] + [target_y])); + } + } + } + } +} +#endif // HELAPORDO_RAYLIB_BUILD #endif // HELAPORDO_CURSES_BUILD diff --git a/src/floors.h b/src/utils/floors.h similarity index 76% rename from src/floors.h rename to src/utils/floors.h index a6455f5e..247673d1 100644 --- a/src/floors.h +++ b/src/utils/floors.h @@ -18,7 +18,6 @@ #ifndef FLOORS_H #define FLOORS_H -#include #include #include "game_utils.h" @@ -33,11 +32,11 @@ void debug_print_roomclass_layout(Floor * floor, FILE * fp); void debug_print_floor_layout(Floor * floor, FILE * fp); #ifdef HELAPORDO_CURSES_BUILD -#include "game_curses.h" +#include "../build-nc/game_curses.h" +void display_roomclass_layout(Floor * floor, WINDOW * win); void display_floor_layout(Floor * floor, WINDOW * win); void display_explored_layout(Floor * floor, WINDOW * win); -void display_roomclass_layout(Floor * floor, WINDOW * win); void draw_cell(Floor * floor, int cell_x, int cell_y, WINDOW * win, int drawcorner_x, int drawcorner_y, int x_size, int y_size, @@ -52,6 +51,15 @@ void move_update(Gamestate * gamestate, Floor * floor, int *current_x, #ifndef HELAPORDO_RAYLIB_BUILD #error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." #else +void display_roomclass_layout(Floor *floor, Rectangle *win, float pixelSize); +void display_floor_layout(Floor * floor, Rectangle * win, float pixelSize); +void display_explored_layout(Floor *floor, Rectangle *win, float pixelSize); +void draw_cell(Floor * floor, int cell_x, int cell_y, Rectangle * win, + int drawcorner_x, int drawcorner_y, int x_size, int y_size, float pixelSize, + int recurse); +void draw_floor_view(Floor * floor, int current_x, int current_y, float pixelSize, Rectangle * win); +void step_floor(Floor * floor, int *current_x, + int *current_y, int control); #endif // HELAPORDO_RAYLIB_BUILD #endif // HELAPORDO_CURSES_BUILD diff --git a/src/utils/game_debug.c b/src/utils/game_debug.c new file mode 100644 index 00000000..8edbf8de --- /dev/null +++ b/src/utils/game_debug.c @@ -0,0 +1,1347 @@ +#include "game_debug.h" + +#ifdef HELAPORDO_CURSES_BUILD +/** + * Takes a Fighter and a Path pointers (and an integer for current room index) and asks user input to execute debug actions. + * @see Fighter + * @see Path + * @see statReset() + * @see GET_CALLBACK() + * @see unlock_special() + * @param gmst The Gamestate pointer. + * @param player The Fighter pointer at hand. + * @param p The Path pointer of the current game. + * @param roomIndex The index of current room. + * @param The Koliseo to debug. + * @param The Koliseo_Temp used for allocations. + */ +void debug_generic(Gamestate *gmst, Fighter *player, Path *p, int roomIndex, + Koliseo *kls, Koliseo_Temp *t_kls) +{ + + char msg[200]; + char ch[25]; + int picked_debug_proc = 0; +#ifndef _WIN32 + struct utsname uts; + uname(&uts); + sprintf(msg, "debug_generic() loaded utsname using uname().\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "System is %s\n", uts.sysname); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "OS Release is %s\n", uts.release); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "OS Version is %s\n", uts.version); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "Machine is %s\n", uts.machine); + log_tag("debug_log.txt", "[DEBUG]", msg); +#endif + + int res = system("clear"); + sprintf(msg, "debug_generic() system(\"clear\") res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + + int c = 0, n = -1; + while (!picked_debug_proc) { + int res = system("clear"); + sprintf(msg, "debug_generic() 2 system(\"clear\") res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + printf("\n\ + What do you want to do? ('q' to quit)\n\ + [\n\ + '0': Give xp points\t'1': Give consumable\n\ + '2': Reset stats\t'3': Alter luck\n\ + '4': Give coins\t'5': Unlock special\n\ + '6': Unlock Artifact\t'7': Print turnCounter\n\ + 's': Sprites slideshow\t'd': Dump debug symbols\n\ + 'g': Toggle godmode\t'A': Toggle autosave\n\ + 'L': Toggle logging\t'F': Try Floor functionality\n\ + 'Q': Toggle fast quit\t'k': Log passed kls state to debug log file.\n\ + 't': Log global temporary_kls state to debug log file.\n\ + 'K': Log usage stats for passed kls to debug log file.\n\ + 'T': Log usage stats for temporary_kls to debug log file.\n\ + 'G': Log Gamestate to debug log file.\n\ + {Return} Process your input line.\t'q': Quit\n\ + ]\n\n\ + [%s@debug-func]$ ", player->name); + + char *fgetsres = fgets(ch, sizeof ch, stdin); + sprintf(msg, "debug_generic() fgets() res was (%s)", fgetsres); + log_tag("debug_log.txt", "[DEBUG]", msg); + switch (ch[0]) { + case '0': { + picked_debug_proc = 1; + int xp; + do { + printf("\nHow much?\n"); + } while ((c = scanf("%i", &xp)) != 1 || xp < 0); + int res = scanf("%*c"); + sprintf(msg, "debug_generic() scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + checkremainder(player, xp); + } + break; + case '1': { + picked_debug_proc = 1; + int q = -1; + do { + printf("\nInsert consumable number:\n"); + } while ((c = scanf("%i", &n)) != 1 || n > CONSUMABLESMAX + || n < 0); + int res = scanf("%*c"); + sprintf(msg, "debug_generic() scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + do { + printf("\nInsert quantity:\n"); + } while ((c = scanf("%i", &q)) != 1 && q <= 0); + res = scanf("%*c"); + sprintf(msg, "debug_generic() 2 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + Consumable *c = (Consumable *) player->consumablesBag[n]; + c->qty += q; + player->stats->consumablesfound += q; + } + break; + case '2': { + picked_debug_proc = 1; + statReset(player, 1); + } + break; + case '3': { + picked_debug_proc = 1; + printf("\nCurrent luck: %i\tRL: %i\n", player->luck, p->luck); + + do { + printf("\nInsert new luck:\n"); + } while ((c = scanf("%i", &n)) != 1 && n > 0); + int res = scanf("%*c"); + sprintf(msg, "debug_generic() 3 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + //FIXME: + //Copy-pasted the calc for player luck... might need a function + p->luck = n; + + player->luck = (p->luck * MAXPLAYERLUCK) / MAXLUCK; + } + break; + case '4': { + picked_debug_proc = 1; + /* Old code invoking the macro for special moves directly. Used for testing. + * int s = -1; + * printf("Insert special num:\n"); + * scanf("%i",&s); + * scanf("%*c"); + * printf("Read: %i\n",s); + * GET_CALLBACK(s,callback_special_t)(player,e,p,roomIndex,currentEnemyNum); + */ + + //printActivePerks(player); + int c; + int n = -1; + do { + printf("\nInsert coin number (0 3 || n < 0 + || n > 100); + int res = scanf("%*c"); + sprintf(msg, "debug_generic() 4 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + player->balance += n; + } + break; + case '5': { + picked_debug_proc = 1; + unlockSpecial(player); + } + break; + case '6': { + picked_debug_proc = 1; + int n = -1; + do { + printf("\nInsert artifact number (0 ARTIFACTSMAX + || n < 0); + + int res = scanf("%*c"); + sprintf(msg, "debug_generic() scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + player->artifactsBag[n]->qty += 1; + player->artifactsBag[n]->active = 0; + player->stats->artifactsfound += 1; + } + break; + case '7': { + picked_debug_proc = 1; + int res = system("clear"); + sprintf(msg, "debug_generic() 3 system(\"clear\") res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + printf("\nPlayer Counters:\n"); + printCounters((Turncounter **) player->counters); + printf("\nPress Enter to resume game"); + res = scanf("%*c"); + sprintf(msg, "debug_generic() 5 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'd': { + picked_debug_proc = 1; + printf("\nVERSION: %s\n", VERSION); +#ifndef _WIN32 + printf("\nSystem: %s\n", uts.sysname); + printf("\nOS Release: %s\n", uts.release); + printf("\nOS Version: %s\n", uts.version); + printf("\nMachine: %s\n", uts.machine); +#endif + printf("\nGAMEMODE: %s\n", stringFromGamemode(GAMEMODE)); + printf("\nPath->current_saveslot->save_path: %s\n", + p->current_saveslot->save_path); + printf("\nGS_AUTOSAVE_ON: %i\n", GS_AUTOSAVE_ON); + printf("\nG_FASTQUIT_ON: %i\n", G_FASTQUIT_ON); + printf("\nG_DEBUG_ON: %i\n", G_DEBUG_ON); + printf("\nG_LOG_ON: %i\n", G_LOG_ON); + printf("\nG_GODMODE_ON: %i\n", G_GODMODE_ON); + printf("\nG_EXPERIMENTAL_ON: %i\n", G_EXPERIMENTAL_ON); + printf("\nG_DEBUG_ROOMTYPE_ON: %i\n", G_DEBUG_ROOMTYPE_ON); + if (G_DEBUG_ROOMTYPE_ON == 1) { + printf("\nG_DEBUG_ROOMTYPE: %i\n", G_DEBUG_ROOMTYPE); + } + printf("\nG_DEBUG_ENEMYTYPE_ON: %i\n", G_DEBUG_ENEMYTYPE_ON); + if (G_DEBUG_ENEMYTYPE_ON == 1) { + printf("\nG_DEBUG_ENEMYTYPE: %i\n", G_DEBUG_ENEMYTYPE); + } + printf("\nPress Enter to resume game.\n"); + int res = scanf("%*c"); + sprintf(msg, "debug_generic() 7 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'F': { + sprintf(msg, "Trying out Floor functionality."); + log_tag("debug_log.txt", "[DEBUG]", msg); + // Declare dbg_floor + sprintf(msg, "Pushing dbg_floor to tkls."); + log_tag("debug_log.txt", "[DEBUG]", msg); + kls_log(kls, "DEBUG", msg); + Floor *dbg_floor = + (Floor *) KLS_PUSH_T_TYPED(t_kls, Floor, HR_Floor, + "Floor", msg); + // Start the random walk from the center of the dungeon + int center_x = FLOOR_MAX_COLS / 2; + int center_y = FLOOR_MAX_ROWS / 2; + // Init dbg_floor + init_floor_layout(dbg_floor); + //Set center as filled + dbg_floor->floor_layout[center_x][center_y] = 1; + + init_floor_rooms(dbg_floor); + + floor_random_walk(dbg_floor, center_x, center_y, 100, 1); // Perform 100 steps of random walk, reload floor_layout if needed + load_floor_explored(dbg_floor); + + floor_set_room_types(dbg_floor); + + /* + debug_print_floor_layout(dbg_floor); + + printf("\nPress Enter to see room layout.\n"); + int res = scanf("%*c"); + sprintf(msg,"debug_generic() 7 scanf() res was (%i)", res); + log_tag("debug_log.txt","[DEBUG]",msg); + */ + debug_print_roomclass_layout(dbg_floor, stdout); + printf("\nPress Enter to return to game.\n"); + res = scanf("%*c"); + sprintf(msg, "debug_generic() 8 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + //free(dbg_floor); + } + break; + case 'A': { + GS_AUTOSAVE_ON = (GS_AUTOSAVE_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_AUTOSAVE_ON, new value: (%i)", + GS_AUTOSAVE_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'G': { + log_tag("debug_log.txt", "[DEBUG]", "Logging Gamestate"); + dbg_Gamestate(gmst); + log_tag("debug_log.txt", "[DEBUG]", "Done logging Gamestate"); + } + break; + case 'T': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + + fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); + for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { + ptrdiff_t usage = kls_type_usage(i, temporary_kls); +#ifndef _WIN32 + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#else + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#endif + } + fprintf(kls_file, "--END debug of temporary_kls--\n\n"); + + fclose(kls_file); + } + break; + case 't': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); + print_kls_2file(kls_file, temporary_kls); + kls_showList_toFile(temporary_kls->regs, kls_file); + kls_usageReport_toFile(temporary_kls, kls_file); + fprintf(kls_file, "--END debug of temporary_kls--\n\n"); + WINDOW *win = NULL; + /* Initialize curses */ + clear(); + refresh(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + win = newwin(20, 50, 1, 2); + keypad(win, TRUE); + wclear(win); + wrefresh(win); + kls_showList_toWin(temporary_kls, win); + delwin(win); + endwin(); + + fclose(kls_file); + } + break; + case 'K': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + + fprintf(kls_file, "--BEGIN debug of passed kls--\n"); + for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { + ptrdiff_t usage = kls_type_usage(i, kls); +#ifndef _WIN32 + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#else + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#endif + } + fprintf(kls_file, "--END debug of passed kls--\n\n"); + + fclose(kls_file); + } + break; + case 'k': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + fprintf(kls_file, "--BEGIN debug of passed kls--\n"); + print_kls_2file(kls_file, kls); + kls_showList_toFile(kls->regs, kls_file); + kls_usageReport_toFile(kls, kls_file); + fprintf(kls_file, "--END debug of passed kls--\n\n"); + WINDOW *win = NULL; + /* Initialize curses */ + clear(); + refresh(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + win = newwin(20, 50, 1, 2); + keypad(win, TRUE); + wclear(win); + wrefresh(win); + kls_showList_toWin(kls, win); + delwin(win); + endwin(); + + fclose(kls_file); + } + break; + case 'Q': { + G_FASTQUIT_ON = (G_FASTQUIT_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_FASTQUIT_ON, new value: (%i)", + G_FASTQUIT_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'g': { + G_GODMODE_ON = (G_GODMODE_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_GODMODE_ON, new value: (%i)", + G_GODMODE_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'L': { + G_LOG_ON = (G_LOG_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_LOG_ON, new value: (%i)", G_LOG_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + case 's': { //Query sprites slideshow + picked_debug_proc = 1; + int res = system("clear"); + sprintf(msg, "debug_generic() 4 system(\"clear\") res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + int comm_len = -1; + int picked_comm = 0; + char comm[15] = "empty"; + char *desc = NULL; + int sprite_total = -1; + int tot_cons = CONSUMABLESMAX + 1; + int tot_enemy = ENEMYCLASSESMAX + 1; + int tot_boss = BOSSCLASSESMAX + 1; + int tot_art = ARTIFACTSMAX + 1; + int tot_eq = EQUIPSMAX + 1; + int tot_eqzones = EQUIPZONES + 1; + int tot_misc = MISC_SPRITES_MAX + 1; + int allsprites = + tot_cons + + tot_enemy + + tot_boss + tot_art + tot_eq + tot_eqzones + tot_misc; + + printf("\nConsumables sprites: \t%d\ +\nArtifacts sprites: \t%d\ +\nEquips sprites: \t%d\ +\nEquip zone sprites: \t%d\ +\nEnemies sprites: \t%d\ +\nBosses sprites: \t%d\ +\nOther misc sprites: \t%d\n", tot_cons, tot_art, tot_eq, tot_eqzones, tot_enemy, tot_boss, tot_misc); + printf("--------------------------"); + printf("\nTotal sprites: \t\t%d\n", allsprites); + printf + ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", + player->name); + while (!picked_comm && (comm_len = scanf("%10s", comm)) > -1) { + int res = scanf("%*c"); + sprintf(msg, "debug_generic() 7 scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + if (strcmp(comm, "q") == 0) { + return; + } else if (strcmp(comm, "boss") == 0) { + picked_comm = 1; + sprite_total = BOSSCLASSESMAX + 1; + } else if (strcmp(comm, "cons") == 0) { + picked_comm = 1; + sprite_total = CONSUMABLESMAX + 1; + } else if (strcmp(comm, "equip") == 0) { + picked_comm = 1; + sprite_total = EQUIPSMAX + 1; + } else if (strcmp(comm, "eqzone") == 0) { + picked_comm = 1; + sprite_total = EQUIPZONES + 1; + } else if (strcmp(comm, "artf") == 0) { + picked_comm = 1; + sprite_total = ARTIFACTSMAX + 1; + } else if (strcmp(comm, "enemy") == 0) { + picked_comm = 1; + sprite_total = ENEMYCLASSESMAX + 1; + } else if (strcmp(comm, "misc") == 0) { + picked_comm = 1; + sprite_total = MISC_SPRITES_MAX + 1; + } else { + printf + ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", + player->name); + } + } + int sprite_count = -1; + int c = -1; + char s[20]; + int startx = 0; + int x, y; + WINDOW *spriteshow_win; + /* Initialize curses */ + //initscr(); + start_color(); + clear(); + refresh(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + spriteshow_win = newwin(19, 19, 2, 2); + keypad(spriteshow_win, TRUE); + for (sprite_count = 0; sprite_count < sprite_total; + sprite_count++) { + if (strcmp(comm, "boss") == 0) { + desc = stringFromBossClass(sprite_count); + } else if (strcmp(comm, "cons") == 0) { + desc = stringFromConsumables(sprite_count); + } else if (strcmp(comm, "equip") == 0) { + desc = stringFromEquips(sprite_count); + } else if (strcmp(comm, "eqzone") == 0) { + desc = stringFromEquipzones(sprite_count); + } else if (strcmp(comm, "artf") == 0) { + desc = stringFromArtifacts(sprite_count); + } else if (strcmp(comm, "enemy") == 0) { + desc = stringFromEClass(sprite_count); + } else if (strcmp(comm, "misc") == 0) { + desc = "Misc"; + } + wclear(spriteshow_win); + wrefresh(spriteshow_win); + wclear(stdscr); + wrefresh(stdscr); + sprintf(msg, "Showing sprite n.%d, class is: %s\n", + sprite_count, desc); + log_tag("debug_log.txt", "[DEBUG]", msg); + mvwprintw(stdscr, 5, 20, "Sprite for: \'%s\'", desc); + mvwprintw(stdscr, 7, 20, "(%i/%i)", sprite_count + 1, + sprite_total); + refresh(); + for (int i = 0; i < 8; i++) { + if (strcmp(comm, "boss") == 0) { + strcpy(s, bosses_sprites[sprite_count][i]); + } else if (strcmp(comm, "cons") == 0) { + strcpy(s, consumables_sprites[sprite_count][i]); + } else if (strcmp(comm, "equip") == 0) { + strcpy(s, equips_sprites[sprite_count][i]); + } else if (strcmp(comm, "eqzone") == 0) { + strcpy(s, equipzones_sprites[sprite_count][i]); + } else if (strcmp(comm, "artf") == 0) { + strcpy(s, artifacts_sprites[sprite_count][i]); + } else if (strcmp(comm, "enemy") == 0) { + strcpy(s, enemies_sprites[sprite_count][i]); + } else if (strcmp(comm, "misc") == 0) { + strcpy(s, misc_sprites[sprite_count][i]); + } + //sprintf(msg,"[DEBUG] Copied string: \'%s\'\n", s); + //debug_log("debug_log.txt",msg); + + for (int j = 0; j < 13; j++) { + x = startx + 1 + j; + y = 1 + i; + + print_encoded_char(spriteshow_win, y, x, s[j]); + } //End for line print + } //End for sprite print + + wrefresh(spriteshow_win); + //printf("\nPress Enter for next, q to quit.\n"); + int picked = 0; + int go_previous = 0; + int quit_show = 0; + while (!picked + && ((c = wgetch(spriteshow_win)) != KEY_F(1))) { + if (c == 10 || c == KEY_RIGHT) { //Enter, right + sprintf(msg, "Going to next sprite.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + wclear(spriteshow_win); + wrefresh(spriteshow_win); + picked = 1; + continue; //Go to next sprite + } else if (c == 'q') { //Quit + sprintf(msg, "Stopping query sprite show.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + picked = 1; + quit_show = 1; + } else if (c == KEY_LEFT) { //Go to previous sprite + go_previous = 1; + sprintf(msg, "Going to previous sprite.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + picked = 1; + } else { //Unexpected char + sprintf(msg, + "Wrong operation. Continuing with next sprite.\n"); + log_tag("debug_log.txt", "\033[1;31m[ERROR]", msg); + picked = 1; + continue; //We still go to next sprite + } + } //End while wait for user input + if (go_previous) { + sprite_count--; + sprite_count--; + if (sprite_count < -1) + sprite_count = -1; + go_previous = 0; + } + if (quit_show) { + break; + } + } //End for all sprites + sprintf(msg, "End of sprite show.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + + delwin(spriteshow_win); + endwin(); + } + break; + case 'q': { + return; + } + default: { //Echo the passed char and ask for one more. + char cmd[50]; + sprintf(cmd, "\necho \"%c\\n\"\n%c\n\n", ch[0], ch[0]); + printf("%s", cmd); + napms(500); + } + break; + } //Close switch on ch[0] + } //Close while !picked_debug_proc + + res = system("clear"); + sprintf(msg, "debug_generic() final system(\"clear\") res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); +} + +/** + * Takes a Room, a Fighter, a Enemy and a Path pointers (and integers for current room and enemy indexes) and asks user input to execute debug actions. + * @see Room + * @see Fighter + * @see Enemy + * @see Path + * @see checkremainder() + * @see statReset() + * @see statResetEnemy() + * @see GET_CALLBACK() + * @see unlock_special() + * @see printCounters() + * @see dropEquip() + * @param gmst The Gamestate pointer. + * @param player The Fighter pointer at hand. + * @param e The Enemy pointer for current enemy. + * @param p The Path pointer of the current game. + * @param roomIndex The index of current room. + * @param currentEnemyNum The index of current enemy. + * @param kls The Koliseo used for allocations. + * @param t_kls The Koliseo_Temp used for temporary allocations. + */ +void debug_enemies_room(Gamestate *gmst, Room *room, Fighter *player, Enemy *e, + Path *p, int roomIndex, int currentEnemyNum, + Koliseo *kls, Koliseo_Temp *t_kls) +{ + + char msg[200]; + char ch[25]; + int picked_debug_proc = 0; +#ifndef _WIN32 + struct utsname uts; + uname(&uts); + sprintf(msg, "debug_enemies_room() loaded utsname using uname().\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "System is %s\n", uts.sysname); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "OS Release is %s\n", uts.release); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "OS Version is %s\n", uts.version); + log_tag("debug_log.txt", "[DEBUG]", msg); + sprintf(msg, "Machine is %s\n", uts.machine); + log_tag("debug_log.txt", "[DEBUG]", msg); +#endif + + int res = system("clear"); + sprintf(msg, "debug_enemies_room() system(\"clear\") res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + + int c = 0, n = -1; + while (!picked_debug_proc) { + int res = system("clear"); + sprintf(msg, "debug_enemies_room() 2 system(\"clear\") res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + printf("\n\ + What do you want to do? ('q' to quit)\n\ + [\n\ + '0': Give xp points\t'1': Give consumable\n\ + '2': Reset stats\t'3': Reset Enemy\n\ + '4': Alter luck\t'5': Give coins\n\ + '6': Unlock special\t'7': Unlock Artifact\n\ + '8': Print counters\t'9': Give Equip\n\ + 's': Sprites slideshow\t'd': Dump debug symbols\n\ + 'f': Show foes info\t'g': Toggle godmode\n\ + 'A': Toggle autosave\t'Q': Toggle fast quit\n\ + 'L': Toggle logging\t'k': Log passed Koliseo info\n\ + 't': Log global temporary_kls Koliseo info\n\ + 'K': Log usage stats for passed kls to debug log file.\n\ + 'T': Log usage stats for temporary_kls to debug log file.\n\ + 'G': Log Gamestate to debug log file.\n\ + 'q': Quit\t{Return} Process your input line.\n\ + ]\n\n\ + [%s@debug-func]$ ", player->name); + + char *fgetsres = fgets(ch, sizeof ch, stdin); + sprintf(msg, "debug_enemies_room() fgets() res was (%s)", fgetsres); + log_tag("debug_log.txt", "[DEBUG]", msg); + switch (ch[0]) { + case '0': { + picked_debug_proc = 1; + int xp; + do { + printf("\nHow much?\n"); + } while ((c = scanf("%i", &xp)) != 1 || xp < 0); + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + checkremainder(player, xp); + } + break; + case '1': { + picked_debug_proc = 1; + int q = -1; + do { + printf("\nInsert consumable number:\n"); + } while ((c = scanf("%i", &n)) != 1 || n > CONSUMABLESMAX + || n < 0); + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + do { + printf("\nInsert quantity:\n"); + } while ((c = scanf("%i", &q)) != 1 && q <= 0); + res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 2 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + Consumable *c = (Consumable *) player->consumablesBag[n]; + c->qty += q; + player->stats->consumablesfound += q; + } + break; + case '2': { + picked_debug_proc = 1; + statReset(player, 1); + } + break; + case '3': { + picked_debug_proc = 1; + statResetEnemy(e, 1); + } + break; + case '4': { + picked_debug_proc = 1; + printf("\nCurrent luck: %i\tRL: %i\n", player->luck, p->luck); + + do { + printf("\nInsert new luck:\n"); + } while ((c = scanf("%i", &n)) != 1 && n > 0); + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 3 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + //FIXME: + //Copy-pasted the calc for player luck... might need a function + p->luck = n; + + player->luck = (p->luck * MAXPLAYERLUCK) / MAXLUCK; + } + break; + case '5': { + picked_debug_proc = 1; + /* Old code invoking the macro for special moves directly. Used for testing. + * int s = -1; + * printf("Insert special num:\n"); + * scanf("%i",&s); + * scanf("%*c"); + * printf("Read: %i\n",s); + * GET_CALLBACK(s,callback_special_t)(player,e,p,roomIndex,currentEnemyNum); + */ + + //printActivePerks(player); + int c; + int n = -1; + do { + printf("\nInsert coin number (0 3 || n < 0 + || n > 100); + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 4 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + player->balance += n; + } + break; + case '6': { + picked_debug_proc = 1; + unlockSpecial(player); + } + break; + case '7': { + picked_debug_proc = 1; + int n = -1; + do { + printf("\nInsert artifact number (0 ARTIFACTSMAX + || n < 0); + + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() scanf() res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + player->artifactsBag[n]->qty += 1; + player->artifactsBag[n]->active = 0; + player->stats->artifactsfound += 1; + } + break; + case '8': { + picked_debug_proc = 1; + int res = system("clear"); + sprintf(msg, + "debug_enemies_room() 3 system(\"clear\") res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + printf("\nPlayer Counters:\n"); + printCounters((Turncounter **) player->counters); + printf("\nEnemy (%s) Counters:\n", stringFromEClass(e->class)); + printCounters((Turncounter **) e->counters); + printf("\nPress Enter to resume game"); + res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 5 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case '9': { + picked_debug_proc = 1; + int q = -1; + int c = -1; + do { + printf("\nInsert quantity:\n"); + } while ((c = scanf("%i", &q)) != 1 && q <= 0); + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 6 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + + //TODO: handle dropping an equip with a new notification window + //for (int i=0; icurrent_saveslot->save_path: %s\n", + p->current_saveslot->save_path); + printf("\nGS_AUTOSAVE_ON: %i\n", GS_AUTOSAVE_ON); + printf("\nG_FASTQUIT_ON: %i\n", G_FASTQUIT_ON); + printf("\nG_DEBUG_ON: %i\n", G_DEBUG_ON); + printf("\nG_LOG_ON: %i\n", G_LOG_ON); + printf("\nG_GODMODE_ON: %i\n", G_GODMODE_ON); + printf("\nG_EXPERIMENTAL_ON: %i\n", G_EXPERIMENTAL_ON); + printf("\nG_DEBUG_ROOMTYPE_ON: %i\n", G_DEBUG_ROOMTYPE_ON); + if (G_DEBUG_ROOMTYPE_ON == 1) { + printf("\nG_DEBUG_ROOMTYPE: %i\n", G_DEBUG_ROOMTYPE); + } + printf("\nG_DEBUG_ENEMYTYPE_ON: %i\n", G_DEBUG_ENEMYTYPE_ON); + if (G_DEBUG_ENEMYTYPE_ON == 1) { + printf("\nG_DEBUG_ENEMYTYPE: %i\n", G_DEBUG_ENEMYTYPE); + } + printf("\nPress Enter to resume game.\n"); + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 7 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'f': { + clear(); + refresh(); + debug_printFoeParty(room->foes); + } + break; + case 'G': { + log_tag("debug_log.txt", "[DEBUG]", "Logging Gamestate"); + dbg_Gamestate(gmst); + log_tag("debug_log.txt", "[DEBUG]", "Done logging Gamestate"); + } + break; + case 'T': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + + fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); + for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { + ptrdiff_t usage = kls_type_usage(i, temporary_kls); +#ifndef _WIN32 + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#else + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#endif + } + fprintf(kls_file, "--END debug of temporary_kls--\n\n"); + + fclose(kls_file); + } + break; + case 't': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + fprintf(kls_file, "--BEGIN debug of temporary_kls--\n"); + print_kls_2file(kls_file, temporary_kls); + kls_showList_toFile(temporary_kls->regs, kls_file); + kls_usageReport_toFile(temporary_kls, kls_file); + fprintf(kls_file, "--END debug of temporary_kls--\n\n"); + WINDOW *win = NULL; + /* Initialize curses */ + clear(); + refresh(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + win = newwin(20, 50, 1, 2); + keypad(win, TRUE); + wclear(win); + wrefresh(win); + kls_showList_toWin(temporary_kls, win); + delwin(win); + endwin(); + + fclose(kls_file); + } + break; + case 'K': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + + fprintf(kls_file, "--BEGIN debug of passed kls--\n"); + for (int i = HR_Path; i < HLP_MAX_INDEX + 99; i++) { + ptrdiff_t usage = kls_type_usage(i, kls); +#ifndef _WIN32 + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %li }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#else + fprintf(kls_file, + "Usage for HLP_Region_Type { %s } [Index: %i] {Size: %lli }\n", + stringFrom_HLP_Region_Type(i - 101 + + KLS_REGIONTYPE_MAX), i, + usage); +#endif + } + fprintf(kls_file, "--END debug of passed kls--\n\n"); + + fclose(kls_file); + } + break; + case 'k': { + char path_to_kls_file[600]; + char static_path[500]; + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + //Append to "kls_log.txt" + sprintf(path_to_kls_file, "%s/%s", static_path, + "debug_log.txt"); + FILE *kls_file = NULL; + kls_file = fopen(path_to_kls_file, "a"); + if (kls_file == NULL) { + fprintf(stderr, + "debug_generic(): failed opening debug logfile.\n"); + exit(EXIT_FAILURE); + } + if (kls == NULL) { + fprintf(stderr, "debug_generic(): kls was NULL.\n"); + exit(EXIT_FAILURE); + } + fprintf(kls_file, "--BEGIN debug of passed kls--\n"); + print_kls_2file(kls_file, kls); + kls_showList_toFile(kls->regs, kls_file); + kls_usageReport_toFile(kls, kls_file); + fprintf(kls_file, "--END debug of passed kls--\n\n"); + WINDOW *win = NULL; + /* Initialize curses */ + clear(); + refresh(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + win = newwin(20, 50, 1, 2); + keypad(win, TRUE); + wclear(win); + wrefresh(win); + kls_showList_toWin(kls, win); + delwin(win); + endwin(); + fclose(kls_file); + } + break; + case 'A': { + GS_AUTOSAVE_ON = (GS_AUTOSAVE_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_AUTOSAVE_ON, new value: (%i)", + GS_AUTOSAVE_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'Q': { + G_FASTQUIT_ON = (G_FASTQUIT_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_FASTQUIT_ON, new value: (%i)", + G_FASTQUIT_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'L': { + G_LOG_ON = (G_LOG_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_LOG_ON, new value: (%i)", G_LOG_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 'g': { + G_GODMODE_ON = (G_GODMODE_ON == 1 ? 0 : 1); + sprintf(msg, "Toggled G_GODMODE_ON, new value: (%i)", + G_GODMODE_ON); + log_tag("debug_log.txt", "[DEBUG]", msg); + } + break; + case 's': { //Query sprites slideshow + picked_debug_proc = 1; + int res = system("clear"); + sprintf(msg, + "debug_enemies_room() 4 system(\"clear\") res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + int comm_len = -1; + int picked_comm = 0; + char comm[15] = "empty"; + char *desc = NULL; + int sprite_total = -1; + int tot_cons = CONSUMABLESMAX + 1; + int tot_enemy = ENEMYCLASSESMAX + 1; + int tot_boss = BOSSCLASSESMAX + 1; + int tot_art = ARTIFACTSMAX + 1; + int tot_eq = EQUIPSMAX + 1; + int tot_eqzones = EQUIPZONES + 1; + int tot_misc = MISC_SPRITES_MAX + 1; + int allsprites = + tot_cons + + tot_enemy + + tot_boss + tot_art + tot_eq + tot_eqzones + tot_misc; + + printf("\nConsumables sprites: \t%d\ +\nArtifacts sprites: \t%d\ +\nEquips sprites: \t%d\ +\nEquip zone sprites: \t%d\ +\nEnemies sprites: \t%d\ +\nBosses sprites: \t%d\ +\nOther misc sprites: \t%d\n", tot_cons, tot_art, tot_eq, tot_eqzones, tot_enemy, tot_boss, tot_misc); + printf("--------------------------"); + printf("\nTotal sprites: \t\t%d\n", allsprites); + printf + ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", + player->name); + while (!picked_comm && (comm_len = scanf("%10s", comm)) > -1) { + int res = scanf("%*c"); + sprintf(msg, "debug_enemies_room() 7 scanf() res was (%i)", + res); + log_tag("debug_log.txt", "[DEBUG]", msg); + if (strcmp(comm, "q") == 0) { + return; + } else if (strcmp(comm, "boss") == 0) { + picked_comm = 1; + sprite_total = BOSSCLASSESMAX + 1; + } else if (strcmp(comm, "cons") == 0) { + picked_comm = 1; + sprite_total = CONSUMABLESMAX + 1; + } else if (strcmp(comm, "equip") == 0) { + picked_comm = 1; + sprite_total = EQUIPSMAX + 1; + } else if (strcmp(comm, "eqzone") == 0) { + picked_comm = 1; + sprite_total = EQUIPZONES + 1; + } else if (strcmp(comm, "artf") == 0) { + picked_comm = 1; + sprite_total = ARTIFACTSMAX + 1; + } else if (strcmp(comm, "enemy") == 0) { + picked_comm = 1; + sprite_total = ENEMYCLASSESMAX + 1; + } else if (strcmp(comm, "misc") == 0) { + picked_comm = 1; + sprite_total = MISC_SPRITES_MAX + 1; + } else { + printf + ("\nInsert sprites query, q to quit: (q|boss|cons|equip|eqzone|artf|enemy|misc):\n\n[%s@spriteshow]$ ", + player->name); + } + } + int sprite_count = -1; + int c = -1; + char s[20]; + int startx = 0; + int x, y; + WINDOW *spriteshow_win; + /* Initialize curses */ + //initscr(); + start_color(); + clear(); + refresh(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + spriteshow_win = newwin(19, 19, 2, 2); + keypad(spriteshow_win, TRUE); + for (sprite_count = 0; sprite_count < sprite_total; + sprite_count++) { + if (strcmp(comm, "boss") == 0) { + desc = stringFromBossClass(sprite_count); + } else if (strcmp(comm, "cons") == 0) { + desc = stringFromConsumables(sprite_count); + } else if (strcmp(comm, "equip") == 0) { + desc = stringFromEquips(sprite_count); + } else if (strcmp(comm, "eqzone") == 0) { + desc = stringFromEquipzones(sprite_count); + } else if (strcmp(comm, "artf") == 0) { + desc = stringFromArtifacts(sprite_count); + } else if (strcmp(comm, "enemy") == 0) { + desc = stringFromEClass(sprite_count); + } else if (strcmp(comm, "misc") == 0) { + desc = "Misc"; + } + wclear(spriteshow_win); + wrefresh(spriteshow_win); + wclear(stdscr); + wrefresh(stdscr); + sprintf(msg, "Showing sprite n.%d, class is: %s\n", + sprite_count, desc); + log_tag("debug_log.txt", "[DEBUG]", msg); + mvwprintw(stdscr, 5, 20, "Sprite for: \'%s\'", desc); + mvwprintw(stdscr, 7, 20, "(%i/%i)", sprite_count + 1, + sprite_total); + refresh(); + for (int i = 0; i < 8; i++) { + if (strcmp(comm, "boss") == 0) { + strcpy(s, bosses_sprites[sprite_count][i]); + } else if (strcmp(comm, "cons") == 0) { + strcpy(s, consumables_sprites[sprite_count][i]); + } else if (strcmp(comm, "equip") == 0) { + strcpy(s, equips_sprites[sprite_count][i]); + } else if (strcmp(comm, "eqzone") == 0) { + strcpy(s, equipzones_sprites[sprite_count][i]); + } else if (strcmp(comm, "artf") == 0) { + strcpy(s, artifacts_sprites[sprite_count][i]); + } else if (strcmp(comm, "enemy") == 0) { + strcpy(s, enemies_sprites[sprite_count][i]); + } else if (strcmp(comm, "misc") == 0) { + strcpy(s, misc_sprites[sprite_count][i]); + } + //sprintf(msg,"[DEBUG] Copied string: \'%s\'\n", s); + //debug_log("debug_log.txt",msg); + + for (int j = 0; j < 13; j++) { + x = startx + 1 + j; + y = 1 + i; + + print_encoded_char(spriteshow_win, y, x, s[j]); + } //End for line print + } //End for sprite print + + wrefresh(spriteshow_win); + //printf("\nPress Enter for next, q to quit.\n"); + int picked = 0; + int go_previous = 0; + int quit_show = 0; + while (!picked + && ((c = wgetch(spriteshow_win)) != KEY_F(1))) { + if (c == 10 || c == KEY_RIGHT) { //Enter, right + sprintf(msg, "Going to next sprite.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + wclear(spriteshow_win); + wrefresh(spriteshow_win); + picked = 1; + continue; //Go to next sprite + } else if (c == 'q') { //Quit + sprintf(msg, "Stopping query sprite show.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + picked = 1; + quit_show = 1; + } else if (c == KEY_LEFT) { //Go to previous sprite + go_previous = 1; + sprintf(msg, "Going to previous sprite.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + picked = 1; + } else { //Unexpected char + sprintf(msg, + "Wrong operation. Continuing with next sprite.\n"); + log_tag("debug_log.txt", "\033[1;31m[ERROR]", msg); + picked = 1; + continue; //We still go to next sprite + } + } //End while wait for user input + if (go_previous) { + sprite_count--; + sprite_count--; + if (sprite_count < -1) + sprite_count = -1; + go_previous = 0; + } + if (quit_show) { + break; + } + } //End for all sprites + sprintf(msg, "End of sprite show.\n"); + log_tag("debug_log.txt", "[DEBUG]", msg); + + delwin(spriteshow_win); + endwin(); + } + break; + case 'q': { + return; + } + default: { //Echo the passed char and ask for one more. + char cmd[50]; + sprintf(cmd, "\necho \"%c\\n\"\n%c\n\n", ch[0], ch[0]); + printf("%s", cmd); + napms(500); + } + break; + } //Close switch on ch[0] + } //Close while !picked_debug_proc + +} + +#endif // HELAPORDO_CURSES_BUILD diff --git a/src/utils/game_debug.h b/src/utils/game_debug.h new file mode 100644 index 00000000..c54f5b0d --- /dev/null +++ b/src/utils/game_debug.h @@ -0,0 +1,18 @@ +#ifndef GAME_DEBUG_H +#define GAME_DEBUG_H + +#include "floors.h" + +#ifdef _WIN32 +#else +#include +#endif // _WIN32 + +#ifdef HELAPORDO_CURSES_BUILD +void debug_generic(Gamestate * gmst, Fighter * player, Path * p, int roomIndex, + Koliseo * kls, Koliseo_Temp * t_kls); +void debug_enemies_room(Gamestate * gmst, Room * room, Fighter * player, + Enemy * e, Path * p, int roomIndex, int currentEnemyNum, + Koliseo * kls, Koliseo_Temp * t_kls); +#endif // HELAPORDO_CURSES_BUILD +#endif // GAME_DEBUG_H diff --git a/src/utils/game_fight.c b/src/utils/game_fight.c new file mode 100644 index 00000000..7d1ea946 --- /dev/null +++ b/src/utils/game_fight.c @@ -0,0 +1,2070 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "game_fight.h" + +#ifdef HELAPORDO_CURSES_BUILD +/** + * Takes a Fighter and a Enemy pointers and compares their stats to determine who gets damaged and returns the fightStatus value. + * Prints notifications to the passed WINDOW pointer. + * On enemy death, there's a chance to call dropConsumable, dropEquip or dropArtifact (guaranteed for beast enemies). + * @see Fighter + * @see Enemy + * @see statReset() + * @see statResetEnemy() + * @see stringFromEClass() + * @see dropConsumable() + * @see dropEquip() + * @see dropArtifact() + * @param player The Fighter pointer at hand. + * @param e The Enemy pointer at hand. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + * @see display_notification() + */ +int fight(Fighter *player, Enemy *e, WINDOW *notify_win, Koliseo *kls) +{ + + fightResult res = FIGHTRES_NO_DMG; + char msg[200]; + //Stat comparisons + // + + int atkdelta = (player->atk + player->equipboost_atk) - e->atk - (rand() % 3) - 1; //Skewed with defender + int defdelta = (player->def + player->equipboost_def) - e->def + (rand() % 2) + 1; //Skewed with attacker + int veldelta = + (player->vel + player->equipboost_vel) - e->vel + (rand() % 3) + 1; + + int atkOnPlayer = + e->atk - (player->def + player->equipboost_def + (player->vel / 6)); + int atkOnEnemy = + (player->atk + player->equipboost_atk) - (e->def + (e->vel / 6)); + + if (G_GODMODE_ON == 1) { + log_tag("debug_log.txt", "[DEBUG]", "fight(): G_GODMODE_ON == 1"); + atkdelta = 100; + defdelta = 100; + veldelta = 100; + atkOnPlayer = 1; + atkOnEnemy = 100; + } + + int damageDealt = -1; + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkdelta %i", atkdelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "defdelta %i", defdelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "veldelta %i", veldelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnEnemy %i", atkOnEnemy); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnPlayer %i", atkOnPlayer); + + if (veldelta >= 0) { + + if (atkOnEnemy > 3) { + damageDealt = atkOnEnemy; + e->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result A WIN (faster, great atk)."); + } else if (atkOnEnemy >= 0) { + damageDealt = abs(atkOnEnemy - atkdelta); + e->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result B WIN (faster, ok atk)."); + } else { + if (atkOnEnemy > -3) { + damageDealt = + fabsf(atkOnPlayer - + 0.75F * (player->vel + player->equipboost_vel)); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result C1 LOST (faster, atk > -3)."); + } else { + damageDealt = abs(atkOnPlayer - 1); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result C2 LOST (faster, atk < -3)."); + } + player->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + } + } else { + atkdelta = -atkdelta; + if (atkOnPlayer > 3) { + damageDealt = atkOnPlayer; + player->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result D LOST (slower, great enemy atk)."); + } else if (atkOnPlayer >= 0) { + damageDealt = abs(atkOnPlayer - atkdelta); + player->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result E LOST (slower, ok enemy atk)."); + } else { + if (atkOnPlayer > -3) { + damageDealt = fabsf(atkOnEnemy - 0.75F * e->vel); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result F1 WIN (slower, enemy atk > -3)."); + } else { + damageDealt = abs(atkOnEnemy - 1); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result F2 WIN (slower, enemy atk < -3)."); + } + e->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + } + } + log_tag("debug_log.txt", "[FIGHT]", "damageCalc %i", damageDealt); + + int yourhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; + char victim[25]; + + if (!yourhit) { + + e->vel--; + e->atk--; + e->def -= 2; + + //Check if someone earned a stat reset after the fight + statReset(player, 0); + statResetEnemy(e, 0); + + strcpy(victim, player->name); + } else { + + player->vel--; + player->atk--; + player->def -= 2; + + //Account for vampirism perk + int vampire_perks = player->perks[VAMPIRISM]->innerValue; + if (vampire_perks > 0) { + int recovery = floor(damageDealt * (0.1 * vampire_perks)); + player->hp += recovery; + log_tag("debug_log.txt", "[PERKS]", "Vampirism proc for +%i HP.", + recovery); + if (player->hp >= player->totalhp) { + player->hp = player->totalhp; + }; + } + //Account for burn on touch perk + int hotbody_perks = player->perks[HOT_BODY]->innerValue; + if (hotbody_perks > 0) { + int burnchance = 11 - hotbody_perks; + if (rand() % burnchance == 0) { + //TODO + //Handle multiple statuses + e->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once + setCounter((Turncounter *) e->counters[Burned], 2); //Give 2 turns of Burned status + log_tag("debug_log.txt", "[PERKS]", + "Hotbody proc on 1/%i chance.", burnchance); + } + } + //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? + int biohazard_perks = player->perks[BIOHAZARD]->innerValue; + if (biohazard_perks > 0) { + int poisonchance = 11 - biohazard_perks; + if (rand() % poisonchance == 0) { + e->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once + setCounter((Turncounter *) e->counters[POISON], 2); //Give 2 turns of Poison status + log_tag("debug_log.txt", "[PERKS]", + "Biohazard proc on 1/%i chance.", poisonchance); + } + } + //Check if someone earned a stat reset after the fight + statResetEnemy(e, 0); + statReset(player, 0); + + strcpy(victim, stringFromEClass(e->class)); + } + + int color = -1; + if (yourhit) { + color = S4C_WHITE; + } else { + color = S4C_RED; + } + + sprintf(msg, "%s was hit. (%i DMG)", victim, + damageDealt > 0 ? damageDealt : 1); + wattron(notify_win, COLOR_PAIR(color)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + + //Rolls + // + //Critical hit roll + + //Account for critboost_chance perks + int critboost_value = 1.5 * player->perks[CRITBOOST_CHANCE]->innerValue; + int critMax = round(10.0 - floor(player->luck / 5) - (critboost_value)); + + int critRes = (rand() % critMax); + + if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { + + //Account for critboost_dmg perks + int dmgboost_perks = player->perks[CRITBOOST_DMG]->innerValue; + damageDealt *= (0.30 + (0.12 * dmgboost_perks)); + e->hp -= (damageDealt > 0 ? damageDealt : 1); + log_tag("debug_log.txt", "[FIGHT]", + "Critical hit for %i dmg, proc on 1/%i chance.", damageDealt, + critMax); + log_tag("debug_log.txt", "[PERKS]", "Critical hit, critboost was %i.", + critboost_value); + + sprintf(msg, "A critical hit! (%i DMG)", + damageDealt > 0 ? damageDealt : 1); + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + //Update stats + player->stats->criticalhits++; + } + //Check for deaths -> exit condition from loop + // + // + // + if (e->hp <= 0) { + res = FIGHTRES_KILL_DONE; + + //Account for runic circle perk + int runic_perks = player->perks[RUNIC_MAGNET]->innerValue; + if (runic_perks > 0) { + int recovery = round(0.51 * runic_perks); + player->energy += recovery; + log_tag("debug_log.txt", "[PERKS]", + "Runicmagnet proc for %i energy.", recovery); + } + if (e->beast) { + color = S4C_MAGENTA; + } else { + color = S4C_RED; + } + wattron(notify_win, COLOR_PAIR(color)); + sprintf(msg, "%s fainted.", stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + + log_tag("debug_log.txt", "[FIGHT]", "Killed %s.", + stringFromEClass(e->class)); + + //Update stats + player->stats->enemieskilled++; + } else { + //Apply status effects to enemy + if (e->status != Normal) { + applyEStatus(notify_win, e); + log_tag("debug_log.txt", "[STATUS]", "Applied %s to %s.", + stringFromStatus(e->status), stringFromEClass(e->class)); + } + } + + if (player->hp <= 0) { + res = FIGHTRES_DEATH; + } else { + //Apply status effects to player + if (player->status != Normal) { + applyStatus(notify_win, player); + } + } + + //Consumable drop, guaranteed on killing a beast + if (res == FIGHTRES_KILL_DONE + && (e->beast || ((rand() % 9) - (player->luck / 10) <= 0))) { + int drop = dropConsumable(player); + sprintf(msg, "You found a %s!", stringFromConsumables(drop)); + wattron(notify_win, COLOR_PAIR(S4C_CYAN)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); + log_tag("debug_log.txt", "[DROPS]", "Found Consumable: %s.", + stringFromConsumables(drop)); + } + + //Artifact drop (if we don't have all of them), guaranteed on killing a beast + if ((player->stats->artifactsfound != ARTIFACTSMAX + 1) + && res == FIGHTRES_KILL_DONE && (e->beast + || + ((rand() % ENEMY_ARTIFACTDROP_CHANCE) - + (player->luck / 10) <= 0))) { + int artifact_drop = dropArtifact(player); + sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + log_tag("debug_log.txt", "[DROPS]", "Found Artifact: %s.", + stringFromArtifacts(artifact_drop)); + if (!e->beast) + log_tag("debug_log.txt", "[.1%% CHANCE]", + "\nNORMAL ENEMY DROPPED ARTIFACT! 0.1%% chance??\n"); + } + + //Equip drop, guaranteed on killing a beast + if (res == FIGHTRES_KILL_DONE + && (e->beast || ((rand() % 15) - (player->luck / 10) <= 0))) { + dropEquip(player, e->beast, notify_win, kls); + } + return res; +} + +/** + * Takes an Enemy and a Fighter pointer and compares their stats to determine who gets damaged and returns the fightStatus value. + * Prints notifications to the passed WINDOW pointer. + * On enemy death, there's a chance to call dropConsumable, dropEquip or dropArtifact (guaranteed for beast enemies). + * NOTE: that the return values are always from the POV of the Fighter: FIGHTRES_DMG_DEALT means the Enemy was damaged! + * @see defer_fight_enemy() + * @see Fighter + * @see Enemy + * @see statReset() + * @see statResetEnemy() + * @see stringFromEClass() + * @see dropConsumable() + * @see dropEquip() + * @see dropArtifact() + * @param player The Fighter pointer at hand. + * @param e The Enemy pointer at hand. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + * @see display_notification() + */ +int enemy_attack(Enemy *e, Fighter *target, WINDOW *notify_win, Koliseo *kls) +{ + //Implementation similar to fight(), as a base idea + //Should return fightResult values, while keeping the perspective on the Fighter, as in: + // + // FIGHTRES_DEATH means the Fighter died + // FIGHTRES_KILL_DONE means the Enemy died + // FIGHTRES_DMG_DEALT means the Fighter inflicted damage + // FIGHRES_DMG_TAKEN means the Fighter received damage + + fightResult res = FIGHTRES_NO_DMG; + char msg[200]; + //Stat comparisons + // + + int atkdelta = (e->atk + e->turnboost_atk) - (target->atk + target->equipboost_atk + target->turnboost_atk - (rand() % 3)) - 1; //Skewed with defender + int defdelta = (e->def + e->turnboost_def) - (target->def + target->equipboost_def + target->turnboost_def) + (rand() % 2) + 1; //Skewed with attacker + int veldelta = + (e->vel + e->turnboost_vel) - (target->vel + target->equipboost_vel + + target->turnboost_vel) + (rand() % 3) + + 1; + + int atkOnPlayer = + (e->atk + e->turnboost_atk) - (target->def + target->equipboost_def + + target->turnboost_def + + (target->vel / 6)); + int atkOnEnemy = + (target->atk + target->equipboost_atk + target->turnboost_atk) - + (e->def + e->turnboost_def + (e->vel / 6)); + + if (G_GODMODE_ON == 1) { + log_tag("debug_log.txt", "[DEBUG]", "[%s]: G_GODMODE_ON == 1", + __func__); + atkdelta = -100; + defdelta = -100; + veldelta = -100; + atkOnPlayer = 1; + atkOnEnemy = 100; + } + + int damageDealt = -1; + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkdelta %i", atkdelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "defdelta %i", defdelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "veldelta %i", veldelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnEnemy %i", atkOnEnemy); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnPlayer %i", atkOnPlayer); + + if (veldelta >= 0) { //Enemy has a non-negative veldelta + if (atkOnPlayer > 3) { + damageDealt = atkOnPlayer; + target->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result D LOST (slower, great enemy atk).", + __func__); + } else if (atkOnPlayer >= 0) { + damageDealt = abs(atkOnPlayer - atkdelta); + target->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result E LOST (slower, ok enemy atk).", + __func__); + } else { + if (atkOnPlayer > -3) { + damageDealt = fabsf(atkOnEnemy - 0.75F * e->vel); + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result F1 WIN (slower, enemy atk > -3).", + __func__); + } else { + damageDealt = abs(atkOnEnemy - 1); + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result F2 WIN (slower, enemy atk < -3).", + __func__); + } + e->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + } + } else { //Enemy veldelta is not strictly positive + atkdelta = -atkdelta; + if (atkOnEnemy > 3) { + damageDealt = atkOnEnemy; + e->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result A WIN (faster, great atk).", __func__); + } else if (atkOnEnemy >= 0) { + damageDealt = abs(atkOnEnemy - atkdelta); + e->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result B WIN (faster, ok atk).", __func__); + } else { + if (atkOnEnemy > -3) { + damageDealt = + fabsf(atkOnPlayer - + 0.75F * (target->vel + target->equipboost_vel)); + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result C1 LOST (faster, atk > -3).", + __func__); + } else { + damageDealt = abs(atkOnPlayer - 1); + log_tag("debug_log.txt", "[FIGHT]", + "[%s]: Fight result C2 LOST (faster, atk < -3).", + __func__); + } + target->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + } + } + log_tag("debug_log.txt", "[FIGHT]", "[%s]: damageCalc %i", __func__, + damageDealt); + + int playerhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; + char victim[25]; + + if (!playerhit) { + + e->vel--; + e->atk--; + e->def -= 2; + + //Check if someone earned a stat reset after the fight + statReset(target, 0); + statResetEnemy(e, 0); + + strcpy(victim, target->name); + } else { + + target->vel--; + target->atk--; + target->def -= 2; + + //Account for vampirism perk + int vampire_perks = target->perks[VAMPIRISM]->innerValue; + if (vampire_perks > 0) { + int recovery = floor(damageDealt * (0.1 * vampire_perks)); + target->hp += recovery; + log_tag("debug_log.txt", "[PERKS]", "Vampirism proc for +%i HP.", + recovery); + if (target->hp >= target->totalhp) { + target->hp = target->totalhp; + }; + } + //Account for burn on touch perk + int hotbody_perks = target->perks[HOT_BODY]->innerValue; + if (hotbody_perks > 0) { + int burnchance = 11 - hotbody_perks; + if (rand() % burnchance == 0) { + //TODO + //Handle multiple statuses + e->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once + setCounter((Turncounter *) e->counters[Burned], 2); //Give 2 turns of Burned status + log_tag("debug_log.txt", "[PERKS]", + "Hotbody proc on 1/%i chance.", burnchance); + } + } + //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? + int biohazard_perks = target->perks[BIOHAZARD]->innerValue; + if (biohazard_perks > 0) { + int poisonchance = 11 - biohazard_perks; + if (rand() % poisonchance == 0) { + e->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once + setCounter((Turncounter *) e->counters[POISON], 2); //Give 2 turns of Poison status + log_tag("debug_log.txt", "[PERKS]", + "Biohazard proc on 1/%i chance.", poisonchance); + } + } + //Check if someone earned a stat reset after the fight + statResetEnemy(e, 0); + statReset(target, 0); + + strcpy(victim, stringFromEClass(e->class)); + } + + int color = -1; + if (playerhit) { + color = S4C_WHITE; + } else { + color = S4C_RED; + } + + sprintf(msg, "%s was hit. (%i DMG)", victim, + damageDealt > 0 ? damageDealt : 1); + wattron(notify_win, COLOR_PAIR(color)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + + //Rolls + // + //Critical hit roll + + //Account for critboost_chance perks + int critboost_value = 1.5 * target->perks[CRITBOOST_CHANCE]->innerValue; + int critMax = round(10.0 - floor(target->luck / 5) - (critboost_value)); + + int critRes = (rand() % critMax); + + if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { + + //Account for critboost_dmg perks + int dmgboost_perks = target->perks[CRITBOOST_DMG]->innerValue; + damageDealt *= (0.30 + (0.12 * dmgboost_perks)); + e->hp -= (damageDealt > 0 ? damageDealt : 1); + log_tag("debug_log.txt", "[FIGHT]", + "Critical hit for %i dmg, proc on 1/%i chance.", damageDealt, + critMax); + log_tag("debug_log.txt", "[PERKS]", "Critical hit, critboost was %i.", + critboost_value); + + sprintf(msg, "A critical hit! (%i DMG)", + damageDealt > 0 ? damageDealt : 1); + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + //Update stats + target->stats->criticalhits++; + } + //Check for deaths -> exit condition from loop + // + // + // + if (e->hp <= 0) { + res = FIGHTRES_KILL_DONE; + + //Account for runic circle perk + int runic_perks = target->perks[RUNIC_MAGNET]->innerValue; + if (runic_perks > 0) { + int recovery = round(0.51 * runic_perks); + target->energy += recovery; + log_tag("debug_log.txt", "[PERKS]", + "Runicmagnet proc for %i energy.", recovery); + } + if (e->beast) { + color = S4C_MAGENTA; + } else { + color = S4C_RED; + } + wattron(notify_win, COLOR_PAIR(color)); + sprintf(msg, "%s fainted.", stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + + log_tag("debug_log.txt", "[FIGHT]", "Killed %s.", + stringFromEClass(e->class)); + + //Update stats + target->stats->enemieskilled++; + } else { + //Apply status effects to enemy + if (e->status != Normal) { + applyEStatus(notify_win, e); + log_tag("debug_log.txt", "[STATUS]", "Applied %s to %s.", + stringFromStatus(e->status), stringFromEClass(e->class)); + } + } + + if (target->hp <= 0) { + log_tag("debug_log.txt", "[DEBUG]", "[%s]: Target died. Hp: (%i)", + __func__, target->hp); + res = FIGHTRES_DEATH; + } else { + //Apply status effects to target + if (target->status != Normal) { + applyStatus(notify_win, target); + } + } + + //Consumable drop, guaranteed on killing a beast + if (res == FIGHTRES_KILL_DONE + && (e->beast || ((rand() % 9) - (target->luck / 10) <= 0))) { + int drop = dropConsumable(target); + sprintf(msg, "You found a %s!", stringFromConsumables(drop)); + wattron(notify_win, COLOR_PAIR(S4C_CYAN)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); + log_tag("debug_log.txt", "[DROPS]", "Found Consumable: %s.", + stringFromConsumables(drop)); + } + + //Artifact drop (if we don't have all of them), guaranteed on killing a beast + if ((target->stats->artifactsfound != ARTIFACTSMAX + 1) + && res == FIGHTRES_KILL_DONE && (e->beast + || + ((rand() % ENEMY_ARTIFACTDROP_CHANCE) - + (target->luck / 10) <= 0))) { + int artifact_drop = dropArtifact(target); + sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + log_tag("debug_log.txt", "[DROPS]", "Found Artifact: %s.", + stringFromArtifacts(artifact_drop)); + if (!e->beast) + log_tag("debug_log.txt", "[.1%% CHANCE]", + "\nNORMAL ENEMY DROPPED ARTIFACT! 0.1%% chance??\n"); + } + + //Equip drop, guaranteed on killing a beast + if (res == FIGHTRES_KILL_DONE + && (e->beast || ((rand() % 15) - (target->luck / 10) <= 0))) { + dropEquip(target, e->beast, notify_win, kls); + } + return res; +} + +/** + * Takes a Fighter and a Enemy pointers and calls fight(). + * @see Fighter + * @see Enemy + * @see fight() + * @param player The Fighter pointer at hand. + * @param e The Enemy pointer at hand. + * @param foe_op The foeTurnOption_OP for the foe. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + */ +int defer_fight_enemy(Fighter *player, Enemy *e, foeTurnOption_OP foe_op, + WINDOW *notify_win, Koliseo *kls) +{ + char msg[200]; + //FIXME + //Is it okay to return just one result, when having 2 interactions that could go differently? + // + //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. + fightResult res = FIGHTRES_NO_DMG; + + int player_goes_first = (player->vel >= e->vel ? 1 : 0); + + int first_act_res = FIGHTRES_NO_DMG; + + if (player_goes_first) { + + res = fight(player, e, notify_win, kls); + + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + first_act_res = res; + + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromEClass(e->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromEClass(e->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is angry!", stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + + res = enemy_attack(e, player, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", + __func__, stringFromEClass(e->class)); + //TODO + //Implement enemy special function + //res = enemy_attack_special(e,player,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", + __func__, foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was not a clash...", __func__); + } else if ((res == FIGHTRES_DMG_TAKEN + && first_act_res == FIGHTRES_DMG_DEALT) + || (res == FIGHTRES_DMG_DEALT + && first_act_res == FIGHTRES_DMG_TAKEN)) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was a clash!", __func__); + res = FIGHTRES_CLASH; + } + + return res; + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } else { + //Foe acts first + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromEClass(e->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromEClass(e->class)); + res = enemy_attack(e, player, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", __func__, + stringFromEClass(e->class)); + //TODO + //Implement enemy special function + //res = enemy_attack_special(e,player,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + first_act_res = res; + + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + res = fight(player, e, notify_win, kls); + + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was not a clash...", __func__); + } else if ((res == FIGHTRES_DMG_TAKEN + && first_act_res == FIGHTRES_DMG_DEALT) + || (res == FIGHTRES_DMG_DEALT + && first_act_res == FIGHTRES_DMG_TAKEN)) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was a clash!", __func__); + res = FIGHTRES_CLASH; + } + + return res; + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } + return res; +} + +/** + * Takes a Fighter and a Enemy pointers and calls do_Skill(). + * @see Fighter + * @see Enemy + * @see do_Skill() + * @param player The Fighter pointer at hand. + * @param e The Enemy pointer at hand. + * @param picked_skill The picked skill by Fighter. + * @param foe_op The foeTurnOption_OP for the foe. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + */ +int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, + WINDOW *notify_win, Koliseo *kls) +{ + char msg[200]; + //FIXME + //Is it okay to return just one result, when having 2 interactions that could go differently? + // + //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. + fightResult res = FIGHTRES_NO_DMG; + + int player_goes_first = (player->vel >= e->vel ? 1 : 0); + + int first_act_res = FIGHTRES_NO_DMG; + + if (player_goes_first) { + + res = do_Skill(player, e, picked_skill, notify_win, kls); + + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + first_act_res = res; + + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromEClass(e->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromEClass(e->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is angry!", stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + + res = enemy_attack(e, player, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", + __func__, stringFromEClass(e->class)); + //TODO + //Implement enemy special function + //res = enemy_attack_special(e,player,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", + __func__, foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was not a clash...", __func__); + } else if ((res == FIGHTRES_DMG_TAKEN + && first_act_res == FIGHTRES_DMG_DEALT) + || (res == FIGHTRES_DMG_DEALT + && first_act_res == FIGHTRES_DMG_TAKEN)) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was a clash!", __func__); + res = FIGHTRES_CLASH; + } + + return res; + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } else { + //Foe acts first + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromEClass(e->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromEClass(e->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromEClass(e->class)); + res = enemy_attack(e, player, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", __func__, + stringFromEClass(e->class)); + //TODO + //Implement enemy special function + //res = enemy_attack_special(e,player,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + first_act_res = res; + + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + res = do_Skill(player, e, picked_skill, notify_win, kls); + + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + if (res == FIGHTRES_DEATH || res == FIGHTRES_KILL_DONE) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was not a clash...", __func__); + } else if ((res == FIGHTRES_DMG_TAKEN + && first_act_res == FIGHTRES_DMG_DEALT) + || (res == FIGHTRES_DMG_DEALT + && first_act_res == FIGHTRES_DMG_TAKEN)) { + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Deferred fight was a clash!", __func__); + res = FIGHTRES_CLASH; + } + + return res; + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } + return res; +} + +/** + * Takes a Fighter, a Boss and a Path pointers and compares fighters stats to determine who gets damaged and returns the fightStatus value. + * Prints notifications to the passed WINDOW pointer. + * On boss death, we call dropConsumable, dropEquip and dropArtifact. + * @see Fighter + * @see Boss + * @see statReset() + * @see statResetBoss() + * @see stringFromBossClass() + * @see dropConsumable() + * @see dropEquip() + * @see dropArtifact() + * @param player The Fighter pointer at hand. + * @param b The Enemy pointer at hand. + * @param p The Path pointer for the game. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + * @see display_notification() + */ +int boss_fight(Fighter *player, Boss *b, Path *p, WINDOW *notify_win, + Koliseo *kls) +{ + + fightResult res = FIGHTRES_NO_DMG; + //Stat comparisons + // + char msg[200]; + + int atkdelta = (player->atk + player->equipboost_atk) - b->atk - (rand() % 3) - 1; //Skewed with defender + int defdelta = (player->def + player->equipboost_def) - b->def + (rand() % 2) + 1; //Skewed with attacker + int veldelta = + (player->vel + player->equipboost_vel) - b->vel + (rand() % 3) + 1; + + int atkOnPlayer = + b->atk - (player->def + player->equipboost_def + (player->vel / 6)); + int atkOnEnemy = + (player->atk + player->equipboost_atk) - (b->def + (b->vel / 6)); + if (G_GODMODE_ON == 1) { + log_tag("debug_log.txt", "[DEBUG]", "boss_fight(): G_GODMODE_ON == 1"); + atkdelta = 100; + defdelta = 100; + veldelta = 100; + atkOnPlayer = 1; + atkOnEnemy = 100; + } + sprintf(msg, "atkdelta %i", atkdelta); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + sprintf(msg, "defdelta %i", defdelta); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + sprintf(msg, "veldelta %i", veldelta); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + sprintf(msg, "atkOnEnemy %i", atkOnEnemy); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + sprintf(msg, "atkOnPlayer %i\n", atkOnPlayer); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + + int damageDealt = -1; + + if (veldelta >= 0) { + + if (atkOnEnemy > 3) { + damageDealt = atkOnEnemy; + b->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result A WIN (faster, great atk).\n"); + } else if (atkOnEnemy >= 0) { + damageDealt = abs(atkOnEnemy - atkdelta); + b->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result B WIN (faster, ok atk).\n"); + } else { + if (atkOnEnemy < -3) { + damageDealt = + fabsf(atkOnPlayer - + 0.75F * (player->vel + player->equipboost_vel)); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result C1 LOST (faster, atk < -3).\n"); + } else { + damageDealt = abs(atkOnPlayer - 1); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result C2 LOST (faster, atk > -3).\n"); + } + player->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + } + } else { + atkdelta = -atkdelta; + if (atkOnPlayer > 3) { + damageDealt = atkOnPlayer; + player->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result D LOST (slower, great enemy atk.\n"); + } else if (atkOnPlayer >= 0) { + damageDealt = abs(atkOnPlayer - atkdelta); + player->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result E LOST (slower, ok enemy atk.\n"); + } else { + if (atkOnPlayer < -3) { + damageDealt = fabsf(atkOnEnemy - 0.75F * b->vel); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result F1 WIN (slower, enemy atk < -3.\n"); + } else { + damageDealt = abs(atkOnEnemy - 1); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result F2 WIN (slower, enemy atk > -3.\n"); + } + b->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + } + } + + log_tag("debug_log.txt", "[FIGHT]", "damageCalc %i", damageDealt); + + int yourhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; + char victim[25]; + + if (!yourhit) { + + b->vel--; + b->atk--; + b->def -= 2; + + //Check if someone earned a stat reset after the fight + statReset(player, 0); + statResetBoss(b, 0); + + strcpy(victim, player->name); + } else { + + player->vel--; + player->atk--; + player->def -= 2; + + //Account for vampirism perk + int vampire_perks = player->perks[VAMPIRISM]->innerValue; + if (vampire_perks > 0) { + int recovery = floor(damageDealt * (0.1 * vampire_perks)); + player->hp += recovery; + sprintf(msg, "Vampirism proc for +%i HP.\n", recovery); + log_tag("debug_log.txt", "[PERKS]", msg); + if (player->hp >= player->totalhp) { + player->hp = player->totalhp; + }; + } + //Account for burn on touch perk + int hotbody_perks = player->perks[HOT_BODY]->innerValue; + if (hotbody_perks > 0) { + int burnchance = 11 - hotbody_perks; + if (rand() % burnchance == 0) { + b->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once + setCounter((Turncounter *) b->counters[Burned], 2); //Give 2 turns of Burned status + sprintf(msg, "Hotbody proc on 1/%i chance.\n", burnchance); + log_tag("debug_log.txt", "[PERKS]", msg); + } + } + //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? + int biohazard_perks = player->perks[BIOHAZARD]->innerValue; + if (biohazard_perks > 0) { + int poisonchance = 11 - biohazard_perks; + if (rand() % poisonchance == 0) { + b->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once + setCounter((Turncounter *) b->counters[POISON], 2); //Give 2 turns of Poison status + sprintf(msg, "Biohazard proc on 1/%i chance.\n", poisonchance); + log_tag("debug_log.txt", "[PERKS]", msg); + } + } + //Check if someone earned a stat reset after the fight + statResetBoss(b, 0); + statReset(player, 0); + + strcpy(victim, stringFromBossClass(b->class)); + } + + int color = -1; + if (yourhit) { + color = S4C_WHITE; + } else { + color = S4C_RED; + } + + wattron(notify_win, COLOR_PAIR(color)); + sprintf(msg, "%s was hit. (%i DMG)", victim, + damageDealt > 0 ? damageDealt : 1); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + + //Rolls + // + //Critical hit roll + + //Account for critboost_chance perks + int critMax = + round(10.0 - floor(player->luck / 5) - + (1.5 * player->perks[CRITBOOST_CHANCE]->innerValue)); + + int critRes = (rand() % critMax); + + if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { + + //Account for critboost_dmg perks + int dmgboost_perks = player->perks[CRITBOOST_DMG]->innerValue; + damageDealt *= (0.30 + (0.12 * dmgboost_perks)); + b->hp -= damageDealt > 0 ? damageDealt : 1; + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + sprintf(msg, "A critical hit! (%i DMG)", + damageDealt > 0 ? damageDealt : 1); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + sprintf(msg, "Critical hit for %i dmg, proc on 1/%i chance.\n", + damageDealt, critMax); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + + //Update stats + player->stats->criticalhits++; + } + //Check for deaths -> exit condition from loop + // + // + // + if (b->hp <= 0) { + res = FIGHTRES_KILL_DONE; + + //Account for runic circle perk + int runic_perks = player->perks[RUNIC_MAGNET]->innerValue; + if (runic_perks > 0) { + int recovery = round(0.51 * runic_perks); + player->energy += recovery; + sprintf(msg, "Runicmagnet proc for %i energy.\n", recovery); + log_tag("debug_log.txt", "[PERKS]", msg); + } + if (b->beast) { + color = S4C_MAGENTA; + } else { + color = S4C_RED; + } + wattron(notify_win, COLOR_PAIR(color)); + sprintf(msg, "%s fainted.", stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + sprintf(msg, "Killed %s.", stringFromBossClass(b->class)); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + + //Update stats + player->stats->bosseskilled++; + + //Check if we killed this boss before + if (player->stats->killed_bosses[b->class] == 0) { + //Update stats + player->stats->unique_bosseskilled++; + player->stats->killed_bosses[b->class] += 1; + //Check if we have to update the wincon value + if (p->win_condition->class == ALL_BOSSES) { + p->win_condition->current_val++; + } + sprintf(msg, "Killed new boss %s.\n", + stringFromBossClass(b->class)); + log_tag("debug_log.txt", "[FIGHT-BOSS]", msg); + } + } else { + //Apply status effects to boss + if (b->status != Normal) { + applyBStatus(notify_win, b); + sprintf(msg, "Applied %s to %s.", stringFromStatus(b->status), + stringFromBossClass(b->class)); + log_tag("debug_log.txt", "[STATUS]", msg); + } + } + + if (player->hp <= 0) { + res = FIGHTRES_DEATH; + } else { + //Apply status effects to player + if (player->status != Normal) { + applyStatus(notify_win, player); + } + } + + //Consumable drop, guaranteed on killing a beast + if (res == FIGHTRES_KILL_DONE) { + int drop = dropConsumable(player); + wattron(notify_win, COLOR_PAIR(S4C_CYAN)); + sprintf(msg, "You found a %s!", stringFromConsumables(drop)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); + sprintf(msg, "Found Consumable: %s.", stringFromConsumables(drop)); + log_tag("debug_log.txt", "[DROPS]", msg); + } + + //Artifact drop (if we don't have all of them) + if (res == FIGHTRES_KILL_DONE + && (player->stats->artifactsfound != ARTIFACTSMAX + 1)) { + int artifact_drop = dropArtifact(player); + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + sprintf(msg, "Found Artifact: %s.", + stringFromArtifacts(artifact_drop)); + log_tag("debug_log.txt", "[DROPS]", msg); + } + //Equip drop + if (res == FIGHTRES_KILL_DONE) { + //We give 1 to obtain the better equip generation used for beasts + dropEquip(player, 1, notify_win, kls); + } + + return res; +} + +int boss_attack(Boss *b, Fighter *target, Path *p, WINDOW *notify_win, + Koliseo *kls) +{ + + //TODO + //Implementation similar to boss_fight(), as a base idea + //Should return fightResult values, while keeping the perspective on the Fighter, as in: + // + // FIGHTRES_DEATH means the Fighter died + // FIGHTRES_KILL_DONE means the Boss died + // FIGHTRES_DMG_DEALT means the Fighter inflicted damage + // FIGHRES_DMG_TAKEN means the Fighter received damage + fightResult res = FIGHTRES_NO_DMG; + //Stat comparisons + // + char msg[200]; + + int atkdelta = (b->atk + b->turnboost_atk) - (target->atk + target->equipboost_atk + target->turnboost_atk - (rand() % 3)) - 1; //Skewed with defender + int defdelta = (b->def + b->turnboost_def) - (target->def + target->equipboost_def + target->turnboost_def) + (rand() % 2) + 1; //Skewed with attacker + int veldelta = + (b->vel + b->turnboost_vel) - (target->vel + target->equipboost_vel + + target->turnboost_vel) + (rand() % 3) + + 1; + + int atkOnPlayer = + (b->atk + b->turnboost_atk) - (target->def + target->equipboost_def + + target->turnboost_def + + (target->vel / 6)); + int atkOnEnemy = + (target->atk + target->equipboost_atk + target->turnboost_atk) - + (b->def + b->turnboost_def + (b->vel / 6)); + if (G_GODMODE_ON == 1) { + log_tag("debug_log.txt", "[DEBUG]", "[%s]: G_GODMODE_ON == 1", + __func__); + atkdelta = -100; + defdelta = -100; + veldelta = -100; + atkOnPlayer = 1; + atkOnEnemy = 100; + } + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkdelta %i", atkdelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "defdelta %i", defdelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "veldelta %i", veldelta); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnEnemy %i", atkOnEnemy); + log_tag("debug_log.txt", "[DEBUG-FIGHT]", "atkOnPlayer %i", atkOnPlayer); + + int damageDealt = -1; + + if (veldelta >= 0) { //Boss was faster + if (atkOnPlayer > 3) { + damageDealt = atkOnPlayer; + target->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result D LOST (slower, great enemy atk."); + } else if (atkOnPlayer >= 0) { + damageDealt = abs(atkOnPlayer - atkdelta); + target->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result E LOST (slower, ok enemy atk."); + } else { + if (atkOnPlayer < -3) { + damageDealt = fabsf(atkOnEnemy - 0.75F * b->vel); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result F1 WIN (slower, enemy atk < -3."); + } else { + damageDealt = abs(atkOnEnemy - 1); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result F2 WIN (slower, enemy atk > -3."); + } + b->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + } + } else { //Target was faster + atkdelta = -atkdelta; + if (atkOnEnemy > 3) { + damageDealt = atkOnEnemy; + b->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result A WIN (faster, great atk)."); + } else if (atkOnEnemy >= 0) { + damageDealt = abs(atkOnEnemy - atkdelta); + b->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_DEALT; + log_tag("debug_log.txt", "[FIGHT]", + "Fight result B WIN (faster, ok atk)."); + } else { + if (atkOnEnemy < -3) { + damageDealt = + fabsf(atkOnPlayer - + 0.75F * (target->vel + target->equipboost_vel)); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result C1 LOST (faster, atk < -3)."); + } else { + damageDealt = abs(atkOnPlayer - 1); + log_tag("debug_log.txt", "[FIGHT]", + "Fight result C2 LOST (faster, atk > -3)."); + } + target->hp -= damageDealt > 0 ? damageDealt : 1; + res = FIGHTRES_DMG_TAKEN; + } + } + + log_tag("debug_log.txt", "[FIGHT]", "damageCalc %i", damageDealt); + + int yourhit = (res == FIGHTRES_DMG_DEALT) ? 1 : 0; + char victim[25]; + + if (!yourhit) { + + b->vel--; + b->atk--; + b->def -= 2; + + //Check if someone earned a stat reset after the fight + statReset(target, 0); + statResetBoss(b, 0); + + strcpy(victim, target->name); + } else { + + target->vel--; + target->atk--; + target->def -= 2; + + //Account for vampirism perk + int vampire_perks = target->perks[VAMPIRISM]->innerValue; + if (vampire_perks > 0) { + int recovery = floor(damageDealt * (0.1 * vampire_perks)); + target->hp += recovery; + log_tag("debug_log.txt", "[PERKS]", "Vampirism proc for +%i HP.", + recovery); + if (target->hp >= target->totalhp) { + target->hp = target->totalhp; + }; + } + //Account for burn on touch perk + int hotbody_perks = target->perks[HOT_BODY]->innerValue; + if (hotbody_perks > 0) { + int burnchance = 11 - hotbody_perks; + if (rand() % burnchance == 0) { + b->status = Burned; //Set status to Burned. May need change to manage multiple statuses active at once + setCounter((Turncounter *) b->counters[Burned], 2); //Give 2 turns of Burned status + log_tag("debug_log.txt", "[PERKS]", + "Hotbody proc on 1/%i chance.", burnchance); + } + } + //Account for poison on touch perk. Order of checks with hot_body perk may cause issues? + int biohazard_perks = target->perks[BIOHAZARD]->innerValue; + if (biohazard_perks > 0) { + int poisonchance = 11 - biohazard_perks; + if (rand() % poisonchance == 0) { + b->status = Poison; //Set status to Poison. May need change to manage multiple statuses active at once + setCounter((Turncounter *) b->counters[POISON], 2); //Give 2 turns of Poison status + log_tag("debug_log.txt", "[PERKS]", + "Biohazard proc on 1/%i chance.", poisonchance); + } + } + //Check if someone earned a stat reset after the fight + statResetBoss(b, 0); + statReset(target, 0); + + strcpy(victim, stringFromBossClass(b->class)); + } + + int color = -1; + if (yourhit) { + color = S4C_WHITE; + } else { + color = S4C_RED; + } + + wattron(notify_win, COLOR_PAIR(color)); + sprintf(msg, "%s was hit. (%i DMG)", victim, + damageDealt > 0 ? damageDealt : 1); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + + //Rolls + // + //Critical hit roll + + //Account for critboost_chance perks + int critMax = + round(10.0 - floor(target->luck / 5) - + (1.5 * target->perks[CRITBOOST_CHANCE]->innerValue)); + + int critRes = (rand() % critMax); + + if (res == FIGHTRES_DMG_DEALT && (critRes <= 0)) { + + //Account for critboost_dmg perks + int dmgboost_perks = target->perks[CRITBOOST_DMG]->innerValue; + damageDealt *= (0.30 + (0.12 * dmgboost_perks)); + b->hp -= damageDealt > 0 ? damageDealt : 1; + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + sprintf(msg, "A critical hit! (%i DMG)", + damageDealt > 0 ? damageDealt : 1); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + log_tag("debug_log.txt", "[FIGHT-BOSS]", + "Critical hit for %i dmg, proc on 1/%i chance.", damageDealt, + critMax); + + //Update stats + target->stats->criticalhits++; + } + //Check for deaths -> exit condition from loop + // + // + // + if (b->hp <= 0) { + res = FIGHTRES_KILL_DONE; + + //Account for runic circle perk + int runic_perks = target->perks[RUNIC_MAGNET]->innerValue; + if (runic_perks > 0) { + int recovery = round(0.51 * runic_perks); + target->energy += recovery; + log_tag("debug_log.txt", "[PERKS]", + "Runicmagnet proc for %i energy.", recovery); + } + if (b->beast) { + color = S4C_MAGENTA; + } else { + color = S4C_RED; + } + wattron(notify_win, COLOR_PAIR(color)); + sprintf(msg, "%s fainted.", stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(color)); + log_tag("debug_log.txt", "[FIGHT-BOSS]", "Killed %s.", + stringFromBossClass(b->class)); + + //Update stats + target->stats->bosseskilled++; + + //Check if we killed this boss before + if (target->stats->killed_bosses[b->class] == 0) { + //Update stats + target->stats->unique_bosseskilled++; + target->stats->killed_bosses[b->class] += 1; + //Check if we have to update the wincon value + if (p->win_condition->class == ALL_BOSSES) { + p->win_condition->current_val++; + } + log_tag("debug_log.txt", "[FIGHT-BOSS]", "Killed new boss %s.", + stringFromBossClass(b->class)); + } + } else { + //Apply status effects to boss + if (b->status != Normal) { + applyBStatus(notify_win, b); + log_tag("debug_log.txt", "[STATUS]", "Applied %s to %s.", + stringFromStatus(b->status), stringFromBossClass(b->class)); + } + } + + if (target->hp <= 0) { + res = FIGHTRES_DEATH; + } else { + //Apply status effects to target + if (target->status != Normal) { + applyStatus(notify_win, target); + } + } + + //Consumable drop, guaranteed on killing a beast + if (res == FIGHTRES_KILL_DONE) { + int drop = dropConsumable(target); + wattron(notify_win, COLOR_PAIR(S4C_CYAN)); + sprintf(msg, "You found a %s!", stringFromConsumables(drop)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_CYAN)); + log_tag("debug_log.txt", "[DROPS]", "Found Consumable: %s.", + stringFromConsumables(drop)); + } + + //Artifact drop (if we don't have all of them) + if (res == FIGHTRES_KILL_DONE + && (target->stats->artifactsfound != ARTIFACTSMAX + 1)) { + int artifact_drop = dropArtifact(target); + wattron(notify_win, COLOR_PAIR(S4C_MAGENTA)); + sprintf(msg, "You found a %s!", stringFromArtifacts(artifact_drop)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_MAGENTA)); + log_tag("debug_log.txt", "[DROPS]", "Found Artifact: %s.", + stringFromArtifacts(artifact_drop)); + } + //Equip drop + if (res == FIGHTRES_KILL_DONE) { + //We give 1 to obtain the better equip generation used for beasts + dropEquip(target, 1, notify_win, kls); + } + + return res; +} + +/** + * Takes a Fighter and a Boss pointers and calls boss_fight(). + * @see Fighter + * @see Boss + * @see boss_fight() + * @param player The Fighter pointer at hand. + * @param b The Boss pointer at hand. + * @param foe_op The foeTurnOption_OP for the foe. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + */ +int defer_fight_boss(Fighter *player, Boss *b, Path *p, foeTurnOption_OP foe_op, + WINDOW *notify_win, Koliseo *kls) +{ + char msg[200]; + //FIXME + //Is it okay to return just one result, when having 2 interactions that could go differently? + // + //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. + fightResult res = FIGHTRES_NO_DMG; + + int player_goes_first = (player->vel >= b->vel ? 1 : 0); + + if (player_goes_first) { + res = boss_fight(player, b, p, notify_win, kls); + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + res = boss_attack(b, player, p, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", + __func__, stringFromBossClass(b->class)); + //TODO + //Implement boss special function + //res = boss_attack_special(b,player,p,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", + __func__, foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + //TODO + //Check second turn act res? + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + + return res; + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } else { + //Foe acts first + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s()]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + res = boss_attack(b, player, p, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", __func__, + stringFromBossClass(b->class)); + //TODO + //Implement boss special function + //res = boss_attack_special(b,player,p,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + res = boss_fight(player, b, p, notify_win, kls); + + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + //TODO + //Check second turn act res? + return res; + + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } + + return res; +} + +/** + * Takes a Fighter and a Boss pointers and calls do_Skill_boss(). + * @see Fighter + * @see Boss + * @see do_Skill_boss() + * @param player The Fighter pointer at hand. + * @param b The Boss pointer at hand. + * @param picked_skill The skill picked by Fighter. + * @param foe_op The foeTurnOption_OP for the foe. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + */ +int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, + WINDOW *notify_win, Koliseo *kls) +{ + char msg[200]; + //FIXME + //Is it okay to return just one result, when having 2 interactions that could go differently? + // + //Use FIGHTRES_CLASH as needed, to indicate both sides were damaged at some point. + fightResult res = FIGHTRES_NO_DMG; + + int player_goes_first = (player->vel >= b->vel ? 1 : 0); + + if (player_goes_first) { + res = do_Skill_boss(player, b, picked_skill, p, notify_win, kls); + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + res = boss_attack(b, player, p, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", + __func__, stringFromBossClass(b->class)); + //TODO + //Implement boss special function + //res = boss_attack_special(b,player,p,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", + __func__, foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + //TODO + //Check second turn act res? + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + + return res; + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } else { + //Foe acts first + switch (foe_op) { + case FOE_OP_INVALID: { + log_tag("debug_log.txt", "[ERROR]", + "foe_op was FOE_OP_INVALID in [%s()]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + case FOE_OP_IDLE: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } was idle.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is loafing around.", + stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + } + break; + case FOE_OP_FIGHT: { + log_tag("debug_log.txt", "[DEFER]", + "[%s()]: Foe { %s } wants to fight.", __func__, + stringFromBossClass(b->class)); + wattron(notify_win, COLOR_PAIR(S4C_GREY)); + sprintf(msg, "%s is angry!", stringFromBossClass(b->class)); + display_notification(notify_win, msg, 500); + wattroff(notify_win, COLOR_PAIR(S4C_GREY)); + res = boss_attack(b, player, p, notify_win, kls); + } + break; + case FOE_OP_SPECIAL: { + log_tag("debug_log.txt", "[TODO]", + "[%s()]: Foe { %s } wants to use a special.", __func__, + stringFromBossClass(b->class)); + //TODO + //Implement boss special function + //res = boss_attack_special(b,player,p,notify_win,kls); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Unexpected foeTurnOption_OP in [%s()]: [%i]", __func__, + foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + break; + } // End foe_op switch + + //Check res and apply second action if needed + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: First act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + + if (res != FIGHTRES_DEATH && res != FIGHTRES_KILL_DONE) { + res = do_Skill_boss(player, b, picked_skill, p, notify_win, kls); + + log_tag("debug_log.txt", "[DEBUG]", + "[%s()]: Second act res was [%s]: [%i]", __func__, + stringFrom_fightResult(res), res); + //TODO + //Check second turn act res? + return res; + + } else if (res == FIGHTRES_DEATH) { + return res; + } else if (res == FIGHTRES_KILL_DONE) { + return res; + } + } + + return res; +} + +fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, WINDOW * notify_win, Koliseo * kls) +{ + + return FIGHTRES_NO_DMG; +} + +fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, WINDOW * notify_win, Koliseo * kls) +{ + + return FIGHTRES_NO_DMG; +} + +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +int defer_fight_enemy(Fighter * player, Enemy * e, foeTurnOption_OP foe_op, + Rectangle * notification_area, Koliseo * kls) +{ + return -1; +} + +int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, + Rectangle * notification_area, Koliseo * kls) +{ + return -1; +} + +int fight(Fighter * player, Enemy * e, Rectangle * notification_area, Koliseo * kls) +{ + return -1; +} + +int enemy_attack(Enemy * e, Fighter * target, Rectangle * notification_area, + Koliseo * kls) +{ + return -1; +} + +int defer_fight_boss(Fighter * player, Boss * b, Path * p, + foeTurnOption_OP foe_op, Rectangle * notification_area, + Koliseo * kls) +{ + return -1; +} + +int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, + Rectangle * notification_area, Koliseo *kls) +{ + return -1; +} + +int boss_fight(Fighter * player, Boss * b, Path * p, Rectangle * notification_area, + Koliseo * kls) +{ + return -1; +} + +int boss_attack(Boss * b, Fighter * target, Path * p, Rectangle * notification_area, + Koliseo * kls) +{ + return -1; +} +fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, Rectangle * notification_area, Koliseo * kls) +{ + return FIGHTRES_NO_DMG; +} +fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, Rectangle * notification_area, Koliseo * kls) +{ + return FIGHTRES_NO_DMG; +} +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD diff --git a/src/utils/game_fight.h b/src/utils/game_fight.h new file mode 100644 index 00000000..e9e8954c --- /dev/null +++ b/src/utils/game_fight.h @@ -0,0 +1,80 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 GAME_FIGHT_H_ +#define GAME_FIGHT_H_ + +#include "game_utils.h" + +#ifdef HELAPORDO_CURSES_BUILD +int defer_fight_enemy(Fighter * player, Enemy * e, foeTurnOption_OP foe_op, + WINDOW * notify_win, Koliseo * kls); +int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, + WINDOW * notify_win, Koliseo * kls); + +int fight(Fighter * player, Enemy * e, WINDOW * notify_win, Koliseo * kls); + +int enemy_attack(Enemy * e, Fighter * target, WINDOW * notify_win, + Koliseo * kls); + +int defer_fight_boss(Fighter * player, Boss * b, Path * p, + foeTurnOption_OP foe_op, WINDOW * notify_win, + Koliseo * kls); + +int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, + WINDOW *notify_win, Koliseo *kls); + +int boss_fight(Fighter * player, Boss * b, Path * p, WINDOW * notify_win, + Koliseo * kls); + +int boss_attack(Boss * b, Fighter * target, Path * p, WINDOW * notify_win, + Koliseo * kls); +fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, WINDOW * notify_win, Koliseo * kls); +fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, WINDOW * notify_win, Koliseo * kls); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +int defer_fight_enemy(Fighter * player, Enemy * e, foeTurnOption_OP foe_op, + Rectangle * notification_area, Koliseo * kls); +int defer_skill_enemy(Fighter *player, Enemy *e, skillType picked_skill, foeTurnOption_OP foe_op, + Rectangle * notification_area, Koliseo * kls); + +int fight(Fighter * player, Enemy * e, Rectangle * notification_area, Koliseo * kls); + +int enemy_attack(Enemy * e, Fighter * target, Rectangle * notification_area, + Koliseo * kls); + +int defer_fight_boss(Fighter * player, Boss * b, Path * p, + foeTurnOption_OP foe_op, Rectangle * notification_area, + Koliseo * kls); + +int defer_skill_boss(Fighter *player, Boss *b, skillType picked_skill, Path *p, foeTurnOption_OP foe_op, + Rectangle * notification_area, Koliseo *kls); + +int boss_fight(Fighter * player, Boss * b, Path * p, Rectangle * notification_area, + Koliseo * kls); + +int boss_attack(Boss * b, Fighter * target, Path * p, Rectangle * notification_area, + Koliseo * kls); +fightResult do_Skill(Fighter * player, Enemy * e, skillType picked_skill, Rectangle * notification_area, Koliseo * kls); +fightResult do_Skill_boss(Fighter * player, Boss * b, skillType picked_skill, Path * path, Rectangle * notification_area, Koliseo * kls); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +#endif // GAME_FIGHT_H_ diff --git a/src/utils/game_init.c b/src/utils/game_init.c new file mode 100644 index 00000000..e405ec6a --- /dev/null +++ b/src/utils/game_init.c @@ -0,0 +1,1814 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "game_init.h" + +/** + * Takes a Fighter pointer and prepares its perks field by allocating all the Perk accounted in perkClass. + * Perks are initialised using the ordering of perkClass. + * @see Fighter + * @see Perk + * @see perkClass + * @see PERKSMAX + * @param f The Fighter pointer whose perks field will be initialised. + * @param kls The Koliseo used for allocation. + */ +void initPerks(Fighter *f, Koliseo *kls) +{ + f->perksCount = 0; + //Ordering of i corresponds to perksClass enum + int total = (PERKSMAX + 1); + for (int i = 0; i < total; i++) { + kls_log(kls, "DEBUG", "Prepping Perk (%i)", i); + Perk *p = + (Perk *) KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); + p->class = i; + char *name = nameStringFromPerk(i); + char *desc = descStringFromPerk(i); + + //p->name = name; //(char*)malloc(sizeof(name)); + strcpy(p->name, name); + + //p->desc = (char*)malloc(sizeof(desc)); + strcpy(p->desc, desc); + + p->innerValue = 0; + + f->perks[i] = p; + } +} + +/** + * Takes a Fighter pointer and prepares its consumablesBag field by allocating a Consumable for each consumableClass. + * @see Fighter + * @see Consumable + * @see consumableClass + * @see CONSUMABLESMAX + * @param f The Fighter pointer whose consumablesBag field will be initialised. + * @param kls The Koliseo to do allocations. + */ +void initConsumableBag(Fighter *f, Koliseo *kls) +{ + + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + kls_log(kls, "DEBUG", "Prepping Consumable (%i)", i); + Consumable *c = + (Consumable *) KLS_PUSH_TYPED(kls, Consumable, HR_Consumable, + "Consumable", "Consumable"); + c->class = i; + + Consumable *base = &consumablesBase[i]; + + strcpy(c->name, base->name); + strcpy(c->desc, base->desc); + for (int j = 0; j < 8; j++) { + strcpy(c->sprite[j], base->sprite[j]); + } + c->qty = 0; + + f->consumablesBag[i] = (struct Consumable *)c; + } + +} + +/** + * Takes a Fighter pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. + * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. + * For a given Counter, only the correct pointer field is assigned and the others are left untouched. + * @see Fighter + * @see Turncounter + * @see Countertype + * @see COUNTERSMAX + * @see counterIndexes + * @see getStatBoostCounterFun() + * @see getStatusCounterFun() + * @param f The Fighter pointer whose counters field will be initialised. + * @param kls The Koliseo used for allocation. + */ +void initCounters(Fighter *f, Koliseo *kls) +{ + //Ordering of i corresponds to counterIndexes enum + int total = (COUNTERSMAX + 1); + for (int i = 0; i < total; i++) { + log_tag("debug_log.txt", "[DEBUG]", "Prepping Turncounter (%i)", i); + kls_log(kls, "DEBUG", "Prepping Turncounter (%i)", i); + Turncounter *c = + (Turncounter *) KLS_PUSH_TYPED(kls, Turncounter, HR_Turncounter, + "Turncounter", "Turncounter"); + + //First, prepare counters for statuses + if (i < STATUSMAX + 1) { + c->desc = + (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof(stringFromStatus(i)), + HR_Turncounter_desc, "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, stringFromStatus(i)); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + kls_log(kls, "DEBUG", "Allocated size %lu for status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + + c->effect_fun = getStatusCounterFun(i); + //sprintf(msg,"Status function pointer is: (%i)", (int) *(c->effect_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + c->type = CNT_STATUS; + + //Register function for the specific status counter + // + //REGISTER_COUNTER_CALLBACK(i,resetFighterStatus); + // + //Why does uncommenting this cause problems to special moves callback? + //More specific, ONLY MAGE MOVES + //debug + //printf("%s",stringFromStatus(j)); + } else { //Then, counters for boosts to (all?) stats + + switch (i) { + case TURNBOOST_ATK: { + c->desc = + (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("ATK boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ATK boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("ATK boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("ATK boost"), c->desc); + + c->boost_fun = getStatBoostCounterFun(ATK); + c->type = CNT_ATKBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_DEF: { + c->desc = + (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("DEF boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "DEF boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("DEF boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("DEF boost"), c->desc); + + c->boost_fun = getStatBoostCounterFun(DEF); + c->type = CNT_DEFBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_VEL: { + c->desc = + (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("VEL boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "VEL boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("VEL boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("VEL boost"), c->desc); + + c->boost_fun = getStatBoostCounterFun(VEL); + c->type = CNT_VELBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_ENR: { + c->desc = + (char *)KLS_PUSH_ARR_TYPED(kls, char *, sizeof("ENR boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ENR boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("ENR boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("ENR boost"), c->desc); + + c->boost_fun = getStatBoostCounterFun(ENR); + c->type = CNT_ENRBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + default: { + printf + ("\n\nERROR in initCounters(): unexpected i: %i value \n\n", + i); + exit(EXIT_FAILURE); + } + } + } //End else + c->count = 0; + c->innerValue = 0; + f->counters[i] = (struct Turncounter *)c; + }; //End for all counters +} + +/** + * Takes a Enemy pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. + * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. + * For a given Counter, only the correct pointer field is assigned and the others are left untouched. + * @see Enemy + * @see Turncounter + * @see Countertype + * @see COUNTERSMAX + * @see counterIndexes + * @see getStatBoostCounterEnemyFun() + * @see getStatusCounterEnemyFun() + * @param e The Enemy pointer whose counters field will be initialised. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initECounters(Enemy *e, Koliseo_Temp *t_kls) +{ + //Ordering of i corresponds to counterIndexes enum + int total = (COUNTERSMAX + 1); + Koliseo *kls = t_kls->kls; + for (int i = 0; i < total; i++) { + log_tag("debug_log.txt", "[DEBUG]", "Prepping enemy Turncounter (%i)", + i); + kls_log(kls, "DEBUG", "Prepping enemy Turncounter (%i)", i); + Turncounter *c = + (Turncounter *) KLS_PUSH_T_TYPED(t_kls, Turncounter, + HR_Turncounter, "Turncounter", + "Turncounter"); + + //First, prepare counters for statuses + if (i < STATUSMAX + 1) { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof(stringFromStatus(i)), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, stringFromStatus(i)); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for enemy status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for enemy status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + + c->effect_e_fun = getStatusCounterEnemyFun(i); + //sprintf(msg,"[DEBUG] Enemy status function pointer is: (%i)", *(c->effect_e_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + c->type = CNT_STATUS; + + } else { //Then, counters for boosts to (all?) stats + + switch (i) { + case TURNBOOST_ATK: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("ATK boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ATK boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("ATK boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("ATK boost"), c->desc); + + c->boost_e_fun = getStatBoostCounterEnemyFun(ATK); + c->type = CNT_ATKBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_DEF: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("DEF boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "DEF boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("DEF boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("DEF boost"), c->desc); + + c->boost_e_fun = getStatBoostCounterEnemyFun(DEF); + c->type = CNT_DEFBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_VEL: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("VEL boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "VEL boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("VEL boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("VEL boost"), c->desc); + + c->boost_e_fun = getStatBoostCounterEnemyFun(VEL); + c->type = CNT_VELBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_ENR: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("ENR boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ENR boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("ENR boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("ENR boost"), c->desc); + + c->boost_e_fun = getStatBoostCounterEnemyFun(ENR); + c->type = CNT_ENRBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "ERROR INITALISING TURNCOUNTER in initECounters()\n"); + exit(EXIT_FAILURE); + } + } + } //End else + c->count = 0; + c->innerValue = 0; + e->counters[i] = (struct Turncounter *)c; + }; +} + +/** + * Takes a Boss pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. + * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. + * For a given Counter, only the correct pointer field is assigned and the others are left untouched. + * @see Boss + * @see Turncounter + * @see Countertype + * @see COUNTERSMAX + * @see counterIndexes + * @see getStatBoostCounterBossFun() + * @see getStatusCounterBossFun() + * @param b The Boss pointer whose counters field will be initialised. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initBCounters(Boss *b, Koliseo_Temp *t_kls) +{ + //Ordering of i corresponds to counterIndexes enum + int total = (COUNTERSMAX + 1); + Koliseo *kls = t_kls->kls; + for (int i = 0; i < total; i++) { + log_tag("debug_log.txt", "[DEBUG]", "Prepping boss counter %i", i); + kls_log(kls, "DEBUG", "Prepping boss counter %i", i); + Turncounter *c = + (Turncounter *) KLS_PUSH_T_TYPED(t_kls, Turncounter, + HR_Turncounter, "Turncounter", + "Turncounter"); + + //First, prepare counters for statuses + if (i < STATUSMAX + 1) { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof(stringFromStatus(i)), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, stringFromStatus(i)); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for boss status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for boss status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + + c->effect_b_fun = getStatusCounterBossFun(i); + //sprintf(msg,"Boss status function pointer is: (%i)", *(c->effect_b_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + c->type = CNT_STATUS; + + } else { //Then, counters for boosts to (all?) stats + + switch (i) { + case TURNBOOST_ATK: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("ATK boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ATK boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("ATK boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("ATK boost"), c->desc); + + c->boost_b_fun = getStatBoostCounterBossFun(ATK); + c->type = CNT_ATKBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_DEF: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("DEF boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "DEF boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("DEF boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("DEF boost"), c->desc); + + c->boost_b_fun = getStatBoostCounterBossFun(DEF); + c->type = CNT_DEFBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_VEL: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("VEL boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "VEL boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("VEL boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("VEL boost"), c->desc); + + c->boost_b_fun = getStatBoostCounterBossFun(VEL); + c->type = CNT_VELBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_ENR: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("ENR boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ENR boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("ENR boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for boss stat counter: (%s)", + sizeof("ENR boost"), c->desc); + + c->boost_b_fun = getStatBoostCounterBossFun(ENR); + c->type = CNT_ENRBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_b_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "ERROR INITALISING TURNCOUNTER in initBCounters()\n"); + exit(EXIT_FAILURE); + } + } + } //End else + c->count = 0; + c->innerValue = 0; + b->counters[i] = (struct Turncounter *)c; + }; +} + +/** + * Takes a FoeParty pointer and prepares its counters field by allocating all the Turncounter accounted in counterIndexes. + * Counters are initialised using the ordering of counterIndexes, primarily for distinguinsing what kind of function pointer will be registered in the counter. + * For a given Counter, only the correct pointer field is assigned and the others are left untouched. + * @see FoeParty + * @see Turncounter + * @see Countertype + * @see COUNTERSMAX + * @see counterIndexes + * @see get_StatBoostCounter_FoeParty_Fun() + * @see get_StatusCounter_FoeParty_Fun() + * @param fp The FoeParty pointer whose counters field will be initialised. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initFoePartyCounters(FoeParty *fp, Koliseo_Temp *t_kls) +{ + //Ordering of i corresponds to counterIndexes enum + int total = (COUNTERSMAX + 1); + Koliseo *kls = t_kls->kls; + for (int i = 0; i < total; i++) { + log_tag("debug_log.txt", "[DEBUG]", "Prepping foeparty counter %i", i); + kls_log(kls, "DEBUG", "Prepping foeparty counter %i", i); + Turncounter *c = + (Turncounter *) KLS_PUSH_T_TYPED(t_kls, Turncounter, + HR_Turncounter, "Turncounter", + "Turncounter"); + + //First, prepare counters for statuses + if (i < STATUSMAX + 1) { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof(stringFromStatus(i)), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, stringFromStatus(i)); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for foeparty status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for foeparty status counter: (%s)", + sizeof(stringFromStatus(i)), c->desc); + + //c->effect_fp_fun = get_StatusCounter_FoeParty_Fun(i); + //sprintf(msg,"Foeparty status function pointer is: (%i)", *(c->effect_b_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + c->type = CNT_STATUS; + + } else { //Then, counters for boosts to (all?) stats + + switch (i) { + case TURNBOOST_ATK: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("ATK boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ATK boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("ATK boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("ATK boost"), c->desc); + + c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(ATK); + c->type = CNT_ATKBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_DEF: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("DEF boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "DEF boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("DEF boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("DEF boost"), c->desc); + + c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(DEF); + c->type = CNT_DEFBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_VEL: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("VEL boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "VEL boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("VEL boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("VEL boost"), c->desc); + + c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(VEL); + c->type = CNT_VELBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + case TURNBOOST_ENR: { + c->desc = + (char *)KLS_PUSH_ARR_T_TYPED(t_kls, char *, + sizeof("ENR boost"), + HR_Turncounter_desc, + "Turncounter desc", + "Turncounter desc"); + strcpy(c->desc, "ENR boost"); + log_tag("debug_log.txt", "[DEBUG]", + "Allocated size %lu for status counter: (%s)", + sizeof("ENR boost"), c->desc); + kls_log(kls, "DEBUG", + "Allocated size %lu for status counter: (%s)", + sizeof("ENR boost"), c->desc); + + c->boost_fp_fun = get_StatBoostCounter_FoeParty_Fun(ENR); + c->type = CNT_ENRBOOST; + //sprintf(msg,"Stat boost function pointer is: (%i)", *(c->boost_fp_fun)); + //log_tag("debug_log.txt","[DEBUG]",msg); + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Invalid counter in initFoePartyCounters"); + exit(EXIT_FAILURE); + } + } + } //End else + c->count = 0; + c->innerValue = 0; + fp->counters[i] = (struct Turncounter *)c; + }; +} + +/** + * Takes a Fighter pointer and prepares its equipslots field by allocating an Equipslot for each Equipzone. + * @see Fighter + * @see Equipslot + * @see Equipzone + * @see counterIndexes + * @see EQUIPZONES + * @param f The Fighter pointer whose equipslots field will be initialised. + * @param kls The Koliseo used for allocations. + */ +void initEquipSlots(Fighter *f, Koliseo *kls) +{ + for (int i = 0; i <= EQUIPZONES; i++) { + kls_log(kls, "DEBUG", "Prepping Equipslot (%i)", i); + Equipslot *s = + (Equipslot *) KLS_PUSH_TYPED(kls, Equipslot, HR_Equipslot, + "Equipslot", "Equipslot"); + s->active = 0; + s->type = i; + setEquipslotSprite(s); + f->equipslots[i] = (struct Equipslot *)s; + }; +} + +/** + * Takes a Fighter pointer and prepares its artifactsBag field by allocating a Artifact for each artifactClass. + * @see Fighter + * @see Artifact + * @see artifactClass + * @see ARTIFACTSMAX + * @param kls The Koliseo used for allocations. + * @param f The Fighter pointer whose artifactsBag field will be initialised. + */ +void initArtifactsBag(Fighter *f, Koliseo *kls) +{ + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + kls_log(kls, "DEBUG", "Prepping Artifact (%i)", i); + Artifact *a = + (Artifact *) KLS_PUSH_TYPED(kls, Artifact, HR_Artifact, + "Artifact", "Artifact"); + a->class = i; + + Artifact *base = &artifactsBase[i]; + + strcpy(a->name, base->name); + strcpy(a->desc, base->desc); + for (int j = 0; j < 8; j++) { + strcpy(a->sprite[j], base->sprite[j]); + } + a->qty = 0; + + f->artifactsBag[i] = (struct Artifact *)a; + } +} + +/** + * Takes one Fighter and one Path pointers and initialises the fighter fields. + * Luck value is set as path luck value modulo MAXPLAYERLUCK. + * The BaseStats pointer for the fighter's figtherClass is loaded. + * The stats field is initalised with all inner values at 0. + * setSpecials(), initCounters() are called to init the specialslots and counters fields. + * initEquipSlots() is called to init the equipslots field, and the relative int field are set to 0. + * initArtifactsFun() is called to init all the Artifact effect_fun field. + * All the tempboost_STAT and permboost_STAT fields are set to 0. + * All the fields common to BaseStats are initialised with the base value. + * The status field is set to Normal. + * @see Fighter + * @see fighterClass + * @see Path + * @see BaseStats + * @see countStats + * @see MAXPLAYERLUCK + * @see setSpecials() + * @see initCounters() + * @see initEquipSlots() + * @see initArtifactsFun() + * @see fighterStatus + * @param player The Fighter whose fields will be initialised. + * @param path The Path pointer of the current game. + * @param kls The Koliseo used for allocation. + */ +void initPlayerStats(Fighter *player, Path *path, Koliseo *kls) +{ + + //player luck : MAXPLAYERLUCK = path luck : MAXLUCK + + player->luck = (path->luck * MAXPLAYERLUCK) / MAXLUCK; + + BaseStats *base = &basestats[player->class]; + + kls_log(kls, "DEBUG", "Prepping countStats"); + countStats *s = + (countStats *) KLS_PUSH_TYPED(kls, countStats, HR_countStats, + "countStats", "countStats"); + + s->enemieskilled = 0; + s->criticalhits = 0; + s->consumablesfound = 0; + s->equipsfound = 0; + s->artifactsfound = 0; + s->roomscompleted = 0; + s->floorscompleted = 0; + s->specialsunlocked = 0; + s->coinsfound = 0; + s->bosseskilled = 0; + s->unique_bosseskilled = 0; + for (int i = 0; i < BOSSCLASSESMAX + 1; i++) { + s->killed_bosses[i] = 0; + } + s->keysfound = 0; + + setSpecials(player, kls); + setSkills(player, kls); + initCounters(player, kls); + initPerks(player, kls); + + initConsumableBag(player, kls); + initArtifactsBag(player, kls); + + initEquipSlots(player, kls); + player->equipsBagOccupiedSlots = 0; //Keeps track of how many slots are occupied. + player->earliestBagSlot = 0; //To alwasy use the array efficiently (???) I sense linked lists may be better + + player->permboost_atk = 0; + player->permboost_def = 0; + player->permboost_vel = 0; + player->permboost_enr = 0; + + player->equipboost_atk = 0; + player->equipboost_def = 0; + player->equipboost_vel = 0; + player->equipboost_enr = 0; + + player->balance = 0; + player->keys_balance = 0; + + player->stats = s; + player->hp = base->hp; + player->totalhp = base->totalhp; + player->atk = base->atk; + player->def = base->def; + player->vel = base->vel; + player->level = base->level; + player->totalxp = base->totalxp; + player->currentlevelxp = base->currentlevelxp; + player->totallevelxp = base->totallevelxp; + player->status = Normal; + player->totalenergy = base->totalenergy; + player->energy = player->totalenergy; + player->totalstamina = base->totalstamina; + player->stamina = player->totalstamina; + + setFighterSprite(player); +} + +/** + * Takes one Enemy pointer and initialises the enemy fields. + * The EnemyBaseStats pointer for the enemy's enemyClass is loaded. + * If the beast field at the pointer is already set before this call, atk def vel and hp of the enemy will receive a multiplicative boost equal to BSTFACTOR . Also, Xp value will be multiplied by 3. + * Notably, the level field is not set at all by this function and needs to be set by the caller. + * All the fields common to EnemyBaseStats are initialised with the base value and eventual beast boost. + * initECounters() is called to init the counters field. + * The status field is set to Normal. + * @see Enemy + * @see enemyClass + * @see EnemyBaseStats + * @see initECounters() + * @see fighterStatus + * @param e The Enemy whose fields will be initialised. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initEnemyStats(Enemy *e, Koliseo_Temp *t_kls) +{ + EnemyBaseStats *base = &baseenemystats[e->class]; + log_tag("debug_log.txt", "[DEBUG]", "Init stats for enemy (%s)", + stringFromEClass(e->class)); + + float beastf = 1; + + if (e->beast) { + beastf = BSTFACTOR; + } + + e->hp = round(beastf * base->hp); + e->totalhp = round(beastf * base->totalhp); + e->atk = round(beastf * base->atk); + e->def = round(beastf * base->def); + e->vel = round(beastf * base->vel); + e->status = Normal; + + //Level should be set by caller + //Index should be set by caller + + e->totalenergy = base->totalenergy; + e->energy = e->totalenergy; + e->totalstamina = base->totalstamina; + e->stamina = e->totalstamina; + + //Set prize, double for beasts + float prize = 2.8 * e->level; + + e->prize = floor((e->beast) ? 2 * prize : prize); + + initECounters(e, t_kls); + + //Triple xp for beasts + e->xp = (e->beast) ? 3 * base->xp : base->xp; + + setEnemySprite(e); +} + +/** + * Takes one Boss pointer and initialises the boss fields. + * The BossBaseStats pointer for the boss's bossClass is loaded. + * If the beast field at the pointer is already set before this call, atk def vel and hp of the enemy will receive a multiplicative boost equal to BSTFACTOR . Xp value will also be multiplie by 3. + * Notably, the level field is not set at all by this function and needs to be set by the caller. + * All the fields common to BossBaseStats are initialised with the base value and eventual beast boost. + * initBCounters() is called to init the counters field. + * The status field is set to Normal. + * @see Boss + * @see bossClass + * @see BossBaseStats + * @see initBCounters() + * @see fighterStatus + * @param b The Boss whose fields will be initialised. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initBossStats(Boss *b, Koliseo_Temp *t_kls) +{ + //Class should be set by caller + BossBaseStats *base = &basebossstats[b->class]; + + float beastf = 1; + + if (b->beast) { + beastf = BSTFACTOR; + } + + b->hp = round(beastf * base->hp); + b->totalhp = round(beastf * base->totalhp); + b->atk = round(beastf * base->atk); + b->def = round(beastf * base->def); + b->vel = round(beastf * base->vel); + b->status = Normal; + + //Level should be set by caller + + b->totalenergy = base->totalenergy; + b->energy = b->totalenergy; + + b->totalstamina = base->totalstamina; + b->stamina = b->totalstamina; + + //Set prize, double for beasts + float prize = 4.5 * b->level; + + b->prize = (b->beast) ? 2 * prize : prize; + + initBCounters(b, t_kls); + + //Triple xp for beasts + b->xp = (b->beast) ? 3 * base->xp : base->xp; + + setBossSprite(b); +} + +/** + * Takes one FoeParty pointer and initialises the party fields. + * The FoePartyBaseStats pointer for the FoeParty's foePartyClass is loaded. + * All the fields common to FoePartyBaseStats are initialised with the base value. + * initFoePartyCounters() is called to init the counters field. + * @see FoeParty + * @see foePartyClass + * @see FoePartyBaseStats + * @see initFoePartyCounters() + * @param fp The FoeParty whose fields will be initialised. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initFoePartyStats(FoeParty *fp, Koliseo_Temp *t_kls) +{ + //Class should be set by caller + //FoePartyBaseStats* base = &basefoepartystats[fp->class]; + //TODO: add loading of more base stats not expected in prepareFoeParty() + + //Level should be set by caller + + //Zero the alive_enemies values + for (int i = 0; i < ROOM_ENEMIES_MAX + 1; i++) { + fp->alive_enemies[i] = 0; + }; + //Zero the alive_bosses values + for (int i = 0; i < FOES_BOSSES_MAX + 1; i++) { + fp->alive_bosses[i] = 0; + }; + + //Zero the turnboost_STAT values + fp->turnboost_atk = 0; + fp->turnboost_def = 0; + fp->turnboost_vel = 0; + fp->turnboost_enr = 0; + + //Zero current enemy index + fp->current_index = 0; + + //Size value should be set by caller + fp->tot_alive = fp->size; + + switch (fp->class) { + case Enemies: { + //Set alive_enemies values + for (int i = 0; i < fp->tot_alive + 1; i++) { + fp->alive_enemies[i] = 1; + }; + } + break; + case Bosses: { + //Set alive_bosses values + for (int i = 0; i < fp->tot_alive + 1; i++) { + fp->alive_bosses[i] = 1; + }; + } + break; + default: { + fprintf(stderr, "UNEXPECTED FOEPARTY CLASS VALUE %i", fp->class); + log_tag("debug_log.txt", "[PANIC]", + "Invalid class value in initFoePartyStats()"); + exit(EXIT_FAILURE); + } + break; + }; + + //Init party counters + initFoePartyCounters(fp, t_kls); +} + +/** + * Takes a FoeParty pointer, a size for complete party, and an integer for the current room index, and initialises all the fields making the FoeParty ready for use in battle. + * Calls initFoePartyStats() after setting class and level + * @see FoeParty + * @see initFoePartyStats() + * @param fp The allocated FoeParty pointer to initialise. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void prepareFoeParty(FoeParty *fp, int partysize, int roomindex, + Koliseo_Temp *t_kls) +{ + + //Class must be set by caller + + FoePartyBaseStats *base = &basefoepartystats[fp->class]; + + fp->level = base->level; + //Set size value + fp->size = partysize; + + //FoeParty's get 1 level every 2 rooms + //fp->level += floor(roomindex / 2) ; + + //Load foeparty stats + initFoePartyStats(fp, t_kls); + + log_tag("debug_log.txt", "[DEBUG]", + "Prepared FoeParty with size (%i), room #%i.", partysize, + roomindex); +} + +/** + * Takes a Fighter pointer and prepares its skillSlot fields by allocating FIGHTER_SKILL_SLOTS slots. + * Skill slots are initialised. + * @see Fighter + * @see Skilllot + * @see FIGHTER_SKILL_SLOTS + * @see SKILL_TYPE_LAST_UNLOCKABLE + * @see costFromSkill() + * @see stringFromSkill() + * @param kls The Koliseo used for allocations. + * @param f The Fighter pointer whose skill slots will be initialised. + */ +void setSkills(Fighter *f, Koliseo *kls) +{ + char movename[80]; + char movedesc[80]; + for (int i = 0; i <= FIGHTER_SKILL_SLOTS; i++) { + kls_log(kls, "DEBUG", "Prepping Skillslot (%i)", i); + Skillslot *s = + (Skillslot *) KLS_PUSH_TYPED(kls, Skillslot, HR_Skillslot, + "Skillslot", "Skillslot"); + s->enabled = 0; + s->class = i; + s->cost = costFromSkill(i); + strcpy(movename, nameStringFromSkill(i)); + strcpy(movedesc, descStringFromSkill(i)); + //printf("DEBUG\n%i\t%s\n",(i),stringFromSkill(i)); + strcpy(s->name, movename); + strcpy(s->desc, movedesc); + f->skills[i] = s; + }; +} + +/** + * Takes a Chest and Fighter pointers and initialises all the fields in chest based on chest class and fighter stats. + * @see Chest + * @param c The allocated Chest pointer with already set class to initialise. + * @param f The Fighter pointer with stats. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initChest(Chest *c, Fighter *f, Koliseo_Temp *t_kls) +{ + + setChestSprite(c); + + strcpy(c->desc, descStringFromChest(c->class)); + int cons_cnt, equip_cnt; + Koliseo *kls = t_kls->kls; + + switch (c->class) { + case CHEST_BASE: { + cons_cnt = rand() % (CHEST_CONSUMABLES_MAX - 1); + equip_cnt = rand() % (CHEST_EQUIPS_MAX - 1); + } + break; + case CHEST_BEAST: { + cons_cnt = (rand() % (CHEST_CONSUMABLES_MAX)) + 1; + equip_cnt = (rand() % (CHEST_EQUIPS_MAX)) + 1; + + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "%i is not a valid chest class.", c->class); + exit(EXIT_FAILURE); + } + break; + + } + + c->consumablesCount = cons_cnt; + c->equipsCount = equip_cnt; + + if (c->consumablesCount > 0) { + for (int i = 0; i < c->consumablesCount; i++) { + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Consumable (%i/%i) for Chest", i, + c->consumablesCount); + kls_log(kls, "DEBUG", "Prepping Consumable (%i/%i) for Chest", i, + c->consumablesCount); + Consumable *cns = + (Consumable *) KLS_PUSH_T_TYPED(t_kls, Consumable, + HR_Consumable, "Consumable", + "Consumable"); + int drop = rand() % (CONSUMABLESMAX + 1); + + cns->class = drop; + + Consumable *base = &consumablesBase[drop]; + + strcpy(cns->name, base->name); + strcpy(cns->desc, base->desc); + for (int j = 0; j < 8; j++) { + strcpy(cns->sprite[j], base->sprite[j]); + } + cns->qty = 1; + + c->consumables[i] = cns; + } + } + + if (c->equipsCount > 0) { + for (int i = 0; i < c->equipsCount; i++) { + + //Select a basic item from the list + int drop = rand() % (EQUIPSMAX + 1); + //Randomise quality + quality q = rand() % (QUALITIESMAX + 1); + + //Prepare the item + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Equip (%i/%i) for Chest", i, c->equipsCount); + kls_log(kls, "DEBUG", "Prepping Equip (%i/%i) for Chest", i, + c->equipsCount); + Equip *e = + (Equip *) KLS_PUSH_T_TYPED(t_kls, Equip, HR_Equip, "Equip", + "Equip"); + + //Get the base item and copy the stats to the drop + Equip *base = &equips[drop]; + + e->class = base->class; + e->type = base->type; + e->qual = q; + + setEquipSprite(e); + strcpy(e->name, base->name); + strcpy(e->desc, base->desc); + + e->qty = 1; + e->equipped = 0; + + e->perksCount = 0; + + //Calc drop level + e->level = base->level + round(f->level / EQUIPLVLBOOSTRATIO); + + //Chance for better leveled item + if ((rand() % 8) - (f->luck / 10) <= 0) { //Should use a defined constant + e->level += 1; //At least a simple +1 + if ((rand() % 25) - (f->luck / 10) <= 0) { //Should use a defined constant + e->level += 1; //A bonus roll for another +1 + + } + } + + float boostFactor = 0.7; + + float lvlBoost = boostFactor * (e->level - 1); + + e->atk = round((base->atk * 1.0) + lvlBoost); + e->def = round((base->def * 1.0) + lvlBoost); + e->vel = round((base->vel * 1.0) + lvlBoost); + e->enr = round((base->enr * 1.0) + lvlBoost); + + //Bonus stats on better quality items? Simple for now + + if (q == Good) { + e->atk += (rand() % 3); //Should use a defined constant + e->def += (rand() % 3); //Should use a defined constant + e->vel += (rand() % 3); //Should use a defined constant + e->enr += (rand() % 2); //Should use a defined constant + } else if (q == Bad) { + e->atk -= (rand() % 3); //Should use a defined constant + e->def -= (rand() % 3); //Should use a defined constant + e->vel -= (rand() % 3); //Should use a defined constant + e->enr -= (rand() % 2); //Should use a defined constant + if (e->atk < 0) { + e->atk = 0; + }; + if (e->def < 0) { + e->def = 0; + }; + if (e->vel < 0) { + e->vel = 0; + }; + if (e->enr < 0) { + e->enr = 0; + }; + } + //Possible perks for the Equip + + for (int j = 0; j < (EQUIPPERKSMAX); j++) { + int chance = 20; + + if (q == Good) { + chance *= 1.5; + } + + if ((rand() % 100) < chance + || (c->class == CHEST_BEAST && e->perksCount == 0)) { + + e->perksCount += 1; + + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Perk (%i/%i) for Equip (%i/%i) for Chest", + j, e->perksCount, i, c->equipsCount); + kls_log(kls, "DEBUG", + "Prepping Perk (%i/%i) for Equip (%i/%i) for Chest", + j, e->perksCount, i, c->equipsCount); + Perk *p = + (Perk *) KLS_PUSH_T_TYPED(t_kls, Perk, HR_Perk, + "Perk", "Perk"); + p->class = rand() % (PERKSMAX + 1); + //p->name = (char*)malloc(sizeof(nameStringFromPerk(p->class))); + strcpy(p->name, nameStringFromPerk(p->class)); + //p->desc = (char*)malloc(sizeof(descStringFromPerk(p->class))); + strcpy(p->desc, descStringFromPerk(p->class)); + p->innerValue = 1; + e->perks[(e->perksCount - 1)] = p; + } + } + + //Set value of how many bonuses we have. Although Equip only has ONE function pointer field for now + e->bonus = base->bonus; + //Randomise if the item will have an effect function. + //Not yet implemented + //Initialisation of function happens here + // + //e->equip_fun = ; + + //Calc cost value + + float cost = 5; + + cost += 2.5 * (e->qual); + cost += 3.5 * (e->perksCount); + + cost += 7.2 * (e->level); + + e->cost = floor(cost); + + c->equips[i] = e; + } //End for all equips + } //End if equipsCount > 0 +} + +/** + * Takes one Shop pointer and initialises all the fields, depeding on stats from the Fighter pointer passed. + * @see Shop + * @param s The Shop whose fields will be initialised. + * @param indexWeight The integer for room index weight. + * @param player The Fighter player to influence item generation. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initShop(Shop *s, int indexWeight, Fighter *player, Koliseo_Temp *t_kls) +{ + + int equipsCount = (rand() % EQUIP_SHOP_MAX) + 1; + Koliseo *kls = t_kls->kls; + + if (equipsCount != 0) { + + for (int equip_index = 0; equip_index < equipsCount; equip_index++) { + int curr = (rand() % (EQUIPSMAX + 1)); + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Equip (%i/%i) for Shop", equip_index, + equipsCount); + kls_log(kls, "DEBUG", "Prepping Equip (%i/%i) for Shop", + equip_index, equipsCount); + Equip *e = + (Equip *) KLS_PUSH_T_TYPED(t_kls, Equip, HR_Equip, "Equip", + "Equip"); + + //Randomise quality + quality q = rand() % (QUALITIESMAX + 1); + + //Get the base item and copy the stats to the current equip + Equip *base = &equips[curr]; + + e->class = base->class; + e->type = base->type; + e->qual = q; + + setEquipSprite(e); + strcpy(e->name, base->name); + strcpy(e->desc, base->desc); + + e->qty = 1; + e->equipped = 0; + e->perksCount = 0; + + //Calc drop level + e->level = base->level + round(player->level / EQUIPLVLBOOSTRATIO); + + //Chance for better leveled item + if ((rand() % 8) - (player->luck / 10) <= 0) { //Should use a defined constant + e->level += 1; //At least a simple +1 + if ((rand() % 25) - (player->luck / 10) <= 0) { //Should use a defined constant + e->level += 1; //A bonus roll for another +1 + + } + } + + float boostFactor = 0.7; + + float lvlBoost = boostFactor * (e->level - 1); + + e->atk = round((base->atk * 1.0) + lvlBoost); + e->def = round((base->def * 1.0) + lvlBoost); + e->vel = round((base->vel * 1.0) + lvlBoost); + e->enr = round((base->enr * 1.0) + lvlBoost); + + //Bonus stats on better quality items? Simple for now + // + if (q == Good) { + e->atk += (rand() % 3); //Should use a defined constant + e->def += (rand() % 3); //Should use a defined constant + e->vel += (rand() % 3); //Should use a defined constant + e->enr += (rand() % 2); //Should use a defined constant + } else if (q == Bad) { + e->atk -= (rand() % 3); //Should use a defined constant + e->def -= (rand() % 3); //Should use a defined constant + e->vel -= (rand() % 3); //Should use a defined constant + e->enr -= (rand() % 2); //Should use a defined constant + if (e->atk < 0) { + e->atk = 0; + }; + if (e->def < 0) { + e->def = 0; + }; + if (e->vel < 0) { + e->vel = 0; + }; + if (e->enr < 0) { + e->enr = 0; + }; + } + //Possible perks for the Equip + + for (int i = 0; i < (EQUIPPERKSMAX); i++) { + int chance = 35; + + if (q == Good) { + chance *= 1.5; + } + + if ((rand() % 100) < chance) { + + e->perksCount += 1; + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Perk (%i) for Shop Equip (%i/%i)", i, + equip_index, equipsCount); + kls_log(kls, "DEBUG", + "Prepping Perk (%i) for Shop Equip (%i/%i)", i, + equip_index, equipsCount); + Perk *p = + (Perk *) KLS_PUSH_T_TYPED(t_kls, Perk, HR_Perk, + "Perk", "Perk"); + p->class = rand() % (PERKSMAX + 1); + //p->name = (char*)malloc(sizeof(nameStringFromPerk(p->class))); + strcpy(p->name, nameStringFromPerk(p->class)); + //p->desc = (char*)malloc(sizeof(descStringFromPerk(p->class))); + strcpy(p->desc, descStringFromPerk(p->class)); + p->innerValue = 1; + e->perks[(e->perksCount - 1)] = p; + } + } + + //Set value of how many bonuses we have. Although Equip only has ONE function pointer field for now + e->bonus = base->bonus; + //Randomise if the item will have an effect function. + //Not yet implemented + //Initialisation of function happens here + // + //e->equip_fun = ; + + //Calc cost value + + float cost = 3; + + cost += 4.5 * (e->qual + 1); + cost += 7.5 * (e->perksCount); + + cost += 10.2 * (e->level); + + e->cost = floor(cost); + + s->equips[equip_index] = e; + s->equipsCount++; + + } //End for all equips + } + s->equipsCount = equipsCount; + setEquipPrices(s->equipsCount, s->equipPrices, s->equips); + + int uniqueConsumablesCount = (rand() % SINGLE_CONSUMABLE_SHOP_MAX) + 1; + int uniques = 0; + //int not_uniques = 0; + if (uniqueConsumablesCount != 0) { + int already_rolled[CONSUMABLESMAX + 1]; + for (int i = 0; i < (CONSUMABLESMAX + 1); i++) { + already_rolled[i] = 0; + } + int cons_prepared = 0; + while (cons_prepared < uniqueConsumablesCount) { + + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + if (cons_prepared < uniqueConsumablesCount) { + int curr = rand() % (CONSUMABLESMAX + 1); + if (!(already_rolled[curr])) { + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Consumable (%i/%i) for Shop", + cons_prepared, uniqueConsumablesCount); + kls_log(kls, "DEBUG", + "Prepping Consumable (%i/%i) for Shop", + cons_prepared, uniqueConsumablesCount); + Consumable *cur = + (Consumable *) KLS_PUSH_T_TYPED(t_kls, Consumable, + HR_Consumable, + "Consumable", + "Consumable"); + cur->class = curr; + already_rolled[curr] = 1; + if (uniqueConsumablesCount - cons_prepared > 0) { + cur->qty = (rand() % 4) + 1; + } else { + cur->qty = 1; + //cur->qty = (rand() % (consumablesCount - cons_index)) +1; + } + setConsumableSprite(cur); + //not_uniques += cur->qty; + cons_prepared++; //= cur->qty; + s->consumables[uniques] = cur; + uniques++; + } + } + }; + } + } + s->consumablesCount = uniqueConsumablesCount; + setConsumablePrices(s->consumablesCount, s->consumablePrices, + s->consumables); + + s->itemCount = s->consumablesCount + s->equipsCount; +} + +/** + * Takes a Treasure and Fighter pointers and initialises all the treasure fields based on its class and fighter's stats. + * @see Treasure + * @param t The allocated Treasure pointer with already set class to initialise. + * @param f The Fighter pointer to influence item generation. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void initTreasure(Treasure *t, Fighter *f, Koliseo_Temp *t_kls) +{ + + Koliseo *kls = t_kls->kls; + strcpy(t->desc, descStringFromTreasure(t->class)); + + switch (t->class) { + case TREASURE_CHEST: { + + log_tag("debug_log.txt", "[DEBUG]", + "Allocated %lu for Treasure [Chest]:", sizeof(Chest)); + kls_log(kls, "DEBUG", "Allocated %lu for Treasure [Chest]:", + sizeof(Chest)); + Chest *c = + (Chest *) KLS_PUSH_T_TYPED(t_kls, Chest, HR_Chest, "Chest", + "Chest"); + prepareChest(c, f, t_kls); + t->chest = c; + + } + break; + case TREASURE_CONSUMABLE: { + log_tag("debug_log.txt", "[DEBUG]", + "Allocated %lu for Treasure [Consumable]:", + sizeof(Consumable)); + kls_log(kls, "DEBUG", "Allocated %lu for Treasure [Consumable]:", + sizeof(Consumable)); + Consumable *cns = + (Consumable *) KLS_PUSH_T_TYPED(t_kls, Consumable, + HR_Consumable, "Consumable", + "Consumable"); + int drop = rand() % (CONSUMABLESMAX + 1); + + cns->class = drop; + + Consumable *base = (Consumable *) f->consumablesBag[drop]; + + strcpy(cns->name, base->name); + strcpy(cns->desc, base->desc); + for (int j = 0; j < 8; j++) { + strcpy(cns->sprite[j], base->sprite[j]); + } + cns->qty = 1; + + t->consumable = cns; + } + break; + case TREASURE_ARTIFACT: { + log_tag("debug_log.txt", "[DEBUG]", + "Allocated %lu for Treasure [Artifact]:", sizeof(Artifact)); + kls_log(kls, "DEBUG", "Allocated %lu for Treasure [Artifact]:", + sizeof(Artifact)); + Artifact *a = + (Artifact *) KLS_PUSH_T_TYPED(t_kls, Artifact, HR_Artifact, + "Artifact", "Artifact"); + int drop = -1; + do { + drop = rand() % (ARTIFACTSMAX + 1); + } while (f->artifactsBag[drop]->qty > 0); + + a->class = drop; + + Artifact *base = f->artifactsBag[drop]; + + strcpy(a->name, base->name); + strcpy(a->desc, base->desc); + for (int j = 0; j < 8; j++) { + strcpy(a->sprite[j], base->sprite[j]); + } + a->qty = 0; + + t->artifact = a; + + } + break; + } +} + +/** + * Takes a Chest and Fighter pointers and initialises all the fields in chest making it ready for use in battle, using fighter stats to influence init. + * Calls initChest() after setting class. + * @see Chest + * @see initChest() + * @param c The allocated Chest pointer to initialise. + * @param f The Fighter pointer to influence item generation. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void prepareChest(Chest *c, Fighter *f, Koliseo_Temp *t_kls) +{ + + //Init chest class + int drop = (rand() % 100) + 1; + + if (drop > 70) { + c->class = CHEST_BASE; + } else { + c->class = CHEST_BEAST; + } + + //Load Chest stats + initChest(c, f, t_kls); + +} + +/** + * Takes a Boss pointer and initialises all the fields making it ready for use in battle. + * Calls initBossStats() after setting class and level, then forces a stat reset to update the stats + * with the level boost. + * @see Boss + * @see initBossStats() + * @param b The allocated Boss pointer to initialise. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void prepareBoss(Boss *b, Koliseo_Temp *t_kls) +{ + + //Randomise boss class + b->class = rand() % (BOSSCLASSESMAX + 1); + + b->beast = 0; + BossBaseStats *base = &basebossstats[b->class]; + + b->level = base->level; + + //Enemies get 1 level every 2 rooms + //e->level += floor(roomindex / 2) ; + + //Load boss stats + initBossStats(b, t_kls); + + //Set skill slots + setBossSkills(b, t_kls); + + //Force load of level bonuses + statResetBoss(b, 1); + +} + +/** + * Takes a Enemy and three integers denoting current room index, how many enemies are in the room and current enemy index. + * The class field of the enemy is randomised according to ENEMYCLASSESMAX. + * If the room index is multiple of BEASTROOM and the enemy is the last one in he room, its beast field is set to 1. + * The EnemyBaseStats pointer for the enemy's enemyClass is loaded and the level field for the enemy is set to base level, before increasing. + * initEnemyStats() is called to set all stat fields and statResetEnemy() is called with force=true to apply the boosted stats to leveled enemies. + * @see Enemy + * @see enemyClass + * @see ENEMYCLASSESMAX + * @see BEASTROOM + * @see BSTFACTOR + * @see ENEMYLVLRATIO + * @see EnemyBaseStats + * @see initEnemyStats() + * @see statResetEnemy() + * @param e The Enemy pointer to prepare. + * @param roomindex The index of current room. + * @param enemiesInRoom The number of enemies in current room. + * @param enemyindex The index of current enemy. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void prepareRoomEnemy(Enemy *e, int roomindex, int enemiesInRoom, + int enemyindex, Koliseo_Temp *t_kls) +{ + + //Randomise enemy class + e->class = rand() % (ENEMYCLASSESMAX + 1); + + if (G_DEBUG_ON && G_DEBUG_ENEMYTYPE_ON && (GAMEMODE != Rogue)) { //Debug flag has a fixed enemy class when used outside of Rogue gamemode + log_tag("debug_log.txt", "[DEBUG]", + "prepareRoomEnemy(): Enemy debug flag was asserted outside of story mode, will always spawn a G_DEBUG_ENEMYTYPE (%s).", + stringFromEClass(G_DEBUG_ENEMYTYPE)); + e->class = G_DEBUG_ENEMYTYPE; + } + + //Check for spawning beast enemies + if ((roomindex % BEASTROOM == 0) && (enemyindex == (enemiesInRoom - 1))) { + //TODO: better mechanic for spawning beast enemies + if (((rand() % 5) == 0)) { + log_tag("debug_log.txt", "[DEBUG]", "Setting e->beast to 1."); + e->beast = 1; + } + } else { + e->beast = 0; + }; + + EnemyBaseStats *base = &baseenemystats[e->class]; + + e->level = base->level; + + //Enemies get 1 level every 2 rooms + e->level += floor(roomindex / 2); + + //Set current enemy index + e->index = enemyindex; + + //Load enemy stats + initEnemyStats(e, t_kls); + + //Load enemy skills + // + setEnemySkills(e, t_kls); + + //Force load of level bonuses + statResetEnemy(e, 1); +} + +/** + * Takes a Treasure and Fighter pointer and initialises all the treasure fields making it ready for use in battle, based on the fighter stats. + * Calls initTreasure() after setting class. + * @see Treasure + * @see initTreasure() + * @param t The allocated Treasure pointer to initialise. + * @param f The Fighter pointer to influence item generation. + * @param t_kls The Koliseo_Temp used for allocations. + */ +void prepareTreasure(Treasure *t, Fighter *f, Koliseo_Temp *t_kls) +{ + + //Init treasure class + + int roll = (rand() % 100) + 1; + + if (roll > 70) { + t->class = TREASURE_CHEST; + } else if (roll > 50) { + t->class = TREASURE_ARTIFACT; + } else { + t->class = TREASURE_CONSUMABLE; + } + + //Load Treasure stats + initTreasure(t, f, t_kls); + +} + +/** + * Takes a Roadfork pointer and initialises all the fields making it ready for use in battle. + * Calls initRoadfork() after setting class. + * @see Roadfork + * @see initRoadfork() + * @param r The allocated Roadfork pointer to initialise. + */ +void prepareRoadfork(Roadfork *r) +{ + + //Randomise options + r->options[0] = rand() % (ROADFORK_OPTIONS_MAX + 1); + int previous = r->options[0]; + int new = -1; + + do { + new = rand() % (ROADFORK_OPTIONS_MAX + 1); + + } while (new == previous); + + previous = new; + r->options[1] = new; + +} + +/** + * Takes a Enemy pointer and prepares its skillSlot fields by allocating ENEMY_SKILL_SLOTS slots. + * Skill slots are initialised. + * @see Enemy + * @see Skilllot + * @see ENEMY_SKILL_SLOTS + * @see SKILLSTOTAL + * @see costFromSkill() + * @see stringFromSkill() + * @param t_kls The Koliseo_Temp used for allocations. + * @param e The Enemy pointer whose skill slots will be initialised. + */ +void setEnemySkills(Enemy *e, Koliseo_Temp *t_kls) +{ + char movename[80]; + char movedesc[80]; + for (int i = 0; i < ENEMY_SKILL_SLOTS; i++) { + kls_log(t_kls->kls, "DEBUG", "Prepping Enemy Skillslot (%i)", i); + Skillslot *s = + (Skillslot *) KLS_PUSH_T_TYPED(t_kls, Skillslot, HR_Skillslot, + "Enemy Skillslot", "Enemy Skillslot"); + s->enabled = 0; + s->class = i; + s->cost = costFromSkill(i); + strcpy(movename, nameStringFromSkill(i)); + strcpy(movedesc, descStringFromSkill(i)); + //printf("DEBUG\n%i\t%s\n",(i),stringFromSkill(i)); + strcpy(s->name, movename); + strcpy(s->desc, movedesc); + e->skills[i] = s; + }; +} + +/** + * Takes a Boss pointer and prepares its skillSlot fields by allocating BOSS_SKILL_SLOTS slots. + * Skill slots are initialised. + * @see Boss + * @see Skilllot + * @see Boss_SKILL_SLOTS + * @see SKILLSTOTAL + * @see costFromSkill() + * @see stringFromSkill() + * @param t_kls The Koliseo_Temp used for allocations. + * @param b The Boss pointer whose skill slots will be initialised. + */ +void setBossSkills(Boss *b, Koliseo_Temp *t_kls) +{ + char movename[80]; + char movedesc[80]; + for (int i = 0; i < BOSS_SKILL_SLOTS; i++) { + kls_log(t_kls->kls, "DEBUG", "Prepping Boss Skillslot (%i)", i); + Skillslot *s = + (Skillslot *) KLS_PUSH_T_TYPED(t_kls, Skillslot, HR_Skillslot, + "Boss Skillslot", "Boss Skillslot"); + s->enabled = 0; + s->class = i; + s->cost = costFromSkill(i); + strcpy(movename, nameStringFromSkill(i)); + strcpy(movedesc, descStringFromSkill(i)); + //printf("DEBUG\n%i\t%s\n",(i),stringFromSkill(i)); + strcpy(s->name, movename); + strcpy(s->desc, movedesc); + b->skills[i] = s; + }; +} diff --git a/src/utils/game_init.h b/src/utils/game_init.h new file mode 100644 index 00000000..be2f2804 --- /dev/null +++ b/src/utils/game_init.h @@ -0,0 +1,71 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 GAME_INIT_H_ +#define GAME_INIT_H_ + +#include "game_utils.h" +#include "specials.h" + +#ifdef HELAPORDO_CURSES_BUILD +#include "../build-nc/game_curses.h" +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +#include "../build-rl/game_rl.h" +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +void initPerks(Fighter * f, Koliseo * kls); +void initConsumableBag(Fighter * f, Koliseo * kls); + +void initCounters(Fighter * f, Koliseo * kls); +void initECounters(Enemy * e, Koliseo_Temp * t_kls); +void initBCounters(Boss * b, Koliseo_Temp * t_kls); +void initFoePartyCounters(FoeParty * fp, Koliseo_Temp * t_kls); + +void initBossStats(Boss * b, Koliseo_Temp * t_kls); +void prepareBoss(Boss * b, Koliseo_Temp * t_kls); + +void initFoePartyStats(FoeParty * fp, Koliseo_Temp * t_kls); +void prepareFoeParty(FoeParty * fp, int total_foes, int roomindex, + Koliseo_Temp * t_kls); + +void initEquipSlots(Fighter * f, Koliseo * kls); + +void initArtifactsBag(Fighter * f, Koliseo * kls); + +void initPlayerStats(Fighter * player, Path * path, Koliseo * kls); + +void initEnemyStats(Enemy * e, Koliseo_Temp * t_kls); +void setSkills(Fighter *f, Koliseo *kls); +void initChest(Chest * c, Fighter * f, Koliseo_Temp * t_kls); +void initShop(Shop * s, int indexWeight, Fighter * player, + Koliseo_Temp * t_kls); +void initTreasure(Treasure * t, Fighter * f, Koliseo_Temp * t_kls); +void prepareChest(Chest * c, Fighter * f, Koliseo_Temp * t_kls); +void prepareRoomEnemy(Enemy * e, int roomindex, int enemiesInRoom, + int enemyindex, Koliseo_Temp * t_kls); + +void prepareTreasure(Treasure * t, Fighter * f, Koliseo_Temp * t_kls); + +void prepareRoadfork(Roadfork * r); +void setEnemySkills(Enemy *e, Koliseo_Temp *t_kls); +void setBossSkills(Boss *b, Koliseo_Temp *t_kls); +#endif // GAME_INIT_H_ diff --git a/src/utils/game_utils.c b/src/utils/game_utils.c new file mode 100644 index 00000000..d213370f --- /dev/null +++ b/src/utils/game_utils.c @@ -0,0 +1,5293 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "game_utils.h" +//Functions useful in many areas +// + +/** + * Takes a Wincon and a Path pointers and a winconClass and initialises the passed Wincon. + * @see Wincon + * @see Path + * @see winconClass + * @see WINCON_CLASS_MAX + * @param w The Wincon pointer to initialise. + * @param p The Path to use to initialise Wincon. + * @param class The winconClass to use to initialise. + */ +void initWincon(Wincon *w, Path *p, winconClass class) +{ + + w->class = class; + + switch (w->class) { + case ALL_BOSSES: { + w->current_val = 0; + w->target_val = BOSSCLASSESMAX + 1; + + }; + break; + case ALL_ARTIFACTS: { + w->current_val = 0; + w->target_val = ARTIFACTSMAX + 1; + + }; + break; + case FULL_PATH: { + w->current_val = 0; + w->target_val = p->length; + }; + break; + default: { + fprintf(stderr, "\nUnexpected Wincon Class %i\n", w->class); + w->class = -1; + w->current_val = 0; + w->target_val = 1; + } + } +} + +/** + * Prints global vars to stdout. + */ +void printGlobVars(void) +{ + printf("\nGlobal vars:\n"); + printf(" G_PRELOAD_ANIMATIONS_ON: { %i }\n", G_PRELOAD_ANIMATIONS_ON); + printf(" G_DEBUG_ON: { %i }\n", G_DEBUG_ON); + printf(" G_LOG_ON: { %i }\n", G_LOG_ON); + printf(" G_EXPERIMENTAL_ON: { %i }\n", G_EXPERIMENTAL_ON); + printf(" G_FASTQUIT_ON: { %i }\n", G_FASTQUIT_ON); + printf(" G_GODMODE_ON: { %i }\n", G_GODMODE_ON); + printf(" G_DEBUG_ROOMTYPE_ON: { %i }\n", G_DEBUG_ROOMTYPE_ON); + printf(" G_ROOMTYPE_ON: { %s } [ %i ]\n", stringFromRoom(G_DEBUG_ROOMTYPE), + G_DEBUG_ROOMTYPE); + printf(" G_ENEMYTYPE_ON: { %i }\n", G_DEBUG_ENEMYTYPE_ON); + printf(" G_DEBUG_ENEMYTYPE { %s } [ %i ]\n", + stringFromEClass(G_DEBUG_ENEMYTYPE), G_DEBUG_ENEMYTYPE); + printf(" G_DOTUTORIAL_ON: { %i }\n", G_DOTUTORIAL_ON); +} + +#ifdef _WIN32 +/** + * Prints Windows envvars to stdout. + */ +void printWin_EnvVars(void) +{ + printf("\nWindows Environment vars:\n"); + printf(" UserProfile: { %s }\n", getenv("UserProfile")); + printf(" HomeDrive: { %s }\n", getenv("HomeDrive")); + printf(" HomePath: { %s }\n", getenv("HomePath")); + printf(" ComputerName: { %s }\n", getenv("ComputerName")); + printf(" Processor_Revision: { %s }\n", getenv("Processor_Revision")); + printf(" Processor_Identifier: { %s }\n", getenv("Processor_Identifier")); + printf(" Processor_Level: { %s }\n", getenv("Processor_Level")); + printf(" Number_Of_Processors: { %s }\n", getenv("Number_Of_Processors")); + printf(" OS: { %s }\n", getenv("OS")); +} + +/** + * Logs Windows envvars to debug log file. + */ +void log_Win_EnvVars(void) +{ + log_tag("debug_log.txt", "[WIN32-DEBUG]", "Windows Environment vars:"); + log_tag("debug_log.txt", "[WIND32-DEBUG", "UserProfile: { %s }", + getenv("UserProfile")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "HomeDrive: { %s }", + getenv("HomeDrive")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "HomePath: { %s }", + getenv("HomePath")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "ComputerName: { %s }", + getenv("ComputerName")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "Processor_Revision: { %s }", + getenv("Processor_Revision")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "Processor_Identifier: { %s }", + getenv("Processor_Identifier")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "Processor_Level: { %s }", + getenv("Processor_Level")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "Number_Of_Processors: { %s }", + getenv("Number_Of_Processors")); + log_tag("debug_log.txt", "[WIN32-DEBUG]", "OS: { %s }", getenv("OS")); +} +#endif + +#ifdef HELAPORDO_CURSES_BUILD +bool set_Saveslot_name(FILE *file, Saveslot *sv) +{ + + //printf("\nLoading game...\n"); + log_tag("debug_log.txt", "[LOAD]", "Starting loading from text file."); + +// FILE* file = fopen("save.txt", "r"); + if (file == NULL) { + endwin(); + printf("Error with file while trying to load!\n"); + return false; + } + char buf[500]; + char comment[300]; + int num_value = -1; + const char version[] = "v0.1.6"; + + int scanres = -1; + /* File version scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, + 1, scanres); + endwin(); + fprintf(stderr, "Error while loading game."); + return false; + } + + int check = -1; + if (!((check = strcmp(buf, version)) == 0)) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "Failed save format version check. Was [%s]. Quitting.", buf); + endwin(); + fprintf(stderr, "[ERROR] File version mismatch on load.\n"); + return false; + }; + log_tag("debug_log.txt", "[LOAD]", "Loaded save format version: (%s).", + buf); + + /* Save type scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, + 1, scanres); + endwin(); + fprintf(stderr, "Error while loading game."); + return false; + } + + check = -1; + if (! + (((check = strcmp(buf, stringFrom_saveType(ENEMIES_SAVE)) == 0)) + || ((check = strcmp(buf, stringFrom_saveType(HOME_SAVE))) == 0))) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "%s(): Failed save type check, was [%s]. Quitting.", buf); + endwin(); + fprintf(stderr, "[ERROR] Save type version mismatch on load.\n"); + return false; + }; + log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s).", buf); + + /* Gamemode scanning */ + scanres = fscanf(file, "%200[^#]# %s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, + 2, scanres); + endwin(); + fprintf(stderr, "Error while loading game."); + return false; + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + int gmd = num_value; + log_tag("debug_log.txt", "[LOAD]", "Gamemode was: {%i}", gmd); + + /* Fighter scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, + 1, scanres); + endwin(); + fprintf(stderr, "Error while loading game."); + return false; + } + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in %s(), expected [%i] was (%i)", __func__, + 2, scanres); + endwin(); + fprintf(stderr, "Error while loading game."); + return false; + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + strncpy(sv->name, buf, 50); + sv->name[49] = '\0'; + return true; +} +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." +#else +bool set_Saveslot_name(FILE *file, Saveslot *sv) +{ + (void) file; + (void) sv; + printf("%s(): TODO - implement set_Saveslot_namefor rl-build.\n", __func__); + return false; +} +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +/** + * Debugs the passed (preallocated) Fighter with log_tag(). + * @param fighter The allocated Fighter to debug. + */ +void dbg_Fighter(Fighter *fighter) +{ + if (fighter == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Fighter was NULL in dbg_Fighter()"); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[FIGHTER]", "Fighter name: { %s }", + fighter->name); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter class: { %s } [ %i ]", + stringFromClass(fighter->class), fighter->class); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter hp: { %i }", fighter->hp); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter atk: { %i }", fighter->atk); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter def: { %i }", fighter->def); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter vel: { %i }", fighter->vel); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter level: { %i }", + fighter->level); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter luck: { %i }", + fighter->luck); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalxp: { %i }", + fighter->totalxp); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter currentlevelxp: { %i }", + fighter->currentlevelxp); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter totallevelxp: { %i }", + fighter->totallevelxp); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalhp: { %i }", + fighter->totalhp); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter status: { %s } [ %i ]", + stringFromStatus(fighter->status), fighter->status); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter energy: { %i }", + fighter->energy); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalenergy: { %i }", + fighter->totalenergy); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter stamina: { %i }", + fighter->stamina); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter totalstamina: { %i }", + fighter->totalstamina); + + //Specialslot* specials[SPECIALSMAX+1]; /**< Array with all the Specialslot*/ + + //struct Turncounter* counters[COUNTERSMAX+1]; /**< Array with all the Turncounter pointers*/ + log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_atk: { %i }", + fighter->turnboost_atk); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_def: { %i }", + fighter->turnboost_def); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_vel: { %i }", + fighter->turnboost_vel); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter turnboost_enr: { %i }", + fighter->turnboost_enr); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter perksCount: { %i }", + fighter->perksCount); + + //Perk* perks[PERKSMAX+1]; /**< Array with all the Perk*/ + + //struct Equipslot* equipslots[EQUIPZONES+1]; /**< Array with all the Equipslot*/ + //struct Equip* equipsBag[EQUIPSBAGSIZE+1]; /**< Array with all the Equip found*/ + //struct Consumable* consumablesBag[CONSUMABLESMAX+1]; /**< Array with all the Consumables found*/ + //struct Artifact* artifactsBag[ARTIFACTSMAX+1]; /**< Array with all the Artifacts found*/ + + log_tag("debug_log.txt", "[FIGHTER]", + "Fighter used equipsBag slots: { %i }", + fighter->equipsBagOccupiedSlots); + log_tag("debug_log.txt", "[FIGHTER]", + "Fighter earliest equipsBag slot: { %i }", + fighter->earliestBagSlot); + + log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_atk: { %i }", + fighter->permboost_atk); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_def: { %i }", + fighter->permboost_def); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_vel: { %i }", + fighter->permboost_vel); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter permboost_enr: { %i }", + fighter->permboost_enr); + + log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_atk: { %i }", + fighter->equipboost_atk); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_def: { %i }", + fighter->equipboost_def); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_vel: { %i }", + fighter->equipboost_vel); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter equipboost_enr: { %i }", + fighter->equipboost_enr); + + //dbg_countStats(fighter->stats); + + log_tag("debug_log.txt", "[FIGHTER]", "Fighter coins balance: { %i }", + fighter->balance); + log_tag("debug_log.txt", "[FIGHTER]", "Fighter keys balance: { %i }", + fighter->keys_balance); +} + +/** + * Debugs the passed (preallocated) Saveslot with log_tag(). + * @param saveslot The allocated Saveslot to debug. + */ +void dbg_Saveslot(Saveslot *saveslot) +{ + if (saveslot == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Saveslot was NULL in dbg_Saveslot()"); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[SAVESLOT]", "Saveslot name: { %s }", + saveslot->name); + log_tag("debug_log.txt", "[SAVESLOT]", "Saveslot save_path: { %s }", + saveslot->save_path); +} + +/** + * Debugs the passed (preallocated) Path with log_tag(). + * @param path The allocated Path to debug. + */ +void dbg_Path(Path *path) +{ + if (path == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Path was NULL in dbg_Path()"); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[PATH]", "Path length: { %i }", path->length); + log_tag("debug_log.txt", "[PATH]", "Path luck: { %i }", path->luck); + log_tag("debug_log.txt", "[PATH]", "Path prize: { %i }", path->prize); + log_tag("debug_log.txt", "[PATH]", "Path loreCounter: { %i }", + path->loreCounter); + log_tag("debug_log.txt", "[PATH]", "Path loreCounter: { %i }", + path->loreCounter); + dbg_Wincon(path->win_condition); + dbg_Saveslot(path->current_saveslot); +} + +/** + * Debugs the passed (preallocated) Wincon with log_tag(). + * @param gmst The allocated countStats to debug. + */ +void dbg_Wincon(Wincon *wc) +{ + if (wc == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Wincon was NULL in dbg_Wincon()"); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[WINCON]", "Wincon class: { %s } [ %i ]", + stringFromWinconClass(wc->class), wc->class); + log_tag("debug_log.txt", "[WINCON]", "Wincon current value: { %i }", + wc->current_val); + log_tag("debug_log.txt", "[WINCON]", "Wincon target value: { %i }", + wc->target_val); +} + +/** + * Debugs the passed (preallocated) countStats with log_tag(). + * @param gmst The allocated countStats to debug. + */ +void dbg_countStats(countStats *stats) +{ + if (stats == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "countStats was NULL in dbg_countStats()"); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[countStats]", "Enemies killed: { %i }", + stats->enemieskilled); + log_tag("debug_log.txt", "[countStats]", "Consumables found: { %i }", + stats->consumablesfound); + log_tag("debug_log.txt", "[countStats]", "Equips found: { %i }", + stats->equipsfound); + log_tag("debug_log.txt", "[countStats]", "Artifacts found: { %i }", + stats->artifactsfound); + log_tag("debug_log.txt", "[countStats]", "Critical hits done: { %i }", + stats->criticalhits); + log_tag("debug_log.txt", "[countStats]", "Rooms completed: { %i }", + stats->roomscompleted); + log_tag("debug_log.txt", "[countStats]", "Floors completed: { %i }", + stats->floorscompleted); + log_tag("debug_log.txt", "[countStats]", "Specials unlocked: { %i }", + stats->specialsunlocked); + log_tag("debug_log.txt", "[countStats]", "Coins found: { %i }", + stats->coinsfound); + log_tag("debug_log.txt", "[countStats]", "Bosses killed: { %i }", + stats->bosseskilled); + log_tag("debug_log.txt", "[countStats]", "Unique Boss kills: { %i }", + stats->unique_bosseskilled); + for (int i = 0; i < BOSSCLASSESMAX + 1; i++) { + log_tag("debug_log.txt", "[countStats]", "Boss [%i] { %s }: { %s }", i, + stringFromBossClass(i), + (stats->killed_bosses[i] == 1 ? "Killed" : "Not Killed")); + } + log_tag("debug_log.txt", "[countStats]", "Keys found: { %i }", + stats->keysfound); +} + +/** + * Logs floor layout for passed Floor. + */ +void dbg_print_floor_layout(Floor *floor) +{ + if (floor == NULL) { + fprintf(stderr, "[ERROR] at %s(): passed floor was NULL.\n", + __func__); + log_tag("debug_log.txt", "[ERROR]", "at %s(): passed floor was NULL.", + __func__); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + for (int y = 0; y < FLOOR_MAX_ROWS; y++) { + char rowbuf[FLOOR_MAX_COLS + 1] = { 0 }; + for (int x = 0; x < FLOOR_MAX_COLS; x++) { + rowbuf[x] = (floor->floor_layout[x][y] == 1 ? '1' : ' '); + } + log_tag("debug_log.txt", "[Floor_row]", "{%s} - %i", rowbuf, y); + } + log_tag("debug_log.txt", "[DEBUG]", "Logged floor layout."); +} + +/** + * Logs explored layout for passed Floor. + */ +void dbg_print_explored_layout(Floor *floor) +{ + if (floor == NULL) { + fprintf(stderr, "[ERROR] at %s(): passed floor was NULL.\n", + __func__); + log_tag("debug_log.txt", "[ERROR]", "at %s(): passed floor was NULL.", + __func__); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + for (int y = 0; y < FLOOR_MAX_ROWS; y++) { + char rowbuf[FLOOR_MAX_COLS + 1] = { 0 }; + for (int x = 0; x < FLOOR_MAX_COLS; x++) { + rowbuf[x] = (floor->explored_matrix[x][y] == 1 ? '1' : ' '); + } + log_tag("debug_log.txt", "[Floor_row]", "{%s} - %i", rowbuf, y); + } + log_tag("debug_log.txt", "[DEBUG]", "Logged explored layout."); +} + +/** + * Logs roomclass layout for passed Floor. + */ +void dbg_print_roomclass_layout(Floor *floor) +{ + if (floor == NULL) { + fprintf(stderr, "[ERROR] at %s(): passed floor was NULL.\n", + __func__); + log_tag("debug_log.txt", "[ERROR]", "at %s(): passed floor was NULL.", + __func__); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } + for (int y = 0; y < FLOOR_MAX_ROWS; y++) { + char rowbuf[FLOOR_MAX_COLS + 1] = { 0 }; + for (int x = 0; x < FLOOR_MAX_COLS; x++) { + char ch = '.'; + switch (floor->roomclass_layout[x][y]) { + case HOME: { + ch = 'H'; + } + break; + case ENEMIES: { + ch = 'E'; + } + break; + case BOSS: { + ch = 'B'; + } + break; + case SHOP: { + ch = '$'; + } + break; + case TREASURE: { + ch = '*'; + } + break; + case WALL: { + ch = '#'; + } + break; + case BASIC: { + ch = ' '; + } + break; + default: { + ch = '?'; + } + break; + } + rowbuf[x] = ch; + } + log_tag("debug_log.txt", "[Floor_row]", "{%s} - %i", rowbuf, y); + } + log_tag("debug_log.txt", "[DEBUG]", "Logged roomclass layout."); +} + +/** + * Debugs the passed (preallocated) Gamestate with log_tag(). + * @param gmst The allocated Gamestate to debug. + */ +void dbg_Gamestate(Gamestate *gmst) +{ + if (gmst == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Gamestate was NULL in dbg_Gamestate()"); + exit(EXIT_FAILURE); + } +#ifdef HELAPORDO_CURSES_BUILD + if (gmst->screen == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Screen was NULL in dbg_Gamestate()"); + } else { + dbg_GameScreen(gmst->screen); + } +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + log_tag("debug_log.txt", "[DEBUG]", "Gamestate:{"); + log_tag("debug_log.txt", "[GAMESTATE]", "Current Gamemode: { %s } [ %i ]", + stringFromGamemode(gmst->gamemode), gmst->gamemode); + log_tag("debug_log.txt", "[GAMESTATE]", "Start time: {%llu}", + (unsigned long long) gmst->start_time); + clock_t run_time = clock() - gmst->start_time; + int time_spent = run_time * 1000 / CLOCKS_PER_SEC; + log_tag("debug_log.txt", "[GAMESTATE]", "Current run time: %d s, %d ms.", + time_spent / 1000, time_spent % 1000); + log_tag("debug_log.txt", "[GAMESTATE]", "Current fighters: { %i }", + gmst->current_fighters); + log_tag("debug_log.txt", "[GAMESTATE]", "Current room index: { %i }", + gmst->current_room_index); + log_tag("debug_log.txt", "[GAMESTATE]", "Current room type: { %s } [ %i ]", + stringFromRoom(gmst->current_roomtype), gmst->current_roomtype); + log_tag("debug_log.txt", "[GAMESTATE]", "Current enemy index: { %i }", + gmst->current_enemy_index); + dbg_countStats(gmst->stats); + dbg_Path(gmst->path); + dbg_Fighter(gmst->player); + //TODO: print out current floor + if (gmst->current_floor == NULL) { + log_tag("debug_log.txt", "[GAMESTATE]", "Current floor was NULL."); + } else { + log_tag("debug_log.txt", "[GAMESTATE]", "Current floor: {"); + log_tag("debug_log.txt", "[Floor]", "index: {%i}", + gmst->current_floor->index); + if (gmst->current_floor->desc != NULL) { + log_tag("debug_log.txt", "[Floor]", "desc: {%s}", + gmst->current_floor->desc); + } + log_tag("debug_log.txt", "[Floor]", "floorClass: {%i} {%s}", + gmst->current_floor->class, + stringFromFloorclass(gmst->current_floor->class)); + log_tag("debug_log.txt", "[Floor]", "area: {%i}", + gmst->current_floor->area); + log_tag("debug_log.txt", "[Floor]", "explorea area: {%i}", + gmst->current_floor->explored_area); + dbg_print_floor_layout(gmst->current_floor); + dbg_print_explored_layout(gmst->current_floor); + dbg_print_roomclass_layout(gmst->current_floor); + log_tag("debug_log.txt", "[GAMESTATE]", " }"); + } + log_tag("debug_log.txt", "[GAMESTATE]", "is_localexe == (%s)", (gmst->is_localexe ? "true" : "false")); + log_tag("debug_log.txt", "[GAMESTATE]", "}"); +} + +/** + * Debugs the passed (preallocated) GameScreen with log_tag(). + * @param scr The allocated GameScreen to debug. + */ +void dbg_GameScreen(GameScreen * scr) +{ +#ifdef HELAPORDO_CURSES_BUILD + int y = 0; + int x = 0; + if (scr->win == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "win was NULL in %s()", __func__); + } else { + getmaxyx(scr->win, y, x); + log_tag("debug_log.txt", "[GAMESCREEN]", + "Screen size: y->(%i), x->(%i)", + y, x); + } + log_tag("debug_log.txt", "[GAMESCREEN]", + "Cols: {%i}", scr->cols); + log_tag("debug_log.txt", "[GAMESCREEN]", + "Rows: {%i}", scr->rows); + log_tag("debug_log.txt", "[GAMESCREEN]", + "Colors: {%i}", scr->colors); + log_tag("debug_log.txt", "[GAMESCREEN]", + "Color pairs: {%i}", scr->color_pairs); + log_tag("debug_log.txt", "[GAMESCREEN]", + "Escape delay: {%i}", scr->escape_delay); + log_tag("debug_log.txt", "[GAMESCREEN]", + "Tab size: {%i}", scr->tabsize); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + printf("TODO: implement %s().\n", __func__); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD +} + +/** + * Updates the passed (preallocated) Gamestate with the passed int values. + * @param gmst The allocated Gamestate to update. + * @param current_fighters Number of current Fighters. + * @param current_roomtype roomClass for current Room. + * @param current_room_index Index for current Room. + * @param current_enemy_index Index for current Enemy. + * @param current_floor Pointer to current Floor, initialised if gmst->gamemode == Rogue. + */ +void update_Gamestate(Gamestate *gmst, int current_fighters, + roomClass current_roomtype, int current_room_index, + int current_enemy_index, Floor *current_floor) +{ + if (gmst == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Gamestate was NULL in %s().", + __func__); + exit(EXIT_FAILURE); + } + gmst->current_fighters = current_fighters; + gmst->current_roomtype = current_roomtype; + gmst->current_room_index = current_room_index; + gmst->current_enemy_index = current_enemy_index; + if (gmst->gamemode == Rogue) { + if (current_floor == NULL) { + log_tag("debug_log.txt", "[WARN]", + "Passed current floor was NULL in %s().", __func__); + } else { + gmst->current_floor = current_floor; + } + } +} + +/** + * Takes a string and returns the corresponding saveType. + * Will return -1 if no match is found. + * @param s The string to convert. + */ +saveType saveTypeFrom_string(char *s) +{ + int check = -1; + + for (int i = 0; i < SAVETYPE_MAX + 1; i++) { + if ((check = strcmp(s, stringFrom_saveType(i))) == 0) { + log_tag("debug_log.txt", "[DEBUG]", + "Matched saveType string [%s] to (%i).", s, i); + return (saveType) i; + } + } + + log_tag("debug_log.txt", "[ERROR]", + "No match found for saveType string [%s].", s); + return -1; +} + +/** + * Logs a turnOption_OP to "$STATICDIR/OPS_log.txt". + * @param op The turnOption_OP to log. + */ +void log_OP(turnOption_OP op) +{ + log_tag(OPS_LOGFILE, "[LOG]", "[OP_code: %i, value: %s]", op, + stringFromTurnOP(op)); + log_tag("debug_log.txt", "[LOG_TURNOP]", "[OP_code: %i, value: %s]", op, + stringFromTurnOP(op)); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick red color. + */ +void red(void) +{ + printf("\033[1;31m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light red color. + */ +void lightRed(void) +{ + printf("\033[0;31m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick white color. + */ +void strongWhite(void) +{ + printf("\033[1;37m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light white color. + */ +void white(void) +{ + printf("\033[0;37m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick green color. + */ +void green(void) +{ + printf("\033[1;32m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light green color. + */ +void lightGreen(void) +{ + printf("\033[0;32m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick yellow color. + */ +void yellow(void) +{ + printf("\033[1;33m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light yellow color. + */ +void lightYellow(void) +{ + printf("\033[0;33m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick blue color. + */ +void blue(void) +{ + printf("\033[1;34m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light blue color. + */ +void lightBlue(void) +{ + printf("\033[0;34m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick purple color. + */ +void purple(void) +{ + printf("\033[1;35m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light purple color. + */ +void lightPurple(void) +{ + printf("\033[0;35m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a thick cyan color. + */ +void cyan(void) +{ + printf("\033[1;36m"); +} + +/** + * Prints an ASCII escape code that makes subsequent output a light cyan color. + */ +void lightCyan(void) +{ + printf("\033[0;36m"); +} + +#ifdef HELAPORDO_CURSES_BUILD +/** + * Initialises color pairs for the game. + */ +void init_game_color_pairs(void) +{ + + // Initialize all the colors + init_pair(1, COLOR_RED, COLOR_BLACK); + init_pair(2, COLOR_GREEN, COLOR_BLACK); + init_pair(3, COLOR_BLUE, COLOR_BLACK); + init_pair(4, COLOR_CYAN, COLOR_BLACK); + init_pair(5, COLOR_WHITE, COLOR_BLACK); + init_pair(6, COLOR_YELLOW, COLOR_BLACK); + init_pair(7, COLOR_BLACK, COLOR_WHITE); + init_pair(8, COLOR_MAGENTA, COLOR_BLACK); + init_pair(9, COLOR_WHITE, COLOR_RED); + init_pair(10, COLOR_WHITE, COLOR_MAGENTA); + +} +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined." +#else +void init_game_color_pairs(void) +{ + printf("%s(): TODO - Implement color pair init for rl-build\n", __func__); + return; +} +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +/** + * Sets the passed char array to the expected path for /static/ folder. + * @param static_path The array that will hold path to static folder. + */ +void resolve_staticPath(char static_path[500]) +{ + char homedir_path[200]; +#ifndef _WIN32 + sprintf(homedir_path, "%s", getenv("HOME")); +#else + sprintf(homedir_path, "%s", getenv("UserProfile")); +#endif + +#ifndef _WIN32 + const char *static_folder_path_wd = "./"; +#else + const char *static_folder_path_wd = ".\\"; +#endif + +#ifndef _WIN32 + const char *local_install_static_folder_path = "/helapordo-local/"; +#else + const char *local_install_static_folder_path = "\\helapordo-local\\"; +#endif + char static_folder_path_global[500]; + sprintf(static_folder_path_global, "%s", homedir_path); + strncat(static_folder_path_global, local_install_static_folder_path, 50); + struct stat sb; + + if (stat(static_folder_path_wd, &sb) == 0 && S_ISDIR(sb.st_mode)) { + //sprintf(msg, "[DEBUG] resolve_staticPath(): Found \"/static/\" dir in working directory (%s).\n",static_folder_path_wd); + strcpy(static_path, static_folder_path_wd); + } else { + //sprintf(msg, "[DEBUG] resolve_staticPath(): Can't find \"/static/\" dir in working directory (%s). Will try \"%s/helapordo-local/static/\".\n", static_folder_path_wd, homedir_path); + if (stat(static_folder_path_global, &sb) == 0 && S_ISDIR(sb.st_mode)) { + //sprintf(msg, "[DEBUG] resolve_staticPath(): Found \"/static/\" dir in global directory: \"%s/helapordo-local/static/\".\n", homedir_path); + strcpy(static_path, static_folder_path_global); + } else { + //sprintf(msg,"[DEBUG] resolve_staticPath(): Can't find \"/static/\" dir in \"%s/helapordo-local/static/\". Quitting.\n", homedir_path); + fprintf(stderr, "\n[ERROR] Can't find static dir. Quitting.\n"); + fprintf(stderr, "\nHome dir at: (%s).\n", homedir_path); + fprintf(stderr, "\nGlobal static dir at: (%s).\n", + static_folder_path_global); + fprintf(stderr, "\nWorking static dir at: (%s).\n", + static_folder_path_wd); + exit(EXIT_FAILURE); + } + } +} + +/** + * Loads the lore strings from the appropriate lore file. + * @param lore_strings The string array to copy to. + * @param loreKind The kind of lore, used to open the corresponding lore file. + * @see gameloop() + */ +void loadLore(char **lore_strings, int loreKind) +{ + + char static_path[500]; + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + char lore_filename[1000]; + + sprintf(lore_filename, "%s/lore/lore%i.txt", static_path, loreKind); + + FILE *lorefile = fopen(lore_filename, "r"); + if (!lorefile) { + fprintf(stderr, "\nCan't open %s\n", lore_filename); + exit(EXIT_FAILURE); + } + + char *line = NULL; + //size_t len = 0; + //ssize_t read; + //int i = 0; + + // FIXME + // If we ever need this again, we'd have to not depend on getline() for mingw32 + /* + while ((read = getline(&line, &len, lorefile)) != -1) { + log_tag("debug_log.txt","[LORE-LOAD]","Retrieved line of length %zu:", read); + log_tag("debug_log.txt","[LORE-LOAD]","%s", line); + strcpy(lore_strings[i],line); + i++; + } + */ + fclose(lorefile); + if (line) + free(line); +} + +/** + * Takes a path pointer, a roadFork value pointer, a room type pointer, and an integer. + * Depending on GAMEMODE (and eventually roadFork value), sets the room type pointer to a roomClass value. + * @param roadFork_value The pointer value of the roadfork that we must use as result. + * @param room_type The pointer value of the room type to set. + * @param roomsDone The total of rooms completed. + */ +void setRoomType(Path *path, int *roadFork_value, roomClass *room_type, + int roomsDone) +{ + log_tag("debug_log.txt", "[DEBUG]", + "setRoomType(): room type (%i) rooms done (%i)", (int)*room_type, + roomsDone); + switch (GAMEMODE) { + case Standard: { + if ((*roadFork_value >= 0)) { + *room_type = *roadFork_value; + *roadFork_value = -1; + log_tag("debug_log.txt", "[TEST]", + "setRoomType() for ROADFORK"); + } else if ((roomsDone == 1) || (roomsDone % HOMEROOM == 0)) { //Only the first and every nth room will be a HOME room. + //FIXME: why the hell does roomsDone need to start from 1? + *room_type = HOME; + log_tag("debug_log.txt", "[TEST]", "setRoomType() for HOME"); + } else if (roomsDone % BOSSROOM == 0) { + *room_type = BOSS; + } else if (roomsDone % SHOPROOM == 0) { + *room_type = SHOP; + } else if (rand() % 5 == 0) { + *room_type = TREASURE; + } else if (rand() % 4 == 0 && (roomsDone + 2 < path->length)) { + *room_type = ROADFORK; + } else if (*room_type == -1) { + *room_type = ENEMIES; + } + if (G_DEBUG_ON && G_DEBUG_ROOMTYPE_ON > 0) { + log_tag("debug_log.txt", "[DEBUG]", + "setRoomType(): Room debug flag asserted in standard gamemode, room type will always be equal to G_DEBUG_ROOMTYPE (%s).", + stringFromRoom(G_DEBUG_ROOMTYPE)); + *room_type = G_DEBUG_ROOMTYPE; + } + } + break; + case Story: { + if (*roadFork_value >= 0) { //Is this branch needed here? + *room_type = *roadFork_value; + *roadFork_value = -1; + } else if ((roomsDone == 1) || (roomsDone % HOMEROOM == 0)) { //Only the first and every nth room will be a HOME room. + //FIXME: why the hell does roomsDone need to start from 1? + *room_type = HOME; + log_tag("debug_log.txt", "[TEST]", + "story mode, setRoomType() for HOME"); + } else if (roomsDone % BOSSROOM == 0) { + *room_type = BOSS; + } else if (roomsDone % 4 == 0) { + *room_type = SHOP; + } else if (rand() % 20 == 0) { + *room_type = TREASURE; + } else if (*room_type == -1) { + *room_type = ENEMIES; + } + if (G_DEBUG_ON && G_DEBUG_ROOMTYPE_ON > 0) { + log_tag("debug_log.txt", "[DEBUG]", + "setRoomType(): Room debug flag asserted in standard gamemode, room type will always be equal to G_DEBUG_ROOMTYPE (%s).", + stringFromRoom(G_DEBUG_ROOMTYPE)); + *room_type = G_DEBUG_ROOMTYPE; + } + } + break; + default: { + fprintf(stderr, "Unexpected GAMEMODE value: %i\n", GAMEMODE); + exit(EXIT_FAILURE); + } + break; + } + log_tag("debug_log.txt", "[DEBUG]", + "setRoomType(): room type (%i) rooms done (%i)", (int)*room_type, + roomsDone); +} + +/** + * Frees the memory allocated for the passed room pointer. + * @param room The Room pointer to free. + * @see Room + */ +void freeRoom(Room *room) +{ + int room_type = room->class; + + log_tag("debug_log.txt", "[DEBUG-FREE]", "Freeing room desc: (%s).", + room->desc); + //Free room memory + //FIXME: do we have all room descs handled ? + //free(room->desc); + + if (room_type == SHOP) { + /* + for (int i = 0 ; i < room->shop->equipsCount; i++) { + Equip* e = room->shop->equips[i]; + if (e->perksCount > 0) { + for (int j = 0 ; j < e->perksCount; j++) { + Perk* p = e->perks[j]; + free(p); + sprintf(msg,"Freeing %s room (index %i), freed Perk %i for Equip %s.", stringFromRoom(room_type), room->index, j, stringFromEquips(e->class)); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done freeing perks.\n"); + } + sprintf(msg,"Freeing %s room (index %i), freed Equip %s.", stringFromRoom(room_type), room->index, stringFromEquips(e->class)); + free(e); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + } + for (int i = 0 ; i < room->shop->consumablesCount; i++) { + Consumable* c = room->shop->consumables[i]; + free(c); + sprintf(msg,"Freeing %s room (index %i), freed Consumable %i.", stringFromRoom(room_type), room->index, i); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + } + */ + //FIXME: remove all the commented out bs + log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); + } else if (room_type == TREASURE) { + if (room->treasure->class == TREASURE_CONSUMABLE) { + + /* + Consumable* dele = room->treasure->consumable; + sprintf(msg,"Freeing %s room (index %i), freed Consumable %s.\n", stringFromRoom(room_type), room->index, stringFromConsumables(dele->class)); + free(dele); + */ + //FIXME: remove all the commented out bs + log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); + } else if (room->treasure->class == TREASURE_ARTIFACT) { + /* + Artifact* dele = room->treasure->artifact; + sprintf(msg,"Freeing %s room (index %i), freed Artifact %s.\n", stringFromRoom(room_type), room->index, stringFromArtifacts(dele->class)); + free(dele); + */ + log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); + } else if (room->treasure->class == TREASURE_CHEST) { + log_tag("debug_log.txt", "[FIXME]", + "freeRoom: freeing Treasure room, CHEST"); + /* + //FIXME: freeing Treasure Chest here + Chest* chest = room->treasure->chest; + for (int eq_i = 0; eq_i < chest->equipsCount; eq_i++) { + Equip* equip = chest->equips[eq_i]; + for (int p_i = 0 ; p_i < equip->perksCount; p_i++) { + Perk* pk = equip->perks[p_i]; + free(pk); + sprintf(msg,"Freeing %s room (index %i), CHEST: freed Perk %i for Equip %s (%i).", stringFromRoom(room_type), room->index, p_i, stringFromEquips(equip->class), eq_i); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + } + sprintf(msg,"Freeing %s room (index %i), CHEST: freed Equip %s (%i).", stringFromRoom(room_type), room->index, stringFromEquips(equip->class), eq_i); + free(equip); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + } + + for (int i = 0 ; i < chest->consumablesCount; i++) { + Consumable* c = chest->consumables[i]; + free(c); + sprintf(msg,"Freeing %s room (index %i), CHEST: freed Consumable %i.", stringFromRoom(room_type), room->index, i); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + } + sprintf(msg,"Freeing %s room (index %i), freed Chest.\n", stringFromRoom(room_type), room->index); + //free(chest); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + */ + log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); + } + } else if (room_type == ROADFORK) { + /* + Roadfork* rfk = room->roadfork; + free(rfk); + sprintf(msg,"Freeing %s room (index %i), freed Roadfork.\n", stringFromRoom(room_type), room->index); + log_tag("debug_log.txt","[DEBUG-FREE]",msg); + */ + log_tag("debug_log.txt", "[FIXME]", "Empty freeRoom branch"); + } + + log_tag("debug_log.txt", "[DEBUG-FREE]", "Freed %s room, index %i.\n", + stringFromRoom(room->class), room->index); + log_tag("debug_log.txt", "[FIXME]", "freeRoom(): done fake free()."); + //free(room); +} + +/** + * Prints an hardcoded title screen. + * @see helapordo_title_string + */ +void printTitle(void) +{ + printf("\n\n\n\n\n"); +#ifndef _WIN32 + red(); +#endif + printf("%s\n", helapordo_title_string); +#ifndef _WIN32 + white(); +#endif +} + +/** + * Prints version string. + */ +void printVersion(void) +{ + printf("%s\n", VERSION); +} + +/** + * Prints formatted version string. + * @param progName The program name string. + */ +void printFormattedVersion(char *progName) +{ + printf("%s v. %s\n", progName, VERSION); +} + +/** + * Prints configuration info. + */ +void hlpd_dbg_features(void) +{ + +#ifdef HELAPORDO_DEBUG_ACCESS + fprintf(stderr,"[HLP] Debug access in enabled\n"); +#else + fprintf(stderr,"[HLP] Debug access in not enabled\n"); +#endif + +#ifdef HELAPORDO_DEBUG_LOG + fprintf(stderr,"[HLP] Debug log is enabled\n"); +#else + fprintf(stderr,"[HLP] Debug log is off\n"); +#endif + +#ifdef ANVIL__helapordo__ +#ifdef INVIL__helapordo__HEADER__ + fprintf(stderr,"[HLP] Built with invil\n"); +#else + fprintf(stderr,"[HLP] Built with amboso\n"); +#endif // INVIL +#else + fprintf(stderr,"[HLP] Built without anvil\n"); +#endif // ANVIL + +#ifdef HELAPORDO_CURSES_BUILD + fprintf(stderr,"[HLP] ncurses build enabled\n"); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + fprintf(stderr,"[HLP] raylib build enabled\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD +} + +/** + * Prints correct argument syntax for command line invocation. + */ +void usage(char *progname) +{ + fprintf(stderr, "\nUsage: %s [...options] [name] [class]\n", + progname); + fprintf(stderr, "\n [class]\n\n [Knight|Archer|Mage|Assassin]\n"); + fprintf(stderr, "\nOptions:\n"); + fprintf(stderr, "\n -R Enable rogue mode\n"); + fprintf(stderr, "\n -s Enable story mode. Deprecated.\n"); + fprintf(stderr, " -l Load a game.\n"); +#ifndef HELAPORDO_DEBUG_ACCESS +#else + fprintf(stderr, "\n -d Enable debug mode\n"); + fprintf(stderr, " -dr Enable forced room.\n"); + fprintf(stderr, " -dE Enable forced enemy.\n"); +#endif + fprintf(stderr, "\n -h Print this help message\n"); + fprintf(stderr, " -T Show a brief tutorial.\n"); + fprintf(stderr, " -G Enable godmode.\n"); + fprintf(stderr, " -X Enable experimental features.\n"); + fprintf(stderr, " -v Prints %s version.\n", progname); + fprintf(stderr, " -V Prints %s build info.\n", progname); + fprintf(stderr, " -a Disable autosave.\n"); + fprintf(stderr, " -L Enable logging.\n"); + fprintf(stderr, " -Q Enable fast quit.\n"); + fprintf(stderr, " -t Test color codes.\n"); +} + +/** + * Takes a filename string, a string headear and a format string. + * Tries logging the message to the passed file if global var G_DEBUG_ON is set. + * @param filename The filename to open. + * @param header The string header for the message to log. + * @param format The format string for message. + */ +void log_tag(char *filename, char *header, const char *format, ...) +{ +#ifndef HELAPORDO_DEBUG_LOG +#else + // Open log file if log flag is set and append to it + if (G_LOG_ON == 1) { + char path_to_debug_file[500]; + char static_path[500]; + + // Set static_path value to the correct static dir path + resolve_staticPath(static_path); + + sprintf(path_to_debug_file, "%s", static_path); + +#ifndef _WIN32 + strncat(path_to_debug_file, "/", 2); +#else + strncat(path_to_debug_file, "\\", 2); +#endif + + strncat(path_to_debug_file, filename, 200); + + //fprintf(stderr, "Using %s as path to debug log.\n", path_to_debug_file); + + FILE *logfile = fopen(path_to_debug_file, "a"); + if (!logfile) { + fprintf(stderr, + "Error opening log file.\n Static path: (%s) Filename : (%s).\n", + static_path, filename); + fprintf(stderr, "Path to debug file was: (%s).", + path_to_debug_file); + fprintf(stderr, "Format was: %s", format); + exit(EXIT_FAILURE); + } + va_list args; + va_start(args, format); + time_t now = time(0); + struct tm *mytime = localtime(&now); + char timeheader[500]; + if (strftime(timeheader, sizeof timeheader, "%X", mytime)) { + fprintf(logfile, "[ %s ] [ %-12.12s ] [", timeheader, header); + vfprintf(logfile, format, args); + fprintf(logfile, "]\n"); + } + va_end(args); + fclose(logfile); + } +#endif +} + +/** + * Takes a OP_res and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see OP_res + * @param r The OP_res. + * @return String corresponding to the OP result. + */ +char *stringFrom_OP_res(OP_res r) +{ + + return opresstrings[r]; +} + +/** + * Takes a saveType and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see saveType + * @param s The saveType value. + * @return String corresponding to the save type. + */ +char *stringFrom_saveType(saveType s) +{ + + return savetypestrings[s]; +} + +/** + * Takes a turnOption_OP and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see turnOption_OP + * @param t The turn choice. + * @return String corresponding to the turn choice. + */ +char *stringFromTurnOP(turnOption_OP t) +{ + + return turnopstrings[t]; +} + +/** + * Takes a foeTurnOption_OP and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see foeTurnOption_OP + * @param ft The turn choice. + * @return String corresponding to the turn choice. + */ +char *stringFromFoeTurnOP(foeTurnOption_OP ft) +{ + return foeturnopstrings[ft]; +} + +/** + * Takes a fightResult fr and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fightResult + * @param fr The fight result value. + * @return String corresponding to the fight result value. + */ +char *stringFrom_fightResult(fightResult fr) +{ + + return fightresultstrings[fr]; +} + +/** + * Takes a fighterStatus and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fighterStatus + * @param s The status. + * @return String corresponding to the status. + */ +char *stringFromStatus(fighterStatus s) +{ + static char *strings[] = { + "Normal", + "Poison", + "Frozen", + "Burned", + "Weak", + "Strong" + }; + + return strings[s]; +} + +/** + * Takes a winconClass and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see winconClass + * @param w The class. + * @return String corresponding to the class. + */ +char *stringFromWinconClass(winconClass w) +{ + + return winconstrings[w]; +} + +/** + * Takes a fighterClass and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fighterClass + * @param f The class. + * @return String corresponding to the class. + */ +char *stringFromClass(fighterClass f) +{ + + return classesstrings[f]; +} + +/** + * Takes a enemyClass and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see enemyClass + * @param e The class. + * @return String corresponding to the class. + */ +char *stringFromEClass(enemyClass e) +{ + + return classenemystrings[e]; +} + +/** + * Takes a bossClass and returns the corresponding string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see bossClass + * @param b The class. + * @return String corresponding to the class. + */ +char *stringFromBossClass(bossClass b) +{ + + return classbossstrings[b]; +} + +/** + * Takes a integer and returns the corresponding consumable string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see consumableClass + * @param c The integer/consumableClass. + * @return String corresponding to the consumable. + */ +char *stringFromConsumables(int c) +{ + + return consumablestrings[c]; +} + +/** + * Takes a integer and returns the corresponding equip string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see equipClass + * @param e The integer/equipClass. + * @return String corresponding to the equip. + */ +char *stringFromEquips(int e) +{ + + return equipstrings[e]; +} + +/** + * Takes a integer and returns the corresponding equipzone string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see Equipzone + * @param z The integer/Equipzone. + * @return String corresponding to the equipzone. + */ +char *stringFromEquipzones(int z) +{ + + return equipzonestrings[z]; +} + +/** + * Takes a integer and returns the corresponding quality string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see quality + * @param q The integer/quality + * @return String corresponding to the quality. + */ +char *stringFromQuality(int q) +{ + + return qualitytrings[q]; +} + +/** + * Takes a integer and returns the corresponding artifact string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see artifactClass + * @param a The integer/artifactClass. + * @return String corresponding to the artifact. + */ +char *stringFromArtifacts(int a) +{ + + return artifactstrings[a]; +} + +/** + * Takes a fighterClass and a specialMove and returns the corresponding name string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fighterClass + * @see specialMove + * @param class The fighterClass. + * @param move The specialMove. + * @return String corresponding to the special move. + */ +char *nameStringFromSpecial(fighterClass class, specialMove move) +{ + return specialsnamestrings[class][(move % (SPECIALSMAX + 1))]; +} + +/** + * Takes a fighterClass and a specialMove and returns the corresponding desc string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fighterClass + * @see specialMove + * @param class The fighterClass. + * @param move The specialMove. + * @return String corresponding to the special move. + */ +char *descStringFromSpecial(fighterClass class, specialMove move) +{ + return specialsdescstrings[class][(move % (SPECIALSMAX + 1))]; +} + +/** + * Takes a fighterClass and a specialMove and returns the corresponding cost by the inner array position, as an integer. + * Correct result is only possible by having the enum values in a consistent order with the integer array. + * @see fighterClass + * @see specialMove + * @param class The fighterClass. + * @param move The specialMove. + * @return int Cost of the corresponding special move. + */ +int costFromSpecial(fighterClass class, specialMove move) +{ + return specialscosts[class][(move % (SPECIALSMAX + 1))]; +} + +/** + * Takes a skillType and returns the corresponding name string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fighterClass + * @see specialMove + * @param class The skillType. + * @return String corresponding to the skillType. + */ +char *nameStringFromSkill(skillType class) +{ + return skillsnamestrings[class]; +} + +/** + * Takes a fighterClass and a specialMove and returns the corresponding desc string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see fighterClass + * @see skillType + * @param class The skillType. + * @return String corresponding to the skillType. + */ +char *descStringFromSkill(skillType class) +{ + return skillsdescstrings[class]; +} + +/** + * Takes a skillType and returns the corresponding cost by the inner array position, as an integer. + * Correct result is only possible by having the enum values in a consistent order with the integer array. + * @see fighterClass + * @see skillType + * @param class The skillType. + * @return int Cost of the corresponding skillType. + */ +int costFromSkill(skillType class) +{ + return skillscosts[class]; +} + +/** + * Takes a integer and returns the corresponding perk name string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see perkClass + * @see Perk + * @param p The integer/perkClass. + * @return String corresponding to the perk name. + */ +char *nameStringFromPerk(int p) +{ + + return perksnamestrings[p]; +} + +/** + * Takes a integer and returns the corresponding perk desc string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see perkClass + * @see Perk + * @param p The integer/perkClass. + * @return String corresponding to the perk desc. + */ +char *descStringFromPerk(int p) +{ + + return perksdescstrings[p]; +} + +/** + * Takes a integer and returns the corresponding treasure desc string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see treasureClass + * @param t The integer/treasureClass. + * @return String corresponding to the treasure desc. + */ +char *descStringFromTreasure(int t) +{ + + return treasuredescstrings[t]; +} + +/** + * Takes a integer and returns the corresponding chest desc string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see chestClass + * @param c The integer/chestClass. + * @return String corresponding to the chest desc. + */ +char *descStringFromChest(int c) +{ + return chestdescstrings[c]; +} + +/** + * Takes a integer and returns the corresponding FoeParty desc string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see foePartyClass + * @param c The integer/foePartyClass. + * @return String corresponding to the FoeParty desc. + */ +char *stringFromFoePartyClass(foePartyClass fp) +{ + return foepartystrings[fp]; +} + +/** + * Takes a integer and returns the corresponding HLP_Region_Type string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see HLP_Region_Type + * @param t The HLP type. + * @return String corresponding to the HLP_Region_Type name. + */ +char *stringFrom_HLP_Region_Type(HLP_Region_Type t) +{ + return hlp_regiontype_strings[t]; +} + +/** + * Takes a integer and returns the corresponding room name string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see roomClass + * @param r The integer/roomClass. + * @return String corresponding to the room name. + */ +char *stringFromRoom(roomClass r) +{ + return roomnamestrings[r]; +} + +/** + * Takes a integer and returns the corresponding gamemode string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see Gamemode + * @param g The integer/Gamemode. + * @return String corresponding to the gamemode. + */ +char *stringFromGamemode(Gamemode g) +{ + return gamemodenamestrings[g]; +} + +/** + * Takes a integer and returns the corresponding floorClass string by the inner array position. + * Correct result is only possible by having the enum values in a consistent order with the string array. + * @see floorClass + * @param fc The integer/floorClass. + * @return String corresponding to the floorClass. + */ +char *stringFromFloorclass(floorClass fc) +{ + return floornamestrings[fc]; +} + +/** + * Takes a Fighter pointer and sets its name value to the string provided on stdin. + * @param player The pointer whose name value will be set. + */ +void scanName(Fighter *player) +{ + char name[50]; + int f; + do { + printf("\n\n\tWhat's your name?\n\n"); + f = scanf("%20s", name); + } while (f >= 21 || f <= 0); + strcpy(player->name, name); +} + +/** + * Prints all the fighterClass values as integers and as strings. + * @see fighterClass + */ +void printClasses(void) +{ + printf("["); + for (int i = 0; i <= CLASSESMAX; i++) { + printf("\t%d)\t%s", i, stringFromClass(i)); + if (i != CLASSESMAX) { + printf("\n"); + } + }; + printf("\t]\n"); +} + +/** + * Asks for an integer on stdin and returns it if it's a valid fighterClass index. + * @see fighterClass + * @see CLASSESMAX + * @return The selected integer, negative for unvalid choices. + */ +int scanClass(void) +{ + int pick = -1; + char c; + while (pick < 0 || pick > CLASSESMAX) { + printf("\nPick a class: (0-%i)\n", CLASSESMAX); + int res = scanf("%1i", &pick); + log_tag("debug_log.txt", "[DEBUG]", "scanClass scanf() res was %i", + res); + res = scanf("%c", &c); + log_tag("debug_log.txt", "[DEBUG]", "scanClass 2 scanf() res was %i", + res); + }; + return pick; +} + +/** + * Takes a Fighter pointer and sets the class value after asking the user for input. + * @see fighterClass + * @see scanClass() + * @param player The pointer whose class value will be set. + */ +void pickClass(Fighter *player) +{ + int pick = -1; + do { + int res = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "pickClass() system(\"clear\") res was (%i)", res); + printf("\nPick a class.\n"); + printClasses(); + pick = scanClass(); + } while (pick < 0); + + player->class = pick; + green(); + printf("\n\n\tClass: %s\n\n", stringFromClass(player->class)); + white(); +} + +/** + * Prints all the winconClass values as integers and as strings. + * @see winconClass + */ +void printWincons(void) +{ + printf("["); + for (int i = 0; i <= WINCON_CLASS_MAX; i++) { + printf("\t%d)\t%s", i, stringFromWinconClass(i)); + if (i != WINCON_CLASS_MAX) { + printf("\n"); + } + }; + printf("\t]\n"); +} + +/** + * Asks for an integer on stdin and returns it if it's a valid winconClass index. + * @see winconClass + * @see WINCON_CLASS_MAX + * @return The selected integer, negative for unvalid choices. + */ +int scanWincon(void) +{ + int pick = -1; + char c; + while (pick < 0 || pick > WINCON_CLASS_MAX) { + printf("\nPick a win condition: (0-%i)\n", WINCON_CLASS_MAX); + int res = scanf("%1i", &pick); + log_tag("debug_log.txt", "[DEBUG]", "scanWincon() scanf() res was (%i)", + res); + res = scanf("%c", &c); + log_tag("debug_log.txt", "[DEBUG]", + "scanWincon() 2 scanf() res was (%i)", res); + }; + return pick; +} + +/** + * Takes a Fighter pointer and sets the name value after asking the user for input. + * @see fighterClass + * @see scanName() + * @param player The pointer whose name value will be set. + */ +void pickName(Fighter *player) +{ + scanName(player); + red(); + printf("\n\n\tName: %s\n\n", player->name); + white(); +} + +/** + * Takes a Wincon pointer and sets its class after asking the user for input. + * @see winconClass + * @see scanWincon() + * @param w The wincon pointer whose class value will be set. + */ +void pickWincon(Wincon *w) +{ + int pick = -1; + do { + int res = system("clear"); + log_tag("debug_log.txt", "[DEBUG]", + "pickWincon() system(\"clear\") res was (%i)", res); + printf("\nPick a win condition.\n"); + printWincons(); + pick = scanWincon(); + } while (pick < 0); + + w->class = pick; + green(); + printf("\n\n\tWincon: %s\n\n", stringFromWinconClass(w->class)); + white(); +} + +/** + * Takes two Fighter pointers, with all their fields already allocated, and copies all valaues from source to dest. + * @see Fighter + * @param source The Fighter pointer to be copied. + * @param dest The Fighter pointer to copy to. + */ +void copy_fighter(Fighter *source, Fighter *dest) +{ + + strcpy(source->name, dest->name); + dest->class = source->class; + dest->hp = source->hp; + dest->atk = source->atk; + dest->def = source->def; + dest->vel = source->vel; + dest->level = source->level; + dest->luck = source->luck; + dest->totalxp = source->totalxp; + dest->currentlevelxp = source->currentlevelxp; + dest->totallevelxp = source->totallevelxp; + dest->totalhp = source->totalhp; + dest->status = source->status; + + dest->energy = source->energy; + dest->totalenergy = source->totalenergy; + for (int i = 0; i < SPECIALSMAX + 1; i++) { + dest->specials[i] = source->specials[i]; + } + + for (int i = 0; i < COUNTERSMAX + 1; i++) { + dest->counters[i] = source->counters[i]; + } + dest->turnboost_atk = source->turnboost_atk; + dest->turnboost_def = source->turnboost_def; + dest->turnboost_vel = source->turnboost_vel; + dest->turnboost_enr = source->turnboost_enr; + + dest->perksCount = source->perksCount; + for (int i = 0; i < PERKSMAX + 1; i++) { + dest->perks[i] = source->perks[i]; + } + + for (int i = 0; i < EQUIPZONES + 1; i++) { + dest->equipslots[i] = source->equipslots[i]; + } + for (int i = 0; i < EQUIPSBAGSIZE + 1; i++) { + dest->equipsBag[i] = source->equipsBag[i]; + } + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + dest->consumablesBag[i] = source->consumablesBag[i]; + } + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + dest->artifactsBag[i] = source->artifactsBag[i]; + } + + dest->equipsBagOccupiedSlots = source->equipsBagOccupiedSlots; + dest->earliestBagSlot = source->earliestBagSlot; + + dest->permboost_atk = source->permboost_atk; + dest->permboost_def = source->permboost_def; + dest->permboost_vel = source->permboost_vel; + dest->permboost_enr = source->permboost_enr; + + dest->equipboost_atk = source->equipboost_atk; + dest->equipboost_def = source->equipboost_def; + dest->equipboost_vel = source->equipboost_vel; + dest->equipboost_enr = source->equipboost_enr; + + dest->stats = source->stats; + dest->balance = source->balance; +} + +/** + * Takes a fighterStatus and returns the corresponding effect_fun pointer for the function relating to the status. + * @see fighterStatus + * @see effect_fun + * @param status The fighterStatus that the caller needs to match to a effect_fun pointer. + * @return The effect_fun pointer related to the status. + */ +effect_fun getStatusCounterFun(fighterStatus status) +{ + switch (status) { + //case Normal: { + default: { + return &resetFighterStatus; + } + break; + }; +} + +/** + * Takes a fighterStatus and returns the corresponding effect_e_fun pointer for the function relating to the status. + * @see fighterStatus + * @see effect_e_fun + * @param status The fighterStatus that the caller needs to match to a effect_e_fun pointer. + * @return The effect_e_fun pointer related to the status. + */ +effect_e_fun getStatusCounterEnemyFun(fighterStatus status) +{ + switch (status) { + //case Normal: { + default: { + return &resetEnemyStatus; + } + break; + }; +} + +/** + * Takes a fighterStatus and returns the corresponding effect_e_fun pointer for the function relating to the status. + * @see fighterStatus + * @see effect_e_fun + * @param status The fighterStatus that the caller needs to match to a effect_e_fun pointer. + * @return The effect_e_fun pointer related to the status. + */ +effect_b_fun getStatusCounterBossFun(fighterStatus status) +{ + switch (status) { + //case Normal: { + default: { + return &resetBossStatus; + } + break; + }; +} + +//Counter callback getters + +/** + * Takes a Stat and returns the corresponding boost_fun pointer for the function relating to the stat. + * @see Stat + * @see boost_fun + * @param s The Stat that the caller needs to match to a boost_fun pointer. + * @return The boost_fun pointer related to the stat. + */ +boost_fun getStatBoostCounterFun(Stat s) +{ + + switch (s) { + case ATK: { + return &set_turnboost_atk; + } + break; + case DEF: { + return &set_turnboost_def; + } + break; + case VEL: { + return &set_turnboost_vel; + } + break; + case ENR: { + return &set_turnboost_enr; + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Invalid stat value in getStatBoostCounterFun()"); + exit(EXIT_FAILURE); + } + break; + }; +} + +/** + * Takes a Stat and returns the corresponding boost_e_fun pointer for the function relating to the stat. + * @see Stat + * @see boost_e_fun + * @param s The Stat that the caller needs to match to a boost_e_fun pointer. + * @return The boost_e_fun pointer related to the stat. + */ +boost_e_fun getStatBoostCounterEnemyFun(Stat s) +{ + + switch (s) { + case ATK: { + return &set_enemy_turnboost_atk; + } + break; + case DEF: { + return &set_enemy_turnboost_def; + } + break; + case VEL: { + return &set_enemy_turnboost_vel; + } + break; + case ENR: { + return &set_enemy_turnboost_enr; + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Invalid stat value in getStatBoostCounterEnemyFun()"); + exit(EXIT_FAILURE); + } + break; + }; +} + +/** + * Takes a Stat and returns the corresponding boost_b_fun pointer for the function relating to the stat. + * @see Stat + * @see boost_b_fun + * @param s The Stat that the caller needs to match to a boost_b_fun pointer. + * @return The boost_b_fun pointer related to the stat. + */ +boost_b_fun getStatBoostCounterBossFun(Stat s) +{ + + switch (s) { + case ATK: { + return &set_boss_turnboost_atk; + } + break; + case DEF: { + return &set_boss_turnboost_def; + } + break; + case VEL: { + return &set_boss_turnboost_vel; + } + break; + case ENR: { + return &set_boss_turnboost_enr; + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Invalid stat value in getStatBoostCounterBossFun()"); + exit(EXIT_FAILURE); + } + break; + }; +} + +/** + * Takes a Stat and returns the corresponding boost_fp_fun pointer for the function relating to the stat. + * @see Stat + * @see boost_fp_fun + * @param s The Stat that the caller needs to match to a boost_fp_fun pointer. + * @return The boost_fp_fun pointer related to the stat. + */ +boost_fp_fun get_StatBoostCounter_FoeParty_Fun(Stat s) +{ + + switch (s) { + case ATK: { + return &set_foeparty_turnboost_atk; + } + break; + case DEF: { + return &set_foeparty_turnboost_def; + } + break; + case VEL: { + return &set_foeparty_turnboost_vel; + } + break; + case ENR: { + return &set_foeparty_turnboost_enr; + } + break; + default: { + log_tag("debug_log.txt", "[ERROR]", + "Invalid stat value in getStatBoostCounter_FoeParty_Fun()"); + exit(EXIT_FAILURE); + } + break; + }; +} + +//Stat boost functions + +/** + * Takes a Fighter pointer and an integer, used to set the turnboost_atk value at the pointer. + * @see Fighter + * @see Turncounter + * @param f The Fighter pointer whose turnboost_atk value will be set. + * @param boost The value that will be set. + */ +void set_turnboost_atk(Fighter *f, int boost) +{ + //Straight addition of the boost + f->turnboost_atk = boost; +} + +/** + * Takes a Fighter pointer and an integer, used to set the turnboost_def value at the pointer. + * @see Fighter + * @see Turncounter + * @param f The Fighter pointer whose turnboost_def value will be set. + * @param boost The value that will be set. + */ +void set_turnboost_def(Fighter *f, int boost) +{ + //Straight addition of the boost + f->turnboost_def = boost; +} + +/** + * Takes a Fighter pointer and an integer, used to set the turnboost_vel value at the pointer. + * @see Fighter + * @see Turncounter + * @param f The Fighter pointer whose turnboost_vel value will be set. + * @param boost The value that will be set. + */ +void set_turnboost_vel(Fighter *f, int boost) +{ + //Straight addition of the boost + f->turnboost_vel = boost; +} + +/** + * Takes a Fighter pointer and an integer, used to set the turnboost_enr value at the pointer. + * @see Fighter + * @see Turncounter + * @param f The Fighter pointer whose turnboost_enr value will be set. + * @param boost The value that will be set. + */ +void set_turnboost_enr(Fighter *f, int boost) +{ + //Straight addition of the boost + f->turnboost_enr = boost; +} + +/** + * Takes a Enemy pointer and an integer, used to set the turnboost_atk value at the pointer. + * @see Enemy + * @see Turncounter + * @param e The Enemy pointer whose turnboost_atk value will be set. + * @param boost The value that will be set. + */ +void set_enemy_turnboost_atk(Enemy *e, int boost) +{ + //Straight addition of the boost + e->turnboost_atk = boost; +} + +/** + * Takes a Enemy pointer and an integer, used to set the turnboost_def value at the pointer. + * @see Enemy + * @see Turncounter + * @param e The Enemy pointer whose turnboost_def value will be set. + * @param boost The value that will be set. + */ +void set_enemy_turnboost_def(Enemy *e, int boost) +{ + //Straight addition of the boost + e->turnboost_def = boost; +} + +/** + * Takes a Enemy pointer and an integer, used to set the turnboost_vel value at the pointer. + * @see Enemy + * @see Turncounter + * @param e The Enemy pointer whose turnboost_vel value will be set. + * @param boost The value that will be set. + */ +void set_enemy_turnboost_vel(Enemy *e, int boost) +{ + //Straight addition of the boost + e->turnboost_vel = boost; +} + +/** + * Takes a Enemy pointer and an integer, used to set the turnboost_enr value at the pointer. + * @see Enemy + * @see Turncounter + * @param e The Enemy pointer whose turnboost_enr value will be set. + * @param boost The value that will be set. + */ +void set_enemy_turnboost_enr(Enemy *e, int boost) +{ + //Straight addition of the boost + e->turnboost_enr = boost; +} + +/** + * Takes a Boss pointer and an integer, used to set the turnboost_atk value at the pointer. + * @see Boss + * @see Turncounter + * @param b The Boss pointer whose turnboost_atk value will be set. + * @param boost The value that will be set. + */ +void set_boss_turnboost_atk(Boss *b, int boost) +{ + //Straight addition of the boost + b->turnboost_atk = boost; +} + +/** + * Takes a Boss pointer and an integer, used to set the turnboost_def value at the pointer. + * @see Boss + * @see Turncounter + * @param b The Boss pointer whose turnboost_def value will be set. + * @param boost The value that will be set. + */ +void set_boss_turnboost_def(Boss *b, int boost) +{ + //Straight addition of the boost + b->turnboost_def = boost; +} + +/** + * Takes a Boss pointer and an integer, used to set the turnboost_vel value at the pointer. + * @see Boss + * @see Turncounter + * @param b The Boss pointer whose turnboost_vel value will be set. + * @param boost The value that will be set. + */ +void set_boss_turnboost_vel(Boss *b, int boost) +{ + //Straight addition of the boost + b->turnboost_vel = boost; +} + +/** + * Takes a Boss pointer and an integer, used to set the turnboost_enr value at the pointer. + * @see Boss + * @see Turncounter + * @param b The Boss pointer whose turnboost_enr value will be set. + * @param boost The value that will be set. + */ +void set_boss_turnboost_enr(Boss *b, int boost) +{ + //Straight addition of the boost + b->turnboost_enr = boost; +} + +/** + * Takes a FoeParty pointer and an integer, used to set the turnboost_atk value at the pointer. + * @see FoeParty + * @see Turncounter + * @param fp The FoeParty pointer whose turnboost_atk value will be set. + * @param boost The value that will be set. + */ +void set_foeparty_turnboost_atk(FoeParty *fp, int boost) +{ + //Straight addition of the boost + fp->turnboost_atk = boost; +} + +/** + * Takes a FoeParty pointer and an integer, used to set the turnboost_def value at the pointer. + * @see FoeParty + * @see Turncounter + * @param fp The FoeParty pointer whose turnboost_def value will be set. + * @param boost The value that will be set. + */ +void set_foeparty_turnboost_def(FoeParty *fp, int boost) +{ + //Straight addition of the boost + fp->turnboost_def = boost; +} + +/** + * Takes a FoeParty pointer and an integer, used to set the turnboost_vel value at the pointer. + * @see FoeParty + * @see Turncounter + * @param fp The FoeParty pointer whose turnboost_vel value will be set. + * @param boost The value that will be set. + */ +void set_foeparty_turnboost_vel(FoeParty *fp, int boost) +{ + //Straight addition of the boost + fp->turnboost_vel = boost; +} + +/** + * Takes a FoeParty pointer and an integer, used to set the turnboost_enr value at the pointer. + * @see FoeParty + * @see Turncounter + * @param fp The FoeParty pointer whose turnboost_enr value will be set. + * @param boost The value that will be set. + */ +void set_foeparty_turnboost_enr(FoeParty *fp, int boost) +{ + //Straight addition of the boost + fp->turnboost_atk = boost; +} + +//Status effect functions + +/** + * Takes a Fighter pointer and resets its status value to Normal. + * @see Fighter + * @see fighterStatus + * @param f The pointer whose status value will be reset. + */ +void resetFighterStatus(Fighter *f) +{ + f->status = Normal; +} + +/** + * Takes a Enemy pointer and resets its status value to Normal. + * @see Enemy + * @see fighterStatus + * @param e The pointer whose status value will be reset. + */ +void resetEnemyStatus(Enemy *e) +{ + e->status = Normal; +} + +/** + * Takes a Boss pointer and resets its status value to Normal. + * @see Boss + * @see fighterStatus + * @param b The pointer whose status value will be reset. + */ +void resetBossStatus(Boss *b) +{ + b->status = Normal; +} + +/** + * Takes a size int and a pointer to integer array, initialises all the prices, depending on stats from the Equips array pointer. + * @see initShop() + * @see Equip + * @param size Size of both arrays. + * @param equipPrices Pointer to integer array for prices. + * @param equips Pointer to Equip pointer to influence pricing. + */ +void setEquipPrices(int size, int *equipPrices, Equip *equips[]) +{ + + for (int i = 0; i < size; i++) { + int *cur_price = &equipPrices[i]; + Equip *e = equips[i]; + + int baseprice = e->cost; + int price = baseprice; + + *cur_price = price; + } + +} + +/** + * Takes a size int and a pointer to integer array, initialises all the prices. + * @see initShop() + * @param size Size of both arrays. + * @param consumablePrices Pointer to integer array for prices. + * @param consumables Pointer to Consumable pointer to influence pricing. + */ +void setConsumablePrices(int size, int *consumablePrices, + Consumable **consumables) +{ + + for (int i = 0; i < size; i++) { + int *cur_price = &consumablePrices[i]; + //Consumable* c = consumables[i]; + + //Price evaluation + int baseprice = 4; + int price = baseprice + (rand() % 5) - 1; + + *cur_price = price; + } +} + +/** + * Takes a Fighter pointer and an integer used to force execution. + * If the force parameter is true, all checks are ignored. + * If enemy's hp value is at least 50% of total, and none of atk, def or vel is 0 or less, nothing happens with an early return. + * Otherwise, getBoost() is called to calc the level stat boost for each stat. + * The BaseStats pointer for the fighter's fighterClass is loaded and each one of atk, def and vel is checked accounting for level boost. + * If none of them is below the respective treshold of 35, 18 and 30 % of total, nothing happens. + * Otherwise, all of them are reset to full amount accounting for permboosts and level boost. + * @see Fighter + * @see fighterClass + * @see getBoost() + * @param player The Fighter pointer to check the stats for. + * @param force The integer to bypass all checks if true. + */ +void statReset(Fighter *player, int force) +{ + log_tag("debug_log.txt", "[DEBUG]", + "Call to statReset() with ($force) == (%i)", force); + if (!force && (player->hp >= 0.5 * player->totalhp) + && !(player->atk <= 0 || player->def <= 0 || player->vel <= 0)) { + return; + } + + int boost = getBoost(player->level, player->luck); + + BaseStats *base = &basestats[player->class]; + if (force || player->vel <= 0.3 * (base->vel + boost) + || player->atk <= 0.35 * (base->atk + boost) + || player->def <= 0.18 * (base->def + boost)) { + player->vel = base->vel + boost + player->permboost_vel; + player->atk = base->atk + boost + player->permboost_atk; + player->def = base->def + boost + player->permboost_def; + //Reset stats + if (!force) { + //yellow(); + //printf("\n\n\t%s's stats reset.\n",player->name); + //white(); + } + } +} + +/** + * Takes a Boss pointer and an integer used to force execution. + * If the force parameter is true, all checks are ignored. + * If boss's hp value is at least 40% of total, and none of atk, def or vel is 0 or less, nothing happens with an early return. + * Otherwise, getBossBoost() is called to calc the level stat boost for each stat. + * The BossBaseStats pointer for the boss's bossClass is loaded and each one of atk, def and vel is checked accounting for level boost. + * If none of them is below the respective treshold of 30, 30 and 20 % of total, nothing happens. + * Otherwise, all of them are reset to full amount accounting for beast boost and level boost. + * @see Boss + * @see bossClass + * @see getBossBoost() + * @see BSTFACTOR + * @see BossBaseStats + * @param b The Boss pointer to check the stats for. + * @param force The integer to bypass all checks if true. + */ +void statResetBoss(Boss *b, int force) +{ + if (!force && (b->hp >= 0.4 * b->totalhp) + && !(b->atk <= 0 || b->def <= 0 || b->vel <= 0)) { + return; + } + int boost = getBossBoost(b->level, b->class); + + float beastf = 1; + + if (b->beast) { + beastf = BSTFACTOR; + } + BossBaseStats *base = &basebossstats[b->class]; + + if (force) { //We also update hp values + int hpBoost = + boost + round(base->level * 0.75) + (base->hp / 10) + + ((base->def / 4) % 10); + b->hp = round(beastf * (base->hp + hpBoost)); + b->totalhp = b->hp; + } + + if (force || b->vel <= (0.3 * (base->vel + boost)) + || (b->atk <= (0.3 * (base->atk + boost))) + || b->def <= (0.2 * (base->def + boost))) { + b->vel = round(beastf * (base->vel + boost)); + b->atk = round(beastf * (base->atk + boost)); + b->def = round(beastf * (base->def + boost)); + //Reset stats + if (!force) { + //yellow(); + //printf("\n\n\t%s's stats reset.\n",stringFromEClass(e->class)); + //white(); + } + } +} + +/** + * Takes an Enemy pointer and an integer used to force execution. + * If the force parameter is true, all checks are ignored. + * If enemy's hp value is at least 40% of total, and none of atk, def or vel is 0 or less, nothing happens with an early return. + * Otherwise, getEnemyBoost() is called to calc the level stat boost for each stat. + * The EnemyBaseStats pointer for the enemy's enemyClass is loaded and each one of atk, def and vel is checked accounting for level boost. + * If none of them is below the respective treshold of 30, 30 and 20 % of total, nothing happens. + * Otherwise, all of them are reset to full amount accounting for beast boost and level boost. + * @see Enemy + * @see enemyClass + * @see getEnemyBoost() + * @see BSTFACTOR + * @see EnemyBaseStats + * @param e The Enemy pointer to check the stats for. + * @param force The integer to bypass all checks if true. + */ +void statResetEnemy(Enemy *e, int force) +{ + log_tag("debug_log.txt", "[DEBUG]", + "Call to statResetEnemy() with ($force) == (%i)", force); + if (!force && (e->hp >= 0.4 * e->totalhp) + && !(e->atk <= 0 || e->def <= 0 || e->vel <= 0)) { + return; + } + int boost = getEnemyBoost(e->level, e->class); + + float beastf = 1; + + if (e->beast) { + beastf = BSTFACTOR; + } + EnemyBaseStats *base = &baseenemystats[e->class]; + + if (force) { //We also update hp values + int hpBoost = + floor(0.5 * boost + round(base->level * 0.75) + (base->hp / 10) + + ((base->def / 4) % 10)); + e->hp = round(beastf * (base->hp + hpBoost)); + e->totalhp = e->hp; + } + + if (force || e->vel <= (0.3 * (base->vel + boost)) + || (e->atk <= (0.3 * (base->atk + boost))) + || e->def <= (0.2 * (base->def + boost))) { + e->vel = round(beastf * (base->vel + boost)); + e->atk = round(beastf * (base->atk + boost)); + e->def = round(beastf * (base->def + boost)); + //Reset stats + if (!force) { + //yellow(); + //printf("\n\n\t%s's stats reset.\n",stringFromEClass(e->class)); + //white(); + } + } +} + +/** + * Takes one integer and a bossClass and returns the boost relative to the level delta with base boss stats, as an integer. + * The EnemyBossStats pointer for the boss's bossClass is loaded. + * If the boost is negative, returns 0. + * @see Boss + * @see bossClass + * @see BossBaseStats + * @param lvl The level to check the boost against. + * @param bclass The bossClass used to determine base level. + * @return int The boost for any given stat, at the level passed as argument. + */ +int getBossBoost(int lvl, bossClass bclass) +{ + + BossBaseStats *base = &basebossstats[bclass]; + + float boost = ((lvl - base->level) * 1.25); + if (boost <= 0) { + boost = 0; + } + + return (int)boost; +} + +/** + * Takes one integer and an enemyClass and returns the boost relative to the level delta with base enemy stats, as an integer. + * The EnemyBaseStats pointer for the enemy's enemyClass is loaded. + * If the boost is negative, returns 0. + * @see Enemy + * @see enemyClass + * @see EnemyBaseStats + * @param lvl The level to check the boost against. + * @param eclass The enemyClass used to determine base level. + * @return int The boost for any given stat, at the level passed as argument. + */ +int getEnemyBoost(int lvl, enemyClass eclass) +{ + + EnemyBaseStats *base = &baseenemystats[eclass]; + + float boost = ((lvl - base->level) * 1.25); + if (boost <= 0) { + boost = 0; + } + + return (int)boost; +} + +/** + * Takes a Fighter pointer and resets all of its permboost_STAT values to 0, also correctly updating the current stat values. + * @see Fighter + * @param f The fighter pointer whose permboosts will be reset. + */ +void resetPermboosts(Fighter *f) +{ + for (int i = 0; i < STATMAX + 1; i++) { + switch (i) { + case ATK: { + f->atk -= f->permboost_atk; + if (f->atk < 0) { + f->atk = 0; + }; + f->permboost_atk = 0; + } + break; + case DEF: { + f->def -= f->permboost_def; + if (f->def < 0) { + f->def = 0; + }; + f->permboost_def = 0; + } + break; + case VEL: { + f->vel -= f->permboost_vel; + if (f->vel < 0) { + f->vel = 0; + }; + f->permboost_vel = 0; + } + break; + case ENR: { + f->totalenergy -= f->permboost_enr; + f->energy -= f->permboost_enr; + if (f->energy < 0) { + f->energy = 0; + }; + f->permboost_enr = 0; + } + break; + }; + }; +} + +/** + * Takes a Fighter pointer and applies all of its permboost_STAT values by adding them to the current stat values. + * @see Fighter + * @param f The fighter pointer whose permboosts will be applied. + */ +void applyPermboosts(Fighter *f) +{ + for (int i = 0; i < STATMAX + 1; i++) { + switch (i) { + case ATK: { + f->atk += f->permboost_atk; + } + break; + case DEF: { + f->def += f->permboost_def; + } + break; + case VEL: { + f->vel += f->permboost_vel; + } + break; + case ENR: { + f->totalenergy += f->permboost_enr; + f->energy += f->permboost_enr; + } + break; + }; + }; +} + +/** + * Takes a Fighter pointer and Resets the active value for each Artifact in the fighter's artifactsBag array that doesn't have an always active trait. + * At the moment, this only excludes CHAOSORB. + * @see Artifact + * @see artifactClass + * @see Fighter + */ +void resetArtifactsState(Fighter *f) +{ + for (int i = 0; i < (ARTIFACTSMAX + 1); i++) { + + //if (i == CHAOSORB) { //Chaosorb never gets reset + // continue; + //}; + + if (f->artifactsBag[i]->qty != 0) { //We only reset the ones we have + f->artifactsBag[i]->active = 0; + }; + }; +} + +/** + * Takes a Enemy pointer and two integers for current room index and current enemy index, and prints the spawn message formatted. + * @see Enemy + * @see stringFromEClass() + * @param e The Enemy pointer to print. + * @param roomIndex The index of current room. + * @param enemyIndex The index of current enemy. + */ +void printSpawnMessage(Enemy *e, int roomIndex, int enemyIndex) +{ + if (!e->beast) { + //TODO: + //Where to print a windowed spawn message? + log_tag("debug_log.txt", "[ROOM]", "Room %i)\t\t%s\t\tEnemy #%i", + roomIndex, stringFromEClass(e->class), enemyIndex + 1); + } else { + log_tag("debug_log.txt", "[ROOM]", + "Room %i)\t\t%s\t\tEnemy #%i IS BEAST", roomIndex, + stringFromEClass(e->class), enemyIndex + 1); + //lightBlue(); + //printf("\nYou feel at discomfort.\n\nRoom %i)\t\t",roomIndex); + //lightRed(); + //printf("Enemy #%i:\t%s",enemyIndex+1,stringFromEClass(e->class)); + //white(); + } +} + +/** + * Takes a Fighter pointer value and adds a random Consumable to consumablesBag. + * @see Fighter + * @see Consumable + * @see consumableClass + * @see CONSUMABLESMAX + * @see stringFromConsumables() + * @param player The Fighter pointer at hand. + * @return int Returns the enum value of the drop as an integer. + */ +int dropConsumable(Fighter *player) +{ + int drop = rand() % (CONSUMABLESMAX + 1); + + //Special drop chances. Maybe a function for this? + if (drop == Powergem) { + if (rand() % 3 == 0) { + drop = rand() % (CONSUMABLESMAX + 1); + } + } + // Powergem has 33% chance to be rerolled + + Consumable *c = (Consumable *) player->consumablesBag[drop]; + c->qty++; + + //Update stats + player->stats->consumablesfound++; + + return drop; +} + +/** + * Takes a Fighter pointer value and adds a random Artifact to artifactsBag. + * The Artifact is randomised according to ARTIFACTSMAX until one which was not found yet drops. + * Special Equip functions are also set up here. + * @see Fighter + * @see Artifact + * @see artifactClass + * @see stringFromArtifacts() + * @param player The Fighter pointer at hand. + * @return int Returns the enum value of the drop as an integer. + */ +int dropArtifact(Fighter *player) +{ + int drop = 0; + do { + drop = rand() % (ARTIFACTSMAX + 1); + } while (player->artifactsBag[drop]->qty != 0); //We reroll to get one we don't have + + player->artifactsBag[drop]->qty++; + + //Update stats + player->stats->artifactsfound++; + + return drop; +} + +/** + * Takes a Fighter pointer and an integer denoting the consumableClass and returns the respective qty value from player's consumablesBag at the provided index. + * @see Fighter + * @see Consumable + * @see consumableClass + * @param f The Fighter pointer. + * @param n The consumableClass value. + * @return int The qty value in consumablesBag for selected consumableClass. + */ +int getConsumableQty(Fighter *f, int n) +{ + Consumable *c = (Consumable *) f->consumablesBag[n]; + return c->qty; +} + +/** + * Sets the qty value to 0 for all Consumable in f's consumablesBag with positive qty. + * @see Consumable + * @see consumableClass + * @see CONSUMABLESMAX + * @see getConsumableQty() + * @param f The Fighter pointer at hand. + */ +void emptyConsumables(Fighter *f) +{ + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + if (getConsumableQty(f, i) > 0) { + Consumable *c = (Consumable *) f->consumablesBag[i]; + c->qty = 0; + } + }; +} + +/** + * Takes a Fighter pointer and sets the qty value to 0 and the active flag to false for all Artifacts in the fighter's artifactsBag with positive qty. + * @see Artifact + * @see artifactClass + * @see ARTIFACTSMAX + * @param f The Fighter pointer at hand. + */ +void emptyArtifacts(Fighter *f) +{ + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + if (f->artifactsBag[i]->qty > 0) { + f->artifactsBag[i]->qty = 0; + f->artifactsBag[i]->active = 0; + } + }; +} + +/** + * Takes a Fighter pointer and, for all Equip in equipsBag field with positive qty, sets qty to 0 and frees the Equip pointer. + * @see Fighter + * @see Equip + * @param player The fighter pointer whose equipsbag will be emptied. + */ +void emptyEquips(Fighter *player) +{ + //We REALLY need to be sure the items are in successive cells + //Still thinking linked lists would be better than an array + int occupied = player->equipsBagOccupiedSlots; + + for (int i = 0; i < occupied; i++) { + + Equip *e = (Equip *) player->equipsBag[i]; + if (e->qty > 0) { + //free(e); + e->qty = 0; + log_tag("debug_log.txt", "[FIXME]", + "emptyEquips(): how do I empty them semantically?"); + } + }; +} + +/** + * Takes an integer seed and returns a Path pointer. + * The seed provided is used to set the random seed and initialise the path values. + * @see Path + * @see MAXLENGTH + * @see MAXLUCK + * @param seed An integer seed. + * @param kls The Koliseo used for allocation. + * @param current_saveslot The Saveslot used to init the Path. + * @return A Path pointer with stats. + */ +Path *randomise_path(int seed, Koliseo *kls, const char *path_to_savefile) +{ + char msg[200]; + sprintf(msg, "Prepping Path"); + kls_log(kls, "DEBUG", msg); + Path *p = (Path *) KLS_PUSH_TYPED(kls, Path, HR_Path, "Path", msg); + srand(seed); + sprintf(msg, "Prepping Saveslot"); + kls_log(kls, "DEBUG", msg); + sprintf(msg, "save_path: [%s]", path_to_savefile); + Saveslot *save = + (Saveslot *) KLS_PUSH_TYPED(kls, Saveslot, HR_Saveslot, "Saveslot", + msg); + sprintf(msg, "Seed: %i", seed); + strcpy(save->name, msg); + sprintf(msg, "%s", path_to_savefile); + strcpy(save->save_path, msg); + p->current_saveslot = save; + kls_log(kls, "DEBUG", + "Prepped Saveslot: path->current_saveslot->save_path == [%s]", + p->current_saveslot->save_path); + log_tag("debug_log.txt", "[SAVESLOT]", + "Prepped Saveslot: path->current_saveslot->save_path == [%s]", + p->current_saveslot->save_path); + + switch (GAMEMODE) { + case Standard: { + p->length = (rand() % MAXLENGTH) + 1; + p->luck = (rand() % MAXLUCK) + 1; + p->prize = 15 / p->luck * (rand() % 150) + 500; + } + break; + case Story: { + p->length = 41; + p->luck = (rand() % MAXLUCK) + 1; + p->prize = 15 / p->luck * (rand() % 150) + 500; + } + break; + case Rogue: { + p->length = 1; + p->luck = (rand() % MAXLUCK) + 1; + p->prize = 15 / p->luck * (rand() % 150) + 500; + } + break; + default: { + fprintf(stderr, "\nUnexpected GAMEMODE value %i.\n", GAMEMODE); + exit(EXIT_FAILURE); + } + } + return p; +} + +/** + * Takes a Fighter pointer and prints most of its values formatted. + * @see Fighter + * @see stringFromClass() + * @see stringFromStatus() + * @param f The Fighter pointer with stats to print. + */ +void printStats(Fighter *f) +{ + + printf("\t%s's stats:\n\n", f->name); + printf("\t\tClass:\t%s\n", stringFromClass(f->class)); + printf("\t\tHp:\t%i/%i\n", f->hp, f->totalhp); + printf("\t\tEnergy:\t%i/%i\n", f->energy, f->totalenergy); + printf("\t\tAtk:\t%i\n", f->atk); + printf("\t\tDef:\t%i\n", f->def); + printf("\t\tVel:\t%i\n", f->vel); + printf("\t\tLvl:\t%i\n", f->level); + printf("\t\tCurrent Level exp:\t%i/%i\n", f->currentlevelxp, + f->totallevelxp); + printf("\t\tTotal exp:\t%i\n", f->totalxp); + printf("\t\tStatus:\t%s\n", stringFromStatus(f->status)); +} + +/** + * Takes a Enemy pointer and prints most of its values formatted. + * @see Enemy + * @see stringFromEClass() + * @see stringFromStatus() + * @param e The Enemy pointer with stats to print. + */ +void printEStats(Enemy *e) +{ + if (e->beast) { + lightRed(); + } + printf("\t%s's stats:\n", stringFromEClass(e->class)); + if (e->beast) { + white(); + } + printf("\tHp:\t%i/%i\n", e->hp, e->totalhp); + printf("\tEnergy:\t%i/%i\n", e->energy, e->totalenergy); + printf("\tAtk:\t%i\n", e->atk); + printf("\tDef:\t%i\n", e->def); + printf("\tVel:\t%i\n", e->vel); + printf("\tLvl:\t%i\n", e->level); + printf("\tXp:\t%i\n", e->xp); + printf("\tStatus:\t%s\n", stringFromStatus(e->status)); +} + +/** + * Takes a Consumable pointer and prints most of its values formatted. + * @see Consumable + * @param c The Consumable pointer with stats to print. + */ +void printConsumablesStats(Consumable *c) +{ + printf(" (%i)\t%i\t%s\t\"%s\"\n", c->class, c->qty, c->name, c->desc); +} + +/** + * Takes a Artifact pointer and prints most of its values formatted. + * @see Artifact + * @param a The Artifact pointer with stats to print. + */ +void printArtifactStats(Artifact *a) +{ + printf(" (%i)\t\t", a->class); + purple(); + printf("%s\t", a->name); + yellow(); + printf("\"%s\"\n", a->desc); + white(); +} + +#ifdef HELAPORDO_CURSES_BUILD +/** + * Demoes color pairs from palette.c to the passed WINDOW. + * @param win The Window pointer to print to. + * @param colors_per_row How many colors to print in each row. + */ +void test_game_color_pairs(WINDOW *win, int colors_per_row) +{ + if (win == NULL) { + fprintf(stderr, "[%s]: Passed Window was NULL.", __func__); + log_tag("debug_log.txt", "[ERROR]", "[%s]: Passed Window was NULL.", + __func__); + exit(EXIT_FAILURE); + } + + int x = 1; + int y = 1; + int x_offset = 0; + + for (int i = S4C_MIN_COLOR_INDEX; i < S4C_MAX_COLOR_INDEX + 1; i++) { + int color_index = i; + if (color_index >= 0) { + wattron(win, COLOR_PAIR(color_index)); + mvwaddch(win, y, x + x_offset, ' ' | A_REVERSE); + wattroff(win, COLOR_PAIR(color_index)); + } + x_offset++; + if ((color_index - S4C_MIN_COLOR_INDEX + 1) % colors_per_row == 0) { + x = 1; + x_offset = 0; + y++; + } + } + + int picked = 0; + int c = -1; + wrefresh(win); + refresh(); + + while (!picked && (c = wgetch(win)) != 'q') { + switch (c) { + case 10: { /*Enter */ + picked = 1; + + }; + break; + } + } +} + +/** + * Inits the passed (preallocated) Gamestate with the passed pointers. + * @param gmst The allocated Gamestate to init. + * @param start_time The start time for current game. + * @param stats Game stats. + * @param wincon Game Wincon. + * @param path Game Path. + * @param player Game main player. + * @param gamemode Picked gamemode. + * @param screen The main screen from initscr(). + * @param is_localexe Denotes if current game was started from a relative path. + */ +void init_Gamestate(Gamestate *gmst, clock_t start_time, countStats *stats, Wincon *wincon, + Path *path, Fighter *player, Gamemode gamemode, GameScreen* screen, bool is_localexe) +{ + if (gmst == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Gamestate was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (stats == NULL) { + log_tag("debug_log.txt", "[ERROR]", "countStats was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (wincon == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Wincon was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (path == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Path was NULL in %s()", __func__); + exit(EXIT_FAILURE); + } + if (player == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Player was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (gamemode != Story && gamemode != Rogue) { + log_tag("debug_log.txt", "[ERROR]", "Invalid gamemode requested: [%i]", + gamemode); + exit(EXIT_FAILURE); + } + if (screen == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Screen was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + gmst->start_time = start_time; + gmst->stats = stats; + gmst->current_fighters = -1; + gmst->current_roomtype = -1; + gmst->current_room_index = -1; + gmst->current_enemy_index = -1; + gmst->wincon = wincon; + gmst->path = path; + gmst->player = player; + gmst->gamemode = gamemode; + gmst->screen = screen; + gmst->is_localexe = is_localexe; +} + +/** + * Allocates and prepares a turnOP_args and returns a pointer to it. + * @see turnOP_args + * @see turnOption_OP + * @see turnOption + * @see turnOP() + * @param gmst The Gamestate pointer to assign to turnOP_args->gmst. + * @param actor The Fighter pointer to assign to turnOP_args->actor. + * @param path The Path pointer to assign to turnOP_args->path. + * @param room The Room pointer to assign to turnOP_args->room. + * @param Enemy The Enemy pointer to assign to turnOP_args->enemy. + * @param Boss The Boss pointer to assign to turnOP_args->boss. + * @param save_file The FILE pointer to assign to turnOP_args->save_file. + * @param notify_win The WINDOW pointer to assign to turnOP_args->notify_win. + * @param t_kls The Koliseo_Temp pointer to assign to turnOP_args->t_kls. + * @param foe_op The foeTurnOption_OP to assign to turnOP_args->foe_op. + * @param picked_skill The skillType to assign to turnOP_args->picked_skill. + */ +turnOP_args *init_turnOP_args(Gamestate *gmst, Fighter *actor, Path *path, + Room *room, loadInfo *load_info, Enemy *enemy, + Boss *boss, FILE *save_file, WINDOW *notify_win, + Koliseo_Temp *t_kls, foeTurnOption_OP foe_op, + skillType picked_skill) +{ + log_tag("debug_log.txt", "[TURNOP]", + "Allocated size %lu for new turnOP_args", sizeof(turnOP_args)); + kls_log(t_kls->kls, "DEBUG", "[TURNOP]", + "Allocated size %lu for new turnOP_args", sizeof(turnOP_args)); + turnOP_args *res = + (turnOP_args *) KLS_PUSH_T_TYPED(t_kls, turnOP_args, HR_turnOP_args, + "turnOP_args", "turnOP_args"); + + res->gmst = gmst; + res->actor = actor; + res->path = path; + res->room = room; + res->load_info = load_info; + res->enemy = enemy; + res->boss = boss; + res->save_file = save_file; + res->notify_win = notify_win; + res->t_kls = t_kls; + res->foe_op = foe_op; + res->picked_skill = picked_skill; + + return res; +} + +/** + * Takes a WINDOW pointer and prints the passed text to it ith wprintw(), before sleeping for the specified amount of milliseconds. + * @see handleRoom_Enemies() + * @see handleRoom_Boss() + * @param w The WINDOW pointer to print to. + * @param text The contents of the notification. + * @param time The display time in milliseconds + */ +void display_notification(WINDOW *w, char *text, int time) +{ + wprintw(w, "\n %s", text); + wrefresh(w); + //refresh(); + napms(time); +} + +/** + * Takes a WINDOW pointer and prints to it the passed string with the passed color. + * Additional parameters set coordinates for the output. + * @param win The WINDOW pointer to print to. + * @param starty The integer indicating starting y coordinate. + * @param startx The integer indicating starting x coordinate. + * @param width The integer indicating panel width. + * @param string The string to print to the window. + * @param color The color to print in. + */ +void print_label(WINDOW *win, int starty, int startx, int width, char *string, + chtype color) +{ + int length, x, y; + float temp; + + if (win == NULL) { + log_tag("debug_log.txt", "[CURSES]", + "win was NULL in boss_print_in_panel()."); + exit(EXIT_FAILURE); + } + getyx(win, y, x); + if (startx != 0) + x = startx; + if (starty != 0) + y = starty; + if (width == 0) + width = 80; + + length = strlen(string); + temp = (width - length) / 2; + x = startx + (int)temp; + wattron(win, color); + mvwprintw(win, y, x, "%s", string); + wattroff(win, color); + refresh(); +} + +/** + * Takes a Equip pointer and prepares its sprite field by copying it line by line from equips_sprites, defined in sprites.h header. + * @see Equip + * @see dropEquip + * @see equips_sprites + * @param e The Equip pointer whose sprite field will be initialised. + */ +void setEquipSprite(Equip *e) +{ + if (e->class < EQUIPSMAX + 1) { + for (int i = 0; i < 8; i++) { + strcpy(e->sprite[i], equips_sprites[e->class][i]); + } + } else { + fprintf(stderr, + "[ERROR] Unexpected equipClass in setEquipSprite().\n"); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a quality value and calls the respective color function without actually printing text. + * @see quality + * @param q The quality value we want to set text color for. + */ +void printQualityColor(quality q) +{ + switch (q) { + case Bad: { + lightRed(); + } + break; + case Average: { + strongWhite(); + } + break; + case Good: { + lightCyan(); + } + break; + }; +} + +/** + * Takes a Equip pointer and prints most of its values formatted. + * The beginning of the format assumes the caller prepended "(x" on the output before calling, where x is the index of the equip. + * @see Equip + * @see stringFromQuality() + * @param e The Equip pointer with stats to print. + */ +void printEquipStats(Equip *e) +{ + printf(")\t"); //This completes the print started in the calling loop, which supplies the index ATM + + //Quality color + printQualityColor(e->qual); + printf("%s ", stringFromQuality(e->qual)); + + printf("%s ", e->name); + white(); + + printf("\"%s\" (L%i)\t", e->desc, e->level); + + lightCyan(); + printf("%s ", stringFromEquipzones(e->type)); + + lightGreen(); + //Stats, will be then printed only if != 0 + if (e->atk != 0) { + printf("A: %i ", e->atk); + }; + if (e->def != 0) { + printf("D: %i ", e->def); + }; + if (e->vel != 0) { + printf("V: %i ", e->vel); + }; + if (e->enr != 0) { + printf("E: %i", e->enr); + }; + + printf("\n"); + white(); + + //Perks, will be then printed only if perksCount != 0 + + for (int i = 0; i < e->perksCount; i++) { + lightPurple(); + printf("\t\t%s\n", e->perks[i]->name); + }; + white(); +} + +/** + * Takes a Fighter pointer value and an integer indicating if the drop was from a beast enemy, and adds a random Equip to the fighter's equipsBag. + * Prints notifications to the passed WINDOW pointer. + * The Equip dropped is initalised here, including stat variations for quality and level boosts (stat increase from base level by adding player level over EQUIPLVLBOOSTRATIO. + * The values of earliestBagSlot and equipsBagOccupiedSlots are managed. + * If equipsBag is full (EQUIPSBAGSIZE), user has to choose one Equip not currently equipped to be deleted and replaced by the new one. + * Special Equip functions are also set up here. + * @see Fighter + * @see Equip + * @see equipClass + * @see quality + * @see EQUIPLVLBOOSTRATIO + * @see EQUIPSBAGSIZE + * @see stringFromQuality() + * @see stringFromEquips() + * @param player The Fighter pointer at hand. + * @param beast The integer for drops coming from a beast kill if true. + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param kls The Koliseo used for allocations. + */ +void dropEquip(Fighter *player, int beast, WINDOW *notify_win, Koliseo *kls) +{ + + //Select a basic item from the list + int drop = rand() % (EQUIPSMAX + 1); + //Randomise quality + quality q = rand() % (QUALITIESMAX + 1); + + //Prepare the item + kls_log(kls, "DEBUG", "Prepping dropped Equip"); + Equip *e = + (Equip *) KLS_PUSH_TYPED(kls, Equip, HR_Equip, "Equip", "Equip"); + + //Get the base item and copy the stats to the drop + Equip *base = &equips[drop]; + + e->class = base->class; + e->type = base->type; + e->qual = q; + + setEquipSprite(e); + strcpy(e->name, base->name); + strcpy(e->desc, base->desc); + + e->qty = 1; + e->equipped = 0; + + e->perksCount = 0; + + //Calc drop level + e->level = base->level + round(player->level / EQUIPLVLBOOSTRATIO); + + //Chance for better leveled item + if ((rand() % 8) - (player->luck / 10) <= 0) { //Should use a defined constant + e->level += 1; //At least a simple +1 + if ((rand() % 25) - (player->luck / 10) <= 0) { //Should use a defined constant + e->level += 1; //A bonus roll for another +1 + + } + } + + float boostFactor = 0.7; + + float lvlBoost = boostFactor * (e->level - 1); + + e->atk = round((base->atk * 1.0) + lvlBoost); + e->def = round((base->def * 1.0) + lvlBoost); + e->vel = round((base->vel * 1.0) + lvlBoost); + e->enr = round((base->enr * 1.0) + lvlBoost); + + //Bonus stats on better quality items? Simple for now + // + if (q == Good) { + e->atk += (rand() % 3); //Should use a defined constant + e->def += (rand() % 3); //Should use a defined constant + e->vel += (rand() % 3); //Should use a defined constant + e->enr += (rand() % 2); //Should use a defined constant + } else if (q == Bad) { + e->atk -= (rand() % 3); //Should use a defined constant + e->def -= (rand() % 3); //Should use a defined constant + e->vel -= (rand() % 3); //Should use a defined constant + e->enr -= (rand() % 2); //Should use a defined constant + if (e->atk < 0) { + e->atk = 0; + }; + if (e->def < 0) { + e->def = 0; + }; + if (e->vel < 0) { + e->vel = 0; + }; + if (e->enr < 0) { + e->enr = 0; + }; + } + //Possible perks for the Equip + + for (int i = 0; i < (EQUIPPERKSMAX); i++) { + int chance = 20; + + if (q == Good) { + chance *= 1.5; + } + + if ((rand() % 100) < chance || (beast && e->perksCount == 0)) { + + e->perksCount += 1; + + log_tag("debug_log.txt", "[DEBUG]", + "Prepping Perk (%i) for dropped Equip)", e->perksCount); + kls_log(kls, "DEBUG", "Prepping Perk (%i) for dropped Equip)", + e->perksCount); + Perk *p = + (Perk *) KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); + p->class = rand() % (PERKSMAX + 1); + //p->name = (char*)malloc(sizeof(nameStringFromPerk(p->class))); + strcpy(p->name, nameStringFromPerk(p->class)); + //p->desc = (char*)malloc(sizeof(descStringFromPerk(p->class))); + strcpy(p->desc, descStringFromPerk(p->class)); + p->innerValue = 1; + e->perks[(e->perksCount - 1)] = p; + } + } + + //Set value of how many bonuses we have. Although Equip only has ONE function pointer field for now + e->bonus = base->bonus; + //Randomise if the item will have an effect function. + //Not yet implemented + //Initialisation of function happens here + // + //e->equip_fun = ; + + //Calc cost value + + float cost = 5; + + cost += 2.5 * (e->qual); + cost += 3.5 * (e->perksCount); + + cost += 7.2 * (e->level); + + e->cost = floor(cost); + + char msg[500]; + + wattron(notify_win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); + sprintf(msg, "You found %s %s!", stringFromQuality(q), + stringFromEquips(drop)); + display_notification(notify_win, msg, 800); + wattroff(notify_win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); + log_tag("debug_log.txt", "[DEBUG-DROPS]", "Found Equip: %s.", + stringFromEquips(drop)); + + if (player->equipsBagOccupiedSlots >= EQUIPSBAGSIZE) { //Handle full bag by asking player if we throw something away + //FIXME: The handling of full bag event is a mess as it does not support curses. + lightRed(); + printf("\tYour bag is full. Want to throw something away?\n"); + white(); + log_tag("debug_log.txt", "[DEBUG-EQUIPS]", + "Bag full, need to make space.\n"); + + for (int i = 0; i < player->equipsBagOccupiedSlots; i++) { + Equip *current = (Equip *) player->equipsBag[i]; + if (current->equipped) { + green(); + printf("ON "); + white(); + }; + + printf("(%i", i); //This starts lines with the item index. + printEquipStats(current); + }; + + int selected = -1; + int c = -1; + Equip *s = NULL; + + while (selected < 0 || selected >= player->equipsBagOccupiedSlots + || c != 1) { + + c = scanf("%i", &selected); + int res = scanf("%*c"); + log_tag("debug_log.txt", "[DEBUG]", + "dropEquip() scanf() res was (%i)", res); + + if (c == 1) { + s = (Equip *) player->equipsBag[selected]; + if (s->equipped) { + printf("You can't delete an equipped item!"); + selected = -1; + } + } + } + + printf + ("\tAre you sure you want to delete %s %s ?\n\t\t[0 to confirm, 1 to go back]\n", + stringFromQuality(s->qual), s->name); + + int n = -1; + c = -1; + while (n < 0 || c != 1) { + c = scanf("%i", &n); + int res = scanf("%*c"); + log_tag("debug_log.txt", "[DEBUG]", + "dropEquip() scanf() res was (%i)", res); + } + + if (n != 0) { //Abort deletion, drop will not be awared. + + /* + int perkscount = e->perksCount; + if (perkscount > 0) { + for (int i=0; i < perkscount; i++) { + free(e->perks[i]); + } + } + free(e); + */ + log_tag("debug_log.txt", "[DEBUG-EQUIPS]", + "Equip was not taken.\n"); + return; + }; + + Equip *toDelete = (Equip *) player->equipsBag[selected]; + int perkscount = toDelete->perksCount; + /* + if (perkscount > 0) { + for (int i=0; i < perkscount; i++) { + free(toDelete->perks[i]); + } + } + */ + log_tag("debug_log.txt", "[DEBUG-EQUIPS]", + "Equip %s (%i Perks) was taken by deleting %s.\n", + stringFromEquips(e->class), perkscount, + stringFromEquips(toDelete->class)); + /* + free(toDelete); + */ + + //Add drop to player bag replacing the one at the selected index + player->equipsBag[selected] = (struct Equip *)e; + + //Update stats + player->stats->equipsfound++; + + napms(500); + return; + }; //End if bag is full + + //Add drop to player bag + player->equipsBag[player->earliestBagSlot] = (struct Equip *)e; + + player->earliestBagSlot += 1; //Advance equips bage pointer + player->equipsBagOccupiedSlots += 1; //Advance equips bage size counter + + //Update stats + player->stats->equipsfound++; +} + +/** + * Takes a Fighter pointer and asks the user to select a specialMove to unlock with a formatted text menu. + * From the specials field of fighter, only the SpecialSlot with the enabled falg not set are printed and selectable by user. + * For the Fighter, the equipboost values are also displayed. + * @see Fighter + * @see SpecialSlot + * @see SPECIALSMAX + * @see setSpecials() + * @see stringFromSpecial() + * @param f The Fighter pointer that get one of his not yet unlocked specials. + */ +void unlockSpecial(Fighter *f) +{ + + //Thanks to u/skeeto for the suggestions. + ITEM *my_items[SPECIALSMAX + 2] = { 0 }; + MENU *my_menu; + WINDOW *my_menu_win; + WINDOW *display_win; + + int n_choices = 0; + int selection = -1; + int currentIndexed = -1; + ITEM *cur; + + /* Initialize curses */ + //initscr(); + clear(); + refresh(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + /* Create menu items */ + for (int i = 0; i < SPECIALSMAX + 1; i++) { + if (!(f->specials[i]->enabled)) { + my_items[n_choices++] = + new_item(nameStringFromSpecial(f->class, i), " "); + } + } + + /* Create menu */ + my_menu = new_menu(my_items); + + /* Set description off */ + menu_opts_off(my_menu, O_SHOWDESC); + + /* Create the window to be associated with the menu */ + my_menu_win = newwin(18, 28, 2, 2); + keypad(my_menu_win, TRUE); + + /* Set main window and sub window */ + set_menu_win(my_menu, my_menu_win); + set_menu_sub(my_menu, derwin(my_menu_win, 12, 26, 4, 2)); + set_menu_format(my_menu, 12, 1); + + /* Set menu mark to the string " > " */ + set_menu_mark(my_menu, " > "); + + /* Print a border around the main window and print a title */ + box(my_menu_win, 0, 0); + print_label(my_menu_win, 1, 0, 20, "New move unlocked", + COLOR_PAIR(S4C_CYAN)); + mvwaddch(my_menu_win, 2, 0, ACS_LTEE); + mvwhline(my_menu_win, 2, 1, ACS_HLINE, 26); + mvwaddch(my_menu_win, 2, 27, ACS_RTEE); + + /* Post the menu */ + post_menu(my_menu); + wrefresh(my_menu_win); + + //attron(COLOR_PAIR(2)); + //mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items"); + mvprintw(23, 0, "Select a new special move to learn."); + //attroff(COLOR_PAIR(2)); + //refresh(); + + refresh(); + + /* Prepare selection display window */ + display_win = newwin(18, 40, 3, 32); + box(display_win, 0, 0); + //Update selected window + cur = current_item(my_menu); + for (int i = 0; i < SPECIALSMAX + 1; i++) { + int check = -1; + if ((check = + strcmp(nameStringFromSpecial(f->class, i), item_name(cur))) == 0) { + currentIndexed = i; + break; + } + } + mvwprintw(display_win, 2, 2, "%s", + descStringFromSpecial(f->class, + f->specials[currentIndexed]->move)); + mvwprintw(display_win, 4, 2, "Energy Cost %i", + f->specials[currentIndexed]->cost); + wrefresh(my_menu_win); + wrefresh(display_win); + + int picked = 0; + int c; + + while (!picked && (c = wgetch(my_menu_win))) { + switch (c) { + case KEY_DOWN: { + menu_driver(my_menu, REQ_DOWN_ITEM); + cur = current_item(my_menu); + //Update selected window + for (int i = 0; i < SPECIALSMAX + 1; i++) { + int check = -1; + if ((check = + strcmp(nameStringFromSpecial(f->class, i), + item_name(cur))) == 0) { + currentIndexed = i; + break; + } + } + } + break; + case KEY_UP: { + menu_driver(my_menu, REQ_UP_ITEM); + cur = current_item(my_menu); + for (int i = 0; i < SPECIALSMAX + 1; i++) { + int check = -1; + if ((check = + strcmp(nameStringFromSpecial(f->class, i), + item_name(cur))) == 0) { + currentIndexed = i; + break; + } + } + } + break; + case KEY_NPAGE: { + menu_driver(my_menu, REQ_SCR_DPAGE); + cur = current_item(my_menu); + //Update selected window + for (int i = 0; i < SPECIALSMAX + 1; i++) { + int check = -1; + if ((check = + strcmp(nameStringFromSpecial(f->class, i), + item_name(cur))) == 0) { + currentIndexed = i; + break; + } + } + } + break; + case KEY_PPAGE: { + menu_driver(my_menu, REQ_SCR_UPAGE); + cur = current_item(my_menu); + for (int i = 0; i < SPECIALSMAX + 1; i++) { + int check = -1; + if ((check = + strcmp(nameStringFromSpecial(f->class, i), + item_name(cur))) == 0) { + currentIndexed = i; + break; + } + } + } + break; + case 10: { /*Enter */ + picked = 1; + cur = current_item(my_menu); + for (int i = 0; i < SPECIALSMAX + 1; i++) { + int check = -1; + if ((check = + strcmp(nameStringFromSpecial(f->class, i), + item_name(cur))) == 0) { + selection = i; + break; + } + + pos_menu_cursor(my_menu); + refresh(); + }; + break; + } + } + wclear(display_win); + wrefresh(display_win); + box(display_win, 0, 0); + mvwprintw(display_win, 2, 2, "%s", + descStringFromSpecial(f->class, + f->specials[currentIndexed]->move)); + mvwprintw(display_win, 4, 2, "Energy Cost %i", + f->specials[currentIndexed]->cost); + wrefresh(my_menu_win); + wrefresh(display_win); + refresh(); + } + /* Unpost and free all the memory taken up */ + unpost_menu(my_menu); + free_menu(my_menu); + for (int k = 0; k <= n_choices; k++) { + free_item(my_items[k]); + } + delwin(my_menu_win); + delwin(display_win); + endwin(); + + int num = selection; + + if (num < SPECIALSMAX + 1) { //Check if selected move number is lower than the maximum + Specialslot *selected = f->specials[num]; + + //Check if the selected move is NOT enabled + if (!(selected->enabled)) { + //Enable the move + selected->enabled = 1; + } + } + f->stats->specialsunlocked += 1; +} + +//TODO update this to actually handle different types of counters and reliably print them, maybe to a ncurses window +/** + * Takes a Turncounter array. + * For every Turncounter in the array, the values of count, innerVal, type and all the function pointers fields are printed. + * @see Turncounter + * @param counters The Turncounter array to be printed. + */ +void printCounters(Turncounter *counters[]) +{ + yellow(); + printf + ("%-10.10s\t%-10.10s\t%-3.3s\t%-3.3s\t%-11.11s\t%-11.11s\t%-11.11s\t%-11.11s\n", + "Count", "Desc", "Val", "Typ", "*(eff())", "*(eff_e())", "*(boost())", + "*(boost_e())"); + for (int i = 0; i < (COUNTERSMAX + 1); i++) { + Turncounter *c = counters[i]; + lightBlue(); + printf("%-10.10i\t%-10.10s\t", c->count, c->desc); + strongWhite(); + printf("(%-3.3i)\t(%-3.3i)\t", c->innerValue, c->type); + purple(); + //printf("[%-11.11i]\t[%-11.11i]\t",*(c->effect_fun),*(c->effect_e_fun)); + cyan(); + //printf("[%-11.11i]\t[%-11.11i]\n",*(c->boost_fun), *(c->boost_e_fun)); + }; + white(); +} + +/** + * Takes a Figher pointer and prints all of its active perks formatted. + * @see Fighter + * @see Perk + * @see Equip + * @param f The Fighter pointer with perks to print. + */ +void printActivePerks(Fighter *f) +{ + + WINDOW *win; + + /* Initialize curses */ + //initscr(); + clear(); + refresh(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + /* Create the windows for player stats and lifetime counters */ + win = newwin(22, 65, 1, 2); + keypad(win, TRUE); + + /* Print a border around the windows and print a title */ + box(win, 0, 0); + print_label(win, 1, 0, 35, "Perks", COLOR_PAIR(S4C_BRIGHT_YELLOW)); + mvwaddch(win, 2, 0, ACS_LTEE); + mvwhline(win, 2, 1, ACS_HLINE, 63); + mvwaddch(win, 2, 64, ACS_RTEE); + + wrefresh(win); + + //attron(COLOR_PAIR(3)); + mvprintw(23, 0, "(Press q or Enter to Exit)"); + //attroff(COLOR_PAIR(3)); + + int y = 4; + int x = 2; + //int startx = 2; + //int width = 65; + + int empty = 1; + + int count = PERKSMAX + 1; + + for (int i = 0; i < count; i++) { + Perk *p = f->perks[i]; + if (p->innerValue > 0) { + empty = 0; + + wattron(win, COLOR_PAIR(S4C_CYAN)); + mvwprintw(win, y, x, " x%i %s ", p->innerValue, + nameStringFromPerk(p->class)); + wattroff(win, COLOR_PAIR(S4C_CYAN)); + char s[250]; + sprintf(s, " x%i %s", p->innerValue, nameStringFromPerk(p->class)); + int l = strlen(s); + wattron(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); + mvwprintw(win, y, x + l + 2, "\"%s\"", + descStringFromPerk(p->class)); + wattroff(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); + y++; + } + }; + + if (empty) { //No perks are active + wattron(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); + mvwprintw(win, y, x, "You don't have any special power yet."); + wattroff(win, COLOR_PAIR(S4C_BRIGHT_YELLOW)); + } + + refresh(); + + int picked = 0; + int c = -1; + wrefresh(win); + + while (!picked && (c = wgetch(win)) != 'q') { + switch (c) { + case 10: { /*Enter */ + picked = 1; + + }; + break; + } + } + delwin(win); + endwin(); +} + +/** + * Takes a WINDOW pointer to print notifications to, a Fighter pointer value and applies the effect pertaining to its status value. + * @see Fighter + * @see fighterStatus + * @see printStatusText() + * @param notify_win The WINDOW pointer to call display_notification() on. + * @param f The Fighter pointer at hand. + */ +void applyStatus(WINDOW *notify_win, Fighter *f) +{ + + switch (f->status) { + case Normal: { + break; + } + break; + case Poison: { + + //Account for penicillin perk + //ATM multiples don't stack + int penicillin = f->perks[PENICILLIN]->innerValue; + if (penicillin > 0) { + return; + } + + if (f->hp >= 4) { + f->hp -= 3; + } else { + f->hp = 1; //Will this be a problem? + } + printStatusText(notify_win, Poison, f->name); + } + break; + case Burned: { + printStatusText(notify_win, Burned, f->name); + } + break; + case Frozen: { + printStatusText(notify_win, Frozen, f->name); + } + break; + case Weak: + + break; + case Strong: + + break; + } +} + +/** + * Takes a WINDOW pointer to print notifications to, a Enemy pointer value and applies the effect pertaining to its status value. + * @see Enemy + * @see fighterStatus + * @see printStatusText() + * @see stringFromEClass() + * @param notify_win The window pointer to call display_notification() on. + * @param e The Enemy pointer at hand. + * @see display_notification() + */ +void applyEStatus(WINDOW *notify_win, Enemy *e) +{ + + wattron(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); + + switch (e->status) { + case Normal: { + break; + } + break; + case Poison: { + if (e->hp >= 4) { + e->hp -= 3; + } else { + e->hp = 1; //Will this be a problem for kills in the enemy loop? + } + printStatusText(notify_win, Poison, stringFromEClass(e->class)); + } + break; + case Burned: { + if (e->hp >= 5) { + e->hp -= 4; + } else { + e->hp = 1; //Will this be a problem for kills in the enemy loop? + } + + if (e->atk >= 3) { + e->atk -= 3; + } else { + e->atk = 1; + } + printStatusText(notify_win, Burned, stringFromEClass(e->class)); + } + break; + case Frozen: { + if (e->vel >= 3) { + e->vel -= 1; + } else { + e->vel = 1; //Will this be a problem for kills in the enemy loop? + } + printStatusText(notify_win, Frozen, stringFromEClass(e->class)); + } + + break; + case Weak: + + break; + case Strong: + + break; + } + + wattroff(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); +} + +/** + * Takes a WINDOW pointer to print notifications to, a Boss pointer value and applies the effect pertaining to its status value. + * @see Boss + * @see fighterStatus + * @see printStatusText() + * @see stringFromBossClass() + * @param notify_win The window pointer to call disaply_notification() on. + * @param b The Boss pointer at hand. + */ +void applyBStatus(WINDOW *notify_win, Boss *b) +{ + + wattron(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); + + switch (b->status) { + case Normal: { + break; + } + break; + case Poison: { + if (b->hp >= 4) { + b->hp -= 3; + } else { + b->hp = 1; //Will this be a problem for kills in the enemy loop? + } + printStatusText(notify_win, Poison, stringFromBossClass(b->class)); + } + break; + case Burned: { + if (b->hp >= 5) { + b->hp -= 4; + } else { + b->hp = 1; //Will this be a problem for kills in the enemy loop? + } + + if (b->atk >= 3) { + b->atk -= 3; + } else { + b->atk = 1; + } + printStatusText(notify_win, Burned, stringFromBossClass(b->class)); + } + break; + case Frozen: { + if (b->vel >= 3) { + b->vel -= 1; + } else { + b->vel = 1; //Will this be a problem for kills in the enemy loop? + } + printStatusText(notify_win, Frozen, stringFromBossClass(b->class)); + } + + break; + case Weak: + + break; + case Strong: + + break; + } + + wattroff(notify_win, COLOR_PAIR(S4C_BRIGHT_GREEN)); +} + +/** + * Takes a WINDOW pointer to print notifications to, a fighterStatus value and a string of who's the entity to print the respective status message. + * @see fighterStatus + * @param notify_win The pointer to the window to use display_notification() on. + * @param status The fighterStatus at hand. + * @param subject A string with name of entity owning the fighterStatus. + */ +void printStatusText(WINDOW *notify_win, fighterStatus status, char *subject) +{ + char msg[500]; + switch (status) { + case Normal: { + return; + }; + break; + case Poison: + case Burned: { + sprintf(msg, "%s is hurt by its %s.", subject, + stringFromStatus(status)); + display_notification(notify_win, msg, 500); + } + break; + case Weak: + case Strong: { + sprintf(msg, "%s is feeling %s.", subject, + stringFromStatus(status)); + display_notification(notify_win, msg, 500); + } + break; + case Frozen: { + sprintf(msg, "%s is frozen cold.", subject); + display_notification(notify_win, msg, 500); + } + break; + } +} + +/** + * Asks the user is they want to continue and returns the choice. + * @return int True for trying again, false otherwise. + */ +int retry(void) +{ + lightGreen(); + printf("\n\nYou died. Want to try again?\n\n\t\t[type no / yes]\n\n"); + white(); + char c[25] = { 0 }; + if (fgets(c, sizeof(c), stdin) != NULL) { + log_tag("debug_log.txt", "[DEBUG]", "Read input for %s().", __func__); + if (c[strlen(c) - 1] == '\n') { + c[strlen(c) - 1] = '\0'; + } + + for (char *ptr = c; *ptr; ++ptr) { + *ptr = tolower(*ptr); + } + + if ( (c[0] == '\0') || (strcmp(c, "no") == 0) || (strcmp(c, "n") == 0) ) { + log_tag("debug_log.txt", "[DEBUG]", "%s(): input was no.", + __func__); + return 0; + } else if ((strcmp(c, "yes") == 0) || (strcmp(c, "y") == 0) ) { + log_tag("debug_log.txt", "[DEBUG]", "%s(): input was yes.", + __func__); + return 1; + } else { + log_tag("debug_log.txt", "[DEBUG]", + "%s(): Invalid input, defaulting to 0.", __func__); + + return 0; + } + } else { + log_tag("debug_log.txt", "[DEBUG]", "Failed reading input for %s.", + __func__); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_FAILURE); + } +} + +/** + * Takes a integer and a string array (possibly from main), a Fighter pointer and a Path pointer to set some values. + * Depending on argc value, the arguments in argv may be used instead of calling the functions to get user input. + * @see Fighter + * @see pickName() + * @see pickClass() + * @see pickWincon() + * @param argc The number of argv values + 1 (0 is program name?). + * @param argv Array of strings with argc - 1 values. + * @param player The Fighter of which we set name and class. + * @param path The Path pointer used for the game. + * @param kls The Koliseo used for allocation. + */ +void getParams(int argc, char **argv, Fighter *player, Path *path, int optTot, + Koliseo *kls) +{ + + int argTot = argc - optTot; + if (argTot == 0) { + pickName(player); + pickClass(player); + kls_log(kls, "DEBUG", "Prepping Wincon"); + Wincon *w = + (Wincon *) KLS_PUSH_TYPED(kls, Wincon, HR_Wincon, "Wincon", + "Wincon"); + if (GAMEMODE == Story) { + //Path length must be already initialised before getting here. + initWincon(w, path, FULL_PATH); + } else if (GAMEMODE == Rogue) { + //Path length must be already initialised before getting here. + initWincon(w, path, ALL_ARTIFACTS); + } else { + pickWincon(w); + initWincon(w, path, w->class); + } + path->win_condition = w; + } else if (argTot == 1 || argTot == 2) { + char read_name[25]; + int i = 0, len = 0; + len = strlen(argv[optTot]); + if (len < 20) { + for (; i < len; i++) { + read_name[i] = argv[optTot][i]; + } + read_name[i] = '\0'; + strcpy(player->name, read_name); + } else { + pickName(player); + } + } else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + if (argTot == 1) { + pickClass(player); + kls_log(kls, "DEBUG", "Prepping Wincon"); + Wincon *w = + (Wincon *) KLS_PUSH_TYPED(kls, Wincon, HR_Wincon, "Wincon", + "Wincon"); + if (GAMEMODE == Story) { + //Path length must be already initialised before getting here. + initWincon(w, path, FULL_PATH); + } else if (GAMEMODE == Rogue) { + //Path length must be already initialised before getting here. + initWincon(w, path, ALL_ARTIFACTS); + } else { + pickWincon(w); + initWincon(w, path, w->class); + } + path->win_condition = w; + } + + if (argTot == 2) { + int c = -1; + int i = 0; + for (i = 0; i <= CLASSESMAX; i++) { + if (strcmp(argv[optTot + 1], classesstrings[i]) == 0) { + c = 1; + player->class = i; + break; + } + } + if (c < 0) { + pickClass(player); + } + kls_log(kls, "DEBUG", "Prepping Wincon"); + Wincon *w = + (Wincon *) KLS_PUSH_TYPED(kls, Wincon, HR_Wincon, "Wincon", + "Wincon"); + if (GAMEMODE == Story) { + //Path length must be already initialised before getting here. + initWincon(w, path, FULL_PATH); + } else if (GAMEMODE == Rogue) { + //TODO: what do we set as path length? Number of floors? + //Path length must be already initialised before getting here. + initWincon(w, path, ALL_ARTIFACTS); + } else { + pickWincon(w); + initWincon(w, path, w->class); + } + path->win_condition = w; + } +} +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + +void test_game_color_pairs(Rectangle * win, int colors_per_row) +{ + (void) win; + (void) colors_per_row; + printf("%s(): TODO - Implement game color pairs test for rl-build\n", __func__); + return; +} + +/** + * Inits the passed (preallocated) Gamestate with the passed pointers. + * @param gmst The allocated Gamestate to init. + * @param start_time The start time for current game. + * @param stats Game stats. + * @param wincon Game Wincon. + * @param path Game Path. + * @param player Game main player. + * @param gamemode Picked gamemode. + */ +void init_Gamestate(Gamestate *gmst, clock_t start_time, countStats *stats, Wincon *wincon, + Path *path, Fighter *player, Gamemode gamemode) +{ + if (gmst == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Gamestate was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (stats == NULL) { + log_tag("debug_log.txt", "[ERROR]", "countStats was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (wincon == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Wincon was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (path == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Path was NULL in %s()", __func__); + exit(EXIT_FAILURE); + } + if (player == NULL) { + log_tag("debug_log.txt", "[ERROR]", "Player was NULL in %s()", + __func__); + exit(EXIT_FAILURE); + } + if (gamemode != Story && gamemode != Rogue) { + log_tag("debug_log.txt", "[ERROR]", "Invalid gamemode requested: [%i]", + gamemode); + exit(EXIT_FAILURE); + } + gmst->start_time = start_time; + gmst->stats = stats; + gmst->current_fighters = -1; + gmst->current_roomtype = -1; + gmst->current_room_index = -1; + gmst->current_enemy_index = -1; + gmst->wincon = wincon; + gmst->path = path; + gmst->player = player; + gmst->gamemode = gamemode; +} + +turnOP_args *init_turnOP_args(Gamestate *gmst, Fighter *actor, Path *path, + Room *room, loadInfo *load_info, Enemy *enemy, + Boss *boss, FILE *save_file, Rectangle *notification_area, + Koliseo_Temp *t_kls, foeTurnOption_OP foe_op, + skillType picked_skill) +{ + printf("%s(): TODO - implement turnOP init for rl-build\n", __func__); + return NULL; +} + +/** + * Takes a Fighter pointer and asks the user to select a specialMove to unlock with a formatted text menu. + * From the specials field of fighter, only the SpecialSlot with the enabled falg not set are printed and selectable by user. + * For the Fighter, the equipboost values are also displayed. + * @see Fighter + * @see SpecialSlot + * @see SPECIALSMAX + * @see setSpecials() + * @see stringFromSpecial() + * @param f The Fighter pointer that get one of his not yet unlocked specials. + */ +void unlockSpecial(Fighter *f) +{ + (void) f; +} + +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +/** + * Takes a Fighter and loadInfo pointers and prints fighter stats and a game over message. + * Consumables and Artifacts are emptied before freeing the player's specials, counters, perks and stats field. + * At last, the player pointer is freed. + * @see Fighter + * @see handleStats() + * @see emptyConsumables() + * @see emptyArtifacts() + * @param player The Fighter pointer to free. + * @param load_info The loadInfo pointer to free. + */ +void death(Fighter *player, loadInfo *load_info) +{ + + //FIXME: + //dropping out of the Koliseo scope might render stat pointer invalid. + //handleStats(player); + + //Free default kls + kls_free(default_kls); + //kls_log(kls,"DEBUG","Freed default KLS"); + log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed default KLS"); + + //Free temporary kls + kls_free(temporary_kls); + //kls_log(kls,"DEBUG","Freed temporary KLS"); + log_tag("debug_log.txt", "[DEBUG-KLS]", "Freed temporary KLS"); + + /* + free(load_info); + sprintf(msg,"Freed loadInfo.\n"); + log_tag("debug_log.txt","[FREE]",msg); + */ + + //emptyConsumables(player); + //emptyArtifacts(player); + /* + //Free player special slots + for (int i=0; i < (SPECIALSMAX + 1) ; i++) { + free(player->specials[i]); + sprintf(msg,"Freed player special %i.",i); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + /* + //Free player equipbag + int total = player->equipsBagOccupiedSlots; + for (int i=0; i < (total ) ; i++) { + Equip* e = (Equip*) player->equipsBag[i]; + int perkscount = e->perksCount; + if (perkscount > 0) { + for (int j=0; j < perkscount; j++) { + free(e->perks[j]); + sprintf(msg,"Freed equip %i perk %i.", i, j); + log_tag("debug_log.txt","[FREE]",msg); + } + } + free(e); + sprintf(msg,"Freed equip %i.\n", i); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + /* + //Free player consumablebag + int cons_total = CONSUMABLESMAX+1; + for (int i=0; i < cons_total ; i++) { + Consumable* c = (Consumable*) player->consumablesBag[i]; + sprintf(msg,"Freed consumable %i.", i); + log_tag("debug_log.txt","[FREE]",msg); + free(c); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + /* + //Free player equip slots + for (int i=0; i < (EQUIPZONES + 1) ; i++) { + Equipslot* s = (Equipslot*) player->equipslots[i]; + + int perkscount = -1; + + if (s->active) { perkscount = s->item->perksCount;}; + if (perkscount > 0) { + for (int i=0; i < perkscount; i++) { + free(s->item->perks[i]); + } + free(s->item); + } + + free(s); + sprintf(msg,"Freed equipslot %i.", i); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + /* + //Free player artifactsbag + int art_total = CONSUMABLESMAX+1; + for (int i=0; i < art_total ; i++) { + Artifact* a = (Artifact*) player->artifactsBag[i]; + free(a); + sprintf(msg,"Freed artifact %i.", i); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + /* + //Free player turnCounters + for (int i=0; i < (COUNTERSMAX + 1) ; i++) { + Turncounter* c = (Turncounter*) player->counters[i]; + free(c->desc); + sprintf(msg,"Freed turncounter %i desc.", i); + log_tag("debug_log.txt","[FREE]",msg); + free(c); + sprintf(msg,"Freed turncounter %i.\n", i); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + /* + //Free player perks + for (int i=0; i < (PERKSMAX + 1) ; i++) { + free(player->perks[i]); + sprintf(msg,"Freed player perk %i.", i); + log_tag("debug_log.txt","[FREE]",msg); + } + log_tag("debug_log.txt","[FREE]","Done.\n"); + */ + + //free(player->stats); + //log_tag("debug_log.txt","[FREE]","Freed player stats.\n"); +} + +/** + * Takes a Enemy pointer and frees its allocated memory. + * The counters field is freed before the enemy pointer. + * @see Enemy + * @param e The Enemy pointer to free. + */ +void e_death(Enemy *e) +{ + + //Free enemy special slots + //for (int i=0; i < SPECIALSMAX + 1 ; i++) { + // free(player->specials[i]); + //} + + /* + //Free enemy turnCounters + for (int i=0; i < (COUNTERSMAX + 1) ; i++) { + Turncounter* c = (Turncounter*) e->counters[i]; + sprintf(msg,"Freed enemy turncounter %i desc: %s.",i, c->desc); + log_tag("debug_log.txt","[FREE]",msg); + if (c->desc == NULL) { + log_tag("debug_log.txt","[ERROR]", "Enemy turncounter desc was null.\n"); + } else { + char* desc_to_free = c->desc; + free(desc_to_free); + } + free(c); + sprintf(msg,"Freed enemy turncounter %i.\n",i); + log_tag("debug_log.txt","[FREE]",msg); + } + */ + + //sprintf(msg,"Freeing enemy %s",stringFromEClass(e->class)); + //log_tag("debug_log.txt","[FREE]",msg); + //free(e); + log_tag("debug_log.txt", "[TODO]", "[%s]: remove this empty function.", + __func__); +} + +/** + * Takes a Boss pointer and frees its allocated memory. + * The counters field is freed before the boss pointer. + * @see Boss + * @param b The Boss pointer to free. + */ +void b_death(Boss *b) +{ + + //TODO + //Remove this bs + log_tag("debug_log.txt", "[DEBUG]", "b_death(): I'm doing nothing."); + + //Free boss special slots + //for (int i=0; i < SPECIALSMAX + 1 ; i++) { + // free(player->specials[i]); + //} + //Free boss turnCounters + /* + for (int i=0; i < (COUNTERSMAX + 1) ; i++) { + Turncounter* c = (Turncounter*) b->counters[i]; + sprintf(msg,"Freed boss turncounter %i desc: %s.",i, c->desc); + log_tag("debug_log.txt","[FREE]",msg); + free(c->desc); + free(c); + sprintf(msg,"Freed boss turncounter %i.\n",i); + log_tag("debug_log.txt","[FREE]",msg); + } + */ + //free(b); +} + +/** + * Takes a Turncounter array, an integer, a Fighter pointer and an Enemy pointer. + * For every Turncounter in the array count value is checked, and when it's equal to 1, the function pointer relevant to the type value of the Counter is called. Depending on the isEnemy input value, the function call will be for the Fighter or Enemy version (and the according pointer from the input will be passed to the called function). + * When the count value is 0, counters are considered inactive, so when the count value is not 1, it is lowered by 1 if it's positive. + * @see Fighter + * @see Enemy + * @see Turncounter + * @see Countertype + * @see COUNTERSMAX + * @see counterIndexes + * @param counters The Turncounter array to be updated. + * @param isEnemy Dictates if the check is done for an Enemy or a Fighter. + * @param f The Fighter pointer whose counters field will be updated if isEnemy is false. + * @param e The Enemy pointer whose counters field will be updated if isEnemy is true. + */ +void updateCounters(Turncounter *counters[], int isEnemy, Fighter *f, Enemy *e) +{ + for (int i = 0; i < COUNTERSMAX + 1; i++) { + + Turncounter *c = counters[i]; + if (c->count == 1) { //Counter is about to expire so we call the correct function: + switch (c->type) { + case CNT_STATUS: { //Callback for status counters + + if (!isEnemy) { + (c->effect_fun) (f); + //green(); + //printf("\t%s status returned to normal.\n",f->name); + //white(); + } else { //Enemy function + (c->effect_e_fun) (e); + //lightRed(); + //printf("\t%s status returned to normal.\n",stringFromEClass(e->class)); + //white(); + //TODO + //Display notification to win + log_tag("debug_log.txt", "[DEBUG-COUNTER]", + "Status reset for %s.", + stringFromEClass(e->class)); + } + } + break; + case CNT_ATKBOOST: + case CNT_DEFBOOST: + case CNT_VELBOOST: + case CNT_ENRBOOST: { //Callback for stat boosts + if (!isEnemy) { + (c->boost_fun) (f, 0); //Call ~setPermBoost(STAT)~ with value 0 + log_tag("debug_log.txt", "[DEBUG-COUNTER]", + "Applied boost function for Fighter."); + } else { + assert(0 && "UNACCESSIBLE CALL.\n"); + (c->boost_e_fun) (e, 0); //Call ~setPermBoost(STAT)~ with value 0 + } + } + break; + } + + //Set counter to zero + c->count = 0; + c->innerValue = 0; + } else if (c->count > 1) { //We simply advance the count + log_tag("debug_log.txt", "[DEBUG-COUNTER]", + "Advancing counter %i for %s.", i, + (isEnemy ? "Enemy" : "Fighter")); + c->count -= 1; + } + }; +} + +/** + * Takes a Turncounter array, an integer, a Fighter pointer and a Boss pointer. + * For every Turncounter in the array count value is checked, and when it's equal to 1, the function pointer relevant to the type value of the Counter is called. Depending on the isBoss input value, the function call will be for the Fighter or Boss version (and the according pointer from the input will be passed to the called function). + * When the count value is 0 Counters are considered inactive, so when the count value is not 1, it is lowered by 1 if it's positive. + * @see Fighter + * @see Boss + * @see Turncounter + * @see Countertype + * @see COUNTERSMAX + * @see counterIndexes + * @param counters The Turncounter array to be updated. + * @param isBoss Dictates if the check is done for a Boss or a Fighter. + * @param f The Fighter pointer whose counters field will be updated if isBoss is false. + * @param b The Boss pointer whose counters field will be updated if isBoss is true. + */ +void updateCounters_Boss(Turncounter *counters[], int isBoss, Fighter *f, + Boss *b) +{ + for (int i = 0; i < COUNTERSMAX + 1; i++) { + + Turncounter *c = counters[i]; + if (c->count == 1) { //Counter is about to expire so we call the correct function: + switch (c->type) { + case CNT_STATUS: { //Callback for status counters + + //TODO + //Add notification to window + if (!isBoss) { + (c->effect_fun) (f); + //green(); + //printf("\t%s status returned to normal.\n",f->name); + //white(); + } else { //Boss function + (c->effect_b_fun) (b); + //lightRed(); + //printf("\t%s status returned to normal.\n",stringFromBossClass(b->class)); + //white(); + } + } + break; + case CNT_ATKBOOST: + case CNT_DEFBOOST: + case CNT_VELBOOST: + case CNT_ENRBOOST: { //Callback for stat boosts + if (!isBoss) { + (c->boost_fun) (f, 0); //Invoke ~setPermBoost(STAT)~ with value 0 + } else { + assert(0 && "UNACCESSIBLE CALL.\n"); + (c->boost_b_fun) (b, 0); //Call ~setPermBoost(STAT)~ with value 0 + } + } + break; + } + + //Set counter to zero + c->count = 0; + c->innerValue = 0; + } else if (c->count > 1) { //We simply advance the count + c->count -= 1; + } + }; +} + +/** + * Takes a Fighter pointer and the amount of xp to add. + * Current level xp is managed by this function, including how much xp is needed to level up again. The values are stored in the fighter struct. + * Thresholds for each level are checked and eventually onLevelUp() is called, with recursion on this function after. + * @see Fighter + * @see onLevelUp() + * @param player The Fighter pointer that gets xp. + * @param xp The amount of xp. + */ +void checkremainder(Fighter *player, int xp) +{ + int curr = player->currentlevelxp; + int tot = player->totallevelxp; + + //TODO: Print notifications to a passed WINDOW + + if (curr + xp >= tot) { + player->totalxp += xp; + //if (xp !=0) printf("\n\t%s obtained %i xp.", player->name, xp); + player->level++; + + //cyan(); + //printf("\n\t%s reached Lvl. %i !", player->name, player->level); + //white(); + + //Stats gains on level up + onLevelUp(player); + + player->currentlevelxp = abs((tot - curr - xp)); + int nextLevelMoreXp = + round(1.75 * (player->level + 1)) + player->level + 1; + player->totallevelxp = (tot / player->level) + nextLevelMoreXp; + checkremainder(player, 0); + } else { + player->currentlevelxp += xp; + player->totalxp += xp; + if (xp != 0) { + //printf("\n\t%s obtained %i xp.", player->name, xp); + } + } +} + +/** + * Takes a Fighter and a Enemy pointers and handles xp gain by fighter. + * @see Fighter + * @see Enemy + * @see getEnemyXpGain() + * @see checkremainder() + * @param player The Fighter pointer that gets xp. + * @param e The Enemy pointer that gives xp. + */ +void giveXp(Fighter *player, Enemy *e) +{ + + int xp = getEnemyXpGain(e); + + checkremainder(player, xp); +} + +/** + * Takes a Fighter and a Boss pointers and handles xp gain by fighter. + * @see Fighter + * @see Boss + * @see getBossXpGain() + * @see checkremainder() + * @param player The Fighter pointer that gets xp. + * @param b The Boss pointer that gives xp. + */ +void giveXp_Boss(Fighter *player, Boss *b) +{ + + int xp = getBossXpGain(b); + + checkremainder(player, xp); +} + +/** + * Takes a Enemy pointer and returns its xp gain as sum of xp field value and level. + * @see Enemy + * @param e The Enemy pointer. + * @return int The xp gain. + */ +int getEnemyXpGain(Enemy *e) +{ + + int xp = e->xp + e->level; + return xp; +} + +/** + * Takes a Boss pointer and returns its xp gain as sum of xp field value and level. + * @see Boss + * @param b The Boss pointer. + * @return int The xp gain. + */ +int getBossXpGain(Boss *b) +{ + + int xp = b->xp + b->level; + return xp; +} + +/** + * Takes a Fighter pointer and updated its stats. + * getBoost() is called to get the stat boost for current level, which is then applyed to atk, def and vel; while hp gets first multiplied by 1.13 and then gets the boost added. + * The totalenergy value is increased by player level over 5. + * Hp and energy are replenished. + * If the level is multiple of SPECIALLVLRATIO and the player still has at least one SpecialSlot not enabled, unlockSpecial() is called. + * @see Fighter + * @see getBoost() + * @see BaseStats + * @see SpecialSlot + * @see SPECIALSMAX + * @see SPECIALLVLRATIO + * @see unlockSpecial() + * @param player The Fighter pointer that levels up. + */ +void onLevelUp(Fighter *player) +{ + int boost = getBoost(player->level, player->luck); + + BaseStats *base = &basestats[player->class]; + + player->atk = (base->atk + boost); + player->def = (base->def + boost); + player->vel = (base->vel + boost); + player->totalhp = (base->hp * 1.13) + boost; + + int energyboost = player->level / 5; //Energy grows by lvl/5 on each lvl up + player->totalenergy = + base->totalenergy + energyboost + player->permboost_enr; + + player->hp = player->totalhp; //Cure on level up + player->energy = player->totalenergy; //Refill energy on level up + + //Check if you get a new special move + if (player->level % SPECIALLVLRATIO == 0 + && (player->stats->specialsunlocked < (SPECIALSMAX + 1))) { + unlockSpecial(player); + } + + log_tag("debug_log.txt", "[LEVELUP]", "Player leveled up."); + + /* + lightCyan(); + printf("\n\n\tYour wounds were healed."); + printf("\n\tYour energy is replenished."); + white(); + */ +} + +/** + * Takes two integers for level to calc against and luck, and returns the boost relative to the level with luck variations, as an integer. + * At level 1, returns 0. + * @param lvl The level to check the boost against. + * @param luck The luck value to influence calcs. + * @return int The boost for any given stat, at the level passed as argument. + */ +int getBoost(int lvl, int luck) +{ + + float boost = (lvl * 1.25F) + ((luck % 2) * 2); + + if (lvl < 2) { + boost = 1.0; // Evitare conflitti + } + + return (int)boost; +} + +/** + * Takes a Fighter pointer and deleted all the equips not in use, granting a payment to the Fighter balance. + * @see Shop + * @see handleRoom_Shop() + * @see Fighter + * @param f The Fighter pointer at hand. + */ +void sell_all_equips(Fighter *f, Koliseo_Temp *t_kls) +{ + char msg[200]; + + Equip *saved_equips[EQUIPZONES + 1]; + int saved_count = 0; + Koliseo *kls = t_kls->kls; + + for (int i = 0; i < EQUIPZONES + 1; i++) { + if (f->equipslots[i]->active) { + sprintf(msg, + "sell_all_equips(): Prepping Equip to save f->equipslot[%i]", + i); + log_tag("debug_log.txt", "[DEBUG]", msg); + kls_log(kls, "DEBUG", msg); + Equip *saved = + (Equip *) KLS_PUSH_T_TYPED(t_kls, Equip, HR_Equip, "Equip", + msg); + Equip *to_save = f->equipslots[i]->item; + + saved->class = to_save->class; + saved->type = to_save->type; + strcpy(saved->name, to_save->name); + strcpy(saved->desc, to_save->desc); + saved->qty = to_save->qty; + saved->equipped = 0; //Will be set after when re-equipped + saved->level = to_save->level; + saved->atk = to_save->atk; + saved->def = to_save->def; + saved->vel = to_save->vel; + saved->enr = to_save->enr; + saved->bonus = to_save->bonus; + saved->perksCount = 0; //Will be set during perks copy + saved->qual = to_save->qual; + saved->equip_fun = to_save->equip_fun; + + for (int j = 0; j < to_save->perksCount; j++) { + sprintf(msg, + "sell_all_equips(): Prepping Perk (%i) to save f->equipslot[%i]", + j, i); + log_tag("debug_log.txt", "[DEBUG]", msg); + kls_log(kls, "DEBUG", msg); + Perk *save_pk = + (Perk *) KLS_PUSH_T_TYPED(t_kls, Perk, HR_Perk, "Perk", + msg); + save_pk->class = to_save->perks[j]->class; + strcpy(save_pk->name, to_save->perks[j]->name); + strcpy(save_pk->desc, to_save->perks[j]->desc); + save_pk->innerValue = to_save->perks[j]->innerValue; + saved->perks[saved->perksCount] = save_pk; + saved->perksCount++; + } + + for (int j = 0; j < 8; j++) { + strcpy(saved->sprite[j], to_save->sprite[j]); + } + + saved_equips[saved_count] = saved; + saved_count++; + } + } + + int deleted_count = 0; + int pay = 0; + + for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { + Equip *toDel = f->equipsBag[i]; + pay += toDel->cost / 2; + //int perksTot = toDel->perksCount; + /* + for (int j = 0; j < perksTot; j++) { + Perk* pk = toDel->perks[j]; + free(pk); + } + */ + //FIXME: are we deleting this correctly? + //free(toDel); + deleted_count++; + } + + f->equipsBagOccupiedSlots -= deleted_count; + + for (int i = 0; i < saved_count; i++) { + f->equipsBag[i] = saved_equips[i]; + f->equipslots[i]->item = saved_equips[i]; + saved_equips[i]->equipped = 1; + f->equipsBagOccupiedSlots++; + } + f->earliestBagSlot = f->equipsBagOccupiedSlots; + + f->balance += pay; + +} + +/** + * Returns the chosen option as a turnOption. + * @param ch A string representing the turn choice. + * @return The chosen turnOption value representing turn action. + */ +turnOption getTurnChoice(char *ch) +{ + int comp = 999; + + log_tag("debug_log.txt", "[TURNPICK]", "Turnchoice string was (%s)", ch); + turnOption pick = INVALID; + + while (pick == INVALID) { + if ((comp = strcmp(ch, "Fight")) == 0) { + pick = FIGHT; + } else if ((comp = strcmp(ch, "New game")) == 0) { + pick = NEW_GAME; + } else if ((comp = strcmp(ch, "Load save")) == 0) { + pick = LOAD_GAME; + } else if ((comp = strcmp(ch, "Special")) == 0) { + pick = SPECIAL; + } else if ((comp = strcmp(ch, "Consumables")) == 0) { + pick = CONSUMABLE; + } else if ((comp = strcmp(ch, "Artifacts")) == 0) { + pick = ARTIFACTS; + } else if ((comp = strcmp(ch, "Equips")) == 0) { + pick = EQUIPS; + } else if ((comp = strcmp(ch, "Perks")) == 0) { + pick = PERKS; + } else if ((comp = strcmp(ch, "Stats")) == 0) { + pick = STATS; + } else if ((comp = strcmp(ch, "Save")) == 0) { + pick = SAVE; + } else if ((comp = strcmp(ch, "Debug")) == 0) { + pick = DEBUG; + } else if ((comp = strcmp(ch, "Quit")) == 0) { + pick = QUIT; + } else if ((comp = strcmp(ch, "Explore")) == 0) { + pick = EXPLORE; + } else if ((comp = strcmp(ch, "Tutorial")) == 0) { + pick = TUTORIAL; + } else if ((comp = strcmp(ch, "Close")) == 0) { + pick = CLOSE_MENU; + } else { + pick = INVALID; + } + } + + log_tag("debug_log.txt", "[TURNOPT]", "Pick was: (%i)", pick); + + if (pick == INVALID) { + fprintf(stderr, "Error: unexpected turn choice value"); + log_tag("debug_log.txt", "[ERROR]", + "Unexpected turn choice in getTurnChoice(), quitting"); + exit(EXIT_FAILURE); + } + return pick; +} + +/** + * Returns a randomised pick as foeTurnOption. + * @param e Pointer to the enemy to pick for. + * @param f Pointer to the target fighter. + * @return The chosen foeturnOption value representing turn action. + */ +foeTurnOption enemyTurnPick(Enemy *e, Fighter *f) +{ + if (e == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "enemyTurnPick(): Enemy was NULL."); + exit(EXIT_FAILURE); + } + if (f == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "enemyTurnPick(): Fighter was NULL."); + exit(EXIT_FAILURE); + } + foeTurnOption pick = FOE_INVALID; + + while (pick == FOE_INVALID) { + int rn = rand() % 101; + /* + if (rn > 80) { + //TODO + //pick = FOE_SPECIAL; + pick = FOE_IDLE; + + } else + */ + if (rn > 40) { + pick = FOE_FIGHT; + } else { + pick = FOE_IDLE; + } + } + + log_tag("debug_log.txt", "[FOETURNOPTION]", "Pick was: ( %i ) [ %s ]", pick, + stringFromFoeTurnOP(foeTurnOP_from_foeTurnOption(pick))); + + if (pick == FOE_INVALID) { + fprintf(stderr, "Error: unexpected turn choice value"); + log_tag("debug_log.txt", "[ERROR]", + "Unexpected turn choice in enemyTurnPick(), quitting"); + exit(EXIT_FAILURE); + } + return pick; +} + +/** + * Returns a randomised pick as foeTurnOption. + * @param b Pointer to the boss to pick for. + * @param f Pointer to the target fighter. + * @return The chosen foeturnOption value representing turn action. + */ +foeTurnOption bossTurnPick(Boss *b, Fighter *f) +{ + if (b == NULL) { + log_tag("debug_log.txt", "[ERROR]", "bossTurnPick(): Boss was NULL."); + exit(EXIT_FAILURE); + } + if (f == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "bossTurnPick(): Fighter was NULL."); + exit(EXIT_FAILURE); + } + foeTurnOption pick = FOE_INVALID; + + while (pick == FOE_INVALID) { + int rn = rand() % 101; + /* + if (rn > 80) { + //TODO + //pick = FOE_SPECIAL; + pick = FOE_IDLE; + } else + */ + if (rn > 40) { + pick = FOE_FIGHT; + } else { + pick = FOE_IDLE; + } + } + + log_tag("debug_log.txt", "[FOETURNOPTION]", "Pick was: ( %i ) [ %s ]", pick, + stringFromFoeTurnOP(foeTurnOP_from_foeTurnOption(pick))); + + if (pick == FOE_INVALID) { + fprintf(stderr, "Error: unexpected turn choice value"); + log_tag("debug_log.txt", "[ERROR]", + "Unexpected turn choice in enemyTurnPick(), quitting"); + exit(EXIT_FAILURE); + } + return pick; +} + +/** + * Takes a Fighter, a Room and a loadInfo pointers, and prints fighter stats and a quitting message, before quitting the program and freeing Room. + * + * @see Fighter + * @see printStats() + * @see death() + * @param p The Fighter pointer at hand. + * @param room The Room pointer at hand. + * @param load_info The loadInfo pointer at hand. + * @param t_kls The Koliseo_Temp to end if possible. + */ +void quit(Fighter *p, Room *room, loadInfo *load_info, Koliseo_Temp *t_kls) +{ + char msg[500]; + Koliseo *kls = t_kls->kls; +#ifdef HELAPORDO_CURSES_BUILD + endwin(); +#endif + int res = system("reset"); + sprintf(msg, "quit() system(\"reset\") res was (%i)", res); + log_tag("debug_log.txt", "[DEBUG]", msg); + //printf("\n\n\tTHANKS 4 PLAYING\n"); + //FIXME + //dropping out of the Koliseo scope might render stat pointer invalid. + //Can't we print stats and clear the kls? + //printStats(p); + //printf("\n"); +#ifndef _WIN32 + sprintf(msg, "Resetting Koliseo_Temp from: (%li)", t_kls->kls->offset); +#else + sprintf(msg, "Resetting Koliseo_Temp from: (%lli)", t_kls->kls->offset); +#endif + kls_log(kls, "DEBUG", msg); + death(p, load_info); + //FIXME + //I think we should free those? + //May cause a crash? + //kls_free(default_kls); + //kls_free(temporary_kls); + //FIXME: + //Calling this segfaults? + //freeRoom(room); + log_tag("debug_log.txt", "[DEBUG]", "Quitting program."); + exit(EXIT_SUCCESS); +} + +/** + * Takes a Turncounter pointer and an integer. + * If the count value at the pointer is 0 (counter is inactive), the turns valueis assigned. + * @see Turncounter + * @param c The Turncounter whose count value will be set. + * @param turns The value to be assigned. + */ +void setCounter(Turncounter *c, int turns) +{ + + if (c->count == 0) { // Counter is NOT already active + c->count = turns; + } else { + //Handle counters already activ + } +} + +/** + * Takes a Fighter, an Enemy and a Boss pointers, a string denoting the consumableClass and an int for use on enemy or boss. + * If qty value for the Consumable is 0, we have an early return. Otherise effect is applied and qty is decreased. + * @see Fighter + * @see Enemy + * @see Boss + * @see Consumable + * @see consumableClass + * @param f The Fighter pointer at hand. + * @param e The Enemy pointer at hand. + * @param b The Boss pointer at hand. + * @param string The string value of consumable to use. + * @param isBoss The mode of use (on boss if == 1) + */ +void useConsumable(Fighter *f, Enemy *e, Boss *b, char *string, int isBoss) +{ + //Mountain of ifs? Where are my damn maps + + int i = 0; + int check; + for (int j = 0; j < CONSUMABLESMAX + 1; j++) { + if ((check = strcmp(consumablestrings[j], string)) == 0) { + i = j; + } + }; + + Consumable *c = (Consumable *) f->consumablesBag[i]; + + if (c->qty == 0) { + return; + } + if (c->class == Potion) { + f->hp = f->totalhp; + //green(); + //printf("\n\n\n\tYour health was restored.\n\n"); + //white(); + } else if (c->class == Rock) { + if (isBoss) { + b->def -= 8; + b->hp -= 2; + //printf("\n\n\n\t%s got smacked.",stringFromBossClass(b->class)); + } else { + e->def -= 8; + e->hp -= 2; + //printf("\n\n\n\t%s got smacked.",stringFromEClass(e->class)); + } + //red(); + //printf("\t-8 DEF and -2 HP.\n\n"); + //white(); + } else if (c->class == Bread) { + f->vel -= 1; + f->def += 6; + f->atk += 4; + //printf("\n\n\n\tYou ate elvish bread."); + //green(); + //printf("\t+6 DEF , +4 ATK, "); + //yellow(); + //printf("-1 VEL\n\n"); + //white(); + } else if (c->class == Coffee) { + f->vel += 6; + f->atk += 2; + f->def -= 2; + //printf("\n\n\n\tYou drank hot coffee."); + //green(); + //printf("\t+6 SPE , +2 ATK, "); + //yellow(); + //printf("-2 DEF\n\n"); + //white(); + } else if (c->class == Powergem) { + //printf("\n\n\n\tYou became wiser."); + //green(); + //printf("\t+25 XP\n\n"); + //white(); + checkremainder(f, 25); + } else if (c->class == Magicbean) { + //printf("\n\n\n\tYou aren't tired anymore."); + //green(); + //printf("\tEnergy was restored\n\n"); + //white(); + f->energy = f->totalenergy; //Refill energy + } else { + return; + } + + c->qty--; +} diff --git a/src/game_utils.h b/src/utils/game_utils.h similarity index 55% rename from src/game_utils.h rename to src/utils/game_utils.h index 816ecf6d..089d3cb3 100644 --- a/src/game_utils.h +++ b/src/utils/game_utils.h @@ -20,9 +20,12 @@ #define GAME_UTILS_H #ifdef HELAPORDO_CURSES_BUILD +#include "../core/sprites.h" #ifdef _WIN32 #include +#include #else +#include #include #endif // _WIN32 #else @@ -40,8 +43,9 @@ #include #include #include -#include "game_core.h" +#include "../core/game_core.h" +void initWincon(Wincon * w, Path * p, winconClass class); void printGlobVars(void); #ifdef _WIN32 @@ -67,15 +71,6 @@ void cyan(void); void lightCyan(void); void init_game_color_pairs(void); -#ifdef HELAPORDO_CURSES_BUILD -void test_game_color_pairs(WINDOW * win, int colors_per_row); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -void test_game_color_pairs(Rectangle * win, int colors_per_row); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD void resolve_staticPath(char static_path[500]); void dbg_print_floor_layout(Floor * floor); @@ -88,17 +83,7 @@ void dbg_countStats(countStats * stats); void dbg_Wincon(Wincon * wc); void dbg_Path(Path * path); void dbg_Saveslot(Saveslot * saveslot); -#ifdef HELAPORDO_CURSES_BUILD -void init_Gamestate(Gamestate * gmst, clock_t start_time, countStats * stats, Wincon * wincon, - Path * path, Fighter * player, Gamemode gamemode, GameScreen* screen); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -void init_Gamestate(Gamestate * gmst, clock_t start_time, countStats * stats, Wincon * wincon, - Path * path, Fighter * player, Gamemode gamemode); -#endif // HELAPORDO_RAYLIB_BUILD -#endif //HELAPORDO_CURSES_BUILD + void update_Gamestate(Gamestate * gmst, int current_fighters, roomClass current_roomtype, int current_room_index, int current_enemy_index, Floor * current_floor); @@ -119,24 +104,6 @@ void usage(char *progname); void log_tag(char *filename, char *header, const char *format, ...); void log_OP(turnOption_OP op); -#ifdef HELAPORDO_CURSES_BUILD -turnOP_args *init_turnOP_args(Gamestate * gmst, Fighter * actor, Path * path, - Room * room, loadInfo * load_info, Enemy * enemy, - Boss * boss, FILE * save_file, - WINDOW * notify_win, Koliseo_Temp * t_kls, - foeTurnOption_OP foe_op, skillType picked_skill); -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -turnOP_args *init_turnOP_args(Gamestate * gmst, Fighter * actor, Path * path, - Room * room, loadInfo * load_info, Enemy * enemy, - Boss * boss, FILE * save_file, - Rectangle * notification_area, Koliseo_Temp * t_kls, - foeTurnOption_OP foe_op, skillType picked_skill); -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD - saveType saveTypeFrom_string(char *s); char *stringFrom_HLP_Region_Type(HLP_Region_Type t); char *stringFrom_OP_res(OP_res r); @@ -189,4 +156,139 @@ void pickName(Fighter * player); void copy_fighter(Fighter * source, Fighter * dest); +effect_fun getStatusCounterFun(fighterStatus status); + +effect_e_fun getStatusCounterEnemyFun(fighterStatus status); + +effect_b_fun getStatusCounterBossFun(fighterStatus status); + +effect_fp_fun get_StatusCounter_FoeParty_Fun(fighterStatus status); + +boost_fun getStatBoostCounterFun(Stat s); +boost_e_fun getStatBoostCounterEnemyFun(Stat s); +boost_b_fun getStatBoostCounterBossFun(Stat s); +boost_fp_fun get_StatBoostCounter_FoeParty_Fun(Stat s); + +void set_turnboost_atk(Fighter * f, int boost); +void set_turnboost_def(Fighter * f, int boost); +void set_turnboost_vel(Fighter * f, int boost); +void set_turnboost_enr(Fighter * f, int boost); + +void set_enemy_turnboost_atk(Enemy * e, int boost); +void set_enemy_turnboost_def(Enemy * e, int boost); +void set_enemy_turnboost_vel(Enemy * e, int boost); +void set_enemy_turnboost_enr(Enemy * e, int boost); + +void set_boss_turnboost_atk(Boss * b, int boost); +void set_boss_turnboost_def(Boss * b, int boost); +void set_boss_turnboost_vel(Boss * b, int boost); +void set_boss_turnboost_enr(Boss * b, int boost); + +void set_foeparty_turnboost_atk(FoeParty * fp, int boost); +void set_foeparty_turnboost_def(FoeParty * fp, int boost); +void set_foeparty_turnboost_vel(FoeParty * fp, int boost); +void set_foeparty_turnboost_enr(FoeParty * fp, int boost); + +void resetFighterStatus(Fighter * f); + +void resetEnemyStatus(Enemy * e); + +void resetBossStatus(Boss * b); + +void setEquipPrices(int size, int *equipPrices, Equip * equips[]); +void setConsumablePrices(int size, int *consumablePrices, + Consumable ** consumables); + +void statReset(Fighter * player, int force); +void statResetBoss(Boss * b, int force); +void statResetEnemy(Enemy * e, int force); +int getBossBoost(int lvl, bossClass bclass); +int getEnemyBoost(int lvl, enemyClass eclass); + +void resetPermboosts(Fighter * f); +void applyPermboosts(Fighter * f); + +void resetArtifactsState(Fighter * f); + +void printSpawnMessage(Enemy * e, int roomIndex, int enemyIndex); +int dropConsumable(Fighter * player); +int dropArtifact(Fighter * player); + +int getConsumableQty(Fighter * f, int n); +void emptyConsumables(Fighter * player); +void emptyArtifacts(Fighter * player); +void emptyEquips(Fighter * player); +Path *randomise_path(int seed, Koliseo * kls, const char *path_to_savefile); +void printStats(Fighter * f); +void printEStats(Enemy * e); +void printConsumablesStats(Consumable * c); +void printArtifactStats(Artifact * a); + +#ifdef HELAPORDO_CURSES_BUILD +void test_game_color_pairs(WINDOW * win, int colors_per_row); +void init_Gamestate(Gamestate * gmst, clock_t start_time, countStats * stats, Wincon * wincon, + Path * path, Fighter * player, Gamemode gamemode, GameScreen* screen, bool is_localexe); +turnOP_args *init_turnOP_args(Gamestate * gmst, Fighter * actor, Path * path, + Room * room, loadInfo * load_info, Enemy * enemy, + Boss * boss, FILE * save_file, + WINDOW * notify_win, Koliseo_Temp * t_kls, + foeTurnOption_OP foe_op, skillType picked_skill); +void display_notification(WINDOW * w, char *text, int time); +void print_label(WINDOW * win, int starty, int startx, int width, char *string, + chtype color); +void setEquipSprite(Equip * e); +void printEquipStats(Equip * e); +void printQualityColor(quality q); +void dropEquip(Fighter * player, int beast, WINDOW * notify_win, Koliseo * kls); +void unlockSpecial(Fighter * f); +void printCounters(Turncounter * counters[]); +void printActivePerks(Fighter * f); +void applyStatus(WINDOW * notify_win, Fighter * f); +void applyEStatus(WINDOW * notify_win, Enemy * e); +void applyBStatus(WINDOW * notify_win, Boss * b); +void printStatusText(WINDOW * notify_win, fighterStatus status, char *subject); +int retry(void); +void getParams(int argc, char **argv, Fighter * player, Path * path, int optTot, + Koliseo * kls); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +void test_game_color_pairs(Rectangle * win, int colors_per_row); +void init_Gamestate(Gamestate * gmst, clock_t start_time, countStats * stats, Wincon * wincon, + Path * path, Fighter * player, Gamemode gamemode); +turnOP_args *init_turnOP_args(Gamestate * gmst, Fighter * actor, Path * path, + Room * room, loadInfo * load_info, Enemy * enemy, + Boss * boss, FILE * save_file, + Rectangle * notification_area, Koliseo_Temp * t_kls, + foeTurnOption_OP foe_op, skillType picked_skill); +void dropEquip(Fighter * player, int beast, Rectangle* notification_window, Koliseo * kls); +void unlockSpecial(Fighter * f); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +void death(Fighter * player, loadInfo * load_info); +void e_death(Enemy * e); +void b_death(Boss * b); + +void updateCounters(Turncounter * counters[], int isEnemy, Fighter * f, + Enemy * e); +void updateCounters_Boss(Turncounter * counters[], int isBoss, Fighter * f, + Boss * b); + +void checkremainder(Fighter * player, int xp); +void giveXp(Fighter * player, Enemy * e); +void giveXp_Boss(Fighter * player, Boss * b); +int getEnemyXpGain(Enemy * e); +int getBossXpGain(Boss * b); +void onLevelUp(Fighter * player); +int getBoost(int lvl, int luck); +void sell_all_equips(Fighter * f, Koliseo_Temp * t_kls); + +turnOption getTurnChoice(char *ch); +foeTurnOption enemyTurnPick(Enemy * e, Fighter * f); +foeTurnOption bossTurnPick(Boss * b, Fighter * f); +void quit(Fighter * p, Room * room, loadInfo * load_info, Koliseo_Temp * t_kls); +void setCounter(Turncounter * c, int turns); +void useConsumable(Fighter * f, Enemy * e, Boss * b, char *string, int isBoss); #endif diff --git a/src/rooms.c b/src/utils/rooms.c similarity index 95% rename from src/rooms.c rename to src/utils/rooms.c index 233ccc12..b7540dff 100644 --- a/src/rooms.c +++ b/src/utils/rooms.c @@ -17,6 +17,7 @@ */ #include "rooms.h" +#ifdef HELAPORDO_CURSES_BUILD /** * Takes an integer for room index and a Fighter and a Path pointers and handles the progression of the room. * It also takes a loadInfo pointer to a struct used for loading a game, and a 4D char array containing animations for all fighters, preloaded in the prep section of gameloop(). @@ -2492,6 +2493,192 @@ int handleRoom_Shop(Room *room, int roomsDone, Path *path, Fighter *f, return FIGHTRES_NO_DMG; } +/** + * Takes a Room pointer and a Fighter pointer, displays a choice for the next room and sets it at *roadFork_value. + * @see Roadfork + * @see Fighter + * @param room The pointer to current room. + * @param roadFork_value The pointer to the value for next room's class. + * @param roomsDone The total of rooms completed. + * @param path The Path pointer. + * @param f The Fighter pointer at hand. + * @return When room is exited, should return NO_DMG. + */ +int handleRoom_Roadfork(Room *room, int *roadFork_value, int roomsDone, + Path *path, Fighter *f) +{ + //Strings for turn menu choices + char choices[ROADFORK_OPTIONS_MAX + 1][80] = { + "One", + "Two" + }; + //TODO: the choices array had a '(char) NULL' value which was giving a obvious warning about pointer to integer casting. + //Was it needed as a sentinel value?? + + char msg[200]; + + for (int i = 0; i < 2; i++) { + char c[80]; + switch (room->roadfork->options[i]) { + case ROADFORK_BOSS: { + strcpy(c, "Boss Room"); + } + break; + case ROADFORK_SHOP: { + strcpy(c, "Shop Room"); + } + break; + case ROADFORK_TREASURE: { + strcpy(c, "Treasure Room"); + } + break; + case ROADFORK_ENEMIES: { + strcpy(c, "Enemies"); + } + break; + case ROADFORK_ROADFORK: { + strcpy(c, "Roadfork"); + } + break; + } + strcpy(choices[i], c); + } + sprintf(msg, "Entered Roadfork with %s and %s.\n", choices[0], choices[1]); + log_tag("debug_log.txt", "[ROADFORK]", msg); + + ITEM **my_items; + MENU *my_menu; + WINDOW *my_menu_win; + int n_choices, c; + + /* Initialize curses */ + //initscr(); + start_color(); + clear(); + refresh(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + /* Create items */ + n_choices = ARRAY_SIZE(choices); + sprintf(msg, "n_choices size was: (%i)\n", n_choices); + log_tag("debug_log.txt", "[ROADFORK]", msg); + my_items = (ITEM **) calloc(n_choices, sizeof(ITEM *)); + for (int k = 0; k < n_choices; k++) { + my_items[k] = new_item(choices[k], choices[k]); + /* Set the user pointer */ + //set_item_userptr(my_items[i]); + } + + /* Create menu */ + my_menu = new_menu((ITEM **) my_items); + + /* Set description off */ + menu_opts_off(my_menu, O_SHOWDESC); + + /* Create the window to be associated with the menu */ + my_menu_win = newwin(12, 28, 1, 1); + keypad(my_menu_win, TRUE); + + /* Set main window and sub window */ + set_menu_win(my_menu, my_menu_win); + set_menu_sub(my_menu, derwin(my_menu_win, 4, 26, 3, 2)); + set_menu_format(my_menu, 3, 1); + + /* Set menu mark to the string " > " */ + set_menu_mark(my_menu, " > "); + + char label[25]; + sprintf(label, "Road Fork"); + + /* Print a border around the main window and print a title */ + box(my_menu_win, 0, 0); + print_label(my_menu_win, 1, 0, 28, label, COLOR_PAIR(S4C_MAGENTA)); + mvwaddch(my_menu_win, 2, 0, ACS_LTEE); + mvwhline(my_menu_win, 2, 1, ACS_HLINE, 26); + mvwaddch(my_menu_win, 2, 27, ACS_RTEE); + + /* Post the menu */ + post_menu(my_menu); + wrefresh(my_menu_win); + + /* Create the items window */ + //win = newwin(22, 54, 1, 23); + //keypad(win, TRUE); + //box(win, 0, 0); + + //print_label(win, 1, 0, 54, "Option", COLOR_PAIR(6)); + //mvwaddch(win, 2, 0, ACS_LTEE); + //mvwhline(win, 2, 1, ACS_HLINE, 52); + //mvwaddch(win, 2, 53, ACS_RTEE); + + attron(COLOR_PAIR(S4C_CYAN)); + mvprintw(20, 2, "Arrows to move"); + mvprintw(21, 2, "(q to Exit)"); + attroff(COLOR_PAIR(S4C_CYAN)); + refresh(); + + int end_room = 0; + int check = -1; + + while (!end_room && (c = wgetch(my_menu_win)) != KEY_F(1)) { + switch (c) { + case KEY_DOWN: + menu_driver(my_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(my_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(my_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(my_menu, REQ_SCR_UPAGE); + break; + case 10: { // Enter + ITEM *cur; + + cur = current_item(my_menu); + sprintf(msg, "Picked %s.\n", item_name(cur)); + log_tag("debug_log.txt", "[ROADFORK]", msg); + if ((check = strcmp("Boss Room", item_name(cur))) == 0) { + *roadFork_value = BOSS; + end_room = 1; + } else if ((check = strcmp("Shop Room", item_name(cur)) == 0)) { + *roadFork_value = SHOP; + end_room = 1; + } else if ((check = + strcmp("Treasure Room", item_name(cur)) == 0)) { + *roadFork_value = TREASURE; + end_room = 1; + } else if ((check = strcmp("Enemies", item_name(cur)) == 0)) { + *roadFork_value = ENEMIES; + end_room = 1; + } else if ((check = strcmp("Roadfork", item_name(cur)) == 0)) { + *roadFork_value = ROADFORK; + end_room = 1; + } + pos_menu_cursor(my_menu); + refresh(); + }; + break; + } + wrefresh(my_menu_win); + } + /* Unpost and free all the memory taken up */ + unpost_menu(my_menu); + free_menu(my_menu); + for (int k = 0; k < n_choices; k++) { + free_item(my_items[k]); + } + endwin(); + + //FIXME + //Why are we relying on this? + return FIGHTRES_NO_DMG; +} + /** * Takes a WINDOW, a Chest and a Fighter pointer and opens the chest adding the contents to the fighter's bags. * Prints result to the passed window. @@ -2984,6 +3171,8 @@ int handleRoom_Treasure(Room *room, int roomsDone, Path *path, Fighter *f, return FIGHTRES_NO_DMG; } +#endif // HELAPORDO_CURSES_BUILD + /** * Takes one Room pointer of class HOME and initialises all the fields. * @see roomClass diff --git a/src/rooms.h b/src/utils/rooms.h similarity index 84% rename from src/rooms.h rename to src/utils/rooms.h index 0e0b6411..0a1e117b 100644 --- a/src/rooms.h +++ b/src/utils/rooms.h @@ -16,9 +16,10 @@ along with this program. If not, see . */ -#ifndef GAME_ROOMS_H -#define GAME_ROOMS_H -#include "helapordo.h" +#ifndef GAME_ROOMS_H_ +#define GAME_ROOMS_H_ +#include "artifacts.h" +#include "turn_op.h" void initRoom(Room * r, Fighter * f, int index, roomClass type, int enemyTotal, loadInfo * load_info, Koliseo_Temp * t_kls); @@ -33,6 +34,7 @@ void initRoom_Treasure(Room * r, int roomIndex, Fighter * f, void initRoom_Roadfork(Room * r, int roomIndex, Fighter * f, Koliseo_Temp * t_kls); +#ifdef HELAPORDO_CURSES_BUILD int handleRoom_Home(Gamestate * gamestate, Room * room, int index, Path * p, Fighter * player, loadInfo * load_info, char fighter_sprites[CLASSESMAX + @@ -59,4 +61,15 @@ int handleRoom_Treasure(Room * room, int roomsDone, Path * path, Fighter * f, int handleRoom_Roadfork(Room * room, int *roadFork_value, int roomsDone, Path * path, Fighter * f); -#endif +void open_chest(WINDOW * w, Chest * c, Fighter * f, Koliseo * kls, + Koliseo_Temp * t_kls); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +void open_chest(Rectangle * notification_area, Chest * c, Fighter * f, Koliseo * kls, + Koliseo_Temp * t_kls); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +#endif // GAME_ROOMS_H_ diff --git a/src/utils/saves.c b/src/utils/saves.c new file mode 100644 index 00000000..eccdc7d2 --- /dev/null +++ b/src/utils/saves.c @@ -0,0 +1,3423 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "saves.h" + +/** + * Takes a FILE pointer from which the gamestate will be loaded. + * Gets the pointers to relevant game structures, sets all the values by reading the save file. + * Fighter, Path pointers, and an integer for room index. + * Saves the state of the game. + * @see Fighter + * @see Path + * @see gameloop() + * @param file The FILE pointer to load from. + * @param f The player struct. + * @param p The path struct. + * @param roomIndex Current room index. + * @param done_loading Flag to check if loading ended. + * @param kls The Koliseo used for allocations. + * @return The OP_res corresponding to loading result. + */ +OP_res handleLoadgame_Home(FILE *file, Fighter *f, Path *p, int *roomIndex, + int *done_loading, Koliseo *kls) +{ + + //printf("\nLoading game...\n"); + log_tag("debug_log.txt", "[LOAD]", "Starting loading from text file."); + +// FILE* file = fopen("save.txt", "r"); + if (file == NULL) { + printf("Error with file while trying to load!\n"); + return OP_CANNOT_OPEN_SAVEFILE; + } + char buf[500]; + char comment[300]; + int num_value = -1; + const char * version = HELAPORDO_SAVEFILE_VERSION; + + int scanres = -1; + /* File version scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + int check = -1; + if (!((check = strcmp(buf, version)) == 0)) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "Failed save format version check. Was [%s]. Quitting.\n", buf); + fprintf(stderr, "[ERROR] File version mismatch on load.\n"); + exit(EXIT_FAILURE); + }; + log_tag("debug_log.txt", "[LOAD]", "Loaded save format version: (%s).", + buf); + + /* Save type scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + check = -1; + if (!((check = strcmp(buf, stringFrom_saveType(HOME_SAVE))) == 0)) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "handleLoadGame_Home(): Failed save type check, was [%s]. Quitting.", + buf); + fprintf(stderr, "[ERROR] Save type version mismatch on load.\n"); + exit(EXIT_FAILURE); + }; + log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s).", buf); + + /* Gamemode scanning */ + scanres = fscanf(file, "%200[^#]# %s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + GAMEMODE = num_value; + + /* Fighter scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + strcpy(f->name, buf); + + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int i = 0; i < CLASSESMAX + 1; i++) { + int check = -1; + if ((check = strcmp(buf, stringFromClass(i))) == 0) { + f->class = i; + break; + } + }; + + //We have to reload the specials callbacks after setting fighter class + setSpecials(f, kls); + + //HP + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->hp = num_value; + //TotalHP + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->totalhp = num_value; + //Atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->atk = num_value; + //Def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + sscanf(buf, "%3i", &num_value); + f->def = num_value; + //Vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->vel = num_value; + //Level + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->level = num_value; + //Luck + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->luck = num_value; + //Totxp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->totalxp = num_value; + //Current level xp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->currentlevelxp = num_value; + //Totallevelxp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->totallevelxp = num_value; + //Energy + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->energy = num_value; + //Totenergy + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->totalenergy = num_value; + //Stamina + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stamina = num_value; + //Totstamina + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->totalstamina = num_value; + //Coin balance + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->balance = num_value; + + //Status + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int i = 0; i < STATUSMAX + 1; i++) { + int check = -1; + if ((check = strcmp(buf, stringFromStatus(i))) == 0) { + f->status = i; + break; + } + }; + //Specials + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < SPECIALSMAX + 1; i++) { + //Enabled flag + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->specials[i]->enabled = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Skills + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { + //Enabled flag + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->skills[i]->enabled = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Fighter counters + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < COUNTERSMAX + 1; i++) { + //innerValue + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->counters[i]->innerValue = num_value; + //count + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->counters[i]->count = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + + //turnboost_atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_atk = num_value; + //turnboost_def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_def = num_value; + //turnboost_vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_vel = num_value; + //turnboost_enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_enr = num_value; + + //equipsbag occupied slots + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipsBagOccupiedSlots = num_value; + //equipsbag earliest slot + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->earliestBagSlot = num_value; + + //Equipsbag + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { + log_tag("debug_log.txt", "[DEBUG]", + "Loadgame_Home(): Prepping Equip (%i)", i); + kls_log(kls, "DEBUG", "Loadgame_Home(): Prepping Equip (%i)", i); + Equip *eq = KLS_PUSH_TYPED(kls, Equip, HR_Equip, "Equip", "Equip"); + scanres = fscanf(file, "%200s\n", buf); //Skip equip_i heading + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + //equipClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int j = 0; j < EQUIPSMAX + 1; j++) { + int check = -1; + if ((check = strcmp(buf, stringFromEquips(j))) == 0) { + eq->class = j; + break; + } + }; + //equipzoneClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int j = 0; j < EQUIPZONES + 1; j++) { + int check = -1; + if ((check = strcmp(buf, stringFromEquipzones(j))) == 0) { + eq->type = j; + break; + } + }; + + //qty + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->qty = num_value; + //equipped + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->equipped = num_value; + //level + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->level = num_value; + //atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->atk = num_value; + //def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->def = num_value; + //vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->vel = num_value; + //enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->enr = num_value; + //bonus + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->bonus = num_value; + //perksCount + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->perksCount = num_value; + //cost + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + eq->cost = num_value; + + //Quality + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int j = 0; j < QUALITIESMAX + 1; j++) { + int check = -1; + if ((check = strcmp(buf, stringFromQuality(j))) == 0) { + eq->qual = j; + break; + } + }; + + //perks + scanres = fscanf(file, "%200s\n", buf); //Skip perks heading + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int j = 0; j < eq->perksCount; j++) { + log_tag("debug_log.txt", "[DEBUG]", + "Loadgame_Home(): Prepping Perk (%i)", j); + kls_log(kls, "DEBUG", "Loadgame_Home(): Prepping Perk (%i)", j); + Perk *pk = + (Perk *) KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); + //perkClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + pk->class = num_value; + char *name = nameStringFromPerk(pk->class); + char *desc = descStringFromPerk(pk->class); + //p->name = name; //(char*)malloc(sizeof(name)); + strcpy(pk->name, name); + //p->desc = (char*)malloc(sizeof(desc)); + strcpy(pk->desc, desc); + pk->innerValue = 0; + eq->perks[j] = pk; + + //innerValue + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + pk->innerValue = num_value; + } + + scanres = fscanf(file, "%200s\n", buf); //Skip closing perks breacket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + scanres = fscanf(file, "%200s\n", buf); //Skip closing current equip bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Get the base item and copy the stats to the loading item + Equip *base = &equips[eq->class]; + setEquipSprite(eq); + strcpy(eq->name, base->name); + strcpy(eq->desc, base->desc); + + if (eq->equipped) { + Equipslot *slot = f->equipslots[eq->type]; + //We equip the item + slot->item = eq; + applyEquipPerks(eq, f); + slot->active = 1; + } + f->equipsBag[i] = eq; + } //End for Equips bag + + scanres = fscanf(file, "%200s\n", buf); //Skip closing equipsbag bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + //Fighter boosts + //permboost_atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_atk = num_value; + //permboost_def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_def = num_value; + //permboost_vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_vel = num_value; + //permboost_enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_enr = num_value; + //equipboost_atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_atk = num_value; + //equipboost_def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_def = num_value; + //equipboost_vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_vel = num_value; + //equipboost_enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_enr = num_value; + + //Stats + scanres = fscanf(file, "%200s\n", buf); //Skip Stats bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //enemieskilled + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->enemieskilled = num_value; + //consumablesfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->consumablesfound = num_value; + //equipsfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->equipsfound = num_value; + //artifactsfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->artifactsfound = num_value; + //crits + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->criticalhits = num_value; + //roomsdone + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->roomscompleted = num_value; + //specials unlocked + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->specialsunlocked = num_value; + //coinsfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->stats->coinsfound = num_value; + //bosseskilled + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->bosseskilled = num_value; + + //Unique boss kills + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->unique_bosseskilled = num_value; + + scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int boss_index = 0; boss_index < BOSSCLASSESMAX + 1; boss_index++) { + //boss %i was killed + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->killed_bosses[boss_index] = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //keysfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->keysfound = num_value; + scanres = fscanf(file, "%200s\n", buf); //Skip Stats closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + scanres = fscanf(file, "%200s\n", buf); //Skip Fighter closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Fighter."); + + //Path + scanres = fscanf(file, "%200s\n", buf); //Skip Path bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Luck + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->luck = num_value; + //Length + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->length = num_value; + //Prize + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + p->prize = num_value; + //loreCounter + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->loreCounter = num_value; + + //Wincon + scanres = fscanf(file, "%200s\n", buf); //Skip Wincon bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //winconClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->win_condition->class = num_value; + //current_val + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->win_condition->current_val = num_value; + //target_val + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->win_condition->target_val = num_value; + + scanres = fscanf(file, "%200s\n", buf); //Skip Wincon closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Wincon."); + + scanres = fscanf(file, "%200s\n", buf); //Skip Path closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Path."); + + //roomindex + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + *roomIndex = num_value; + + log_tag("debug_log.txt", "[LOAD]", "Done loading room info."); + + //Consumables bag + scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + initConsumableBag(f, kls); + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + Consumable *cn = (Consumable *) f->consumablesBag[i]; + //qty + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + cn->qty = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Consumable bag."); + + //Artifacts bag + scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + Artifact *a = f->artifactsBag[i]; + //qty + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + a->qty = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadgame_Home(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Artifacts bag."); + + fclose(file); + log_tag("debug_log.txt", "[LOAD]", "Done loading from text file!"); + //printf("[INFO] Done loading!\n"); + //TODO: + //Notification win for load status + + return OP_OK; +} + +/** + * Takes a FILE pointer from which the gamestate will be loaded. + * Gets the pointers to relevant game structures, sets all the values by reading the save file. + * Fighter, Path and Enemy pointers, and integers for room / path progression indexes. + * Saves the state of the game. + * @see Fighter + * @see Enemy + * @see Path + * @see gameloop() + * @param file The FILE pointer to load from. + * @param f The player struct. + * @param p The path struct. + * @param e The current enemy struct. + * @param enemyIndex Index in current room for current enemy. + * @param roomTotalEnemies Total enemies for current room. + * @param roomIndex Current room index. + * @param total_foes Total foes in current room. + * @param done_loading Flag to check if loading ended. + * @param kls The Koliseo used for allocations. + * @return The OP_res corresponding to loading result. + */ +OP_res handleLoadgame_Enemies(FILE *file, Fighter *f, Path *p, Enemy *e, + int *enemyIndex, int *roomTotalEnemies, + int *roomIndex, int *total_foes, + int *done_loading, Koliseo *kls) +{ + + //printf("\nLoading game...\n"); + log_tag("debug_log.txt", "[LOAD]", "Starting loading from text file."); + +// FILE* file = fopen("save.txt", "r"); + if (file == NULL) { + printf("Error with file while trying to load!\n"); + return OP_CANNOT_OPEN_SAVEFILE; + } + char buf[500]; + char comment[300]; + int num_value = -1; + const char version[] = HELAPORDO_SAVEFILE_VERSION; + + int scanres = -1; + /* File version scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + int check = -1; + if (!((check = strcmp(buf, version)) == 0)) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "Failed save format version check. Was [%s]. Quitting.\n", buf); + fprintf(stderr, "[ERROR] File version mismatch on load.\n"); + exit(EXIT_FAILURE); + }; + log_tag("debug_log.txt", "[LOAD]", "Loaded save format version: (%s).\n", + buf); + + /* Save type scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + check = -1; + if (!((check = strcmp(buf, stringFrom_saveType(ENEMIES_SAVE))) == 0)) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "handleLoadGame_Enemies(): Failed save type check, was [%s]. Quitting.\n", + buf); + fprintf(stderr, "[ERROR] Save type version mismatch on load.\n"); + exit(EXIT_FAILURE); + }; + log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s).\n", buf); + + /* Gamemode scanning */ + scanres = fscanf(file, "%200[^#]# %s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.\n", comment, buf); + sscanf(buf, "%3i", &num_value); + GAMEMODE = num_value; + + /* Fighter scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + strcpy(f->name, buf); + + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int i = 0; i < CLASSESMAX + 1; i++) { + int check = -1; + if ((check = strcmp(buf, stringFromClass(i))) == 0) { + f->class = i; + break; + } + }; + + //We have to reload the specials callbacks after setting fighter class + setSpecials(f, kls); + + //HP + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->hp = num_value; + //TotalHP + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->totalhp = num_value; + //Atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->atk = num_value; + //Def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + sscanf(buf, "%3i", &num_value); + f->def = num_value; + //Vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->vel = num_value; + //Level + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->level = num_value; + //Luck + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->luck = num_value; + //Totxp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->totalxp = num_value; + //Current level xp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->currentlevelxp = num_value; + //Totallevelxp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->totallevelxp = num_value; + //Energy + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->energy = num_value; + //Totenergy + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->totalenergy = num_value; + //Stamina + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stamina = num_value; + //Totstamina + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->totalstamina = num_value; + //Coin balance + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->balance = num_value; + + //Status + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int i = 0; i < STATUSMAX + 1; i++) { + int check = -1; + if ((check = strcmp(buf, stringFromStatus(i))) == 0) { + f->status = i; + break; + } + }; + //Specials + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < SPECIALSMAX + 1; i++) { + //Enabled flag + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->specials[i]->enabled = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Skills + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { + //Enabled flag + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->skills[i]->enabled = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Fighter counters + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < COUNTERSMAX + 1; i++) { + //innerValue + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->counters[i]->innerValue = num_value; + //count + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->counters[i]->count = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + + //turnboost_atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_atk = num_value; + //turnboost_def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_def = num_value; + //turnboost_vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_vel = num_value; + //turnboost_enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->turnboost_enr = num_value; + + //equipsbag occupied slots + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipsBagOccupiedSlots = num_value; + //equipsbag earliest slot + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->earliestBagSlot = num_value; + + //Equipsbag + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { + log_tag("debug_log.txt", "[DEBUG]", + "Loadgame_Enemies(): Prepping Equip (%i)", i); + kls_log(kls, "DEBUG", "Loadgame_Enemies(): Prepping Equip (%i)", i); + Equip *eq = KLS_PUSH_TYPED(kls, Equip, HR_Equip, "Equip", "Equip"); + scanres = fscanf(file, "%200s\n", buf); //Skip equip_i heading + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + //equipClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int j = 0; j < EQUIPSMAX + 1; j++) { + int check = -1; + if ((check = strcmp(buf, stringFromEquips(j))) == 0) { + eq->class = j; + break; + } + }; + //equipzoneClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int j = 0; j < EQUIPZONES + 1; j++) { + int check = -1; + if ((check = strcmp(buf, stringFromEquipzones(j))) == 0) { + eq->type = j; + break; + } + }; + + //qty + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->qty = num_value; + //equipped + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->equipped = num_value; + //level + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->level = num_value; + //atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->atk = num_value; + //def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->def = num_value; + //vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->vel = num_value; + //enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->enr = num_value; + //bonus + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->bonus = num_value; + //perksCount + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + eq->perksCount = num_value; + //cost + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + eq->cost = num_value; + + //Quality + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int j = 0; j < QUALITIESMAX + 1; j++) { + int check = -1; + if ((check = strcmp(buf, stringFromQuality(j))) == 0) { + eq->qual = j; + break; + } + }; + + //perks + scanres = fscanf(file, "%200s\n", buf); //Skip perks heading + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int j = 0; j < eq->perksCount; j++) { + log_tag("debug_log.txt", "[DEBUG]", + "Loadgame_Enemies(): Prepping Perk (%i/%i)", j, + eq->perksCount); + kls_log(kls, "DEBUG", "Loadgame_Enemies(): Prepping Perk (%i/%i)", + j, eq->perksCount); + Perk *pk = KLS_PUSH_TYPED(kls, Perk, HR_Perk, "Perk", "Perk"); + //perkClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + pk->class = num_value; + char *name = nameStringFromPerk(pk->class); + char *desc = descStringFromPerk(pk->class); + //p->name = name; //(char*)malloc(sizeof(name)); + strcpy(pk->name, name); + //p->desc = (char*)malloc(sizeof(desc)); + strcpy(pk->desc, desc); + pk->innerValue = 0; + eq->perks[j] = pk; + + //innerValue + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + pk->innerValue = num_value; + } + + scanres = fscanf(file, "%200s\n", buf); //Skip closing perks breacket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + scanres = fscanf(file, "%200s\n", buf); //Skip closing current equip bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Get the base item and copy the stats to the loading item + Equip *base = &equips[eq->class]; + setEquipSprite(eq); + strcpy(eq->name, base->name); + strcpy(eq->desc, base->desc); + + if (eq->equipped) { + Equipslot *slot = f->equipslots[eq->type]; + //We equip the item + slot->item = eq; + applyEquipPerks(eq, f); + slot->active = 1; + } + f->equipsBag[i] = eq; + } //End for Equips bag + + scanres = fscanf(file, "%200s\n", buf); //Skip closing equipsbag bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + //Fighter boosts + //permboost_atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_atk = num_value; + //permboost_def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_def = num_value; + //permboost_vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_vel = num_value; + //permboost_enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->permboost_enr = num_value; + //equipboost_atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_atk = num_value; + //equipboost_def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_def = num_value; + //equipboost_vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_vel = num_value; + //equipboost_enr + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->equipboost_enr = num_value; + + //Stats + scanres = fscanf(file, "%200s\n", buf); //Skip Stats bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //enemieskilled + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->enemieskilled = num_value; + //consumablesfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->consumablesfound = num_value; + //equipsfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->equipsfound = num_value; + //artifactsfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->artifactsfound = num_value; + //crits + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->criticalhits = num_value; + //roomsdone + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->roomscompleted = num_value; + //specials unlocked + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->specialsunlocked = num_value; + //coinsfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + f->stats->coinsfound = num_value; + //bosseskilled + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->bosseskilled = num_value; + + //Unique boss kills + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->unique_bosseskilled = num_value; + + scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int boss_index = 0; boss_index < BOSSCLASSESMAX + 1; boss_index++) { + //boss %i was killed + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->killed_bosses[boss_index] = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip unique bosses closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //keysfound + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + f->stats->keysfound = num_value; + scanres = fscanf(file, "%200s\n", buf); //Skip Stats closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + scanres = fscanf(file, "%200s\n", buf); //Skip Fighter closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Fighter."); + + //Current enemy + scanres = fscanf(file, "%200s\n", buf); //Skip Enemy bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Enemy class + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int i = 0; i < ENEMYCLASSESMAX + 1; i++) { + int check = -1; + if ((check = strcmp(buf, stringFromEClass(i))) == 0) { + e->class = i; + break; + }; + } + //We have to reload the sprite after setting enemy class + setEnemySprite(e); + + //hp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->hp = num_value; + //totalhp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->totalhp = num_value; + //atk + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->atk = num_value; + //def + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->def = num_value; + //vel + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->vel = num_value; + //level + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->level = num_value; + //xp + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + e->xp = num_value; + //energy + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->energy = num_value; + //totalenergy + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->totalenergy = num_value; + //Stamina + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->stamina = num_value; + //Totstamina + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->totalstamina = num_value; + //beast value + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->beast = num_value; + //prize + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->prize = num_value; + + //status + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + for (int i = 0; i < STATUSMAX + 1; i++) { + int check = -1; + if ((check = strcmp(buf, stringFromStatus(i))) == 0) { + e->status = i; + break; + } + }; + + //Skills + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < ENEMY_SKILL_SLOTS; i++) { + //Enabled flag + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->skills[i]->enabled = num_value; + } + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Enemy counters + scanres = fscanf(file, "%200s\n", buf); //Skip Enemy counters bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < COUNTERSMAX + 1; i++) { + //innerValue + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->counters[i]->innerValue = num_value; + //count + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + e->counters[i]->count = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip Enemy counters closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + scanres = fscanf(file, "%200s\n", buf); //Skip Enemy closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading current Enemy."); + + //Path + scanres = fscanf(file, "%200s\n", buf); //Skip Path bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //Luck + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->luck = num_value; + //Length + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->length = num_value; + //Prize + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + p->prize = num_value; + //loreCounter + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->loreCounter = num_value; + + //Wincon + scanres = fscanf(file, "%200s\n", buf); //Skip Wincon bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + //winconClass + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->win_condition->class = num_value; + //current_val + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->win_condition->current_val = num_value; + //target_val + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + p->win_condition->target_val = num_value; + + scanres = fscanf(file, "%200s\n", buf); //Skip Wincon closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Wincon."); + + scanres = fscanf(file, "%200s\n", buf); //Skip Path closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Path."); + + //enemyindex + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + *enemyIndex = num_value; + //roomtotalenemies + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + *roomTotalEnemies = num_value; + *total_foes = num_value; + log_tag("debug_log.txt", "[LOAD]", + "Also Loaded %s: %s. Additional assignment to pointer for foes, see handleLoadGame(_Enemies)", + "total_foes", buf); + //roomindex + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%8i", &num_value); + *roomIndex = num_value; + + log_tag("debug_log.txt", "[LOAD]", "Done loading room info."); + + //Consumables bag + scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + initConsumableBag(f, kls); + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + Consumable *cn = (Consumable *) f->consumablesBag[i]; + //qty + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + cn->qty = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip Consumablebag closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Consumable bag."); + + //Artifacts bag + scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + Artifact *a = f->artifactsBag[i]; + //qty + scanres = fscanf(file, "%200[^#]# %200s\n", buf, comment); + if (scanres != 2) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 2, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Loaded %s: %s.", comment, buf); + sscanf(buf, "%3i", &num_value); + a->qty = num_value; + } + scanres = fscanf(file, "%200s\n", buf); //Skip Artifactsbag closing bracket + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in handleLoadGame_Enemies(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while loading game."); + exit(EXIT_FAILURE); + } + + log_tag("debug_log.txt", "[LOAD]", "Done loading Artifacts bag."); + + fclose(file); + log_tag("debug_log.txt", "[LOAD]", "Done loading from text file!"); + //printf("[INFO] Done loading!\n"); + //TODO: + //Notification win for load status + + return OP_OK; +} + +/** + * Takes a FILE pointer to which the gamestate from the passed args will be saved. + * Fighter, Path and an integer for room index. + * Saves the state of the game. + * @see Fighter + * @see Path + * @see gameloop() + * @param file The FILE pointer struct to write to. + * @param f The player struct. + * @param p The path struct. + * @param roomIndex Current room index. + */ +OP_res handleSave_Home(FILE *file, Fighter *f, Path *p, int roomIndex) +{ + const char* version = HELAPORDO_SAVEFILE_VERSION; + //FILE *file = fopen("save.txt", "w"); + log_tag("debug_log.txt", "[DEBUG]", "Saving with version %s", version); + + if (file == NULL) { + fprintf(stderr, "[ERROR] Can't open save file!\n"); + return OP_CANNOT_OPEN_SAVEFILE; + } + + /* File version printing */ + fprintf(file, "%s\n", version); + + /* Save type printing */ + fprintf(file, "%s\n", stringFrom_saveType(HOME_SAVE)); + + /* Gamemode printing */ + fprintf(file, "%i# gamemode\n", GAMEMODE); + + /* Fighter printing */ + fprintf(file, "Fighter{\n"); + fprintf(file, "%s# name\n", f->name); + fprintf(file, "%s# class\n", stringFromClass(f->class)); + fprintf(file, "%i# hp\n", f->hp); + fprintf(file, "%i# totalhp\n", f->totalhp); + fprintf(file, "%i# atk\n", f->atk); + fprintf(file, "%i# def\n", f->def); + fprintf(file, "%i# vel\n", f->vel); + fprintf(file, "%i# level\n", f->level); + fprintf(file, "%i# luck\n", f->luck); + fprintf(file, "%i# totxp\n", f->totalxp); + fprintf(file, "%i# currlevxp\n", f->currentlevelxp); + fprintf(file, "%i# totlevxp\n", f->totallevelxp); + fprintf(file, "%i# energy\n", f->energy); + fprintf(file, "%i# totenergy\n", f->totalenergy); + fprintf(file, "%i# stamina\n", f->stamina); + fprintf(file, "%i# totstamina\n", f->totalstamina); + fprintf(file, "%i# coinbalance\n", f->balance); + fprintf(file, "%s# status\n", stringFromStatus(f->status)); + fprintf(file, " Specials{\n"); + for (int i = 0; i < SPECIALSMAX + 1; i++) { + fprintf(file, "%i# %i_special_enabled_flag\n", f->specials[i]->enabled, + i); + } + fprintf(file, " },\n"); + fprintf(file, " Skills{\n"); + for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { + fprintf(file, "%i# %i_skill_enabled_flag\n", f->skills[i]->enabled, + i); + } + fprintf(file, " },\n"); + fprintf(file, " Counters{\n"); + for (int i = 0; i < COUNTERSMAX + 1; i++) { + fprintf(file, "%i# innervalue\n", f->counters[i]->innerValue); + fprintf(file, "%i# count\n", f->counters[i]->count); + } + fprintf(file, " },\n"); + fprintf(file, "%i# tb_atk\n", f->turnboost_atk); + fprintf(file, "%i# tb_def\n", f->turnboost_def); + fprintf(file, "%i# tb_vel\n", f->turnboost_vel); + fprintf(file, "%i# tb_enr\n", f->turnboost_enr); + fprintf(file, "%i# eqpbag_occupied_slots\n", f->equipsBagOccupiedSlots); + fprintf(file, "%i# earliestbagslot\n", f->earliestBagSlot); + fprintf(file, " EquipsBag{\n"); + for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { + Equip *eq = f->equipsBag[i]; + fprintf(file, " Equip_%i{\n", i); + + fprintf(file, "%s# equipclass\n", stringFromEquips(eq->class)); + fprintf(file, "%s# equipzone\n", stringFromEquipzones(eq->type)); + fprintf(file, "%i# qty\n", eq->qty); + fprintf(file, "%i# equipped\n", eq->equipped); + fprintf(file, "%i# lvl\n", eq->level); + fprintf(file, "%i# atk\n", eq->atk); + fprintf(file, "%i# def\n", eq->def); + fprintf(file, "%i# vel\n", eq->vel); + fprintf(file, "%i# enr\n", eq->enr); + fprintf(file, "%i# bonus\n", eq->bonus); + fprintf(file, "%i# perkscount\n", eq->perksCount); + fprintf(file, "%i# cost\n", eq->cost); + fprintf(file, "%s# quality\n", stringFromQuality(eq->type)); + fprintf(file, " Perks{\n"); + for (int j = 0; j < eq->perksCount; j++) { + Perk *pk = eq->perks[j]; + fprintf(file, "%i# class\n", pk->class); + fprintf(file, "%i# innervalue\n", pk->innerValue); + } + fprintf(file, " }\n"); + fprintf(file, " }\n"); + } + fprintf(file, " }\n"); + fprintf(file, "%i# pbst_atk\n", f->permboost_atk); + fprintf(file, "%i# pbst_def\n", f->permboost_def); + fprintf(file, "%i# pbst_vel\n", f->permboost_vel); + fprintf(file, "%i# pbst_enr\n", f->permboost_enr); + fprintf(file, "%i# ebst_atk\n", f->equipboost_atk); + fprintf(file, "%i# ebst_atk\n", f->equipboost_def); + fprintf(file, "%i# ebst_atk\n", f->equipboost_vel); + fprintf(file, "%i# ebst_atk\n", f->equipboost_enr); + fprintf(file, " Stats{\n"); + fprintf(file, "%i# enemieskilled\n", f->stats->enemieskilled); + fprintf(file, "%i# consumablesfound\n", f->stats->consumablesfound); + fprintf(file, "%i# equipsfound\n", f->stats->equipsfound); + fprintf(file, "%i# artifactsfound\n", f->stats->artifactsfound); + fprintf(file, "%i# crits\n", f->stats->criticalhits); + fprintf(file, "%i# roomsdone\n", f->stats->roomscompleted); + fprintf(file, "%i# specialsunlocked\n", f->stats->specialsunlocked); + fprintf(file, "%i# coinsfound\n", f->stats->coinsfound); + fprintf(file, "%i# bosseskilled\n", f->stats->bosseskilled); + fprintf(file, "%i# uniquebosseskilled\n", f->stats->unique_bosseskilled); + fprintf(file, " Bosses_killed{\n"); + for (int b_i = 0; b_i < BOSSCLASSESMAX + 1; b_i++) { + fprintf(file, "%i# boss_%iwas_%s_killed\n", + f->stats->killed_bosses[b_i], b_i, + f->stats->killed_bosses[b_i] ? "" : "not"); + } + fprintf(file, " },\n"); + fprintf(file, "%i# keysfound\n", f->stats->keysfound); + fprintf(file, " },\n"); + fprintf(file, "},\n"); + + /* Path and current room indexes printing */ + fprintf(file, "Path{\n"); + fprintf(file, "%i# luck\n", p->luck); + fprintf(file, "%i# length\n", p->length); + fprintf(file, "%i# prize\n", p->prize); + fprintf(file, "%i# lorecounter\n", (p->loreCounter) - 1); //We want to see the last message again when the game is loaded. This might need investigation. TODO + fprintf(file, " Wincon{\n"); + fprintf(file, "%i# winconclass\n", p->win_condition->class); + fprintf(file, "%i# current_val\n", p->win_condition->current_val); + fprintf(file, "%i# target_val\n", p->win_condition->target_val); + fprintf(file, " },\n"); + fprintf(file, "},\n"); + fprintf(file, "%i# roomindex\n", roomIndex); + + /* Consumables bag printing */ + fprintf(file, "ConsumableBag{\n"); + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + Consumable *cn = (Consumable *) f->consumablesBag[i]; + fprintf(file, "%i# qty_for_consumable_%i\n", cn->qty, i); + } + fprintf(file, "},\n"); + + /* Artifacts bag printing */ + fprintf(file, "ArtifactsBag{\n"); + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + Artifact *a = f->artifactsBag[i]; + fprintf(file, "%i# qty_for_artifact_%i\n", a->qty, i); + } + fprintf(file, "},\n"); + + log_tag("debug_log.txt", "[DEBUG]", "Done saving"); + + return OP_OK; +} + +/** + * Takes a FILE pointer to which the gamestate from the passed args will be saved. + * Fighter, Path and Enemy pointers, and integers for room / path progression indexes. + * Saves the state of the game. + * @see Fighter + * @see Enemy + * @see Path + * @see room() + * @see gameloop() + * @param file The FILE pointer struct to write to. + * @param f The player struct. + * @param p The path struct. + * @param e The current enemy struct. + * @param enemyIndex Index in current room for current enemy. + * @param roomTotalEnemies Total enemies for current room. + * @param roomIndex Current room index. + */ +OP_res handleSave_Enemies(FILE *file, Fighter *f, Path *p, Enemy *e, + int enemyIndex, int roomTotalEnemies, int roomIndex) +{ + const char * version = HELAPORDO_SAVEFILE_VERSION; + //FILE *file = fopen("save.txt", "w"); + log_tag("debug_log.txt", "[DEBUG]", "Saving with version %s", version); + + if (file == NULL) { + fprintf(stderr, "[ERROR] Can't open save file!\n"); + return OP_CANNOT_OPEN_SAVEFILE; + } + + /* File version printing */ + fprintf(file, "%s\n", version); + + /* Save type printing */ + fprintf(file, "%s\n", stringFrom_saveType(ENEMIES_SAVE)); + + /* Gamemode printing */ + fprintf(file, "%i# gamemode\n", GAMEMODE); + + /* Fighter printing */ + fprintf(file, "Fighter{\n"); + fprintf(file, "%s# name\n", f->name); + fprintf(file, "%s# class\n", stringFromClass(f->class)); + fprintf(file, "%i# hp\n", f->hp); + fprintf(file, "%i# totalhp\n", f->totalhp); + fprintf(file, "%i# atk\n", f->atk); + fprintf(file, "%i# def\n", f->def); + fprintf(file, "%i# vel\n", f->vel); + fprintf(file, "%i# level\n", f->level); + fprintf(file, "%i# luck\n", f->luck); + fprintf(file, "%i# totxp\n", f->totalxp); + fprintf(file, "%i# currlevxp\n", f->currentlevelxp); + fprintf(file, "%i# totlevxp\n", f->totallevelxp); + fprintf(file, "%i# energy\n", f->energy); + fprintf(file, "%i# totenergy\n", f->totalenergy); + fprintf(file, "%i# stamina\n", f->stamina); + fprintf(file, "%i# totstamina\n", f->totalstamina); + fprintf(file, "%i# coinbalance\n", f->balance); + fprintf(file, "%s# status\n", stringFromStatus(f->status)); + fprintf(file, " Specials{\n"); + for (int i = 0; i < SPECIALSMAX + 1; i++) { + fprintf(file, "%i# %i_special_enabled_flag\n", f->specials[i]->enabled, + i); + } + fprintf(file, " },\n"); + fprintf(file, " Skills{\n"); + for (int i = 0; i < FIGHTER_SKILL_SLOTS; i++) { + fprintf(file, "%i# %i_skill_enabled_flag\n", f->skills[i]->enabled, + i); + } + fprintf(file, " },\n"); + fprintf(file, " Counters{\n"); + for (int i = 0; i < COUNTERSMAX + 1; i++) { + fprintf(file, "%i# innervalue\n", f->counters[i]->innerValue); + fprintf(file, "%i# count\n", f->counters[i]->count); + } + fprintf(file, " },\n"); + fprintf(file, "%i# tb_atk\n", f->turnboost_atk); + fprintf(file, "%i# tb_def\n", f->turnboost_def); + fprintf(file, "%i# tb_vel\n", f->turnboost_vel); + fprintf(file, "%i# tb_enr\n", f->turnboost_enr); + fprintf(file, "%i# eqpbag_occupied_slots\n", f->equipsBagOccupiedSlots); + fprintf(file, "%i# earliestbagslot\n", f->earliestBagSlot); + fprintf(file, " EquipsBag{\n"); + for (int i = 0; i < f->equipsBagOccupiedSlots; i++) { + Equip *eq = f->equipsBag[i]; + fprintf(file, " Equip_%i{\n", i); + + fprintf(file, "%s# equipclass\n", stringFromEquips(eq->class)); + fprintf(file, "%s# equipzone\n", stringFromEquipzones(eq->type)); + fprintf(file, "%i# qty\n", eq->qty); + fprintf(file, "%i# equipped\n", eq->equipped); + fprintf(file, "%i# lvl\n", eq->level); + fprintf(file, "%i# atk\n", eq->atk); + fprintf(file, "%i# def\n", eq->def); + fprintf(file, "%i# vel\n", eq->vel); + fprintf(file, "%i# enr\n", eq->enr); + fprintf(file, "%i# bonus\n", eq->bonus); + fprintf(file, "%i# perkscount\n", eq->perksCount); + fprintf(file, "%i# cost\n", eq->cost); + fprintf(file, "%s# quality\n", stringFromQuality(eq->type)); + fprintf(file, " Perks{\n"); + for (int j = 0; j < eq->perksCount; j++) { + Perk *pk = eq->perks[j]; + fprintf(file, "%i# class\n", pk->class); + fprintf(file, "%i# innervalue\n", pk->innerValue); + } + fprintf(file, " }\n"); + fprintf(file, " }\n"); + } + fprintf(file, " }\n"); + fprintf(file, "%i# pbst_atk\n", f->permboost_atk); + fprintf(file, "%i# pbst_def\n", f->permboost_def); + fprintf(file, "%i# pbst_vel\n", f->permboost_vel); + fprintf(file, "%i# pbst_enr\n", f->permboost_enr); + fprintf(file, "%i# ebst_atk\n", f->equipboost_atk); + fprintf(file, "%i# ebst_atk\n", f->equipboost_def); + fprintf(file, "%i# ebst_atk\n", f->equipboost_vel); + fprintf(file, "%i# ebst_atk\n", f->equipboost_enr); + fprintf(file, " Stats{\n"); + fprintf(file, "%i# enemieskilled\n", f->stats->enemieskilled); + fprintf(file, "%i# consumablesfound\n", f->stats->consumablesfound); + fprintf(file, "%i# equipsfound\n", f->stats->equipsfound); + fprintf(file, "%i# artifactsfound\n", f->stats->artifactsfound); + fprintf(file, "%i# crits\n", f->stats->criticalhits); + fprintf(file, "%i# roomsdone\n", f->stats->roomscompleted); + fprintf(file, "%i# specialsunlocked\n", f->stats->specialsunlocked); + fprintf(file, "%i# coinsfound\n", f->stats->coinsfound); + fprintf(file, "%i# bosseskilled\n", f->stats->bosseskilled); + fprintf(file, "%i# uniquebosseskilled\n", f->stats->unique_bosseskilled); + fprintf(file, " Bosses_killed{\n"); + for (int b_i = 0; b_i < BOSSCLASSESMAX + 1; b_i++) { + fprintf(file, "%i# boss_%iwas_%s_killed\n", + f->stats->killed_bosses[b_i], b_i, + f->stats->killed_bosses[b_i] ? "" : "not"); + } + fprintf(file, " },\n"); + fprintf(file, "%i# keysfound\n", f->stats->keysfound); + fprintf(file, " },\n"); + fprintf(file, "},\n"); + + /* Current enemy printing */ + fprintf(file, "Enemy{\n"); + fprintf(file, "%s# class\n", stringFromEClass(e->class)); + fprintf(file, "%i# hp\n", e->hp); + fprintf(file, "%i# totalhp\n", e->totalhp); + fprintf(file, "%i# atk\n", e->atk); + fprintf(file, "%i# def\n", e->def); + fprintf(file, "%i# vel\n", e->vel); + fprintf(file, "%i# level\n", e->level); + fprintf(file, "%i# xp\n", e->xp); + fprintf(file, "%i# energy\n", e->energy); + fprintf(file, "%i# totenergy\n", e->totalenergy); + fprintf(file, "%i# stamina\n", e->stamina); + fprintf(file, "%i# totstamina\n", e->totalstamina); + fprintf(file, "%i# beast\n", e->beast); + fprintf(file, "%i# prize\n", e->prize); + fprintf(file, "%s# status\n", stringFromStatus(e->status)); + fprintf(file, " Skills{\n"); + for (int i = 0; i < ENEMY_SKILL_SLOTS; i++) { + fprintf(file, "%i# %i_skill_enabled_flag\n", e->skills[i]->enabled, + i); + } + fprintf(file, " },\n"); + fprintf(file, " Counters{\n"); + for (int i = 0; i < COUNTERSMAX + 1; i++) { + fprintf(file, "%i# innervalue\n", e->counters[i]->innerValue); + fprintf(file, "%i# count\n", e->counters[i]->count); + } + fprintf(file, " },\n"); + fprintf(file, "},\n"); + + /* Path and current room indexes printing */ + fprintf(file, "Path{\n"); + fprintf(file, "%i# luck\n", p->luck); + fprintf(file, "%i# length\n", p->length); + fprintf(file, "%i# prize\n", p->prize); + fprintf(file, "%i# lorecounter\n", (p->loreCounter) - 1); //We want to see the last message again when the game is loaded. This might need investigation. TODO + fprintf(file, " Wincon{\n"); + fprintf(file, "%i# winconclass\n", p->win_condition->class); + fprintf(file, "%i# current_val\n", p->win_condition->current_val); + fprintf(file, "%i# target_val\n", p->win_condition->target_val); + fprintf(file, " },\n"); + fprintf(file, "},\n"); + fprintf(file, "%i# enemyindex\n", enemyIndex); + fprintf(file, "%i# roomtotalenemies\n", roomTotalEnemies); + fprintf(file, "%i# roomindex\n", roomIndex); + + /* Consumables bag printing */ + fprintf(file, "ConsumableBag{\n"); + for (int i = 0; i < CONSUMABLESMAX + 1; i++) { + Consumable *cn = (Consumable *) f->consumablesBag[i]; + fprintf(file, "%i# qty_for_consumable_%i\n", cn->qty, i); + } + fprintf(file, "},\n"); + + /* Artifacts bag printing */ + fprintf(file, "ArtifactsBag{\n"); + for (int i = 0; i < ARTIFACTSMAX + 1; i++) { + Artifact *a = f->artifactsBag[i]; + fprintf(file, "%i# qty_for_artifact_%i\n", a->qty, i); + } + fprintf(file, "},\n"); + + log_tag("debug_log.txt", "[DEBUG]", "Done saving"); + + return OP_OK; +} + +/** + * Takes a FILE pointer from which the save type will be loaded. + * Returns the read savetype value or -1 if an invalid value is found. + * @see saveType + * @see gameloop() + * @param file The FILE pointer to load from. + * @return The saveType read from the file. + */ +saveType read_saveType(FILE *file) +{ + log_tag("debug_log.txt", "[DEBUG]", "Reading save type from text file."); + + if (file == NULL) { +#ifdef HELAPORDO_CURSES_BUILD + endwin(); +#endif // HELAPORDO_CURSES_BUILD + printf("Error with file while trying to read save type!\n"); + return -1; + } + char buf[500]; + const char* version = HELAPORDO_SAVEFILE_VERSION; + + int scanres = -1; + /* File version scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in read_saveType(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while reading save type."); + exit(EXIT_FAILURE); + } + + int check = -1; + if (!((check = strcmp(buf, version)) == 0)) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "Failed save format version check. Quitting."); + fprintf(stderr, + "[ERROR] File version mismatch on save type reading.\n"); + exit(EXIT_FAILURE); + }; + log_tag("debug_log.txt", "[LOAD]", "Read save format version: (%s).\n", + buf); + + /* Save type scanning */ + scanres = fscanf(file, "%200s\n", buf); + if (scanres != 1) { + log_tag("debug_log.txt", "[DEBUG]", + "Bad fscanf() result in read_saveType(), expected [%i] was (%i)", + 1, scanres); + fprintf(stderr, "Error while reading save type."); + exit(EXIT_FAILURE); + } + + saveType result = saveTypeFrom_string(buf); + + if (result == -1) { + log_tag("debug_log.txt", "[LOAD-ERROR]", + "read_saveType(): Failed save type reading. Read string Was [%s]. Quitting.", + buf); + fprintf(stderr, "[ERROR] Save type version error.\n"); + exit(EXIT_FAILURE); + + }; + + log_tag("debug_log.txt", "[LOAD]", "Loaded save type: (%s) --> [%s].\n", + buf, stringFrom_saveType(result)); + + log_tag("debug_log.txt", "[LOAD]", + "Doing rewind(save_file) before returning from read_saveType()!"); + rewind(file); + return result; +} diff --git a/src/utils/saves.h b/src/utils/saves.h new file mode 100644 index 00000000..4c250f88 --- /dev/null +++ b/src/utils/saves.h @@ -0,0 +1,45 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 SAVES_H_ +#define SAVES_H_ + +#include "../core/equips.h" +#include "game_init.h" + +#ifdef HELAPORDO_CURSES_BUILD +#include "../build-nc/game_curses.h" +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else +#include "../build-rl/game_rl.h" +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + +OP_res handleLoadgame_Home(FILE * file, Fighter * f, Path * p, int *roomIndex, + int *done_loading, Koliseo * kls); +OP_res handleLoadgame_Enemies(FILE * file, Fighter * f, Path * p, Enemy * e, + int *enemyIndex, int *roomTotalEnemies, + int *roomIndex, int *total_foes, + int *done_loading, Koliseo * kls); +OP_res handleSave_Enemies(FILE * file, Fighter * f, Path * p, Enemy * e, + int enemyIndex, int roomTotalEnemies, int roomIndex); +OP_res handleSave_Home(FILE * file, Fighter * f, Path * p, int roomIndex); +saveType read_saveType(FILE * file); +#endif // SAVES_H_ diff --git a/src/specials.c b/src/utils/specials.c similarity index 96% rename from src/specials.c rename to src/utils/specials.c index d7d5cf56..8162ba2e 100644 --- a/src/specials.c +++ b/src/utils/specials.c @@ -15,15 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifdef HELAPORDO_CURSES_BUILD -#include "helapordo.h" -#else -#ifndef HELAPORDO_RAYLIB_BUILD -#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" -#else -#include "helapordo_raylib.h" -#endif // HELAPORDO_RAYLIB_BUILD -#endif // HELAPORDO_CURSES_BUILD #include "specials.h" #ifdef HELAPORDO_CURSES_BUILD @@ -904,6 +895,40 @@ void assassinSpecial_Venomblade(WINDOW *w, Fighter *f, Enemy *e, Boss *b, wattroff(w, COLOR_PAIR(S4C_BRIGHT_YELLOW)); } } + +/** + * Takes a Fighter pointer and prepares its specialSlot fields by allocating SPECIALSMAX slots. + * Special slots are initialised. + * The specific move assigned is determined using the ordering of both fighterClass values and SPECIALSMAX. + * @see Fighter + * @see Specialslot + * @see SPECIALSMAX + * @see REGISTER_CALLBACK() + * @see costFromSpecial() + * @see stringFromSpecial() + * @param kls The Koliseo used for allocations. + * @param f The Fighter pointer whose special slots will be initialised. + */ +void setSpecials(Fighter *f, Koliseo *kls) +{ + char movename[80]; + char movedesc[80]; + for (int i = 0; i <= SPECIALSMAX; i++) { + kls_log(kls, "DEBUG", "Prepping Specialslot (%i)", i); + Specialslot *s = + (Specialslot *) KLS_PUSH_TYPED(kls, Specialslot, HR_Specialslot, + "Specialslot", "Specialslot"); + s->enabled = 0; + s->move = i + (f->class * (SPECIALSMAX + 1)); // Assign the i-th move offsetting by classNum * specialsMax + s->cost = costFromSpecial(f->class, i); + strcpy(movename, nameStringFromSpecial(f->class, i)); + strcpy(movedesc, descStringFromSpecial(f->class, i)); + //printf("DEBUG\n%i\t%s\n",(i+ (f->class * (SPECIALSMAX + 1))),stringFromSpecial(f->class,i)); + strcpy(s->name, movename); + strcpy(s->desc, movedesc); + f->specials[i] = s; + }; +} #else #ifndef HELAPORDO_RAYLIB_BUILD #error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" @@ -1001,6 +1026,10 @@ void assassinSpecial_Venomblade(Rectangle * win, Fighter * f, Enemy * e, Boss * int isBoss) { +} +void setSpecials(Fighter *f, Koliseo *kls) +{ + } #endif // HELAPORDO_RAYLIB_BUILD #endif // HELAPORDO_CURSES_BUILD diff --git a/src/specials.h b/src/utils/specials.h similarity index 98% rename from src/specials.h rename to src/utils/specials.h index 8792e342..f2d74f23 100644 --- a/src/specials.h +++ b/src/utils/specials.h @@ -18,7 +18,7 @@ #ifndef SPECIALS_H #define SPECIALS_H -#include "game_core.h" +#include "game_utils.h" #ifdef HELAPORDO_CURSES_BUILD #ifdef _WIN32 @@ -74,6 +74,7 @@ void assassinSpecial_Disguise(WINDOW * w, Fighter * f, Enemy * e, Boss * b, void assassinSpecial_Venomblade(WINDOW * w, Fighter * f, Enemy * e, Boss * b, Path * p, int roomIndex, int enemyIndex, int isBoss); +void setSpecials(Fighter * f, Koliseo * kls); #else #ifndef HELAPORDO_RAYLIB_BUILD #error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" @@ -120,6 +121,7 @@ void assassinSpecial_Disguise(Rectangle * win, Fighter * f, Enemy * e, Boss * b, void assassinSpecial_Venomblade(Rectangle * win, Fighter * f, Enemy * e, Boss * b, Path * p, int roomIndex, int enemyIndex, int isBoss); +void setSpecials(Fighter * f, Koliseo * kls); #endif // HELAPORDO_RAYLIB_BUILD #endif // HELAPORDO_CURSES_BUILD #endif // SPECIALS_H diff --git a/src/utils/turn_op.c b/src/utils/turn_op.c new file mode 100644 index 00000000..a7aa3cc9 --- /dev/null +++ b/src/utils/turn_op.c @@ -0,0 +1,812 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 "turn_op.h" + +/** + * Takes a turnOption_OP and a pointer to a turnOP_args struct. + * Logs a warning for any NULL field in the struct. + * Performs the defined turn operation, before returning an OP_res. + * @param op The kind of operation to do. + * @param args Struct containing needed args for current operation. Can have some fields uninitialised, if not relevant to requested turnOP. + * @param kls The Koliseo used for allocations. + * @param t_kls The Koliseo_Temp used for temporary allocations. + * @return An OP_res representing result of turn option operation. + * @see turnOP_args + * @see turnOption_OP + * @see OP_res + */ +OP_res turnOP(turnOption_OP op, turnOP_args *args, Koliseo *kls, + Koliseo_Temp *t_kls) +{ + + OP_res res = INVALID_OP; + + Gamestate *gmst = args->gmst; + if (gmst == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(gmst) was NULL"); + Fighter *actor = args->actor; + if (actor == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(actor) was NULL"); + Path *path = args->path; + if (path == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(path) was NULL"); + Room *room = args->room; + if (room == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(room) was NULL"); + loadInfo *load_info = args->load_info; + if (load_info == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(load_info) was NULL"); + Enemy *enemy = args->enemy; + if (enemy == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(enemy) was NULL"); + Boss *boss = args->boss; + if (boss == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(boss) was NULL"); + FILE *save_file = args->save_file; + if (save_file == NULL) + log_tag("debug_log.txt", "[WARN]", "turnOP_args->(save_file) was NULL"); +#ifdef HELAPORDO_CURSES_BUILD + WINDOW *notify_win = args->notify_win; +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + Rectangle *notify_win = args->notify_win; +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + if (notify_win == NULL) + log_tag("debug_log.txt", "[WARN]", + "turnOP_args->(notify_win) was NULL"); + foeTurnOption_OP foe_op = args->foe_op; + if (foe_op == FOE_OP_INVALID) { + log_tag("debug_log.txt", "[WARN]", + "turnOP_args->(foe_op) was FOE_OP_INVALID"); + } else if (foe_op < 0 || foe_op > FOETURNOP_MAX) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(foe_op) was invalid: [%i]", foe_op); + kls_free(default_kls); + kls_free(temporary_kls); + exit(EXIT_SUCCESS); + } + skillType skill = args->picked_skill; + if (skill < 0 || skill >= SKILLSTOTAL) { + log_tag("debug_log.txt", "[WARN]", + "turnOP_args->(picked_skill) was invalid: [%i]", skill); + } + + int isBoss = -1; +#ifdef HELAPORDO_RAYLIB_BUILD + log_tag("debug_log.txt", "[DEBUG]", + "Logging isBoss: {%i}", isBoss); +#endif + int room_index = -1; + int enemy_index = -1; + + //Log operation code + log_OP(op); + switch (op) { + case OP_INVALID: { + //No_OP, but unexpected + log_tag("debug_log.txt", "[ERROR]", + "Done turnOP() on an OP_INVALID opcode."); + } + break; + case OP_NEW_GAME: { + res = NO_OP; + } + break; + case OP_LOAD_GAME: { + if (load_info == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(load_info) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } + load_info->is_new_game = 0; + res = OP_OK; + } + break; + case OP_LOAD_ENEMYROOM: { + if (load_info == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(load_info) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } + load_info = args->load_info; + if (load_info == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "load_info was NULL after load_info = args->load_info: in turnOP(OP_LOAD_ENEMYROOM"); + return res; + } + save_file = args->save_file; + + if (save_file == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(save_file) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } + int *ptr_to_loaded_enemy_index = &(load_info->enemy_index); + log_tag("debug_log.txt", "[TURNOP]", + "*(ptr_to_loaded_enemy_index) == [%i]", + *ptr_to_loaded_enemy_index); + int *ptr_to_loaded_roomtotalenemies = + (load_info->ptr_to_roomtotalenemies); + log_tag("debug_log.txt", "[TURNOP]", + "*(ptr_to_loaded_roomtotalenemies) == [%i]", + *ptr_to_loaded_roomtotalenemies); + int *ptr_to_loaded_roomindex = (load_info->ptr_to_roomindex); + log_tag("debug_log.txt", "[TURNOP]", + "*(ptr_to_loaded_roomindex) == [%i]", + *ptr_to_loaded_roomindex); + int *tot_foes = &(load_info->total_foes); + log_tag("debug_log.txt", "[TURNOP]", "*(tot_foes) == [%i]", + *tot_foes); + int *ptr_to_done_loading = &(load_info->done_loading); + log_tag("debug_log.txt", "[TURNOP]", "*(done_loading) == [%i]", + *ptr_to_done_loading); + res = + handleLoadgame_Enemies(save_file, actor, path, + load_info->loaded_enemy, + ptr_to_loaded_enemy_index, + ptr_to_loaded_roomtotalenemies, + ptr_to_loaded_roomindex, tot_foes, + ptr_to_done_loading, kls); + //Log end of operation + log_tag("debug_log.txt", "[TURNOP]", + "Done operation: [%s] res: [%s (%i)]", stringFromTurnOP(op), + stringFrom_OP_res(res), res); + + log_tag(OPS_LOGFILE, "[RES]", "res: [%s (%i)]", + stringFrom_OP_res(res), res); + + return res; + } + break; + case OP_LOAD_HOMEROOM: { + if (load_info == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(load_info) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } + load_info = args->load_info; + if (load_info == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "load_info was NULL after load_info = args->load_info: in turnOP(OP_LOAD_HOMEROOM"); + return res; + } + save_file = args->save_file; + + if (save_file == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(save_file) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } + if (load_info->ptr_to_roomindex == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "load_info->ptr_to_roomindex was NULL in turnOP(OP_LOAD_HOMEROOM"); + return res; + } + int *ptr_to_loaded_roomindex = (load_info->ptr_to_roomindex); + if (ptr_to_loaded_roomindex == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "ptr_to_loaded_roomindex was NULL in turnOP(OP_LOAD_HOMEROOM"); + return res; + } + log_tag("debug_log.txt", "[TURNOP]", + "*(ptr_to_loaded_roomindex) == [%i]", + *ptr_to_loaded_roomindex); + + int *ptr_to_done_loading = &(load_info->done_loading); + log_tag("debug_log.txt", "[TURNOP]", "*(done_loading) == [%i]", + *ptr_to_done_loading); + res = + handleLoadgame_Home(save_file, actor, path, + ptr_to_loaded_roomindex, + ptr_to_done_loading, kls); + //Log end of operation + log_tag("debug_log.txt", "[TURNOP]", + "Done operation: [%s] res: [%s (%i)]", stringFromTurnOP(op), + stringFrom_OP_res(res), res); + + log_tag(OPS_LOGFILE, "[RES]", "res: [%s (%i)]", + stringFrom_OP_res(res), res); + + return res; + } + break; + case OP_FIGHT: { + if (notify_win == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Notification WINDOW pointer was null in turnOP(OP_FIGHT)"); + exit(EXIT_FAILURE); + } + if (room == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Room pointer was null in turnOP(OP_FIGHT)"); + exit(EXIT_FAILURE); + } + if (foe_op == FOE_OP_INVALID) { + log_tag("debug_log.txt", "[CRITICAL]", + "foe_op was FOE_OP_INVALID in turnOP(OP_FIGHT)"); + exit(EXIT_FAILURE); + } else if (foe_op < 0 || foe_op > FOETURNOP_MAX) { + log_tag("debug_log.txt", "[CRITICAL]", + "foe_op was invalid in turnOP(OP_FIGHT): [%i]", foe_op); + exit(EXIT_FAILURE); + } + room_index = room->index; + if (room->class == ENEMIES && enemy == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Enemy pointer was null in turnOP(OP_FIGHT) for ENEMIES room."); + exit(EXIT_FAILURE); + } else if (room->class == BOSS && boss == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Boss pointer was null in turnOP(OP_FIGHT) for BOSS room."); + exit(EXIT_FAILURE); + } else if (room->class != ENEMIES && room->class != BOSS) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid room class in turnOP(OP_FIGHT): (%s [%i])", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + } + switch (room->class) { + case ENEMIES: { + enemy_index = enemy->index; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_FIGHT), isBoss == 0", + enemy->index); + isBoss = 0; + res = + OP_res_from_fightResult(defer_fight_enemy + (actor, enemy, foe_op, + notify_win, kls)); + } + break; + case BOSS: { + enemy_index = 0; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (0) (OP_FIGHT), isBoss == 1"); + isBoss = 1; + res = + OP_res_from_fightResult(defer_fight_boss + (actor, boss, path, foe_op, + notify_win, kls)); + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid room value in turnOP(OP_FIGHT): [%s (%i)]", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + + } + break; + } + } + break; + case OP_SPECIAL: { + if (room == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Room pointer was null in turnOP(OP_SPECIAL)"); + exit(EXIT_FAILURE); + } + room_index = room->index; + if (room->class == ENEMIES && enemy == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Enemy pointer was null in turnOP(OP_SPECIAL) for ENEMIES room."); + exit(EXIT_FAILURE); + } else if (room->class == BOSS && boss == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Boss pointer was null in turnOP(OP_SPECIAL) for BOSS room."); + exit(EXIT_FAILURE); + } else if (room->class != ENEMIES && room->class != BOSS) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid room class in turnOP(OP_SPECIAL): (%s [%i])", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + } + switch (room->class) { + case ENEMIES: { + enemy_index = enemy->index; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_SPECIAL), isBoss == 0", + enemy->index); + isBoss = 0; + } + break; + case BOSS: { + enemy_index = 0; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (0) (OP_SPECIAL), isBoss == 1"); + isBoss = 1; + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid room value in turnOP(OP_SPECIAL): [%s (%i)]", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + + } + } +#ifdef HELAPORDO_CURSES_BUILD + handleSpecials(actor, enemy, boss, path, room_index, enemy_index, + isBoss); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement handleSpecials() for raylib build\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case OP_CONSUMABLE: { + if (room == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Room pointer was null in turnOP(OP_CONSUMABLE)"); + exit(EXIT_FAILURE); + } + room_index = room->index; + if (room->class == ENEMIES && enemy == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Enemy pointer was null in turnOP(OP_CONSUMABLE) for ENEMIES room."); + exit(EXIT_FAILURE); + } else if (room->class == BOSS && boss == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Boss pointer was null in turnOP(OP_CONSUMABLE) for BOSS room."); + exit(EXIT_FAILURE); + } else if (room->class != ENEMIES && room->class != BOSS) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid room class in turnOP(OP_CONSUMABLE): (%s [%i])", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + } + switch (room->class) { + case ENEMIES: { + enemy_index = enemy->index; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_CONSUMABLE), isBoss == 0", + enemy->index); + isBoss = 0; + } + break; + case BOSS: { + enemy_index = 0; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (0) (OP_CONSUMABLE), isBoss == 1"); + isBoss = 1; + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid room value in turnOP(OP_CONSUMABLE): [%s (%i)]", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + + } + } +#ifdef HELAPORDO_CURSES_BUILD + handleConsumables(actor, enemy, boss, isBoss); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement handleConsumables() for raylib build\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case OP_SAVE: { + if (GAMEMODE == Rogue) { + log_tag("debug_log.txt", "[WARN]", + "GAMEMODE was [Rogue] in turnOP(OP_SAVE)"); + res = NO_OP; + break; + } + if (save_file == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "save_file pointer was null in turnOP(OP_SAVE)"); + exit(EXIT_FAILURE); + } + if (load_info == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(load_info) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } + if (room == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Room pointer was null in turnOP(OP_SAVE)"); + exit(EXIT_FAILURE); + } + room_index = room->index; + if (room->class == ENEMIES && enemy == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Enemy pointer was null in turnOP(OP_SAVE) for ENEMIES room."); + exit(EXIT_FAILURE); + } else if (room->class == BOSS && boss == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Boss pointer was null in turnOP(OP_SAVE) for BOSS room."); + exit(EXIT_FAILURE); + } + + if ((room->class != ENEMIES) && (room->class != HOME)) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid room class in turnOP(OP_SAVE): (%s [%i])", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + } + + switch (room->class) { + case ENEMIES: { + enemy_index = enemy->index; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_SAVE), isBoss == 0", + enemy->index); + isBoss = 0; + load_info->save_type = ENEMIES_SAVE; + log_tag("debug_log.txt", "[TURNOP]", + "Setting save_type to ENEMIES_SAVE. [%s]", + stringFrom_saveType(load_info->save_type)); + } + break; + case BOSS: { + enemy_index = 0; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (0) (OP_SAVE), isBoss == 1"); + isBoss = 1; + } + break; + case HOME: { + enemy_index = -1; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (-1) (OP_SAVE), isBoss == -1"); + isBoss = -1; + load_info->save_type = HOME_SAVE; + log_tag("debug_log.txt", "[TURNOP]", + "Setting save_type to HOME_SAVE. [%s]", + stringFrom_saveType(load_info->save_type)); + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid room value in turnOP(OP_SAVE): [%s (%i)]", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + + } + } + switch (load_info->save_type) { + case ENEMIES_SAVE: { + res = + handleSave_Enemies(save_file, actor, path, enemy, + enemy_index, room->enemyTotal, + room_index); + } + break; + case HOME_SAVE: { + res = handleSave_Home(save_file, actor, path, room_index); + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid save_type value in turnOP(OP_SAVE): (%i)", + (int)load_info->save_type); + exit(EXIT_FAILURE); + } + break; + } + } + break; + case OP_DEBUG: { + if (gmst == NULL) { + log_tag("debug_log.txt", "[WARN]", + "Gamestate pointer was null in turnOP(OP_DEBUG)"); + exit(EXIT_FAILURE); + } + if (room == NULL) { + log_tag("debug_log.txt", "[WARN]", + "Room pointer was null in turnOP(OP_DEBUG)"); + exit(EXIT_FAILURE); + } + room_index = room->index; + if (room->class == ENEMIES && enemy == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Enemy pointer was null in turnOP(OP_DEBUG) for ENEMIES room."); + exit(EXIT_FAILURE); + } else if (room->class == BOSS && boss == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Boss pointer was null in turnOP(OP_DEBUG) for BOSS room."); + exit(EXIT_FAILURE); + } + + switch (room->class) { + case HOME: { + enemy_index = -1; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_DEBUG), isBoss == -1", + enemy_index); + isBoss = -1; +#ifdef HELAPORDO_CURSES_BUILD + log_tag("debug_log.txt", "[TURNOP]", + "Doing endwin() before debug_generic()"); + endwin(); + debug_generic(gmst, actor, path, room_index, kls, t_kls); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement debug_generic() for raylib build.\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case ENEMIES: { + enemy_index = enemy->index; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_DEBUG), isBoss == 0", + enemy->index); + isBoss = 0; +#ifdef HELAPORDO_CURSES_BUILD + debug_enemies_room(gmst, room, actor, enemy, path, + room_index, enemy_index, kls, t_kls); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement debug_enemies_room() for raylib build.\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case BOSS: { + enemy_index = 0; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (0) (OP_DEBUG), isBoss == 1"); + isBoss = 1; +#ifdef HELAPORDO_CURSES_BUILD + log_tag("debug_log.txt", "[TURNOP]", + "Doing endwin() before debug_generic()"); + endwin(); + debug_generic(gmst, actor, path, room_index, kls, t_kls); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement debug_generic() for raylib build.\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid room value in turnOP(OP_DEBUG): [%s (%i)]", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + } + } + } + break; + case OP_EQUIPS: { + if (actor == NULL || path == NULL) { + if (actor == NULL) + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(actor) was NULL"); + if (path == NULL) + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(path) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } +#ifdef HELAPORDO_CURSES_BUILD + handleEquips(actor, path); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement handleEquips() for raylib build\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + }; + break; + case OP_PERKS: { + if (actor == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(actor) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } +#ifdef HELAPORDO_CURSES_BUILD + printActivePerks(actor); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement printActivePerks() for raylib build\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case OP_STATS: { + if (actor == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(actor) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } +#ifdef HELAPORDO_CURSES_BUILD + handleStats(actor); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement handleStats() for raylib build\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case OP_ARTIFACTS: { + if (actor == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "turnOP_args->(actor) was NULL"); + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + return res; + } +#ifdef HELAPORDO_CURSES_BUILD + handleArtifacts(actor); +#else +#ifndef HELAPORDO_RAYLIB_BUILD +#error "HELAPORDO_CURSES_BUILD and HELAPORDO_RAYLIB_BUILD are both undefined.\n" +#else + assert(0 && "Implement handleArtifacts() for raylib build\n"); +#endif // HELAPORDO_RAYLIB_BUILD +#endif // HELAPORDO_CURSES_BUILD + res = OP_OK; + } + break; + case OP_EXPLORE: { + log_tag("debug_log.txt", "[DEBUG]", "Going to explore!"); + //The free of args should be done after the OP; in handleRoom_Home() + res = NO_OP; + } + break; + case OP_QUIT: { + quit(actor, room, load_info, t_kls); + //FIXME + //We can't free the turnOP_args, can we? + //free(args); + log_tag("debug_log.txt", "[FREE]", "Freed turnOP_args"); + } + break; + case OP_SKILL: { + + log_tag("debug_log.txt", "[DEBUG]", "OP_SKILL"); + + res = NO_OP; + + if (notify_win == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Notification WINDOW pointer was null in turnOP(OP_SKILL)"); + exit(EXIT_FAILURE); + } + if (room == NULL) { + log_tag("debug_log.txt", "[CRITICAL]", + "Room pointer was null in turnOP(OP_SKILL)"); + exit(EXIT_FAILURE); + } + if (foe_op == FOE_OP_INVALID) { + log_tag("debug_log.txt", "[CRITICAL]", + "foe_op was FOE_OP_INVALID in turnOP(OP_SKILL)"); + exit(EXIT_FAILURE); + } else if (foe_op < 0 || foe_op > FOETURNOP_MAX) { + log_tag("debug_log.txt", "[CRITICAL]", + "foe_op was invalid in turnOP(OP_SKILL): [%i]", foe_op); + exit(EXIT_FAILURE); + } + if (skill < 0 || skill > SKILLSTOTAL) { + log_tag("debug_log.txt", "[CRITICAL]", + "skill was invalid in turnOP(OP_SKILL): [%i]", skill); + exit(EXIT_FAILURE); + } + room_index = room->index; + if (room->class == ENEMIES && enemy == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Enemy pointer was null in turnOP(OP_SKILL) for ENEMIES room."); + exit(EXIT_FAILURE); + } else if (room->class == BOSS && boss == NULL) { + log_tag("debug_log.txt", "[ERROR]", + "Boss pointer was null in turnOP(OP_SKILL) for BOSS room."); + exit(EXIT_FAILURE); + } else if (room->class != ENEMIES && room->class != BOSS) { + log_tag("debug_log.txt", "[ERROR]", + "Invalid room class in turnOP(OP_SKILL): (%s [%i])", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + } + switch (room->class) { + case ENEMIES: { + enemy_index = enemy->index; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (%i) (OP_SKILL), isBoss == 0", + enemy->index); + isBoss = 0; + //TODO + //Implement the missing function to wrap skill usage and foe op + res = OP_res_from_fightResult(defer_skill_enemy(actor, enemy, skill, foe_op, notify_win, kls)); + } + break; + case BOSS: { + enemy_index = 0; + log_tag("debug_log.txt", "[TURNOP]", + "Setting enemy_index to (0) (OP_SKILL), isBoss == 1"); + isBoss = 1; + //TODO + //Implement the missing function to wrap skill usage and foe op + res = OP_res_from_fightResult(defer_skill_boss(actor, boss, skill, path, foe_op, notify_win, kls)); + } + break; + default: { + log_tag("debug_log.txt", "[TURNOP]", + "Invalid room value in turnOP(OP_FIGHT): [%s (%i)]", + stringFromRoom(room->class), room->class); + exit(EXIT_FAILURE); + + } + break; + } + } + break; + default: { + log_tag(OPS_LOGFILE, "[ERROR]", "Invalid OP in turnOP()"); + log_tag("debug_log.txt", "[ERROR]", "Invalid OP in turnOP()"); + } + break; + } + + //Log end of operation + log_tag("debug_log.txt", "[TURNOP]", "Done operation: [%s] res: [%s (%i)]", + stringFromTurnOP(op), stringFrom_OP_res(res), res); + + log_tag(OPS_LOGFILE, "[RES]", "res: [%s (%i)]", stringFrom_OP_res(res), + res); + + return res; +} diff --git a/src/utils/turn_op.h b/src/utils/turn_op.h new file mode 100644 index 00000000..32fe3fcc --- /dev/null +++ b/src/utils/turn_op.h @@ -0,0 +1,34 @@ +// jgabaut @ github.com/jgabaut +// SPDX-License-Identifier: GPL-3.0-only +/* + Copyright (C) 2022-2024 jgabaut + + 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, version 3 of the License. + + 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 TURNOP_H_ +#define TURNOP_H_ + +#include "game_debug.h" +#include "game_fight.h" +#include "saves.h" + +/** + * Call function associated with the passed turnOption_OP. + * @param op The turnOption_OP to execute. + * @param args Pointer to turnOP_args object. + * @param kls The Koliseo used for allocations. + */ +OP_res turnOP(turnOption_OP op, turnOP_args * args, Koliseo * kls, + Koliseo_Temp * t_kls); +#endif // TURNOP_H_ diff --git a/stego.lock b/stego.lock index f35f5c90..549f1037 100644 --- a/stego.lock +++ b/stego.lock @@ -1,6 +1,6 @@ [ anvil ] -version = "2.0.3" +version = "2.0.4" kern = "amboso-C" [ build ] @@ -62,3 +62,4 @@ errortestsdir = "kulpo" "1.4.0" = "Add WIP raylib integration, bump s4c to 0.4.2" "1.4.1" = "Fix broken clang build, add s4c-scripts, bump s4c to 0.4.3, invil to 0.2.5" "1.4.2" = "Change static_path to working dir, Gamestate has screen for curses build, check screen size, bump deps" +"1.4.3" = "Major files refactor, rooms.h drops circular dependency on helapordo.h, rl build has interactive floor generation"