diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..196c51c --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +PointerAlignment: Right +SpaceBeforeAssignmentOperators: true +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpaceBeforeParens: Never +IndentCaseBlocks: true +IncludeBlocks: Regroup +AllowShortBlocksOnASingleLine: Empty +ColumnLimit: 80 diff --git a/.gitignore b/.gitignore index 085829e..2c5a8cf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /build-fx /build-cg /build-cg-push +/build-fxg3a /*.g1a /*.g3a @@ -13,5 +14,4 @@ __pycache__/ *.sublime-workspace .vscode -level*.json tilesetnpp.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4d9ffe6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "assets/tinytiled"] + path = assets/tinytiled + url = https://git.planet-casio.com/mibi88/tinytiled +[submodule "assets/--force"] + path = assets/--force + url = https://git.planet-casio.com/mibi88/tinytiled diff --git a/CMakeLists.txt b/CMakeLists.txt index 65291bf..e3c55a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,18 +4,24 @@ cmake_minimum_required(VERSION 3.15) project(MyAddin) +#set the color mode either to 1b or 2b +set(COLORMODE_fx 1b) +#set the color mode either to 1b, 2b or EGA64 +set(COLORMODE_cg EGA64) + +if(NOT "${COLORMODE_cg}" STREQUAL EGA64) + set(FXSDK_PLATFORM_LONG fx9860G_G3A) + set(FXSDK_PLATFORM fx) +endif() + include(GenerateG1A) include(GenerateG3A) include(Fxconv) -find_package(Gint 2.9 REQUIRED) +find_package(Gint 2.11 REQUIRED) +# Gint 2.11 is required, because we're using the new macros like GINT_RENDER_RGB find_package(LibProf 2.4 REQUIRED) -#set the color mode either to 1b or 2b -set(COLORMODE_fx 2b) -#set the color mode either to 1b, 2b or EGA64 -set(COLORMODE_cg EGA64) - fxconv_declare_converters(assets/converters.py) set(SOURCES @@ -26,44 +32,53 @@ set(SOURCES src/game.c src/dialogs.c src/npc.c + src/events.c # ... ) # Shared assets, fx-9860G-only assets and fx-CG-50-only assets set(ASSETS - assets/WorldRPG.world + assets/level0_dialogs.json + assets/level1_dialogs.json + assets/level2_dialogs.json + assets/level3_dialogs.json + assets/level4_dialogs.json + assets/level0.tmx + assets/level1.tmx + assets/level2.tmx + assets/level3.tmx + assets/level4.tmx + assets/interior1_0_dialogs.json + assets/interior1_0.tmx # ... ) set(ASSETS_cg - assets-cg/demo_player.png - assets-cg/demo_PNJ.png + assets-cg/player_male.png + assets-cg/player_female.png + assets-cg/npc/char/npc_male.png + assets-cg/npc/char/npc_female.png + assets-cg/npc/char/npc_milkman.png + assets-cg/npc/char/npc_police.png assets-cg/SignAction.png - assets-cg/NPC_Icon.png + assets-cg/npc/face/npc_male.png + assets-cg/npc/face/npc_female.png + assets-cg/npc/face/npc_milkman.png + assets-cg/npc/face/npc_police.png assets-cg/SGN_Icon.png assets-cg/INFO_Icon.png assets-cg/player_face.png assets-cg/font.png ) -set(ASSETS_cg_1b - assets-cg/1b/tileset/tileset1b_CG.png -) - -set(ASSETS_cg_2b - assets-cg/2b/tileset/tileset2b_CG.png -) - set(ASSETS_cg_EGA64 assets-cg/ega64/tileset/tilesetEGA64_CG.png ) set(ASSETS_fx - assets-fx/demo_player.png - assets-fx/demo_PNJ.png + assets-fx/player_male.png + assets-fx/player_female.png assets-fx/SignAction.png - assets-fx/NPC_Icon.png assets-fx/SGN_Icon.png - assets-fx/INFO_Icon.png assets-fx/player_face.png assets-fx/font.png # ... @@ -71,11 +86,29 @@ set(ASSETS_fx set(ASSETS_fx_1b assets-fx/1b/tileset/tileset1b.png + assets-fx/1b/npc/char/npc_male.png + assets-fx/1b/npc/char/npc_female.png + assets-fx/1b/npc/char/npc_milkman.png + assets-fx/1b/npc/char/npc_police.png + assets-fx/1b/npc/face/npc_male.png + assets-fx/1b/npc/face/npc_female.png + assets-fx/1b/npc/face/npc_milkman.png + assets-fx/1b/npc/face/npc_police.png + assets-fx/1b/INFO_Icon.png # ... ) set(ASSETS_fx_2b assets-fx/2b/tileset/tileset2b.png + assets-fx/2b/npc/char/npc_male.png + assets-fx/2b/npc/char/npc_female.png + assets-fx/2b/npc/char/npc_milkman.png + assets-fx/2b/npc/char/npc_police.png + assets-fx/2b/npc/face/npc_male.png + assets-fx/2b/npc/face/npc_female.png + assets-fx/2b/npc/face/npc_milkman.png + assets-fx/2b/npc/face/npc_police.png + assets-fx/1b/INFO_Icon.png # ... ) @@ -85,29 +118,8 @@ if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}} ${ASSETS_${FXSDK_PLATFORM}_${COLORMODE_fx}} ) elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}} ${ASSETS_${FXSDK_PLATFORM}_${COLORMODE_cg}} ) -endif() - -# fx colormode -if("${COLORMODE_fx}" STREQUAL 1b) - target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -DCOLOR1BIT) -endif() - - -if("${COLORMODE_fx}" STREQUAL 2b) - target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -DCOLOR2BIT) -endif() - -# cg colormode -if("${COLORMODE_cg}" STREQUAL 1b) - target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -DCOLOR1BIT) -endif() - -if("${COLORMODE_cg}" STREQUAL 2b) - target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -DCOLOR2BIT) -endif() - -if("${COLORMODE_cg}" STREQUAL EGA64) - target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -DCOLOREGA) +elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A) + add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}} ${ASSETS_${FXSDK_PLATFORM}_${COLORMODE_fx}} ) endif() target_link_options(myaddin PRIVATE -Wl,-Map=Build_Addin.map -Wl,--print-memory-usage) @@ -115,6 +127,14 @@ target_link_libraries(myaddin LibProf::LibProf Gint::Gint) if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) + # fx colormode + if("${COLORMODE_fx}" STREQUAL 1b) + target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -g -DCOLOR1BIT) + endif() + + if("${COLORMODE_fx}" STREQUAL 2b) + target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -g -DCOLOR2BIT) + endif() if("${COLORMODE_fx}" STREQUAL 1b) generate_g1a(TARGET myaddin OUTPUT "RPG_1b.g1a" @@ -127,16 +147,21 @@ if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) endif() + elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) + # cg colormode + if("${COLORMODE_cg}" STREQUAL EGA64) + target_compile_options(myaddin PRIVATE -Wall -Wextra -O0 -g -DCOLOREGA) + endif() if("${COLORMODE_cg}" STREQUAL 1b) - generate_g3a(TARGET myaddin OUTPUT "RPG_1b.g3a" - NAME "RPG PC 1b" ICONS assets-cg/1b/icon-uns-1b.png assets-cg/1b/icon-sel-1b.png) + generate_g3a(TARGET myaddin OUTPUT "RPG_1bfx.g3a" + NAME "RPG PC 1b fx" ICONS assets-cg/1b/icon-uns-1b.png assets-cg/1b/icon-sel-1b.png) endif() if("${COLORMODE_cg}" STREQUAL 2b) - generate_g3a(TARGET myaddin OUTPUT "RPG_2b.g3a" - NAME "RPG PC 2b" ICONS assets-cg/2b/icon-uns-2b.png assets-cg/2b/icon-sel-2b.png) + generate_g3a(TARGET myaddin OUTPUT "RPG_2bfx.g3a" + NAME "RPG PC 2b fx" ICONS assets-cg/2b/icon-uns-2b.png assets-cg/2b/icon-sel-2b.png) endif() if("${COLORMODE_cg}" STREQUAL EGA64) @@ -144,4 +169,19 @@ elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) NAME "RPG PC EGA" ICONS assets-cg/ega64/icon-uns-ega64.png assets-cg/ega64/icon-sel-ega64.png) endif() + + +elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G_G3A) + + if("${COLORMODE_fx}" STREQUAL 1b) + generate_g3a(TARGET myaddin OUTPUT "RPG_1bfx.g3a" + NAME "RPG PC 1b fx" ICONS assets-cg/1b/icon-uns-1b.png assets-cg/1b/icon-sel-1b.png) + endif() + + if("${COLORMODE_fx}" STREQUAL 2b) + generate_g3a(TARGET myaddin OUTPUT "RPG_2bfx.g3a" + NAME "RPG PC 2b fx" ICONS assets-cg/2b/icon-uns-2b.png assets-cg/2b/icon-sel-2b.png) + endif() + + endif() diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..8ddbd80 --- /dev/null +++ b/PROJECT_STRUCTURE.md @@ -0,0 +1,26 @@ +# Project structure + + * `assets` contains the tiled maps, and the tiled map converters. + * `assets-cg` contains the assets for cg calculators like the cg-50. + * `assets-fx` contains the assets for monochrome calculators. + * `captures` contains screenshots. + * `src` This folder contains the source code. + * `config.h` This header file contains defines for the size of various + things on screen, like the size of a tile in the tilemap, the size of the + dialog box, etc. + * `dialogs.c` and `dialogs.h` contain various functions to display dialogs + and also let the user respond. + * `events.c` and `events.h` parse tags in the messages that are displayed + using the dialogs procedures to modify variables (and soon, call + procedures). + * `game.c` and `game.h` handles the rendering, the input, etc. + * `main.c` handles the USB connection and the gint gray rendering, for 2bpp + rendering on monochrome calculators. Contains the mainloop. Also contains + code to display debug informations. + * `map.c` and `map.h` contain code to render, get a tile in the map, see if + the tile is walkable, etc. + * `mapdata.h` contains the available maps. + * `memory.c` and `memory.h` procedures to handle arrays (currently: search + in an array of short ints). + * `npc.c` and `npc.h` npc rendering and movement (and soon pathfinding). + * `player.c` and `player.h` handle the player movement, collision, etc. diff --git a/README.md b/README.md index 03c5af6..09d5ec3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,12 @@ Plus d'infos sur ce projet ici : [Le projet Collaboratif de PC](https://www.planet-casio.com/Fr/forums/topic17343-last-projet-collaboratif-avec-toute-la-commu.html) -## Avencement du projet +## Contribuer! +Style du code [STYLE.md](STYLE.md). + +Structure du projet [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md). + +## Avancement du projet A ce stade, on a déjà implémenté : @@ -13,12 +18,13 @@ A ce stade, on a déjà implémenté : - [x] Multiple cartes avec importation automatique des fichiers `world` issus de Tiled - [x] Carte Multilayer (Background, Foreground + accessibilité / Dommages) avec transparence du calque Foreground - [x] Personnage -- [x] Dialogues avec fichiers externes `json` et séquenceage possible de ceux-ci via un arbre d'histoire (sauts de lignes et mots plus grands que l'écran pas supportés) +- [x] Dialogues avec fichiers externes `json` et séquenceage possible de ceux-ci via un arbre d'histoire (sauts de lignes et mots plus grands que l'écran pas supportés + limite d'un kibibyte) - [x] Fontes de caractères - [x] Interaction - [ ] NPC - [x] Changement de map durant le jeu - [ ] Système d'événements +- [ ] Pathfinding ## Crédits diff --git a/README_en.md b/README_en.md new file mode 100644 index 0000000..7a892d8 --- /dev/null +++ b/README_en.md @@ -0,0 +1,44 @@ +# Planet Casio Collaborative Project + +(maybe I should've used google translate) + +More informations can be found here (in french): +[Le projet Collaboratif de PC](https://www.planet-casio.com/Fr/forums/topic17343-last-projet-collaboratif-avec-toute-la-commu.html) + +## Contribute! +Style guidelines [STYLE.md](STYLE.md). + +Project structure [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md). + +## Current state + +What we've implemented so far: + +- [x] Screenshots via USB +- [x] Displaying the current map at the players position +- [x] Handling keyboard inputs +- [x] Handling collisions. +- [x] Multiple maps with automatic `world` files import (made with Tiled) +- [x] Multilayer map (Background, Foreground + accessibility / damage) with + foreground layer transparency. +- [x] Player character. +- [x] Dialogs from external `json` files (line jumps and words bigger than the + screen are unsupported + 1 kibibyte per message limit) +- [x] Font +- [x] Interaction +- [ ] NPC +- [x] Changing map in game. +- [ ] Event system +- [ ] Pathfinding + + +## Credits + +The tiles are from Game Boy Top-down RPG Fantasy Tileset (FREE) +"Background Assets by Gumpy Function (gumpyfunction.itch.io)" +[Tiles Background Assets by Gumpy Function](https://gumpyfunction.itch.io/game-boy-rpg-fantasy-tileset-free) + +Converted to greyscale with gimp. + +1-bit (black and white) version by Shadow15510 +CG (palette EGA64) color version by Fcalva diff --git a/STYLE.md b/STYLE.md new file mode 100644 index 0000000..fae5c75 --- /dev/null +++ b/STYLE.md @@ -0,0 +1,14 @@ +# Style guidelines in Collab RPG + +(Mibi88) Fcalva, SlyVTT: What do you think of this? + +Variables names in sneak_case. + +Name your procedures as following: `filename_whatitdoes`. + +The procedures are documented using sphinx. + +We're using `clang-formatter` to keep the code readable. Please run it before +committing your code as following: `clang-format -i *` in the `src` folder. + +Have I forgotten something? diff --git a/assets-cg/INFO_Icon.png b/assets-cg/INFO_Icon.png index ce5e500..ba8e286 100644 Binary files a/assets-cg/INFO_Icon.png and b/assets-cg/INFO_Icon.png differ diff --git a/assets-cg/NPC_Icon.png b/assets-cg/NPC_Icon.png deleted file mode 100644 index e9cc819..0000000 Binary files a/assets-cg/NPC_Icon.png and /dev/null differ diff --git a/assets-cg/NPC_Icon_2.png b/assets-cg/NPC_Icon_2.png index 6f0245a..47640be 100644 Binary files a/assets-cg/NPC_Icon_2.png and b/assets-cg/NPC_Icon_2.png differ diff --git a/assets-cg/SGN_Icon.png b/assets-cg/SGN_Icon.png index d68b589..d3b15f5 100644 Binary files a/assets-cg/SGN_Icon.png and b/assets-cg/SGN_Icon.png differ diff --git a/assets-cg/SignAction.png b/assets-cg/SignAction.png index ced6850..965ea6e 100644 Binary files a/assets-cg/SignAction.png and b/assets-cg/SignAction.png differ diff --git a/assets-cg/demo_PNJ.png b/assets-cg/demo_PNJ.png deleted file mode 100644 index 8198c59..0000000 Binary files a/assets-cg/demo_PNJ.png and /dev/null differ diff --git a/assets-cg/demo_player.png b/assets-cg/demo_player.png deleted file mode 100644 index 04c4d34..0000000 Binary files a/assets-cg/demo_player.png and /dev/null differ diff --git a/assets-cg/ega64/tileset/tilesetEGA64_CG.png b/assets-cg/ega64/tileset/tilesetEGA64_CG.png old mode 100755 new mode 100644 index 86428c6..4fcde4c Binary files a/assets-cg/ega64/tileset/tilesetEGA64_CG.png and b/assets-cg/ega64/tileset/tilesetEGA64_CG.png differ diff --git a/assets-cg/ega64/tileset/tileset_inEGA64_CG.png b/assets-cg/ega64/tileset/tileset_inEGA64_CG.png new file mode 100644 index 0000000..4d391b2 Binary files /dev/null and b/assets-cg/ega64/tileset/tileset_inEGA64_CG.png differ diff --git a/assets-cg/fxconv-metadata.txt b/assets-cg/fxconv-metadata.txt index 87de14b..a8d3e6e 100644 --- a/assets-cg/fxconv-metadata.txt +++ b/assets-cg/fxconv-metadata.txt @@ -1,11 +1,7 @@ *.png: - custom-type: custom-image + custom-type: bopti-image name_regex: (.*)\.png \1_img profile: p8 - scale: 2 - -demo_PNG.png: - scale: 1 font.png: name: fontRPG diff --git a/assets-cg/npc/char/fxconv-metadata.txt b/assets-cg/npc/char/fxconv-metadata.txt new file mode 100644 index 0000000..33fca10 --- /dev/null +++ b/assets-cg/npc/char/fxconv-metadata.txt @@ -0,0 +1,15 @@ +npc_male.png: + type: bopti-image + name: tiny_npc_male + +npc_female.png: + type: bopti-image + name: tiny_npc_female + +npc_milkman.png: + type: bopti-image + name: tiny_npc_milkman + +npc_police.png: + type: bopti-image + name: tiny_npc_police diff --git a/assets-cg/npc/char/npc_female.png b/assets-cg/npc/char/npc_female.png new file mode 100644 index 0000000..041e951 Binary files /dev/null and b/assets-cg/npc/char/npc_female.png differ diff --git a/assets-cg/npc/char/npc_male.png b/assets-cg/npc/char/npc_male.png new file mode 100644 index 0000000..9734b02 Binary files /dev/null and b/assets-cg/npc/char/npc_male.png differ diff --git a/assets-cg/npc/char/npc_milkman.png b/assets-cg/npc/char/npc_milkman.png new file mode 100644 index 0000000..92ead4b Binary files /dev/null and b/assets-cg/npc/char/npc_milkman.png differ diff --git a/assets-cg/npc/char/npc_police.png b/assets-cg/npc/char/npc_police.png new file mode 100644 index 0000000..e590a72 Binary files /dev/null and b/assets-cg/npc/char/npc_police.png differ diff --git a/assets-cg/npc/face/fxconv-metadata.txt b/assets-cg/npc/face/fxconv-metadata.txt new file mode 100644 index 0000000..664ce84 --- /dev/null +++ b/assets-cg/npc/face/fxconv-metadata.txt @@ -0,0 +1,12 @@ +npc_male.png: + type: bopti-image + name: npc_male +npc_female.png: + type: bopti-image + name: npc_female +npc_milkman.png: + type: bopti-image + name: npc_milkman +npc_police.png: + type: bopti-image + name: npc_police diff --git a/assets-cg/npc/face/npc_female.png b/assets-cg/npc/face/npc_female.png new file mode 100644 index 0000000..77f10cc Binary files /dev/null and b/assets-cg/npc/face/npc_female.png differ diff --git a/assets-cg/npc/face/npc_male.png b/assets-cg/npc/face/npc_male.png new file mode 100644 index 0000000..e91f2e6 Binary files /dev/null and b/assets-cg/npc/face/npc_male.png differ diff --git a/assets-cg/npc/face/npc_milkman.ase b/assets-cg/npc/face/npc_milkman.ase new file mode 100644 index 0000000..6993b2e Binary files /dev/null and b/assets-cg/npc/face/npc_milkman.ase differ diff --git a/assets-cg/npc/face/npc_milkman.png b/assets-cg/npc/face/npc_milkman.png new file mode 100644 index 0000000..78aa9f7 Binary files /dev/null and b/assets-cg/npc/face/npc_milkman.png differ diff --git a/assets-cg/npc/face/npc_police.ase b/assets-cg/npc/face/npc_police.ase new file mode 100644 index 0000000..fdfef9e Binary files /dev/null and b/assets-cg/npc/face/npc_police.ase differ diff --git a/assets-cg/npc/face/npc_police.png b/assets-cg/npc/face/npc_police.png new file mode 100644 index 0000000..d9ec265 Binary files /dev/null and b/assets-cg/npc/face/npc_police.png differ diff --git a/assets-cg/player_face.png b/assets-cg/player_face.png index f564e32..a749649 100644 Binary files a/assets-cg/player_face.png and b/assets-cg/player_face.png differ diff --git a/assets-cg/player_female.png b/assets-cg/player_female.png new file mode 100644 index 0000000..5bacf68 Binary files /dev/null and b/assets-cg/player_female.png differ diff --git a/assets-cg/player_male.png b/assets-cg/player_male.png new file mode 100644 index 0000000..830590a Binary files /dev/null and b/assets-cg/player_male.png differ diff --git a/assets-fx/1b/INFO_Icon.png b/assets-fx/1b/INFO_Icon.png new file mode 100644 index 0000000..462ee7b Binary files /dev/null and b/assets-fx/1b/INFO_Icon.png differ diff --git a/assets-fx/1b/fxconv-metadata.txt b/assets-fx/1b/fxconv-metadata.txt new file mode 100644 index 0000000..9f0baf7 --- /dev/null +++ b/assets-fx/1b/fxconv-metadata.txt @@ -0,0 +1,3 @@ +INFO_Icon.png: + type: bopti-image + name: INFO_Icon_img diff --git a/assets-fx/1b/npc/char/fxconv-metadata.txt b/assets-fx/1b/npc/char/fxconv-metadata.txt new file mode 100644 index 0000000..be0fd73 --- /dev/null +++ b/assets-fx/1b/npc/char/fxconv-metadata.txt @@ -0,0 +1,12 @@ +npc_male.png: + type: bopti-image + name: tiny_npc_male +npc_female.png: + type: bopti-image + name: tiny_npc_female +npc_milkman.png: + type: bopti-image + name: tiny_npc_milkman +npc_police.png: + type: bopti-image + name: tiny_npc_police diff --git a/assets-fx/1b/npc/char/npc_female.png b/assets-fx/1b/npc/char/npc_female.png new file mode 100644 index 0000000..5a8e7bb Binary files /dev/null and b/assets-fx/1b/npc/char/npc_female.png differ diff --git a/assets-fx/1b/npc/char/npc_male.png b/assets-fx/1b/npc/char/npc_male.png new file mode 100644 index 0000000..45d8efb Binary files /dev/null and b/assets-fx/1b/npc/char/npc_male.png differ diff --git a/assets-fx/1b/npc/char/npc_milkman.png b/assets-fx/1b/npc/char/npc_milkman.png new file mode 100644 index 0000000..45d8efb Binary files /dev/null and b/assets-fx/1b/npc/char/npc_milkman.png differ diff --git a/assets-fx/1b/npc/char/npc_police.png b/assets-fx/1b/npc/char/npc_police.png new file mode 100644 index 0000000..45d8efb Binary files /dev/null and b/assets-fx/1b/npc/char/npc_police.png differ diff --git a/assets-fx/1b/npc/face/fxconv-metadata.txt b/assets-fx/1b/npc/face/fxconv-metadata.txt new file mode 100644 index 0000000..664ce84 --- /dev/null +++ b/assets-fx/1b/npc/face/fxconv-metadata.txt @@ -0,0 +1,12 @@ +npc_male.png: + type: bopti-image + name: npc_male +npc_female.png: + type: bopti-image + name: npc_female +npc_milkman.png: + type: bopti-image + name: npc_milkman +npc_police.png: + type: bopti-image + name: npc_police diff --git a/assets-fx/1b/npc/face/npc_female.png b/assets-fx/1b/npc/face/npc_female.png new file mode 100644 index 0000000..1a5675a Binary files /dev/null and b/assets-fx/1b/npc/face/npc_female.png differ diff --git a/assets-fx/1b/npc/face/npc_male.png b/assets-fx/1b/npc/face/npc_male.png new file mode 100644 index 0000000..58a20a3 Binary files /dev/null and b/assets-fx/1b/npc/face/npc_male.png differ diff --git a/assets-fx/1b/npc/face/npc_milkman.png b/assets-fx/1b/npc/face/npc_milkman.png new file mode 100644 index 0000000..6cc3313 Binary files /dev/null and b/assets-fx/1b/npc/face/npc_milkman.png differ diff --git a/assets-fx/1b/npc/face/npc_police.png b/assets-fx/1b/npc/face/npc_police.png new file mode 100644 index 0000000..4811934 Binary files /dev/null and b/assets-fx/1b/npc/face/npc_police.png differ diff --git a/assets-fx/1b/tileset/tileset1b.png b/assets-fx/1b/tileset/tileset1b.png index 63f9c7b..27ef69d 100644 Binary files a/assets-fx/1b/tileset/tileset1b.png and b/assets-fx/1b/tileset/tileset1b.png differ diff --git a/assets-fx/1b/tileset/tileset_in1b.png b/assets-fx/1b/tileset/tileset_in1b.png new file mode 100644 index 0000000..fa7820b Binary files /dev/null and b/assets-fx/1b/tileset/tileset_in1b.png differ diff --git a/assets-fx/INFO_Icon.png b/assets-fx/2b/INFO_Icon.png similarity index 100% rename from assets-fx/INFO_Icon.png rename to assets-fx/2b/INFO_Icon.png diff --git a/assets-fx/2b/fxconv-metadata.txt b/assets-fx/2b/fxconv-metadata.txt new file mode 100644 index 0000000..9f0baf7 --- /dev/null +++ b/assets-fx/2b/fxconv-metadata.txt @@ -0,0 +1,3 @@ +INFO_Icon.png: + type: bopti-image + name: INFO_Icon_img diff --git a/assets-fx/2b/npc/char/fxconv-metadata.txt b/assets-fx/2b/npc/char/fxconv-metadata.txt new file mode 100644 index 0000000..be0fd73 --- /dev/null +++ b/assets-fx/2b/npc/char/fxconv-metadata.txt @@ -0,0 +1,12 @@ +npc_male.png: + type: bopti-image + name: tiny_npc_male +npc_female.png: + type: bopti-image + name: tiny_npc_female +npc_milkman.png: + type: bopti-image + name: tiny_npc_milkman +npc_police.png: + type: bopti-image + name: tiny_npc_police diff --git a/assets-fx/2b/npc/char/npc_female.png b/assets-fx/2b/npc/char/npc_female.png new file mode 100644 index 0000000..08d2bcd Binary files /dev/null and b/assets-fx/2b/npc/char/npc_female.png differ diff --git a/assets-fx/2b/npc/char/npc_male.png b/assets-fx/2b/npc/char/npc_male.png new file mode 100644 index 0000000..639504e Binary files /dev/null and b/assets-fx/2b/npc/char/npc_male.png differ diff --git a/assets-fx/2b/npc/char/npc_milkman.png b/assets-fx/2b/npc/char/npc_milkman.png new file mode 100644 index 0000000..639504e Binary files /dev/null and b/assets-fx/2b/npc/char/npc_milkman.png differ diff --git a/assets-fx/2b/npc/char/npc_police.png b/assets-fx/2b/npc/char/npc_police.png new file mode 100644 index 0000000..639504e Binary files /dev/null and b/assets-fx/2b/npc/char/npc_police.png differ diff --git a/assets-fx/2b/npc/face/fxconv-metadata.txt b/assets-fx/2b/npc/face/fxconv-metadata.txt new file mode 100644 index 0000000..664ce84 --- /dev/null +++ b/assets-fx/2b/npc/face/fxconv-metadata.txt @@ -0,0 +1,12 @@ +npc_male.png: + type: bopti-image + name: npc_male +npc_female.png: + type: bopti-image + name: npc_female +npc_milkman.png: + type: bopti-image + name: npc_milkman +npc_police.png: + type: bopti-image + name: npc_police diff --git a/assets-fx/2b/npc/face/npc_female.png b/assets-fx/2b/npc/face/npc_female.png new file mode 100644 index 0000000..dcd2468 Binary files /dev/null and b/assets-fx/2b/npc/face/npc_female.png differ diff --git a/assets-fx/2b/npc/face/npc_male.png b/assets-fx/2b/npc/face/npc_male.png new file mode 100644 index 0000000..994a16d Binary files /dev/null and b/assets-fx/2b/npc/face/npc_male.png differ diff --git a/assets-fx/2b/npc/face/npc_milkman.png b/assets-fx/2b/npc/face/npc_milkman.png new file mode 100644 index 0000000..f92f7bf Binary files /dev/null and b/assets-fx/2b/npc/face/npc_milkman.png differ diff --git a/assets-fx/2b/npc/face/npc_police.png b/assets-fx/2b/npc/face/npc_police.png new file mode 100644 index 0000000..b5903ad Binary files /dev/null and b/assets-fx/2b/npc/face/npc_police.png differ diff --git a/assets-fx/2b/tileset/tileset_in2b.png b/assets-fx/2b/tileset/tileset_in2b.png new file mode 100644 index 0000000..e2e1273 Binary files /dev/null and b/assets-fx/2b/tileset/tileset_in2b.png differ diff --git a/assets-fx/2bpp_palette.png b/assets-fx/2bpp_palette.png new file mode 100644 index 0000000..05dc19d Binary files /dev/null and b/assets-fx/2bpp_palette.png differ diff --git a/assets-fx/NPC_Icon.png b/assets-fx/NPC_Icon.png deleted file mode 100644 index b353607..0000000 Binary files a/assets-fx/NPC_Icon.png and /dev/null differ diff --git a/assets-fx/demo_PNJ.png b/assets-fx/demo_PNJ.png deleted file mode 100644 index 8198c59..0000000 Binary files a/assets-fx/demo_PNJ.png and /dev/null differ diff --git a/assets-fx/demo_player.png b/assets-fx/demo_player.png deleted file mode 100644 index e522e61..0000000 Binary files a/assets-fx/demo_player.png and /dev/null differ diff --git a/assets-fx/fxconv-metadata.txt b/assets-fx/fxconv-metadata.txt index 499f659..1d7d0f9 100644 --- a/assets-fx/fxconv-metadata.txt +++ b/assets-fx/fxconv-metadata.txt @@ -1,10 +1,9 @@ -demo_player.png: +player_male.png: type: bopti-image - name: demo_player_img - -demo_PNJ.png: + name: player_male_img +player_female.png: type: bopti-image - name: demo_PNJ_img + name: player_female_img player_face.png: type: bopti-image @@ -13,14 +12,6 @@ player_face.png: SignAction.png: type: bopti-image name: SignAction_img - -INFO_Icon.png: - type: bopti-image - name: INFO_Icon_img - -NPC_Icon.png: - type: bopti-image - name: NPC_Icon_img SGN_Icon.png: type: bopti-image @@ -34,4 +25,4 @@ font.png: grid.padding: 1 grid.border: 0 proportional: true - height: 5 \ No newline at end of file + height: 5 diff --git a/assets-fx/player_female.png b/assets-fx/player_female.png new file mode 100644 index 0000000..786f9b9 Binary files /dev/null and b/assets-fx/player_female.png differ diff --git a/assets-fx/player_male.png b/assets-fx/player_male.png new file mode 100644 index 0000000..7c1da00 Binary files /dev/null and b/assets-fx/player_male.png differ diff --git a/assets/WorldRPG.world b/assets/WorldRPG.world index 7cbaa1d..5042789 100644 --- a/assets/WorldRPG.world +++ b/assets/WorldRPG.world @@ -27,6 +27,13 @@ "width": 384, "x": 384, "y": 192 + }, + { + "fileName": "level4.tmx", + "height": 192, + "width": 384, + "x": 384, + "y": 384 } ], "onlyShowAdjacentMaps": false, diff --git a/assets/converters.py b/assets/converters.py index 7b19bc8..63d6de5 100644 --- a/assets/converters.py +++ b/assets/converters.py @@ -1,405 +1,392 @@ -from random import randint -from PIL import Image -import fxconv +""" +This is the main converter script. It uses the tiled.py script to handle the +tiled maps. + +We're trying to follow the PEP, so please read PEP 8 (if you haven't already): +https://peps.python.org/pep-0008/, so please write variable names in sneak_case +and class names in PascalCase. + +To improve the lisibility of this code, please document your methods, add +comments (yes, it's hard to add the right amount of comments), and add type +hints, to avoid bugs and make it easy to understand how to use them. + +To document your methods, you should read PEP 257: +https://peps.python.org/pep-0257/. + +Thanks, +Mibi88 +""" + +import xml.etree.ElementTree as ET import json -import pathlib -import csv import os - - -def convert(input, output, params, target): - if params["custom-type"] == "map": - print("ERROR : Asset ", params["name"], " has legacy type map") - return 1 - elif params["custom-type"] == "world": - convert_world(input, output, params, target) - return 0 - elif params["custom-type"] == "custom-image": - convert_custom_image(input, output, params, target) - return 0 - elif params["custom-type"] == "font": - convert_font(input, output, params, target) - return 0 - elif params["custom-type"] == "dialogs": - print("ERROR : Asset ", params["name"], " has legacy type dialog") - #convert_dialogs(input, output, params, target) - return 0 - else: - return 1 - - - -def convert_world(input, output, params, target): - print( "WE ARE COMPUTING THE WORLD", input ) - - data = json.load(open(input, "r")) - nbMaps = ["fileName" in i for i in data["maps"]].count(True) - print( "We have to treat ", nbMaps, " maps") - print( "So let's go ... ") - - structWorld = fxconv.Structure() - #structExtra = fxconv.Structure() - - for i in range(nbMaps): - nameMap = data["maps"][i]["fileName"].replace(".tmx","") - nameMapFree = nameMap.split("/")[-1] - #count the number of "back" (cd ..) to locate the map on the computer - nbRetour = nameMap.count("..")+1 - #create the map absolute path - - nameTMX = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".tmx" - nameJSON = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".json" - - commandline = 'tiled --export-map json ' + nameTMX + ' ' + nameJSON - print( "TILED COMMAND LINE FOR MAPS : ", commandline ) - os.system( commandline ) - - mapPath = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".json" - print("Map ", i , " name : ", mapPath ) - - xmin = data["maps"][i]["x"] - print( "xmin = ", xmin ) - - ymin = data["maps"][i]["y"] - print( "ymin = ", ymin ) - - xmax = data["maps"][i]["x"] + data["maps"][i]["width"] - print( "xmax = ", xmax ) - - ymax = data["maps"][i]["y"] + data["maps"][i]["height"] - print( "ymax = ", ymax ) - - map = get_tile_map_data( mapPath, output, params, target, xmin, ymin, xmax, ymax) - print( "Map = ", map ) - structWorld += fxconv.ptr( map ) - - structWorld += fxconv.u32(0) - - #generate ! - fxconv.elf(structWorld, output, "_" + params["name"], **target) - - -def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax): - print( "WE ARE COMPUTING THE MAP : ", input ) - data = json.load(open(input, "r")) - - #find the tileset in use. it's a relative path (like ../tileset.tsx) - nameTileset = data["tilesets"][0]["source"].replace(".tsx","") - print(nameTileset) - #the name of the tileset without the .something - nameTilesetFree = nameTileset.split("/")[-1] - #count the number of "back" (cd ..) to locate the tileset on the computer - nbRetour = nameTileset.count("..")+1 - #create the tileset absolute path - tilesetTSX = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".tsx" - tilesetJSON = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".json" - - commandline = 'tiled --export-tileset json ' + tilesetTSX + ' ' + tilesetJSON - print( "TILED COMMAND LINE FOR TILESET : ", commandline ) - os.system( commandline ) - - tileset = open(tilesetJSON, "r") - data_tileset = json.load(tileset) - tileset_size = data_tileset.get("columns") - tileset.close() - - #find the ID of the first tile in the walkable tileset () - indexWalkable = data["tilesets"][1]["firstgid"] - print(indexWalkable) - - #Extract from the json the width, height - w, h = data["width"], data["height"] - - #nbTileLayer is the number of "true" layers (without ObjectsLayer) - nbTilelayer = ["data" in i for i in data["layers"]].count(True) - 1 - print( nbTilelayer) - - #index of the various layers (may change from one map to another) - layer_walkable = 0 - layer_foreground = 0 - layer_background = 0 - - #create the structure of the map - structMap = fxconv.Structure() - - structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer) - structMap += fxconv.u32(tileset_size) - - structMap += fxconv.u32(xmin) + fxconv.u32(ymin) + fxconv.u32(xmax) + fxconv.u32(ymax) - - structMap += fxconv.ref(f"img_{nameTilesetFree}") - - - #extraction of the data contained in the layer "Walkable" of the map - for i in range(nbTilelayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="Walkable": - layer_walkable = i - print( "Walkable Tile Data in layer : ", layer_walkable) - break - elif i==nbTilelayer: - print( "ERROR : No Walkable layer data !!!" ) - - walk_data = bytes() - layer = data["layers"][layer_walkable] - for tile in layer["data"]: - #print( tile ) - if tile == 0: walk_data += fxconv.u8(tile) #if walkable_data = 0 then it is a blanck cell so nothing to change - else : walk_data += fxconv.u8(tile-indexWalkable) #if !=0 than we need to shift the tile number by considering the first tileID (given by indexwalkable) - structMap += fxconv.ptr(walk_data) - - - - - nbextra = 0 - extradata = fxconv.Structure() - - nbextra, extradata = get_extra_map_data(input, output, params, target, xmin, ymin, xmax, ymax) - - if (nbextra==0): - structMap += fxconv.u32( 0 ) - structMap += fxconv.u32( 0 ) - else: - structMap += fxconv.u32( int(nbextra) ) - structMap += fxconv.ptr( extradata ) - - - - - nameDialog = data["properties"][0]["value"] - dialogfile = "/".join(input.split("/")[:-nbRetour]) + "/" + nameDialog - print( "THE DIALOGS ARE CONTAINED IN THE FILE : ", dialogfile ) - - nbdiag = 0 - diagdata = fxconv.Structure() - - nbdiag, diagdata = convert_dialogs(dialogfile, output, params, target) - - if (nbdiag==0): - structMap += fxconv.u32( 0 ) - structMap += fxconv.u32( 0 ) - else: - structMap += fxconv.u32( int(nbdiag) ) - structMap += fxconv.ptr( diagdata ) - - - - #extraction of the data contained in the layer "Background" and "Foreground" of the map - - - #import the Background layer of the map - for i in range(nbTilelayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="Background": - layer_background = i - print( "Background Tile Data in layer : ", layer_background) - break - elif i==nbTilelayer: - print( "ERROR : No Background layer data !!!" ) - - layer_data = bytes() - layer = data["layers"][layer_background] - for tile in layer["data"]: - layer_data += fxconv.u16(tile-1) - structMap += fxconv.ptr(layer_data) - - - - #import the foreground layer of the map - for i in range(nbTilelayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="Foreground": - layer_foreground = i - print( "Foreground Tile Data in layer : ", layer_foreground) - break - elif i==nbTilelayer: - printf( "ERROR : No Foreground layer data !!!" ) - - layer_data = bytes() - layer = data["layers"][layer_foreground] - for tile in layer["data"]: - layer_data += fxconv.u16(tile-1) - structMap += fxconv.ptr(layer_data) - - - return structMap - - - -def get_extra_map_data(input, output, params, target, xmin, ymin, xmax, ymax): - print( "WE ARE COMPUTING THE EXTRA DATA OF THE MAP : ", input ) - data = json.load(open(input, "r")) - - nblayer = ["id" in i for i in data["layers"]].count(True) - 1 - print( "I found ", nblayer, " of extradata") - - #index of the various layers (may change from one map to another) - layer_extradata = 0 - - #import the foreground layer of the map - for i in range(nblayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="ExtraData": - layer_extradata = i - print( "Extra Data in layer : ", layer_extradata) - break - elif i==nblayer: - print( "ERROR : No ExtraData layer data !!!" ) - return 0, fxconv.u32(0) - - #create the structure of the map - structData = fxconv.Structure() - - nbExtraData = 0 - layer = data["layers"][layer_extradata] - for i in layer["objects"]: - - #get the type of the item - tpe = i["type"] - - #we check if the type corresponds to a items of type Point in Tiled - if tpe in ( "SGN", "NPC", "INFO" ): - - nbExtraData = nbExtraData + 1 - x = i["x"] + xmin - y = i["y"] + ymin - nme = i["name"] - - - dialogID = None - needAction = None - path = 0 - path_length = 0 - xdata = None - ydata = None - - #we now fill all the properties of this item - for j in i["properties"]: - #property "dialog" - if j["name"]=="dialogID": dialogID = j[ "value" ] - #property "isQuestion" - elif j["name"]=="needAction": needAction = j[ "value" ] - - else: - #Extra properties for NPCs (path) - if tpe=="NPC": - if j["name"]=="hasPath": - pathID = None - path = j[ "value" ] - if path==1: - print( "PNJ has path - NOW LOOKING FOR RELEVANT DATA" ) - - # we start looking for path data with first the ID of the path Object - for u in i["properties"]: - if u["name"]=="path": - pathID = u[ "value" ] - print( "path ID is identified : ID= ", pathID ) - - for v in layer["objects"]: - if v[ "id" ] == pathID: - print( "path data found : " ) - - xdata = bytes() - ydata = bytes() - - for w in v[ "polyline" ]: - path_length = path_length + 1 - print( "X= ", w[ "x" ], " Y= ", w[ "y" ] ) - xdata += fxconv.u16( int( w[ "x" ] ) ) - ydata += fxconv.u16( int( w[ "y" ] ) ) - - else: - print( "PNJ has no Path" ) - - else: - print( "UNIDENTIFIED PROPERTY : ", j["name"]) - - print( "OBJECT X= ", x, " Y= ", y, "STR= ", dialogID ) - print( " Type= ", tpe, " Name= ", nme ) - print( " Action?= ", needAction ) - - - - structData += fxconv.u32( int(x) ) - structData += fxconv.u32( int(y) ) - structData += fxconv.string( nme ) - structData += fxconv.string( tpe ) - structData += fxconv.u32( int(dialogID) ) - structData += fxconv.u32( int(needAction) ) - - if path==0: - structData += fxconv.u32(0) - structData += fxconv.u32(0) - structData += fxconv.u32(0) - structData += fxconv.u32(0) - else: - o_xdata = fxconv.Structure() - o_xdata += xdata - o_ydata = fxconv.Structure() - o_ydata += ydata - - structData += fxconv.u32(path) - structData += fxconv.u32(path_length) - structData += fxconv.ptr(o_xdata) - structData += fxconv.ptr(o_ydata) - - #else we do nothing (yet) - else: - print( "Skip this object" ) - - - return nbExtraData, structData - - -def convert_custom_image(input, output, params, target): - scale = int(params.get("scale", 1)) - - # Upscale image before converting - im = Image.open(input) - im = im.resize((im.width * scale, im.height * scale), - resample=Image.NEAREST) - - o = fxconv.convert_image_cg(im, params) - fxconv.elf(o, output, "_" + params["name"], **target) - - - -def convert_font(input, output, params, target): - o = fxconv.convert_topti(input, params) - fxconv.elf(o, output, "_" + params["name"], **target) - - - -def convert_dialogs(input, output, params, target): - - print( "WE ARE COMPUTING THE DIALOGS FROM : ", input ) - data = json.load(open(input, "r")) - - structDialogs = fxconv.Structure() - nbdialogs = 0 - - for d in data["dialogs"]: - print( int(d[ "ID" ])) - # print( d[ "dialog" ] ) - print( int(d[ "isQuestion" ]) ) - # print( d[ "choice" ].replace('$', chr(0)) ) - # print( d[ "conclusion1" ] ) - # print( int(d[ "next1" ] ) ) - # print( d[ "conclusion2" ] ) - # print( int(d[ "next2" ] ) ) - # print( int(d[ "nextOther" ]) ) - nbdialogs = nbdialogs + 1 - - structDialogs += fxconv.u32( int(d[ "ID" ] ) ) - structDialogs += fxconv.string( d[ "dialog" ] ) - structDialogs += fxconv.u32( int(d[ "isQuestion" ] ) ) - structDialogs += fxconv.string( d[ "choice" ].replace('$', chr(0)) ) - structDialogs += fxconv.string( d[ "conclusion1" ] ) - structDialogs += fxconv.u32( int(d[ "next1" ] ) ) - structDialogs += fxconv.string( d[ "conclusion2" ] ) - structDialogs += fxconv.u32( int(d[ "next2" ] ) ) - structDialogs += fxconv.u32( int(d[ "nextOther" ] ) ) - - return nbdialogs, structDialogs - - #fxconv.elf(structDialogs, output, "_" + params["name"], **target) \ No newline at end of file +import sys +# Add the assets folder to the path, to be able to import the tiled script. +sys.path.append("../assets/") +import fxconv +from tinytiled import * + +# If the output of the converter should be verbose. +VERBOSE = 1 +# The sign types, used to find the sign icon. +SIGN_TYPES = ["SGN", "INFO"] +# The NPC faces, used to find the face id. +FACES = ["MALE", "FEMALE", "MILKMAN", "POLICE"] +# The precision of the fixed point numbers. +# WARNING: The PRECISION define in config.h should contain the same value! +PRECISION = 8 + +def convert(input: str, output: str, params: dict, target): + """ + This method gets called by fxconv for each asset to convert. + """ + if params["custom-type"] == "tmx": + convert_map(input, output, params, target) + return 0 + elif params["custom-type"] == "dialog": + convert_dialog(input, output, params, target) + return 0 + +def convert_map(input: str, output: str, params: dict, target): + """ + Convert a map. + """ + if VERBOSE: print(f"INFO: Converting map {input} -> {output}") + input_map = Map(input) + dialog_file = "" + background_layer = [] + foreground_layer = [] + walkable_layer = [] + map_x = 0 + map_y = 0 + width = 0 + height = 0 + outdoor_tileset = None + walkable_tileset = None + dialog_num = 0 + dialog_ids = [] + + npc_paths = {} + npcs = {} + signs = {} + portals = {} + + name = os.path.splitext(os.path.basename(input))[0] + + map_struct = fxconv.Structure() + + # Get the dialog file + try: + if VERBOSE: print("INFO: Getting the dialog file") + dialog_file = input_map.get_property("dialogFile") + if VERBOSE: print(f"INFO: Dialog file: {dialog_file}.") + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the dialog file.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the map position + try: + if VERBOSE: print("INFO: Getting the map position") + map_x = int(input_map.get_property("mapX")) + map_y = int(input_map.get_property("mapY")) + if VERBOSE: print(f"INFO: Map position: ({map_x}, {map_y}).") + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the map position.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get informations about dialogs + try: + if VERBOSE: print("INFO: Getting informations about dialogs") + with open(f"{input_map.parent_dir}/{dialog_file}", "r") as file: + dialog_data = json.load(file) + dialog_num = len(dialog_data["dialogs"]) + for i in dialog_data["dialogs"]: + dialog_ids.append(i["ID"]) + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get informations about dialogs.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the outdoor tileset + try: + if VERBOSE: print("INFO: Getting the outdoor tileset") + outdoor_tileset = input_map.get_tileset_by_firstgid(1) + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the outdoor tileset.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the walkable tileset + try: + if VERBOSE: print("INFO: Getting the walkable tileset") + walkable_tileset = input_map.get_tileset_by_firstgid(409) + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the walkable tileset.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the background + try: + if VERBOSE: print("INFO: Getting the background layer") + bg_layer = input_map.get_layer_by_name("Background") + # The bg layer will be used to set the map width and height. + width = bg_layer.get_width() + height = bg_layer.get_height() + if VERBOSE: print(f"INFO: Map size: ({width}, {height}).") + # Get the layer data himself + background_layer = bg_layer.get_data_with_tileset(outdoor_tileset) + # Check if the size of the layer data is correct. + if len(background_layer) != width*height: + raise Exception("Bad layer size!") + if VERBOSE: print("INFO: Layer data has the right size.") + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the background layer.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the foreground + try: + if VERBOSE: print("INFO: Getting the foreground layer") + fg_layer = input_map.get_layer_by_name("Foreground") + # Get the layer data himself + foreground_layer = fg_layer.get_data_with_tileset(outdoor_tileset) + # Check if the size of the layer data is correct. + if len(foreground_layer) != width*height: + raise Exception("Bad layer size!") + if VERBOSE: print("INFO: Layer data has the right size.") + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the foreground layer.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the walkable layer + try: + if VERBOSE: print("INFO: Getting the walkable layer") + wk_layer = input_map.get_layer_by_name("Walkable") + # Get the layer data himself + walkable_layer = wk_layer.get_data_with_tileset(walkable_tileset) + # Check if the size of the layer data is correct. + if len(walkable_layer) != width*height: + raise Exception("Bad layer size!") + if VERBOSE: print("INFO: Layer data has the right size.") + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the walkable layer.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the extra data + try: + if VERBOSE: print("INFO: Getting the extra data") + ed_objgroup = input_map.get_objectgroup_by_name("ExtraData") + # Get the paths the NPCs take. + for object in ed_objgroup.objects: + if object.get_data_type() == "polyline": + npc_paths[object.id] = object.get_data() + # Get the NPCs + for object in ed_objgroup.objects: + if object.get_data_type() == "point" and object.type == "NPC": + path = [0, 0] + if int(object.get_property("hasPath")): + if object.get_property("path") in npc_paths: + path = npc_paths[object.get_property("path")] + else: + raise Exception("Path required but not found!") + dialog_id = 0 + has_dialog = 0 + try: + dialog_id = int(object.get_property("dialogID")) + has_dialog = 1 + except: + pass + data = { + "position": object.get_data(), + "name": object.name, + "needAction": int(object.get_property("needAction")), + "dialogID": dialog_id, + "hasDialog": has_dialog, + "face": FACES.index(object.get_property("face")), + "path": path + } + npcs[object.id] = data + # Get the signs + for object in ed_objgroup.objects: + if object.get_data_type() == "point" and object.type in SIGN_TYPES: + data = { + "position": object.get_data(), + "name": object.name, + "needAction": int(object.get_property("needAction")), + "dialogID": int(object.get_property("dialogID")), + "icon": SIGN_TYPES.index(object.type) + } + signs[object.id] = data + # Get the portals + for object in ed_objgroup.objects: + if (object.get_data_type() == "rectangle" + and object.type == "PORTAL"): + data = { + "rect": object.get_data(), + "name": object.name, + "dest": object.get_property("dest"), + "destPortal": object.get_property("destPortal") + } + portals[object.id] = data + except Exception as e: + # Show a simple error message on failure. + sys.stderr.write(f"ERROR: Failed to get the extra data.\n" + + f" Error message: {e}\n") + sys.exit(1) + # Generate the structs + # Map struct + map_struct += fxconv.u32(map_x) + map_struct += fxconv.u32(map_y) + map_struct += fxconv.u32(width) + map_struct += fxconv.u32(height) + map_struct += fxconv.u32(3) + map_struct += fxconv.u32(outdoor_tileset.columns) + tileset_name = os.path.splitext(os.path.basename(outdoor_tileset.source))[0] + map_struct += fxconv.ref(f"img_{tileset_name}") + + # Store the walkable layer + walkable_data = bytes() + for i in walkable_layer: + if i < 0: i = 0 + walkable_data += fxconv.u8(i) + map_struct += fxconv.ptr(walkable_data) + + # Load NPCs + map_struct += fxconv.u32(len(npcs)) + npc_struct = fxconv.Structure() + for i in npcs.values(): + # Convert currentpos to a fixed point value. + npc_struct += fxconv.u32((i["position"][0]+i["path"][0])< 2) + npc_struct += fxconv.u32(len(i["path"])//2) + npc_struct += fxconv.u32(0) + + xpath = bytes() + ypath = bytes() + x = True + for n in i["path"]: + if x: xpath += fxconv.u16(n) + else: ypath += fxconv.u16(n) + x = not x + + npc_struct += fxconv.ptr(xpath) + npc_struct += fxconv.ptr(ypath) + + npc_struct += fxconv.u32(0) # TODO: Type + npc_struct += fxconv.u8(0) # TODO: Group + npc_struct += fxconv.u8(0) # TODO: Hostile to + npc_struct += fxconv.u16(0) # TODO: Padding (what is it ?) + map_struct += fxconv.ptr(npc_struct) + # Load signs + map_struct += fxconv.u32(len(signs)) + sign_struct = fxconv.Structure() + for i in signs.values(): + # Create a sign struct for each sign. + sign_struct += fxconv.u32(i["position"][0]) + sign_struct += fxconv.u32(i["position"][1]) + sign_struct += fxconv.u32(i["icon"]) + sign_struct += fxconv.string(i["name"]) + sign_struct += fxconv.u32(i["dialogID"]) + sign_struct += fxconv.u32(i["needAction"]) + map_struct += fxconv.ptr(sign_struct) + # Load portals + map_struct += fxconv.u32(len(portals)) + portal_struct = fxconv.Structure() + for i in portals.values(): + dest_file_name = os.path.splitext(os.path.basename(i["dest"]))[0] + dest_portal = i["destPortal"] + portal_name = i["name"] + if VERBOSE: print(f"INFO: Storing portal {name}_{portal_name}") + portal_struct += fxconv.sym(f"{name}_{portal_name}") + # Add the collider + rect = i["rect"] + portal_struct += fxconv.u32(rect[0]) + portal_struct += fxconv.u32(rect[1]) + portal_struct += fxconv.u32(rect[2]) + portal_struct += fxconv.u32(rect[3]) + # Add a reference to the destination portal + portal_struct += fxconv.ref(f"{dest_file_name}_{dest_portal}") + portal_struct += fxconv.ref(f"{dest_file_name}") + map_struct += fxconv.ptr(portal_struct) + map_struct += fxconv.u32(dialog_num) + + # Get the name of the dialog file and create a reference to it: it is built + # separately. + dialog_name = os.path.splitext(os.path.basename(dialog_file))[0] + map_struct += fxconv.ref(f"_{dialog_name}") + + # Store the background layer + background_data = bytes() + for i in background_layer: + background_data += fxconv.u16(i) + map_struct += fxconv.ptr(background_data) + + # Store the foreground layer + foreground_data = bytes() + for i in foreground_layer: + foreground_data += fxconv.u16(i) + map_struct += fxconv.ptr(foreground_data) + + # Create the fxconv object + fxconv.elf(map_struct, output, f"_{name}", **target) + +def convert_dialog(input: str, output: str, params: dict, target): + """ + Convert a JSON dialog file. + """ + if VERBOSE: print(f"INFO: Converting dialog file {input} -> {output}") + + # Load the JSON dialog file. + dialog_data = None + try: + with open(input, "r") as file: + dialog_data = json.load(file) + except Exception as e: + sys.stderr.write(f"ERROR: Failed parse json.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Create the dialog struct + dialog_struct = fxconv.Structure() + try: + for i in dialog_data["dialogs"]: + # Create a dialog structure for each dialog. + dialog_id = i["ID"] + dialog_struct += fxconv.u32(dialog_id) + dialog_struct += fxconv.string(i["dialog"]) + dialog_struct += fxconv.u32(i["isQuestion"]) + dialog_struct += fxconv.string(i["choice"].replace('$', '\0')) + dialog_struct += fxconv.string(i["conclusion1"]) + dialog_struct += fxconv.u32(i["next1"]) + dialog_struct += fxconv.string(i["conclusion2"]) + dialog_struct += fxconv.u32(i["next2"]) + dialog_struct += fxconv.u32(i["nextOther"]) + # Save this struct + name = os.path.splitext(os.path.basename(input))[0] + fxconv.elf(dialog_struct, output, f"__{name}", **target) + except Exception as e: + # Show an error message if the conversion fails. + sys.stderr.write(f"ERROR: Failed convert dialogs.\n" + + f" Error message: {e}\n") + sys.exit(1) diff --git a/assets/fxconv-metadata.txt b/assets/fxconv-metadata.txt index 822cad1..9a82591 100644 --- a/assets/fxconv-metadata.txt +++ b/assets/fxconv-metadata.txt @@ -1,7 +1,47 @@ -WorldRPG.world: - custom-type: world - name: worldRPG +level0.tmx: + custom-type: tmx + name: level0 -#DialogsRPG.json: -# custom-type: dialogs -# name: dialogRPG +level1.tmx: + custom-type: tmx + name: level1 + +level2.tmx: + custom-type: tmx + name: level2 + +level3.tmx: + custom-type: tmx + name: level3 + +level4.tmx: + custom-type: tmx + name: level4 + +level0_dialogs.json: + custom-type: dialog + name: level0_dialogs + +level1_dialogs.json: + custom-type: dialog + name: level1_dialogs + +level2_dialogs.json: + custom-type: dialog + name: level2_dialogs + +level3_dialogs.json: + custom-type: dialog + name: level3_dialogs + +level4_dialogs.json: + custom-type: dialog + name: level4_dialogs + +interior1_0.tmx: + custom-type: tmx + name: level0 + +interior1_0_dialogs.json: + custom-type: dialog + name: interior1_0_dialogs diff --git a/assets/interior1_0.tmx b/assets/interior1_0.tmx new file mode 100644 index 0000000..cca09fa --- /dev/null +++ b/assets/interior1_0.tmx @@ -0,0 +1,54 @@ + + + + + + + + + + + +86,90,91,89,90,91,89,90,91,89,90,92, +110,114,115,113,114,115,113,114,115,113,114,116, +86,93,94,1,1,1,1,1,9,10,1,92, +110,117,118,1,1,1,1,1,33,34,1,116, +86,1,1,1,1,1,1,1,1,1,1,92, +110,1,1,1,1,133,2,1,1,1,1,116, +110,1,1,1,1,2,2,1,1,1,1,92, +110,114,114,114,114,114,114,114,114,114,114,116 + + + + +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0 + + + + +410,410,410,410,410,410,410,410,410,410,410,410, +410,410,410,410,410,410,410,410,410,410,410,410, +410,410,410,0,0,0,0,0,410,0,0,410, +410,410,410,0,0,0,0,0,410,0,0,410, +410,0,0,0,0,0,0,0,0,0,0,410, +410,0,0,0,0,0,0,0,0,0,0,410, +410,0,0,0,0,0,0,0,0,0,0,410, +410,410,410,410,410,410,410,410,410,410,410,410 + + + + + + + + + + + diff --git a/assets/interior1_0_dialogs.json b/assets/interior1_0_dialogs.json new file mode 100644 index 0000000..f503523 --- /dev/null +++ b/assets/interior1_0_dialogs.json @@ -0,0 +1,13 @@ +{ "dialogs":[ + { "ID":0, + "dialog":"_", + "isQuestion":0, + "choice":"_", + "conclusion1":"_", + "next1":-1, + "conclusion2":"_", + "next2":-1, + "nextOther":1 + } + ] +} diff --git a/assets/level0.tmx b/assets/level0.tmx index 4cf2838..6bc62a8 100644 --- a/assets/level0.tmx +++ b/assets/level0.tmx @@ -1,32 +1,34 @@ - + - + + + 2,297,298,299,300,2,386,297,298,299,300,2,2,2,2,2,2,337,338,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,2,2,2,345,346,347,348,2,337,338, -253,205,229,205,229,280,179,180,179,156,156,156,158,157,179,180,253,361,362,2,2,2,2,2,2,2,2,297,298,299,300,2,2,2,2,25,26,27,117,118,28,369,370,371,372,2,361,362, -301,2,2,2,2,2,385,2,2,2,2,2,2,2,2,2,301,2,386,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,49,9,10,134,135,52,393,394,395,396,337,338,2, -325,149,150,151,152,2,2,327,374,375,327,2,2,185,374,375,325,387,2,297,298,299,300,2,2,2,2,2,2,2,2,2,2,2,2,73,33,34,74,219,76,2,2,2,2,361,362,2, -257,2,2,385,2,2,385,2,265,266,2,2,208,209,352,353,257,2,2,2,2,2,2,297,298,299,300,2,2,2,2,25,26,27,27,97,98,99,98,99,100,26,26,27,28,131,2,2, -281,176,2,2,2,2,176,385,289,290,2,2,232,233,376,377,281,2,326,2,154,153,190,2,2,2,2,2,2,2,2,49,2,2,2,121,59,60,60,61,124,2,2,2,52,132,2,2, -2,2,2,2,2,385,2,2,265,266,2,385,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,73,2,2,2,145,83,84,84,85,148,2,2,2,76,132,2,2, -2,2,2,2,326,2,385,2,265,266,2,2,2,2,2,2,2,2,2,2,2,2,190,2,2,2,2,2,2,385,2,49,404,405,2,169,107,108,108,109,172,2,402,403,76,132,2,2, -2,2,2,2,2,2,2,2,289,290,2,258,259,260,238,239,260,260,261,262,262,263,264,2,2,2,2,2,2,2,385,49,134,135,2,2,2,2,2,2,2,2,134,135,52,132,297,298, -2,2,2,2,2,2,2,2,265,266,2,282,283,284,285,285,285,285,285,285,286,287,288,297,298,299,300,2,117,118,2,73,373,2,217,2,190,373,373,190,2,219,2,373,76,132,2,2, -297,298,299,300,2,2,2,2,290,2,2,306,307,308,309,308,309,308,309,310,310,311,312,131,2,339,340,2,134,135,2,97,98,99,99,98,99,2,2,98,98,99,98,99,100,132,2,2, +253,205,229,205,229,280,179,180,179,156,156,156,158,157,179,180,253,361,362,2,2,2,2,2,2,2,2,297,298,299,300,2,2,2,2,25,358,359,117,118,28,369,370,371,372,2,361,362, +301,2,2,2,2,2,385,2,2,2,2,2,2,2,2,2,301,2,386,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,382,9,10,134,135,360,393,394,395,396,337,338,2, +325,149,150,151,152,2,2,327,374,375,327,2,2,185,374,375,325,387,2,297,298,299,300,2,2,2,2,2,2,2,2,2,2,2,2,406,33,34,2,219,384,2,2,2,2,361,362,2, +257,2,2,385,2,2,385,2,265,266,2,2,208,209,352,353,257,2,2,2,2,2,2,297,298,299,300,2,2,2,2,25,358,359,358,97,407,408,407,408,100,358,358,359,28,131,2,2, +281,176,2,2,2,2,176,385,289,290,2,2,232,233,376,377,281,2,326,2,154,153,190,2,2,2,2,2,2,2,2,382,2,2,2,121,59,60,60,61,124,2,2,2,360,132,2,2, +2,2,2,2,2,385,2,2,265,266,2,385,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,406,2,2,2,145,83,84,84,85,148,2,2,2,384,132,2,2, +2,2,2,2,326,2,385,2,265,266,2,2,2,2,2,2,2,2,2,2,2,2,190,2,2,2,2,2,2,385,2,406,404,405,2,169,107,108,108,109,172,2,402,403,384,132,2,2, +2,2,2,2,2,2,2,2,289,290,2,258,259,260,238,239,260,260,261,262,262,263,264,2,2,2,2,2,2,2,385,382,134,135,2,2,2,2,2,2,2,2,134,135,360,132,297,298, +2,2,2,2,2,2,2,2,265,266,2,282,283,284,285,285,285,285,285,285,286,287,288,297,298,299,300,2,117,118,2,382,373,2,217,2,190,373,373,190,2,219,2,373,384,132,2,2, +297,298,299,300,2,2,2,2,290,2,2,306,307,308,309,308,309,308,309,310,310,311,312,131,2,339,340,2,134,135,2,97,407,408,408,408,408,19,18,407,408,408,407,408,100,132,2,2, 2,2,2,386,2,2,2,2,2,2,2,330,331,332,333,332,333,332,333,334,334,335,336,132,2,363,364,2,2,2,2,121,122,122,122,123,124,81,82,121,122,123,122,123,124,132,2,2, 2,2,2,386,297,298,299,300,2,290,2,162,163,164,165,162,163,164,165,162,163,164,165,132,2,2,2,2,2,2,2,145,146,146,146,147,148,57,58,145,146,147,146,147,148,132,2,2, -2,2,2,2,2,2,2,2,2,2,2,86,87,88,89,186,187,188,189,86,87,88,89,132,385,2,2,2,2,2,2,169,170,170,170,171,172,81,82,169,170,171,14,15,27,26,27,27, -2,2,2,2,270,271,271,271,272,2,2,110,111,112,113,210,211,212,213,110,111,112,113,133,2,2,2,2,2,2,2,2,2,2,2,2,2,290,265,265,266,266,38,39,2,2,2,51, -298,299,300,2,294,1,1,1,296,2,2,2,2,2,2,234,290,265,237,2,2,2,339,340,385,2,2,2,2,2,2,327,2,2,2,160,161,386,266,289,290,265,62,63,73,74,75,75, -2,2,2,2,294,1,1,1,296,2,2,160,161,265,266,266,265,266,290,2,2,2,363,364,2,297,298,299,300,2,2,2,2,2,2,2,2,266,290,2,2,2,2,2,97,98,99,99, +2,2,2,2,2,2,2,2,2,2,2,86,87,88,89,186,187,188,189,86,87,88,89,132,385,2,2,2,2,2,2,169,170,170,170,171,172,81,82,169,170,171,14,15,42,358,359,359, +2,2,2,2,270,271,271,271,272,2,2,110,111,112,113,210,211,212,213,110,111,112,113,133,2,2,2,2,2,2,2,2,2,2,2,2,2,290,265,265,266,266,38,39,19,2,2,2, +298,299,300,2,294,1,1,1,296,2,2,2,2,2,2,234,290,265,237,2,2,2,339,340,385,2,2,2,2,2,2,327,2,2,2,160,161,386,266,289,290,265,62,63,406,2,2,2, +2,2,2,2,294,1,1,1,296,2,2,160,161,265,266,266,265,266,290,2,2,2,363,364,2,297,298,299,300,2,2,2,2,2,2,2,2,266,290,2,2,2,2,2,97,407,408,408, 2,2,2,2,318,319,319,319,320,2,386,266,266,289,290,265,266,241,265,266,266,265,266,241,385,2,2,2,241,265,266,266,265,386,265,266,266,265,266,2,2,2,2,2,121,122,123,123, 2,2,2,2,2,2,2,2,2,385,289,290,386,265,265,2,2,241,289,290,265,266,290,266,265,266,266,386,266,289,290,265,266,290,289,385,265,266,290,2,2,2,2,2,145,146,147,147, 2,2,2,2,2,2,2,2,2,2,2,2,2,265,386,2,2,2,2,2,2,2,241,241,289,290,265,266,290,241,2,2,2,2,2,2,21,22,23,24,2,2,254,255,169,170,171,171, @@ -68,28 +70,28 @@ 0,0,410,410,0,0,0,0,410,410,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,410,410,410,410,0,410,410, 410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,410,410, -410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,410,0,0,0,0,410,410,410,410,410,410,410,0, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,410,0,0,0,0,410,410,410,410,410,410,410,0, 410,410,410,410,410,0,0,410,410,410,410,0,0,0,410,410,410,410,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,410,410,0, -410,0,0,0,0,0,0,0,0,0,0,0,410,411,411,411,410,0,0,0,0,0,0,0,410,410,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0, +410,0,0,412,0,0,0,0,0,0,0,0,410,411,411,411,410,0,0,0,0,0,0,0,410,410,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0, 410,0,0,0,0,0,0,0,0,0,0,0,411,411,411,411,410,0,410,0,410,410,410,0,0,0,0,0,0,0,0,410,0,0,0,410,410,410,410,410,410,0,0,0,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,410,0,0,0,410,410,410,410,410,410,0,0,0,410,0,0,0, -0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,410,410,0,410,410,0,0,410,410,0,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,410, +0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,410,0,0,0,410,410,410,410,410,410,0,0,0,410,0,0,0, +0,0,0,0,410,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,412,0,410,410,410,0,410,410,0,0,410,410,0,410,410,410,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,412,410,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,410, 0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,410,410,0,0,410,410,0,410,0,0,0,0,410,0,0,410,0,0,0,0,410,0,0,0, 0,410,410,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,0,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,410,410,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,0,0,410,410,410, +0,0,0,412,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,410,410,0,0,0, +0,0,0,412,0,410,410,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,410,410,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,412,0,0,0,0,0,0,410,410,410,410,410,410,0,0,410,410,410,410,0,0,410,410,410, 0,0,0,0,412,412,412,412,412,0,0,410,410,410,410,410,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -410,410,0,0,412,412,412,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,410,0,0,0,410,410,0,0,0,0,0,0,410,0,0,0,0, +410,410,0,0,412,412,412,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,412,0,0,0,0,0,0,410,0,0,0,410,410,0,0,0,0,0,0,410,410,0,0,0, 0,0,0,0,412,412,412,412,412,0,0,410,410,0,0,0,0,0,0,0,0,0,410,410,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410, 0,0,0,0,412,412,412,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,410,410,410,410,410,410, 410,410,0,0,0,0,0,410,410,410,410,410,0,0,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,410,410,410,410,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,0,0,0,0,0,0,0, +0,0,412,0,0,0,0,410,410,410,410,410,0,0,0,0,410,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,410,410,410,410,410,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,410,410,0,410,410,410,410,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,410,410,0,410,410,410,410,410,0,0,0,0,410,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0 @@ -117,6 +119,7 @@ + @@ -126,6 +129,7 @@ + @@ -135,6 +139,7 @@ + @@ -168,5 +173,11 @@ + + + + + + diff --git a/assets/DialogsLvl0.json b/assets/level0_dialogs.json similarity index 100% rename from assets/DialogsLvl0.json rename to assets/level0_dialogs.json diff --git a/assets/level1.tmx b/assets/level1.tmx index c3af03c..4166a9a 100644 --- a/assets/level1.tmx +++ b/assets/level1.tmx @@ -1,7 +1,9 @@ - + - + + + @@ -20,10 +22,10 @@ 2,2,269,1,1,1,1,1,1,319,319,269,1,1,1,316,271,316,271,317,1,1,1,1,319,319,319,268,268,319,319,319,268,319,320,2,2,318,319,320,268,269,1,1,1,1,1,1, 2,2,2,269,1,1,1,1,320,2,2,2,269,1,1,1,1,1,1,1,1,1,267,2,2,2,2,2,2,2,2,2,2,2,2,2,2,219,2,2,2,318,319,320,269,1,1,1, 2,2,2,2,319,268,319,320,2,2,2,2,318,319,269,1,1,1,1,1,1,267,2,2,2,2,313,265,242,266,241,219,314,313,242,241,2,2,219,2,2,2,2,2,2,269,1,1, -27,26,27,26,27,28,2,2,2,2,2,2,2,2,318,319,319,268,268,319,319,320,2,2,2,219,2,2,2,2,266,241,289,290,266,265,2,2,2,297,298,299,300,2,2,318,319,320, -2,50,51,51,99,100,132,2,2,2,2,2,2,2,2,2,2,2,2,314,265,2,2,2,2,313,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,74,75,76,16,17,133,2,2,2,2,2,2,2,2,2,2,2,241,219,290,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -98,98,99,100,40,41,290,314,297,298,299,300,2,2,2,2,2,219,219,289,2,297,298,299,300,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,2, +359,358,359,358,359,28,2,2,2,2,2,2,2,2,318,319,319,268,268,319,319,320,2,2,2,219,2,2,2,2,266,241,289,290,266,265,2,2,2,297,298,299,300,2,2,318,319,320, +2,2,2,18,407,100,132,2,2,2,2,2,2,2,2,2,2,2,2,314,265,2,2,2,2,313,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,42,16,17,133,2,2,2,2,2,2,2,2,2,2,2,241,219,290,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +408,407,407,408,40,41,290,314,297,298,299,300,2,2,2,2,2,219,219,289,2,297,298,299,300,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,2, 121,122,123,124,64,65,265,289,313,289,241,265,219,2,2,2,2,290,314,2,2,2,2,2,2,2,297,298,299,300,2,2,2,2,402,403,2,374,375,2,404,405,2,2,2,2,2,2, 145,146,147,148,132,2,2,2,2,2,2,314,314,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 169,170,171,172,133,2,2,2,2,2,2,2,2,297,298,299,300,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,385,2,2,2,2,2,2,2,2,2,2,2,2, @@ -79,13 +81,13 @@ 410,410,410,410,410,410,0,0,0,0,0,0,0,0,412,412,412,412,412,412,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,412,412,412, 0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0, +410,410,409,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0, 410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,410,410,0,410,410,0,410,410,0,0,0,0,0,0, 410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -410,410,410,410,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,410,410,0, +410,410,410,410,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,410,410,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @@ -100,13 +102,14 @@ + - + diff --git a/assets/DialogsLvl1.json b/assets/level1_dialogs.json similarity index 100% rename from assets/DialogsLvl1.json rename to assets/level1_dialogs.json diff --git a/assets/level2.tmx b/assets/level2.tmx index 3592373..293ef64 100644 --- a/assets/level2.tmx +++ b/assets/level2.tmx @@ -1,7 +1,9 @@ - + - + + + @@ -11,13 +13,13 @@ 2,2,2,2,2,386,2,2,2,2,2,277,2,386,266,2,349,385,385,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,2,2,2, 298,299,300,2,2,2,2,385,385,2,2,301,2,266,290,2,349,2,385,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,386,2,2,256,2,265,266,2,257,2,2,2,2,2,2,2,2,2,2,2,297,298,299,300,297,298,299,258,259,262,330,333,333,336,262,263,264,2,2,2, -2,2,2,2,2,2,2,2,386,386,2,281,2,266,290,2,280,2,2,2,2,2,2,2,2,2,386,2,2,2,2,2,2,2,2,283,283,3,91,87,88,92,3,312,288,2,385,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,290,266,2,2,2,385,2,297,298,299,300,2,2,2,2,2,2,2,9,10,2,2,283,283,3,115,111,112,113,3,312,312,131,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,386,266,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,34,385,2,283,283,3,114,114,115,114,3,312,312,132,385,2, -2,386,2,2,2,2,2,2,2,2,2,2,2,313,290,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,282,283,3,3,3,3,3,3,312,288,132,2,2, -2,2,2,297,298,299,300,2,345,346,347,348,2,265,266,2,2,374,375,151,152,149,150,151,152,149,150,374,375,149,150,151,152,2,2,282,283,3,3,3,3,3,3,287,288,132,2,2, -2,2,2,2,2,2,2,386,369,370,371,372,2,266,290,208,209,352,353,2,2,385,2,2,2,2,385,2,2,2,2,2,2,2,2,282,283,3,3,3,3,3,3,312,312,132,2,2, -2,2,2,2,2,2,386,2,393,394,395,396,2,290,266,232,233,376,377,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,282,283,3,3,3,3,3,3,312,288,132,2,2, +2,2,2,2,2,2,2,2,386,386,2,281,2,266,290,2,280,2,2,2,2,2,2,2,2,2,386,2,2,2,2,2,2,2,2,283,283,5,91,87,88,92,5,312,288,2,385,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,290,266,2,2,2,385,2,297,298,299,300,2,2,2,2,2,2,2,9,10,2,2,283,283,5,115,111,112,113,5,312,312,131,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,386,266,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,34,385,2,283,283,5,114,114,115,114,5,312,312,132,385,2, +2,386,2,2,2,2,2,2,2,2,2,2,2,313,290,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,282,283,5,5,5,5,5,5,312,288,132,2,2, +2,2,2,297,298,299,300,2,345,346,347,348,2,265,266,2,2,374,375,151,152,149,150,151,152,149,150,374,375,149,150,151,152,2,2,282,283,5,5,5,5,5,5,287,288,132,2,2, +2,2,2,2,2,2,2,386,369,370,371,372,2,266,290,208,209,352,353,2,2,385,2,2,2,2,385,2,2,2,2,2,2,2,2,282,283,5,5,5,5,5,5,312,312,132,2,2, +2,2,2,2,2,2,386,2,393,394,395,396,2,290,266,232,233,376,377,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,282,283,5,5,5,5,5,5,312,288,132,2,2, 2,2,2,2,2,385,2,2,2,2,2,2,2,386,313,2,2,149,149,374,375,149,150,151,152,374,375,151,152,149,150,151,152,2,2,282,330,308,308,308,308,308,308,311,312,132,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,266,290,2,2,2,2,2,2,2,2,2,2,385,2,2,385,2,2,2,2,2,2,330,331,331,331,331,331,331,331,331,336,132,2,2, 2,297,298,299,300,2,2,2,2,2,2,2,2,265,266,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,90,91,92,162,163,164,165,90,91,92,132,2,2, @@ -37,7 +39,7 @@ 250,251,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,297,298,299,300,0,0,0,225,226,227,228,225,226,227,228,0,0,0,0,0,273,274,275,276,0,0,0, 274,275,276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,201,202,203,204,0,0,0,0,249,250,251,252,249,250,251,252,0,0,258,259,263,264,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,225,226,227,228,0,0,0,0,273,274,275,276,273,274,275,276,0,0,282,3,3,288,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,225,226,227,228,0,0,0,0,273,274,275,276,273,274,275,276,0,0,282,307,311,288,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,250,251,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,201,202,203,204,0,0,0,0,0,0,0,0,0,0,0,0,0,273,274,275,276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,225,226,227,228,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -63,30 +65,30 @@ -0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410, -0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0, -410,410,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, +0,0,0,0,412,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410, +0,0,0,0,0,412,0,0,0,0,0,410,0,0,0,0,410,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0, +410,410,0,0,0,0,0,412,412,0,0,410,0,0,0,0,410,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,412,0,0,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0, +0,0,0,0,0,0,0,0,412,412,0,410,0,0,0,0,410,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,412,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,412,0, +0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, 0,0,0,0,410,410,0,0,410,410,410,410,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,410,411,411,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,411,411,411,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, +0,0,0,0,0,0,0,412,410,410,410,410,0,0,0,410,411,411,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, +0,0,0,0,0,0,412,0,410,410,410,410,0,0,0,411,411,411,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, +0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, 0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,410,410,410,410,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,410,410,410,410,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,412,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,410,410,410,410,0,0,0, +0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0, +0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,412,0,0,0,0,0,0,0,0,0,0,0,410,410,412,0,0,0,0,0,0,412,412,0, +0,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,410,410,410,410,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,410,410,410,410,0,0,0,412,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,412,412,412,0,0,0,412,0,0,0,0,0,412,0,0,412,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/assets/DialogsLvl2.json b/assets/level2_dialogs.json similarity index 100% rename from assets/DialogsLvl2.json rename to assets/level2_dialogs.json diff --git a/assets/level3.tmx b/assets/level3.tmx index 17705ee..4f722ef 100644 --- a/assets/level3.tmx +++ b/assets/level3.tmx @@ -1,7 +1,9 @@ - + - + + + @@ -30,7 +32,7 @@ 289,290,265,266,290,2,2,2,2,2,2,2,2,265,266,2,110,111,112,114,114,111,112,210,211,212,213,116,133,2,2,2,2,2,2,2,2,2,2,386,2,2,45,46,47,48,2,2, 2,2,2,2,2,2,2,2,2,386,2,2,2,265,266,2,2,2,2,2,2,2,2,2,265,266,2,2,2,2,345,346,347,348,2,339,340,2,2,2,2,2,69,70,71,72,2,2, 2,297,298,299,300,2,2,339,340,2,2,2,2,289,290,266,265,266,266,265,386,265,266,266,289,290,2,160,161,2,369,370,371,372,2,363,364,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,386,2,2,363,364,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,385,2,393,394,395,396,2,2,2,2,2,2,2,387,2,2,2,386,2,2 +2,2,2,2,386,2,2,363,364,2,2,2,2,2,2,2,2,2,2,2,265,265,2,2,2,2,2,2,385,2,393,394,395,396,2,2,2,2,2,2,2,387,2,2,2,386,2,2 @@ -64,29 +66,29 @@ 0,0,0,0,410,410,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,0,410,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,0,410,410, -410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,410,410, -410,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0, -410,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,410,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0, -410,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,410,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,412,0,0,410,410,0,0,0,0,410,0,0,412,0,0,412,0,410,410,410,410,410,410,410,410,410,410,0,410,410, +410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,410,410, +410,412,412,412,0,412,412,412,412,0,412,412,412,412,410,0,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0, +410,412,412,412,0,412,412,412,412,0,412,412,412,412,410,0,410,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0, +410,412,412,412,0,412,412,412,412,0,412,412,412,412,410,0,410,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,0, 410,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,410,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,410,0,0,410,410,410,410,0,0,410,0,0,0, 410,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,410,0,0,0,0,0,0,0,0,0,410,0,0,0,410,410,0,0,0,410,410,410,410,0,0,410,410,410,410,0,0,0, -410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,410,410,410,410,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,410,410,410,410,410,410,410,410,0,410,410,410,410,0,410,410,410,410,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,0,0,410, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,410,410,410,410,0,0,0,410,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,410,410,410,410,410,410,410,410,0,410,410,410,410,0,410,410,410,410,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,412,0,0,410, 0,0,410,0,0,0,0,0,0,410,0,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,410,0,0,0,0,0,0,410,0,410,410,410,410,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0, +0,0,410,0,0,0,0,0,0,410,0,410,410,410,410,0,0,0,0,0,0,412,410,410,0,412,0,0,0,0,0,0,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,0, 0,0,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0, 0,0,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0, 0,0,410,0,0,410,410,410,410,410,0,0,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0, 0,0,410,410,410,410,0,0,410,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,0,0,0,0,410,0,0,0,0,410,410,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,410,410,410,0,0,410,410,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,412,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0, +0,0,0,412,0,0,0,0,410,410,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,410,410,410,410,0,0,410,410,0,0,0,0,0,0,412,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,410,410,410,410,410,0,0,0,0,0,0,0,0,0,0,0,410,410,0,410,410,410,410,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,410,410,0,0,0,0,0,410,410,410,410,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,410,410,410,410,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,412,0,0,410,410,410,410,0,0, +0,0,0,0,0,0,0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,410,410,0,0,0,0,0,410,410,410,410,0,0, 0,0,410,410,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,0,410,410,410,410,0,410,410,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,0,0,0,0,0,410,0,0,0,0,0,0 +0,0,0,0,412,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,0,410,410,410,410,0,0,0,0,0,0,0,410,0,0,0,412,0,0 diff --git a/assets/DialogsLvl3.json b/assets/level3_dialogs.json similarity index 100% rename from assets/DialogsLvl3.json rename to assets/level3_dialogs.json diff --git a/assets/level4.tmx b/assets/level4.tmx new file mode 100644 index 0000000..2b42d40 --- /dev/null +++ b/assets/level4.tmx @@ -0,0 +1,126 @@ + + + + + + + + + + + +385,386,2,2,385,386,385,2,2,2,2,2,2,2,2,2,385,386,385,265,266,385,386,385,386,385,121,122,123,122,123,122,124,2,2,2,2,2,2,2,2,386,2,2,2,2,2,2, +385,386,385,386,385,386,385,386,2,2,218,219,385,386,385,386,385,386,385,289,241,385,386,385,386,385,145,146,147,147,146,147,148,385,386,385,385,386,2,2,2,217,218,219,385,2,2,386, +385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,313,314,25,358,359,358,359,145,146,146,146,147,146,148,358,359,28,385,386,385,386,385,217,218,219,385,386,385,386, +385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,387,265,266,382,2,2,176,2,169,170,170,170,171,170,172,2,176,360,385,386,385,386,385,217,218,219,363,364,385,386, +385,386,385,386,176,386,385,386,385,386,385,386,385,386,385,386,385,386,385,289,290,97,98,19,2,2,121,122,59,60,61,123,124,2,2,384,385,149,150,151,152,153,154,386,176,177,178,386, +385,385,386,218,385,386,386,219,218,219,385,176,385,386,217,218,219,386,385,313,314,121,122,406,2,2,145,146,83,84,85,147,148,2,2,360,385,386,385,386,385,386,385,386,385,386,385,386, +385,386,25,26,26,26,26,238,239,28,385,386,385,386,217,218,219,386,385,265,241,14,15,43,254,255,169,170,107,108,109,171,172,254,255,360,385,387,149,150,151,152,153,154,385,217,218,219, +385,386,73,74,74,74,74,74,75,76,385,386,385,386,25,26,27,28,385,289,290,38,39,19,2,2,2,2,2,2,2,176,2,2,177,384,385,386,385,386,385,386,385,386,385,217,218,219, +385,386,97,98,98,98,98,98,99,100,385,386,385,386,73,74,75,76,385,313,314,62,63,97,407,407,408,407,407,408,407,407,408,98,99,100,385,149,150,151,152,153,154,218,219,386,385,386, +385,386,162,163,163,163,163,163,164,165,385,386,385,386,97,98,99,100,385,265,266,2,2,197,198,199,200,197,198,199,200,197,198,199,200,197,385,386,385,386,385,386,217,361,362,386,385,386, +25,26,86,87,88,89,186,187,188,189,359,358,359,26,87,88,187,188,28,241,290,160,161,221,222,223,224,221,222,223,224,221,222,223,224,221,385,386,385,386,385,386,385,386,385,386,385,386, +49,50,110,111,112,113,210,211,212,213,177,2,11,12,111,112,211,212,52,313,314,2,2,245,246,247,248,245,246,247,248,245,246,247,248,245,385,386,385,386,385,386,385,386,385,386,385,386, +73,74,75,74,75,176,234,235,236,237,2,2,35,36,75,74,74,75,76,265,266,265,266,265,266,265,266,241,266,313,314,265,266,265,266,265,241,265,266,313,314,265,266,265,266,265,266,265, +97,98,99,98,99,407,408,407,408,407,408,408,407,98,99,98,98,99,100,289,290,289,313,241,290,289,290,289,290,289,290,289,313,241,290,289,290,289,290,289,290,289,290,313,314,313,290,289, +121,122,14,15,16,17,14,15,16,17,14,15,16,17,122,59,60,61,124,265,266,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385, +145,146,38,39,40,41,38,39,40,41,38,39,40,41,146,83,84,85,148,289,290,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385, +169,170,62,63,64,65,62,63,64,65,62,63,64,65,170,107,108,109,172,265,266,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385, +385,386,187,188,87,88,187,188,87,88,187,188,87,88,265,266,266,289,290,241,290,385,386,385,386,385,386,385,386,385,386,385,386,304,305,385,386,385,386,385,386,385,386,385,386,385,386,385, +385,386,211,212,111,112,211,212,111,112,211,212,111,112,289,290,241,313,314,313,314,21,22,23,24,217,386,385,217,218,219,217,386,328,329,385,386,176,386,217,218,219,386,385,386,385,386,385, +385,386,289,241,265,266,289,290,241,266,289,290,265,266,241,290,385,386,385,385,386,45,46,47,48,217,386,385,217,218,219,217,386,385,386,385,386,385,386,217,218,219,386,385,386,385,386,385, +385,386,313,314,289,290,241,314,289,290,313,241,289,290,313,314,385,386,385,385,386,69,70,71,72,217,386,385,217,218,219,217,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385, +385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,385,386,385,386,385,386,385,304,305,386,176,386,385,386,385,386,385,386,385,386,385,386,385,386,385,217,304,305,385, +385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,385,386,385,386,385,386,385,328,329,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,217,328,329,385, +385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385,386,385 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,339,340,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,126,127,128,129,130,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,206,207,0,0,0,0,0,0,0,206,207,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,214,215,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,231,0,0,0,0,0,0,0,230,231,0,0,0,125,126,127,128,129,130,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,126,127,128,129,130,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,337,338,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +412,412,409,409,412,412,412,409,409,409,409,409,409,409,409,409,412,412,412,0,0,412,412,412,412,412,410,410,410,410,410,410,410,409,409,409,409,409,409,409,409,412,409,409,409,409,409,409, +412,412,412,412,412,412,412,412,409,409,412,412,412,412,412,412,412,412,412,0,0,412,412,412,412,412,410,0,0,0,0,0,410,412,412,412,412,412,409,409,409,412,412,412,412,409,409,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,0,0,410,410,410,410,410,410,0,0,0,0,0,410,410,410,410,412,412,412,412,412,412,412,412,410,410,412,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,410,0,0,410,0,0,0,0,410,0,0,0,0,0,410,0,0,410,412,412,412,412,412,412,412,412,410,410,412,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,0,0,410,0,0,0,0,410,0,410,410,410,0,410,0,0,410,412,410,410,410,410,410,410,412,412,412,412,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,0,0,410,410,0,0,0,410,0,410,410,410,0,410,0,0,410,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,410,410,410,410,410,410,410,410,412,412,412,412,412,412,412,412,412,0,0,0,0,0,410,410,410,410,410,0,410,410,410,410,410,410,412,410,410,410,410,410,410,410,412,412,412,412, +412,412,410,0,0,0,0,0,0,410,412,412,412,412,410,410,410,410,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,410,0,0,0,0,0,0,410,412,412,412,412,410,0,0,410,412,0,0,0,410,410,0,0,0,0,0,0,0,0,0,0,0,410,412,410,410,410,410,410,410,410,410,412,412,412, +412,412,410,0,0,0,410,410,410,410,412,412,412,412,410,410,410,410,412,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,412,412,412,412,412,412,412,410,410,412,412,412, +410,410,410,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,410,410,410,0,0,0,0,0,0,0,0,0,0,0,410,412,412,412,412,412,412,412,412,412,412,412,412, +410,0,410,410,410,410,410,0,0,410,0,0,0,0,410,410,0,0,410,0,0,0,0,410,410,410,410,410,410,410,410,410,410,410,410,410,412,412,412,412,412,412,412,412,412,412,412,412, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,0,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,410,410,410,410,0,0,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412, +410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,410,0,410,410,0,0,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,410,410,410,410,410,410,410,410,410,410,410,410,0,0,0,0,0,0,0,412,412,412,412,412,412,412,412,412,412,412,412,410,410,412,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,409,409,410,410,0,0,410,410,0,0,410,410,0,0,0,0,0,0,0,410,410,410,410,412,412,412,412,412,412,412,412,410,410,412,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,412,412,412,412,410,410,410,410,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,0,0,0,0,0,0,0,0,0,0,0,0,0,0,412,412,412,412,412,410,410,410,410,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,410,410,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,410,410,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,410,410,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,410,410,412, +412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/level4_dialogs.json b/assets/level4_dialogs.json new file mode 100644 index 0000000..f4c8c58 --- /dev/null +++ b/assets/level4_dialogs.json @@ -0,0 +1,37 @@ +{ + "dialogs": [ + { + "ID": 0, + "dialog": "Pas sur que tu trouves grand chose ici, je suis le seul ici depuis cinquante ans.", + "isQuestion": 0, + "choice": "_", + "conclusion1": "_", + "next1": -1, + "conclusion2": "_", + "next2": -1, + "nextOther": -1 + }, + { + "ID": 1, + "dialog": "L'eglise de Champdubouc", + "isQuestion": 0, + "choice": "_", + "conclusion1": "_", + "next1": -1, + "conclusion2": "_", + "next2": -1, + "nextOther": -1 + }, + { + "ID": 2, + "dialog": "Passe moi ton fric !", + "isQuestion": 0, + "choice": "_", + "conclusion1": "_", + "next1": -1, + "conclusion2": "_", + "next2": -1, + "nextOther": -1 + } + ] +} diff --git a/assets/tileset.png b/assets/tileset.png deleted file mode 100644 index 2c2ad04..0000000 Binary files a/assets/tileset.png and /dev/null differ diff --git a/assets/tileset.png b/assets/tileset.png new file mode 120000 index 0000000..2378d17 --- /dev/null +++ b/assets/tileset.png @@ -0,0 +1 @@ +../assets-fx/2b/tileset/tileset2b.png \ No newline at end of file diff --git a/assets/tinytiled b/assets/tinytiled new file mode 160000 index 0000000..b084ecd --- /dev/null +++ b/assets/tinytiled @@ -0,0 +1 @@ +Subproject commit b084ecda91a2352a72a5d1a61b37e0009228ee40 diff --git a/clean b/clean index 445982d..bcc4d2a 100755 --- a/clean +++ b/clean @@ -6,6 +6,7 @@ cd .. rm -r build-cg rm -r build-cg-push rm -r build-fx +rm -r build-fxg3a rm *.g1a rm *.g3a diff --git a/src/config.h b/src/config.h index ed692b7..2f7a890 100644 --- a/src/config.h +++ b/src/config.h @@ -1,28 +1,53 @@ #ifndef CONFIG_H #define CONFIG_H - -#if !defined(FXCG50) && defined(COLOR2BIT) - #define GRAYMODEOK 1 -#endif - #define USB_FEATURE 0 - #define DEBUGMODE 0 +#define PRECISION 8 -#ifdef FXCG50 - #define T_HEIGHT 16 - #define T_WIDTH 16 +#include + +/* Enable GrayMode on either FX and FX_G3A targets */ +#if GINT_RENDER_MONO && defined(COLOR2BIT) +#define GRAYMODEOK 1 +#endif + +#if GINT_RENDER_RGB +/* The tile size */ +#define T_HEIGHT 16 +#define T_WIDTH 16 +/* The size of a pixel */ +#define PXSIZE 2 +#define PATH_COLOR C_RED +/* The size of the player */ +#define P_WIDTH 16 +#define P_HEIGHT 16 #else - #define T_HEIGHT 8 - #define T_WIDTH 8 +/* The tile size */ +#define T_HEIGHT 8 +#define T_WIDTH 8 +/* The pixel size */ +#define PXSIZE 1 +#define PATH_COLOR C_BLACK +/* The player size */ +#define P_WIDTH 8 +#define P_HEIGHT 8 #endif -#ifdef FXCG50 - #define PXSIZE 2 +/* SPEED should NOT be 8 or bigger: it may cause bugs when handling + * collisions! */ +#define SPEED (PXSIZE * 2) + +/* The face size (in the dialogs) */ +#define F_WIDTH (32 * PXSIZE) +#define F_HEIGHT (32 * PXSIZE) + +/* the color of the text to go to the next dialog phase */ +/* it improves readability to have something lighter */ +#if GRAYMODEOK || (GINT_RENDER_RGB && !defined(COLOR1BIT)) +#define NEXT_COLOR C_DARK #else - #define PXSIZE 1 +#define NEXT_COLOR C_BLACK #endif - #endif diff --git a/src/dialogs.c b/src/dialogs.c index 4757303..241e38f 100644 --- a/src/dialogs.c +++ b/src/dialogs.c @@ -1,209 +1,223 @@ #include "dialogs.h" -#include -#include - -#include - #include "config.h" +#include "events.h" #include "game.h" #include "npc.h" +#include +#include +#include -#define BOX_HEIGHT (F_HEIGHT/PXSIZE+8) +#define BOX_HEIGHT (F_HEIGHT / PXSIZE + 8) #define CHOICE_BOX_HEIGHT 10 #define CHOICE_BOX_PADDING_TOP 3 - extern font_t fontRPG; #define FONT_USED fontRPG #if GRAYMODEOK - #include - uint32_t *lightVRAMnext, *darkVRAMnext; - uint32_t *lightVRAMcurrent, *darkVRAMcurrent; -#endif //GRAYMODEOK +#include +uint32_t *lightVRAMnext, *darkVRAMnext; +uint32_t *lightVRAMcurrent, *darkVRAMcurrent; +#endif // GRAYMODEOK -/* the color of the text to go to the next dialog phase */ -/* it improves readability to have somathing lighter */ -#if GRAYMODEOK || (defined(FXCG50) && !defined(COLOR1BIT)) - #define NEXT_COLOR C_DARK -#else - #define NEXT_COLOR C_BLACK +void blit() { + dupdate(); + +#if GRAYMODEOK && !GINT_HW_CG + dgray_getvram(&lightVRAMnext, &darkVRAMnext); + dgray_getscreen(&lightVRAMcurrent, &darkVRAMcurrent); + + memcpy(lightVRAMnext, lightVRAMcurrent, 256 * sizeof(uint32_t)); + memcpy(darkVRAMnext, darkVRAMcurrent, 256 * sizeof(uint32_t)); #endif - - -void blit() -{ - dupdate(); - - #if GRAYMODEOK - dgray_getvram( &lightVRAMnext, &darkVRAMnext ); - dgray_getscreen( &lightVRAMcurrent, &darkVRAMcurrent ); - - memcpy( lightVRAMnext, lightVRAMcurrent, 256*sizeof( uint32_t) ); - memcpy( darkVRAMnext, darkVRAMcurrent, 256*sizeof( uint32_t) ); - #endif } - -int showtext_opt(Game *game, bopti_image_t *face, char *text, - int call_before_end(Game *game, unsigned int i), - bool start_anim, - bool end_anim, - void for_each_screen(Game *game, unsigned int i), - int line_duration, bool update_screen, unsigned int start_i, - bool wait_continue) { +int dialogs_text_opt(Game *game, bopti_image_t *face, char *text, + int call_before_end(Game *game, unsigned int i), + bool start_anim, bool end_anim, + void for_each_screen(Game *game, unsigned int i), + int line_duration, bool update_screen, + unsigned int start_i, bool wait_continue) { + text = events_parse_string(&game->handler, text); dfont(&FONT_USED); unsigned int i, n, y = PXSIZE, l = 0; int line_max_chars, return_int = 0; - unsigned int max_lines_amount = (BOX_HEIGHT-2)*PXSIZE/ - (FONT_USED.line_height+PXSIZE); + unsigned int max_lines_amount = + (BOX_HEIGHT - 2) * PXSIZE / (FONT_USED.line_height + PXSIZE); const char *c; - if(start_anim){ + if(start_anim) { /* Run a little fancy animation. */ - for(i=0;i<=BOX_HEIGHT;i++){ + for(i = 0; i <= BOX_HEIGHT; i++) { /* Redrawing the entire screen, because maybe there was no dialog displayed before. */ - update_npc(game); - draw(game); + update_npcs(game); + game_draw(game); /* Fill the dialog box with white */ - drect(0, 0, DWIDTH, i*PXSIZE, C_WHITE); + drect(0, 0, DWIDTH, i * PXSIZE, C_WHITE); /* Draw a thick black line on the bottom of the dialog. */ - drect(0, i*PXSIZE, DWIDTH, (i+1)*PXSIZE, C_BLACK); + drect(0, i * PXSIZE, DWIDTH, (i + 1) * PXSIZE, C_BLACK); /* Draw the part of the face of the player that can fit correctly in * the dialog drawn. */ - dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH, (i-8)*PXSIZE, - DIMAGE_NONE); + dsubimage(4 * PXSIZE, 2 * PXSIZE, face, 0, 0, F_WIDTH, + (i - 8) * PXSIZE, DIMAGE_NONE); blit(); - while(game->frame_duration < 20) sleep(); + while(game->frame_duration < 20) + sleep(); game->frame_duration = 0; } - }else{ + } else { /* Here I'm drawing the same as if start_anim is true, but whitout * making an animation. */ - draw(game); - drect(0, 0, DWIDTH, BOX_HEIGHT*PXSIZE, C_WHITE); - drect(0, BOX_HEIGHT*PXSIZE, DWIDTH, (BOX_HEIGHT+1)*PXSIZE, C_BLACK); - dimage(4*PXSIZE, 2*PXSIZE, face); + game_draw(game); + drect(0, 0, DWIDTH, BOX_HEIGHT * PXSIZE, C_WHITE); + drect(0, BOX_HEIGHT * PXSIZE, DWIDTH, (BOX_HEIGHT + 1) * PXSIZE, + C_BLACK); + dimage(4 * PXSIZE, 2 * PXSIZE, face); - if(update_screen){ + if(update_screen) { blit(); - while(game->frame_duration < 20) sleep(); + while(game->frame_duration < 20) + sleep(); game->frame_duration = 0; } } /* We should start to drawing the text on the x axis at BOX_HEIGHT to avoid * drawing on the face. */ - for(i=start_i;i0; n--) { + for(n = line_max_chars; n > 0; n--) { /* If we found a space, we can draw this line and do the same - * for the next line. */ - if(text[i+n] == ' '){ - dtext_opt(BOX_HEIGHT*PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT, - DTEXT_TOP, text+i, n); /* Draw everything. */ + * for the next line. */ + if(text[i + n] == ' ') { + dtext_opt(BOX_HEIGHT * PXSIZE, y, C_BLACK, C_NONE, + DTEXT_LEFT, DTEXT_TOP, text + i, + n); /* Draw everything. */ /* Increment y by the line height. */ - y += FONT_USED.line_height+PXSIZE; + y += FONT_USED.line_height + PXSIZE; i += n; /* We drew everything to i+n */ - l++; /* We drew one more line. */ + l++; /* We drew one more line. */ break; } } - }else{ + } else { /* If it is the last line of the text. */ - dtext_opt(BOX_HEIGHT*PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT, - DTEXT_TOP, text+i, line_max_chars); - y += FONT_USED.line_height+PXSIZE; + dtext_opt(BOX_HEIGHT * PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT, + DTEXT_TOP, text + i, line_max_chars); + y += FONT_USED.line_height + PXSIZE; i += line_max_chars; l++; } - if(l>=max_lines_amount-1){ + if(l >= max_lines_amount - 1) { /* We drew one entire screen, reset everything to draw the next one. */ /* Make a little animation :). */ - if(update_screen) blit(); - while(game->frame_duration < line_duration) sleep(); + if(update_screen) + blit(); + while(game->frame_duration < line_duration) + sleep(); game->frame_duration = 0; /* Ask the user to press SHIFT to continue. */ - dtext(BOX_HEIGHT*PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite..."); + dtext(BOX_HEIGHT * PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite..."); } /* Make a little animation :). */ - if(update_screen) blit(); - if(l>=max_lines_amount-1){ + if(update_screen) + blit(); + if(l >= max_lines_amount - 1) { /* If we drew one entire screen. */ /* Wait that the SHIFT key is pressed if we should. */ - if(wait_continue) while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key != KEY_SHIFT) sleep(); + if(wait_continue) { + while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & + ~GETKEY_MOD_ALPHA, + NULL) + .key != KEY_SHIFT) { + sleep(); + } + } /* Clear the text area. */ - drect(BOX_HEIGHT*PXSIZE, 0, DWIDTH, (BOX_HEIGHT-1)*PXSIZE-2, + drect(BOX_HEIGHT * PXSIZE, 0, DWIDTH, (BOX_HEIGHT - 1) * PXSIZE - 2, C_WHITE); /* Reset y and l. */ y = PXSIZE; l = 0; - } - else{ + } else { /* Else, wait a bit for the animation. */ - while(game->frame_duration < line_duration) sleep(); + while(game->frame_duration < line_duration) + sleep(); game->frame_duration = 0; } } - if(lframe_duration < line_duration) sleep(); + if(update_screen) + blit(); + while(game->frame_duration < line_duration) + sleep(); game->frame_duration = 0; /* Ask the user to press SHIFT to continue. */ - dtext(BOX_HEIGHT*PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite..."); + dtext(BOX_HEIGHT * PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite..."); /* Update the screen and wait for SHIFT being pressed, if needed. */ - if(update_screen) blit(); - if(wait_continue) while(getkey_opt( GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key != KEY_SHIFT) sleep(); + if(update_screen) + blit(); + if(wait_continue) { + while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & + ~GETKEY_MOD_ALPHA, + NULL) + .key != KEY_SHIFT) { + sleep(); + } + } } - if(call_before_end) return_int = call_before_end(game, i); - if(end_anim){ + if(call_before_end) + return_int = call_before_end(game, i); + if(end_anim) { /* Run another little fancy animation if we should. */ - for(i=BOX_HEIGHT;i>0;i--){ + for(i = BOX_HEIGHT; i > 0; i--) { /* It is the same as the start animation. */ - update_npc(game); - draw(game); - drect(0, 0, DWIDTH, i*PXSIZE, C_WHITE); - drect(0, i*PXSIZE, DWIDTH, (i+1)*PXSIZE, C_BLACK); - dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH, (i-8)*PXSIZE, - DIMAGE_NONE); + update_npcs(game); + game_draw(game); + drect(0, 0, DWIDTH, i * PXSIZE, C_WHITE); + drect(0, i * PXSIZE, DWIDTH, (i + 1) * PXSIZE, C_BLACK); + dsubimage(4 * PXSIZE, 2 * PXSIZE, face, 0, 0, F_WIDTH, + (i - 8) * PXSIZE, DIMAGE_NONE); dupdate(); - while(game->frame_duration < 20) sleep(); + while(game->frame_duration < 20) + sleep(); game->frame_duration = 0; } } return return_int; } -void showtext_dialog(Game *game, bopti_image_t *face, char *text, - bool dialog_start, bool dialog_end) { +void dialogs_text(Game *game, bopti_image_t *face, char *text, + bool dialog_start, bool dialog_end) { /* Run showtext_opt with some default values. It makes it easier to use in * simple dialogs. */ - showtext_opt(game, face, text, NULL, dialog_start, dialog_end, NULL, 100, - true, 0, true); + dialogs_text_opt(game, face, text, NULL, dialog_start, dialog_end, NULL, + 100, true, 0, true); } - /* Some variables and pointers used to get some arguments passed in * showtext_dialog_ask in _choice_call_before_end. */ char *_choices, *_text; @@ -213,31 +227,33 @@ unsigned int _i; /* Get where I started drawing a dialog page, to be able to redraw the last page * for the end animation in _choice_call_before_end. */ -void _choice_screen_call( [[maybe_unused]] Game *game, unsigned int i) { +void _choice_screen_call([[maybe_unused]] Game *game, unsigned int i) { _i = i; } int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) { int i, key; /* Make a little animation because we looove little animations ;) */ - for(i=0;iframe_duration < 20) sleep(); + while(game->frame_duration < 20) + sleep(); game->frame_duration = 0; } /* Calculate the maximal size of a choice. */ - const int choice_size = DWIDTH/_choices_amount; + const int choice_size = DWIDTH / _choices_amount; /* arrow_width: The space taken by the arrow that shows the selected item. * arrow_height: The height of the arrow used to show which item is choosen. * Used to calculate the size of the rectangle used to remove @@ -253,65 +269,70 @@ int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) { dsize(">", &FONT_USED, &arrow_width, &arrow_height); /* Add the character spacing of the font to it. */ arrow_width += FONT_USED.char_spacing; - for(i=0;i<_choices_amount;i++){ - dtext(i*choice_size+arrow_width+PXSIZE, - (BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, C_BLACK, - _choices+pos); - pos += strlen(_choices+pos)+1; + for(i = 0; i < _choices_amount; i++) { + dtext(i * choice_size + arrow_width + PXSIZE, + (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE, C_BLACK, + _choices + pos); + pos += strlen(_choices + pos) + 1; } - do{ + do { /* Display the diffrent choices. */ - for(i=0;i<_choices_amount;i++){ - if(i == selected) dtext(i*choice_size+PXSIZE, - (BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, - C_BLACK, ">"); + for(i = 0; i < _choices_amount; i++) { + if(i == selected) + dtext(i * choice_size + PXSIZE, + (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE, C_BLACK, + ">"); } blit(); - key = getkey_opt( GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key; + key = getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, + NULL) + .key; /* If the player pressed the left arrow key and has not already selected * the first possible choice. */ - if(key == KEY_LEFT && selected > 0){ + if(key == KEY_LEFT && selected > 0) { /* Remove the old arrow. */ - drect(selected*choice_size+PXSIZE, - (BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, - selected*choice_size+PXSIZE+arrow_width, - (BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE+arrow_height, + drect(selected * choice_size + PXSIZE, + (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE, + selected * choice_size + PXSIZE + arrow_width, + (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE + arrow_height, C_WHITE); - + /* Move the selection arrow and update the selected item. */ selected--; } /* If the player pressed the right arrow key and has not already * selected the last possible choice. */ - else if(key == KEY_RIGHT && selected < _choices_amount-1){ + else if(key == KEY_RIGHT && selected < _choices_amount - 1) { /* Remove the old arrow. */ - drect(selected*choice_size+PXSIZE, - (BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, - selected*choice_size+PXSIZE+arrow_width, - (BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE+arrow_height, + drect(selected * choice_size + PXSIZE, + (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE, + selected * choice_size + PXSIZE + arrow_width, + (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE + arrow_height, C_WHITE); - + /* Move the selection arrow and update the selected item. */ selected++; } - /* If the user has not validated his choice by pressing SHIFT, we loop one - * more time. */ - }while(key != KEY_SHIFT); + /* If the user has not validated his choice by pressing SHIFT, we loop + * one more time. */ + } while(key != KEY_SHIFT); /* Make a little animation because we looove little animations ;) */ - for(i=DWIDTH/8+1;i>0;i--){ + for(i = DWIDTH / 8 + 1; i > 0; i--) { /* I'm drawing the same box as on the start animation */ - update_npc(game); - draw(game); - showtext_opt(game, _face, _text, NULL, false, false, NULL, 0, false, - _i, false); - drect(0, (BOX_HEIGHT+1)*PXSIZE+1, i*(DWIDTH/8), - (BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, C_WHITE); - drect(i*(DWIDTH/8), BOX_HEIGHT*PXSIZE, i*(DWIDTH/8)+PXSIZE-1, - (BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK); - drect(0, (BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, i*(DWIDTH/8), - (BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK); + update_npcs(game); + game_draw(game); + dialogs_text_opt(game, _face, _text, NULL, false, false, NULL, 0, false, + _i, false); + drect(0, (BOX_HEIGHT + 1) * PXSIZE + 1, i * (DWIDTH / 8), + (BOX_HEIGHT + CHOICE_BOX_HEIGHT) * PXSIZE, C_WHITE); + drect(i * (DWIDTH / 8), BOX_HEIGHT * PXSIZE, + i * (DWIDTH / 8) + PXSIZE - 1, + (BOX_HEIGHT + CHOICE_BOX_HEIGHT + 1) * PXSIZE, C_BLACK); + drect(0, (BOX_HEIGHT + CHOICE_BOX_HEIGHT) * PXSIZE, i * (DWIDTH / 8), + (BOX_HEIGHT + CHOICE_BOX_HEIGHT + 1) * PXSIZE, C_BLACK); dupdate(); - while(game->frame_duration < 20) sleep(); + while(game->frame_duration < 20) + sleep(); game->frame_duration = 0; } /* Return the selected item because he'll also be returned by showtext_opt. @@ -319,9 +340,9 @@ int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) { return selected; } -int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start, - bool end, char *choices, int choices_amount, - int default_choice) { +int dialogs_ask(Game *game, bopti_image_t *face, char *text, bool start, + bool end, char *choices, int choices_amount, + int default_choice) { /* Put some arguments in global pointers and variables to make them * accessible by _choice_call_before_end. */ _choices = choices; @@ -331,50 +352,45 @@ int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start, _text = text; /* Run showtext_opt and return his return value (the return value of *_choice_call_before_end) */ - return showtext_opt(game, face, text, _choice_call_before_end, start, end, - _choice_screen_call, 100, true, 0, true); + return dialogs_text_opt(game, face, text, _choice_call_before_end, start, + end, _choice_screen_call, 100, true, 0, true); } +void dialogs_initiate_sequence(Game *game, bopti_image_t *face, + uint32_t dialogNumber) { + Dialog *currentDiag = &game->map_level->dialogs[dialogNumber]; + /* we collect the information */ + char *text = currentDiag->dialog; + char *choices = currentDiag->choices; + char *conclusion1 = currentDiag->conclusion1; + int next1 = currentDiag->next1; + char *conclusion2 = currentDiag->conclusion2; + int next2 = currentDiag->next2; + int nextOther = currentDiag->nextOther; + int isQuestion = currentDiag->isQuestion; -void initiate_dialog_sequence(Game *game, bopti_image_t *face, uint32_t dialogNumber ) -{ - Dialog *currentDiag = &game->map_level->dialogs[ dialogNumber ]; + /* we treat the action - i.e. we show a dialog */ + if(isQuestion == 1) { + /* we have to manage a question */ + int answer = dialogs_ask(game, face, text, true, true, choices, 2, 0); - /* we collect the information */ - char *text = currentDiag->dialog; + /* TO DO we need to split the strings conclusion1 and conclusion2 */ + /* to extract the "gift" part */ - char *choices = currentDiag->choices ; - char *conclusion1 = currentDiag->conclusion1; - int next1 = currentDiag->next1; - char *conclusion2 = currentDiag->conclusion2; - int next2 = currentDiag->next2; - int nextOther = currentDiag->nextOther; - int isQuestion = currentDiag->isQuestion; - - /* we treat the action - i.e. we show a dialog */ - if (isQuestion == 1) /* we have to manage a question */ - { - int answer = showtext_dialog_ask( game, face, text, true, true, choices, 2, 0 ); - - /* TO DO we need to split the strings conclusion1 and conclusion2 */ - /* to extract the "gift" part */ - - if (answer==0) - { - showtext_dialog( game, face, conclusion1, true, true ); - if (next1!=-1) initiate_dialog_sequence( game, face, next1 ); - } - else - { - showtext_dialog( game, face, conclusion2, true, true ); - if (next2!=-1) initiate_dialog_sequence( game, face, next2 ); - } + if(answer == 0) { + dialogs_text(game, face, conclusion1, true, true); + if(next1 != -1) + dialogs_initiate_sequence(game, face, next1); + } else { + dialogs_text(game, face, conclusion2, true, true); + if(next2 != -1) + dialogs_initiate_sequence(game, face, next2); } - else - { - showtext_dialog( game, face, text, true, true ); - if (nextOther!=-1) initiate_dialog_sequence( game, face, nextOther ); - } -} \ No newline at end of file + } else { + dialogs_text(game, face, text, true, true); + if(nextOther != -1) + dialogs_initiate_sequence(game, face, nextOther); + } +} diff --git a/src/dialogs.h b/src/dialogs.h index 39729b7..dae2adf 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -1,15 +1,14 @@ #ifndef DIALOG_H #define DIALOG_H -#include -#include +#include "config.h" #include "game.h" #include "map.h" -#define F_WIDTH (32*PXSIZE) -#define F_HEIGHT (32*PXSIZE) +#include +#include -/* showtext_opt() +/* dialogs_text_opt() * * Show some text in a box with word wrap for dialogs. * @@ -37,17 +36,16 @@ * wait_continue: If I should wait that EXE is pressed after drawing a page. */ -int showtext_opt(Game *game, bopti_image_t *face, char *text, - int call_before_end(Game *game, unsigned int i), - bool start_anim, - bool end_anim, - void for_each_screen(Game *game, unsigned int i), - int line_duration, bool update_screen, unsigned int start_i, - bool wait_continue); +int dialogs_text_opt(Game *game, bopti_image_t *face, char *text, + int call_before_end(Game *game, unsigned int i), + bool start_anim, bool end_anim, + void for_each_screen(Game *game, unsigned int i), + int line_duration, bool update_screen, + unsigned int start_i, bool wait_continue); -/* showtext_dialog() +/* dialogs_text() * - * Calls showtext_opt with default parameters. + * Calls dialogs_text_opt with default parameters. * * game: The game struct of the current game. * face: A bopti_image_t of the face of the person who's saying this @@ -60,12 +58,12 @@ int showtext_opt(Game *game, bopti_image_t *face, char *text, * shown at the end of showtext_opt. */ -void showtext_dialog(Game *game, bopti_image_t *face, char *text, - bool dialog_start, bool dialog_end); +void dialogs_text(Game *game, bopti_image_t *face, char *text, + bool dialog_start, bool dialog_end); -/* showtext_dialog_ask() +/* dialogs_ask() * - * Like showtext_dialog, but lets the user choose between multiple possible + * Like dialogs_text, but lets the user choose between multiple possible * choices after displaying the text. * * game: The game struct of the current game. @@ -85,10 +83,12 @@ void showtext_dialog(Game *game, bopti_image_t *face, char *text, * default_choice: The choice choosen by default when the dialog just opened. */ -int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start, - bool end, char *choices, int choices_amount, - int default_choice); +int dialogs_ask(Game *game, bopti_image_t *face, char *text, bool start, + bool end, char *choices, int choices_amount, + int default_choice); -void initiate_dialog_sequence(Game *game, bopti_image_t *face, uint32_t dialogNumber ); +/* TODO: Doc. */ +void dialogs_initiate_sequence(Game *game, bopti_image_t *face, + uint32_t dialogNumber); #endif diff --git a/src/events.c b/src/events.c new file mode 100644 index 0000000..ff66087 --- /dev/null +++ b/src/events.c @@ -0,0 +1,110 @@ +#include "events.h" + +#include +#include + +void events_init_handler(EventHandler *handler) { handler->vars = 0; } + +int events_bind_variable(EventHandler *handler, int *var, char *name) { + if(handler->vars < MAX_VARIABLES) { + handler->variables[handler->vars] = var; + handler->var_names[handler->vars++] = name; + } else { + return 1; + } + return 0; +} + +char op_chars[OP_AMOUNT + 1] = " =+-/*%"; + +int _op_null(int a, int b) { return 0; } + +int _op_set(int a, int b) { return b; } + +int _op_add(int a, int b) { return a + b; } + +int _op_sub(int a, int b) { return a - b; } + +int _op_div(int a, int b) { + if(b == 0) + return 0; + return a / b; +} + +int _op_mul(int a, int b) { return a * b; } + +int _op_mod(int a, int b) { + if(b == 0) + return 0; + return a % b; +} + +int (*_operations[OP_AMOUNT])(int, int) = {_op_null, _op_set, _op_add, _op_sub, + _op_div, _op_mul, _op_mod}; + +#define MIN(a, b) a < b ? a : b + +char _message_buffer[MESSAGE_BUFFER_SZ]; +char *events_parse_string(EventHandler *handler, char *message) { + size_t message_pos = 0; + char in_token = 0; + char var_name[TOKEN_MAX_SZ]; + size_t name_pos = 0; + Operation var_op = OP_NULL; + char num[TOKEN_MAX_SZ]; + size_t num_pos = 0; + Token tok_type = T_NULL; + char c; + size_t i, n; + int *var; + for(i = 0; i < strlen(message); i++) { + c = message[i]; + if(c == '`') { + in_token = !in_token; + if(!in_token) { + if(tok_type == T_VAR_EDIT) { + /* Do the calculation */ + var_name[MIN(name_pos, TOKEN_MAX_SZ)] = '\0'; + num[MIN(num_pos, TOKEN_MAX_SZ)] = '\0'; + for(n = 0; n < handler->vars; n++) { + if(!strcmp(var_name, handler->var_names[n])) { + var = handler->variables[n]; + if(var_op) { + *var = _operations[var_op](*var, atoi(num)); + } + break; + } + } + } + /* Reset everything */ + tok_type = T_NULL; + name_pos = 0; + var_op = OP_NULL; + num_pos = 0; + } + } else if(!in_token) { + if(message_pos < TOKEN_MAX_SZ) + _message_buffer[message_pos++] = c; + } + if(in_token && c != ' ') { + if(tok_type == T_VAR_EDIT) { + if(var_op != OP_NULL) { + if(num_pos < TOKEN_MAX_SZ) + num[num_pos++] = c; + } + if(strchr(op_chars, c)) { + var_op = (Operation)(strchr(op_chars, c) - op_chars); + } + if(var_op == OP_NULL) { + if(name_pos < TOKEN_MAX_SZ) + var_name[name_pos++] = c; + } + } + if(c == '$') { + tok_type = T_VAR_EDIT; + } + } + } + _message_buffer[MIN(message_pos, MESSAGE_BUFFER_SZ)] = '\0'; + return _message_buffer; +} diff --git a/src/events.h b/src/events.h new file mode 100644 index 0000000..f4a19bf --- /dev/null +++ b/src/events.h @@ -0,0 +1,60 @@ +#ifndef EVENTS_H +#define EVENTS_H + +/* The max amount of variables that can be bound. */ +#define MAX_VARIABLES 32 +/* The max. size of the message buffer. + * WARNING: Bigger messages will be truncated! */ +#define MESSAGE_BUFFER_SZ 1024 +/* The maximal size of a token. Bigger tokens will be truncated. */ +#define TOKEN_MAX_SZ 1024 + +typedef struct { + int *variables[MAX_VARIABLES]; + char *var_names[MAX_VARIABLES]; + unsigned int vars; +} EventHandler; + +typedef enum { T_NULL, T_VAR_EDIT, T_AMOUNT } Token; + +typedef enum { + OP_NULL, + OP_SET, + OP_ADD, + OP_SUB, + OP_DIV, + OP_MUL, + OP_MOD, + OP_AMOUNT +} Operation; + +/* events_init_handler() + * + * Initialize an event handler. + * handler: The Event handler to initialize. + */ +void events_init_handler(EventHandler *handler); +/* events_bind_variable() + * + * Bind a variable. Binding a variable allows it to be modified by messages + * passed to the event handler using tags written as following: + * `variable+number` (The backticks delimit the tag). Available operators: + * '=': Assign a value to the variable. + * '+': Addition. + * '-': Substraction. + * '*': Multiplication. + * '/': Division. + * '%': Modulo. + * handler: The event handler. + * var: A pointer to the variable to bind. + * name: The name of the variable. This is the name that will be used to + * refer to this variable in a tag. + */ +int events_bind_variable(EventHandler *handler, int *var, char *name); +/* events_parse_string() + * handler: The event handler. + * message: The message to parse. + */ +char *events_parse_string(EventHandler *handler, char *message); + +#endif diff --git a/src/game.c b/src/game.c index 899dbc4..1b84b1f 100644 --- a/src/game.c +++ b/src/game.c @@ -1,77 +1,69 @@ #include "game.h" -#include "map.h" - #include "config.h" - -#include -#include -#include -#include -#include - +#include "map.h" #include "npc.h" +#include +#include +#include +#include +#include extern bopti_image_t SignAction_img; extern Dialog *dialogRPG; -extern NPC *npcRPG; -extern uint32_t nbNPC; +// extern NPC *npcRPG; +// extern uint32_t nbNPC; -#define MAX_INTERACTION_DISTANCE 12 +#define MAX_INTERACTION_DISTANCE 12 +void interaction_available(Game *game) { + uint32_t i; -void game_logic(Game *game) { + /*NPCs take priority over signs*/ - update_npc( game ); + for(uint32_t i = 0; i < game->map_level->nbNPC; i++) { + if(!game->map_level->npcs[i].has_dialog) + continue; - /* we check if interactions are possible close to the player */ - for( uint32_t i=0; imap_level->nbextradata; i++ ) - { /* simple distance check along X and Y axis */ /* Be careful to use world coordinates, not local (i.e.map) ones */ - if ( (abs((int) game->player.wx - - (int) game->map_level->extradata[i].x*PXSIZE ) - < MAX_INTERACTION_DISTANCE*PXSIZE) - && (abs((int) game->player.wy - - (int) game->map_level->extradata[i].y*PXSIZE ) - < MAX_INTERACTION_DISTANCE*PXSIZE) - && strcmp( game->map_level->extradata[i].type, "NPC") !=0 ) - { + if((abs((int)game->player.x - + (int)(game->map_level->npcs[i].curx >> PRECISION) * PXSIZE) < + MAX_INTERACTION_DISTANCE * PXSIZE) && + (abs((int)game->player.y - + (int)(game->map_level->npcs[i].cury >> PRECISION) * PXSIZE) < + MAX_INTERACTION_DISTANCE * PXSIZE)) { /* the player can do something */ game->player.canDoSomething = true; /* we mark the action for futur treatment in player_action() */ game->player.whichAction = i; + /* this is an interraction with a NPC */ + game->player.isInteractingWithNPC = true; + return; + } + } + + for(i = 0; i < game->map_level->nbSign; i++) { + /* simple distance check along X and Y axis */ + /* Be careful to use world coordinates, not local (i.e.map) ones */ + if((abs((int)game->player.x - + (int)game->map_level->signs[i].x * PXSIZE) < + MAX_INTERACTION_DISTANCE * PXSIZE) && + (abs((int)game->player.y - + (int)game->map_level->signs[i].y * PXSIZE) < + MAX_INTERACTION_DISTANCE * PXSIZE)) { + /* the player can do something */ + game->player.canDoSomething = true; + /* we mark the action for future treatment in player_action() */ + game->player.whichAction = i; /* this is not an interraction with a NPC */ game->player.isInteractingWithNPC = false; return; } } - for( uint32_t i=0; iplayer.wx - - (int) npcRPG[i].curx*PXSIZE ) - < MAX_INTERACTION_DISTANCE*PXSIZE) - && (abs((int) game->player.wy - - (int) npcRPG[i].cury*PXSIZE ) - < MAX_INTERACTION_DISTANCE*PXSIZE) - && strcmp( game->map_level->extradata[i].type, "NPC") !=0 ) - { - /* the player can do something */ - game->player.canDoSomething = true; - /* we mark the action for futur treatment in player_action() */ - game->player.whichAction = i; - /* this is not an interraction with a NPC */ - game->player.isInteractingWithNPC = true; - return; - } - } - - /* else nothing to be done here */ game->player.canDoSomething = false; game->player.whichAction = -1; @@ -79,47 +71,101 @@ void game_logic(Game *game) { return; } +void game_logic(Game *game) { -void render_indicator(Game *game) -{ - /* nothing to do for the player so we quit */ - if (game->player.canDoSomething==false) - return; + update_npcs(game); - /* else we draw a small indicator on the screen */ - dimage(5, 5, &SignAction_img); + /* we check if interactions are possible close to the player */ + + interaction_available(game); } +void game_render_indicator(Game *game) { + /* nothing to do for the player so we quit */ + if(game->player.canDoSomething) + dimage(5, 5, &SignAction_img); + int i; + Player *player = &game->player; + for(i = 0; i < game->map_level->nbPortal; i++) { + Portal *portal = &game->map_level->portals[i]; + if(player->x >= portal->collider.x1 * PXSIZE && + player->x < portal->collider.x2 * PXSIZE && + player->y >= portal->collider.y1 * PXSIZE && + player->y < portal->collider.y2 * PXSIZE) { + dimage(5, 5, &SignAction_img); + break; + } + } +} -void draw(Game *game) { +void game_draw(Game *game) { /* Draw everything. */ - render_map_by_layer(game, BACKGROUND); - npc_draw( game ); + dclear(C_WHITE); + map_render_by_layer(game, BACKGROUND); + npc_draw(game); player_draw(game); - render_map_by_layer(game, FOREGROUND); - render_indicator( game ); + map_render_by_layer(game, FOREGROUND); + game_render_indicator(game); + /*DEBUG*/ + dprint(8, 8, C_BLACK, "Lifes: %d", game->player.life); + dprint(8, 16, C_BLACK, "Mana: %d", game->mana); + dprint(8, 24, C_BLACK, "X: %d Y: %d", game->player.x, game->player.y); } /* Key management */ -void get_inputs(Game *game) { - key_event_t ev; - while((ev = pollevent()).type != KEYEV_NONE){ - /**/ - } +void game_get_inputs(Game *game) { + clearevents(); /* Key binding for the Player action */ /*************************************/ - if(keydown(KEY_EXIT)) game->exittoOS = true; + if(keydown(KEY_EXIT)) + game->exittoOS = true; /* Player actions - Prototypes in player.h and implementation in player.c */ - if(keydown(KEY_LEFT)) player_move(game, D_LEFT); - if(keydown(KEY_RIGHT)) player_move(game, D_RIGHT); - if(keydown(KEY_UP)) player_move(game, D_UP); - if(keydown(KEY_DOWN)) player_move(game, D_DOWN); - if(keydown(KEY_SHIFT)) player_action(game); + if(keydown(KEY_LEFT)) + player_move(game, D_LEFT); + if(keydown(KEY_RIGHT)) + player_move(game, D_RIGHT); + if(keydown(KEY_UP)) + player_move(game, D_UP); + if(keydown(KEY_DOWN)) + player_move(game, D_DOWN); + if(keydown(KEY_SHIFT)) + player_action(game); + if(keydown(KEY_OPTN)) { + game->player.is_male = !game->player.is_male; + /* TODO: Make something cleaner */ + while(keydown(KEY_OPTN)) { + clearevents(); + sleep(); + } + } + Player *player = &game->player; + if(keydown(KEY_SHIFT)) { + int i; + for(i = 0; i < game->map_level->nbPortal; i++) { + Portal *portal = &game->map_level->portals[i]; + if(player->x >= portal->collider.x1 * PXSIZE && + player->x < portal->collider.x2 * PXSIZE && + player->y >= portal->collider.y1 * PXSIZE && + player->y < portal->collider.y2 * PXSIZE) { + Portal *dest_portal = (Portal *)portal->portal; + Collider dest_collider = dest_portal->collider; + Map *dest_map = (Map *)portal->map; + player->x = (dest_collider.x1 + dest_collider.x2) / 2 * PXSIZE; + player->y = (dest_collider.y1 + dest_collider.y2) / 2 * PXSIZE; + game->map_level = dest_map; + /* TODO: Make something cleaner */ + while(keydown(KEY_SHIFT)) { + clearevents(); + sleep(); + } + } + } + } /* Display Debug Information on screen */ #if DEBUGMODE @@ -134,13 +180,13 @@ void get_inputs(Game *game) { } #endif - /* if USB is enabled - keybinding for screencapture */ #if USB_FEATURE - if(keydown(KEY_7)) game->screenshot = true; - if(keydown(KEY_8)) game->record = !game->record; + if(keydown(KEY_7)) + game->screenshot = true; + if(keydown(KEY_8)) + game->record = !game->record; -#endif //USB_FEATURE +#endif // USB_FEATURE } - diff --git a/src/game.h b/src/game.h index 8d24797..c1ef0a9 100644 --- a/src/game.h +++ b/src/game.h @@ -1,49 +1,41 @@ #ifndef GAME_H #define GAME_H +#include "events.h" #include #include - - /* The direction where the player is going to. */ -typedef enum { - D_UP, - D_DOWN, - D_LEFT, - D_RIGHT -} Direction; +typedef enum { D_UP, D_DOWN, D_LEFT, D_RIGHT } Direction; -typedef enum { - P_LEFTUP = -1, - P_CENTER = 0, - P_RIGHTDOWN = 1 -} Checkpos; +typedef enum { P_LEFTUP = -1, P_CENTER = 0, P_RIGHTDOWN = 1 } Checkpos; +typedef struct { + uint32_t x1, y1; + uint32_t x2, y2; +} Collider; /* Struct that define player parameters */ typedef struct { - int16_t x, y; /* The position of the player int the current map */ + int16_t x, y; /* The position of the player in the current map */ uint16_t px, py; /* The position of the player on screen */ - int16_t wx, wy; /* position of the player in the world */ - int8_t life; /* How many lives the player still has between 0 and 100. */ + int8_t life; /* How many lives the player still has between 0 and 100. */ int8_t speed; /* The speed of the movement of the player. */ - /* set to true if a action can be done in the current position of the map */ - bool canDoSomething; + bool canDoSomething; /* indicates which data are relevant to the current action in the */ /* extradata layer of the map */ - int32_t whichAction; + int32_t whichAction; /* the player is doing something */ bool isDoingAction; /* the player is interacting with a NPC */ bool isInteractingWithNPC; + bool is_male; } Player; - typedef struct { uint32_t ID; /* data to be shown in the dialog*/ @@ -61,47 +53,77 @@ typedef struct { int32_t nextOther; } Dialog; - typedef struct { /* position of the item */ uint32_t x; uint32_t y; - /* its name */ + /*id of it's icon*/ + uint32_t icon; + char *name; - /* its class (NPC, SGN, INFO, ... )*/ - char *type; /* the ID of the first element of the dialog */ /* (to be aligned with "dialogs.json" IDs)*/ uint32_t dialogID; - /* 0 if imperative dialog (story mode) */ - /* or 1 if the player need to press [SHIFT] to initiate the sequence*/ + /*if the dialog is interactive or not*/ uint32_t needAction; +} Sign; + +typedef struct { + /* current coordinates of the NPC */ + uint32_t curx; + uint32_t cury; + + /* initial coordinates of the NPC (needed to get absolute coordinates of + * path) */ + uint32_t x; + uint32_t y; + /* id of it's face */ + uint16_t face; + + uint8_t paused; + + uint8_t has_dialog; + /* the ID of the first element of the dialog */ + /* (to be aligned with "dialogs.json" IDs)*/ + uint32_t dialogID; + /*if the dialog is interactive or not*/ + uint32_t needAction; + + char *name; /* data for NPC's trajectories */ uint32_t hasPath; uint32_t path_length; + uint32_t currentPoint; int16_t *xpath; int16_t *ypath; - /* ... this can be extended as per needs ... */ -} ExtraData; + int type : 32; + uint8_t current_group; + uint8_t hostile_to_group; + + uint16_t __padding; +} NPC; + +typedef struct { + Collider collider; + /* The destination portal */ + void *portal; + /* The destination map */ + void *map; +} Portal; typedef struct { /* width, height and the number of layer of the map */ + uint32_t x; + uint32_t y; uint32_t w; uint32_t h; uint32_t nblayers; uint32_t tileset_size; - /* world coordinates of the upper left and bootom right*/ - /* corners of the current map to be multiplied in game by PXSIZE */ - uint32_t xmin; - uint32_t ymin; - uint32_t xmax; - uint32_t ymax; - /* the tileset to use */ bopti_image_t *tileset; @@ -109,11 +131,14 @@ typedef struct { /* this is given by the layer Walkable of the map in Tiled */ uint8_t *walkable; - /* structure that contains all the items on the map to interract with */ - /* each portion of the map has its own list to avoid scrutinizing too much */ - /* data when lloking for proximity of items */ - uint32_t nbextradata; - ExtraData *extradata; + uint32_t nbNPC; + NPC *npcs; + + uint32_t nbSign; + Sign *signs; + + uint32_t nbPortal; + Portal *portals; /* structure that contains all the dialogs for that part of the map */ uint32_t nbdialogsdata; @@ -121,16 +146,16 @@ typedef struct { /* list of all the tiles to draw the background and the foreground layers */ uint16_t *layers[]; + } Map; - - /* This struct will contain all the data of the game. It will make it possible * to pass it to the NPCs to let them interact with the player and the rest of * the world. */ typedef struct { - Map *map_level; /* The level that the player is currently playing */ - Player player; /* The player data (see player.h). */ + Map *map_level; /* The level that the player is currently playing */ + Player player; /* The player data. */ + EventHandler handler; /* The event handler (see events.h). */ /* Some global variables */ /* Set to true when asked for exit */ bool exittoOS; @@ -145,20 +170,33 @@ typedef struct { bool debug_map; bool debug_player; bool debug_extra; + + int mana; /* Only for testing events TODO: Remove this! */ } Game; /* (Mibi88) TODO: Describe what this function is doing. */ void game_logic(Game *game); -/* Draws everything on screen. */ -void draw(Game *game); +/* game_draw() + * + * Draws everything on screen. + * game: The game struct. + */ +void game_draw(Game *game); -/* This render a small sign on the upper lecft corner of the screen */ -/* if the player can do an action */ -void render_indicator(Game *game); +/* game_render_indicator() + * + * This render a small sign on the upper left corner of the screen + * if the player can do an action + * game: The game struct. + */ +void game_render_indicator(Game *game); -/* Handle key presses. */ -void get_inputs(Game *game); +/* game_get_inputs() + * + * Handle key presses. + * game: The game struct. + */ +void game_get_inputs(Game *game); #endif - diff --git a/src/main.c b/src/main.c index 0375212..6029129 100644 --- a/src/main.c +++ b/src/main.c @@ -1,83 +1,86 @@ +#include "config.h" +#include +#include #include #include #include -#include - -#include - -#include "config.h" -#include "npc.h" #if USB_FEATURE - #include - #include -#endif //USB_FEATURE - +#include +#include +#endif // USB_FEATURE #if GRAYMODEOK - #include -#endif //GRAYMODEOK +#include +#endif // GRAYMODEOK -#include -#include +#if DEBUGMODE +#include +#endif /*DEBUGMODE*/ +#include "dialogs.h" #include "game.h" #include "mapdata.h" -#include "dialogs.h" +#include +#include +#include extern bopti_image_t player_face_img; - extern Map *worldRPG[]; /* Game data (defined in "game.h")*/ Game game = { NULL, - {12*PXSIZE, 36*PXSIZE, 0, 0, 12*PXSIZE, 36*PXSIZE, 100, SPEED, false, 0, false, false}, - false, false, false, 0 + {12 * PXSIZE, 36 * PXSIZE, 0, 0, 100, SPEED, false, 0, false, false, true}, + {{}, {}, 0}, + false, + false, + false, + 0, /* debug variables*/ - , false, false, false -}; + false, + false, + false, + 100}; -/* screen capture management code */ +/* screen capture management code. TODO: Clean this up! */ #if USB_FEATURE - void USB_feature( void ) - { - if (game.screenshot && usb_is_open()) { +void USB_feature(void) { + if(game.screenshot && usb_is_open()) { - #if GRAYMODEOK // This is a trick, if GRAYMODEOK is defined then - // we make the code accessible +#if GRAYMODEOK // This is a trick, if GRAYMODEOK is defined then + // we make the code accessible - if (dgray_enabled()) - usb_fxlink_screenshot_gray(false); - else + if(dgray_enabled()) + usb_fxlink_screenshot_gray(false); + else - #endif +#endif // else we just let the usual screeshot function - usb_fxlink_screenshot(false); - game.screenshot = false; - } + usb_fxlink_screenshot(false); + game.screenshot = false; + } + if(game.record && usb_is_open()) { - if (game.record && usb_is_open()) { - - #if GRAYMODEOK +#if GRAYMODEOK - if (dgray_enabled()) - usb_fxlink_videocapture_gray(false); - else + if(dgray_enabled()) + usb_fxlink_videocapture_gray(false); + else - #endif +#endif usb_fxlink_videocapture(false); - } } +} #endif @@ -89,48 +92,51 @@ int update_time(void) { } int main(void) { - + +#if DEBUGMODE + gdb_start_on_exception(); +#endif /*DEBUGMODE*/ + __printf_enable_fp(); - + int timer; timer = timer_configure(TIMER_TMU, 1000, GINT_CALL(update_time)); - if(timer < 0){ + if(timer < 0) { return -1; } timer_start(timer); game.map_level = worldRPG[0]; + events_init_handler(&game.handler); + events_bind_variable(&game.handler, (int *)&game.player.life, "life"); + events_bind_variable(&game.handler, &game.mana, "mana"); - reload_npc(&game); - - #if USB_FEATURE - usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL}; - usb_open(interfaces, GINT_CALL_NULL); - #endif + // reload_npc(&game); +#if USB_FEATURE + usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL}; + usb_open(interfaces, GINT_CALL_NULL); +#endif /* start grayscale engine */ - #if GRAYMODEOK - dgray(DGRAY_ON); - #endif +#if GRAYMODEOK + dgray(DGRAY_ON); +#endif -/* - showtext_dialog(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet.", true, true); - int in = showtext_dialog_ask(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet.", true, false, "Lorem\0Ipsum\0Dolor", 3, 0); - if(in==2) showtext_dialog(&game, &player_face_img, "You choosed Dolor", false, true); - else if(in==1) showtext_dialog(&game, &player_face_img, "You choosed Ipsum", false, true); - else showtext_dialog(&game, &player_face_img, "You choosed Lorem", false, true); -*/ +#if DEBUGMODE + dupdate(); + getkey(); +#endif - do{ + do { /* clear screen */ dclear(C_WHITE); /* render the map */ - draw(&game); + game_draw(&game); - #if DEBUGMODE && FXCG50 + /*#if DEBUGMODE && GINT_RENDER_RGB if (game.debug_map) { dfont( NULL ); @@ -141,7 +147,7 @@ int main(void) { dprint(10, 20, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", 1, worldRPG[1]->xmin, worldRPG[1]->ymin, worldRPG[1]->xmax, worldRPG[1]->ymax); - dprint(10, 30, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", + dprint(10, 30, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", 2, worldRPG[2]->xmin, worldRPG[2]->ymin, worldRPG[2]->xmax, worldRPG[2]->ymax); dprint(10, 40, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", @@ -160,14 +166,15 @@ int main(void) { { dfont( NULL ); for (int i=0; inbextradata; i++ ) - dprint( 10, 90+i*15, C_RED, "X= %d - Y= %d - T: %d - ID: %d - S: %c", - game.map_level->extradata[i].x, + dprint( 10, 90+i*15, C_RED, "X= %d - Y= %d - T: %d - ID: %d + - S: %c", game.map_level->extradata[i].x, game.map_level->extradata[i].y, game.map_level->extradata[i].dialogID, - game.map_level->dialogs[ game.map_level->extradata[i].dialogID ].ID, - game.map_level->dialogs[ game.map_level->extradata[i].dialogID ].conclusion1[0] ); + game.map_level->dialogs[ + game.map_level->extradata[i].dialogID ].ID, game.map_level->dialogs[ + game.map_level->extradata[i].dialogID ].conclusion1[0] ); } - #endif + #endif*/ /* start the logic of the game */ game_logic(&game); @@ -175,33 +182,30 @@ int main(void) { /* Screen blit */ dupdate(); - /* Screen capture feature if enabled */ - #if USB_FEATURE - USB_feature(); - #endif +/* Screen capture feature if enabled */ +#if USB_FEATURE + USB_feature(); +#endif /* Management of the inputs */ - get_inputs(&game); + game_get_inputs(&game); /* Run the game at max. 50fps */ - while(game.frame_duration < 20) sleep(); + while(game.frame_duration < 20) + sleep(); /* Reset frame_duration for the next frame */ game.frame_duration = 0; - }while(!game.exittoOS); // want to exit ? + } while(!game.exittoOS); // want to exit ? +/* shutdown grayengine*/ +#if GRAYMODEOK + dgray(DGRAY_OFF); +#endif - - /* shutdown grayengine*/ - #if GRAYMODEOK - dgray(DGRAY_OFF); - #endif - - - /* close USB */ - #if USB_FEATURE - usb_close(); - #endif +/* close USB */ +#if USB_FEATURE + usb_close(); +#endif timer_stop(timer); return 1; } - diff --git a/src/map.c b/src/map.c index d378263..0314811 100644 --- a/src/map.c +++ b/src/map.c @@ -1,14 +1,22 @@ #include "map.h" + #include "config.h" #include "game.h" #include +#include -extern Map *worldRPG[]; -//extern ExtraData *extraRPG[]; +extern Map level0; +extern Map level1; +extern Map level2; +extern Map level3; +extern Map level4; +Map *worldRPG[] = {&level0, &level1, &level2, &level3, &level4, NULL}; -void render_map(Game *game) { +// extern ExtraData *extraRPG[]; + +void map_render(Game *game) { Map *map_level = game->map_level; Player *player = &game->player; @@ -25,9 +33,10 @@ void render_map(Game *game) { unsigned char mx, my; /* dw and dh contain the amount of tiles that will be drawn on x and on * y. */ - unsigned char dw = DWIDTH/T_WIDTH+2, dh = DHEIGHT/T_HEIGHT+1; + unsigned char dw = DWIDTH / T_WIDTH + 2, dh = DHEIGHT / T_HEIGHT + 1; /* mw and mh will contain the height and the width of the map. */ - unsigned short int mw = map_level->w*T_WIDTH, mh = map_level->h*T_HEIGHT; + unsigned short int mw = map_level->w * T_WIDTH, + mh = map_level->h * T_HEIGHT; /* tile contains the tile to draw. */ short int tile; /* The position where I start drawing */ @@ -39,62 +48,62 @@ void render_map(Game *game) { /* The index of the current tile we're drawing in the layer. */ int current_index; /* Fix sx. */ - if(player->xx < DWIDTH / 2) { /* If I can't center the player because I'm near the left border of * the map. */ player->px = player->x; sx = 0; - }else if(player->x+DWIDTH/2>mw){ + } else if(player->x + DWIDTH / 2 > mw) { /* If I can't center the player because I'm near the right border of * the map. */ - sx = mw-DWIDTH; - player->px = player->x-sx; - }else{ + sx = mw - DWIDTH; + player->px = player->x - sx; + } else { /* I can center the player. */ - player->px = DWIDTH/2; - sx = player->x-player->px; + player->px = DWIDTH / 2; + sx = player->x - player->px; } /* Fix sy. */ - if(player->yy < DHEIGHT / 2) { /* If I can't center the player because I'm near the top border of * the map. */ player->py = player->y; sy = 0; - }else if(player->y+DHEIGHT/2>mh){ + } else if(player->y + DHEIGHT / 2 > mh) { /* If I can't center the player because I'm near the bottom border * of the map. */ - sy = mh-DHEIGHT; - player->py = player->y-sy; - }else{ + sy = mh - DHEIGHT; + player->py = player->y - sy; + } else { /* I can center the player. */ - player->py = DHEIGHT/2; - sy = player->y-player->py; + player->py = DHEIGHT / 2; + sy = player->y - player->py; } - tx = sx/T_WIDTH; - ty = sy/T_HEIGHT; - mx = sx-tx*T_WIDTH; - my = sy-ty*T_HEIGHT; - for (l = 0; l < map_level->nblayers-1; l++){ + tx = sx / T_WIDTH; + ty = sy / T_HEIGHT; + mx = sx - tx * T_WIDTH; + my = sy - ty * T_HEIGHT; + for(l = 0; l < map_level->nblayers - 1; l++) { /* Draw a layer of the map on screen. */ - for(y=0;y=0 && tx+x < map_level->w && - ty+y>=0 && ty+y < map_level->h){ + if(tx + x >= 0 && tx + x < map_level->w && ty + y >= 0 && + ty + y < map_level->h) { /* index of the current tile */ - current_index = (y+ty) * map_level->w + tx+x; + current_index = (y + ty) * map_level->w + tx + x; /* we get the ID of the tile in the current drawable layers */ tile = map_level->layers[l][current_index]; - + /* tile == -1 means nothing to be drawn */ - if(tile >= 0){ + if(tile >= 0) { /* get x and y position in the tileset image */ xtile = (tile % map_level->tileset_size) * T_WIDTH; ytile = (tile / map_level->tileset_size) * T_HEIGHT; /* render */ - dsubimage(x*T_WIDTH-mx, y*T_HEIGHT-my, + dsubimage(x * T_WIDTH - mx, y * T_HEIGHT - my, map_level->tileset, xtile, ytile, T_WIDTH, T_HEIGHT, DIMAGE_NONE); } @@ -104,8 +113,8 @@ void render_map(Game *game) { } } -void render_map_by_layer(Game *game, int layer) { - +void map_render_by_layer(Game *game, int layer) { + Map *map_level = game->map_level; Player *player = &game->player; @@ -121,9 +130,10 @@ void render_map_by_layer(Game *game, int layer) { unsigned char mx, my; /* dw and dh contain the amount of tiles that will be drawn on x and on * y. */ - unsigned char dw = DWIDTH/T_WIDTH+2, dh = DHEIGHT/T_HEIGHT+1; + unsigned char dw = DWIDTH / T_WIDTH + 2, dh = DHEIGHT / T_HEIGHT + 1; /* mw and mh will contain the height and the width of the map. */ - unsigned short int mw = map_level->w*T_WIDTH, mh = map_level->h*T_HEIGHT; + unsigned short int mw = map_level->w * T_WIDTH, + mh = map_level->h * T_HEIGHT; /* tile contains the tile to draw. */ short int tile; /* The position where I start drawing */ @@ -131,109 +141,101 @@ void render_map_by_layer(Game *game, int layer) { /* The position of the tile in the tileset. */ unsigned short int xtile, ytile; /* Fix sx. */ - if(player->xx < DWIDTH / 2) { /* If I can't center the player because I'm near the left border of * the map. */ player->px = player->x; sx = 0; - }else if(player->x+DWIDTH/2>mw){ + } else if(player->x + DWIDTH / 2 > mw) { /* If I can't center the player because I'm near the right border of * the map. */ - sx = mw-DWIDTH; - player->px = player->x-sx; - }else{ + sx = mw - DWIDTH; + player->px = player->x - sx; + } else { /* I can center the player. */ - player->px = DWIDTH/2; - sx = player->x-player->px; + player->px = DWIDTH / 2; + sx = player->x - player->px; } /* Fix sy. */ - if(player->yy < DHEIGHT / 2) { /* If I can't center the player because I'm near the top border of * the map. */ player->py = player->y; sy = 0; - }else if(player->y+DHEIGHT/2>mh){ + } else if(player->y + DHEIGHT / 2 > mh) { /* If I can't center the player because I'm near the bottom border * of the map. */ - sy = mh-DHEIGHT; - player->py = player->y-sy; - }else{ + sy = mh - DHEIGHT; + player->py = player->y - sy; + } else { /* I can center the player. */ - player->py = DHEIGHT/2; - sy = player->y-player->py; + player->py = DHEIGHT / 2; + sy = player->y - player->py; } - tx = sx/T_WIDTH; - ty = sy/T_HEIGHT; - mx = sx-tx*T_WIDTH; - my = sy-ty*T_HEIGHT; + tx = sx / T_WIDTH; + ty = sy / T_HEIGHT; + mx = sx - tx * T_WIDTH; + my = sy - ty * T_HEIGHT; /* Draw a layer of the map on screen. */ - for(y=0;y=0 && tx+x < map_level->w && - ty+y>=0 && ty+y < map_level->h){ + * I draw it. */ + if(tx + x >= 0 && tx + x < map_level->w && ty + y >= 0 && + ty + y < map_level->h) { /* index of the current tile */ - int currentIndex = (y+ty) * map_level->w + tx+x; + int currentIndex = (y + ty) * map_level->w + tx + x; /* we get the ID of the tile in the current drawable layers - */ + */ tile = map_level->layers[layer][currentIndex]; - + /* tile == -1 means nothing to be drawn */ - if(tile >= 0){ + if(tile >= 0) { /* get x and y position in the tileset image */ xtile = (tile % map_level->tileset_size) * T_WIDTH; ytile = (tile / map_level->tileset_size) * T_HEIGHT; /* render */ - dsubimage(x*T_WIDTH-mx, y*T_HEIGHT-my, - map_level->tileset, xtile, ytile, T_WIDTH, - T_HEIGHT, DIMAGE_NONE); + dsubimage(x * T_WIDTH - mx, y * T_HEIGHT - my, + map_level->tileset, xtile, ytile, T_WIDTH, + T_HEIGHT, DIMAGE_NONE); } } } } } -short int get_tile(Game *game, int x, int y, int l) { - +short int map_get_tile(Game *game, int x, int y, int l) { + Map *map_level = game->map_level; - + /* Get the tile at (x, y) on layer l. Returns the tile ID or MAP_OUTSIDE if * it's not found. */ - return (x>=0 && x < (int) map_level->w && y>=0 && y < (int) map_level->h) ? - map_level->layers[l][y * map_level->w + x] : MAP_OUTSIDE; + return (x >= 0 && x < (int)map_level->w && y >= 0 && y < (int)map_level->h) + ? map_level->layers[l][y * map_level->w + x] + : MAP_OUTSIDE; } -short int get_walkable(Game *game, int x, int y) { - +short int map_get_walkable(Game *game, int x, int y) { + Map *map_level = game->map_level; /* Get the tile at (x, y). Returns the tile ID or MAP_OUTSIDE if she's not * found. */ - return (x>=0 && x < (int) map_level->w && y>=0 && y < (int) map_level->h) ? - map_level->walkable[y * map_level->w + x] : MAP_OUTSIDE; + return (x >= 0 && x < (int)map_level->w && y >= 0 && y < (int)map_level->h) + ? map_level->walkable[y * map_level->w + x] + : MAP_OUTSIDE; } -/* return the pointer to the map containing the given position */ -Map *get_map_for_coordinates( Game *game, int x, int y ) -{ - /* check if the current map contains the point */ - if (x>= (int)game->map_level->xmin && x< (int)game->map_level->xmax && - y>= (int)game->map_level->ymin && y< (int)game->map_level->ymax) - return game->map_level; - - /* else we check in worldRPG if there is a mal containing that point */ +Map *map_get_for_tile(Game *game, int x, int y) { int i = 0; - Map *current = worldRPG[i]; - do - { - if (x>= (int)current->xmin && x< (int)current->xmax && - y>= (int)current->ymin && y< (int)current->ymax) - return current; + Map *map = worldRPG[i]; + do { + int rx = x - map->x; + int ry = y - map->y; + if(rx >= 0 && rx < (int)map->w && ry >= 0 && ry < (int)map->h) { + return map; + } i++; - current = worldRPG[i]; - } - while (current!=NULL); - - /* else we return NULL cause the point is a not within a map */ - return NULL; -} \ No newline at end of file + map = worldRPG[i]; + } while(map != NULL); + return game->map_level; +} diff --git a/src/map.h b/src/map.h index 1586186..249f148 100644 --- a/src/map.h +++ b/src/map.h @@ -1,39 +1,55 @@ #ifndef MAP_H #define MAP_H - #define BACKGROUND 0 #define FOREGROUND 1 -#define MAP_OUTSIDE -2 /* Returned by get_tile_at_pos if the point is outside of - * the map. */ +#define MAP_OUTSIDE \ + -2 /* Returned by get_tile_at_pos if the point is outside of \ + * the map. */ #include "game.h" #include "player.h" - - /* Structure 'Map' has been moved to game.h */ /* to avoid circular references between map.h, game.h and player.h */ /* only methods propotypes are now in dedicated header files */ - - -/* Draws the map map on the entire screen to be viewed by the player player. */ -void render_map(Game *game); - -/* Draws the map layer on the entire screen to be viewed by the player player. +/* map_render() + * + * Draws the map map on the entire screen to be viewed by the player player. + * game: The game struct. */ -void render_map_by_layer(Game *game, int layer); +void map_render(Game *game); -/* Get the tile at (x, y) of the map map. If the tile is located outside of the - * screen, MAP_OUTSIDE is returned. */ -short int get_tile(Game *game, int x, int y, int l); +/* map_render_by_layer() + * + * Draws the map layer on the entire screen to be viewed by the player player. + * game: The game struct. + * layer: The layer to render. + */ +void map_render_by_layer(Game *game, int layer); -/* Returns what is in the walkable layer at (x, y). */ -short int get_walkable(Game *game, int x, int y); +/* map_get_tile() + * + * Get the tile at (x, y) of the map map. If the tile is located outside of the + * screen, MAP_OUTSIDE is returned. + * game: The game struct. + * x: The coordinates of the tile. + * y: The coordinates of the tile. + * l: The layer of the tile. + */ +short int map_get_tile(Game *game, int x, int y, int l); -/* return the pointer to the map containing the given position */ -Map* get_map_for_coordinates(Game *game, int x, int y ); +/* map_get_walkable() + * + * Returns what is in the walkable layer at (x, y). + * game: The game struct. + * x: The coordinates of the tile. + * y: The coordinates of the tile. + */ +short int map_get_walkable(Game *game, int x, int y); + +Map *map_get_for_tile(Game *game, int x, int y); #endif diff --git a/src/mapdata.h b/src/mapdata.h index fb40c12..0b6d0e4 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -1,10 +1,10 @@ #ifndef MAPDATA_H #define MAPDATA_H -#include #include "game.h" +#include + extern Map *worldRPG[]; #endif - diff --git a/src/memory.c b/src/memory.c index 9e3e58a..99901c4 100644 --- a/src/memory.c +++ b/src/memory.c @@ -1,12 +1,11 @@ #include "memory.h" -bool is_in(short int *array, short int array_length, short int item) { +bool memory_is_in(short int *array, short int array_length, short int item) { short int i; - for(i=0;i - -bool is_in(short int *array, short int array_length, short int item); +/* memory_is_in() + * + * returns true if item is in array. + * array: The array to search in. + * array_length: The length of the array. + * item: The item to search for. + */ +bool memory_is_in(short int *array, short int array_length, short int item); #endif - diff --git a/src/npc.c b/src/npc.c index 86a62b7..5479ba0 100644 --- a/src/npc.c +++ b/src/npc.c @@ -1,208 +1,275 @@ #include "npc.h" + +#include "config.h" #include "dialogs.h" #include "game.h" #include "map.h" -#include "config.h" + #include #include /*debug*/ - +#include #include #include -#include +extern bopti_image_t tiny_npc_male; +extern bopti_image_t tiny_npc_female; +extern bopti_image_t tiny_npc_milkman; +extern bopti_image_t tiny_npc_police; -extern bopti_image_t demo_PNJ_img; +// NPC *npcRPG; +// uint32_t nbNPC = 0; +float length(float x, float y) { return sqrtf(x * x + y * y); } -/* the color of the text to go to the next dialog phase */ -/* it improves readability to have somathing lighter */ -#if defined(FXCG50) - #define PATH_COLOR C_RED -#else - #define PATH_COLOR C_BLACK -#endif - - -NPC *npcRPG; -uint32_t nbNPC = 0; - -float length( float x, float y ) -{ - return sqrtf( x*x+y*y ); +int npc_clear_path(NPC *npc) { + npc->currentPoint = 0; + npc->hasPath = 0; + npc->path_length = 0; + free(npc->xpath); + free(npc->ypath); + npc->xpath = malloc(4); + npc->ypath = malloc(4); + if(npc->xpath == NULL || npc->ypath == NULL) + return 1; + return 0; } -void update_npc( [[maybe_unused]] Game *game) -{ - for( uint32_t u=0; u0.5f) - { - vecX /= vecN*2.0; - vecY /= vecN*2.0; - } - else - { - npcRPG[u].currentPoint++; - npcRPG[u].currentPoint = npcRPG[u].currentPoint % npcRPG[u].path_length; - } - - npcRPG[u].curx += vecX; - npcRPG[u].cury += vecY; - - } - } - +int npc_append_path(uint16_t x, uint16_t y, NPC *npc) { + npc->xpath = realloc(npc->xpath, npc->path_length * 2 + 2); + npc->ypath = realloc(npc->ypath, npc->path_length * 2 + 2); + if(npc->xpath == NULL || npc->ypath == NULL) + return 1; + npc->path_length++; + npc->xpath[npc->path_length - 1] = x - npc->x; + npc->ypath[npc->path_length - 1] = y - npc->y; + return 0; } -void reload_npc(Game *game) -{ - if (npcRPG!=NULL) - { - free(npcRPG); - npcRPG = NULL; +void as_clean(uint8_t *visited, uint8_t *gscore, uint8_t *fscore) { + free(visited); + free(gscore); + free(fscore); +} - } - - nbNPC = 0; +int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos, + int16_t dest, NPC *npc) { + if(npc_clear_path(npc)) + goto as_recons_fail; + int16_t next = came_from[dest]; - for (uint32_t u=0; umap_level->nbextradata; u++) //uint pour enlever un warning - { - ExtraData *Data = &game->map_level->extradata[u]; + unsigned int i; - if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */ - { - nbNPC++; + for(i = 0; i < 64; i++) { + if(npc_append_path((next % w) * T_WIDTH, (next / h) * T_HEIGHT, npc)) { + goto as_recons_fail; + } + + next = came_from[next]; + if(next == spos) { + if(npc_append_path((spos % w) * T_WIDTH, (spos / h) * T_HEIGHT, + npc)) + goto as_recons_fail; + break; } } - npcRPG = (NPC*) malloc( nbNPC * sizeof(NPC) ); - int currentNPC=0; + uint16_t tx, ty; - for (uint32_t u=0; umap_level->nbextradata; u++) //uint pour enlever un warning - { - ExtraData *Data = &game->map_level->extradata[u]; + // Flip the path because it started from the end - if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */ - { - npcRPG[currentNPC].curx = (float) Data->x; - npcRPG[currentNPC].cury = (float) Data->y; - npcRPG[currentNPC].x = Data->x; - npcRPG[currentNPC].y = Data->y; - npcRPG[currentNPC].dialogID = Data->dialogID; - npcRPG[currentNPC].currentPoint = 1; - npcRPG[currentNPC].hasPath = Data->hasPath; - npcRPG[currentNPC].path_length = Data->path_length; - npcRPG[currentNPC].xpath = Data->xpath; - npcRPG[currentNPC].ypath = Data->ypath; - npcRPG[currentNPC].paused = false; - currentNPC++; + for(i = 0; i < npc->path_length / 2; i++) { + tx = npc->xpath[i]; + ty = npc->ypath[i]; + npc->xpath[i] = npc->xpath[npc->path_length - i - 1]; + npc->ypath[i] = npc->ypath[npc->path_length - i - 1]; + npc->ypath[npc->path_length - i - 1] = tx; + npc->ypath[npc->path_length - i - 1] = ty; + } + + free(came_from); + + npc->hasPath = true; + + return 0; + +as_recons_fail: + + free(came_from); + + return 1; +} + +// Returns non zero error code on failure +// Custom a* implemetation +// Unoptimized, may become an issue +int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { + int32_t i, j; + + int32_t w = full_map->w; + int32_t h = full_map->h; + int32_t x = (npc->curx >> PRECISION) / T_WIDTH; + int32_t y = (npc->cury >> PRECISION) / T_HEIGHT; + dest_x /= T_WIDTH; + dest_y /= T_HEIGHT; + int32_t spos = y * w + x; + + uint8_t *map = full_map->walkable; + + if(dest_x < 0 || dest_x > w || dest_y < 0 || dest_x > h) + return 2; + if(map[spos]) + return 2; + if(map[dest_y * w + dest_x]) + return 2; + + npc_clear_path(npc); + + uint8_t *visited = malloc(w * h); + for(i = 0; i < w * h; i++) + visited[i] = 1; + visited[spos] = 0; + + int16_t *came_from = malloc(w * h * 2); + for(i = 0; i < w * h; i++) + came_from[i] = -1; + + uint8_t *gscore = malloc(w * h * 2); + for(i = 0; i < w * h; i++) + gscore[i] = 255; + gscore[spos] = 0; + + uint8_t *fscore = malloc(w * h * 2); + for(i = 0; i < w * h; i++) + fscore[i] = 255; + fscore[spos] = length(dest_x - x, dest_y - y); + + uint8_t bscore; + int32_t bx = x; + int32_t by = y; + + for(int iter = 0; iter < 64; iter++) { + bscore = 255; + // Cheapest known tile + for(i = 0; i <= w * h; i++) { + if(visited[i]) + continue; + if(map[i] == 1) + continue; + if(fscore[i] > bscore) + continue; + bx = i % w; + by = i / w; + bscore = fscore[i]; + } + if(bx == dest_x && by == dest_y) { + as_clean(visited, gscore, fscore); + return as_reconstruct_path(came_from, w, h, spos, + dest_y * w + dest_x, npc); + } + + visited[by * w + bx] = 1; + + int att_score; + + for(i = bx - 1; i < bx + 2; i++) { + if(i > w) + break; + for(j = by - 1; j < by + 2; j++) { + if(j > h) + break; + if(map[j * w + i] == 1) + continue; + if(i == bx && j == by) + continue; + att_score = gscore[by * w + bx] + round(length(bx - i, by - j)); + if(att_score < gscore[j * w + i]) { + came_from[j * w + i] = by * w + bx; + gscore[j * w + i] = att_score; + fscore[j * w + i] = + att_score + round(length(dest_x - i, dest_y - j)); + if(visited[j * w + i]) + visited[j * w + i] = 0; + } + } } } + + as_clean(visited, gscore, fscore); + + free(came_from); + return 3; +} + +// Refactoring to make adding complexity cleaner +void update_npcs(Game *game) { + for(uint32_t u = 0; u < game->map_level->nbNPC; u++) { + update_npc(&game->map_level->npcs[u]); + } +} + +void update_npc(NPC *npc) { + /* if the NPC has no path or is paused, skip it */ + if(!npc->hasPath || npc->paused == true) + return; + + float vecX = (float)(npc->xpath[npc->currentPoint] + npc->x) - + (npc->curx >> PRECISION); + float vecY = (float)(npc->ypath[npc->currentPoint] + npc->y) - + (npc->cury >> PRECISION); + float vecN = length(vecX, vecY); + + if(vecN > 0.5f) { + vecX /= vecN * 2.0; + vecY /= vecN * 2.0; + } else { + npc->currentPoint++; + npc->currentPoint = npc->currentPoint % npc->path_length; + } + + npc->curx += vecX * (float)(1 << PRECISION); + npc->cury += vecY * (float)(1 << PRECISION); } void npc_draw(Game *game) { Player *pl = &game->player; + size_t i; + const bopti_image_t *npc_sprites[FACES] = { + &tiny_npc_male, &tiny_npc_female, &tiny_npc_milkman, &tiny_npc_police}; - for (uint32_t u=0; uhasPath==1) /* this NPC has a trajectory */ - { - int NbPoints = Data->path_length+1; - for(int v=0; vx + - Data->xpath[v % NbPoints]) * PXSIZE) - -(int16_t) pl->wx; - int16_t deltaY1=((int16_t) (Data->y + - Data->ypath[v % NbPoints]) * PXSIZE) - -(int16_t) pl->wy; - int16_t deltaX2=((int16_t) (Data->x + - Data->xpath[(v+1) % NbPoints]) * PXSIZE) - -(int16_t) pl->wx; - int16_t deltaY2=((int16_t) (Data->y + - Data->ypath[(v+1) % NbPoints]) * PXSIZE) - -(int16_t) pl->wy; - - dline( pl->px + deltaX1, pl->py + deltaY1, - pl->px + deltaX2, pl->py + deltaY2, - PATH_COLOR); - } - } - #endif // DEBUGMODE + for(uint32_t u = 0; u < game->map_level->nbNPC; u++) { + NPC *Data = &game->map_level->npcs[u]; - int16_t delX=((int16_t) (Data->curx * PXSIZE))-(int16_t) pl->wx; - int16_t delY=((int16_t) (Data->cury * PXSIZE))-(int16_t) pl->wy; - dimage( pl->px-P_WIDTH/2+delX, pl->py-P_HEIGHT/2+delY, &demo_PNJ_img); - } -} +/* Render the path if in debug*/ +#if DEBUGMODE + if(!Data->hasPath) + continue; /* this NPC has a trajectory */ + int NbPoints = Data->path_length + 1; + for(int v = 0; v < NbPoints; v++) { + int16_t deltaX1 = + ((int16_t)(Data->x + Data->xpath[v % NbPoints]) * PXSIZE) - + (int16_t)pl->wx; + int16_t deltaY1 = + ((int16_t)(Data->y + Data->ypath[v % NbPoints]) * PXSIZE) - + (int16_t)pl->wy; + int16_t deltaX2 = + ((int16_t)(Data->x + Data->xpath[(v + 1) % NbPoints]) * + PXSIZE) - + (int16_t)pl->wx; + int16_t deltaY2 = + ((int16_t)(Data->y + Data->ypath[(v + 1) % NbPoints]) * + PXSIZE) - + (int16_t)pl->wy; - - -void OLD_npc_draw(Game *game) { - Player *player = &game->player; - - for (uint32_t u=0; umap_level->nbextradata; u++) //uint pour enlever un warning - { - ExtraData *Data = &game->map_level->extradata[u]; - - - if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */ - { - - /* TODO : This is for debugging purpose, JUste to render the path */ - /* to be followed by the NPC when this will be implemented */ - - #if DEBUGMODE - - if (Data->hasPath==1) /* this NPC has a trajectory */ - { - int NbPoints = Data->path_length+1; - for(int v=0; vx + Data->xpath[v % NbPoints]) * PXSIZE)-(int16_t) player->wx; - int16_t deltaY1=((int16_t) (Data->y + Data->ypath[v % NbPoints]) * PXSIZE)-(int16_t) player->wy; - - int16_t deltaX2=((int16_t) (Data->x + Data->xpath[(v+1) % NbPoints]) * PXSIZE)-(int16_t) player->wx; - int16_t deltaY2=((int16_t) (Data->y + Data->ypath[(v+1) % NbPoints]) * PXSIZE)-(int16_t) player->wy; - - dline( player->px + deltaX1, player->py + deltaY1, - player->px + deltaX2, player->py + deltaY2, - PATH_COLOR); - } - } - - #endif // DEBUGMODE - - int16_t deltaX=((int16_t) (Data->x * PXSIZE))-(int16_t) player->wx; - int16_t deltaY=((int16_t) (Data->y * PXSIZE))-(int16_t) player->wy; - dimage( player->px-P_WIDTH/2+deltaX, - player->py-P_HEIGHT/2+deltaY, - &demo_PNJ_img); - + dline(pl->px + deltaX1, pl->py + deltaY1, pl->px + deltaX2, + pl->py + deltaY2, PATH_COLOR); } +#endif // DEBUGMODE + int16_t delX = ((Data->curx * PXSIZE) >> PRECISION) - (int16_t)pl->x; + int16_t delY = ((Data->cury * PXSIZE) >> PRECISION) - (int16_t)pl->y; + bopti_image_t *face = npc_sprites[Data->face]; + dimage(pl->px - P_WIDTH / 2 + delX, pl->py - P_HEIGHT / 2 + delY, face); } - - } - diff --git a/src/npc.h b/src/npc.h index e7e1e12..d12161c 100644 --- a/src/npc.h +++ b/src/npc.h @@ -1,47 +1,49 @@ #ifndef NPC_H #define NPC_H - -#include -#include - #include "game.h" #include "memory.h" +#include +#include -typedef struct -{ - /* current coordinates of the NPC */ - float curx, cury; +enum { - /* initial coordinates of the NPC (needed to get absolute coordinates of path) */ - uint32_t x; - uint32_t y; - /* the ID of the first element of the dialog */ - /* (to be aligned with "dialogs.json" IDs)*/ - uint32_t dialogID; - /* the number of the target point of the path */ - /* Note: it must keep the value 0 if NPC has no path assigned */ - uint32_t currentPoint; - /* data of the path */ - uint32_t hasPath; - uint32_t path_length; - int16_t *xpath; - int16_t *ypath; + NPC_NONE = 0, + NPC_FRIENDLY = 1, // The player's team + NPC_HOSTILE = 2, // to the player + NPC_ALL = 3 - /* is the current NPC in pause (during dialog) */ - bool paused; -} NPC; +}; +// Frees then malloc()s a new path to npc +// Useful if you want to safely edit a path +int npc_clear_path(NPC *npc); +// Adds point x,y to the path of npc +// Won't work on static NPCs, use npc_clear_path before or make them on the heap +int npc_append_path(uint16_t x, uint16_t y, NPC *npc); + +// Clears the NPCs path and creates a new one going to dest, +// avoiding non-walkable tiles +// Returns non-zero on failure +int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc); + +// realloc()s npcRPG to adequate size and returns a pointer to the new element +// Returns NULL on failure +NPC *npc_create(); + +// Pops the NPC from npcRPG +void npc_remove(NPC *npc); /* Draws the player player. This function should be called after drawing the * map! */ void npc_draw(Game *game); -void update_npc(Game *game); +void update_npcs(Game *game); + +void update_npc(NPC *npc); void reload_npc(Game *game); #endif - diff --git a/src/player.c b/src/player.c index 2274b11..6751d15 100644 --- a/src/player.c +++ b/src/player.c @@ -1,267 +1,235 @@ #include "player.h" + +#include "config.h" #include "dialogs.h" #include "game.h" #include "map.h" -#include "config.h" #include "npc.h" + #include +extern bopti_image_t player_male_img; +extern bopti_image_t player_female_img; +extern bopti_image_t npc_male; +extern bopti_image_t npc_female; +extern bopti_image_t npc_milkman; +extern bopti_image_t npc_police; +extern bopti_image_t SGN_Icon_img; +extern bopti_image_t INFO_Icon_img; + +const bopti_image_t *faces[FACES] = {&npc_male, &npc_female, &npc_milkman, + &npc_police}; + const char one_px_mov[8] = { - 0, -1, /* Up */ - 0, 1, /* Down */ - -1, 0, /* Left */ - 1, 0 /* Right */ + 0, -1, /* Up */ + 0, 1, /* Down */ + -1, 0, /* Left */ + 1, 0 /* Right */ }; /* TODO: Search for all hard tiles in the tileset. hard_tiles is a list of their * IDs */ /* The speed of the player on the diffrent tiles in the walkable layer. */ #define WALKABLE_TILE_MAX 4 -const short int walkable_speed[WALKABLE_TILE_MAX] = { - SPEED, 0, PXSIZE, PXSIZE -}; +const short int walkable_speed[WALKABLE_TILE_MAX] = {SPEED, 0, PXSIZE, PXSIZE}; /* How much damage the player takes on the diffrent tiles in the walkable * layer. */ -const char damage_taken_walkable[WALKABLE_TILE_MAX] = { - 0, 0, 5, 0 -}; +const char damage_taken_walkable[WALKABLE_TILE_MAX] = {0, 0, 5, 0}; extern bopti_image_t demo_player_img; extern NPC *npcRPG; extern uint32_t nbNPC; - void player_draw(Game *game) { Player *player = &game->player; - dimage(player->px-P_WIDTH/2, player->py-P_HEIGHT/2, &demo_player_img); + dimage(player->px - P_WIDTH / 2, player->py - P_HEIGHT / 2, + player->is_male ? &player_male_img : &player_female_img); } -void player_move(Game *game, Direction direction) { +void player_move(Game *game, Direction direction) { Player *player = &game->player; - /* How this player movement will modify the player x and y. */ char dx, dy; - + /* If the player will collide with a hard tile or if the will go outside of * the map. */ - - if(player_collision(game, direction, P_CENTER)){ - + + if(player_collision(game, direction, P_CENTER)) { + /* If the will collide with the center of the player. */ - dx = one_px_mov[direction*2]*player->speed; - dy = one_px_mov[direction*2+1]*player->speed; - + dx = one_px_mov[direction * 2] * player->speed; + dy = one_px_mov[direction * 2 + 1] * player->speed; + player_fix_position(game, dx, dy); - } - else{ + } else { if(player_collision(game, direction, P_RIGHTDOWN) || - player_collision(game, direction, P_LEFTUP)){ - + player_collision(game, direction, P_LEFTUP)) { + /* If the will collide with the edges of the player. */ /* I fix his position so he won't be partially in the tile. */ /* I invert dx and dy to fix the axis where he is not moving on. */ /* Do not replace dx==0 with !dx or dy==0 with !dy, it won't work! */ - dx = one_px_mov[direction*2]*player->speed; - dy = one_px_mov[direction*2+1]*player->speed; - - player_fix_position(game, dx==0, dy==0); + dx = one_px_mov[direction * 2] * player->speed; + dy = one_px_mov[direction * 2 + 1] * player->speed; + + player_fix_position(game, dx == 0, dy == 0); } - + /* If he won't collide with the center, so I just move him normally */ - dx = one_px_mov[direction*2]*player->speed; - dy = one_px_mov[direction*2+1]*player->speed; - + dx = one_px_mov[direction * 2] * player->speed; + dy = one_px_mov[direction * 2 + 1] * player->speed; + player->x += dx; player->y += dy; } - player->wx = game->map_level->xmin * PXSIZE + player->x; - player->wy = game->map_level->ymin * PXSIZE + player->y; + /* Check if we should change map */ + Map *target = map_get_for_tile(game, + game->map_level->x + player->x / T_WIDTH + + one_px_mov[direction * 2], + game->map_level->y + player->y / T_HEIGHT + + one_px_mov[direction * 2 + 1]); + if(target != game->map_level) { + if(target->x > game->map_level->x) { + player->x = 0; + } + if(target->x < game->map_level->x) { + player->x = target->w * T_WIDTH; + } + if(target->y > game->map_level->y) { + player->y = 0; + } + if(target->y < game->map_level->y) { + player->y = target->h * T_HEIGHT; + } + game->map_level = target; + } } - -extern bopti_image_t demo_player_img; -extern bopti_image_t NPC_Icon_img; -extern bopti_image_t SGN_Icon_img; -extern bopti_image_t INFO_Icon_img; - - void player_action(Game *game) { - if( game->player.isDoingAction ) return; /* alreday doing something (action IS NOT with an NPC ) */ + /* already doing something, or can't do anything*/ + if(game->player.isDoingAction || !game->player.canDoSomething) + return; - if( game->player.canDoSomething && !game->player.isInteractingWithNPC ) /* we can do something */ - { + if(!game->player.isInteractingWithNPC) { + /* we can do something */ /* we indicate that the player is occupied */ game->player.isDoingAction = true; - ExtraData *currentData = &game->map_level->extradata[game->player.whichAction]; - - /* we use the correct image as per the class of the item */ + Sign *sign = &game->map_level->signs[game->player.whichAction]; bopti_image_t *face; - /* we use the correct image as per the class of the item */ - + /* we use the correct image as per the type of the item */ - if (strcmp("INFO", currentData->type)==0) + if(sign->icon) face = &INFO_Icon_img; - //else if (strcmp("NPC", currentData->type)==0) - // face = &NPC_Icon_img; - else if (strcmp("SGN", currentData->type)==0) + else face = &SGN_Icon_img; - else face = &demo_player_img; - uint32_t dialogStart = currentData->dialogID; + uint32_t dialogStart = sign->dialogID; - initiate_dialog_sequence( game, face, dialogStart ); + dialogs_initiate_sequence(game, face, dialogStart); /* when done we release the occupied status of the player */ game->player.isDoingAction = false; - } - else if( game->player.canDoSomething && game->player.isInteractingWithNPC ) /* we can do something (action IS with an NPC ) */ - { + } else { + /* we can do something (action IS with an NPC) */ /* we indicate that the player is occupied */ game->player.isDoingAction = true; - NPC *currentNPC = &npcRPG[game->player.whichAction]; + NPC *currentNPC = &game->map_level->npcs[game->player.whichAction]; - /* we use the correct image as per the class of the item */ + /* we use the correct image as per the class of the item */ + bopti_image_t *face = &npc_male; - bopti_image_t *face = &NPC_Icon_img; + /* It's a NPC */ + face = (bopti_image_t *)faces[currentNPC->face]; uint32_t dialogStart = currentNPC->dialogID; - /* we setr this NPC to paused to avoid changing its position while talking (the rest of the NPCs pursue their action)*/ + /* we set this NPC to paused to avoid changing its position while + * talking (the rest of the NPCs pursue their action) */ currentNPC->paused = true; - - initiate_dialog_sequence( game, face, dialogStart ); + dialogs_initiate_sequence(game, face, dialogStart); /* when done we release the occupied status of the player */ game->player.isDoingAction = false; currentNPC->paused = false; } - - - } bool player_collision(Game *game, Direction direction, - Checkpos nomov_axis_check) { + Checkpos nomov_axis_check) { Player *player = &game->player; /* Where is the tile where he will go to from his position. */ - char dx = one_px_mov[direction*2]; - char dy = one_px_mov[direction*2+1]; + char dx = one_px_mov[direction * 2]; + char dy = one_px_mov[direction * 2 + 1]; - if(!dx){ + if(!dx) { dx += nomov_axis_check; - }else if(!dy){ + } else if(!dy) { dy += nomov_axis_check; } - - dx = dx*(P_WIDTH/2+1); - dy = dy*(P_HEIGHT/2+1); - + + dx = dx * (P_WIDTH / 2 + 1); + dy = dy * (P_HEIGHT / 2 + 1); + /* The tile he will go to. */ - int player_tile_x = player->x+dx; - int player_tile_y = player->y+dy; - - /* check where the player is expected to go on the next move */ - /* if outside the map, we check if there is a map on the other */ - /* side of the current map*/ - if (get_walkable(game, player_tile_x, player_tile_y) == MAP_OUTSIDE) - { - // we compute the expected world coordinates accordingly - // while taking care of the scaling between fx and cg models (PXSIZE) - int worldX = (player->wx+dx) / PXSIZE; - int worldY = (player->wy+dy) / PXSIZE; - Map *map = get_map_for_coordinates(game, worldX, worldY ); - if (map!=NULL && map!=game->map_level) - { - Map *backupmap = game->map_level; - int backupx = player->x; - int backupy = player->y; - int backupwx = player->wx; - int backupwy = player->wy; - - game->map_level = map; - - player->wx = worldX * PXSIZE; - player->wy = worldY * PXSIZE; - - player->x = (worldX - map->xmin ) * PXSIZE; - player->y = (worldY - map->ymin ) * PXSIZE; - - int on_walkable = get_walkable(game, player->x/T_WIDTH, - player->y/T_HEIGHT); - - int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ? - walkable_speed[on_walkable] : 0; - - /* if he's on a hard tile and we need to revert the changes as */ - /* tile on the next side of the border is not walkable */ - - if(!speed){ - game->map_level = backupmap; - player->x = backupx; - player->y = backupy; - player->wx = backupwx; - player->wy = backupwy; - return true; /* He will collide with it. */ - } - - /* we update the list of NPCs in the current map */ - /* to follow the trajectories */ - reload_npc( game ); - - return false; - } - } - + int player_tile_x = player->x + dx; + int player_tile_y = player->y + dy; /* Handle a negative position differently than a positive one. */ - if(player_tile_x < 0) player_tile_x = player_tile_x/T_WIDTH-1; - else player_tile_x = player_tile_x/T_WIDTH; - - if(player_tile_y < 0) player_tile_y = player_tile_y/T_HEIGHT-1; - else player_tile_y = player_tile_y/T_HEIGHT; - - int on_walkable = get_walkable(game, player_tile_x, player_tile_y); - - int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ? - walkable_speed[on_walkable] : 0; - + if(player_tile_x < 0) + player_tile_x = player_tile_x / T_WIDTH - 1; + else + player_tile_x = player_tile_x / T_WIDTH; + + if(player_tile_y < 0) + player_tile_y = player_tile_y / T_HEIGHT - 1; + else + player_tile_y = player_tile_y / T_HEIGHT; + + int on_walkable = map_get_walkable(game, player_tile_x, player_tile_y); + + int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) + ? walkable_speed[on_walkable] + : 0; + // speed = SPEED; + /* if he's on a hard tile */ - if(!speed){ + if(!speed) { return true; /* He will collide with it. */ } - + player->speed = speed; - + return false; /* He won't collide with a hard tile. */ } void player_fix_position(Game *game, bool fix_x, bool fix_y) { Player *player = &game->player; - + /* I fix his poition on x or/and on y if y need to, so that he won't be over * the hard tile that he collided with. */ - if(fix_x) player->x = player->x/T_WIDTH*T_WIDTH+P_WIDTH/2; - - if(fix_y) player->y = player->y/T_HEIGHT*T_HEIGHT+P_HEIGHT/2; + if(fix_x) + player->x = player->x / T_WIDTH * T_WIDTH + P_WIDTH / 2; + + if(fix_y) + player->y = player->y / T_HEIGHT * T_HEIGHT + P_HEIGHT / 2; } void player_damage(Game *game, int amount) { Player *player = &game->player; - - player->life-=amount; + + player->life -= amount; /* TODO: Let the player dye if life < 1. */ }; - diff --git a/src/player.h b/src/player.h index 7b69716..a34bd75 100644 --- a/src/player.h +++ b/src/player.h @@ -1,52 +1,70 @@ #ifndef PLAYER_H #define PLAYER_H -/* The size of the player. */ -#ifdef FXCG50 - #define P_WIDTH 16 - #define P_HEIGHT 16 -#else - #define P_WIDTH 8 - #define P_HEIGHT 8 -#endif - -/* SPEED should NOT be 8 or bigger: it may cause bugs when handling - * collisions! */ -#define SPEED PXSIZE*2 - -#include - +#include "config.h" #include "game.h" #include "memory.h" +#include + +typedef struct { + const char *name; + bopti_image_t *face; +} Face; + +#define FACES 4 /* Structure 'Player' has been moved to game.h */ /* to avoid circular references between map.h, game.h and player.h */ /* only methods propotypes are now in dedicated header files */ - -/* Draws the player player. This function should be called after drawing the - * map! */ +/* player_draw() + * + * Draws the player. This function should be called after drawing the + * map! + * game: The game struct which contains the player struct used. + */ void player_draw(Game *game); -/* Move the player player in the direction direction. */ +/* player_move() + * + * Move the player in a direction. + * game: The game struct. + * direction: The direction to move the player in. + */ void player_move(Game *game, Direction direction); -/* (Mibi88) TODO: Describe this function please, I've no idea what she's for! */ +/*Tries to do an action based on previously set flags (called if the shift key + * is pressed)*/ void player_action(Game *game); -/* Check if the player is in collision with the map or a NPC. Checkpos is used - * to check the axis where the player is not moving. */ +/* player_collision() + * + * Check if the player is in collision with the map or a NPC. Checkpos is used + * to check the axis where the player is not moving. + * game: The game struct. + * direction: The direction the player is moving in. + * nomov_axis_check: The axis that isn't changed by this movement. + */ bool player_collision(Game *game, Direction direction, Checkpos nomov_axis_check); -/* Fix the position of the player so that he's not a bit inside of a hard block - * after a collision. */ +/* player_fix_position() + * + * Fix the position of the player so that he's not a bit inside of a hard block + * after a collision. + * game: The game struct. + * fix_x: If we should fix the position on the X axis. + * fix_y: If we should fix the position on the Y axis. + */ void player_fix_position(Game *game, bool fix_x, bool fix_y); - -/* Apply damage to player */ +/* player_damage() + * + * Apply damage to player + * game: The game struct. + * amount: The amount of damage to apply. + */ void player_damage(Game *game, int amount); #endif -