├── premake-mingw.bat ├── premake5 ├── premake5.exe ├── premake5.osx ├── _resources ├── sounds │ ├── chop.ogg │ ├── click3.ogg │ ├── woosh4.ogg │ ├── creature1.ogg │ ├── creature5.ogg │ ├── metalPot1.ogg │ ├── powerUp2.ogg │ ├── doorOpen_1.ogg │ ├── handleCoins.ogg │ ├── knifeSlice2.ogg │ ├── Flowing Rocks.ogg │ ├── Mission Plausible.ogg │ └── handleSmallLeather.ogg ├── colored_tilemap.png ├── icons │ ├── Icon.5_46.png │ └── Icon.6_98.png └── maps │ ├── menu_map.tmx │ ├── level1.tmx │ ├── level0.tmx │ ├── level4.tmx │ ├── level2.tmx │ └── level3.tmx ├── RPG ├── include │ ├── sprites.h │ ├── pause.h │ ├── loading.h │ ├── audio.h │ ├── treasure.h │ ├── combat.h │ ├── main.h │ ├── screens.h │ ├── game_hud.h │ ├── monsters.h │ ├── game.h │ ├── items.h │ ├── map.h │ ├── resource_ids.h │ └── tile_map.h ├── premake5.lua ├── combat.cpp ├── treasure.cpp ├── PUGIXML │ ├── readme.txt │ └── pugiconfig.hpp ├── pause.cpp ├── audio.cpp ├── screens.cpp ├── tile_map_drawing.cpp ├── monsters.cpp ├── items.cpp ├── loading.cpp ├── sprites.cpp ├── Makefile ├── main.cpp ├── map.cpp ├── game_hud.cpp ├── tile_map_io.cpp └── game.cpp ├── LICENSE ├── README.md ├── premake5.lua ├── .gitignore └── raylib_premake5.lua /premake-mingw.bat: -------------------------------------------------------------------------------- 1 | premake5.exe gmake2 || pause 2 | -------------------------------------------------------------------------------- /premake5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/premake5 -------------------------------------------------------------------------------- /premake5.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/premake5.exe -------------------------------------------------------------------------------- /premake5.osx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/premake5.osx -------------------------------------------------------------------------------- /_resources/sounds/chop.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/chop.ogg -------------------------------------------------------------------------------- /_resources/sounds/click3.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/click3.ogg -------------------------------------------------------------------------------- /_resources/sounds/woosh4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/woosh4.ogg -------------------------------------------------------------------------------- /_resources/colored_tilemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/colored_tilemap.png -------------------------------------------------------------------------------- /_resources/icons/Icon.5_46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/icons/Icon.5_46.png -------------------------------------------------------------------------------- /_resources/icons/Icon.6_98.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/icons/Icon.6_98.png -------------------------------------------------------------------------------- /_resources/sounds/creature1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/creature1.ogg -------------------------------------------------------------------------------- /_resources/sounds/creature5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/creature5.ogg -------------------------------------------------------------------------------- /_resources/sounds/metalPot1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/metalPot1.ogg -------------------------------------------------------------------------------- /_resources/sounds/powerUp2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/powerUp2.ogg -------------------------------------------------------------------------------- /_resources/sounds/doorOpen_1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/doorOpen_1.ogg -------------------------------------------------------------------------------- /_resources/sounds/handleCoins.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/handleCoins.ogg -------------------------------------------------------------------------------- /_resources/sounds/knifeSlice2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/knifeSlice2.ogg -------------------------------------------------------------------------------- /_resources/sounds/Flowing Rocks.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/Flowing Rocks.ogg -------------------------------------------------------------------------------- /_resources/sounds/Mission Plausible.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/Mission Plausible.ogg -------------------------------------------------------------------------------- /_resources/sounds/handleSmallLeather.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/RPGExample/HEAD/_resources/sounds/handleSmallLeather.ogg -------------------------------------------------------------------------------- /RPG/include/sprites.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raylib.h" 4 | 5 | #include 6 | 7 | #define SpriteFlipNone 0 8 | #define SpriteFlipX 0x02 9 | #define SpriteFlipY 0x04 10 | #define SpriteFlipDiagonal 0x08 11 | 12 | void LoadSpriteFrames(int textureId, int colums, int rows, int spacing); 13 | void SetSpriteOrigin(int spriteId, int x, int y); 14 | void SetSpriteBorders(int spriteId, int left, int top, int right, int bottom); 15 | void SetSpriteBorders(int spriteId, int inset); 16 | void CenterSprite(int spriteId); 17 | 18 | void DrawSprite(int spriteId, float x, float y, float rotation = 0, float scale = 1, Color tint = { 255, 255, 255, 255 }, uint8_t flip = SpriteFlipNone); 19 | void FillRectWithSprite(int spriteId, const Rectangle& rect, Color tint = { 255, 255, 255, 255 }, uint8_t flip = SpriteFlipNone); -------------------------------------------------------------------------------- /RPG/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()); 3 | 4 | project (workspaceName) 5 | kind "ConsoleApp" 6 | location "../_build" 7 | targetdir "../_bin/%{cfg.buildcfg}" 8 | 9 | filter "configurations:Release" 10 | kind "WindowedApp" 11 | entrypoint "mainCRTStartup" 12 | 13 | filter "action:vs*" 14 | debugdir "$(SolutionDir)" 15 | 16 | filter {"action:vs*", "configurations:Release"} 17 | kind "WindowedApp" 18 | entrypoint "mainCRTStartup" 19 | filter {} 20 | 21 | vpaths 22 | { 23 | ["Header Files/*"] = { "include/**.h", "include/**.hpp", "src/**.h", "src/**.hpp", "**.h", "**.hpp"}, 24 | ["Source Files/*"] = {"src/**.c", "src/**.cpp","**.c", "**.cpp"}, 25 | } 26 | files {"**.c", "**.cpp", "**.h", "**.hpp"} 27 | 28 | includedirs { "./", "src", "include"} 29 | link_raylib(); 30 | 31 | -- To link to a lib use link_to("LIB_FOLDER_NAME") -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ZLib/png License 2 | 3 | Copyright (c) 2021 Jeffery Myers 4 | 5 | This software is provided "as-is", without any express or implied warranty. In no event 6 | will the authors be held liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including commercial 9 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not claim that you 12 | wrote the original software. If you use this software in a product, an acknowledgment 13 | in the product documentation would be appreciated but is not required. 14 | 15 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 16 | as being the original software. 17 | 18 | 3. This notice may not be removed or altered from any source distribution. 19 | -------------------------------------------------------------------------------- /RPG/include/pause.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | void UpdatePaused(); -------------------------------------------------------------------------------- /RPG/include/loading.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | void InitResources(); 29 | void CleanupResources(); 30 | 31 | void UpdateLoad(); 32 | 33 | -------------------------------------------------------------------------------- /RPG/include/audio.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | void InitAudio(); 29 | void ShutdownAudio(); 30 | void UpdateAudio(); 31 | 32 | int LoadSoundFile(const char* soundFile); 33 | 34 | void StartBGM(const char* musicFile); 35 | void StopBGM(); 36 | 37 | void PlaySound(int sound); 38 | -------------------------------------------------------------------------------- /RPG/combat.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "combat.h" 27 | 28 | #include "raylib.h" 29 | 30 | int ResolveAttack(const AttackInfo& attack, int defense) 31 | { 32 | int damage = GetRandomValue(-3, 6) + GetRandomValue(attack.MinDamage, attack.MaxDamage); 33 | int total = damage - defense; 34 | 35 | if (total < 0) 36 | return 0; 37 | 38 | return total; 39 | } -------------------------------------------------------------------------------- /RPG/include/treasure.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "items.h" 29 | 30 | #include "raylib.h" 31 | 32 | #include 33 | #include 34 | 35 | struct TreasureInstance 36 | { 37 | int ItemId = -1; 38 | int Quantity = 1; 39 | 40 | Vector2 Position = { 0,0 }; 41 | int SpriteId; 42 | }; 43 | 44 | std::vector GetLoot(const std::string& loot_name); -------------------------------------------------------------------------------- /RPG/include/combat.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | struct DefenseInfo 31 | { 32 | int Defense = 0; 33 | }; 34 | 35 | struct AttackInfo 36 | { 37 | std::string Name; 38 | 39 | bool Melee = true; 40 | 41 | int MinDamage = 0; 42 | int MaxDamage = 0; 43 | 44 | float Cooldown = 1; 45 | 46 | float Range = 10; 47 | }; 48 | 49 | int ResolveAttack(const AttackInfo& attack, int defense); -------------------------------------------------------------------------------- /RPG/include/main.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | constexpr char VersionString[] = "v 0.5.28122021"; 29 | constexpr char CopyrightString[] = "Copyright 2021-22 Jeffery Myers"; 30 | 31 | // functions to change the game states 32 | 33 | void LoadComplete(); 34 | void GoToMainMenu(); 35 | void StartGame(); 36 | void PauseGame(); 37 | void ResumeGame(); 38 | void EndGame(bool win, int gold); 39 | void QuitApplication(); 40 | 41 | -------------------------------------------------------------------------------- /RPG/include/screens.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "raylib.h" 29 | 30 | class Screen 31 | { 32 | public: 33 | virtual void Draw() = 0; 34 | 35 | protected: 36 | bool RectIsHovered(Rectangle& rect); 37 | void DrawCenteredText(int y, const char* text, int fontSize, Color color); 38 | bool CenteredButton(int y, const char* text); 39 | 40 | void DimSceen(float alpha = 0.75f); 41 | 42 | protected: 43 | Color ButtonColor = WHITE; 44 | Color ButtonHighlight = SKYBLUE; 45 | Color ButtonPressColor = DARKBLUE; 46 | 47 | int ButtonFontSize = 60; 48 | int ButtonBorder = 10; 49 | }; 50 | 51 | void SetActiveScreen(Screen* screen); 52 | 53 | void DrawScreen(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raylib RPG Example 2 | 3 | An example RPG Game. 4 | 5 | Demo Gamplay 6 | https://youtu.be/9apXiHKIlsg 7 | 8 | ## Design Document 9 | https://docs.google.com/document/d/1lxpR6WbbjmCi9X_seGPYPYz7UhFcAKkX5Xl3pVfEwHs/edit?usp=sharing 10 | 11 | ## Video Overview 12 | https://youtu.be/krykjMt9ZKQ 13 | 14 | # Building 15 | The RPG Example uses premake just like all other items in raylib extras. A tutorial on how to build a raylib project with premake can be found here. https://github.com/raylib-extras/game-premake 16 | 17 | ### Windows MinGW 18 | Run the premake-mingw.bat and then run make in the folder 19 | 20 | ### Windows Visual Studio (not VSC) 21 | Run premake-VisualStudio.bat and then open the RPGExample.sln that is generated 22 | 23 | ### Linux 24 | CD into the directory, run ./premake5 gmake2 and then run make 25 | 26 | ### MacOS 27 | CD into the directory, run ./premake5.osx gmake2 and then run make 28 | 29 | 30 | # State 31 | The current example is feature complete and would be considered in 'beta' state. It has all the main features that are required by the game. 32 | 33 | # Features 34 | This sample has examples of how to do the following things in raylib 35 | 36 | - Game State 37 | - Menus 38 | - Quiting the game from menus 39 | - Pause/Resume Game 40 | - Tile Map with object layers 41 | - Click to Move 42 | - 2D Camera that keeps the player in view 43 | - Simple Effects 44 | - Basic AI 45 | - Background Music 46 | - Sound Effects 47 | - Resource Loading 48 | 49 | # C++ 50 | This example does use C++. The use of C++ has been keept at a resonable level. C++ is used for 51 | 52 | - Containers (vector, list, map, etc...) 53 | - Simple classes 54 | - Menu Screens 55 | 56 | Every use of C++ in this project can be replicated in C, or any other language. The main reason for using C++ was to not clutter up the project with implementations of common containers such as linked lists. 57 | Do not fear the C++. C++ is just another tool to use to solve problems. 58 | -------------------------------------------------------------------------------- /RPG/include/game_hud.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "screens.h" 29 | #include "game.h" 30 | #include "items.h" 31 | 32 | class GameHudScreen : public Screen 33 | { 34 | public: 35 | GameHudScreen(PlayerData& player); 36 | 37 | void Draw() override; 38 | 39 | PlayerData& Player; 40 | 41 | bool IsUiClick(const Vector2& pos); 42 | 43 | bool InventoryOpen = false; 44 | 45 | private: 46 | bool DrawButton(float x, float y, int itemId = -1, int quantity = 1, Color border = BROWN, Color center = BEIGE); 47 | void DrawInventory(); 48 | void ShowItemToolTip(const Item* item, const Rectangle& rect); 49 | 50 | private: 51 | float ButtonSize = 70; 52 | float ButtonInset = 6; 53 | 54 | const Item* HoveredItem = nullptr; 55 | }; 56 | -------------------------------------------------------------------------------- /RPG/include/monsters.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "sprites.h" 29 | #include "combat.h" 30 | 31 | #include "raylib.h" 32 | 33 | #include 34 | 35 | class MOB 36 | { 37 | public: 38 | int Id = -1; 39 | 40 | std::string Name; 41 | int Sprite = -1; 42 | 43 | int Health = 1; 44 | DefenseInfo Defense; 45 | AttackInfo Attack; 46 | 47 | float DetectionRadius = 200; 48 | float Speed = 50; 49 | 50 | std::string lootTable = "mob_loot"; 51 | }; 52 | 53 | // Mob Database 54 | MOB* AddMob(const char* name, int sprite, int health = 1); 55 | MOB* GetMob(int id); 56 | 57 | void SetupDefaultMobs(); 58 | 59 | // monster constants 60 | constexpr int RatMob = 0; 61 | constexpr int SnakeMob = 1; 62 | constexpr int GhostMob = 2; 63 | constexpr int TrollMob = 3; 64 | constexpr int TurtleMob = 4; 65 | constexpr int BlobMob = 5; 66 | constexpr int OgreMob = 6; 67 | constexpr int MonkMob = 7; 68 | constexpr int BeholderMob = 8; 69 | -------------------------------------------------------------------------------- /RPG/treasure.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "treasure.h" 27 | #include "items.h" 28 | 29 | std::vector GetLoot(const std::string& loot_name) 30 | { 31 | std::vector loot; 32 | 33 | if (loot_name == "tutorial_loot_0") 34 | { 35 | loot.emplace_back(TreasureInstance{ LeatherArmorItem }); 36 | loot.emplace_back(TreasureInstance{ FoodItem, GetRandomValue(2,5) }); 37 | } 38 | else if (loot_name == "tutorial_loot_1") 39 | { 40 | loot.emplace_back(TreasureInstance{ SwordItem }); 41 | } 42 | else if (loot_name == "random_loot") 43 | { 44 | int count = GetRandomValue(1, 3); 45 | for (int i = 0; i < count; i++) 46 | loot.emplace_back(TreasureInstance{ GetRandomItem(GoldBagItem) }); 47 | } 48 | else if (loot_name == "mob_loot") 49 | { 50 | loot.emplace_back(TreasureInstance{ GetRandomItem(GoldBagItem) }); 51 | } 52 | 53 | // random gold 54 | int value = GetRandomValue(1, 20); 55 | loot.emplace_back(TreasureInstance{ GoldBagItem, value }); 56 | 57 | return loot; 58 | } -------------------------------------------------------------------------------- /RPG/PUGIXML/readme.txt: -------------------------------------------------------------------------------- 1 | pugixml 1.11 - an XML processing library 2 | 3 | Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 4 | Report bugs and download new versions at https://pugixml.org/ 5 | 6 | This is the distribution of pugixml, which is a C++ XML processing library, 7 | which consists of a DOM-like interface with rich traversal/modification 8 | capabilities, an extremely fast XML parser which constructs the DOM tree from 9 | an XML file/buffer, and an XPath 1.0 implementation for complex data-driven 10 | tree queries. Full Unicode support is also available, with Unicode interface 11 | variants and conversions between different Unicode encodings (which happen 12 | automatically during parsing/saving). 13 | 14 | The distribution contains the following folders: 15 | 16 | docs/ - documentation 17 | docs/samples - pugixml usage examples 18 | docs/quickstart.html - quick start guide 19 | docs/manual.html - complete manual 20 | 21 | scripts/ - project files for IDE/build systems 22 | 23 | src/ - header and source files 24 | 25 | readme.txt - this file. 26 | 27 | This library is distributed under the MIT License: 28 | 29 | Copyright (c) 2006-2019 Arseny Kapoulkine 30 | 31 | Permission is hereby granted, free of charge, to any person 32 | obtaining a copy of this software and associated documentation 33 | files (the "Software"), to deal in the Software without 34 | restriction, including without limitation the rights to use, 35 | copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the 37 | Software is furnished to do so, subject to the following 38 | conditions: 39 | 40 | The above copyright notice and this permission notice shall be 41 | included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 44 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 45 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 46 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 47 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 48 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 49 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 50 | OTHER DEALINGS IN THE SOFTWARE. 51 | -------------------------------------------------------------------------------- /RPG/pause.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "pause.h" 27 | 28 | #include "screens.h" 29 | #include "main.h" 30 | 31 | class PauseMenuScreen : public Screen 32 | { 33 | public: 34 | void Draw() override 35 | { 36 | // dim the background 37 | DimSceen(); 38 | 39 | DrawCenteredText(40, "Raylib RPG Example", 40, BLUE); 40 | DrawCenteredText(105, "Paused", 60, RED); 41 | 42 | DrawText(VersionString, 2, GetScreenHeight() - 10, 10, GRAY); 43 | DrawText(CopyrightString, GetScreenWidth() - 2 - MeasureText(CopyrightString, 10), GetScreenHeight() - 10, 10, GRAY); 44 | 45 | if (CenteredButton(GetScreenHeight() / 4, "Resume")) 46 | ResumeGame(); 47 | 48 | if (CenteredButton(GetScreenHeight() / 2, "Quit to Menu")) 49 | GoToMainMenu(); 50 | 51 | if (CenteredButton(GetScreenHeight() - (GetScreenHeight() / 4), "Quit to Desktop")) 52 | QuitApplication(); 53 | } 54 | }; 55 | 56 | PauseMenuScreen PauseMenu; 57 | 58 | void UpdatePaused() 59 | { 60 | SetActiveScreen(&PauseMenu); 61 | 62 | if (IsKeyPressed(KEY_ESCAPE)) 63 | ResumeGame(); 64 | } -------------------------------------------------------------------------------- /RPG/audio.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "audio.h" 27 | 28 | #include "raylib.h" 29 | 30 | #include 31 | 32 | Music BGM = { 0 }; 33 | std::vector Sounds; 34 | 35 | void InitAudio() 36 | { 37 | InitAudioDevice(); 38 | SetMasterVolume(0.25f); 39 | StartBGM("sounds/Flowing Rocks.ogg"); 40 | } 41 | 42 | void ShutdownAudio() 43 | { 44 | CloseAudioDevice(); 45 | for (const auto& sound : Sounds) 46 | UnloadSound(sound); 47 | 48 | Sounds.clear(); 49 | StopBGM(); 50 | } 51 | 52 | void UpdateAudio() 53 | { 54 | if (BGM.frameCount > 0) 55 | UpdateMusicStream(BGM); 56 | } 57 | 58 | void StartBGM(const char* musicFIle) 59 | { 60 | StopBGM(); 61 | BGM = LoadMusicStream(musicFIle); 62 | BGM.looping = true; 63 | PlayMusicStream(BGM); 64 | } 65 | 66 | void StopBGM() 67 | { 68 | if (BGM.frameCount > 0) 69 | { 70 | StopMusicStream(BGM); 71 | UnloadMusicStream(BGM); 72 | BGM.frameCount = 0; 73 | } 74 | } 75 | 76 | int LoadSoundFile(const char* sound) 77 | { 78 | Sounds.push_back(LoadSound(sound)); 79 | return int(Sounds.size() - 1); 80 | } 81 | 82 | void PlaySound(int sound) 83 | { 84 | if (sound < 0 || sound > Sounds.size()) 85 | return; 86 | 87 | PlaySound(Sounds[sound]); 88 | } -------------------------------------------------------------------------------- /_resources/maps/menu_map.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1,2,60,2,2,60,2,59,2,60,2,60,2,2,2,2,60,2,2,60,2,59,2,4, 9 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 10 | 15,16,16,61,16,16,16,61,16,16,16,16,16,16,16,16,16,61,16,16,16,16,61,18, 11 | 15,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,16,16,16,16,18, 12 | 29,60,60,60,4,16,61,16,16,16,61,16,16,16,16,16,16,61,16,16,61,16,16,18, 13 | 62,16,16,62,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 14 | 16,16,16,62,18,61,16,61,16,16,16,61,61,16,61,16,61,16,16,16,16,16,16,18, 15 | 16,62,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 16 | 62,16,62,16,18,16,61,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,18, 17 | 1,2,2,2,32,16,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,18, 18 | 15,61,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,61,18, 19 | 15,16,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,61,16,16,18, 20 | 15,16,16,61,16,61,16,16,61,16,61,61,16,16,61,16,16,16,16,61,16,16,61,18, 21 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 22 | 29,59,59,60,2,59,2,59,2,59,2,60,59,2,2,2,2,2,59,59,2,59,59,32 23 | 24 | 25 | 26 | 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 28 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 29 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0, 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 32 | 0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 33 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,57,58,0, 34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,15,18,0, 35 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,32,0, 36 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 37 | 0,0,0,0,0,0,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 38 | 0,0,0,110,111,111,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 39 | 0,0,0,138,139,139,140,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0, 40 | 0,0,0,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /RPG/include/game.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "raylib.h" 29 | #include "sprites.h" 30 | #include "map.h" 31 | #include "combat.h" 32 | 33 | #include 34 | 35 | void InitGame(); 36 | void ActivateGame(); 37 | void QuitGame(); 38 | void UpdateGame(); 39 | 40 | // game state data 41 | struct InventoryContents 42 | { 43 | int ItemId; 44 | int Quantity; 45 | }; 46 | 47 | class PlayerData 48 | { 49 | public: 50 | Vector2 Position = { 0,0 }; 51 | SpriteInstance* Sprite = nullptr; 52 | 53 | bool TargetActive = false; 54 | Vector2 Target = { 0, 0 }; 55 | SpriteInstance* TargetSprite = nullptr; 56 | 57 | float Speed = 100; 58 | 59 | // player stats 60 | int Health = 100; 61 | int MaxHealth = 100; 62 | 63 | int Gold = 0; 64 | 65 | const AttackInfo& GetAttack() const; 66 | const int GetDefense() const; 67 | 68 | float LastAttack = 0; 69 | float LastConsumeable = 0; 70 | float AttackCooldown = 0; 71 | float ItemCooldown = 0; 72 | 73 | int BuffItem = -1; 74 | float BuffLifetimeLeft = 0; 75 | 76 | int BuffDefense = 0; 77 | 78 | // inventory 79 | int EquipedWeapon = -1; 80 | int EquipedArmor = -1; 81 | std::vector BackpackContents; 82 | 83 | float PickupDistance = 20; 84 | 85 | // event callbacks 86 | // a callback that takes an int 87 | typedef void(*ItemCallback)(int); 88 | 89 | // callbacks that the HUD can trigger on inventory 90 | ItemCallback ActivateItemCallback = nullptr; 91 | ItemCallback EquipArmorCallback = nullptr; 92 | ItemCallback EquipWeaponCallback = nullptr; 93 | ItemCallback DropItemCallback = nullptr; 94 | 95 | private: 96 | AttackInfo DefaultAttack = { "Slap", true, 1, 1, 1.0f, 10.0f }; 97 | DefenseInfo DefaultDefense = { 0 }; 98 | }; 99 | -------------------------------------------------------------------------------- /RPG/include/items.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "combat.h" 29 | #include 30 | 31 | enum class ItemTypes 32 | { 33 | None, 34 | Weapon, 35 | Armor, 36 | Activatable, 37 | }; 38 | 39 | enum class ActivatableEffects 40 | { 41 | None, 42 | Healing, 43 | Defense, 44 | Damage 45 | }; 46 | 47 | class Item 48 | { 49 | public: 50 | int Id = -1; 51 | std::string Name; 52 | int Sprite; 53 | 54 | ItemTypes ItemType = ItemTypes::None; 55 | int Value = 0; 56 | float Lifetime = 0; 57 | 58 | inline bool IsWeapon() const { return ItemType == ItemTypes::Weapon; } 59 | inline bool IsArmor() const { return ItemType == ItemTypes::Armor; } 60 | inline bool IsActivatable() const { return ItemType == ItemTypes::Activatable; } 61 | 62 | AttackInfo Attack; 63 | DefenseInfo Defense; 64 | 65 | ActivatableEffects Effect = ActivatableEffects::None; 66 | float Durration = 0; 67 | }; 68 | 69 | // ItemDatabase 70 | Item* AddItem(const char* name, int sprite, ItemTypes type); 71 | Item* GetItem(int id); 72 | 73 | int GetRandomItem(int except = -1); 74 | 75 | void SetupDefaultItems(); 76 | 77 | // Item constants 78 | constexpr int SwordItem = 0; 79 | constexpr int LeatherArmorItem = 1; 80 | constexpr int GoldBagItem = 2; 81 | constexpr int FoodItem = 3; 82 | constexpr int CoolSwordItem = 4; 83 | constexpr int AwesomeSwordItem = 5; 84 | constexpr int AxeItem = 6; 85 | constexpr int MightyAxeItem = 7; 86 | constexpr int ForkItem = 8; 87 | constexpr int BowItem = 9; 88 | constexpr int GoodBowItem = 10; 89 | constexpr int ClubItem = 11; 90 | constexpr int ChainArmorItem = 12; 91 | constexpr int PlateArmorItem = 13; 92 | constexpr int PotionItem = 14; 93 | constexpr int ShieldItem = 15; 94 | constexpr int FireballItem = 16; 95 | 96 | 97 | -------------------------------------------------------------------------------- /RPG/include/map.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "raylib.h" 29 | #include "tile_map.h" 30 | 31 | #include 32 | 33 | // map basics 34 | void LoadMap(const char* file); 35 | void ClearMap(); 36 | void DrawMap(); 37 | 38 | Camera2D& GetMapCamera(); 39 | 40 | void SetVisiblePoint(const Vector2& point); 41 | 42 | // tile map objects 43 | std::vector GetMapObjectsOfType(const char* objType, TileObject::SubTypes requiredType = TileObject::SubTypes::None); 44 | const TileObject* GetFirstMapObjectOfType(const char* objType, TileObject::SubTypes requiredType = TileObject::SubTypes::None); 45 | 46 | // map collisions 47 | bool PointInMap(const Vector2& point); 48 | bool Ray2DHitsMap(const Vector2& startPoint, const Vector2& endPoint); 49 | 50 | // map sprites 51 | struct SpriteInstance 52 | { 53 | int Id = -1; 54 | bool Active = true; 55 | int SpriteFrame = -1; 56 | Vector2 Position = { 0,0 }; 57 | Color Tint = WHITE; 58 | bool Bobble = false; 59 | bool Shadow = true; 60 | }; 61 | 62 | SpriteInstance* AddSprite(int frame, const Vector2& position); 63 | void UpdateSprite(int spriteId, const Vector2& position); 64 | void RemoveSprite(SpriteInstance* sprite); 65 | void RemoveSprite(int id); 66 | void ClearSprites(); 67 | 68 | // Effects 69 | enum class EffectType 70 | { 71 | Fade, 72 | RiseFade, 73 | RotateFade, 74 | ScaleFade, 75 | ToTarget, 76 | }; 77 | void AddEffect(const Vector2& position, EffectType effect, int spriteId, float lifetime = 1); 78 | void AddEffect(const Vector2& position, EffectType effect, int spriteId, const Vector2& target, float lifetime = 1); 79 | 80 | // common object types 81 | constexpr char PlayerSpawnType[] = "player_spawn"; 82 | constexpr char MobSpawnType[] = "mob_spawn"; 83 | constexpr char ChestType[] = "chest"; 84 | constexpr char ExitType[] = "exit"; -------------------------------------------------------------------------------- /RPG/screens.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "screens.h" 27 | #include "audio.h" 28 | #include "resource_ids.h" 29 | 30 | Screen* ActiveScreen = nullptr; 31 | 32 | void SetActiveScreen(Screen* screen) 33 | { 34 | ActiveScreen = screen; 35 | } 36 | 37 | void DrawScreen() 38 | { 39 | if (ActiveScreen != nullptr) 40 | ActiveScreen->Draw(); 41 | } 42 | 43 | bool Screen::RectIsHovered(Rectangle& rect) 44 | { 45 | return CheckCollisionPointRec(GetMousePosition(), rect); 46 | } 47 | 48 | void Screen::DrawCenteredText(int y, const char* text, int fontSize, Color color) 49 | { 50 | int textWidth = MeasureText(text, fontSize); 51 | DrawText(text, GetScreenWidth() / 2 - textWidth / 2, y - fontSize / 2, fontSize, color); 52 | } 53 | 54 | bool Screen::CenteredButton(int y, const char* text) 55 | { 56 | float rectHeight = ButtonFontSize + (ButtonBorder * 2.0f); 57 | float textWidth = float(MeasureText(text, ButtonFontSize)); 58 | 59 | float textXOrigin = GetScreenWidth() / 2.0f - textWidth / 2.0f; 60 | float textYOrigin = y - ButtonFontSize / 2.0f; 61 | 62 | Rectangle buttonRect = { textXOrigin - ButtonBorder, textYOrigin - ButtonBorder, textWidth + (ButtonBorder * 2.0f), ButtonFontSize + (ButtonBorder * 2.0f) }; 63 | 64 | bool hovered = RectIsHovered(buttonRect); 65 | bool down = hovered & IsMouseButtonDown(MOUSE_BUTTON_LEFT); 66 | 67 | Color color = hovered ? (down ? ButtonPressColor : ButtonHighlight) : (ButtonColor); 68 | 69 | DrawRectangleRec(buttonRect, ColorAlpha(color, 0.25f)); 70 | DrawText(text, int(textXOrigin), int(textYOrigin), ButtonFontSize, color); 71 | DrawRectangleLinesEx(buttonRect, 2, color); 72 | 73 | bool clicked = hovered && IsMouseButtonPressed(MOUSE_BUTTON_LEFT); 74 | 75 | if (clicked) 76 | PlaySound(ClickSoundId); 77 | 78 | return clicked; 79 | } 80 | 81 | void Screen::DimSceen(float alpha) 82 | { 83 | DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), ColorAlpha(BLACK, alpha)); 84 | } -------------------------------------------------------------------------------- /RPG/PUGIXML/pugiconfig.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * pugixml parser - version 1.11 3 | * -------------------------------------------------------- 4 | * Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 5 | * Report bugs and download new versions at https://pugixml.org/ 6 | * 7 | * This library is distributed under the MIT License. See notice at the end 8 | * of this file. 9 | * 10 | * This work is based on the pugxml parser, which is: 11 | * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) 12 | */ 13 | 14 | #ifndef HEADER_PUGICONFIG_HPP 15 | #define HEADER_PUGICONFIG_HPP 16 | 17 | // Uncomment this to enable wchar_t mode 18 | // #define PUGIXML_WCHAR_MODE 19 | 20 | // Uncomment this to enable compact mode 21 | // #define PUGIXML_COMPACT 22 | 23 | // Uncomment this to disable XPath 24 | // #define PUGIXML_NO_XPATH 25 | 26 | // Uncomment this to disable STL 27 | // #define PUGIXML_NO_STL 28 | 29 | // Uncomment this to disable exceptions 30 | // #define PUGIXML_NO_EXCEPTIONS 31 | 32 | // Set this to control attributes for public classes/functions, i.e.: 33 | // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL 34 | // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL 35 | // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall 36 | // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead 37 | 38 | // Tune these constants to adjust memory-related behavior 39 | // #define PUGIXML_MEMORY_PAGE_SIZE 32768 40 | // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 41 | // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 42 | 43 | // Tune this constant to adjust max nesting for XPath queries 44 | // #define PUGIXML_XPATH_DEPTH_LIMIT 1024 45 | 46 | // Uncomment this to switch to header-only version 47 | // #define PUGIXML_HEADER_ONLY 48 | 49 | // Uncomment this to enable long long support 50 | // #define PUGIXML_HAS_LONG_LONG 51 | 52 | #endif 53 | 54 | /** 55 | * Copyright (c) 2006-2020 Arseny Kapoulkine 56 | * 57 | * Permission is hereby granted, free of charge, to any person 58 | * obtaining a copy of this software and associated documentation 59 | * files (the "Software"), to deal in the Software without 60 | * restriction, including without limitation the rights to use, 61 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 62 | * copies of the Software, and to permit persons to whom the 63 | * Software is furnished to do so, subject to the following 64 | * conditions: 65 | * 66 | * The above copyright notice and this permission notice shall be 67 | * included in all copies or substantial portions of the Software. 68 | * 69 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 70 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 71 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 72 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 73 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 74 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 75 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 76 | * OTHER DEALINGS IN THE SOFTWARE. 77 | */ 78 | -------------------------------------------------------------------------------- /RPG/include/resource_ids.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "raylib.h" 29 | 30 | // texture IDs 31 | constexpr int TileSetTexture = 0; 32 | constexpr int LogoTexture = 1; 33 | 34 | // sprite IDs 35 | // UI sprites 36 | constexpr int BackgroundSprite = 60; 37 | constexpr int ClickTargetSprite = 140; 38 | constexpr int CoinSprite = 141; 39 | constexpr int InventoryBackgroundSprite = 147; 40 | constexpr int ItemBackgroundSprite = 148; 41 | constexpr int AwakeSprite = 149; 42 | constexpr int LootSprite = 150; 43 | constexpr int MobAttackSprite = 114; 44 | constexpr int DamageSprite = 151; 45 | constexpr int HealingSprite = 90; 46 | constexpr int ProjectileSprite = 158; 47 | 48 | // equipment sprites 49 | constexpr int BagSprite = 108; 50 | constexpr int SwordSprite = 62; 51 | constexpr int CoolSwordSprite = 154; 52 | constexpr int AwesomeSwordSprite = 155; 53 | constexpr int AxeSprite = 63; 54 | constexpr int MightyAxeSprite = 156; 55 | constexpr int ForkSprite = 66; 56 | constexpr int BowSprite = 64; 57 | constexpr int GoodBowSprite = 157; 58 | constexpr int ClubSprite = 52; 59 | constexpr int LeatherArmorSprite = 142; 60 | constexpr int ChainArmorSprite = 143; 61 | constexpr int PlateArmorSprite = 38; 62 | constexpr int FoodSprite = 122; 63 | constexpr int PotionSprite = 119; 64 | constexpr int ShieldSprite = 94; 65 | constexpr int FireballSprite = 120; 66 | 67 | // MOB sprites 68 | constexpr int PlayerSprite = 159; 69 | constexpr int PlayerLeatherSprite = 4; 70 | constexpr int PlayerChainSprite = 5; 71 | constexpr int PlayerPlateSprite = 6; 72 | constexpr int RatSprite = 20; 73 | constexpr int SnakeSprite = 18; 74 | constexpr int GhostSprite = 23; 75 | constexpr int TrollSprite = 11; 76 | constexpr int TurtleSprite = 24; 77 | constexpr int BlobSprite = 22; 78 | constexpr int OgreSprite = 8; 79 | constexpr int MonkSprite = 10; 80 | constexpr int BeholderSprite = 13; 81 | 82 | // sound IDs 83 | constexpr int ClickSoundId = 0; 84 | constexpr int CoinSoundId = 1; 85 | constexpr int ChestOpenSoundId = 2; 86 | constexpr int ItemPickupSoundId = 3; 87 | constexpr int AlertSoundId = 4; 88 | constexpr int MissSoundId = 5; 89 | constexpr int HitSoundId = 6; 90 | constexpr int PlayerDamageSoundId = 7; 91 | constexpr int CreatureDamageSoundId = 8; 92 | constexpr int PlayerHealSoundId = 9; 93 | 94 | const Texture& GetTexture(int id); -------------------------------------------------------------------------------- /RPG/tile_map_drawing.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "tile_map.h" 27 | #include "sprites.h" 28 | 29 | Rectangle CurrentViewRect = { 0 }; 30 | 31 | Rectangle GetTileDisplayRect(int x, int y, bool orthographic, const Vector2& tileSize) 32 | { 33 | if (orthographic) 34 | return Rectangle{ static_cast(x * tileSize.x), static_cast(y * tileSize.y), tileSize.x, tileSize.y }; 35 | 36 | // isometric 37 | float halfWidth = tileSize.x * 0.5f; 38 | float halfHeight = tileSize.y * 0.5f; 39 | float quarterHeight = tileSize.y * 0.25f; 40 | 41 | return Rectangle{ x * halfWidth - y * halfWidth - halfWidth, y * halfHeight + (x * halfHeight), tileSize.x, tileSize.y }; 42 | } 43 | 44 | const Tile* GetTile(int x, int y, const TileLayer& layer) 45 | { 46 | if (x < 0 || y < 0 || x >= layer.Size.x || y >= layer.Size.y) 47 | return nullptr; 48 | 49 | return &layer.Tiles[y * int(layer.Size.x) + x]; 50 | } 51 | 52 | bool RectInView(const Rectangle& rect) 53 | { 54 | if (rect.x + rect.width < CurrentViewRect.x) 55 | return false; 56 | 57 | if (rect.y + rect.height < CurrentViewRect.y) 58 | return false; 59 | 60 | if (rect.x > CurrentViewRect.x + CurrentViewRect.width) 61 | return false; 62 | 63 | if (rect.y > CurrentViewRect.y + CurrentViewRect.height) 64 | return false; 65 | 66 | return true; 67 | } 68 | 69 | void DrawTileMap(Camera2D& camera, const TileMap& map) 70 | { 71 | CurrentViewRect.x = camera.target.x - (camera.offset.x / camera.zoom); 72 | CurrentViewRect.y = camera.target.y - (camera.offset.y / camera.zoom); 73 | 74 | CurrentViewRect.width = GetScreenWidth() / camera.zoom; 75 | CurrentViewRect.height = GetScreenHeight() / camera.zoom; 76 | 77 | // iterate the layers, back to front 78 | for (const auto& layer : map.Layers) 79 | { 80 | if (layer.second->IsObject) 81 | { 82 | const ObjectLayer& objectLayer = *(static_cast(layer.second.get())); 83 | 84 | for (const auto& object : objectLayer.Objects) 85 | { 86 | if (object->SubType == TileObject::SubTypes::Text) 87 | { 88 | const TileTextObject* textObject = static_cast(object.get()); 89 | DrawText(textObject->Text.c_str(), int(textObject->Bounds.x), int(textObject->Bounds.y), textObject->FontSize, textObject->TextColor); 90 | } 91 | } 92 | } 93 | else 94 | { 95 | const TileLayer& tileLayer = *(static_cast(layer.second.get())); 96 | 97 | for (int y = 0; y < int(tileLayer.Size.y); ++y) 98 | { 99 | for (int x = 0; x < int(tileLayer.Size.x); ++x) 100 | { 101 | Rectangle destinationRect = GetTileDisplayRect(x, y, map.MapType == TileMapTypes::Orthographic, tileLayer.TileSize); 102 | if (!RectInView(destinationRect)) 103 | continue; 104 | 105 | const Tile* tile = GetTile(x, y, tileLayer); 106 | if (tile == nullptr) 107 | continue; 108 | DrawSprite(tile->Sprite, destinationRect.x, destinationRect.y, 0, 1, WHITE, tile->Flip); 109 | } 110 | } 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /_resources/maps/level1.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1,2,60,2,2,60,4,16,16,1,2,60,2,2,2,2,60,2,2,60,2,59,2,4, 9 | 15,61,16,16,16,16,18,16,16,15,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 10 | 15,16,16,61,16,16,18,16,16,15,16,16,16,16,16,16,16,61,16,16,16,16,61,18, 11 | 15,61,16,16,16,16,18,16,16,15,61,16,16,16,16,61,16,16,16,16,16,16,16,18, 12 | 15,16,16,16,16,16,18,16,16,15,61,16,16,16,16,16,16,61,16,16,61,16,16,18, 13 | 15,16,16,16,16,16,43,2,2,44,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 14 | 15,16,16,16,16,61,16,16,16,16,16,61,61,16,61,16,61,16,16,16,16,16,16,18, 15 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 16 | 15,16,16,16,16,16,61,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,18, 17 | 15,16,16,16,16,16,45,2,2,46,16,61,16,16,16,16,16,16,61,16,16,16,16,18, 18 | 15,61,16,16,16,16,18,16,16,15,16,16,16,16,61,16,16,16,16,16,16,16,61,18, 19 | 15,16,61,16,16,16,18,16,16,15,16,61,16,16,16,16,61,16,16,16,61,16,16,18, 20 | 15,16,16,61,16,61,18,16,16,15,61,61,16,16,61,16,16,16,16,61,16,16,61,18, 21 | 15,61,16,16,16,16,18,16,16,15,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 22 | 29,59,59,60,2,59,32,16,16,29,2,60,59,2,2,2,2,2,59,59,2,59,59,32 23 | 24 | 25 | 26 | 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 28 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 29 | 0,0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 33 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 35 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 36 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 38 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 39 | 0,2147483696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,0, 40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Loot Me 71 | 72 | 73 | 74 | 75 | 76 | Click To Attack 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /RPG/monsters.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "monsters.h" 27 | #include "resource_ids.h" 28 | 29 | #include 30 | 31 | std::vector MobDB; 32 | 33 | MOB* AddMob(const char* name, int sprite, int health) 34 | { 35 | int id = int(MobDB.size()); 36 | 37 | CenterSprite(sprite); 38 | MobDB.emplace_back(MOB{ id, std::string(name), sprite, health }); 39 | return GetMob(id); 40 | } 41 | 42 | MOB* GetMob(int id) 43 | { 44 | if (id < 0 || id >= MobDB.size()) 45 | return nullptr; 46 | 47 | return &MobDB[id]; 48 | } 49 | 50 | void SetupDefaultMobs() 51 | { 52 | MOB* mob = nullptr; 53 | 54 | // rat 55 | mob = AddMob("Rat", RatSprite, 1); 56 | mob->Defense.Defense = 0; 57 | mob->Attack.Name = "Claw"; 58 | mob->Attack.MinDamage = mob->Attack.MaxDamage = 1; 59 | mob->Attack.Cooldown = 1; 60 | 61 | // Snake 62 | mob = AddMob("Snek", SnakeSprite, 10); 63 | mob->Defense.Defense = 4; 64 | mob->Attack.Name = "Bite"; 65 | mob->Attack.MinDamage = 1; 66 | mob->Attack.MaxDamage = 2; 67 | mob->Attack.Cooldown = 1; 68 | 69 | // Ghost 70 | mob = AddMob("Ghust", GhostSprite, 10); 71 | mob->Defense.Defense = 7; 72 | mob->Attack.Name = "Scare"; 73 | mob->Attack.Range = 50; 74 | mob->Attack.Melee = false; 75 | mob->Attack.MinDamage = 1; 76 | mob->Attack.MaxDamage = 10; 77 | mob->Attack.Cooldown = 5; 78 | 79 | // Troll 80 | mob = AddMob("Troll", TrollSprite, 100); 81 | mob->Defense.Defense = 5; 82 | mob->Attack.Name = "Punch"; 83 | mob->Attack.Range = 10; 84 | mob->Attack.Melee = true; 85 | mob->Attack.MinDamage = 5; 86 | mob->Attack.MaxDamage = 10; 87 | mob->Attack.Cooldown = 1; 88 | 89 | // Turtle 90 | mob = AddMob("Tortile", TurtleSprite, 15); 91 | mob->Defense.Defense = 7; 92 | mob->Attack.Name = "Headbut"; 93 | mob->Attack.Range = 10; 94 | mob->Attack.Melee = true; 95 | mob->Attack.MinDamage = 1; 96 | mob->Attack.MaxDamage = 1; 97 | mob->Attack.Cooldown = 15; 98 | 99 | // Blob 100 | mob = AddMob("Blorb", BlobSprite, 30); 101 | mob->Defense.Defense = 4; 102 | mob->Attack.Name = "Ewwww Gross"; 103 | mob->Attack.Range = 15; 104 | mob->Attack.Melee = true; 105 | mob->Attack.MinDamage = 8; 106 | mob->Attack.MaxDamage = 15; 107 | mob->Attack.Cooldown = 2; 108 | 109 | // Ogre 110 | mob = AddMob("DudeBro", OgreSprite, 45); 111 | mob->Defense.Defense = 4; 112 | mob->Attack.Name = "Talk about how rust is a better language"; 113 | mob->Attack.Range = 20; 114 | mob->Attack.Melee = true; 115 | mob->Attack.MinDamage = 15; 116 | mob->Attack.MaxDamage = 20; 117 | mob->Attack.Cooldown = 2; 118 | 119 | // Monk 120 | mob = AddMob("Munk", OgreSprite, 50); 121 | mob->Defense.Defense = 5; 122 | mob->Attack.Name = "GPL Virus Attack"; 123 | mob->Attack.Range = 100; 124 | mob->Attack.Melee = false; 125 | mob->Attack.MinDamage = 20; 126 | mob->Attack.MaxDamage = 25; 127 | mob->Attack.Cooldown = 5; 128 | 129 | // EyeballMonster 130 | mob = AddMob("Moderator", BeholderSprite, 100); 131 | mob->Defense.Defense = 4; 132 | mob->Attack.Name = "Cast Ray"; 133 | mob->Attack.Range = 100; 134 | mob->Attack.Melee = false; 135 | mob->Attack.MinDamage = 20; 136 | mob->Attack.MaxDamage = 25; 137 | mob->Attack.Cooldown = 3; 138 | } -------------------------------------------------------------------------------- /_resources/maps/level0.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1,2,60,2,2,60,2,59,2,60,2,60,2,2,2,2,60,2,2,60,2,59,2,4, 9 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 10 | 15,16,16,61,16,16,16,61,16,16,16,16,16,16,16,16,16,61,16,16,16,16,61,18, 11 | 15,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,16,16,16,16,18, 12 | 15,16,16,16,16,16,61,16,16,16,61,16,16,16,16,16,16,61,16,16,61,16,16,18, 13 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 14 | 15,16,16,16,16,61,16,61,16,16,16,61,61,16,61,16,61,16,16,16,16,16,16,18, 15 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 16 | 15,16,16,16,16,16,61,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,18, 17 | 15,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,18, 18 | 15,61,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,61,18, 19 | 15,16,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,61,16,16,18, 20 | 15,16,16,61,16,61,16,16,61,16,61,61,16,16,61,16,16,16,16,61,16,16,61,18, 21 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 22 | 29,59,59,60,2,59,2,59,2,59,2,60,59,2,2,2,2,2,59,59,2,59,59,32, 23 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 24 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 25 | 26 | 27 | 28 | 29 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 32 | 0,0,0,0,0,0,0,0,0,0,0,0,2684354648,0,0,0,0,0,0,0,0,0,0,0, 33 | 0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,0,0, 34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 35 | 0,0,0,0,0,0,0,0,0,0,0,0,1610612838,2684354659,0,0,0,0,0,0,0,0,0,0, 36 | 0,0,99,100,100,100,100,100,100,100,100,100,1073741925,3221225573,100,100,100,100,100,100,100,102,47,0, 37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 38 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 42 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 44 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 45 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Click to Move 70 | 71 | 72 | Click To Loot 73 | 74 | 75 | Next Level 76 | 77 | 78 | Click Bag To See Inventory 79 | 80 | 81 | Get to the end to win! 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /RPG/include/tile_map.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "sprites.h" 29 | 30 | #include "raylib.h" 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | enum class TileMapTypes 39 | { 40 | Orthographic, 41 | Isometric, 42 | }; 43 | 44 | struct Tile 45 | { 46 | int16_t Sprite = -1; 47 | uint8_t Flip = SpriteFlipNone; 48 | }; 49 | 50 | class Layer 51 | { 52 | public: 53 | int Id; 54 | std::string Name; 55 | Vector2 Size = { 0,0 }; 56 | 57 | bool IsObject = false; 58 | }; 59 | 60 | class TileLayer : public Layer 61 | { 62 | public: 63 | Vector2 TileSize = { 0,0 }; 64 | std::vector Tiles; 65 | }; 66 | 67 | class Property 68 | { 69 | public: 70 | std::string Name; 71 | std::string Type; 72 | std::string Value; 73 | 74 | inline int GetInt() const 75 | { 76 | if (Type != "int" || Value.empty()) 77 | return 0; 78 | 79 | return atoi(Value.c_str()); 80 | } 81 | 82 | inline float GetFloat() const 83 | { 84 | if (Type != "float" || Value.empty()) 85 | return 0; 86 | 87 | return float(atof(Value.c_str())); 88 | } 89 | 90 | inline const char* GetString() const 91 | { 92 | return Value.c_str(); 93 | } 94 | }; 95 | 96 | class TileObject 97 | { 98 | public: 99 | int ID = 0; 100 | std::string Name; 101 | Rectangle Bounds = { 0,0,0,0 }; 102 | 103 | bool Visible = true; 104 | std::string Type; 105 | 106 | float Rotation = 0; 107 | int GridTile = -1; 108 | 109 | std::string Template; 110 | 111 | enum class SubTypes 112 | { 113 | None, 114 | Ellipse, 115 | Point, 116 | Polygon, 117 | Polyline, 118 | Text, 119 | }; 120 | 121 | SubTypes SubType = SubTypes::None; 122 | 123 | std::vector Properties; 124 | 125 | inline const Property* GetProperty(const char* name) const 126 | { 127 | for (const auto& prop : Properties) 128 | { 129 | if (prop.Name == name) 130 | return ∝ 131 | } 132 | return nullptr; 133 | } 134 | }; 135 | 136 | class TilePolygonObject : public TileObject 137 | { 138 | public: 139 | std::vector Points; 140 | }; 141 | 142 | class TileTextObject : public TileObject 143 | { 144 | public: 145 | std::string Text; 146 | Color TextColor = WHITE; 147 | bool Wrap = false; 148 | 149 | int FontSize = 20; 150 | std::string FontFamily; 151 | bool Bold = false; 152 | bool Italic = false; 153 | bool Underline = false; 154 | bool Strikeout = false; 155 | bool Kerning = true; 156 | std::string HorizontalAlignment = "left"; 157 | std::string VerticalAlignment = "top"; 158 | }; 159 | 160 | class ObjectLayer : public Layer 161 | { 162 | public: 163 | ObjectLayer() { IsObject = true; } 164 | 165 | std::vector> Objects; 166 | }; 167 | 168 | class TileMap 169 | { 170 | public: 171 | TileMapTypes MapType = TileMapTypes::Orthographic; 172 | 173 | std::map> Layers; 174 | 175 | std::map TileLayers; 176 | std::map ObjectLayers; 177 | 178 | std::vector Properties; 179 | 180 | inline const Property* GetProperty(const char* name) const 181 | { 182 | for (const auto& prop : Properties) 183 | { 184 | if (prop.Name == name) 185 | return ∝ 186 | } 187 | return nullptr; 188 | } 189 | }; 190 | 191 | bool ReadTileMap(const char* filePath, TileMap& map); 192 | 193 | void DrawTileMap(Camera2D& camera, const TileMap& map); -------------------------------------------------------------------------------- /RPG/items.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "items.h" 27 | #include "sprites.h" 28 | #include "resource_ids.h" 29 | 30 | #include 31 | 32 | std::vector ItemDB; 33 | 34 | // ItemDatabase 35 | Item* AddItem(const char* name, int sprite, ItemTypes type) 36 | { 37 | int id = int(ItemDB.size()); 38 | 39 | CenterSprite(sprite); 40 | ItemDB.emplace_back(Item{ id, std::string(name), sprite, type }); 41 | return GetItem(id); 42 | } 43 | 44 | Item* GetItem(int id) 45 | { 46 | if (id < 0 || id >= ItemDB.size()) 47 | return nullptr; 48 | 49 | return &ItemDB[id]; 50 | } 51 | 52 | int GetRandomItem(int except) 53 | { 54 | int id = -1; 55 | while (id == -1) 56 | { 57 | int index = GetRandomValue(0, int(ItemDB.size()) - 1); 58 | id = ItemDB[index].Id; 59 | if (id == except) 60 | id = -1; 61 | } 62 | 63 | return id; 64 | } 65 | 66 | void SetupDefaultItems() 67 | { 68 | // basic items 69 | auto* item = AddItem("Sword", SwordSprite, ItemTypes::Weapon); 70 | item->Attack.MinDamage = 0; 71 | item->Attack.MaxDamage = 2; 72 | item->Attack.Cooldown = 1; 73 | 74 | item = AddItem("Pleather Armor", LeatherArmorSprite, ItemTypes::Armor); 75 | item->Defense.Defense = 2; 76 | 77 | item = AddItem("Bag-o-Gold", BagSprite, ItemTypes::None); 78 | 79 | item = AddItem("Fud", FoodSprite, ItemTypes::Activatable); 80 | item->Effect = ActivatableEffects::Healing; 81 | item->Value = 5; 82 | 83 | // extended weapons 84 | item = AddItem("Cool Sword", CoolSwordSprite, ItemTypes::Weapon); 85 | item->Attack.MinDamage = 2; 86 | item->Attack.MaxDamage = 6; 87 | item->Attack.Cooldown = 1; 88 | 89 | item = AddItem("Awesome Sword", AwesomeSwordSprite, ItemTypes::Weapon); 90 | item->Attack.MinDamage = 4; 91 | item->Attack.MaxDamage = 8; 92 | item->Attack.Cooldown = 0.75f; 93 | 94 | item = AddItem("Axe", AxeSprite, ItemTypes::Weapon); 95 | item->Attack.MinDamage = 1; 96 | item->Attack.MaxDamage = 4; 97 | item->Attack.Cooldown = 1.5f; 98 | 99 | item = AddItem("Mighty Axe", MightyAxeSprite, ItemTypes::Weapon); 100 | item->Attack.MinDamage = 2; 101 | item->Attack.MaxDamage = 7; 102 | item->Attack.Cooldown = 1.5f; 103 | 104 | item = AddItem("Battle Fork Axe", ForkSprite, ItemTypes::Weapon); 105 | item->Attack.MinDamage = 1; 106 | item->Attack.MaxDamage = 3; 107 | item->Attack.Range = 20; 108 | item->Attack.Cooldown = 0.5f; 109 | 110 | item = AddItem("Bow", BowSprite, ItemTypes::Weapon); 111 | item->Attack.MinDamage = 1; 112 | item->Attack.MaxDamage = 3; 113 | item->Attack.Melee = false; 114 | item->Attack.Range = 150.0f; 115 | item->Attack.Cooldown = 0.25f; 116 | 117 | item = AddItem("Sweet Bow", GoodBowSprite, ItemTypes::Weapon); 118 | item->Attack.MinDamage = 3; 119 | item->Attack.MaxDamage = 6; 120 | item->Attack.Melee = false; 121 | item->Attack.Range = 250.0f; 122 | item->Attack.Cooldown = 0.25f; 123 | 124 | item = AddItem("Bonkmaster 5000", ClubSprite, ItemTypes::Weapon); 125 | item->Attack.MinDamage = 6; 126 | item->Attack.MaxDamage = 10; 127 | item->Attack.Range = 15.0f; 128 | item->Attack.Cooldown = 3; 129 | 130 | // extended armor 131 | item = AddItem("Chain Shirt", ChainArmorSprite, ItemTypes::Armor); 132 | item->Defense.Defense = 4; 133 | 134 | item = AddItem("Full Plate", PlateArmorSprite, ItemTypes::Armor); 135 | item->Defense.Defense = 10; 136 | 137 | // extended activatables 138 | item = AddItem("Potion", PotionSprite, ItemTypes::Activatable); 139 | item->Effect = ActivatableEffects::Healing; 140 | item->Value = 20; 141 | 142 | item = AddItem("Shield", ShieldSprite, ItemTypes::Activatable); 143 | item->Effect = ActivatableEffects::Defense; 144 | item->Value = 10; 145 | item->Durration = 30; 146 | 147 | item = AddItem("Fireball Scroll", FireballSprite, ItemTypes::Activatable); 148 | item->Effect = ActivatableEffects::Damage; 149 | item->Value = 20; 150 | } -------------------------------------------------------------------------------- /_resources/maps/level4.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 1,2,60,2,2,60,2,59,2,60,2,60,2,2,2,2,60,2,2,60,2,59,2,4, 12 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 13 | 15,16,16,61,16,16,16,61,16,16,16,16,16,16,16,16,16,61,16,16,16,16,61,18, 14 | 15,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,16,16,16,16,18, 15 | 15,16,16,16,16,16,61,16,16,16,61,16,16,16,16,16,16,61,16,16,61,16,16,18, 16 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 17 | 15,16,16,16,16,61,16,61,16,16,16,61,61,16,61,16,61,16,16,16,16,16,16,18, 18 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 19 | 15,16,16,16,16,16,61,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,18, 20 | 15,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,18, 21 | 15,61,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,61,18, 22 | 15,16,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,61,16,16,18, 23 | 15,16,16,61,16,61,16,16,61,16,61,61,16,16,61,16,16,16,16,61,16,16,61,18, 24 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 25 | 29,59,59,60,2,59,2,59,2,59,2,60,59,2,2,2,2,2,59,59,2,59,59,32, 26 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 28 | 29 | 30 | 31 | 32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 33 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 34 | 0,2147483696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 35 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 36 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 38 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,52,0,52,0,0, 42 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0, 43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 44 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,48,0, 45 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 47 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 48 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2020-2024 Jeffery Myers 2 | -- 3 | --This software is provided "as-is", without any express or implied warranty. In no event 4 | --will the authors be held liable for any damages arising from the use of this software. 5 | 6 | --Permission is granted to anyone to use this software for any purpose, including commercial 7 | --applications, and to alter it and redistribute it freely, subject to the following restrictions: 8 | 9 | -- 1. The origin of this software must not be misrepresented; you must not claim that you 10 | -- wrote the original software. If you use this software in a product, an acknowledgment 11 | -- in the product documentation would be appreciated but is not required. 12 | -- 13 | -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented 14 | -- as being the original software. 15 | -- 16 | -- 3. This notice may not be removed or altered from any source distribution. 17 | 18 | newoption 19 | { 20 | trigger = "graphics", 21 | value = "OPENGL_VERSION", 22 | description = "version of OpenGL to build raylib against", 23 | allowed = { 24 | { "opengl11", "OpenGL 1.1"}, 25 | { "opengl21", "OpenGL 2.1"}, 26 | { "opengl33", "OpenGL 3.3"}, 27 | { "opengl43", "OpenGL 4.3"}, 28 | { "opengles2", "OpenGLES 2.0"}, 29 | { "opengles3", "OpenGLES 3.0"} 30 | }, 31 | default = "opengl33" 32 | } 33 | 34 | newoption 35 | { 36 | trigger = "backend", 37 | value = "BACKEND", 38 | description = "backend to use", 39 | allowed = { 40 | { "GLFW", "GLFW"}, 41 | { "SDL2", "SDL2"}, 42 | { "SDL3", "SDL3"}, 43 | { "RLFW", "RLFW"} 44 | }, 45 | default = "GLFW" 46 | } 47 | 48 | function string.starts(String,Start) 49 | return string.sub(String,1,string.len(Start))==Start 50 | end 51 | 52 | function link_to(lib) 53 | links (lib) 54 | includedirs ("../"..lib.."/include") 55 | includedirs ("../"..lib.."/" ) 56 | end 57 | 58 | function download_progress(total, current) 59 | local ratio = current / total; 60 | ratio = math.min(math.max(ratio, 0), 1); 61 | local percent = math.floor(ratio * 100); 62 | print("Download progress (" .. percent .. "%/100%)") 63 | end 64 | 65 | function check_raylib() 66 | if(os.isdir("raylib") == false and os.isdir("raylib-master") == false) then 67 | if(not os.isfile("raylib-master.zip")) then 68 | print("Raylib not found, downloading from github") 69 | local result_str, response_code = http.download("https://github.com/raysan5/raylib/archive/refs/heads/master.zip", "raylib-master.zip", { 70 | progress = download_progress, 71 | headers = { "From: Premake", "Referer: Premake" } 72 | }) 73 | end 74 | print("Unzipping to " .. os.getcwd()) 75 | zip.extract("raylib-master.zip", os.getcwd()) 76 | os.remove("raylib-master.zip") 77 | end 78 | end 79 | 80 | function use_library(libraryName, githubFolder, repoHead) 81 | libFolder = libraryName .. "-" .. repoHead 82 | zipFile = libFolder .. ".zip" 83 | 84 | baseName = path.getbasename(os.getcwd()); 85 | 86 | links(libraryName); 87 | includedirs {"../" .. libFolder .. "/" } 88 | includedirs {"../" .. libFolder .."/src/" } 89 | includedirs {"../" .. libFolder .."/include/" } 90 | 91 | 92 | os.chdir("..") 93 | 94 | if(os.isdir(libFolder) == false) then 95 | if(not os.isfile(zipFile)) then 96 | print(libraryName .. " not found, downloading from github") 97 | local result_str, response_code = http.download("https://github.com/" .. githubFolder .. "/archive/refs/heads/" .. repoHead ..".zip", zipFile, { 98 | progress = download_progress, 99 | headers = { "From: Premake", "Referer: Premake" } 100 | }) 101 | end 102 | print("Unzipping to " .. os.getcwd()) 103 | zip.extract(zipFile, os.getcwd()) 104 | os.remove(zipFile) 105 | end 106 | 107 | os.chdir(libFolder) 108 | 109 | project (libraryName) 110 | kind "StaticLib" 111 | location "./" 112 | targetdir "../bin/%{cfg.buildcfg}" 113 | 114 | filter "action:vs*" 115 | buildoptions { "/experimental:c11atomics" } 116 | 117 | vpaths 118 | { 119 | ["Header Files/*"] = { "include/**.h", "include/**.hpp", "**.h", "**.hpp"}, 120 | ["Source Files/*"] = { "src/**.cpp", "src/**.c", "**.cpp", "**.c"}, 121 | } 122 | files {"include/**.hpp", "include/**.h","src/**.hpp", "src/**.h", "src/**.cpp", "src/**.c"} 123 | 124 | includedirs { "./" } 125 | includedirs { "./src" } 126 | includedirs { "./include" } 127 | 128 | os.chdir(baseName) 129 | end 130 | 131 | function use_Box2dV3() 132 | use_library("box2d", "erincatto/box2d", "main") 133 | end 134 | 135 | workspaceName = path.getbasename(os.getcwd()) 136 | 137 | if (string.lower(workspaceName) == "raylib") then 138 | print("raylib is a reserved name. Name your project directory something else.") 139 | -- Project generation will succeed, but compilation will definitely fail, so just abort here. 140 | os.exit() 141 | end 142 | 143 | workspace (workspaceName) 144 | configurations { "Debug", "Release"} 145 | platforms { "x64", "x86", "ARM64"} 146 | 147 | defaultplatform ("x64") 148 | 149 | filter "configurations:Debug" 150 | defines { "DEBUG" } 151 | symbols "On" 152 | 153 | filter "configurations:Release" 154 | defines { "NDEBUG" } 155 | optimize "On" 156 | 157 | filter { "platforms:x64" } 158 | architecture "x86_64" 159 | 160 | filter { "platforms:Arm64" } 161 | architecture "ARM64" 162 | 163 | filter {} 164 | 165 | targetdir "bin/%{cfg.buildcfg}/" 166 | 167 | if(os.isdir("game")) then 168 | startproject(workspaceName) 169 | end 170 | 171 | cdialect "C17" 172 | cppdialect "C++17" 173 | check_raylib(); 174 | 175 | include ("raylib_premake5.lua") 176 | 177 | if(os.isdir("game")) then 178 | include ("game") 179 | end 180 | 181 | folders = os.matchdirs("*") 182 | for _, folderName in ipairs(folders) do 183 | if (string.starts(folderName, "raylib") == false and string.starts(folderName, ".") == false) then 184 | if (os.isfile(folderName .. "/premake5.lua")) then 185 | print(folderName) 186 | include (folderName) 187 | end 188 | end 189 | end 190 | -------------------------------------------------------------------------------- /RPG/loading.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "loading.h" 27 | #include "main.h" 28 | #include "resource_ids.h" 29 | #include "screens.h" 30 | #include "sprites.h" 31 | #include "items.h" 32 | #include "monsters.h" 33 | #include "audio.h" 34 | 35 | #include "raylib.h" 36 | #include "raymath.h" 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | class LoadingScreen : public Screen 43 | { 44 | public: 45 | std::string LoadingText = "Loading..."; 46 | 47 | LoadingScreen() 48 | { 49 | int size = MeasureText(LoadingText.c_str(), 20); 50 | Origin.x = GetScreenWidth() * 0.5f - size * 0.5f; 51 | Origin.y = GetScreenHeight() * 0.5f - 10; 52 | 53 | LeftSpinner.x = Origin.x - 25.0f; 54 | RightSpinner.x = Origin.x + size + 25.0f; 55 | LeftSpinner.y = RightSpinner.y = GetScreenHeight() * 0.5f; 56 | 57 | LeftSpinner.width = RightSpinner.width = 20; 58 | LeftSpinner.height = RightSpinner.height = 20; 59 | } 60 | 61 | void Draw() override 62 | { 63 | // tell them we are loading 64 | DrawText(LoadingText.c_str(), int(Origin.x), int(Origin.y), 20, WHITE); 65 | 66 | // some spinny things to know that the app hasn't locked up 67 | DrawRectanglePro(LeftSpinner, Vector2{ 10, 10 }, float(GetTime()) * 180.0f, BLUE); 68 | DrawRectanglePro(RightSpinner, Vector2{ 10, 10 }, float(GetTime()) * -180.0f, BLUE); 69 | 70 | // progress bar. 71 | float progressWidth = RightSpinner.x - LeftSpinner.x; 72 | DrawRectangle(int(LeftSpinner.x), int(LeftSpinner.y + 20), (int)(progressWidth * Progress), 5, RAYWHITE); 73 | } 74 | 75 | Vector2 Origin = { 0,0 }; 76 | 77 | Rectangle LeftSpinner = { 0,0 }; 78 | Rectangle RightSpinner = { 0,0 }; 79 | 80 | // Load progress 0 = 0% 1 = 100% 81 | float Progress = 0; 82 | }; 83 | 84 | LoadingScreen* LoadScreen = nullptr; 85 | 86 | std::deque TexturesToLoad; 87 | std::deque SoundsToLoad; 88 | 89 | std::vector LoadedTextures; 90 | 91 | Texture DefaultTexture = { 0 }; 92 | 93 | size_t LoadedItems = 0; 94 | size_t TotalToLoad = 0; 95 | 96 | void InitResources() 97 | { 98 | LoadScreen = new LoadingScreen(); 99 | SetActiveScreen(LoadScreen); 100 | 101 | // setup the assets to load 102 | TexturesToLoad.emplace_back("colored_tilemap.png"); //TileSetTexture 103 | TexturesToLoad.emplace_back("icons/Icon.5_46.png"); //LogoTexture 104 | 105 | // setup default texture 106 | Image checkered = GenImageChecked(32, 32, 8, 8, GRAY, RAYWHITE); 107 | DefaultTexture = LoadTextureFromImage(checkered); 108 | UnloadImage(checkered); 109 | 110 | SoundsToLoad.emplace_back("sounds/click3.ogg"); 111 | SoundsToLoad.emplace_back("sounds/handleCoins.ogg"); 112 | SoundsToLoad.emplace_back("sounds/doorOpen_1.ogg"); 113 | SoundsToLoad.emplace_back("sounds/metalPot1.ogg"); 114 | SoundsToLoad.emplace_back("sounds/creature1.ogg"); 115 | SoundsToLoad.emplace_back("sounds/woosh4.ogg"); 116 | SoundsToLoad.emplace_back("sounds/knifeSlice2.ogg"); 117 | SoundsToLoad.emplace_back("sounds/chop.ogg"); 118 | SoundsToLoad.emplace_back("sounds/creature5.ogg"); 119 | SoundsToLoad.emplace_back("sounds/powerUp2.ogg"); 120 | 121 | TotalToLoad = TexturesToLoad.size() + SoundsToLoad.size(); 122 | } 123 | 124 | void CleanupResources() 125 | { 126 | // destroy the loading screen 127 | if (LoadScreen != nullptr) 128 | delete(LoadScreen); 129 | 130 | // unload the textures 131 | UnloadTexture(DefaultTexture); 132 | for (const Texture& texture : LoadedTextures) 133 | UnloadTexture(texture); 134 | 135 | // clear any data we stored 136 | LoadedTextures.clear(); 137 | DefaultTexture.id = 0; 138 | LoadScreen = nullptr; 139 | } 140 | 141 | void FinalizeLoad() 142 | { 143 | LoadSpriteFrames(TileSetTexture, 14, 12, 4); 144 | 145 | for (int i = 4; i < 14; i++) 146 | { 147 | CenterSprite(i); 148 | CenterSprite(i + 14); 149 | } 150 | 151 | CenterSprite(PlayerSprite); 152 | CenterSprite(PlayerLeatherSprite); 153 | CenterSprite(PlayerChainSprite); 154 | CenterSprite(PlayerPlateSprite); 155 | 156 | CenterSprite(ClickTargetSprite); 157 | CenterSprite(CoinSprite); 158 | 159 | CenterSprite(AwakeSprite); 160 | CenterSprite(LootSprite); 161 | CenterSprite(MobAttackSprite); 162 | 163 | SetSpriteBorders(InventoryBackgroundSprite, 10); 164 | SetSpriteBorders(ItemBackgroundSprite, 10); 165 | 166 | SetupDefaultItems(); 167 | SetupDefaultMobs(); 168 | } 169 | 170 | void UpdateLoad() 171 | { 172 | if (TexturesToLoad.empty() && SoundsToLoad.empty()) 173 | { 174 | FinalizeLoad(); 175 | LoadComplete(); 176 | return; 177 | } 178 | 179 | // load some resources 180 | // we don't want to load them all in one shot, that may take some time, and the app will look like it is dead 181 | // so we only load a few per frame. 182 | const int maxToLoadPerFrame = 1; 183 | 184 | for (int i = 0; i < maxToLoadPerFrame; ++i) 185 | { 186 | if (!TexturesToLoad.empty()) 187 | { 188 | LoadedTextures.push_back(LoadTexture(TexturesToLoad.front().c_str())); 189 | TexturesToLoad.pop_front(); 190 | 191 | LoadedItems++; 192 | } 193 | else if (!SoundsToLoad.empty()) 194 | { 195 | LoadSoundFile(SoundsToLoad.front().c_str()); 196 | SoundsToLoad.pop_front(); 197 | LoadedItems++; 198 | } 199 | } 200 | 201 | // then get the inverse to get how much we have loaded 202 | LoadScreen->Progress = LoadedItems/float(TotalToLoad); 203 | } 204 | 205 | // gets a texture from an ID. The textures are loaded in ID order. 206 | const Texture& GetTexture(int id) 207 | { 208 | if (id < 0 || id >= int(LoadedTextures.size())) 209 | return DefaultTexture; 210 | 211 | return LoadedTextures[id]; 212 | } -------------------------------------------------------------------------------- /_resources/maps/level2.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1,2,60,2,2,60,2,2,60,2,2,60,2,2,2,2,60,2,2,60,2,59,2,60,60,59,2,60,60,4, 9 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 10 | 15,16,16,61,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,61,16,16,18, 11 | 15,61,16,16,16,16,16,61,16,16,61,16,16,16,16,61,16,16,16,16,16,16,16,16,16,16,16,61,16,18, 12 | 15,16,16,16,61,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,61,16,16,16,16,16,16,16,16,18, 13 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,18, 14 | 15,16,16,16,16,61,16,16,16,16,16,61,61,16,61,16,61,16,16,16,16,16,16,16,16,16,16,16,61,18, 15 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,61,16,16,16,16,18, 16 | 15,16,16,61,16,16,61,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 17 | 15,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,61,16,18, 18 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,61,16,16,16,16,16,1,32, 19 | 15,16,61,1,2,2,2,2,2,2,4,61,16,16,16,16,61,16,16,16,61,16,16,16,16,61,16,16,15,16, 20 | 15,16,16,15,16,61,16,16,16,16,18,16,16,16,61,16,16,16,16,61,16,16,61,16,16,16,16,16,29,4, 21 | 15,61,16,15,16,16,16,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 22 | 15,16,16,15,61,16,16,16,16,16,18,16,61,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,18, 23 | 15,16,16,29,2,2,4,16,61,16,18,16,16,16,16,16,16,16,61,16,16,16,16,61,16,61,16,16,16,18, 24 | 15,61,16,16,16,16,18,16,16,16,18,16,16,61,16,16,16,16,16,16,16,61,16,16,16,16,16,16,61,18, 25 | 15,16,16,16,61,16,18,16,16,16,18,16,16,16,16,16,61,16,16,16,16,16,16,16,16,16,16,16,16,18, 26 | 15,16,16,16,16,16,18,61,16,16,18,16,61,61,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,18, 27 | 15,61,61,16,16,16,18,16,16,16,18,16,16,16,16,16,16,16,16,61,16,16,61,16,16,61,16,16,16,18, 28 | 15,16,16,16,61,16,18,61,16,16,18,16,16,16,16,16,61,61,16,16,16,16,61,16,16,16,16,16,61,18, 29 | 15,16,61,16,16,16,18,16,16,16,18,16,16,16,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 30 | 29,60,2,2,59,60,32,16,16,16,43,2,59,2,60,2,59,2,2,59,59,60,60,60,59,2,60,60,2,32 31 | 32 | 33 | 34 | 35 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,16,16,16,16,16,1,0,0,0,0,0,0,0, 36 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,15,0,0,0,0,0,0,0, 37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,17,0,76,0,15,0,0,0,0,0,47,0, 38 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,76,0,15,0,0,0,0,0,0,0, 39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,76,0,0,0,15,0,0,0,0,0,0,0, 40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,15,0,0,0,0,0,0,0, 41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,76,0,17,0,15,0,0,0,0,0,0,0, 42 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,15,0,0,0,0,0,0,0, 43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,2,2,4,0,0,15,0,0,0,0,0,0,0, 44 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,15,0,0,0,0,0,0,0, 45 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,15,0,0,0,0,0,0,0, 46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,76,15,0,0,0,0,0,0,96, 47 | 0,0,0,0,110,111,111,111,111,112,0,0,0,0,0,0,0,0,0,18,0,0,15,0,0,0,0,0,0,0, 48 | 0,0,0,0,124,125,125,125,125,126,0,0,0,0,0,0,0,0,0,18,0,0,15,0,0,0,0,0,0,0, 49 | 0,0,0,0,138,139,139,139,125,126,0,0,0,0,0,0,0,0,0,18,0,0,15,0,0,0,0,0,0,0, 50 | 0,0,0,0,0,0,0,0,124,126,0,0,0,0,0,0,0,0,0,43,2,2,44,0,0,0,0,0,0,0, 51 | 0,0,0,0,0,0,0,0,124,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 52 | 0,0,0,0,0,52,0,0,124,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 53 | 0,0,0,0,0,0,0,0,124,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 54 | 0,0,0,0,0,0,0,0,124,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 55 | 0,2147483696,0,0,0,0,0,0,124,126,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0, 56 | 0,0,0,0,0,0,0,0,138,140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 57 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /RPG/sprites.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "sprites.h" 27 | #include "resource_ids.h" 28 | 29 | #include "raylib.h" 30 | #include "raymath.h" 31 | 32 | #include 33 | 34 | struct SpriteInfo 35 | { 36 | int TextureId = -1; 37 | Rectangle SourceRect = { 0,0,0,0 }; 38 | Vector2 Origin = { 0,0 }; 39 | 40 | Rectangle Borders = { 0,0,0,0 }; 41 | }; 42 | 43 | std::vector Sprites; 44 | 45 | void LoadSpriteFrames(int textureId, int columns, int rows, int spacing) 46 | { 47 | if (columns == 0 || rows == 0) 48 | return; 49 | 50 | const Texture2D& texture = GetTexture(textureId); 51 | 52 | int itemWidth = (texture.width + spacing) / columns; 53 | int itemHeight = (texture.height + spacing) / rows; 54 | 55 | SpriteInfo info; 56 | info.TextureId = textureId; 57 | info.SourceRect.width = float(itemWidth - spacing); 58 | info.SourceRect.height = float(itemHeight - spacing); 59 | 60 | for (int y = 0; y < rows; ++y) 61 | { 62 | info.SourceRect.x = 0; 63 | for (int x = 0; x < columns; ++x) 64 | { 65 | Sprites.push_back(info); 66 | 67 | info.SourceRect.x += itemWidth; 68 | } 69 | 70 | info.SourceRect.y += itemHeight; 71 | } 72 | } 73 | 74 | void SetSpriteOrigin(int spriteId, int x, int y) 75 | { 76 | if (spriteId < 0 || spriteId >= int(Sprites.size())) 77 | return; 78 | 79 | SpriteInfo& sprite = Sprites[spriteId]; 80 | sprite.Origin.x = float(x); 81 | sprite.Origin.y = float(y); 82 | } 83 | 84 | void SetSpriteBorders(int spriteId, int left, int top, int right, int bottom) 85 | { 86 | if (spriteId < 0 || spriteId >= int(Sprites.size())) 87 | return; 88 | 89 | SpriteInfo& sprite = Sprites[spriteId]; 90 | sprite.Borders.x = float(left); 91 | sprite.Borders.y = float(top); 92 | 93 | sprite.Borders.width = float(right); 94 | sprite.Borders.height = float(bottom); 95 | } 96 | 97 | void SetSpriteBorders(int spriteId, int inset) 98 | { 99 | if (spriteId < 0 || spriteId >= int(Sprites.size())) 100 | return; 101 | 102 | SpriteInfo& sprite = Sprites[spriteId]; 103 | sprite.Borders.x = float(inset); 104 | sprite.Borders.y = float(inset); 105 | 106 | sprite.Borders.width = float(sprite.SourceRect.width - inset); 107 | sprite.Borders.height = float(sprite.SourceRect.height - inset); 108 | } 109 | 110 | void CenterSprite(int spriteId) 111 | { 112 | if (spriteId < 0 || spriteId >= int(Sprites.size())) 113 | return; 114 | 115 | SpriteInfo& sprite = Sprites[spriteId]; 116 | sprite.Origin.x = sprite.SourceRect.width/2; 117 | sprite.Origin.y = sprite.SourceRect.height/2; 118 | } 119 | 120 | void DrawSprite(int spriteId, float x, float y, float rotation, float scale, Color tint, uint8_t flip) 121 | { 122 | if (spriteId < 0 || spriteId >= int(Sprites.size())) 123 | return; 124 | 125 | SpriteInfo& sprite = Sprites[spriteId]; 126 | 127 | Rectangle source = sprite.SourceRect; 128 | 129 | if (flip & SpriteFlipDiagonal) 130 | rotation -= 90; 131 | if (flip & SpriteFlipX) 132 | source.width *= -1; 133 | if (flip & SpriteFlipY) 134 | source.height *= -1; 135 | 136 | Rectangle destination = { x, y, sprite.SourceRect.width * scale,sprite.SourceRect.height * scale }; 137 | 138 | if (flip & SpriteFlipDiagonal) 139 | destination.y += destination.height; 140 | 141 | DrawTexturePro(GetTexture(sprite.TextureId), source, destination, Vector2Scale(sprite.Origin,scale), rotation, tint); 142 | } 143 | 144 | void FillRectWithSprite(int spriteId, const Rectangle& rect, Color tint, uint8_t flip) 145 | { 146 | if (spriteId < 0 || spriteId >= int(Sprites.size())) 147 | return; 148 | 149 | SpriteInfo& sprite = Sprites[spriteId]; 150 | 151 | Rectangle source = sprite.SourceRect; 152 | float rotation = 0; 153 | 154 | if (flip && SpriteFlipDiagonal == 0) 155 | rotation += 90; 156 | if (flip && SpriteFlipX == 0) 157 | source.width *= -1; 158 | if (flip && SpriteFlipY == 0) 159 | source.height *= -1; 160 | 161 | if (sprite.Borders.width != 0 || sprite.Borders.height != 0) 162 | { 163 | NPatchInfo info; 164 | info.source = source; 165 | info.left = int(sprite.Borders.x); 166 | info.right = int(sprite.Borders.width); 167 | info.top = int(sprite.Borders.y); 168 | info.bottom = int(sprite.Borders.height); 169 | info.layout = NPATCH_NINE_PATCH; 170 | 171 | DrawTextureNPatch(GetTexture(sprite.TextureId), info, rect, Vector2{ 0,0 }, rotation, tint); 172 | } 173 | else 174 | { 175 | Rectangle source = sprite.SourceRect; 176 | float rotation = 0; 177 | 178 | if (flip && SpriteFlipDiagonal == 0) 179 | rotation += 90; 180 | if (flip && SpriteFlipX == 0) 181 | source.width *= -1; 182 | if (flip && SpriteFlipY == 0) 183 | source.height *= -1; 184 | 185 | int yCount = int(floor(rect.height / sprite.SourceRect.height)); 186 | int xCount = int(floor(rect.width / sprite.SourceRect.width)); 187 | 188 | Rectangle destRect = { 0, 0, sprite.SourceRect.width, sprite.SourceRect.height }; 189 | 190 | for (int y = 0; y < yCount; y++) 191 | { 192 | // full rows 193 | for (int x = 0; x < xCount; x++) 194 | { 195 | destRect.x = rect.x + (x * destRect.width); 196 | destRect.y = rect.y + (y * destRect.height); 197 | 198 | DrawTexturePro(GetTexture(sprite.TextureId), source, destRect, Vector2Zero(), 0, tint); 199 | } 200 | 201 | // remainder column 202 | Rectangle remainderRect; 203 | remainderRect.x = rect.x + (xCount * destRect.width); 204 | remainderRect.y = rect.y + (y * destRect.height); 205 | 206 | remainderRect.width = (rect.x + rect.width) - remainderRect.x; 207 | remainderRect.height = destRect.height; 208 | if(remainderRect.width > 0) 209 | DrawTexturePro(GetTexture(sprite.TextureId), source, remainderRect, Vector2Zero(), 0, tint); 210 | } 211 | 212 | destRect = { 0, (yCount * destRect.height), sprite.SourceRect.width, (rect.y + rect.height) - (yCount * destRect.height) }; 213 | 214 | if (destRect.height > 0) 215 | { 216 | // remainder row 217 | for (int x = 0; x < xCount; x++) 218 | { 219 | destRect.x = rect.x + (x * destRect.width); 220 | DrawTexturePro(GetTexture(sprite.TextureId), source, destRect, Vector2Zero(), 0, tint); 221 | } 222 | 223 | // last item 224 | destRect.x = (xCount * destRect.width); 225 | destRect.width = (rect.x + rect.width) - destRect.x; 226 | 227 | if (destRect.x > 0) 228 | DrawTexturePro(GetTexture(sprite.TextureId), source, destRect, Vector2Zero(), 0, tint); 229 | } 230 | } 231 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | raylib-master 352 | Catalog 353 | -------------------------------------------------------------------------------- /raylib_premake5.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2020-2024 Jeffery Myers 2 | -- 3 | --This software is provided "as-is", without any express or implied warranty. In no event 4 | --will the authors be held liable for any damages arising from the use of this software. 5 | 6 | --Permission is granted to anyone to use this software for any purpose, including commercial 7 | --applications, and to alter it and redistribute it freely, subject to the following restrictions: 8 | 9 | -- 1. The origin of this software must not be misrepresented; you must not claim that you 10 | -- wrote the original software. If you use this software in a product, an acknowledgment 11 | -- in the product documentation would be appreciated but is not required. 12 | -- 13 | -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented 14 | -- as being the original software. 15 | -- 16 | -- 3. This notice may not be removed or altered from any source distribution. 17 | 18 | function platform_defines() 19 | filter {"options:backend=GLFW"} 20 | defines{"PLATFORM_DESKTOP"} 21 | 22 | filter {"options:backend=RLFW"} 23 | defines{"PLATFORM_DESKTOP_RGFW"} 24 | 25 | filter {"options:backend=SDL2"} 26 | defines{"PLATFORM_DESKTOP_SDL"} 27 | 28 | filter {"options:backend=SDL3"} 29 | defines{"PLATFORM_DESKTOP_SDL"} 30 | 31 | filter {"options:graphics=opengl43"} 32 | defines{"GRAPHICS_API_OPENGL_43"} 33 | 34 | filter {"options:graphics=opengl33"} 35 | defines{"GRAPHICS_API_OPENGL_33"} 36 | 37 | filter {"options:graphics=opengl21"} 38 | defines{"GRAPHICS_API_OPENGL_21"} 39 | 40 | filter {"options:graphics=opengl11"} 41 | defines{"GRAPHICS_API_OPENGL_11"} 42 | 43 | filter {"options:graphics=openges3"} 44 | defines{"GRAPHICS_API_OPENGL_ES3"} 45 | 46 | filter {"options:graphics=openges2"} 47 | defines{"GRAPHICS_API_OPENGL_ES2"} 48 | 49 | filter {"system:macosx"} 50 | disablewarnings {"deprecated-declarations"} 51 | 52 | filter {"system:linux"} 53 | defines {"_GLFW_X11"} 54 | defines {"_GNU_SOURCE"} 55 | -- This is necessary, otherwise compilation will fail since 56 | -- there is no CLOCK_MONOTOMIC. raylib claims to have a workaround 57 | -- to compile under c99 without -D_GNU_SOURCE, but it didn't seem 58 | -- to work. raylib's Makefile also adds this flag, probably why it went 59 | -- unnoticed for so long. 60 | -- It compiles under c11 without -D_GNU_SOURCE, because c11 requires 61 | -- to have CLOCK_MONOTOMIC 62 | -- See: https://github.com/raysan5/raylib/issues/2729 63 | 64 | filter{} 65 | end 66 | 67 | function get_raylib_dir() 68 | if (os.isdir("raylib-master")) then 69 | return "raylib-master" 70 | end 71 | if (os.isdir("../raylib-master")) then 72 | return "raylib-master" 73 | end 74 | return "raylib" 75 | end 76 | 77 | function link_raylib() 78 | links {"raylib"} 79 | 80 | raylib_dir = get_raylib_dir(); 81 | includedirs {"../" .. raylib_dir .. "/src" } 82 | includedirs {"../" .. raylib_dir .."/src/external" } 83 | includedirs {"../" .. raylib_dir .."/src/external/glfw/include" } 84 | platform_defines() 85 | 86 | filter "files:**.dll" 87 | buildaction "Copy" 88 | 89 | filter "action:vs*" 90 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS"} 91 | dependson {"raylib"} 92 | links {"raylib.lib"} 93 | characterset ("MBCS") 94 | buildoptions { "/Zc:__cplusplus" } 95 | 96 | filter "system:windows" 97 | defines{"_WIN32"} 98 | links {"winmm", "gdi32", "opengl32"} 99 | libdirs {"../bin/%{cfg.buildcfg}"} 100 | 101 | filter "system:linux" 102 | links {"pthread", "m", "dl", "rt", "X11"} 103 | 104 | filter "system:macosx" 105 | links {"OpenGL.framework", "Cocoa.framework", "IOKit.framework", "CoreFoundation.framework", "CoreAudio.framework", "CoreVideo.framework", "AudioToolbox.framework"} 106 | 107 | filter {"options:backend=SDL2"} 108 | includedirs {"../SDL2/include" } 109 | 110 | filter { "system:windows", "options:backend=SDL2", "platforms:x64"} 111 | libdirs {"../SDL2/lib/x64"} 112 | links {"SDL2"} 113 | files "../SDL2/lib/x64/SDL2.dll" 114 | 115 | filter { "system:windows", "options:backend=SDL2", "platforms:x32"} 116 | libdirs {"../SDL2/lib/x32"} 117 | links {"SDL2"} 118 | files "../SDL2/lib/x32/SDL2.dll" 119 | 120 | filter { "system:windows", "options:backend=SDL3", "platforms:x64", "action:vs*"} 121 | includedirs {"../SDL3/include/SDL3" } 122 | includedirs {"../SDL3/include" } 123 | libdirs {"../SDL3/lib/x64"} 124 | links {"SDL3"} 125 | files "../SDL3/lib/x64/SDL3.dll" 126 | 127 | filter { "system:windows", "options:backend=SDL3", "platforms:x32", "action:vs*"} 128 | includedirs {"../SDL3/include/SDL3" } 129 | includedirs {"../SDL3/include" } 130 | libdirs {"../SDL3/lib/x32"} 131 | links {"SDL3"} 132 | files "../SDL3/lib/x32/SDL3.dll" 133 | 134 | filter { "system:windows", "options:backend=SDL3", "platforms:x64", "action:gmake*"} 135 | includedirs {"../SDL3/x86_64-w64-mingw32/include/SDL3" } 136 | includedirs {"../SDL3/x86_64-w64-mingw32/include" } 137 | libdirs {"../SDL3/x86_64-w64-mingw32/lib/"} 138 | libdirs {"../SDL3/x86_64-w64-mingw32/bin/"} 139 | links {"SDL3"} 140 | files "../SDL3/x86_64-w64-mingw32/bin/SDL3.dll" 141 | 142 | filter { "system:*nix OR system:macosx", "options:backend=SDL2", "configurations:Debug OR configurations:Release"} 143 | links {"SDL2"} 144 | 145 | filter { "system:*nix OR system:macosx", "options:backend=SDL3", "configurations:Debug OR configurations:Release"} 146 | links {"SDL3"} 147 | 148 | filter{} 149 | end 150 | 151 | function include_raylib() 152 | raylib_dir = get_raylib_dir(); 153 | includedirs {"../" .. raylib_dir .."/src" } 154 | includedirs {"../" .. raylib_dir .."/src/external" } 155 | includedirs {"../" .. raylib_dir .."/src/external/glfw/include" } 156 | platform_defines() 157 | 158 | filter "action:vs*" 159 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS"} 160 | 161 | filter{} 162 | end 163 | 164 | project "raylib" 165 | kind "StaticLib" 166 | raylib_dir = get_raylib_dir(); 167 | 168 | platform_defines() 169 | 170 | location (raylib_dir) 171 | language "C" 172 | targetdir "bin/%{cfg.buildcfg}" 173 | 174 | filter {"options:backend=SDL2"} 175 | includedirs {"SDL2/include" } 176 | 177 | filter {"options:backend=SDL3", "action:vs*"} 178 | includedirs {"SDL3/include/SDL3" } 179 | includedirs {"SDL3/include" } 180 | 181 | filter { "system:windows", "options:backend=SDL3", "platforms:x64", "action:gmake*"} 182 | includedirs {"SDL3/x86_64-w64-mingw32/include/SDL3" } 183 | includedirs {"SDL3/x86_64-w64-mingw32/include" } 184 | 185 | filter "action:vs*" 186 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS"} 187 | characterset ("MBCS") 188 | buildoptions { "/Zc:__cplusplus" } 189 | filter{} 190 | 191 | print ("Using raylib dir " .. raylib_dir); 192 | includedirs {raylib_dir .. "/src", raylib_dir .. "/src/external/glfw/include" } 193 | vpaths 194 | { 195 | ["Header Files"] = { raylib_dir .. "/src/**.h"}, 196 | ["Source Files/*"] = { raylib_dir .. "/src/**.c"}, 197 | } 198 | files {raylib_dir .. "/src/*.h", raylib_dir .. "/src/*.c"} 199 | 200 | removefiles {raylib_dir .. "/src/rcore_*.c"} 201 | 202 | filter { "system:macosx", "files:" .. raylib_dir .. "/src/rglfw.c" } 203 | compileas "Objective-C" 204 | 205 | filter{} 206 | -------------------------------------------------------------------------------- /RPG/Makefile: -------------------------------------------------------------------------------- 1 | # Alternative GNU Make project makefile autogenerated by Premake 2 | 3 | ifndef config 4 | config=debug_x64 5 | endif 6 | 7 | ifndef verbose 8 | SILENT = @ 9 | endif 10 | 11 | .PHONY: clean prebuild 12 | 13 | SHELLTYPE := posix 14 | ifeq (.exe,$(findstring .exe,$(ComSpec))) 15 | SHELLTYPE := msdos 16 | endif 17 | 18 | # Configurations 19 | # ############################################# 20 | 21 | RESCOMP = windres 22 | INCLUDES += -I. -Iinclude -I../raylib/src 23 | FORCE_INCLUDE += 24 | ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) 25 | ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) 26 | LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) 27 | define PREBUILDCMDS 28 | endef 29 | define PRELINKCMDS 30 | endef 31 | define POSTBUILDCMDS 32 | endef 33 | 34 | ifeq ($(config),debug_x64) 35 | TARGETDIR = ../bin/Debug 36 | TARGET = $(TARGETDIR)/RPGExample.exe 37 | OBJDIR = obj/x64/Debug 38 | DEFINES += -DDEBUG -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33 -D_WIN32 39 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g 40 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++17 41 | LIBS += ../bin/Debug/raylib.lib -lwinmm -lopengl32 -lkernel32 -lgdi32 42 | LDDEPS += ../bin/Debug/raylib.lib 43 | ALL_LDFLAGS += $(LDFLAGS) -L../bin/Debug -L/usr/lib64 -m64 44 | 45 | else ifeq ($(config),debug.dll_x64) 46 | TARGETDIR = ../bin/Debug.DLL 47 | TARGET = $(TARGETDIR)/RPGExample.exe 48 | OBJDIR = obj/x64/Debug.DLL 49 | DEFINES += -DDEBUG -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33 -D_WIN32 50 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g 51 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++17 52 | LIBS += ../bin/Debug.DLL/raylib.lib -lwinmm -lopengl32 -lkernel32 -lgdi32 53 | LDDEPS += ../bin/Debug.DLL/raylib.lib 54 | ALL_LDFLAGS += $(LDFLAGS) -L../bin/Debug.DLL -L/usr/lib64 -m64 55 | 56 | else ifeq ($(config),release_x64) 57 | TARGETDIR = ../bin/Release 58 | TARGET = $(TARGETDIR)/RPGExample.exe 59 | OBJDIR = obj/x64/Release 60 | DEFINES += -DNDEBUG -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33 -D_WIN32 61 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 62 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -std=c++17 63 | LIBS += ../bin/Release/raylib.lib -lwinmm -lopengl32 -lkernel32 -lgdi32 64 | LDDEPS += ../bin/Release/raylib.lib 65 | ALL_LDFLAGS += $(LDFLAGS) -L../bin/Release -L/usr/lib64 -m64 -s 66 | 67 | else ifeq ($(config),release.dll_x64) 68 | TARGETDIR = ../bin/Release.DLL 69 | TARGET = $(TARGETDIR)/RPGExample.exe 70 | OBJDIR = obj/x64/Release.DLL 71 | DEFINES += -DNDEBUG -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33 -D_WIN32 72 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 73 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -std=c++17 74 | LIBS += ../bin/Release.DLL/raylib.lib -lwinmm -lopengl32 -lkernel32 -lgdi32 75 | LDDEPS += ../bin/Release.DLL/raylib.lib 76 | ALL_LDFLAGS += $(LDFLAGS) -L../bin/Release.DLL -L/usr/lib64 -m64 -s 77 | 78 | endif 79 | 80 | # Per File Configurations 81 | # ############################################# 82 | 83 | 84 | # File sets 85 | # ############################################# 86 | 87 | GENERATED := 88 | OBJECTS := 89 | 90 | GENERATED += $(OBJDIR)/audio.o 91 | GENERATED += $(OBJDIR)/combat.o 92 | GENERATED += $(OBJDIR)/game.o 93 | GENERATED += $(OBJDIR)/game_hud.o 94 | GENERATED += $(OBJDIR)/items.o 95 | GENERATED += $(OBJDIR)/loading.o 96 | GENERATED += $(OBJDIR)/main.o 97 | GENERATED += $(OBJDIR)/map.o 98 | GENERATED += $(OBJDIR)/monsters.o 99 | GENERATED += $(OBJDIR)/pause.o 100 | GENERATED += $(OBJDIR)/pugixml.o 101 | GENERATED += $(OBJDIR)/screens.o 102 | GENERATED += $(OBJDIR)/sprites.o 103 | GENERATED += $(OBJDIR)/tile_map_drawing.o 104 | GENERATED += $(OBJDIR)/tile_map_io.o 105 | GENERATED += $(OBJDIR)/treasure.o 106 | OBJECTS += $(OBJDIR)/audio.o 107 | OBJECTS += $(OBJDIR)/combat.o 108 | OBJECTS += $(OBJDIR)/game.o 109 | OBJECTS += $(OBJDIR)/game_hud.o 110 | OBJECTS += $(OBJDIR)/items.o 111 | OBJECTS += $(OBJDIR)/loading.o 112 | OBJECTS += $(OBJDIR)/main.o 113 | OBJECTS += $(OBJDIR)/map.o 114 | OBJECTS += $(OBJDIR)/monsters.o 115 | OBJECTS += $(OBJDIR)/pause.o 116 | OBJECTS += $(OBJDIR)/pugixml.o 117 | OBJECTS += $(OBJDIR)/screens.o 118 | OBJECTS += $(OBJDIR)/sprites.o 119 | OBJECTS += $(OBJDIR)/tile_map_drawing.o 120 | OBJECTS += $(OBJDIR)/tile_map_io.o 121 | OBJECTS += $(OBJDIR)/treasure.o 122 | 123 | # Rules 124 | # ############################################# 125 | 126 | all: $(TARGET) 127 | @: 128 | 129 | $(TARGET): $(GENERATED) $(OBJECTS) $(LDDEPS) | $(TARGETDIR) 130 | $(PRELINKCMDS) 131 | @echo Linking RPGExample 132 | $(SILENT) $(LINKCMD) 133 | $(POSTBUILDCMDS) 134 | 135 | $(TARGETDIR): 136 | @echo Creating $(TARGETDIR) 137 | ifeq (posix,$(SHELLTYPE)) 138 | $(SILENT) mkdir -p $(TARGETDIR) 139 | else 140 | $(SILENT) mkdir $(subst /,\\,$(TARGETDIR)) 141 | endif 142 | 143 | $(OBJDIR): 144 | @echo Creating $(OBJDIR) 145 | ifeq (posix,$(SHELLTYPE)) 146 | $(SILENT) mkdir -p $(OBJDIR) 147 | else 148 | $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) 149 | endif 150 | 151 | clean: 152 | @echo Cleaning RPGExample 153 | ifeq (posix,$(SHELLTYPE)) 154 | $(SILENT) rm -f $(TARGET) 155 | $(SILENT) rm -rf $(GENERATED) 156 | $(SILENT) rm -rf $(OBJDIR) 157 | else 158 | $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) 159 | $(SILENT) if exist $(subst /,\\,$(GENERATED)) rmdir /s /q $(subst /,\\,$(GENERATED)) 160 | $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) 161 | endif 162 | 163 | prebuild: | $(OBJDIR) 164 | $(PREBUILDCMDS) 165 | 166 | ifneq (,$(PCH)) 167 | $(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER) 168 | $(GCH): $(PCH) | prebuild 169 | @echo $(notdir $<) 170 | $(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<" 171 | $(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR) 172 | ifeq (posix,$(SHELLTYPE)) 173 | $(SILENT) touch "$@" 174 | else 175 | $(SILENT) echo $null >> "$@" 176 | endif 177 | else 178 | $(OBJECTS): | prebuild 179 | endif 180 | 181 | 182 | # File Rules 183 | # ############################################# 184 | 185 | $(OBJDIR)/audio.o: audio.cpp 186 | @echo $(notdir $<) 187 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 188 | $(OBJDIR)/combat.o: combat.cpp 189 | @echo $(notdir $<) 190 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 191 | $(OBJDIR)/game.o: game.cpp 192 | @echo $(notdir $<) 193 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 194 | $(OBJDIR)/game_hud.o: game_hud.cpp 195 | @echo $(notdir $<) 196 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 197 | $(OBJDIR)/items.o: items.cpp 198 | @echo $(notdir $<) 199 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 200 | $(OBJDIR)/loading.o: loading.cpp 201 | @echo $(notdir $<) 202 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 203 | $(OBJDIR)/main.o: main.cpp 204 | @echo $(notdir $<) 205 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 206 | $(OBJDIR)/map.o: map.cpp 207 | @echo $(notdir $<) 208 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 209 | $(OBJDIR)/monsters.o: monsters.cpp 210 | @echo $(notdir $<) 211 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 212 | $(OBJDIR)/pause.o: pause.cpp 213 | @echo $(notdir $<) 214 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 215 | $(OBJDIR)/pugixml.o: PUGIXML/pugixml.cpp 216 | @echo $(notdir $<) 217 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 218 | $(OBJDIR)/screens.o: screens.cpp 219 | @echo $(notdir $<) 220 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 221 | $(OBJDIR)/sprites.o: sprites.cpp 222 | @echo $(notdir $<) 223 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 224 | $(OBJDIR)/tile_map_drawing.o: tile_map_drawing.cpp 225 | @echo $(notdir $<) 226 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 227 | $(OBJDIR)/tile_map_io.o: tile_map_io.cpp 228 | @echo $(notdir $<) 229 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 230 | $(OBJDIR)/treasure.o: treasure.cpp 231 | @echo $(notdir $<) 232 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 233 | 234 | -include $(OBJECTS:%.o=%.d) 235 | ifneq (,$(PCH)) 236 | -include $(PCH_PLACEHOLDER).d 237 | endif -------------------------------------------------------------------------------- /RPG/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "game.h" 27 | #include "loading.h" 28 | #include "main.h" 29 | #include "map.h" 30 | #include "pause.h" 31 | #include "resource_ids.h" 32 | #include "screens.h" 33 | #include "audio.h" 34 | 35 | #include "raylib.h" 36 | 37 | // all the states the program can be in 38 | enum class ApplicationStates 39 | { 40 | Startup, 41 | Loading, 42 | Menu, 43 | Running, 44 | Paused, 45 | GameOver, 46 | Quitting 47 | }; 48 | ApplicationStates ApplicationState = ApplicationStates::Startup; 49 | 50 | // the main menu screen 51 | // based on the screen class 52 | class MainMenuScreen : public Screen 53 | { 54 | public: 55 | void Draw() override 56 | { 57 | // dim the background 58 | DimSceen(); 59 | 60 | // title 61 | DrawCenteredText(40, "Raylib RPG Example", 40, BLUE); 62 | 63 | // version and copyright 64 | DrawText(VersionString, 2, GetScreenHeight() - 10, 10, GRAY); 65 | DrawText(CopyrightString, GetScreenWidth() - 2 - MeasureText(CopyrightString, 10), GetScreenHeight() - 10, 10, GRAY); 66 | 67 | // play button 68 | if (CenteredButton(GetScreenHeight() / 4, "Play")) 69 | StartGame(); 70 | 71 | // options button 72 | CenteredButton(GetScreenHeight()/2, "Options"); 73 | 74 | // quit button 75 | if (CenteredButton(GetScreenHeight() - (GetScreenHeight() / 4), "Quit")) 76 | QuitApplication(); 77 | } 78 | }; 79 | MainMenuScreen MainMenu; 80 | 81 | // the game over screen 82 | // shows the win state and final score 83 | class GameOverScreen : public Screen 84 | { 85 | public: 86 | void Draw() override 87 | { 88 | // dim the background 89 | DimSceen(); 90 | 91 | // title 92 | DrawCenteredText(40, "Raylib RPG Example", 40, BLUE); 93 | 94 | 95 | // win state 96 | if (IsWin) 97 | DrawCenteredText(120, "Congratulations You WON!", 60, WHITE); 98 | else 99 | DrawCenteredText(120, "You died, better luck next time.", 60, RED); 100 | 101 | // score 102 | DrawCenteredText(200, TextFormat("Score = %d", Gold), 60, YELLOW); 103 | 104 | // version and copyright 105 | DrawText(VersionString, 2, GetScreenHeight() - 10, 10, GRAY); 106 | DrawText(CopyrightString, GetScreenWidth() - 2 - MeasureText(CopyrightString, 10), GetScreenHeight() - 10, 10, GRAY); 107 | 108 | // main menu button 109 | if (CenteredButton(GetScreenHeight() / 2, "Main Menu")) 110 | GoToMainMenu(); 111 | 112 | // quit button 113 | if (CenteredButton(GetScreenHeight() - (GetScreenHeight() / 4), "Quit")) 114 | QuitApplication(); 115 | } 116 | 117 | bool IsWin = false; 118 | int Gold = 0; 119 | }; 120 | GameOverScreen GameOver; 121 | 122 | // setup the window and icon 123 | void SetupWindow() 124 | { 125 | // Validate that the window is not taller than the monitor size, if so, set it to a smaller size 126 | int monitor = GetCurrentMonitor(); 127 | 128 | int maxHeight = GetMonitorHeight(monitor) - 40; 129 | if (GetScreenHeight() > maxHeight) 130 | SetWindowSize(GetScreenWidth(), maxHeight); 131 | 132 | SetExitKey(0); 133 | SetTargetFPS(144); 134 | 135 | // load an image for the window icon 136 | Image icon = LoadImage("icons/Icon.6_98.png"); 137 | 138 | // ensure that the picture is in the correct format 139 | ImageFormat(&icon, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); 140 | 141 | // replace the background and border colors with transparent 142 | ImageColorReplace(&icon, BLACK, BLANK); 143 | ImageColorReplace(&icon, Color{ 136,136,136,255 }, BLANK); 144 | 145 | // set the icon 146 | SetWindowIcon(icon); 147 | 148 | // free the image data 149 | UnloadImage(icon); 150 | } 151 | 152 | // called by the loading system when all assets are loaded 153 | void LoadComplete() 154 | { 155 | ApplicationState = ApplicationStates::Menu; 156 | SetActiveScreen(&MainMenu); 157 | 158 | // load background world so we have something to look at behind the menu 159 | LoadMap("maps/menu_map.tmx"); 160 | } 161 | 162 | // called when the game wants to go back to the main menu, from pause or game over screens 163 | void GoToMainMenu() 164 | { 165 | // quit our game, if our game was running 166 | if (ApplicationState == ApplicationStates::Running || ApplicationState == ApplicationStates::Paused) 167 | QuitGame(); 168 | 169 | // start our background music again 170 | StartBGM("sounds/Flowing Rocks.ogg"); 171 | 172 | // go back to the main menu like we did when we started up 173 | LoadComplete(); 174 | } 175 | 176 | // called by the main menu to check for exit 177 | void UpdateMainMenu() 178 | { 179 | if (IsKeyPressed(KEY_ESCAPE)) 180 | QuitApplication(); 181 | } 182 | 183 | // starts a new game 184 | void StartGame() 185 | { 186 | ApplicationState = ApplicationStates::Running; 187 | SetActiveScreen(nullptr); 188 | StopBGM(); 189 | InitGame(); 190 | } 191 | 192 | // called when the menu wants to pause the game 193 | void PauseGame() 194 | { 195 | ApplicationState = ApplicationStates::Paused; 196 | } 197 | 198 | // called when the menu wants to resume the game 199 | void ResumeGame() 200 | { 201 | ApplicationState = ApplicationStates::Running; 202 | SetActiveScreen(nullptr); 203 | ActivateGame(); 204 | } 205 | 206 | // called by the game when it is over, by win or loss 207 | void EndGame(bool win, int gold) 208 | { 209 | ApplicationState = ApplicationStates::GameOver; 210 | SetActiveScreen(&GameOver); 211 | GameOver.IsWin = win; 212 | GameOver.Gold = gold; 213 | } 214 | 215 | // quit the entire application 216 | void QuitApplication() 217 | { 218 | ApplicationState = ApplicationStates::Quitting; 219 | } 220 | 221 | bool SearchAndSetResourceDir(const char* folderName) 222 | { 223 | // check the working dir 224 | if (DirectoryExists(folderName)) 225 | { 226 | ChangeDirectory(TextFormat("%s/%s", GetWorkingDirectory(), folderName)); 227 | return true; 228 | } 229 | 230 | const char* appDir = GetApplicationDirectory(); 231 | 232 | // check the applicationDir 233 | const char* dir = TextFormat("%s%s", appDir, folderName); 234 | if (DirectoryExists(dir)) 235 | { 236 | ChangeDirectory(dir); 237 | return true; 238 | } 239 | 240 | // check one up from the app dir 241 | dir = TextFormat("%s../%s", appDir, folderName); 242 | if (DirectoryExists(dir)) 243 | { 244 | ChangeDirectory(dir); 245 | return true; 246 | } 247 | 248 | // check two up from the app dir 249 | dir = TextFormat("%s../../%s", appDir, folderName); 250 | if (DirectoryExists(dir)) 251 | { 252 | ChangeDirectory(dir); 253 | return true; 254 | } 255 | 256 | // check three up from the app dir 257 | dir = TextFormat("%s../../../%s", appDir, folderName); 258 | if (DirectoryExists(dir)) 259 | { 260 | ChangeDirectory(dir); 261 | return true; 262 | } 263 | 264 | return false; 265 | } 266 | 267 | // the main application loop 268 | int main() 269 | { 270 | // setup the window 271 | SetConfigFlags(FLAG_VSYNC_HINT); 272 | InitWindow(1280,700,"RPG Example"); 273 | SetupWindow(); 274 | 275 | SearchAndSetResourceDir("_resources"); 276 | InitAudio(); 277 | InitResources(); 278 | 279 | ApplicationState = ApplicationStates::Loading; 280 | 281 | // game loop 282 | while (!WindowShouldClose() && ApplicationState != ApplicationStates::Quitting) 283 | { 284 | // call the update that goes with our current game state 285 | switch (ApplicationState) 286 | { 287 | case ApplicationStates::Loading: 288 | UpdateLoad(); 289 | break; 290 | 291 | case ApplicationStates::Menu: 292 | UpdateMainMenu(); 293 | break; 294 | 295 | case ApplicationStates::Running: 296 | UpdateGame(); 297 | break; 298 | 299 | case ApplicationStates::Paused: 300 | UpdatePaused(); 301 | break; 302 | } 303 | 304 | // update the screen for this frame 305 | BeginDrawing(); 306 | ClearBackground(BLACK); 307 | 308 | // the map is always first because it is always under the menu 309 | DrawMap(); 310 | 311 | // draw whatever menu or hud screen we have 312 | DrawScreen(); 313 | 314 | UpdateAudio(); 315 | EndDrawing(); 316 | } 317 | 318 | ShutdownAudio(); 319 | CleanupResources(); 320 | CloseWindow(); 321 | 322 | return 0; 323 | } 324 | -------------------------------------------------------------------------------- /RPG/map.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "map.h" 27 | 28 | #include "resource_ids.h" 29 | #include "sprites.h" 30 | #include "tile_map.h" 31 | #include "audio.h" 32 | 33 | #include "raylib.h" 34 | #include "raymath.h" 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | struct EffectInstance 41 | { 42 | Vector2 Position = { 0,0 }; 43 | EffectType Effect = EffectType::Fade; 44 | int SpriteId = -1; 45 | float Lifetime = 1; 46 | float MaxLifetime = 1; 47 | Vector2 Target = { 0,0 }; 48 | }; 49 | 50 | std::list Effects; 51 | 52 | Rectangle VisibilityInset = { 200, 200, 200, 250 }; 53 | Camera2D MapCamera = { 0 }; 54 | TileMap CurrentMap; 55 | 56 | std::unordered_map SpriteInstances; 57 | int NextSpriteId = 0; 58 | 59 | Rectangle MapBounds = { 0,0,0,0 }; 60 | 61 | Camera2D& GetMapCamera() 62 | { 63 | return MapCamera; 64 | } 65 | 66 | void SetVisiblePoint(const Vector2& point) 67 | { 68 | Vector2 screenPoint = GetWorldToScreen2D(point, MapCamera); 69 | 70 | if (screenPoint.x < VisibilityInset.x) 71 | MapCamera.target.x -= VisibilityInset.x - screenPoint.x; 72 | 73 | if (screenPoint.x > GetScreenWidth() - VisibilityInset.width) 74 | MapCamera.target.x += screenPoint.x - (GetScreenWidth() - VisibilityInset.width); 75 | 76 | if (screenPoint.y < VisibilityInset.y) 77 | MapCamera.target.y -= VisibilityInset.y - screenPoint.y; 78 | 79 | if (screenPoint.y > GetScreenHeight() - VisibilityInset.height) 80 | MapCamera.target.y += screenPoint.y -(GetScreenHeight() - VisibilityInset.height); 81 | } 82 | 83 | bool PointInMap(const Vector2& point) 84 | { 85 | if (!CheckCollisionPointRec(point, MapBounds)) 86 | return false; 87 | 88 | for (const auto& layerInfo : CurrentMap.ObjectLayers) 89 | { 90 | for (const auto& object : layerInfo.second->Objects) 91 | { 92 | if (object->Type == "wall") 93 | { 94 | if (CheckCollisionPointRec(point, object->Bounds)) 95 | return false; 96 | } 97 | } 98 | } 99 | 100 | return true; 101 | } 102 | 103 | // check to see if a line collides with a rectangle 104 | bool CheckCollisionLineRec(const Vector2& startPoint, const Vector2& endPoint, const Rectangle& rectangle) 105 | { 106 | // ether point is in the rectangle 107 | if (CheckCollisionPointRec(startPoint, rectangle) || CheckCollisionPointRec(endPoint, rectangle)) 108 | return true; 109 | 110 | // top 111 | if (CheckCollisionLines(startPoint, endPoint, Vector2{ rectangle.x,rectangle.y }, Vector2{ rectangle.x + rectangle.width, rectangle.y }, nullptr)) 112 | return true; 113 | 114 | // right 115 | if (CheckCollisionLines(startPoint, endPoint, Vector2{ rectangle.x + rectangle.width,rectangle.y }, Vector2{ rectangle.x + rectangle.width, rectangle.y + rectangle.height }, nullptr)) 116 | return true; 117 | 118 | // bottom 119 | if (CheckCollisionLines(startPoint, endPoint, Vector2{ rectangle.x, rectangle.y + rectangle.height }, Vector2{ rectangle.x + rectangle.width, rectangle.y + rectangle.height }, nullptr)) 120 | return true; 121 | 122 | // left 123 | if (CheckCollisionLines(startPoint, endPoint, Vector2{ rectangle.x,rectangle.y }, Vector2{ rectangle.x, rectangle.y + rectangle.height }, nullptr)) 124 | return true; 125 | 126 | return false; 127 | } 128 | 129 | bool Ray2DHitsMap(const Vector2& startPoint, const Vector2& endPoint) 130 | { 131 | if (!PointInMap(startPoint) || !PointInMap(endPoint)) 132 | return true; 133 | 134 | for (const auto& layerInfo : CurrentMap.ObjectLayers) 135 | { 136 | for (const auto& object : layerInfo.second->Objects) 137 | { 138 | if (object->Type == "wall") 139 | { 140 | if (CheckCollisionLineRec(startPoint, endPoint, object->Bounds)) 141 | return true; 142 | } 143 | } 144 | } 145 | 146 | return false; 147 | } 148 | 149 | void LoadMap(const char* file) 150 | { 151 | ClearSprites(); 152 | ReadTileMap(file, CurrentMap); 153 | 154 | MapCamera.offset.x = GetScreenWidth() * 0.5f; 155 | MapCamera.offset.y = GetScreenHeight() * 0.5f; 156 | 157 | MapCamera.rotation = 0; 158 | MapCamera.zoom = 1; 159 | 160 | MapCamera.target.x = 0; 161 | MapCamera.target.y = 0; 162 | 163 | MapBounds = Rectangle{ 0,0,0,0 }; 164 | 165 | if (!CurrentMap.TileLayers.empty()) 166 | { 167 | int index = CurrentMap.TileLayers.rbegin()->first; 168 | 169 | MapBounds.width = (CurrentMap.TileLayers[index]->Size.x * CurrentMap.TileLayers[index]->TileSize.x); 170 | MapBounds.height = (CurrentMap.TileLayers[index]->Size.y * CurrentMap.TileLayers[index]->TileSize.y); 171 | 172 | MapCamera.target.x = MapBounds.width / 2; 173 | MapCamera.target.y = MapBounds.height / 2; 174 | } 175 | 176 | const auto* bgm = CurrentMap.GetProperty("bgm"); 177 | if (bgm) 178 | { 179 | StopBGM(); 180 | StartBGM(bgm->GetString()); 181 | } 182 | } 183 | 184 | void ClearMap() 185 | { 186 | CurrentMap.ObjectLayers.clear(); 187 | CurrentMap.TileLayers.clear(); 188 | ClearSprites(); 189 | Effects.clear(); 190 | } 191 | 192 | void DrawMap() 193 | { 194 | if (CurrentMap.TileLayers.empty()) 195 | return; 196 | 197 | BeginMode2D(GetMapCamera()); 198 | DrawTileMap(MapCamera, CurrentMap); 199 | 200 | for (const auto& entry : SpriteInstances) 201 | { 202 | const SpriteInstance& sprite = entry.second; 203 | if (sprite.Active) 204 | { 205 | float offset = 0; 206 | if (sprite.Bobble) 207 | offset = fabsf(sinf(float(GetTime() * 5)) * 3); 208 | 209 | if (sprite.Shadow) 210 | DrawSprite(sprite.SpriteFrame, sprite.Position.x+2, sprite.Position.y+2 + offset, 0.0f, 1.0f, ColorAlpha(BLACK,0.5f)); 211 | 212 | DrawSprite(sprite.SpriteFrame, sprite.Position.x, sprite.Position.y + offset, 0.0f, 1.0f, sprite.Tint); 213 | } 214 | } 215 | 216 | for (std::list::iterator effect = Effects.begin(); effect != Effects.end();) 217 | { 218 | effect->Lifetime -= GetFrameTime(); 219 | 220 | if (effect->Lifetime < 0) 221 | { 222 | effect = Effects.erase(effect); 223 | continue; 224 | } 225 | 226 | float param = effect->Lifetime / effect->MaxLifetime; 227 | float rotation = 0; 228 | float alpha = 1; 229 | float scale = 1; 230 | 231 | Vector2 pos = effect->Position; 232 | 233 | switch (effect->Effect) 234 | { 235 | case EffectType::Fade: 236 | alpha = param; 237 | break; 238 | 239 | case EffectType::RiseFade: 240 | alpha = param; 241 | pos.y -= (1.0f - param) * 30; 242 | break; 243 | 244 | case EffectType::RotateFade: 245 | rotation = (1.0f - param) * 360; 246 | alpha = param; 247 | break; 248 | 249 | case EffectType::ScaleFade: 250 | alpha = param; 251 | scale = 1 + (1.0f - param); 252 | break; 253 | 254 | case EffectType::ToTarget: 255 | { 256 | Vector2 vec = Vector2Subtract(effect->Target, effect->Position); 257 | float dist = Vector2Length(vec); 258 | vec = Vector2Normalize(vec); 259 | 260 | pos = Vector2Add(effect->Position, Vector2Scale(vec, dist * (1.0f - param))); 261 | break; 262 | } 263 | } 264 | 265 | DrawSprite(effect->SpriteId, pos.x, pos.y, rotation, scale, ColorAlpha(WHITE, alpha)); 266 | 267 | effect++; 268 | } 269 | 270 | EndMode2D(); 271 | } 272 | 273 | std::vector GetMapObjectsOfType(const char* objType, TileObject::SubTypes requiredType) 274 | { 275 | std::vector objects; 276 | if (CurrentMap.ObjectLayers.empty()) 277 | return objects; 278 | 279 | for (const auto& layerInfo : CurrentMap.ObjectLayers) 280 | { 281 | for (const auto& object : layerInfo.second->Objects) 282 | { 283 | if (object->Type == objType && (requiredType == TileObject::SubTypes::None || object->SubType == requiredType)) 284 | objects.push_back(object.get()); 285 | } 286 | } 287 | 288 | return objects; 289 | } 290 | 291 | const TileObject* GetFirstMapObjectOfType(const char* objType, TileObject::SubTypes requiredType) 292 | { 293 | std::vector objects; 294 | if (CurrentMap.ObjectLayers.empty()) 295 | return nullptr; 296 | 297 | for (const auto& layerInfo : CurrentMap.ObjectLayers) 298 | { 299 | for (const auto& object : layerInfo.second->Objects) 300 | { 301 | if (object->Type == objType && (requiredType == TileObject::SubTypes::None || object->SubType == requiredType)) 302 | return object.get(); 303 | } 304 | } 305 | 306 | return nullptr; 307 | } 308 | 309 | SpriteInstance* AddSprite(int frame, const Vector2& position) 310 | { 311 | NextSpriteId++; 312 | return &(SpriteInstances.insert_or_assign(NextSpriteId, SpriteInstance{ NextSpriteId, true, frame, position }).first->second); 313 | } 314 | 315 | void UpdateSprite(int spriteId, const Vector2& position) 316 | { 317 | auto itr = SpriteInstances.find(spriteId); 318 | if (itr == SpriteInstances.end()) 319 | return; 320 | 321 | itr->second.Position = position; 322 | } 323 | 324 | void RemoveSprite(SpriteInstance* sprite) 325 | { 326 | if (sprite != nullptr) 327 | RemoveSprite(sprite->Id); 328 | } 329 | 330 | void RemoveSprite(int spriteId) 331 | { 332 | auto itr = SpriteInstances.find(spriteId); 333 | if (itr != SpriteInstances.end()) 334 | SpriteInstances.erase(itr); 335 | } 336 | 337 | void ClearSprites() 338 | { 339 | SpriteInstances.clear(); 340 | NextSpriteId = 0; 341 | } 342 | 343 | void AddEffect(const Vector2& position, EffectType effect, int spriteId, float lifetime) 344 | { 345 | CenterSprite(spriteId); 346 | Effects.emplace_back(EffectInstance{ position,effect,spriteId,lifetime,lifetime }); 347 | } 348 | 349 | void AddEffect(const Vector2& position, EffectType effect, int spriteId, const Vector2& target, float lifetime) 350 | { 351 | CenterSprite(spriteId); 352 | Effects.emplace_back(EffectInstance{ position, effect, spriteId, lifetime, lifetime, target }); 353 | } -------------------------------------------------------------------------------- /RPG/game_hud.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "game_hud.h" 27 | #include "items.h" 28 | #include "resource_ids.h" 29 | 30 | #include "raylib.h" 31 | 32 | GameHudScreen::GameHudScreen(PlayerData& player) 33 | : Screen() 34 | , Player(player) 35 | { 36 | } 37 | 38 | void GameHudScreen::ShowItemToolTip(const Item* item, const Rectangle& rect) 39 | { 40 | if (item == nullptr || !CheckCollisionPointRec(GetMousePosition(), rect)) 41 | return; 42 | 43 | DrawRectangleRec(Rectangle{ rect.x,rect.y,100,100 }, ColorAlpha(BLACK, 0.75f)); 44 | DrawText(item->Name.c_str(), int(rect.x), int(rect.y), 10, WHITE); 45 | } 46 | 47 | void GameHudScreen::DrawInventory() 48 | { 49 | Rectangle inventoryWindowRect = { GetScreenWidth() - 475.0f ,GetScreenHeight() - 500.0f, 354, 400.0f }; 50 | Rectangle shadowRect = inventoryWindowRect; 51 | shadowRect.x += 10; 52 | shadowRect.y += 10; 53 | DrawRectangleRec(shadowRect, ColorAlpha(DARKBROWN, 0.5f)); 54 | FillRectWithSprite(InventoryBackgroundSprite, inventoryWindowRect); 55 | 56 | // equipment 57 | Item* weaponItem = GetItem(Player.EquipedWeapon); 58 | if (DrawButton(inventoryWindowRect.x + 20, inventoryWindowRect.y + 20, weaponItem != nullptr ? weaponItem->Sprite : -1, 0, DARKGRAY, GRAY)) 59 | { 60 | HoveredItem = weaponItem; 61 | } 62 | DrawText("Weapon", int(inventoryWindowRect.x + 20 + ButtonSize + 2), int(inventoryWindowRect.y + 20), 20, DARKBROWN); 63 | DrawText(TextFormat("%d - %d", Player.GetAttack().MinDamage, Player.GetAttack().MaxDamage), int(inventoryWindowRect.x + 20 + ButtonSize + 2), int(inventoryWindowRect.y + 40), 20, WHITE); 64 | 65 | Item* armorItem = GetItem(Player.EquipedArmor); 66 | if (DrawButton(inventoryWindowRect.x + inventoryWindowRect.width - (20 + ButtonSize), inventoryWindowRect.y + 20, armorItem != nullptr ? armorItem->Sprite : -1, 0, DARKBROWN, BROWN)) 67 | { 68 | HoveredItem = armorItem; 69 | } 70 | DrawText("Armor", int(inventoryWindowRect.x + inventoryWindowRect.width - (20 + ButtonSize + 62)), int(inventoryWindowRect.y + ButtonSize), 20, DARKBROWN); 71 | DrawText(TextFormat("%d", Player.GetDefense()), int(inventoryWindowRect.x + inventoryWindowRect.width - (20 + ButtonSize + 22)), int(inventoryWindowRect.y + ButtonSize - 20), 20, WHITE); 72 | 73 | // backpack contents 74 | constexpr int inventoryItemSize = 64; 75 | constexpr int inventoryItemPadding = 4; 76 | 77 | DrawText("Backpack (LMB)Use/Equip (RMB)Drop", int(inventoryWindowRect.x + 10), int(inventoryWindowRect.y + 100), 10, DARKBROWN); 78 | 79 | int itemIndex = 0; 80 | for (int y = 0; y < 4; y++) 81 | { 82 | for (int x = 0; x < 5; x++) 83 | { 84 | float itemY = inventoryWindowRect.y + (inventoryWindowRect.height - inventoryItemPadding) - ((inventoryItemPadding + inventoryItemSize) * (4 - y)); 85 | float itemX = inventoryWindowRect.x + (inventoryItemPadding * 2) + ((inventoryItemSize + inventoryItemPadding) * x); 86 | 87 | Rectangle itemRect = { itemX, itemY, inventoryItemSize, inventoryItemSize }; 88 | Rectangle shadowRect = itemRect; 89 | shadowRect.x += 2; 90 | shadowRect.y += 2; 91 | 92 | DrawRectangleRec(shadowRect, ColorAlpha(BLACK, 0.5f)); 93 | FillRectWithSprite(ItemBackgroundSprite, itemRect); 94 | 95 | if (itemIndex < Player.BackpackContents.size()) 96 | { 97 | Item* item = GetItem(Player.BackpackContents[itemIndex].ItemId); 98 | if (item != nullptr) 99 | { 100 | DrawSprite(item->Sprite, itemRect.x + itemRect.width / 2, itemRect.y + itemRect.height / 2); 101 | 102 | if (Player.BackpackContents[itemIndex].Quantity > 1) 103 | DrawText(TextFormat("%d", Player.BackpackContents[itemIndex].Quantity), int(itemRect.x) + 2, int(itemRect.y + itemRect.height - 10), 10, WHITE); 104 | 105 | bool hovered = CheckCollisionPointRec(GetMousePosition(), itemRect); 106 | 107 | if (hovered) 108 | { 109 | HoveredItem = item; 110 | if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) 111 | { 112 | if (item->IsActivatable() && Player.ActivateItemCallback != nullptr) 113 | Player.ActivateItemCallback(itemIndex); 114 | else if (item->IsWeapon() && Player.EquipWeaponCallback != nullptr) 115 | Player.EquipWeaponCallback(itemIndex); 116 | else if (item->IsArmor() && Player.EquipArmorCallback != nullptr) 117 | Player.EquipArmorCallback(itemIndex); 118 | } 119 | else if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON) && Player.DropItemCallback != nullptr) 120 | { 121 | Player.DropItemCallback(itemIndex); 122 | } 123 | } 124 | } 125 | } 126 | itemIndex++; 127 | } 128 | } 129 | } 130 | 131 | bool GameHudScreen::IsUiClick(const Vector2& pos) 132 | { 133 | if (pos.y > GetScreenHeight() - 80.0f) 134 | return true; 135 | 136 | Rectangle inventoryWindowRect = { GetScreenWidth() - 475.0f ,GetScreenHeight() - 500.0f, 354, 400.0f }; 137 | 138 | if (InventoryOpen && CheckCollisionPointRec(pos, inventoryWindowRect)) 139 | return true; 140 | 141 | return false; 142 | } 143 | 144 | void GameHudScreen::Draw() 145 | { 146 | float barHieght = GetScreenHeight() - 80.0f; 147 | // background 148 | DrawRectangleRec(Rectangle{ 0, barHieght, float(GetScreenWidth()), 80 }, ColorAlpha(DARKGRAY, 0.25f)); 149 | 150 | // score 151 | DrawSprite(CoinSprite, GetScreenWidth() - 200.0f, barHieght + 40.0f, 4); 152 | DrawText(TextFormat("x %03d", Player.Gold), GetScreenWidth() - 170, int(barHieght + 20), 40, WHITE); 153 | 154 | // health bar 155 | DrawText("Health", 20, int(barHieght + 5), 20, RED); 156 | 157 | float healthBarWidth = 300; 158 | DrawRectangleLinesEx(Rectangle{ 20, barHieght + 30, healthBarWidth, 32 }, 1, WHITE); 159 | 160 | float healthPram = Player.Health / float(Player.MaxHealth); 161 | DrawRectangleRec(Rectangle{ 22,barHieght + 32,healthBarWidth * healthPram - 4,28 }, RED); 162 | 163 | // clear the hover item from last frame 164 | HoveredItem = nullptr; 165 | 166 | // action buttons 167 | float buttonX = 20 + healthBarWidth + 10; 168 | float buttonY = barHieght + 4; 169 | 170 | Item* weapon = GetItem(Player.EquipedWeapon); 171 | // equipped weapon 172 | DrawButton(buttonX, buttonY, weapon != nullptr ? weapon->Sprite : -1, 0, DARKGRAY, GRAY); 173 | 174 | if (Player.AttackCooldown > 0) 175 | { 176 | float height = ButtonSize * Player.AttackCooldown; 177 | DrawRectangleRec(Rectangle{ buttonX,buttonY + (ButtonSize - height),ButtonSize,height }, ColorAlpha(RED, 0.5f)); 178 | } 179 | 180 | std::vector activatableItems; 181 | for (int i = 0; i < Player.BackpackContents.size(); i++) 182 | { 183 | Item* item = GetItem(Player.BackpackContents[i].ItemId); 184 | if (item != nullptr && item->IsActivatable()) 185 | activatableItems.push_back(i); 186 | } 187 | 188 | int activatedItem = -1; 189 | 190 | // activatable items 191 | int backpackSlot = 0; 192 | for (int i = 0; i < 7; i++) 193 | { 194 | buttonX += ButtonSize + 4; 195 | 196 | if (i < activatableItems.size()) 197 | { 198 | bool shortcutPressed = IsKeyPressed(KEY_ONE + i); 199 | 200 | Item* item = GetItem(Player.BackpackContents[activatableItems[i]].ItemId); 201 | if ((DrawButton(buttonX, buttonY, item->Sprite, Player.BackpackContents[activatableItems[i]].Quantity) || shortcutPressed) && item != nullptr) 202 | { 203 | if ((IsMouseButtonPressed(MOUSE_BUTTON_LEFT) || shortcutPressed) && Player.ItemCooldown == 0) 204 | { 205 | activatedItem = activatableItems[i]; 206 | } 207 | else 208 | { 209 | HoveredItem = item; 210 | } 211 | } 212 | 213 | DrawText(TextFormat("%d", i + 1), int(buttonX), int(buttonY), 20, WHITE); 214 | 215 | if (Player.ItemCooldown > 0) 216 | { 217 | float height = ButtonSize * Player.ItemCooldown; 218 | DrawRectangleRec(Rectangle{ buttonX,buttonY + (ButtonSize - height),ButtonSize,height }, ColorAlpha(BLACK, 0.5f)); 219 | } 220 | } 221 | } 222 | 223 | if (activatedItem != -1 && Player.ActivateItemCallback != nullptr) 224 | Player.ActivateItemCallback(activatedItem); 225 | 226 | // backpack buttons 227 | buttonX += ButtonSize + 4; 228 | if ((DrawButton(buttonX, buttonY, BagSprite, 0, GRAY, LIGHTGRAY) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) || IsKeyPressed(KEY_I)) 229 | { 230 | InventoryOpen = !InventoryOpen; 231 | } 232 | 233 | buttonX += ButtonSize + 4; 234 | 235 | // buff icon 236 | if (Player.BuffLifetimeLeft > 0) 237 | { 238 | DrawSprite(Player.BuffItem, buttonX + ButtonSize/2, buttonY + ButtonSize/2, 0, 2); 239 | DrawText(TextFormat("%0.0f", Player.BuffLifetimeLeft), int(buttonX), int(buttonY + ButtonSize-30), 30, RED); 240 | } 241 | 242 | if (InventoryOpen) 243 | DrawInventory(); 244 | 245 | if (HoveredItem != nullptr) 246 | { 247 | Vector2 size = MeasureTextEx(GetFontDefault(), HoveredItem->Name.c_str(), 20, 2); 248 | Rectangle toolTipRect = { GetMousePosition().x - (size.x/2 + 2), GetMousePosition().y - (size.y + 2), size.x + 4, size.y + 4 }; 249 | 250 | DrawRectangleRec(toolTipRect, ColorAlpha(BLACK, 0.5f)); 251 | DrawText(HoveredItem->Name.c_str(), int(toolTipRect.x) + 2, int(toolTipRect.y) + 2, 20, WHITE); 252 | } 253 | } 254 | 255 | bool GameHudScreen::DrawButton(float x, float y, int sprite, int quantity, Color border, Color center ) 256 | { 257 | Rectangle buttonRect = { x, y, ButtonSize, ButtonSize }; 258 | DrawRectangleRec(buttonRect, border); 259 | DrawRectangleRec(Rectangle{ x + ButtonInset, y + ButtonInset, ButtonSize - ButtonInset * 2, ButtonSize - ButtonInset * 2 }, center); 260 | 261 | if (sprite != -1) 262 | { 263 | Vector2 center = { x + ButtonSize / 2, y + ButtonSize / 2 }; 264 | DrawSprite(sprite, center.x+2, center.y+2, 0, 2, BLACK); 265 | DrawSprite(sprite, center.x, center.y, 0, 2); 266 | } 267 | 268 | if (quantity > 1) 269 | { 270 | DrawText(TextFormat("X%d", quantity), int(x + ButtonSize/2), int(y + ButtonSize - 22), 20, WHITE); 271 | } 272 | 273 | return CheckCollisionPointRec(GetMousePosition(), buttonRect); 274 | } 275 | -------------------------------------------------------------------------------- /RPG/tile_map_io.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * Raylib RPG Example * A simple RPG made using raylib 4 | * 5 | * LICENSE: zlib/libpng 6 | * 7 | * Copyright (c) 2020 Jeffery Myers 8 | * 9 | * This software is provided "as-is", without any express or implied warranty. In no event 10 | * will the authors be held liable for any damages arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, including commercial 13 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not claim that you 16 | * wrote the original software. If you use this software in a product, an acknowledgment 17 | * in the product documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 20 | * as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | * 24 | **********************************************************************************************/ 25 | 26 | #include "tile_map.h" 27 | #include "sprites.h" 28 | 29 | #include "PUGIXML/pugixml.hpp" 30 | 31 | const unsigned FLIPPED_HORIZONTALLY_FLAG = 0x80000000; 32 | const unsigned FLIPPED_VERTICALLY_FLAG = 0x40000000; 33 | const unsigned FLIPPED_DIAGONALLY_FLAG = 0x20000000; 34 | 35 | 36 | std::string GetRelativeResource(const std::string& rootFile, const std::string& relFile) 37 | { 38 | std::string fullPath = rootFile; 39 | auto term = fullPath.find_last_of('/'); 40 | if (term != std::string::npos) 41 | fullPath = fullPath.substr(0, term); 42 | 43 | return fullPath + "/" + relFile; 44 | } 45 | 46 | static bool ReadImageData(int& width, int& height, std::string& source, pugi::xml_node image) 47 | { 48 | if (image.root() == nullptr) 49 | return false; 50 | 51 | width = image.attribute("width").as_int(); 52 | height = image.attribute("height").as_int(); 53 | 54 | source = image.attribute("source").as_string(); 55 | 56 | if (source.size() > 0) 57 | { 58 | if (source[0] == '.') 59 | { 60 | size_t firstSlash = source.find_first_of('/'); 61 | if (firstSlash != std::string::npos) 62 | source = source.substr(firstSlash + 1); 63 | } 64 | } 65 | return true; 66 | } 67 | 68 | bool ReadTileSetNode(pugi::xml_node root, int idOffset, TileMap& map) 69 | { 70 | float tileWidth = root.attribute("tilewidth").as_float(); 71 | float tileHeight = root.attribute("tileheight").as_float(); 72 | 73 | int tileCount = root.attribute("tilecount").as_int(); 74 | 75 | int columCount = root.attribute("columns").as_int(); 76 | int spacing = root.attribute("spacing").as_int(); 77 | int margin = root.attribute("margin").as_int(); 78 | 79 | for (pugi::xml_node child : root.children()) 80 | { 81 | std::string n = child.name(); 82 | if (n == "tile") 83 | { 84 | int id = child.attribute("id").as_int(); 85 | 86 | int width, height; 87 | std::string source; 88 | if (!ReadImageData(width, height, source, child.child("image"))) 89 | continue; 90 | 91 | // this is where tilesheet data would go 92 | } 93 | else if (n == "image") 94 | { 95 | int width, height; 96 | std::string source; 97 | ReadImageData(width, height, source, child); 98 | 99 | // this is where tilesheet data would go 100 | } 101 | } 102 | 103 | return true; 104 | } 105 | 106 | bool ReadTileSetFile(const std::string& tilesetFileName, int idOffset, TileMap& map) 107 | { 108 | pugi::xml_document doc; 109 | pugi::xml_parse_result result = doc.load_file(tilesetFileName.c_str()); 110 | 111 | if (result.status != pugi::xml_parse_status::status_ok) 112 | return false; 113 | 114 | pugi::xml_node root = doc.child("tileset"); 115 | 116 | return ReadTileSetNode(root, idOffset, map); 117 | } 118 | 119 | std::vector split(const char* str, char c = ' ') 120 | { 121 | std::vector result; 122 | 123 | do 124 | { 125 | const char* begin = str; 126 | 127 | while (*str != c && *str) 128 | str++; 129 | 130 | result.push_back(std::string(begin, str)); 131 | } while (0 != *str++); 132 | 133 | return result; 134 | } 135 | 136 | bool ReadObjectsLayer(pugi::xml_node& root, TileMap& map) 137 | { 138 | std::shared_ptr layerPtr = std::make_shared(); 139 | 140 | ObjectLayer& layer = *layerPtr; 141 | int id = root.attribute("id").as_int(); 142 | 143 | layer.Id = id; 144 | layer.Name = root.attribute("name").as_string(); 145 | 146 | for (pugi::xml_node child : root.children()) 147 | { 148 | std::string n = child.name(); 149 | if (n == "object") 150 | { 151 | int id = child.attribute("id").as_int(); 152 | 153 | std::shared_ptr object = nullptr; 154 | 155 | if (!child.child("polygon").empty() || !child.child("polyline").empty()) 156 | { 157 | auto poly = std::make_shared(); 158 | 159 | auto points = split(child.child("polygon").attribute("points").as_string(), ' '); 160 | for (auto point : points) 161 | { 162 | auto coords = split(point.c_str(), ','); 163 | if (coords.size() == 2) 164 | { 165 | Vector2 p = { (float)atof(coords[0].c_str()), (float)atof(coords[1].c_str()) }; 166 | poly->Points.emplace_back(p); 167 | } 168 | } 169 | object = poly; 170 | 171 | } 172 | else if (!child.child("text").empty()) 173 | { 174 | auto text = std::make_shared(); 175 | auto textEntity = child.child("text"); 176 | 177 | text->Text = textEntity.child_value(); 178 | if (!textEntity.attribute("pixelsize").empty()) 179 | text->FontSize = textEntity.attribute("pixelsize").as_int(); 180 | 181 | // TODO, add the rest of the text attributes 182 | 183 | object = text; 184 | } 185 | else 186 | { 187 | object = std::make_shared(); 188 | } 189 | 190 | if (!child.child("polygon").empty()) 191 | object->SubType = TileObject::SubTypes::Polygon; 192 | else if (!child.child("polyline").empty()) 193 | object->SubType = TileObject::SubTypes::Polyline; 194 | else if (!child.child("ellipse").empty()) 195 | object->SubType = TileObject::SubTypes::Ellipse; 196 | else if (!child.child("text").empty()) 197 | object->SubType = TileObject::SubTypes::Text; 198 | else if (!child.child("point").empty()) 199 | object->SubType = TileObject::SubTypes::Point; 200 | else 201 | object->SubType = TileObject::SubTypes::None; 202 | 203 | object->Name = child.attribute("name").as_string(); 204 | object->Type = child.attribute("type").as_string(); 205 | object->Template = child.attribute("template").as_string(); 206 | 207 | object->Bounds.x = child.attribute("x").as_float(); 208 | object->Bounds.y = child.attribute("y").as_float(); 209 | object->Bounds.width = child.attribute("width").as_float(); 210 | object->Bounds.height = child.attribute("height").as_float(); 211 | object->Rotation = child.attribute("rotation").as_float(); 212 | object->Visible = child.attribute("visible").empty() || child.attribute("visible").as_int() != 0; 213 | 214 | object->GridTile = child.attribute("gid").as_int(); 215 | 216 | auto properties = child.child("properties"); 217 | if (!properties.empty()) 218 | { 219 | for (auto prop : properties.children()) 220 | { 221 | Property propertyRectord; 222 | propertyRectord.Name = prop.attribute("name").as_string(); 223 | propertyRectord.Type = prop.attribute("type").as_string(); 224 | propertyRectord.Value = prop.attribute("value").as_string(); 225 | 226 | object->Properties.emplace_back(std::move(propertyRectord)); 227 | } 228 | } 229 | 230 | layer.Objects.emplace_back(object); 231 | } 232 | } 233 | 234 | int index = int(map.Layers.size()); 235 | map.Layers[index] = layerPtr; 236 | map.ObjectLayers[index] = layerPtr.get(); 237 | return true; 238 | } 239 | 240 | bool ReadTiledXML(pugi::xml_document& doc, TileMap& map, const std::string& filePath = std::string()) 241 | { 242 | auto root = doc.child("map"); 243 | 244 | auto version = root.attribute("version"); 245 | auto tiledVersion = root.attribute("tiledversion"); 246 | 247 | std::string orient = root.attribute("orientation").as_string(); 248 | std::string renderorder = root.attribute("renderorder").as_string(); 249 | 250 | map.MapType = TileMapTypes::Isometric; 251 | if (orient == "orthogonal") 252 | map.MapType = TileMapTypes::Orthographic; 253 | 254 | int width = root.attribute("width").as_int(); 255 | int height = root.attribute("height").as_int(); 256 | 257 | int tilewidth = root.attribute("tilewidth").as_int(); 258 | int tileheight = root.attribute("tileheight").as_int(); 259 | 260 | for (auto child : root.children()) 261 | { 262 | std::string childName = child.name(); 263 | if (childName == "tileset") 264 | { 265 | int idOffset = 0; 266 | if (!child.attribute("firstgid").empty()) 267 | idOffset = child.attribute("firstgid").as_int(); 268 | 269 | std::string tilesetFile = child.attribute("source").as_string(); 270 | if (tilesetFile.size() == 0) 271 | { 272 | if (!ReadTileSetNode(child, idOffset, map)) 273 | return false; 274 | } 275 | else if (!ReadTileSetFile(GetRelativeResource(filePath, tilesetFile), idOffset, map)) 276 | return false; 277 | } 278 | else if (childName == "properties") 279 | { 280 | if (!child.empty()) 281 | { 282 | for (auto prop : child.children()) 283 | { 284 | Property propertyRectord; 285 | propertyRectord.Name = prop.attribute("name").as_string(); 286 | propertyRectord.Type = prop.attribute("type").as_string(); 287 | propertyRectord.Value = prop.attribute("value").as_string(); 288 | 289 | map.Properties.emplace_back(std::move(propertyRectord)); 290 | } 291 | } 292 | } 293 | else if (childName == "objectgroup") 294 | { 295 | ReadObjectsLayer(child, map); 296 | } 297 | else if (childName == "layer") 298 | { 299 | int index = int(map.Layers.size()); 300 | int layerID = child.attribute("id").as_int(); 301 | 302 | std::string name = child.attribute("name").as_string(); 303 | 304 | std::shared_ptr layerPtr = std::make_shared(); 305 | map.Layers[index] = layerPtr; 306 | map.TileLayers[index] = layerPtr.get(); 307 | 308 | TileLayer& layer = *layerPtr; 309 | layer.Name = name; 310 | layer.Id = layerID; 311 | layer.Size.x = float(width); 312 | layer.Size.y = float(height); 313 | layer.TileSize.x = float(tilewidth); 314 | layer.TileSize.y = float(tileheight); 315 | 316 | auto data = child.child("data"); 317 | std::string encoding = data.attribute("encoding").as_string(); 318 | if (encoding == "csv") 319 | { 320 | std::string contents = data.first_child().value(); 321 | 322 | std::vector> rawData; 323 | 324 | int posX = 0; 325 | int posY = 0; 326 | 327 | size_t linePos = 0; 328 | do 329 | { 330 | size_t nextLine = contents.find_first_of('\n', linePos); 331 | if (nextLine == std::string::npos) 332 | nextLine = contents.size(); 333 | 334 | std::string colText = contents.substr(linePos, nextLine - linePos); 335 | linePos = nextLine + 1; 336 | 337 | if (colText.size() == 0) 338 | continue; 339 | size_t charPos = 0; 340 | posX = 0; 341 | do 342 | { 343 | size_t nextDelim = colText.find_first_of(',', charPos); 344 | if (nextDelim == std::string::npos || nextDelim == colText.size() - 1) 345 | nextDelim = colText.size(); 346 | 347 | std::string valStr = colText.substr(charPos, nextDelim - charPos); 348 | uint32_t val = static_cast(std::atoll(valStr.c_str())); 349 | charPos = nextDelim + 1; 350 | 351 | Tile tile; 352 | if (val & FLIPPED_HORIZONTALLY_FLAG) 353 | tile.Flip |= SpriteFlipX; 354 | 355 | if (val & FLIPPED_VERTICALLY_FLAG) 356 | tile.Flip |= SpriteFlipY; 357 | 358 | if (val & FLIPPED_DIAGONALLY_FLAG) 359 | tile.Flip |= SpriteFlipDiagonal; 360 | 361 | val &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG); 362 | 363 | // subtract 1 from the index, since our sprites start at 0 not 1 364 | tile.Sprite = static_cast(val-1); 365 | 366 | layer.Tiles.emplace_back(std::move(tile)); 367 | posX++; 368 | 369 | } while (charPos <= colText.size()); 370 | posY++; 371 | } while (linePos < contents.size() && linePos != std::string::npos); 372 | } 373 | } 374 | } 375 | 376 | return true; 377 | } 378 | 379 | bool ReadTileMap(const char* filename, TileMap& map) 380 | { 381 | map.TileLayers.clear(); 382 | map.ObjectLayers.clear(); 383 | map.Layers.clear(); 384 | 385 | if (filename == nullptr) 386 | return false; 387 | 388 | pugi::xml_document doc; 389 | pugi::xml_parse_result result = doc.load_file(filename); 390 | return result.status == pugi::xml_parse_status::status_ok && ReadTiledXML(doc, map, filename); 391 | } 392 | -------------------------------------------------------------------------------- /_resources/maps/level3.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1,2,60,2,2,60,2,2,60,2,60,60,2,2,30,2,60,60,2,60,2,59,2,60,60,59,2,60,60,2,2,59,2,59,2,59,2,60,30,60,59,2,4, 9 | 15,61,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,18, 10 | 15,16,16,61,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,61,16,16,16,61,61,16,16,16,16,61,16,16,16,16,61,18, 11 | 15,61,16,16,16,16,16,61,16,16,61,16,16,16,16,61,16,1,60,2,2,2,60,2,2,4,16,61,16,16,16,61,61,61,16,16,16,16,16,16,16,16,18, 12 | 15,16,16,16,61,46,16,16,16,16,61,16,16,16,16,16,16,44,16,16,61,16,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 13 | 15,16,16,16,16,29,2,2,2,2,4,16,16,16,16,16,16,16,16,16,16,16,16,16,61,18,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,18, 14 | 15,16,16,16,16,61,16,16,16,16,18,61,61,16,61,16,61,16,16,16,16,16,16,16,16,18,16,16,61,16,16,16,16,16,16,16,16,16,16,16,16,16,18, 15 | 15,16,16,16,16,16,16,16,16,16,18,16,16,16,16,16,16,46,16,16,61,16,16,16,61,18,16,16,16,16,16,16,16,16,61,61,61,16,16,16,16,16,18, 16 | 15,16,16,61,16,16,61,16,61,16,18,16,16,16,16,61,16,29,2,2,59,2,2,2,59,32,16,16,16,16,16,16,61,16,61,61,16,16,16,16,16,16,18, 17 | 57,2,2,2,2,4,16,16,16,16,18,61,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,61,16,16,16,16,16,16,16,16,18, 18 | 15,61,16,16,16,43,2,2,2,2,32,16,16,16,61,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,16,16,61,61,61,61,16,16,16,16,16,18, 19 | 15,16,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,16,61,16,16,16,16,61,16,16,61,16,16,16,16,16,16,16,61,61,61,16,16,16,18, 20 | 15,16,16,16,45,61,16,16,16,16,16,16,16,16,61,16,16,16,16,61,16,16,61,16,16,16,16,16,61,16,16,61,16,16,61,16,16,16,16,16,61,16,18, 21 | 15,61,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,1,2,2,2,44,43,2,2,2,2,4,16,16,16,16,61,61,61,16,18, 22 | 57,2,2,2,32,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,61,16,15,16,16,16,16,16,16,16,16,16,18,16,16,16,16,61,16,16,16,18, 23 | 15,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,16,61,16,16,16,16,15,16,61,16,61,61,61,61,61,16,18,61,16,16,16,16,16,16,16,18, 24 | 15,61,16,16,16,16,16,1,2,2,2,2,2,2,2,4,16,16,16,16,16,61,16,15,16,16,16,16,61,61,16,16,16,18,16,16,16,16,16,16,16,16,18, 25 | 15,16,16,16,61,16,16,15,16,16,16,16,16,16,16,18,61,16,16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,18,16,16,16,16,16,16,61,16,18, 26 | 15,16,16,16,16,16,16,15,16,16,16,16,16,16,16,18,16,16,16,16,16,16,61,15,16,16,16,16,16,16,16,16,16,18,16,61,16,16,16,16,16,16,18, 27 | 15,61,61,16,16,16,16,15,16,16,16,16,16,16,16,18,16,16,16,61,16,16,61,15,16,61,16,16,16,16,16,16,16,18,16,16,16,16,16,16,16,16,18, 28 | 15,16,16,16,61,16,16,29,2,2,2,46,16,16,16,18,61,61,16,16,16,16,61,29,30,30,30,30,30,30,30,30,30,32,16,16,16,16,16,16,16,16,18, 29 | 15,16,61,16,16,16,61,16,16,16,16,15,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,18, 30 | 15,16,61,16,16,16,16,16,16,16,16,15,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,16,61,16,16,18, 31 | 15,16,61,16,16,16,16,16,16,61,16,29,2,2,2,32,16,16,16,16,16,16,16,1,2,2,2,2,2,2,2,2,4,16,16,16,16,61,16,61,16,16,18, 32 | 15,16,16,16,16,16,16,16,61,61,16,16,61,16,16,16,16,16,16,16,16,16,16,29,2,2,2,2,2,2,2,2,32,61,16,16,16,16,16,16,16,16,18, 33 | 15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,16,16,16,16,16,16,16,18, 34 | 15,16,61,16,16,16,16,16,16,16,1,2,2,2,2,2,2,2,2,2,2,4,16,16,61,16,16,16,16,16,61,16,16,16,16,16,16,16,16,16,43,2,58, 35 | 15,16,61,16,16,16,16,16,61,16,15,16,16,16,16,16,16,16,16,16,61,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,46,16,16,18, 36 | 15,16,16,16,16,16,16,16,61,16,15,16,61,16,16,16,16,16,16,16,16,43,16,16,16,16,16,16,16,16,16,16,16,61,61,61,16,16,16,15,16,61,18, 37 | 15,16,16,61,16,16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,61,61,61,16,16,16,16,16,16,16,16,16,16,15,16,47,18, 38 | 15,16,16,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,16,16,18, 39 | 29,59,59,59,2,30,2,2,30,2,2,59,2,2,2,2,2,59,2,59,2,2,59,2,2,2,2,2,59,2,2,2,2,30,2,2,2,2,59,2,2,2,32 40 | 41 | 42 | 43 | 44 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 45 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 47 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,100,100,100,100,100,101,96,0,0, 48 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,107,0,107,122,1610612836,0,0,0, 49 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,0,0,0,0,0,1610612836,0,0,0, 50 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,108,107,0,1610612836,0,0,0, 51 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1610612836,0,0,0, 52 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,0,107,0,1610612836,0,0,0, 53 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,0,0,107,0,122,1610612836,0,0,0, 54 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,100,100,100,100,100,2684354661,0,0,0, 55 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0, 56 | 0,2147483696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 57 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 58 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 59 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 60 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 61 | 0,0,0,0,0,0,0,0,75,78,76,75,75,75,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 62 | 0,0,0,0,0,0,0,0,78,76,76,75,76,78,75,0,0,0,0,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 | 0,0,0,0,0,0,0,0,76,0,77,76,77,76,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 64 | 0,0,0,0,0,0,0,0,0,0,0,0,77,77,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 65 | 0,0,0,0,0,0,0,0,0,0,0,0,76,77,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 66 | 0,0,0,0,0,0,0,0,0,0,0,0,77,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 67 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 68 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0, 69 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 70 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,0,0,0, 71 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,0,0, 72 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 73 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,0,0,0,0,0, 74 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 75 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 277 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 278 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 279 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 280 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0, 281 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 282 | 0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 283 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0, 284 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 285 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 286 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 287 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 289 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 290 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 291 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 292 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 293 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,0,0, 294 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 295 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 296 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 297 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 298 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 299 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 300 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 301 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 302 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 303 | 0,0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 304 | 0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 305 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 306 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 307 | 308 | 309 | 310 | -------------------------------------------------------------------------------- /RPG/game.cpp: -------------------------------------------------------------------------------- 1 | #include "game.h" 2 | #include "main.h" 3 | #include "map.h" 4 | #include "game_hud.h" 5 | #include "items.h" 6 | #include "treasure.h" 7 | #include "monsters.h" 8 | #include "audio.h" 9 | #include "resource_ids.h" 10 | 11 | #include "raylib.h" 12 | #include "raymath.h" 13 | 14 | struct Exit 15 | { 16 | Rectangle Bounds; 17 | std::string Destination; 18 | }; 19 | 20 | struct Chest 21 | { 22 | Rectangle Bounds; 23 | std::string Contents; 24 | bool Opened = false; 25 | }; 26 | 27 | struct MobInstance 28 | { 29 | int MobId = -1; 30 | Vector2 Position; 31 | int Health; 32 | int SpriteId; 33 | 34 | bool Triggered = false; 35 | float LastAttack = -100; 36 | }; 37 | 38 | PlayerData Player; 39 | 40 | const AttackInfo& PlayerData::GetAttack() const 41 | { 42 | if (EquipedWeapon == -1) 43 | return DefaultAttack; 44 | 45 | return GetItem(EquipedWeapon)->Attack; 46 | } 47 | 48 | const int PlayerData::GetDefense() const 49 | { 50 | if (EquipedArmor == -1) 51 | return 0 + BuffDefense; 52 | 53 | return GetItem(Player.EquipedArmor)->Defense.Defense + BuffDefense; 54 | } 55 | 56 | std::vector Exits; 57 | std::vector Chests; 58 | Chest* TargetChest = nullptr; 59 | MobInstance* TargetMob = nullptr; 60 | 61 | double GameClock = 0; 62 | 63 | float GetGameTime() { return float(GameClock); } 64 | 65 | std::vector ItemDrops; 66 | std::vector Mobs; 67 | 68 | GameHudScreen GameHud(Player); 69 | 70 | void ActivateItem(int item); 71 | void DropItem(int item); 72 | 73 | void LoadLevel(const char* level) 74 | { 75 | LoadMap(level); 76 | Player.TargetSprite = AddSprite(ClickTargetSprite, Player.Target); 77 | Player.TargetSprite->Tint = ColorAlpha(Player.TargetSprite->Tint, 0.5f); 78 | 79 | Player.Sprite = AddSprite(PlayerSprite, Player.Position); 80 | Player.Sprite->Bobble = true; 81 | Player.Sprite->Shadow = true; 82 | 83 | Player.ActivateItemCallback = ActivateItem; 84 | Player.DropItemCallback = DropItem; 85 | Player.EquipWeaponCallback = ActivateItem; 86 | Player.EquipArmorCallback = ActivateItem; 87 | } 88 | 89 | void StartLevel() 90 | { 91 | GameClock = 0; 92 | 93 | Player.LastConsumeable = -100; 94 | Player.LastAttack = -100; 95 | 96 | auto* spawn = GetFirstMapObjectOfType(PlayerSpawnType); 97 | if (spawn != nullptr) 98 | { 99 | Player.Position.x = spawn->Bounds.x; 100 | Player.Position.y = spawn->Bounds.y; 101 | } 102 | 103 | Player.TargetActive = false; 104 | 105 | Exits.clear(); 106 | for (const TileObject* exit : GetMapObjectsOfType(ExitType)) 107 | { 108 | const Property* level = exit->GetProperty("target_level"); 109 | if (level != nullptr) 110 | { 111 | if (level->Value == "-1") 112 | Exits.emplace_back(Exit{ exit->Bounds,"endgame" }); 113 | else 114 | Exits.emplace_back(Exit{ exit->Bounds,"level" + level->Value + ".tmx" }); 115 | } 116 | } 117 | 118 | Chests.clear(); 119 | TargetChest = nullptr; 120 | for (const TileObject* chest : GetMapObjectsOfType(ChestType)) 121 | { 122 | const Property* contents = chest->GetProperty("contents"); 123 | if (contents != nullptr) 124 | Chests.emplace_back(Chest{ chest->Bounds, contents->Value }); 125 | } 126 | 127 | ItemDrops.clear(); 128 | 129 | for (const TileObject* mobSpawn : GetMapObjectsOfType(MobSpawnType)) 130 | { 131 | const Property* mobType = mobSpawn->GetProperty("mob_type"); 132 | 133 | MOB* monster = GetMob(mobType->GetInt()); 134 | if (monster == nullptr) 135 | continue; 136 | 137 | Vector2 pos = Vector2{ mobSpawn->Bounds.x,mobSpawn->Bounds.y }; 138 | auto* sprite = AddSprite(monster->Sprite, pos); 139 | sprite->Bobble = true; 140 | sprite->Shadow = true; 141 | 142 | Mobs.push_back(MobInstance{ monster->Id ,pos ,monster->Health, sprite->Id }); 143 | } 144 | } 145 | 146 | void InitGame() 147 | { 148 | ActivateGame(); 149 | 150 | // load start level 151 | LoadLevel("maps/level0.tmx"); 152 | StartLevel(); 153 | } 154 | 155 | void QuitGame() 156 | { 157 | ClearMap(); 158 | } 159 | 160 | void ActivateGame() 161 | { 162 | SetActiveScreen(&GameHud); 163 | } 164 | 165 | void GetPlayerInput() 166 | { 167 | // check for clicks 168 | if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && !GameHud.IsUiClick(GetMousePosition())) 169 | { 170 | Vector2 mousePos = GetScreenToWorld2D(GetMousePosition(), GetMapCamera()); 171 | 172 | if (PointInMap(mousePos)) 173 | { 174 | Player.TargetActive = true; 175 | Player.Target = mousePos; 176 | } 177 | 178 | TargetChest = nullptr; 179 | for (auto& chest : Chests) 180 | { 181 | if (CheckCollisionPointRec(mousePos, chest.Bounds)) 182 | { 183 | TargetChest = &chest; 184 | } 185 | } 186 | 187 | for (auto& mob : Mobs) 188 | { 189 | if (CheckCollisionPointCircle(mousePos, mob.Position, 20)) 190 | { 191 | TargetMob = &mob; 192 | 193 | if (Vector2Distance(Player.Position, mob.Position) <= Player.GetAttack().Range + 40) 194 | Player.TargetActive = false; 195 | break; 196 | } 197 | } 198 | } 199 | } 200 | 201 | void PlaceItemDrop(TreasureInstance& item, Vector2& dropPoint) 202 | { 203 | Item* itemRecord = GetItem(item.ItemId); 204 | if (!itemRecord) 205 | return; 206 | 207 | bool valid = false; 208 | while (!valid) 209 | { 210 | float angle = float(GetRandomValue(-180, 180)); 211 | Vector2 vec = { cosf(angle * DEG2RAD), sinf(angle * DEG2RAD) }; 212 | vec = Vector2Add(dropPoint, Vector2Scale(vec, 45)); 213 | 214 | if (PointInMap(vec) && Vector2Distance(vec, Player.Position) > Player.PickupDistance) 215 | { 216 | item.Position = vec; 217 | valid = true; 218 | } 219 | } 220 | 221 | auto* sprite = AddSprite(itemRecord->Sprite, item.Position); 222 | sprite->Shadow = true; 223 | sprite->Bobble = true; 224 | item.SpriteId = sprite->Id; 225 | 226 | ItemDrops.push_back(item); 227 | } 228 | 229 | void DropLoot(const char* contents, Vector2& dropPoint) 230 | { 231 | std::vector loot = GetLoot(contents); 232 | for (TreasureInstance& item : loot) 233 | { 234 | PlaceItemDrop(item, dropPoint); 235 | AddEffect(item.Position, EffectType::ScaleFade, LootSprite, 1); 236 | } 237 | } 238 | 239 | TreasureInstance RemoveInventoryItem(int slot, int quantity) 240 | { 241 | TreasureInstance treasure = { -1,0 }; 242 | 243 | // is it a valid slot? 244 | if (slot < 0 || slot >= Player.BackpackContents.size()) 245 | return treasure; 246 | 247 | // can't take more than we have 248 | InventoryContents& inventory = Player.BackpackContents[slot]; 249 | if (inventory.Quantity < quantity) 250 | quantity = inventory.Quantity; 251 | 252 | // make an item for what we removed 253 | treasure.ItemId = inventory.ItemId; 254 | treasure.Quantity = quantity; 255 | 256 | // reduce quantity in inventory 257 | inventory.Quantity -= quantity; 258 | 259 | // delete the item in inventory if it's empty 260 | if (inventory.Quantity <= 0) 261 | { 262 | Player.BackpackContents.erase(Player.BackpackContents.begin() + slot); 263 | } 264 | 265 | // return the drop instance 266 | return treasure; 267 | } 268 | 269 | bool PickupItem(TreasureInstance& drop) 270 | { 271 | // special case for bag of gold, because it's not a real item 272 | if (drop.ItemId == GoldBagItem) 273 | { 274 | PlaySound(CoinSoundId); 275 | Player.Gold += drop.Quantity; 276 | return true; 277 | } 278 | 279 | // find our item 280 | Item* item = GetItem(drop.ItemId); 281 | 282 | // it's an invalid item, remove it but nobody gets it 283 | if (item == nullptr) 284 | return true; 285 | 286 | // see if this is a weapon, and we are unarmed, if so, equip one 287 | if (item->IsWeapon() && Player.EquipedWeapon == -1) 288 | { 289 | Player.EquipedWeapon = item->Id; 290 | drop.Quantity--; 291 | PlaySound(ItemPickupSoundId); 292 | } 293 | 294 | // see if this is armor, and we are naked, if so, equip one 295 | if (item->IsArmor() && Player.EquipedArmor == -1) 296 | { 297 | Player.EquipedArmor = item->Id; 298 | drop.Quantity--; 299 | PlaySound(ItemPickupSoundId); 300 | } 301 | 302 | // Try to add items to any stacks we already have 303 | if (drop.Quantity > 0) 304 | { 305 | // see if we have any already 306 | for (InventoryContents& content : Player.BackpackContents) 307 | { 308 | if (content.ItemId == item->Id) 309 | { 310 | content.Quantity += drop.Quantity; 311 | drop.Quantity = 0; 312 | PlaySound(ItemPickupSoundId); 313 | break; 314 | } 315 | } 316 | } 317 | 318 | // Try to add items to a new inventory slot 319 | if (drop.Quantity > 0 && Player.BackpackContents.size() < 20 ) 320 | { 321 | Player.BackpackContents.emplace_back(InventoryContents{item->Id,drop.Quantity }); 322 | drop.Quantity = 0; 323 | 324 | PlaySound(ItemPickupSoundId); 325 | } 326 | 327 | // if we picked them all up, we can destroy the item 328 | return drop.Quantity == 0; 329 | } 330 | 331 | 332 | void MovePlayer() 333 | { 334 | // does the player want to move 335 | if (Player.TargetActive) 336 | { 337 | Vector2 movement = Vector2Subtract(Player.Target, Player.Position); 338 | float distance = Vector2Length(movement); 339 | 340 | float frameSpeed = GetFrameTime() * Player.Speed; 341 | 342 | if (distance <= frameSpeed) 343 | { 344 | Player.Position = Player.Target; 345 | Player.TargetActive = false; 346 | } 347 | else 348 | { 349 | movement = Vector2Normalize(movement); 350 | Vector2 newPos = Vector2Add(Player.Position, Vector2Scale(movement, frameSpeed)); 351 | 352 | if (!PointInMap(newPos)) 353 | { 354 | Player.TargetActive = false; 355 | } 356 | else 357 | { 358 | Player.Position = newPos; 359 | } 360 | } 361 | } 362 | 363 | // see if the player entered an exit 364 | for (auto exit : Exits) 365 | { 366 | if (CheckCollisionPointRec(Player.Position, exit.Bounds)) 367 | { 368 | if (exit.Destination == "endgame") 369 | { 370 | EndGame(true, Player.Gold + 100); 371 | } 372 | else 373 | { 374 | std::string map = "maps/" + exit.Destination; 375 | LoadLevel(map.c_str()); 376 | StartLevel(); 377 | } 378 | 379 | break; 380 | } 381 | } 382 | } 383 | 384 | void ApplyPlayerActions() 385 | { 386 | // see if we want to attack any mobs 387 | if (TargetMob != nullptr) 388 | { 389 | // see if we can even attack. 390 | if (GetGameTime() - Player.LastAttack >= Player.GetAttack().Cooldown) 391 | { 392 | float distance = Vector2Distance(TargetMob->Position, Player.Position); 393 | if (distance < Player.GetAttack().Range + 40) 394 | { 395 | MOB* monsterInfo = GetMob(TargetMob->MobId); 396 | if (monsterInfo != nullptr) 397 | { 398 | AddEffect(TargetMob->Position, EffectType::ScaleFade, ClickTargetSprite); 399 | if (!Player.GetAttack().Melee) 400 | AddEffect(Player.Position, EffectType::ToTarget, ProjectileSprite, TargetMob->Position, 0.25f); 401 | 402 | int damage = ResolveAttack(Player.GetAttack(), monsterInfo->Defense.Defense); 403 | if (damage == 0) 404 | { 405 | PlaySound(MissSoundId); 406 | } 407 | else 408 | { 409 | PlaySound(HitSoundId); 410 | PlaySound(CreatureDamageSoundId); 411 | AddEffect(Vector2{ TargetMob->Position.x, TargetMob->Position.y - 16 }, EffectType::RiseFade, DamageSprite); 412 | TargetMob->Health -= damage; 413 | 414 | // if you hit them, they wake up! 415 | TargetMob->Triggered = true; 416 | } 417 | } 418 | } 419 | 420 | TargetMob = nullptr; 421 | } 422 | } 423 | 424 | // see if the player is near the last clicked chest, if so open it 425 | if (TargetChest != nullptr) 426 | { 427 | Vector2 center = { TargetChest->Bounds.x + TargetChest->Bounds.width / 2,TargetChest->Bounds.y + TargetChest->Bounds.height / 2 }; 428 | 429 | float distance = Vector2Distance(center, Player.Position); 430 | if (distance <= 50) 431 | { 432 | if (!TargetChest->Opened) 433 | { 434 | PlaySound(ChestOpenSoundId); 435 | TargetChest->Opened = true; 436 | DropLoot(TargetChest->Contents.c_str(), center); 437 | } 438 | TargetChest = nullptr; 439 | } 440 | } 441 | 442 | // see if we are under any items to pickup 443 | for (std::vector::iterator item = ItemDrops.begin(); item != ItemDrops.end(); ) 444 | { 445 | float distance = Vector2Distance(item->Position, Player.Position); 446 | if (distance <= Player.PickupDistance) 447 | { 448 | if (PickupItem(*item)) 449 | { 450 | RemoveSprite(item->SpriteId); 451 | item = ItemDrops.erase(item); 452 | continue; 453 | } 454 | } 455 | 456 | item++; 457 | } 458 | 459 | 460 | float time = GetGameTime(); 461 | 462 | float attackTime = time - Player.LastAttack; 463 | float itemTime = time - Player.LastConsumeable; 464 | 465 | if (attackTime >= Player.GetAttack().Cooldown) 466 | Player.AttackCooldown = 0; 467 | else 468 | Player.AttackCooldown = 1.0f - (attackTime / Player.AttackCooldown); 469 | 470 | float itemCooldown = 1; 471 | 472 | if (itemTime >= itemCooldown) 473 | Player.ItemCooldown = 0; 474 | else 475 | Player.ItemCooldown = 1.0f - (itemTime / itemCooldown); 476 | 477 | if (Player.BuffLifetimeLeft > 0) 478 | { 479 | Player.BuffLifetimeLeft -= GetFrameTime(); 480 | if (Player.BuffLifetimeLeft <= 0) 481 | { 482 | Player.BuffDefense = 0; 483 | Player.BuffItem = -1; 484 | Player.BuffLifetimeLeft = 0; 485 | } 486 | } 487 | } 488 | 489 | void CullDeadMobs() 490 | { 491 | for (std::vector::iterator mobItr = Mobs.begin(); mobItr != Mobs.end();) 492 | { 493 | MOB* monsterInfo = GetMob(mobItr->MobId); 494 | if (monsterInfo != nullptr && mobItr->Health > 0) 495 | { 496 | mobItr++; 497 | continue; 498 | } 499 | 500 | if (monsterInfo != nullptr) 501 | DropLoot(monsterInfo->lootTable.c_str(), mobItr->Position); 502 | 503 | RemoveSprite(mobItr->SpriteId); 504 | if (monsterInfo != nullptr) 505 | AddEffect(mobItr->Position, EffectType::RotateFade, monsterInfo->Sprite, 3.5f); 506 | 507 | mobItr = Mobs.erase(mobItr); 508 | } 509 | } 510 | 511 | void UpdateMobs() 512 | { 513 | CullDeadMobs(); 514 | 515 | // check for mob actions 516 | for (auto& mob : Mobs) 517 | { 518 | Vector2 vecToPlayer = Vector2Subtract(Player.Position, mob.Position); 519 | float distance = Vector2Length(vecToPlayer); 520 | 521 | MOB* monsterInfo = GetMob(mob.MobId); 522 | if (monsterInfo == nullptr) 523 | continue; 524 | 525 | if (!mob.Triggered) 526 | { 527 | // see if the mob should wake up 528 | if (distance > monsterInfo->DetectionRadius) // too far away 529 | continue; 530 | 531 | if (Ray2DHitsMap(Player.Position, mob.Position)) 532 | continue; // something is blocking line of sight 533 | 534 | // we see our prey, wake up and get em. 535 | mob.Triggered = true; 536 | 537 | PlaySound(AlertSoundId); 538 | AddEffect(mob.Position, EffectType::RiseFade, AwakeSprite, 1); 539 | } 540 | 541 | if (mob.Triggered) 542 | { 543 | if (distance < monsterInfo->Attack.Range) 544 | { 545 | // try to attack the player 546 | if (GetGameTime() - mob.LastAttack >= monsterInfo->Attack.Cooldown) 547 | { 548 | mob.LastAttack = GetGameTime(); 549 | int damage = ResolveAttack(monsterInfo->Attack, Player.GetDefense()); 550 | 551 | if (monsterInfo->Attack.Melee) 552 | AddEffect(Player.Position, EffectType::RotateFade, MobAttackSprite); 553 | else 554 | AddEffect(mob.Position, EffectType::ToTarget, ProjectileSprite, Player.Position, 0.5f); 555 | 556 | if (damage == 0) 557 | { 558 | PlaySound(MissSoundId); 559 | } 560 | else 561 | { 562 | PlaySound(HitSoundId); 563 | PlaySound(PlayerDamageSoundId); 564 | AddEffect(Vector2{ Player.Position.x,Player.Position.y - 16 }, EffectType::RiseFade, DamageSprite); 565 | Player.Health -= damage; 566 | } 567 | } 568 | } 569 | else 570 | { 571 | // try to move 572 | Vector2 movement = Vector2Normalize(vecToPlayer); 573 | 574 | float frameSpeed = monsterInfo->Speed * GetFrameTime(); 575 | Vector2 newPos = Vector2Add(mob.Position, Vector2Scale(movement, frameSpeed)); 576 | 577 | if (PointInMap(newPos)) 578 | mob.Position = newPos; 579 | } 580 | } 581 | } 582 | } 583 | 584 | void UpdatePlayerSprite() 585 | { 586 | if (Player.Sprite != nullptr) 587 | Player.Sprite->Position = Player.Position; 588 | 589 | if (Player.EquipedArmor == ChainArmorItem) 590 | Player.Sprite->SpriteFrame = PlayerChainSprite; 591 | else if (Player.EquipedArmor == PlateArmorItem) 592 | Player.Sprite->SpriteFrame = PlayerPlateSprite; 593 | else if (Player.EquipedArmor == LeatherArmorItem) 594 | Player.Sprite->SpriteFrame = PlayerLeatherSprite; 595 | else 596 | Player.Sprite->SpriteFrame = PlayerSprite; 597 | 598 | if (Player.TargetSprite != nullptr) 599 | { 600 | Player.TargetSprite->Active = Player.TargetActive; 601 | Player.TargetSprite->Position = Player.Target; 602 | } 603 | } 604 | 605 | void UpdateMobSprites() 606 | { 607 | for (auto& mob : Mobs) 608 | { 609 | UpdateSprite(mob.SpriteId, mob.Position); 610 | } 611 | } 612 | 613 | MobInstance* GetNearestMobInSight() 614 | { 615 | MobInstance* nearest = nullptr; 616 | float nearestDistance = 9999999.9f; 617 | 618 | for (auto& mob : Mobs) 619 | { 620 | if (Ray2DHitsMap(mob.Position,Player.Position)) 621 | continue; 622 | 623 | float dist = Vector2Distance(mob.Position, Player.Position); 624 | 625 | if (dist < nearestDistance) 626 | { 627 | nearest = &mob; 628 | nearestDistance = dist; 629 | } 630 | } 631 | 632 | return nearest; 633 | } 634 | 635 | void UpdateSprites() 636 | { 637 | UpdatePlayerSprite(); 638 | UpdateMobSprites(); 639 | } 640 | 641 | void UpdateGame() 642 | { 643 | if (IsKeyPressed(KEY_ESCAPE)) 644 | { 645 | if (GameHud.InventoryOpen) 646 | GameHud.InventoryOpen = false; 647 | else 648 | { 649 | PauseGame(); 650 | return; 651 | } 652 | } 653 | 654 | if (!IsWindowFocused()) 655 | { 656 | PauseGame(); 657 | return; 658 | } 659 | 660 | // only update our game clock when we are unpaused 661 | GameClock += GetFrameTime(); 662 | 663 | GetPlayerInput(); 664 | MovePlayer(); 665 | ApplyPlayerActions(); 666 | 667 | UpdateMobs(); 668 | 669 | if (Player.Health < 0) 670 | { 671 | // you died, change to the end screen 672 | EndGame(false,Player.Gold); 673 | } 674 | 675 | UpdateSprites(); 676 | 677 | SetVisiblePoint(Player.Position); 678 | } 679 | 680 | void UseConsumable(Item* item) 681 | { 682 | if (item == nullptr || !item->IsActivatable()) 683 | return; 684 | 685 | float time = GetGameTime() - Player.LastConsumeable; 686 | if (time < 1) 687 | return; 688 | 689 | Player.LastConsumeable = GetGameTime(); 690 | 691 | switch (item->Effect) 692 | { 693 | case ActivatableEffects::Healing: 694 | Player.Health += item->Value; 695 | if (Player.Health > Player.MaxHealth) 696 | Player.Health = Player.MaxHealth; 697 | 698 | PlaySound(PlayerHealSoundId); 699 | AddEffect(Player.Position, EffectType::RiseFade, HealingSprite, 2); 700 | break; 701 | 702 | case ActivatableEffects::Defense: 703 | Player.BuffDefense = item->Value; 704 | Player.BuffLifetimeLeft = item->Durration; 705 | Player.BuffItem = item->Sprite; 706 | break; 707 | 708 | case ActivatableEffects::Damage: 709 | { 710 | MobInstance* mob = GetNearestMobInSight(); 711 | if (mob != nullptr) 712 | { 713 | mob->Health -= item->Value; 714 | PlaySound(CreatureDamageSoundId); 715 | AddEffect(Player.Position, EffectType::ToTarget, item->Sprite, mob->Position, 1); 716 | AddEffect(mob->Position, EffectType::RotateFade, item->Sprite, 1); 717 | } 718 | break; 719 | } 720 | } 721 | } 722 | 723 | void ActivateItem(int slotIndex) 724 | { 725 | if (slotIndex < 0 || slotIndex >= Player.BackpackContents.size()) 726 | return; 727 | 728 | InventoryContents& inventorySlot = Player.BackpackContents[slotIndex]; 729 | 730 | Item* item = GetItem(inventorySlot.ItemId); 731 | if (item == nullptr) 732 | return; 733 | 734 | TreasureInstance removedItem = RemoveInventoryItem(slotIndex, 1); 735 | 736 | if (removedItem.Quantity == 0) 737 | return; 738 | 739 | switch (item->ItemType) 740 | { 741 | case ItemTypes::Activatable: 742 | UseConsumable(item); 743 | removedItem.ItemId = -1; 744 | removedItem.Quantity = 0; 745 | break; 746 | 747 | case ItemTypes::Weapon: 748 | { 749 | // save our current weapon 750 | int weapon = Player.EquipedWeapon; 751 | 752 | // equip new weapon 753 | Player.EquipedWeapon = removedItem.ItemId; 754 | 755 | // replace the removed item with the old weapon 756 | removedItem.ItemId = weapon; 757 | break; 758 | } 759 | 760 | case ItemTypes::Armor: 761 | { 762 | // save our current armor 763 | int armor = Player.EquipedArmor; 764 | 765 | // equip new weapon 766 | Player.EquipedArmor = removedItem.ItemId; 767 | 768 | // replace the removed item with the old weapon 769 | removedItem.ItemId = armor; 770 | break; 771 | } 772 | 773 | } 774 | 775 | // put whatever we have back, or drop it 776 | if (removedItem.ItemId != -1) 777 | { 778 | // stick it back in our bag 779 | if (!PickupItem(removedItem)) 780 | { 781 | // no room, drop it 782 | PlaceItemDrop(removedItem, Player.Position); 783 | } 784 | } 785 | } 786 | 787 | void DropItem(int item) 788 | { 789 | TreasureInstance drop = RemoveInventoryItem(item, 999); 790 | PlaceItemDrop(drop, Player.Position); 791 | } --------------------------------------------------------------------------------