├── game_engine ├── data │ ├── gfx │ │ └── upload your graphics here.txt │ ├── maps │ │ └── 1.map │ └── config-example.ini ├── src │ ├── guiforms.cpp │ ├── guiforms.hpp │ ├── handlers │ │ ├── init.hpp │ │ ├── ping.hpp │ │ ├── login.hpp │ │ ├── ping.cpp │ │ ├── file_data.hpp │ │ ├── h_map.hpp │ │ ├── account.hpp │ │ ├── h_npc.hpp │ │ ├── h_character.hpp │ │ ├── init.cpp │ │ ├── account.cpp │ │ ├── file_data.cpp │ │ ├── login.cpp │ │ ├── h_map.cpp │ │ ├── h_npc.cpp │ │ └── h_character.cpp │ ├── const │ │ ├── entity.hpp │ │ └── packet.hpp │ ├── font_handler.hpp │ ├── game_state.cpp │ ├── game_state.hpp │ ├── font_handler.cpp │ ├── map_cursor.hpp │ ├── animation.hpp │ ├── map_editor.hpp │ ├── input_handler.hpp │ ├── config.hpp │ ├── packet_handler.hpp │ ├── file_handler.hpp │ ├── imgui_impl_a5.h │ ├── npc.hpp │ ├── gfx_loader.hpp │ ├── animation.cpp │ ├── character.hpp │ ├── util.hpp │ ├── packet_handler.cpp │ ├── gui.hpp │ ├── client.hpp │ ├── util.cpp │ ├── gfx_loader.cpp │ ├── map.hpp │ ├── config.cpp │ ├── file_handler.cpp │ ├── input_handler.cpp │ ├── map_cursor.cpp │ ├── npc.cpp │ ├── character.cpp │ ├── client.cpp │ ├── main.cpp │ ├── map_editor.cpp │ ├── imgui_impl_a5.cpp │ └── map.cpp └── imgui.ini ├── server_engine ├── data │ ├── config-example.ini │ ├── eo.db │ └── maps │ │ ├── 1.map │ │ └── 2.map └── src │ ├── handlers │ ├── init.hpp │ ├── login.hpp │ ├── h_map.hpp │ ├── ping.hpp │ ├── file_data.hpp │ ├── h_map.cpp │ ├── ping.cpp │ ├── h_npc.hpp │ ├── account.hpp │ ├── h_character.hpp │ ├── file_data.cpp │ ├── init.cpp │ ├── h_npc.cpp │ ├── account.cpp │ └── login.cpp │ ├── const │ ├── packet.hpp │ └── entity.hpp │ ├── map_handler.hpp │ ├── server_state.hpp │ ├── server_state.cpp │ ├── database.hpp │ ├── config.hpp │ ├── map_handler.cpp │ ├── npc.hpp │ ├── server.hpp │ ├── packet_handler.hpp │ ├── file_handler.hpp │ ├── character.hpp │ ├── main.cpp │ ├── client.hpp │ ├── util.hpp │ ├── packet_handler.cpp │ ├── database.cpp │ ├── character.cpp │ ├── util.cpp │ ├── map.hpp │ ├── config.cpp │ ├── npc.cpp │ ├── file_handler.cpp │ ├── client.cpp │ ├── server.cpp │ └── map.cpp ├── changelog.txt └── README.md /game_engine/data/gfx/upload your graphics here.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server_engine/data/config-example.ini: -------------------------------------------------------------------------------- 1 | # EOA Server Configuration File. 2 | # General settings. 3 | -------------------------------------------------------------------------------- /server_engine/data/eo.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jimmyee/Endless-Online-Awaken/HEAD/server_engine/data/eo.db -------------------------------------------------------------------------------- /game_engine/data/maps/1.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jimmyee/Endless-Online-Awaken/HEAD/game_engine/data/maps/1.map -------------------------------------------------------------------------------- /server_engine/data/maps/1.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jimmyee/Endless-Online-Awaken/HEAD/server_engine/data/maps/1.map -------------------------------------------------------------------------------- /server_engine/data/maps/2.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jimmyee/Endless-Online-Awaken/HEAD/server_engine/data/maps/2.map -------------------------------------------------------------------------------- /game_engine/src/guiforms.cpp: -------------------------------------------------------------------------------- 1 | #include "guiforms.hpp" 2 | 3 | #include 4 | 5 | 6 | namespace GUIForms 7 | { 8 | 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /game_engine/data/config-example.ini: -------------------------------------------------------------------------------- 1 | # Endless Online Awaken configuration file. 2 | # General settings. 3 | # 4 | Address 5 | localhost 6 | Port 7 | 8078 8 | Fullscreen 9 | no 10 | Resolution 11 | 640 480 -------------------------------------------------------------------------------- /game_engine/src/guiforms.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GUIFORMS_HPP_INCLUDED 2 | #define GUIFORMS_HPP_INCLUDED 3 | 4 | namespace GUIForms 5 | { 6 | 7 | void MainMenu(); 8 | 9 | } 10 | 11 | #endif // GUIFORMS_HPP_INCLUDED 12 | -------------------------------------------------------------------------------- /server_engine/src/handlers/init.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INIT_HPP_INCLUDED 2 | #define INIT_HPP_INCLUDED 3 | 4 | #include 5 | 6 | namespace PacketHandlers::HInit 7 | { 8 | void Main(sf::Packet &packet, std::array data_ptr); 9 | }; 10 | 11 | #endif // INIT_HPP_INCLUDED 12 | -------------------------------------------------------------------------------- /server_engine/src/handlers/login.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOGIN_HPP_INCLUDED 2 | #define LOGIN_HPP_INCLUDED 3 | 4 | #include 5 | 6 | namespace PacketHandlers::HLogin 7 | { 8 | void Main(sf::Packet &packet, std::array data_ptr); 9 | }; 10 | 11 | #endif // LOGIN_HPP_INCLUDED 12 | -------------------------------------------------------------------------------- /game_engine/src/handlers/init.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INIT_HPP_INCLUDED 2 | #define INIT_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HInit 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | }; 11 | 12 | #endif // INIT_HPP_INCLUDED 13 | -------------------------------------------------------------------------------- /game_engine/src/handlers/ping.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PING_HPP_INCLUDED 2 | #define PING_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HPing 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | } 11 | 12 | #endif // PING_HPP_INCLUDED 13 | -------------------------------------------------------------------------------- /game_engine/src/handlers/login.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOGIN_HPP_INCLUDED 2 | #define LOGIN_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HLogin 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | }; 11 | 12 | #endif // LOGIN_HPP_INCLUDED 13 | -------------------------------------------------------------------------------- /server_engine/src/handlers/h_map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef H_MAP_HPP_INCLUDED 2 | #define H_MAP_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HMap 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | } 11 | 12 | #endif // H_MAP_HPP_INCLUDED 13 | -------------------------------------------------------------------------------- /server_engine/src/handlers/ping.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PING_HPP_INCLUDED 2 | #define PING_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HPing 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | } 11 | 12 | #endif // PING_HPP_INCLUDED 13 | -------------------------------------------------------------------------------- /server_engine/src/const/packet.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CONST_HPP_INCLUDED 4 | #define CONST_HPP_INCLUDED 5 | 6 | enum class PacketID : unsigned char 7 | { 8 | Init, 9 | Login, 10 | Account, 11 | Character, 12 | NPC, 13 | Map, 14 | FileData, 15 | Ping 16 | }; 17 | 18 | #endif // CONST_HPP_INCLUDED 19 | -------------------------------------------------------------------------------- /game_engine/src/handlers/ping.cpp: -------------------------------------------------------------------------------- 1 | #include "ping.hpp" 2 | 3 | #include "../client.hpp" 4 | 5 | namespace PacketHandlers::HPing 6 | { 7 | void Main(sf::Packet &packet, std::array data_ptr) 8 | { 9 | sf::Packet reply; 10 | 11 | reply << (unsigned char)PacketID::Ping; 12 | 13 | Client().Send(reply); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /game_engine/src/const/entity.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef ENTITY_HPP_INCLUDED 4 | #define ENTITY_HPP_INCLUDED 5 | 6 | enum class Direction : unsigned char 7 | { 8 | Up, 9 | Right, 10 | Down, 11 | Left 12 | }; 13 | 14 | enum class Gender : unsigned char 15 | { 16 | Female, 17 | Male 18 | }; 19 | 20 | #endif // ENTITY_HPP_INCLUDED 21 | -------------------------------------------------------------------------------- /server_engine/src/const/entity.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef ENTITY_HPP_INCLUDED 4 | #define ENTITY_HPP_INCLUDED 5 | 6 | enum class Direction : unsigned char 7 | { 8 | Up, 9 | Right, 10 | Down, 11 | Left 12 | }; 13 | 14 | enum class Gender : unsigned char 15 | { 16 | Female, 17 | Male 18 | }; 19 | 20 | #endif // ENTITY_HPP_INCLUDED 21 | -------------------------------------------------------------------------------- /game_engine/src/const/packet.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CONST_HPP_INCLUDED 4 | #define CONST_HPP_INCLUDED 5 | 6 | #include 7 | 8 | enum class PacketID : unsigned char 9 | { 10 | Init, 11 | Login, 12 | Account, 13 | Character, 14 | NPC, 15 | Map, 16 | FileData, 17 | Ping 18 | }; 19 | 20 | #endif // CONST_HPP_INCLUDED 21 | -------------------------------------------------------------------------------- /game_engine/src/handlers/file_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FILE_DATA_HPP_INCLUDED 2 | #define FILE_DATA_HPP_INCLUDED 3 | 4 | #include 5 | 6 | namespace PacketHandlers::FileData 7 | { 8 | void Main(sf::Packet &packet, std::array data_ptr); 9 | void FileTransfer(sf::Packet &packet, std::array data_ptr); 10 | } 11 | 12 | #endif // FILE_DATA_HPP_INCLUDED 13 | -------------------------------------------------------------------------------- /game_engine/src/font_handler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FONT_HANDLER_HPP_INCLUDED 2 | #define FONT_HANDLER_HPP_INCLUDED 3 | 4 | #include 5 | 6 | // (monostate) 7 | class FontHandler 8 | { 9 | private: 10 | static bool initialized; 11 | 12 | public: 13 | static ALLEGRO_FONT *font; 14 | 15 | FontHandler(); 16 | void Load(); 17 | }; 18 | 19 | #endif // FONT_HANDLER_HPP_INCLUDED 20 | -------------------------------------------------------------------------------- /server_engine/src/handlers/file_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FILE_DATA_HPP_INCLUDED 2 | #define FILE_DATA_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::FileData 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void FileTransfer(sf::Packet &packet, std::array data_ptr); 11 | } 12 | 13 | #endif // FILE_DATA_HPP_INCLUDED 14 | -------------------------------------------------------------------------------- /server_engine/src/handlers/h_map.cpp: -------------------------------------------------------------------------------- 1 | #include "h_map.hpp" 2 | 3 | namespace PacketHandlers::HMap 4 | { 5 | void Main(sf::Packet &packet, std::array data_ptr) 6 | { 7 | unsigned char sub_id = 0; 8 | 9 | packet >> sub_id; 10 | 11 | if(sub_id == 1) // an entity appears 12 | { 13 | 14 | } 15 | if(sub_id == 2) // an entity leaves 16 | { 17 | 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server_engine/src/handlers/ping.cpp: -------------------------------------------------------------------------------- 1 | #include "ping.hpp" 2 | 3 | #include "../client.hpp" 4 | 5 | #include 6 | 7 | namespace PacketHandlers::HPing 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr) 10 | { 11 | Client *client = (Client *)data_ptr[0]; 12 | 13 | client->latency = client->ping_clock.getElapsedTime().asMilliseconds(); 14 | 15 | client->ping_clock.restart(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /game_engine/src/handlers/h_map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef H_MAP_HPP_INCLUDED 2 | #define H_MAP_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HMap 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void Appear(sf::Packet &packet, std::array data_ptr); 11 | void Leave(sf::Packet &packet, std::array data_ptr); 12 | } 13 | 14 | #endif // H_MAP_HPP_INCLUDED 15 | -------------------------------------------------------------------------------- /server_engine/src/handlers/h_npc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef H_NPC_HPP_INCLUDED 2 | #define H_NPC_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HNPC 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void List(sf::Packet &packet, std::array data_ptr); 11 | 12 | void GetInRange(sf::Packet packet, std::array data_ptr); 13 | }; 14 | 15 | #endif // H_NPC_HPP_INCLUDED 16 | -------------------------------------------------------------------------------- /game_engine/src/handlers/account.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ACCOUNT_HPP_INCLUDED 2 | #define ACCOUNT_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HAccount 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void Create(sf::Packet &packet, std::array data_ptr); 11 | void Delete(sf::Packet &packet, std::array data_ptr); 12 | }; 13 | 14 | #endif // ACCOUNT_HPP_INCLUDED 15 | -------------------------------------------------------------------------------- /server_engine/src/handlers/account.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ACCOUNT_HPP_INCLUDED 2 | #define ACCOUNT_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HAccount 8 | { 9 | 10 | void Main(sf::Packet &packet, std::array data_ptr); 11 | void Create(sf::Packet &packet, std::array data_ptr); 12 | void Delete(sf::Packet &packet, std::array data_ptr); 13 | 14 | }; 15 | 16 | #endif // ACCOUNT_HPP_INCLUDED 17 | -------------------------------------------------------------------------------- /server_engine/src/map_handler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAP_HANDLER_HPP_INCLUDED 2 | #define MAP_HANDLER_HPP_INCLUDED 3 | 4 | #include "map.hpp" 5 | 6 | #include 7 | 8 | // (monostate) 9 | class MapHandler 10 | { 11 | private: 12 | static bool initialized_; 13 | 14 | public: 15 | static std::map maps; 16 | 17 | MapHandler(); 18 | Map *GetMap(unsigned int id); 19 | void Clear(); 20 | void Reload(); 21 | }; 22 | 23 | #endif // MAP_HANDLER_HPP_INCLUDED 24 | -------------------------------------------------------------------------------- /server_engine/src/server_state.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef SERVER_STATE_HPP_INCLUDED 4 | #define SERVER_STATE_HPP_INCLUDED 5 | 6 | // (monostate) 7 | class ServerState 8 | { 9 | public: 10 | enum class State 11 | { 12 | Exit, 13 | Run 14 | }; 15 | 16 | private: 17 | static bool initialized_; 18 | static State state; 19 | 20 | public: 21 | ServerState(); 22 | State Get(); 23 | void Set(State state); 24 | }; 25 | 26 | #endif // SERVER_STATE_HPP_INCLUDED 27 | -------------------------------------------------------------------------------- /game_engine/src/game_state.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "game_state.hpp" 4 | 5 | bool GameState::initialized_ = false; 6 | GameState::State GameState::state; 7 | 8 | GameState::GameState() 9 | { 10 | if(!this->initialized_) 11 | { 12 | this->state = GameState::State::MainMenu; 13 | 14 | this->initialized_ = true; 15 | } 16 | } 17 | 18 | GameState::State GameState::Get() 19 | { 20 | return this->state; 21 | } 22 | 23 | void GameState::Set(State state) 24 | { 25 | this->state = state; 26 | } 27 | -------------------------------------------------------------------------------- /game_engine/src/game_state.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef STATE_HANDLER_HPP_INCLUDED 4 | #define STATE_HANDLER_HPP_INCLUDED 5 | 6 | // game state handler (monostate) 7 | class GameState 8 | { 9 | public: 10 | enum class State 11 | { 12 | Exit, 13 | MainMenu, 14 | Playing 15 | }; 16 | 17 | private: 18 | static bool initialized_; 19 | static State state; 20 | 21 | public: 22 | GameState(); 23 | State Get(); 24 | void Set(State state); 25 | }; 26 | 27 | #endif // STATE_HANDLER_HPP_INCLUDED 28 | -------------------------------------------------------------------------------- /server_engine/src/server_state.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "server_state.hpp" 4 | 5 | bool ServerState::initialized_ = false; 6 | ServerState::State ServerState::state; 7 | 8 | ServerState::ServerState() 9 | { 10 | if(!this->initialized_) 11 | { 12 | this->state = ServerState::State::Run; 13 | 14 | this->initialized_ = true; 15 | } 16 | } 17 | 18 | ServerState::State ServerState::Get() 19 | { 20 | return this->state; 21 | } 22 | 23 | void ServerState::Set(State state) 24 | { 25 | this->state = state; 26 | } 27 | -------------------------------------------------------------------------------- /game_engine/src/font_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "font_handler.hpp" 2 | 3 | #include 4 | 5 | bool FontHandler::initialized = false; 6 | ALLEGRO_FONT *FontHandler::font; 7 | 8 | FontHandler::FontHandler() 9 | { 10 | if(!this->initialized) 11 | { 12 | this->Load(); 13 | 14 | this->initialized = true; 15 | } 16 | } 17 | 18 | void FontHandler::Load() 19 | { 20 | this->font = al_load_ttf_font("data/fonts/micross.ttf", 14, 0); 21 | 22 | if(font == NULL) 23 | { 24 | std::cout << "Could not load font" << std::endl; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /game_engine/src/handlers/h_npc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef H_NPC_HPP_INCLUDED 2 | #define H_NPC_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HNPC 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void List(sf::Packet &packet, std::array data_ptr); 11 | void Talk(sf::Packet &packet, std::array data_ptr); 12 | void Face(sf::Packet &packet, std::array data_ptr); 13 | void Walk(sf::Packet &packet, std::array data_ptr); 14 | }; 15 | 16 | #endif // H_NPC_HPP_INCLUDED 17 | -------------------------------------------------------------------------------- /game_engine/src/map_cursor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAP_CURSOR_HPP_INCLUDED 2 | #define MAP_CURSOR_HPP_INCLUDED 3 | 4 | #include 5 | 6 | // (monostate) 7 | class MapCursor 8 | { 9 | private: 10 | static bool initialized_; 11 | 12 | public: 13 | static std::string nickname; 14 | static unsigned short x; 15 | static unsigned short y; 16 | static int rx; 17 | static int ry; 18 | 19 | MapCursor(); 20 | void Render(int rx, int ry); 21 | bool TestMousePos(int mx, int my, unsigned short x, unsigned short y); 22 | bool MouseOnMap(); 23 | }; 24 | 25 | #endif // MAP_CURSOR_HPP_INCLUDED 26 | -------------------------------------------------------------------------------- /game_engine/src/animation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ANIMATION_HPP_INCLUDED 2 | #define ANIMATION_HPP_INCLUDED 3 | 4 | #include 5 | 6 | class Animation 7 | { 8 | public: 9 | struct Frame 10 | { 11 | int delay; 12 | 13 | Frame() : delay(0) { } 14 | Frame(int delay) : delay(delay) { } 15 | }; 16 | 17 | public: 18 | std::vector frames; 19 | std::size_t current_frame; 20 | bool play; 21 | int delay_count; 22 | bool replay; 23 | 24 | Animation(); 25 | void Tick(); 26 | void Play(); 27 | void Clear(); 28 | }; 29 | 30 | #endif // ANIMATION_HPP_INCLUDED 31 | -------------------------------------------------------------------------------- /game_engine/src/map_editor.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef MAP_EDITOR_HPP_INCLUDED 4 | #define MAP_EDITOR_HPP_INCLUDED 5 | 6 | #include "map.hpp" 7 | 8 | #include 9 | #include 10 | 11 | // (monostate) 12 | class MapEditor 13 | { 14 | private: 15 | static bool initialized_; 16 | static unsigned int graphic_id; 17 | static Map::Layer::Type type; 18 | 19 | public: 20 | static int render_xoff; 21 | static int render_yoff; 22 | 23 | MapEditor(); 24 | void MakeGUI(); 25 | void ProcessInput(); 26 | void Reset(); 27 | }; 28 | 29 | #endif // MAP_EDITOR_HPP_INCLUDED 30 | -------------------------------------------------------------------------------- /server_engine/src/database.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef DATABASE_HPP_INCLUDED 4 | #define DATABASE_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | 9 | typedef int(*sqlite_callback)(void *, int, char **, char **); 10 | 11 | class Database 12 | { 13 | private: 14 | static bool initialized_; 15 | static sqlite3 *db; 16 | 17 | public: 18 | Database(std::string name); 19 | Database(); 20 | void Load(std::string name); 21 | void Close(); 22 | sqlite3 *Get(); 23 | int Execute(const char *sql, sqlite_callback callback, void *data = 0); 24 | }; 25 | 26 | #endif // DATABASE_HPP_INCLUDED 27 | -------------------------------------------------------------------------------- /game_engine/src/input_handler.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef INPUT_HANDLER_HPP_INCLUDED 4 | #define INPUT_HANDLER_HPP_INCLUDED 5 | 6 | #include "const/entity.hpp" 7 | 8 | #include 9 | #include 10 | 11 | // (monostate) 12 | class InputHandler 13 | { 14 | private: 15 | static bool initialized_; 16 | 17 | public: 18 | static std::map keys; 19 | static std::map mouse; 20 | static Direction direction; 21 | static bool rewalk; 22 | 23 | InputHandler(); 24 | 25 | void ProcessEvent(ALLEGRO_EVENT event); 26 | void Process(); 27 | 28 | void CharacterMovement(); 29 | }; 30 | 31 | #endif // INPUT_HANDLER_HPP_INCLUDED 32 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | 0.0.1: 2 | - network client/server and packet handler 3 | - map editor for fill tile layer 4 | - map of two layers 5 | - database support 6 | - character with few attributes (map ID, x, y, direction, gender) 7 | - account creation, login features 8 | - character creation and deletion 9 | - credits window 10 | - character list 11 | - "turn around" feature for character 12 | - very simple chat (public chat only) 13 | - support for multiple characters 14 | - support for managing multiple maps at once 15 | - character walk feature 16 | - improved character management while walking 17 | 18 | 0.0.1b: 19 | - support for rendering nicknames for characters on the map 20 | - new character graphics 21 | - file transfer for updating clients -------------------------------------------------------------------------------- /server_engine/src/config.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CONFIG_HPP_INCLUDED 4 | #define CONFIG_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | 9 | class Config 10 | { 11 | public: 12 | struct Entry 13 | { 14 | std::string key; 15 | std::string value; 16 | 17 | Entry(std::string key, std::string value) { this->key = key; this->value = value; } 18 | }; 19 | 20 | public: 21 | std::vector entries; 22 | 23 | Config(); 24 | Config(std::string filename); 25 | void Load(std::string filename); 26 | void Save(std::string filename); 27 | Entry GetEntry(std::string key); 28 | std::string GetValue(std::string key); 29 | void AddEntry(Entry); 30 | void AddEntry(std::string key, std::string value); 31 | }; 32 | 33 | #endif // CONFIG_HPP_INCLUDED 34 | -------------------------------------------------------------------------------- /game_engine/src/handlers/h_character.hpp: -------------------------------------------------------------------------------- 1 | #ifndef H_CHARACTER_HPP_INCLUDED 2 | #define H_CHARACTER_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HCharacter 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void Create(sf::Packet &packet, std::array data_ptr); 11 | void Delete(sf::Packet &packet, std::array data_ptr); 12 | void List(sf::Packet &packet, std::array data_ptr); 13 | void Select(sf::Packet &packet, std::array data_ptr); 14 | 15 | void Talk(sf::Packet &packet, std::array data_ptr); 16 | void Face(sf::Packet &packet, std::array data_ptr); 17 | void Walk(sf::Packet &packet, std::array data_ptr); 18 | }; 19 | 20 | #endif // H_CHARACTER_HPP_INCLUDED 21 | -------------------------------------------------------------------------------- /game_engine/src/config.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CONFIG_HPP_INCLUDED 4 | #define CONFIG_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | 9 | class Config 10 | { 11 | public: 12 | struct Entry 13 | { 14 | std::string key; 15 | std::string value; 16 | 17 | Entry(std::string key, std::string value) { this->key = key; this->value = value; } 18 | }; 19 | 20 | private: 21 | static bool initialized_; 22 | 23 | public: 24 | static std::vector entries; 25 | 26 | Config(); 27 | Config(std::string filename); 28 | void Load(std::string filename); 29 | void Save(std::string filename); 30 | Entry GetEntry(std::string key); 31 | std::string GetValue(std::string key); 32 | void AddEntry(Entry); 33 | void AddEntry(std::string key, std::string value); 34 | }; 35 | 36 | #endif // CONFIG_HPP_INCLUDED 37 | -------------------------------------------------------------------------------- /server_engine/src/map_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "map_handler.hpp" 2 | 3 | #include 4 | 5 | bool MapHandler::initialized_ = false; 6 | std::map MapHandler::maps; 7 | 8 | MapHandler::MapHandler() 9 | { 10 | if(!this->initialized_) 11 | { 12 | this->initialized_ = true; 13 | } 14 | } 15 | 16 | Map *MapHandler::GetMap(unsigned int id) 17 | { 18 | for(auto &it: this->maps) 19 | { 20 | if(it.first == id) return &it.second; 21 | } 22 | 23 | std::cout << "Loading map" << std::endl; 24 | 25 | Map map(id); 26 | this->maps[id] = map; 27 | 28 | return &this->maps[id]; 29 | } 30 | 31 | void MapHandler::Clear() 32 | { 33 | this->maps.clear(); 34 | } 35 | 36 | void MapHandler::Reload() 37 | { 38 | for(auto &it: this->maps) 39 | { 40 | unsigned int id = it.first; 41 | 42 | it.second.Load(id); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /server_engine/src/handlers/h_character.hpp: -------------------------------------------------------------------------------- 1 | #ifndef H_CHARACTER_HPP_INCLUDED 2 | #define H_CHARACTER_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | namespace PacketHandlers::HCharacter 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr); 10 | void Create(sf::Packet &packet, std::array data_ptr); 11 | void Delete(sf::Packet &packet, std::array data_ptr); 12 | void List(sf::Packet &packet, std::array data_ptr); 13 | void Select(sf::Packet &packet, std::array data_ptr); 14 | 15 | void Talk(sf::Packet &packet, std::array data_ptr); 16 | void Face(sf::Packet &packet, std::array data_ptr); 17 | void Walk(sf::Packet &packet, std::array data_ptr); 18 | 19 | void GetInRange(sf::Packet packet, std::array data_ptr); 20 | }; 21 | 22 | #endif // H_CHARACTER_HPP_INCLUDED 23 | -------------------------------------------------------------------------------- /server_engine/src/npc.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef NPC_HPP_INCLUDED 4 | #define NPC_HPP_INCLUDED 5 | 6 | #include "const/entity.hpp" 7 | #include "animation.hpp" 8 | 9 | #include 10 | 11 | class NPC 12 | { 13 | public: 14 | enum class AnimState 15 | { 16 | Stand, 17 | Sit, 18 | Walk 19 | }; 20 | 21 | public: 22 | unsigned int id; 23 | unsigned int index; 24 | std::string name; 25 | unsigned int map_id; 26 | unsigned short x; 27 | unsigned short y; 28 | Direction direction; 29 | unsigned char speed; 30 | 31 | AnimState anim_state; 32 | Animation animation; 33 | 34 | int frame_counter; 35 | 36 | NPC(); 37 | NPC(unsigned int id, unsigned int index, unsigned int map_id, unsigned short x, unsigned short y); 38 | 39 | void Tick(); 40 | 41 | void Talk(std::string message); 42 | void Face(Direction direction); 43 | void Walk(Direction direction); 44 | }; 45 | 46 | #endif // NPC_HPP_INCLUDED 47 | -------------------------------------------------------------------------------- /server_engine/src/server.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef SERVER_HPP_INCLUDED 4 | #define SERVER_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "client.hpp" 11 | #include "config.hpp" 12 | 13 | // class responsible for managing clients and server-client data transfer (monostate) 14 | class Server 15 | { 16 | private: 17 | static bool initialized_; 18 | static sf::TcpListener listener; 19 | static std::vector> sockets; 20 | static std::vector> clients; 21 | static std::array client_version; 22 | 23 | 24 | public: 25 | static Config config; 26 | static Config welcome_msg; 27 | 28 | Server(); 29 | Server(unsigned short port); 30 | void Tick(); 31 | Client *GetClientByChar(std::string char_name); 32 | Client *GetClientByAcc(std::string acc_name); 33 | std::array GetClientVersion(); 34 | }; 35 | 36 | #endif // SERVER_HPP_INCLUDED 37 | -------------------------------------------------------------------------------- /game_engine/src/packet_handler.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef PACKET_HANDLER_HPP_INCLUDED 4 | #define PACKET_HANDLER_HPP_INCLUDED 5 | 6 | #include "const/packet.hpp" 7 | 8 | #include 9 | #include 10 | 11 | typedef std::function data_ptr)> HandlerFunction; 12 | 13 | class PacketHandler 14 | { 15 | public: 16 | struct Handler 17 | { 18 | PacketID packet_id; 19 | HandlerFunction func; 20 | std::array data_ptr; 21 | 22 | Handler(); 23 | Handler(PacketID packet_id, HandlerFunction func, std::array data_ptr); 24 | void Execute(sf::Packet &packet); 25 | }; 26 | 27 | public: 28 | std::map handlers; 29 | 30 | void Register(PacketID id, HandlerFunction func, std::array data_ptr); 31 | void Unregister(PacketID id); 32 | void Clear(); 33 | void Execute(sf::Packet &packet); 34 | }; 35 | 36 | #endif // PACKET_HANDLER_HPP_INCLUDED 37 | -------------------------------------------------------------------------------- /server_engine/src/packet_handler.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef PACKET_HANDLER_HPP_INCLUDED 4 | #define PACKET_HANDLER_HPP_INCLUDED 5 | 6 | #include "const/packet.hpp" 7 | 8 | #include 9 | #include 10 | 11 | typedef std::function data_ptr)> HandlerFunction; 12 | 13 | class PacketHandler 14 | { 15 | public: 16 | struct Handler 17 | { 18 | PacketID packet_id; 19 | HandlerFunction func; 20 | std::array data_ptr; 21 | 22 | Handler(); 23 | Handler(PacketID packet_id, HandlerFunction func, std::array data_ptr); 24 | void Execute(sf::Packet &packet); 25 | }; 26 | 27 | public: 28 | std::map handlers; 29 | 30 | void Register(PacketID id, HandlerFunction func, std::array data_ptr); 31 | void Unregister(PacketID id); 32 | void Clear(); 33 | void Execute(sf::Packet &packet); 34 | }; 35 | 36 | #endif // PACKET_HANDLER_HPP_INCLUDED 37 | -------------------------------------------------------------------------------- /game_engine/src/file_handler.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef FILE_HANDLER_HPP_INCLUDED 4 | #define FILE_HANDLER_HPP_INCLUDED 5 | 6 | #include 7 | 8 | class FileHandler 9 | { 10 | private: 11 | std::string filename; 12 | std::string data; 13 | bool exists; 14 | 15 | public: 16 | FileHandler() { this->filename = ""; this->data = ""; this->exists = false; } 17 | FileHandler(std::string filename); 18 | bool Load(std::string filename); 19 | void Save(); 20 | void Save(std::string filename); 21 | bool Exists() { return this->exists; } 22 | 23 | unsigned int GetNumber(std::size_t num_size); 24 | unsigned char GetChar(); 25 | unsigned short GetShort(); 26 | unsigned int GetThree(); 27 | unsigned int GetInt(); 28 | std::string GetString(); 29 | std::string GetData(); 30 | 31 | void AddChar(unsigned char char_); 32 | void AddShort(unsigned short num); 33 | void AddThree(unsigned int num); 34 | void AddInt(unsigned int num); 35 | void AddString(std::string str); 36 | }; 37 | 38 | #endif // FILE_HANDLER_HPP_INCLUDED 39 | -------------------------------------------------------------------------------- /server_engine/src/file_handler.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef FILE_HANDLER_HPP_INCLUDED 4 | #define FILE_HANDLER_HPP_INCLUDED 5 | 6 | #include 7 | 8 | class FileHandler 9 | { 10 | private: 11 | std::string filename; 12 | std::string data; 13 | bool exists; 14 | 15 | public: 16 | FileHandler() { this->filename = ""; this->data = ""; this->exists = false; } 17 | FileHandler(std::string filename); 18 | bool Load(std::string filename); 19 | void Save(); 20 | void Save(std::string filename); 21 | bool Exists() { return this->exists; } 22 | 23 | unsigned int GetNumber(std::size_t num_size); 24 | unsigned char GetChar(); 25 | unsigned short GetShort(); 26 | unsigned int GetThree(); 27 | unsigned int GetInt(); 28 | std::string GetString(); 29 | std::string GetData(); 30 | 31 | void AddChar(unsigned char char_); 32 | void AddShort(unsigned short num); 33 | void AddThree(unsigned int num); 34 | void AddInt(unsigned int num); 35 | void AddString(std::string str); 36 | }; 37 | 38 | #endif // FILE_HANDLER_HPP_INCLUDED 39 | -------------------------------------------------------------------------------- /game_engine/src/imgui_impl_a5.h: -------------------------------------------------------------------------------- 1 | // ImGui Allegro 5 bindings 2 | // In this binding, ImTextureID is used to store a 'ALLEGRO_BITMAP*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. 3 | 4 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 5 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 6 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. 7 | // https://github.com/ocornut/imgui 8 | // by @birthggd 9 | 10 | #pragma once 11 | 12 | struct ALLEGRO_DISPLAY; 13 | union ALLEGRO_EVENT; 14 | 15 | IMGUI_API bool ImGui_ImplA5_Init(ALLEGRO_DISPLAY* display); 16 | IMGUI_API void ImGui_ImplA5_Shutdown(); 17 | IMGUI_API void ImGui_ImplA5_NewFrame(); 18 | IMGUI_API bool ImGui_ImplA5_ProcessEvent(ALLEGRO_EVENT* event); 19 | 20 | // Use if you want to reset your rendering device without losing ImGui state. 21 | IMGUI_API bool Imgui_ImplA5_CreateDeviceObjects(); 22 | IMGUI_API void ImGui_ImplA5_InvalidateDeviceObjects(); 23 | -------------------------------------------------------------------------------- /game_engine/src/npc.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef NPC_HPP_INCLUDED 4 | #define NPC_HPP_INCLUDED 5 | 6 | #include "const/entity.hpp" 7 | #include "animation.hpp" 8 | 9 | #include 10 | 11 | class NPC 12 | { 13 | public: 14 | enum class AnimState 15 | { 16 | Stand, 17 | Sit, 18 | Walk 19 | }; 20 | 21 | public: 22 | unsigned int id; 23 | unsigned int index; 24 | std::string name; 25 | unsigned int map_id; 26 | unsigned short x; 27 | unsigned short y; 28 | Direction direction; 29 | unsigned char speed; 30 | 31 | AnimState anim_state; 32 | Animation animation; 33 | 34 | int screen_x; 35 | int screen_y; 36 | 37 | unsigned int frame_counter; 38 | 39 | NPC(); 40 | NPC(unsigned int id, unsigned int index, unsigned int map_id, unsigned short x, unsigned short y); 41 | 42 | void Tick(); 43 | void Render(int rx, int ry); 44 | 45 | std::vector GetScreenPos(); 46 | 47 | void Talk(std::string message); 48 | void Face(Direction direction); 49 | void Walk(Direction direction); 50 | }; 51 | 52 | #endif // NPC_HPP_INCLUDED 53 | -------------------------------------------------------------------------------- /game_engine/src/gfx_loader.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef GFX_LOADER_HPP_INCLUDED 4 | #define GFX_LOADER_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // to load and store graphics (monostate) 12 | class GFXLoader 13 | { 14 | public: 15 | class Directory 16 | { 17 | private: 18 | std::string path; 19 | unsigned int id; 20 | std::map bitmaps; 21 | 22 | public: 23 | Directory(std::string path, unsigned int id); 24 | ALLEGRO_BITMAP *GetBitmap(unsigned int id, bool mask = true, std::string format = ""); 25 | void Clear(); 26 | }; 27 | 28 | private: 29 | static bool initialized_; 30 | static std::map> directories; 31 | 32 | public: 33 | static std::string path; 34 | 35 | GFXLoader(); 36 | GFXLoader(std::string path); 37 | ALLEGRO_BITMAP *GetBitmap(unsigned int dir_id, unsigned int bmp_id, bool mask = true, std::string format = ""); 38 | void Clear(); 39 | }; 40 | 41 | #endif // GFX_LOADER_HPP_INCLUDED 42 | -------------------------------------------------------------------------------- /server_engine/src/character.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CHARACTER_HPP_INCLUDED 4 | #define CHARACTER_HPP_INCLUDED 5 | 6 | #include 7 | #include "const/entity.hpp" 8 | #include "npc.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class Character 16 | { 17 | public: 18 | enum class Action 19 | { 20 | Face, 21 | Walk 22 | }; 23 | 24 | public: 25 | std::string username; 26 | std::string name; 27 | unsigned int map_id; 28 | unsigned short x; 29 | unsigned short y; 30 | Direction direction; 31 | Gender gender; 32 | unsigned char speed; 33 | 34 | std::vector> chars_in_range; 35 | std::vector> npcs_in_range; 36 | 37 | std::map action_clocks; 38 | 39 | Character(); 40 | Character(std::string username, std::string name, unsigned int map_id, unsigned short x, unsigned short y); 41 | 42 | void Tick(); 43 | void Render(int rx, int ry); 44 | 45 | Character *GetInRange(std::string name); 46 | void DeleteInRange(std::string name); 47 | }; 48 | 49 | #endif // CHARACTER_HPP_INCLUDED 50 | -------------------------------------------------------------------------------- /server_engine/src/main.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "config.hpp" 4 | #include "server.hpp" 5 | #include "server_state.hpp" 6 | #include "database.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main() 14 | { 15 | try 16 | { 17 | Server server(8078); 18 | 19 | std::array version = server.GetClientVersion(); 20 | 21 | std::cout << "Endless Online Awaken Server v" << version[0] << "." << version[1] << "." << version[2] << std::endl 22 | << std::endl; 23 | 24 | ServerState server_state; 25 | Database database("data/eo.db"); 26 | 27 | while(server_state.Get() != ServerState::State::Exit) 28 | { 29 | server.Tick(); 30 | sf::Time time = sf::milliseconds(5); 31 | sf::sleep(time); 32 | } 33 | } 34 | catch(std::runtime_error rt_err) 35 | { 36 | std::cout << "Exception: " << rt_err.what() << std::endl; 37 | std::ofstream file("errorlog.txt", std::ios::trunc); 38 | if(file.is_open() && file.good()) 39 | { 40 | file << rt_err.what() << std::endl; 41 | file.close(); 42 | } 43 | } 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /game_engine/src/animation.cpp: -------------------------------------------------------------------------------- 1 | #include "animation.hpp" 2 | 3 | Animation::Animation() 4 | { 5 | this->current_frame = 0; 6 | this->frames.push_back(Frame(0)); 7 | this->play = false; 8 | this->delay_count = 0; 9 | this->replay = false; 10 | } 11 | 12 | void Animation::Tick() 13 | { 14 | if(this->play) 15 | { 16 | if(this->frames.size() == 0) 17 | { 18 | this->play = false; 19 | return; 20 | } 21 | 22 | this->delay_count++; 23 | 24 | if(this->delay_count >= this->frames[this->current_frame].delay) 25 | { 26 | this->delay_count = 0; 27 | this->current_frame++; 28 | 29 | if(this->current_frame >= this->frames.size()) 30 | { 31 | this->play = false; 32 | 33 | if(this->replay) 34 | { 35 | this->Play(); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | void Animation::Play() 43 | { 44 | this->current_frame = 0; 45 | this->play = true; 46 | } 47 | 48 | void Animation::Clear() 49 | { 50 | this->frames.clear(); 51 | this->current_frame = 0; 52 | this->play = false; 53 | this->delay_count = 0; 54 | this->replay = false; 55 | } 56 | -------------------------------------------------------------------------------- /game_engine/src/handlers/init.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "init.hpp" 4 | 5 | #include "ping.hpp" 6 | #include "login.hpp" 7 | #include "account.hpp" 8 | #include "../client.hpp" 9 | #include "../gui.hpp" 10 | 11 | #include 12 | 13 | namespace PacketHandlers::HInit 14 | { 15 | void Main(sf::Packet &packet, std::array data_ptr) 16 | { 17 | Client client; 18 | unsigned char answer = 0; 19 | 20 | if(client.state != Client::State::Uninitialized) return; 21 | 22 | packet >> answer; 23 | 24 | if(answer == 1) 25 | { 26 | client.packet_handler.Register(PacketID::Ping, PacketHandlers::HPing::Main, data_ptr); 27 | client.packet_handler.Register(PacketID::Login, PacketHandlers::HLogin::Main, data_ptr); 28 | client.packet_handler.Register(PacketID::Account, PacketHandlers::HAccount::Main, data_ptr); 29 | client.state = Client::State::Initialized; 30 | 31 | std::cout << "Initialized." << std::endl; 32 | } 33 | if(answer == 2) 34 | { 35 | std::string message = "This client is outdated. Please update it and connect again."; 36 | 37 | GUI().OpenPopup("Server answer", message); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /game_engine/src/character.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CHARACTER_HPP_INCLUDED 4 | #define CHARACTER_HPP_INCLUDED 5 | 6 | #include "const/entity.hpp" 7 | #include "animation.hpp" 8 | 9 | #include 10 | #include 11 | 12 | class Character 13 | { 14 | public: 15 | enum class AnimState 16 | { 17 | Stand, 18 | Sit, 19 | Walk, 20 | Attack 21 | }; 22 | 23 | enum class Action 24 | { 25 | Face, 26 | Walk 27 | }; 28 | 29 | public: 30 | std::string name; 31 | unsigned int map_id; 32 | unsigned short x; 33 | unsigned short y; 34 | Direction direction; 35 | Gender gender; 36 | unsigned char speed; 37 | 38 | AnimState anim_state; 39 | Animation animation; 40 | 41 | int screen_x; 42 | int screen_y; 43 | 44 | int frame_counter; 45 | 46 | Character(); 47 | Character(std::string name, unsigned int map_id, unsigned short x, unsigned short y); 48 | 49 | void Tick(); 50 | void Render(int rx, int ry); 51 | void RenderNew(int rx, int ry); 52 | 53 | std::vector GetScreenPos(); 54 | 55 | void Talk(unsigned char channel, std::string message, std::string char_name = ""); 56 | void Face(Direction direction); 57 | void Walk(Direction direction); 58 | }; 59 | 60 | #endif // CHARACTER_HPP_INCLUDED 61 | -------------------------------------------------------------------------------- /server_engine/src/handlers/file_data.cpp: -------------------------------------------------------------------------------- 1 | #include "file_data.hpp" 2 | 3 | #include "../file_handler.hpp" 4 | #include "../const/packet.hpp" 5 | #include "../client.hpp" 6 | 7 | #include 8 | 9 | namespace PacketHandlers::FileData 10 | { 11 | void Main(sf::Packet &packet, std::array data_ptr) 12 | { 13 | unsigned char type = 0; 14 | 15 | packet >> type; 16 | 17 | if(type == 1) 18 | { 19 | FileTransfer(packet, data_ptr); 20 | } 21 | } 22 | 23 | void FileTransfer(sf::Packet &packet, std::array data_ptr) 24 | { 25 | Client *client = (Client *)data_ptr[0]; 26 | unsigned int id = 0; 27 | 28 | packet >> id; 29 | 30 | std::string filename = "data/maps/" + std::to_string(id) + ".map"; 31 | 32 | FileHandler fh(filename); 33 | 34 | if(fh.Exists()) 35 | { 36 | std::string data = fh.GetData(); 37 | 38 | sf::Packet reply; 39 | 40 | reply << (unsigned char)PacketID::FileData; 41 | reply << (unsigned char)1; 42 | reply << (unsigned char)1; 43 | 44 | client->Send(reply); 45 | 46 | client->transfer_data = fh.GetData(); 47 | client->transfer_id = id; 48 | client->transfer_clock.restart(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /game_engine/imgui.ini: -------------------------------------------------------------------------------- 1 | [Debug] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | [ImGui Demo] 7 | Pos=20,10 8 | Size=550,680 9 | Collapsed=0 10 | 11 | [Map editor] 12 | Pos=102,72 13 | Size=463,364 14 | Collapsed=0 15 | 16 | [Debug##Default] 17 | Pos=78,155 18 | Size=400,400 19 | Collapsed=0 20 | 21 | [Example: Console] 22 | Pos=20,10 23 | Size=520,600 24 | Collapsed=0 25 | 26 | [Example: Layout] 27 | Pos=20,10 28 | Size=500,440 29 | Collapsed=0 30 | 31 | [Example: Property editor] 32 | Pos=20,10 33 | Size=430,450 34 | Collapsed=0 35 | 36 | [Example: Custom rendering] 37 | Pos=20,10 38 | Size=350,560 39 | Collapsed=0 40 | 41 | [Style Editor] 42 | Pos=20,10 43 | Size=344,316 44 | Collapsed=0 45 | 46 | [Main menu] 47 | Pos=20,200 48 | Size=121,123 49 | Collapsed=0 50 | 51 | [Create Account] 52 | Pos=220,200 53 | Size=325,192 54 | Collapsed=0 55 | 56 | [Login] 57 | Pos=200,193 58 | Size=283,100 59 | Collapsed=0 60 | 61 | [Credits] 62 | Pos=190,197 63 | Size=78,122 64 | Collapsed=0 65 | 66 | [Character list] 67 | Pos=463,43 68 | Size=122,262 69 | Collapsed=0 70 | 71 | [Create account] 72 | Pos=160,134 73 | Size=325,215 74 | Collapsed=0 75 | 76 | [Create character] 77 | Pos=178,165 78 | Size=255,139 79 | Collapsed=0 80 | 81 | [Game Screen] 82 | Pos=0,0 83 | Size=640,480 84 | Collapsed=0 85 | 86 | [Chat] 87 | Pos=102,330 88 | Size=482,118 89 | Collapsed=0 90 | 91 | [Game Panel] 92 | Pos=10,308 93 | Size=620,162 94 | Collapsed=0 95 | 96 | -------------------------------------------------------------------------------- /game_engine/src/handlers/account.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "account.hpp" 4 | 5 | #include "../client.hpp" 6 | #include "../gui.hpp" 7 | 8 | #include 9 | #include 10 | #include "../imgui_impl_a5.h" 11 | 12 | namespace PacketHandlers::HAccount 13 | { 14 | 15 | void Main(sf::Packet &packet, std::array data_ptr) 16 | { 17 | unsigned char sub_id = 0; 18 | 19 | packet >> sub_id; 20 | 21 | if(sub_id == 1) // create account reply 22 | { 23 | Create(packet, data_ptr); 24 | } 25 | if(sub_id == 2) // delete account reply 26 | { 27 | Delete(packet, data_ptr); 28 | } 29 | } 30 | 31 | void Create(sf::Packet &packet, std::array data_ptr) 32 | { 33 | GUI gui; 34 | unsigned char answer = 0; 35 | std::string message; 36 | 37 | packet >> answer; 38 | packet >> message; 39 | 40 | if(answer == 1) 41 | { 42 | std::cout << "Account created!" << std::endl; 43 | 44 | gui.SetState(GUI::State::MainMenu); 45 | gui.OpenPopup("Account created"); 46 | } 47 | if(answer == 0) 48 | { 49 | gui.OpenPopup("Server answer", message); 50 | } 51 | } 52 | 53 | void Delete(sf::Packet &packet, std::array data_ptr) 54 | { 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /game_engine/src/util.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef UTIL_HPP_INCLUDED 4 | #define UTIL_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static const unsigned int MAX1 = 253; 12 | static const unsigned int MAX2 = 64009; 13 | static const unsigned int MAX3 = 16194277; 14 | 15 | inline static std::vector GetArgs(std::string str) 16 | { 17 | std::vector args; 18 | std::string word; 19 | for(std::size_t i = 0; i < str.length(); ++i) 20 | { 21 | if((str[i] == ' ' || i == str.length() - 1)) 22 | { 23 | if(str[i] != ' ') word += str[i]; 24 | if(!word.empty()) args.push_back(word); 25 | word.clear(); 26 | } 27 | else if(str[i] != ' ') 28 | { 29 | word += str[i]; 30 | } 31 | } 32 | 33 | return args; 34 | } 35 | 36 | unsigned int DecodeNumber(unsigned char, unsigned char = 254, unsigned char = 254, unsigned char = 254); 37 | std::array EncodeNumber(unsigned int); 38 | std::array EncodeNumber(unsigned int, std::size_t &size); 39 | 40 | class RandGen 41 | { 42 | private: 43 | static bool initialized_; 44 | static unsigned int seed; 45 | static std::mt19937 gen; 46 | 47 | public: 48 | RandGen(); 49 | int RandInt(int imin, int imax); 50 | }; 51 | 52 | #endif // UTIL_HPP_INCLUDED 53 | -------------------------------------------------------------------------------- /server_engine/src/client.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CLIENT_HPP_INCLUDED 4 | #define CLIENT_HPP_INCLUDED 5 | 6 | #include "packet_handler.hpp" 7 | #include "character.hpp" 8 | 9 | #include 10 | #include 11 | 12 | // for managing client's connection and data transfer 13 | class Client 14 | { 15 | public: 16 | enum class State 17 | { 18 | Uninitialized, 19 | Initialized, 20 | Logged_in, 21 | Playing 22 | }; 23 | 24 | private: 25 | bool connected; 26 | std::vector recv_queue; 27 | std::vector send_queue; 28 | 29 | public: 30 | State state; 31 | std::shared_ptr socket; 32 | PacketHandler packet_handler; 33 | 34 | std::string username; 35 | std::vector> characters; 36 | std::string selected_character; 37 | unsigned short map_id; 38 | 39 | std::string transfer_data; 40 | unsigned int transfer_id; 41 | sf::Clock transfer_clock; 42 | 43 | std::vector> action_queue; 44 | sf::Clock action_clock; 45 | sf::Clock ping_clock; 46 | int latency; 47 | 48 | Client(); 49 | void Tick(); 50 | bool Connected(); 51 | void Send(sf::Packet packet); 52 | sf::Packet Recv(); 53 | 54 | Character *GetCharacter(std::string name); 55 | void RemoveCharacter(std::string name); 56 | }; 57 | 58 | #endif // CLIENT_HPP_INCLUDED 59 | -------------------------------------------------------------------------------- /server_engine/src/util.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef UTIL_HPP_INCLUDED 4 | #define UTIL_HPP_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static const unsigned int MAX1 = 253; 12 | static const unsigned int MAX2 = 64009; 13 | static const unsigned int MAX3 = 16194277; 14 | 15 | inline static std::vector GetArgs(std::string str) 16 | { 17 | std::vector args; 18 | std::string word; 19 | for(std::size_t i = 0; i < str.length(); ++i) 20 | { 21 | if((str[i] == ' ' || i == str.length() - 1)) 22 | { 23 | if(str[i] != ' ') word += str[i]; 24 | if(!word.empty()) args.push_back(word); 25 | word.clear(); 26 | } 27 | else if(str[i] != ' ') 28 | { 29 | word += str[i]; 30 | } 31 | } 32 | 33 | return args; 34 | } 35 | 36 | unsigned int DecodeNumber(unsigned char, unsigned char = 254, unsigned char = 254, unsigned char = 254); 37 | std::array EncodeNumber(unsigned int); 38 | std::array EncodeNumber(unsigned int, std::size_t &size); 39 | 40 | class RandGen 41 | { 42 | private: 43 | static bool initialized_; 44 | static unsigned int seed; 45 | static std::mt19937 gen; 46 | 47 | public: 48 | RandGen(); 49 | int RandInt(int imin, int imax); 50 | }; 51 | 52 | int path_length(int x1, int y1, int x2, int y2); 53 | 54 | #endif // UTIL_HPP_INCLUDED 55 | -------------------------------------------------------------------------------- /server_engine/src/handlers/init.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "init.hpp" 4 | 5 | #include "ping.hpp" 6 | #include "login.hpp" 7 | #include "account.hpp" 8 | #include "../client.hpp" 9 | #include "../server.hpp" 10 | 11 | #include 12 | #include 13 | 14 | namespace PacketHandlers::HInit 15 | { 16 | 17 | void Main(sf::Packet &packet, std::array data_ptr) 18 | { 19 | Client *client = (Client *)data_ptr[0]; 20 | 21 | if(client->state != Client::State::Uninitialized) return; 22 | 23 | std::array version = { 0, 0, 0 }; 24 | 25 | for(int i = 0; i < 3; ++i) 26 | { 27 | packet >> version[i]; 28 | } 29 | 30 | bool valid = true; 31 | 32 | for(int i = 0; i < 3; ++i) 33 | { 34 | if(version[i] != Server().GetClientVersion()[i]) valid = false; 35 | } 36 | 37 | unsigned char answer = 0; 38 | 39 | if(valid) 40 | { 41 | answer = 1; 42 | 43 | client->state = Client::State::Initialized; 44 | client->packet_handler.Register(PacketID::Ping, PacketHandlers::HPing::Main, data_ptr); 45 | client->packet_handler.Register(PacketID::Login, PacketHandlers::HLogin::Main, data_ptr); 46 | client->packet_handler.Register(PacketID::Account, PacketHandlers::HAccount::Main, data_ptr); 47 | } 48 | else 49 | { 50 | answer = 2; 51 | } 52 | 53 | sf::Packet reply; 54 | reply << (unsigned char)PacketID::Init; 55 | reply << answer; 56 | client->Send(reply); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /game_engine/src/packet_handler.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "packet_handler.hpp" 4 | 5 | PacketHandler::Handler::Handler() 6 | { 7 | this->packet_id = PacketID::Init; 8 | this->func = NULL; 9 | } 10 | 11 | PacketHandler::Handler::Handler(PacketID packet_id, HandlerFunction func, std::array data_ptr) 12 | { 13 | this->packet_id = packet_id; 14 | this->func = func; 15 | this->data_ptr = data_ptr; 16 | } 17 | 18 | void PacketHandler::Handler::Execute(sf::Packet &packet) 19 | { 20 | if(this->func != NULL) this->func(packet, this->data_ptr); 21 | else throw std::runtime_error("Network: Unknown data packet detected."); 22 | } 23 | 24 | void PacketHandler::Register(PacketID id, HandlerFunction func, std::array data_ptr) 25 | { 26 | Handler handler(id, func, data_ptr); 27 | this->handlers.insert(std::pair(id, handler)); 28 | } 29 | 30 | void PacketHandler::Unregister(PacketID id) 31 | { 32 | auto it = this->handlers.find(id); 33 | 34 | if(it != this->handlers.end()) 35 | { 36 | this->handlers.erase(it); 37 | } 38 | } 39 | 40 | void PacketHandler::Clear() 41 | { 42 | this->handlers.clear(); 43 | } 44 | 45 | void PacketHandler::Execute(sf::Packet &packet) 46 | { 47 | unsigned char id; 48 | PacketID packet_id; 49 | 50 | packet >> id; 51 | packet_id = static_cast(id); 52 | 53 | auto it = this->handlers.find(packet_id); 54 | if(it != this->handlers.end()) 55 | { 56 | this->handlers[packet_id].Execute(packet); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /server_engine/src/packet_handler.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "packet_handler.hpp" 4 | 5 | PacketHandler::Handler::Handler() 6 | { 7 | this->packet_id = PacketID::Init; 8 | this->func = NULL; 9 | } 10 | 11 | PacketHandler::Handler::Handler(PacketID packet_id, HandlerFunction func, std::array data_ptr) 12 | { 13 | this->packet_id = packet_id; 14 | this->func = func; 15 | this->data_ptr = data_ptr; 16 | } 17 | 18 | void PacketHandler::Handler::Execute(sf::Packet &packet) 19 | { 20 | if(this->func != NULL) this->func(packet, this->data_ptr); 21 | else throw std::runtime_error("Network: Unknown data packet detected."); 22 | } 23 | 24 | void PacketHandler::Register(PacketID id, HandlerFunction func, std::array data_ptr) 25 | { 26 | Handler handler(id, func, data_ptr); 27 | this->handlers.insert(std::pair(id, handler)); 28 | } 29 | 30 | void PacketHandler::Unregister(PacketID id) 31 | { 32 | auto it = this->handlers.find(id); 33 | 34 | if(it != this->handlers.end()) 35 | { 36 | this->handlers.erase(it); 37 | } 38 | } 39 | 40 | void PacketHandler::Clear() 41 | { 42 | this->handlers.clear(); 43 | } 44 | 45 | void PacketHandler::Execute(sf::Packet &packet) 46 | { 47 | unsigned char id; 48 | PacketID packet_id; 49 | 50 | packet >> id; 51 | packet_id = static_cast(id); 52 | 53 | auto it = this->handlers.find(packet_id); 54 | if(it != this->handlers.end()) 55 | { 56 | this->handlers[packet_id].Execute(packet); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /server_engine/src/database.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "database.hpp" 4 | #include 5 | 6 | bool Database::initialized_ = false;; 7 | sqlite3 *Database::db; 8 | 9 | Database::Database() 10 | { 11 | if(!this->initialized_) 12 | { 13 | this->db = 0; 14 | 15 | this->initialized_ = true; 16 | } 17 | } 18 | 19 | Database::Database(std::string name) 20 | { 21 | if(!this->initialized_) 22 | { 23 | this->initialized_ = true; 24 | } 25 | 26 | this->Load(name); 27 | } 28 | 29 | void Database::Load(std::string name) 30 | { 31 | int rc = sqlite3_open(name.c_str(), &this->db); 32 | 33 | if(rc) 34 | { 35 | std::string sqlite_msg = sqlite3_errmsg(this->db); 36 | throw std::runtime_error("Can't open database: " + sqlite_msg + '\n'); 37 | } 38 | else 39 | { 40 | std::cout << "Database opened." << std::endl; 41 | } 42 | } 43 | 44 | void Database::Close() 45 | { 46 | sqlite3_close(this->db); 47 | } 48 | 49 | sqlite3 *Database::Get() 50 | { 51 | return db; 52 | } 53 | 54 | int Database::Execute(const char *sql, sqlite_callback callback, void *data) 55 | { 56 | char *error_msg = 0; 57 | 58 | if(!this->db) 59 | { 60 | std::cout << "Error: no connection with database." << std::endl; 61 | return 0; 62 | } 63 | 64 | int ret = sqlite3_exec(this->db, sql, callback, data, &error_msg); 65 | 66 | if(ret != SQLITE_OK) 67 | { 68 | std::cout << "Error: " << error_msg << std::endl; 69 | //throw std::runtime_error(error_msg + '\n'); 70 | } 71 | 72 | return ret; 73 | } 74 | -------------------------------------------------------------------------------- /game_engine/src/gui.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef GUI_HPP_INCLUDED 4 | #define GUI_HPP_INCLUDED 5 | 6 | #include "gfx_loader.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // to put all gui forms together and process it / render (monostate) 13 | class GUI 14 | { 15 | public: 16 | enum class State 17 | { 18 | MainMenu, 19 | Editor, 20 | CreateAccount, 21 | Credits, 22 | CharacterList, 23 | CreateCharacter, 24 | Playing 25 | }; 26 | 27 | private: 28 | static bool initialized_; 29 | static State state; 30 | static unsigned int bg; 31 | static std::string open_popup; 32 | static std::string popup_message; 33 | static int input_focus; 34 | static bool clear_gfx; 35 | 36 | public: 37 | GUI(); 38 | void Process(); 39 | void Render(); 40 | void SetState(State state); 41 | State GetState(); 42 | void OpenPopup(std::string id, std::string message = ""); 43 | void SetFocus(int widget); 44 | 45 | unsigned int BackgroundID() { return this->bg; } 46 | void MainMenu(); 47 | void CreateAccount(); 48 | void Login(bool *p_open); 49 | void Credits(); 50 | void CharacterList(); 51 | void CreateCharacter(); 52 | void Playing(); 53 | void ChatBox(); 54 | }; 55 | 56 | class Chat 57 | { 58 | private: 59 | static bool initialized_; 60 | 61 | public: 62 | static std::vector> messages; 63 | static bool new_message; 64 | 65 | Chat(); 66 | void AddMessage(std::string char_name, std::string message); 67 | }; 68 | 69 | #endif // GUI_HPP_INCLUDED 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Endless-Online-Awaken 2 | Endless Online Awaken is an open source client/server for Endless Online. It is intended to support all features of the original Endless Online v28 and many things more. 3 | 4 | Please visit this website for more information: http://eoawaken.co.nf/ 5 | 6 | ### Current version: 0.0.1 pre-alpha 7 | 8 | Please see changelog.txt for more information about updates. 9 | 10 | 11 | # Setup guide 12 | ## Client build requirements: 13 | * MinGW 6.1+ (https://sourceforge.net/projects/mingw/files/Installer/) 14 | 15 | * Allegro 5.2.3.0 16 | 17 | * SFML 2.4.2 Network and System modules. 18 | 19 | ## Server build requirements: 20 | * MinGW 6.1+ (https://sourceforge.net/projects/mingw/files/Installer/) 21 | 22 | * SFML 2.4.2 Network and System modules. 23 | 24 | 25 | * Project files for Code::Blocks coming soon :) 26 | 27 | ## How to run client: 28 | ``` 29 | To run the game client you need to put decompressed EO graphics in client_engine/data/gfx/ folder. You also need to create config.ini in client_engine/data/ folder; config-example.ini may be helpful for that. 30 | ``` 31 | ## How to run server: 32 | ``` 33 | In order to run the game server you need to create config.ini. There's also config-example.ini for the game server. 34 | You need to create new SQLite3 database. (example database: server_engine/data/eo.db). 35 | ``` 36 | 37 | ### Have fun! 38 | 39 | Please see https://www.patreon.com/Jimmyee for additional information about what's going on. Also, there you have an opportunity to donate this project (become a Patron) if you are willing to :) 40 | 41 | 42 | This project is released under MIT licence. See LICENCE file for more info. 43 | 44 | Copyright © Karol Woszczek. 45 | -------------------------------------------------------------------------------- /server_engine/src/character.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "character.hpp" 4 | 5 | #include 6 | 7 | Character::Character() 8 | { 9 | this->username = ""; 10 | this->name = ""; 11 | this->map_id = 0; 12 | this->x = 0; 13 | this->y = 0; 14 | this->direction = static_cast(0); 15 | this->gender = static_cast(0); 16 | this->speed = 1; 17 | 18 | for(int i = 0; i <= (int)Action::Walk; ++i) 19 | { 20 | this->action_clocks[(Action)i].restart(); 21 | } 22 | } 23 | 24 | Character::Character(std::string username, std::string name, unsigned int map_id, unsigned short x, unsigned short y) 25 | { 26 | this->username = username; 27 | this->name = name; 28 | this->map_id = map_id; 29 | this->x = x; 30 | this->y = y; 31 | this->direction = static_cast(0); 32 | this->gender = static_cast(0); 33 | this->speed = 1; 34 | 35 | for(int i = 0; i <= (int)Action::Walk; ++i) 36 | { 37 | this->action_clocks[(Action)i].restart(); 38 | } 39 | } 40 | 41 | void Character::Tick() 42 | { 43 | 44 | } 45 | 46 | void Character::Render(int rx, int ry) 47 | { 48 | 49 | } 50 | 51 | Character *Character::GetInRange(std::string name) 52 | { 53 | for(auto &it : this->chars_in_range) 54 | { 55 | if(it->name == name) return it.get(); 56 | } 57 | 58 | return 0; 59 | } 60 | 61 | void Character::DeleteInRange(std::string name) 62 | { 63 | for(std::size_t i = 0; i < this->chars_in_range.size(); ++i) 64 | { 65 | if(this->chars_in_range[i]->name == name) this->chars_in_range.erase(this->chars_in_range.begin() + i); 66 | return; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /game_engine/src/handlers/file_data.cpp: -------------------------------------------------------------------------------- 1 | #include "file_data.hpp" 2 | 3 | #include "../map.hpp" 4 | 5 | #include 6 | #include 7 | 8 | static std::string file_data = ""; 9 | 10 | namespace PacketHandlers::FileData 11 | { 12 | void Main(sf::Packet &packet, std::array data_ptr) 13 | { 14 | unsigned char type = 0; 15 | 16 | packet >> type; 17 | 18 | if(type == 1) 19 | { 20 | FileTransfer(packet, data_ptr); 21 | } 22 | } 23 | 24 | void FileTransfer(sf::Packet &packet, std::array data_ptr) 25 | { 26 | unsigned char phase = 0; 27 | 28 | packet >> phase; 29 | 30 | if(phase == 1) 31 | { 32 | file_data = ""; 33 | } 34 | if(phase == 2) 35 | { 36 | std::size_t psize = packet.getDataSize(); 37 | 38 | char data_block[psize] = ""; 39 | packet >> data_block; 40 | 41 | file_data += data_block; 42 | } 43 | if(phase == 3) 44 | { 45 | unsigned int id = 0; 46 | 47 | packet >> id; 48 | 49 | std::string filename = "data/maps/"; 50 | filename += std::to_string(id) + ".map"; 51 | 52 | std::ofstream file(filename, std::ios::trunc); 53 | if(!file.is_open()) 54 | { 55 | throw std::runtime_error("Map: could not open file."); 56 | } 57 | else if(!file.good()) 58 | { 59 | throw std::runtime_error("Map: data stream error."); 60 | } 61 | 62 | const char *cdata = file_data.c_str(); 63 | file.write(cdata, (unsigned)strlen(cdata)); 64 | file.close(); 65 | 66 | file_data = ""; 67 | 68 | Map map; 69 | 70 | std::vector> characters = map.characters; 71 | map.Load(id); 72 | map.characters = characters; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /game_engine/src/client.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef CLIENT_HPP_INCLUDED 4 | #define CLIENT_HPP_INCLUDED 5 | 6 | #include "packet_handler.hpp" 7 | #include "const/entity.hpp" 8 | #include "character.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // for managing client's connection and data transfer (monostate) 15 | class Client 16 | { 17 | public: 18 | enum class State 19 | { 20 | Uninitialized, 21 | Initialized, 22 | Logged_in, 23 | Playing 24 | }; 25 | 26 | private: 27 | static bool initialized_; 28 | static bool connected; 29 | static std::vector recv_queue; 30 | static std::vector send_queue; 31 | 32 | public: 33 | static std::unique_ptr socket; 34 | static PacketHandler packet_handler; 35 | static State state; 36 | 37 | static std::vector> characters; // account characters 38 | static Character *character; 39 | 40 | static std::array version; 41 | 42 | Client(); 43 | bool Connect(std::string address, unsigned short port); 44 | void Disconnect(); 45 | void Tick(); 46 | bool Connected(); 47 | void Send(sf::Packet &packet); 48 | sf::Packet Recv(); 49 | 50 | Character *GetCharacter(std::string name); 51 | void RemoveCharacter(std::string name); 52 | 53 | void Init(); 54 | void Login(std::string username, std::string password); 55 | void CreateAccount(std::array input_data); 56 | void CreateCharacter(std::string name, Gender gender); 57 | void DeleteCharacter(std::string name); 58 | void CharacterList(); 59 | void SelectCharacter(std::string name); 60 | void Talk(unsigned char channel, std::string message, std::string char_name = ""); 61 | void Face(Direction direction); 62 | void Walk(Direction direction); 63 | void GetInRange(std::string name); 64 | void GetInRange(unsigned int index); 65 | }; 66 | 67 | #endif // CLIENT_HPP_INCLUDED 68 | -------------------------------------------------------------------------------- /game_engine/src/handlers/login.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "login.hpp" 4 | 5 | #include "h_character.hpp" 6 | #include "../client.hpp" 7 | #include "../gui.hpp" 8 | #include "../map.hpp" 9 | #include "../character.hpp" 10 | 11 | #include 12 | 13 | namespace PacketHandlers::HLogin 14 | { 15 | void Main(sf::Packet &packet, std::array data_ptr) 16 | { 17 | Client client; 18 | unsigned char sub_id = 0; 19 | unsigned char answer = 0; 20 | std::string message = ""; 21 | 22 | packet >> sub_id; 23 | packet >> answer; 24 | 25 | 26 | if(sub_id == 1) 27 | { 28 | // reply for login request 29 | packet >> message; 30 | 31 | if(answer) 32 | { 33 | Client client; 34 | client.state = Client::State::Logged_in; 35 | client.packet_handler.Register(PacketID::Character, PacketHandlers::HCharacter::Main, data_ptr); 36 | GUI().SetState(GUI::State::CharacterList); 37 | 38 | std::size_t characters = 0; 39 | packet >> characters; 40 | 41 | for(std::size_t i = 0; i < characters; ++i) 42 | { 43 | std::string name = ""; 44 | unsigned char gender = 0; 45 | 46 | packet >> name; 47 | packet >> gender; 48 | 49 | std::shared_ptr character = std::shared_ptr(new Character()); 50 | character->name = name; 51 | character->gender = (Gender)gender; 52 | 53 | client.characters.push_back(character); 54 | } 55 | } 56 | else 57 | { 58 | GUI().OpenPopup("Server answer", message); 59 | } 60 | 61 | std::cout << message << std::endl; 62 | } 63 | if(sub_id == 2) 64 | { 65 | // reply for character selection 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /game_engine/src/util.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "util.hpp" 4 | 5 | bool RandGen::initialized_; 6 | unsigned int RandGen::seed; 7 | std::mt19937 RandGen::gen; 8 | 9 | unsigned int DecodeNumber(unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4) 10 | { 11 | if (b1 == 254) b1 = 1; 12 | if (b2 == 254) b2 = 1; 13 | if (b3 == 254) b3 = 1; 14 | if (b4 == 254) b4 = 1; 15 | 16 | if (b1 == 0) b1 = 128; 17 | if (b2 == 0) b2 = 128; 18 | if (b3 == 0) b3 = 128; 19 | if (b4 == 0) b4 = 128; 20 | 21 | --b1; 22 | --b2; 23 | --b3; 24 | --b4; 25 | 26 | return (b4*MAX3 + b3*MAX2 + b2*MAX1 + b1); 27 | } 28 | 29 | std::array EncodeNumber(unsigned int number) 30 | { 31 | std::size_t throwaway; 32 | 33 | return EncodeNumber(number, throwaway); 34 | } 35 | 36 | std::array EncodeNumber(unsigned int number, std::size_t &size) 37 | { 38 | std::array bytes { 254, 254, 254, 254 }; 39 | unsigned int onumber = number; 40 | 41 | if (onumber >= MAX3) 42 | { 43 | bytes[3] = number / MAX3 + 1; 44 | number = number % MAX3; 45 | } 46 | 47 | if (onumber >= MAX2) 48 | { 49 | bytes[2] = number / MAX2 + 1; 50 | number = number % MAX2; 51 | } 52 | 53 | if (onumber >= MAX1) 54 | { 55 | bytes[1] = number / MAX1 + 1; 56 | number = number % MAX1; 57 | } 58 | 59 | bytes[0] = number + 1; 60 | 61 | for (int i = 3; i >= 0; --i) 62 | { 63 | if (i == 0) 64 | { 65 | size = 1; 66 | break; 67 | } 68 | else if (bytes[i] > 0) 69 | { 70 | size = i + 1; 71 | break; 72 | } 73 | } 74 | 75 | return bytes; 76 | } 77 | 78 | RandGen::RandGen() 79 | { 80 | if(!this->initialized_) 81 | { 82 | this->seed = std::chrono::system_clock::now().time_since_epoch().count(); 83 | this->gen = std::mt19937(seed); 84 | 85 | this->initialized_ = true; 86 | } 87 | } 88 | 89 | int RandGen::RandInt(int imin, int imax) 90 | { 91 | std::uniform_int_distribution<> uniform_dist(imin, imax); 92 | int rand_num = uniform_dist(this->gen); 93 | 94 | return rand_num; 95 | } 96 | -------------------------------------------------------------------------------- /server_engine/src/handlers/h_npc.cpp: -------------------------------------------------------------------------------- 1 | #include "h_npc.hpp" 2 | 3 | #include "../client.hpp" 4 | #include "../map.hpp" 5 | #include "../map_handler.hpp" 6 | 7 | namespace PacketHandlers::HNPC 8 | { 9 | void Main(sf::Packet &packet, std::array data_ptr) 10 | { 11 | unsigned char sub_id = 0; 12 | packet >> sub_id; 13 | 14 | if(sub_id == 1) // npc list 15 | { 16 | List(packet, data_ptr); 17 | } 18 | if(sub_id == 2) // get npc in range by id 19 | { 20 | GetInRange(packet, data_ptr); 21 | } 22 | } 23 | 24 | void List(sf::Packet &packet, std::array data_ptr) 25 | { 26 | Client *client = (Client*)data_ptr[0]; 27 | Map *map = MapHandler().GetMap(client->map_id); 28 | 29 | sf::Packet reply; 30 | 31 | reply << (unsigned char)PacketID::NPC; 32 | reply << (unsigned char)1; // npc list 33 | reply << map->npcs.size(); 34 | for(auto &npc : map->npcs) 35 | { 36 | reply << npc->id; 37 | reply << npc->index; 38 | reply << npc->map_id; 39 | reply << npc->x; 40 | reply << npc->y; 41 | reply << (unsigned char)npc->direction; 42 | reply << npc->speed; 43 | } 44 | 45 | client->Send(reply); 46 | } 47 | 48 | void GetInRange(sf::Packet packet, std::array data_ptr) 49 | { 50 | Client *client = (Client*)data_ptr[0]; 51 | unsigned int index = 0; 52 | 53 | packet >> index; 54 | 55 | Map *map = MapHandler().GetMap(client->map_id); 56 | NPC *npc = map->GetNPC(index); 57 | 58 | if(npc == 0) return; 59 | 60 | sf::Packet reply; 61 | 62 | reply << (unsigned char)PacketID::Map; 63 | reply << (unsigned char)1; // appear 64 | reply << (unsigned char)2; // npc 65 | reply << npc->id; 66 | reply << npc->index; 67 | reply << npc->map_id; 68 | reply << npc->x; 69 | reply << npc->y; 70 | reply << (unsigned char)npc->direction; 71 | reply << npc->speed; 72 | 73 | client->Send(reply); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /game_engine/src/gfx_loader.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "gfx_loader.hpp" 4 | 5 | #include 6 | 7 | bool GFXLoader::initialized_ = false; 8 | std::map> GFXLoader::directories; 9 | std::string GFXLoader::path; 10 | 11 | GFXLoader::GFXLoader() 12 | { 13 | if(!this->initialized_) 14 | { 15 | this->path = ""; 16 | 17 | this->initialized_ = true; 18 | } 19 | } 20 | 21 | GFXLoader::GFXLoader(std::string path) 22 | { 23 | this->path = path; 24 | 25 | if(!this->initialized_) 26 | { 27 | this->initialized_ = true; 28 | } 29 | } 30 | 31 | GFXLoader::Directory::Directory(std::string path, unsigned int id) 32 | { 33 | this->path = path; 34 | this->id = id; 35 | } 36 | 37 | ALLEGRO_BITMAP *GFXLoader::Directory::GetBitmap(unsigned int id, bool mask, std::string format) 38 | { 39 | if(this->bitmaps.find(id) == this->bitmaps.end()) 40 | { 41 | if(format == "") format = ".bmp"; 42 | std::string filename = path + "/" + std::to_string(this->id) + "/" + std::to_string(id + 100) + format; 43 | this->bitmaps[id] = al_load_bitmap(filename.c_str()); 44 | 45 | if(!this->bitmaps[id]) 46 | { 47 | return NULL; 48 | //throw std::runtime_error("Can't load " + filename); 49 | } 50 | else 51 | { 52 | if(mask) 53 | { 54 | al_convert_mask_to_alpha(this->bitmaps[id], al_map_rgb(0, 0, 0)); 55 | } 56 | } 57 | } 58 | 59 | return this->bitmaps[id]; 60 | } 61 | 62 | void GFXLoader::Directory::Clear() 63 | { 64 | for(auto &it : this->bitmaps) 65 | { 66 | al_destroy_bitmap(it.second); 67 | } 68 | 69 | this->bitmaps.clear(); 70 | } 71 | 72 | ALLEGRO_BITMAP *GFXLoader::GetBitmap(unsigned int dir_id, unsigned int bmp_id, bool mask, std::string format) 73 | { 74 | if(this->directories.find(dir_id) == this->directories.end()) 75 | { 76 | this->directories[dir_id] = std::make_unique(this->path, dir_id); 77 | } 78 | 79 | return this->directories[dir_id]->GetBitmap(bmp_id, mask, format); 80 | } 81 | 82 | void GFXLoader::Clear() 83 | { 84 | for(auto &it : this->directories) 85 | { 86 | it.second->Clear(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /server_engine/src/util.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "util.hpp" 4 | 5 | #include 6 | 7 | bool RandGen::initialized_ = false; 8 | unsigned int RandGen::seed; 9 | std::mt19937 RandGen::gen; 10 | 11 | unsigned int DecodeNumber(unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4) 12 | { 13 | if (b1 == 254) b1 = 1; 14 | if (b2 == 254) b2 = 1; 15 | if (b3 == 254) b3 = 1; 16 | if (b4 == 254) b4 = 1; 17 | 18 | if (b1 == 0) b1 = 128; 19 | if (b2 == 0) b2 = 128; 20 | if (b3 == 0) b3 = 128; 21 | if (b4 == 0) b4 = 128; 22 | 23 | --b1; 24 | --b2; 25 | --b3; 26 | --b4; 27 | 28 | return (b4*MAX3 + b3*MAX2 + b2*MAX1 + b1); 29 | } 30 | 31 | std::array EncodeNumber(unsigned int number) 32 | { 33 | std::size_t throwaway; 34 | 35 | return EncodeNumber(number, throwaway); 36 | } 37 | 38 | std::array EncodeNumber(unsigned int number, std::size_t &size) 39 | { 40 | std::array bytes { 254, 254, 254, 254 }; 41 | unsigned int onumber = number; 42 | 43 | if (onumber >= MAX3) 44 | { 45 | bytes[3] = number / MAX3 + 1; 46 | number = number % MAX3; 47 | } 48 | 49 | if (onumber >= MAX2) 50 | { 51 | bytes[2] = number / MAX2 + 1; 52 | number = number % MAX2; 53 | } 54 | 55 | if (onumber >= MAX1) 56 | { 57 | bytes[1] = number / MAX1 + 1; 58 | number = number % MAX1; 59 | } 60 | 61 | bytes[0] = number + 1; 62 | 63 | for (int i = 3; i >= 0; --i) 64 | { 65 | if (i == 0) 66 | { 67 | size = 1; 68 | break; 69 | } 70 | else if (bytes[i] > 0) 71 | { 72 | size = i + 1; 73 | break; 74 | } 75 | } 76 | 77 | return bytes; 78 | } 79 | 80 | RandGen::RandGen() 81 | { 82 | if(!this->initialized_) 83 | { 84 | this->seed = std::chrono::system_clock::now().time_since_epoch().count(); 85 | this->gen = std::mt19937(seed); 86 | 87 | this->initialized_ = true; 88 | } 89 | } 90 | 91 | int RandGen::RandInt(int imin, int imax) 92 | { 93 | std::uniform_int_distribution<> uniform_dist(imin, imax); 94 | int rand_num = uniform_dist(this->gen); 95 | 96 | return rand_num; 97 | } 98 | 99 | int path_length(int x1, int y1, int x2, int y2) 100 | { 101 | int dx = std::abs(x1 - x2); 102 | int dy = std::abs(y1 - y2); 103 | 104 | return dx + dy; 105 | } 106 | -------------------------------------------------------------------------------- /game_engine/src/map.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef MAP_HPP_INCLUDED 4 | #define MAP_HPP_INCLUDED 5 | 6 | #include "gfx_loader.hpp" 7 | #include "character.hpp" 8 | #include "npc.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // (monostate) 15 | class Map 16 | { 17 | public: 18 | class Tile 19 | { 20 | public: 21 | unsigned int graphic_id; 22 | unsigned short x; 23 | unsigned short y; 24 | 25 | Tile() : graphic_id(0), x(0), y(0) { } 26 | }; 27 | 28 | class Layer 29 | { 30 | public: 31 | enum class Type 32 | { 33 | Ground, 34 | Object 35 | }; 36 | 37 | public: 38 | Type type; 39 | std::map>> tiles; 40 | 41 | Layer(); 42 | }; 43 | 44 | class Attribute 45 | { 46 | public: 47 | enum class Type 48 | { 49 | Wall 50 | }; 51 | 52 | public: 53 | Type type; 54 | unsigned short x; 55 | unsigned short y; 56 | 57 | Attribute() : type(Type::Wall), x(0), y(0) { } 58 | }; 59 | 60 | private: 61 | static bool initialized_; 62 | static bool exists; 63 | 64 | public: 65 | static unsigned int id; 66 | static std::string name; 67 | static unsigned int revision; 68 | static unsigned short width; 69 | static unsigned short height; 70 | static unsigned int fill_tile; 71 | 72 | static std::map layers; 73 | static std::map>> atts; 74 | 75 | static std::vector> characters; 76 | static std::vector> npcs; 77 | 78 | Map(); 79 | Map(unsigned int id); 80 | bool Load(unsigned int id); 81 | void Save(); 82 | bool Exists() { return this->exists; } 83 | void Tick(); 84 | void Render(int rx, int ry); 85 | void Reset(); 86 | 87 | std::vector GetCharactersAt(unsigned short x, unsigned short y); 88 | Character *GetCharacter(std::string name); 89 | void DeleteCharacter(std::string name); 90 | 91 | std::vector GetNPCsAt(unsigned short x, unsigned short y); 92 | NPC *GetNPC(unsigned int index); 93 | void DeleteNPC(unsigned int index); 94 | 95 | bool Walkable(unsigned short x, unsigned short y, bool entity = true); 96 | }; 97 | 98 | #endif // MAP_HPP_INCLUDED 99 | -------------------------------------------------------------------------------- /server_engine/src/map.hpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #ifndef MAP_HPP_INCLUDED 4 | #define MAP_HPP_INCLUDED 5 | 6 | #include 7 | #include "character.hpp" 8 | #include "npc.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // (monostate) 16 | class Map 17 | { 18 | public: 19 | class Tile 20 | { 21 | public: 22 | unsigned int graphic_id; 23 | unsigned short x; 24 | unsigned short y; 25 | 26 | Tile() : graphic_id(0), x(0), y(0) { } 27 | }; 28 | 29 | class Layer 30 | { 31 | public: 32 | enum class Type 33 | { 34 | Ground, 35 | Object 36 | }; 37 | 38 | public: 39 | Type type; 40 | std::map>> tiles; 41 | 42 | Layer(); 43 | }; 44 | 45 | class Attribute 46 | { 47 | public: 48 | enum class Type 49 | { 50 | Wall 51 | }; 52 | 53 | public: 54 | Type type; 55 | unsigned short x; 56 | unsigned short y; 57 | 58 | Attribute() : type(Type::Wall), x(0), y(0) { } 59 | }; 60 | 61 | private: 62 | bool exists; 63 | 64 | public: 65 | unsigned int id; 66 | std::string name; 67 | unsigned int revision; 68 | unsigned short width; 69 | unsigned short height; 70 | unsigned int fill_tile; 71 | 72 | std::map layers; 73 | std::map>> atts; 74 | 75 | std::vector> characters; 76 | std::vector> npcs; 77 | 78 | sf::Clock npc_clock; 79 | 80 | Map(); 81 | Map(unsigned int id); 82 | bool Load(unsigned int id); 83 | void Save(); 84 | void Tick(); 85 | bool Exists() { return this->exists; } 86 | void Reset(); 87 | 88 | std::vector GetCharactersAt(unsigned short x, unsigned short y); 89 | Character *GetCharacter(std::string name); 90 | void DeleteCharacter(std::string name); 91 | 92 | std::vector GetNPCsAt(unsigned short x, unsigned short y); 93 | NPC *GetNPC(unsigned int index); 94 | void AddNPC(std::shared_ptr npc); 95 | void DeleteNPC(unsigned int index); 96 | 97 | bool Walkable(unsigned short x, unsigned short y, bool entity = true); 98 | 99 | unsigned int GenerateNPCIndex(); 100 | }; 101 | 102 | #endif // MAP_HPP_INCLUDED 103 | -------------------------------------------------------------------------------- /game_engine/src/handlers/h_map.cpp: -------------------------------------------------------------------------------- 1 | #include "h_map.hpp" 2 | 3 | #include "../client.hpp" 4 | #include "../map.hpp" 5 | 6 | #include 7 | 8 | namespace PacketHandlers::HMap 9 | { 10 | void Main(sf::Packet &packet, std::array data_ptr) 11 | { 12 | unsigned char sub_id = 0; 13 | 14 | packet >> sub_id; 15 | 16 | if(sub_id == 1) 17 | { 18 | Appear(packet, data_ptr); 19 | } 20 | if(sub_id == 2) 21 | { 22 | Leave(packet, data_ptr); 23 | } 24 | } 25 | 26 | void Appear(sf::Packet &packet, std::array data_ptr) 27 | { 28 | unsigned char buf = 0; 29 | unsigned char entity = 0; 30 | 31 | packet >> entity; 32 | 33 | if(entity == 1) // character 34 | { 35 | Character *character = 0; 36 | std::string name = ""; 37 | 38 | packet >> name; 39 | 40 | character = Map().GetCharacter(name); 41 | 42 | if(character == 0) 43 | { 44 | character = new Character(); 45 | character->name = name; 46 | Map().characters.push_back(std::shared_ptr(character)); 47 | } 48 | 49 | packet >> character->map_id; 50 | packet >> character->x; 51 | packet >> character->y; 52 | packet >> buf; character->direction = (Direction)buf; 53 | packet >> buf; character->gender = (Gender)buf; 54 | packet >> character->speed; 55 | 56 | std::cout << "Hello " << character->name << "." << std::endl; 57 | } 58 | if(entity == 2) // npc 59 | { 60 | unsigned int id = 0; 61 | unsigned int index = 0; 62 | 63 | packet >> id; 64 | packet >> index; 65 | 66 | NPC *npc = Map().GetNPC(index); 67 | 68 | if(npc == 0) 69 | { 70 | npc = new NPC(); 71 | npc->id = id; 72 | npc->index = index; 73 | Map().npcs.push_back(std::shared_ptr(npc)); 74 | } 75 | 76 | packet >> npc->map_id; 77 | packet >> npc->x; 78 | packet >> npc->y; 79 | packet >> buf; npc->direction = (Direction)buf; 80 | packet >> npc->speed; 81 | } 82 | } 83 | 84 | void Leave(sf::Packet &packet, std::array data_ptr) 85 | { 86 | std::string name = ""; 87 | 88 | packet >> name; 89 | 90 | Map map; 91 | Character *character = map.GetCharacter(name); 92 | 93 | if(character == 0) return; 94 | 95 | map.DeleteCharacter(name); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /server_engine/src/config.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "config.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | Config::Config() 11 | { 12 | 13 | } 14 | 15 | Config::Config(std::string filename) 16 | { 17 | this->Load(filename); 18 | } 19 | 20 | void Config::Load(std::string filename) 21 | { 22 | std::ifstream file(filename); 23 | if(!file.is_open()) 24 | { 25 | throw std::runtime_error("Config: could not load file."); 26 | } 27 | 28 | std::vector lines; 29 | std::string line; 30 | while(std::getline(file, line)) 31 | { 32 | lines.push_back(line); 33 | } 34 | 35 | file.close(); 36 | 37 | while(lines.size() > 0) 38 | { 39 | if(lines[0][0] == '#') 40 | { 41 | lines.erase(lines.begin()); 42 | continue; 43 | } 44 | 45 | std::string key = lines[0]; 46 | lines.erase(lines.begin()); 47 | 48 | if(lines.size() == 0) continue; 49 | 50 | std::string value = lines[0]; 51 | lines.erase(lines.begin()); 52 | 53 | if(value.size() > 0) 54 | { 55 | this->entries.push_back(Entry(key, value)); 56 | } 57 | } 58 | } 59 | 60 | void Config::Save(std::string filename) 61 | { 62 | std::ofstream file(filename, std::ios::trunc); 63 | if(!file.is_open()) 64 | { 65 | throw std::runtime_error("Config: could not open file."); 66 | } 67 | else if(!file.good()) 68 | { 69 | printf("Data stream error"); 70 | throw std::runtime_error("Config: data stream error."); 71 | } 72 | 73 | for(auto &it : this->entries) 74 | { 75 | std::string data = '[' + it.key + '=' + it.value + ']' + '\n'; 76 | const char *cdata = data.c_str(); 77 | file.write(cdata, (unsigned)strlen(cdata)); 78 | 79 | } 80 | file.close(); 81 | } 82 | 83 | Config::Entry Config::GetEntry(std::string key) 84 | { 85 | for(auto &it : this->entries) 86 | { 87 | if(it.key == key) 88 | { 89 | return it; 90 | } 91 | } 92 | 93 | return Entry("", ""); 94 | } 95 | 96 | std::string Config::GetValue(std::string key) 97 | { 98 | Entry entry = this->GetEntry(key); 99 | 100 | return entry.value; 101 | } 102 | 103 | void Config::AddEntry(Entry entry) 104 | { 105 | if(this->GetEntry(entry.key).key == "") 106 | { 107 | this->entries.push_back(entry); 108 | } 109 | } 110 | 111 | void Config::AddEntry(std::string key, std::string value) 112 | { 113 | this->AddEntry(Entry(key, value)); 114 | } 115 | -------------------------------------------------------------------------------- /server_engine/src/npc.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "npc.hpp" 4 | 5 | #include "util.hpp" 6 | 7 | #include 8 | #include 9 | 10 | NPC::NPC() 11 | { 12 | this->id = 0; 13 | this->index = 0; 14 | this->name = ""; 15 | this->map_id = 0; 16 | this->x = 0; 17 | this->y = 0; 18 | this->direction = (Direction)0; 19 | this->speed = 1; 20 | 21 | this->anim_state = AnimState::Stand; 22 | 23 | this->frame_counter = 0; 24 | } 25 | 26 | NPC::NPC(unsigned int id, unsigned int index, unsigned int map_id, unsigned short x, unsigned short y) 27 | { 28 | this->id = id; 29 | this->index = index; 30 | this->name = ""; 31 | this->map_id = map_id; 32 | this->x = x; 33 | this->y = y; 34 | this->direction = (Direction)0; 35 | this->speed = 1; 36 | 37 | this->anim_state = AnimState::Stand; 38 | 39 | this->frame_counter = 0; 40 | } 41 | 42 | void NPC::Tick() 43 | { 44 | if(this->frame_counter >= 20 - this->speed) 45 | { 46 | this->frame_counter = 0; 47 | 48 | this->animation.Tick(); 49 | } 50 | 51 | if(!this->animation.play && this->animation.current_frame != 0) 52 | { 53 | if(this->anim_state == AnimState::Walk) 54 | { 55 | this->animation.Clear(); 56 | this->anim_state = AnimState::Stand; 57 | } 58 | else 59 | { 60 | this->animation.Clear(); 61 | } 62 | } 63 | 64 | this->frame_counter++; 65 | } 66 | 67 | void NPC::Talk(std::string message) 68 | { 69 | 70 | } 71 | 72 | void NPC::Face(Direction direction) 73 | { 74 | if(this->animation.play || direction == this->direction) return; 75 | 76 | this->direction = direction; 77 | 78 | this->anim_state = AnimState::Stand; 79 | this->animation.Clear(); 80 | this->animation.frames.push_back(Animation::Frame(2)); 81 | this->animation.Play(); 82 | } 83 | 84 | void NPC::Walk(Direction direction) 85 | { 86 | if(this->animation.play) return; 87 | 88 | this->direction = direction; 89 | 90 | if(this->direction == Direction::Up) this->y--; 91 | if(this->direction == Direction::Right) this->x++; 92 | if(this->direction == Direction::Down) this->y++; 93 | if(this->direction == Direction::Left) this->x--; 94 | 95 | this->anim_state = AnimState::Walk; 96 | this->animation.Clear(); 97 | this->animation.frames.push_back(Animation::Frame(1)); 98 | this->animation.frames.push_back(Animation::Frame(1)); 99 | this->animation.frames.push_back(Animation::Frame(1)); 100 | this->animation.frames.push_back(Animation::Frame(1)); 101 | this->animation.Play(); 102 | } 103 | -------------------------------------------------------------------------------- /game_engine/src/config.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "config.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | bool Config::initialized_ = false; 11 | std::vector Config::entries; 12 | 13 | Config::Config() 14 | { 15 | if(!this->initialized_) 16 | { 17 | this->initialized_ = true; 18 | } 19 | } 20 | 21 | Config::Config(std::string filename) 22 | { 23 | if(!this->initialized_) 24 | { 25 | this->initialized_ = true; 26 | } 27 | 28 | this->Load(filename); 29 | } 30 | 31 | void Config::Load(std::string filename) 32 | { 33 | std::ifstream file(filename); 34 | if(!file.is_open()) 35 | { 36 | throw std::runtime_error("Config: could not load file."); 37 | } 38 | 39 | std::vector lines; 40 | std::string line; 41 | while(std::getline(file, line)) 42 | { 43 | lines.push_back(line); 44 | } 45 | 46 | file.close(); 47 | 48 | while(lines.size() > 0) 49 | { 50 | if(lines[0][0] == '#') 51 | { 52 | lines.erase(lines.begin()); 53 | continue; 54 | } 55 | 56 | std::string key = lines[0]; 57 | lines.erase(lines.begin()); 58 | 59 | if(lines.size() == 0) continue; 60 | 61 | std::string value = lines[0]; 62 | lines.erase(lines.begin()); 63 | 64 | if(value.size() > 0) 65 | { 66 | this->entries.push_back(Entry(key, value)); 67 | } 68 | } 69 | } 70 | 71 | void Config::Save(std::string filename) 72 | { 73 | std::ofstream file(filename, std::ios::trunc); 74 | if(!file.is_open()) 75 | { 76 | throw std::runtime_error("Config: could not open file."); 77 | } 78 | else if(!file.good()) 79 | { 80 | printf("Data stream error"); 81 | throw std::runtime_error("Config: data stream error."); 82 | } 83 | 84 | for(auto &it : this->entries) 85 | { 86 | std::string data = '[' + it.key + '=' + it.value + ']' + '\n'; 87 | const char *cdata = data.c_str(); 88 | file.write(cdata, (unsigned)strlen(cdata)); 89 | 90 | } 91 | file.close(); 92 | } 93 | 94 | Config::Entry Config::GetEntry(std::string key) 95 | { 96 | for(auto &it : this->entries) 97 | { 98 | if(it.key == key) 99 | { 100 | return it; 101 | } 102 | } 103 | 104 | return Entry("", ""); 105 | } 106 | 107 | std::string Config::GetValue(std::string key) 108 | { 109 | Entry entry = this->GetEntry(key); 110 | 111 | return entry.value; 112 | } 113 | 114 | void Config::AddEntry(Entry entry) 115 | { 116 | if(this->GetEntry(entry.key).key == "") 117 | { 118 | this->entries.push_back(entry); 119 | } 120 | } 121 | 122 | void Config::AddEntry(std::string key, std::string value) 123 | { 124 | this->AddEntry(Entry(key, value)); 125 | } 126 | -------------------------------------------------------------------------------- /game_engine/src/handlers/h_npc.cpp: -------------------------------------------------------------------------------- 1 | #include "h_npc.hpp" 2 | 3 | #include "../client.hpp" 4 | #include "../map.hpp" 5 | 6 | #include 7 | 8 | namespace PacketHandlers::HNPC 9 | { 10 | void Main(sf::Packet &packet, std::array data_ptr) 11 | { 12 | unsigned char sub_id = 0; 13 | packet >> sub_id; 14 | 15 | if(sub_id == 1) // npc list 16 | { 17 | List(packet, data_ptr); 18 | } 19 | if(sub_id == 2) // get in range 20 | { 21 | 22 | } 23 | if(sub_id == 3) // talk 24 | { 25 | Talk(packet, data_ptr); 26 | } 27 | if(sub_id == 4) // face 28 | { 29 | Face(packet, data_ptr); 30 | } 31 | if(sub_id == 5) // walk 32 | { 33 | Walk(packet, data_ptr); 34 | } 35 | } 36 | 37 | void List(sf::Packet &packet, std::array data_ptr) 38 | { 39 | std::size_t npcs = 0; 40 | 41 | packet >> npcs; 42 | 43 | Map().npcs.clear(); 44 | 45 | for(std::size_t i = 0; i < npcs; ++i) 46 | { 47 | NPC *npc = new NPC(); 48 | 49 | packet >> npc->id; 50 | packet >> npc->index; 51 | packet >> npc->map_id; 52 | packet >> npc->x; 53 | packet >> npc->y; 54 | unsigned char dir = 0; 55 | packet >> dir; 56 | npc->direction = (Direction)dir; 57 | packet >> npc->speed; 58 | 59 | Map().npcs.push_back(std::shared_ptr(npc)); 60 | } 61 | } 62 | 63 | void Talk(sf::Packet &packet, std::array data_ptr) 64 | { 65 | unsigned int index = 0; 66 | std::string message = ""; 67 | 68 | packet >> index; 69 | packet >> message; 70 | 71 | NPC *npc = Map().GetNPC(index); 72 | 73 | if(npc == 0) return; 74 | 75 | npc->Talk(message); 76 | } 77 | 78 | void Face(sf::Packet &packet, std::array data_ptr) 79 | { 80 | unsigned int index = 0; 81 | unsigned char direction = 0; 82 | 83 | packet >> index; 84 | packet >> direction; 85 | 86 | NPC *npc = Map().GetNPC(index); 87 | 88 | if(npc == 0) return; 89 | 90 | npc->Face((Direction)direction); 91 | } 92 | 93 | void Walk(sf::Packet &packet, std::array data_ptr) 94 | { 95 | unsigned char index = 0; 96 | unsigned char direction = 0; 97 | unsigned short x = 0; 98 | unsigned short y = 0; 99 | 100 | packet >> index; 101 | packet >> direction; 102 | packet >> x; 103 | packet >> y; 104 | 105 | NPC *npc = Map().GetNPC(index); 106 | 107 | if(npc == 0) 108 | { 109 | Client().GetInRange(index); 110 | 111 | return; 112 | } 113 | 114 | npc->Walk((Direction)direction); 115 | 116 | npc->direction = (Direction)direction; 117 | npc->x = x; 118 | npc->y = y; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /game_engine/src/file_handler.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "file_handler.hpp" 4 | #include "util.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | FileHandler::FileHandler(std::string filename) 13 | { 14 | this->Load(filename); 15 | } 16 | 17 | bool FileHandler::Load(std::string filename) 18 | { 19 | std::ifstream file; 20 | std::stringstream buffer; 21 | 22 | this->exists = false; 23 | 24 | file.open(filename); 25 | if(!file.is_open() || !file.good()) 26 | { 27 | std::cout << "File handler: could not load input file." << std::endl; 28 | return false; 29 | } 30 | 31 | this->exists = true; 32 | 33 | buffer << file.rdbuf(); 34 | 35 | file.close(); 36 | 37 | this->data = buffer.str(); 38 | 39 | return true; 40 | } 41 | 42 | void FileHandler::Save() 43 | { 44 | if(this->filename.empty()) 45 | { 46 | throw std::runtime_error("File handler: could not save file - empty file name given."); 47 | } 48 | 49 | std::ofstream file; 50 | 51 | file.open(this->filename, std::ofstream::trunc); 52 | if(!file.is_open() || !file.good()) 53 | { 54 | throw std::runtime_error("Map: could not load output file."); 55 | } 56 | 57 | this->exists = true; 58 | 59 | file << this->data; 60 | 61 | file.close(); 62 | } 63 | 64 | void FileHandler::Save(std::string filename) 65 | { 66 | this->filename = filename; 67 | this->Save(); 68 | } 69 | 70 | unsigned int FileHandler::GetNumber(std::size_t num_size) 71 | { 72 | std::array bytes = { 254, 254, 254, 254 }; 73 | 74 | std::copy_n(cbegin(this->data), std::min(num_size, this->data.size()), begin(bytes)); 75 | 76 | this->data.erase(0, std::min(this->data.size(), num_size)); 77 | 78 | return DecodeNumber(bytes[0], bytes[1], bytes[2], bytes[3]); 79 | } 80 | 81 | unsigned char FileHandler::GetChar() 82 | { 83 | return this->GetNumber(1); 84 | } 85 | 86 | unsigned short FileHandler::GetShort() 87 | { 88 | return this->GetNumber(2); 89 | } 90 | 91 | unsigned int FileHandler::GetThree() 92 | { 93 | return this->GetNumber(3); 94 | } 95 | 96 | unsigned int FileHandler::GetInt() 97 | { 98 | return this->GetNumber(4); 99 | } 100 | 101 | std::string FileHandler::GetString() 102 | { 103 | std::string str = ""; 104 | 105 | if(this->data.empty()) return str; 106 | 107 | std::size_t length = this->data.find_first_of((unsigned char)0xFF); 108 | 109 | if(length > this->data.size()) return str; 110 | 111 | str = this->data.substr(0, length); 112 | this->data.erase(0, length + 1); 113 | 114 | return str; 115 | } 116 | 117 | std::string FileHandler::GetData() 118 | { 119 | return this->data; 120 | } 121 | 122 | void FileHandler::AddChar(unsigned char char_) 123 | { 124 | this->data += EncodeNumber(char_)[0]; 125 | } 126 | 127 | void FileHandler::AddShort(unsigned short num) 128 | { 129 | this->data.append((char *)EncodeNumber(num).data(), 2); 130 | } 131 | 132 | void FileHandler::AddThree(unsigned int num) 133 | { 134 | this->data.append((char *)EncodeNumber(num).data(), 3); 135 | } 136 | 137 | void FileHandler::AddInt(unsigned int num) 138 | { 139 | this->data.append((char *)EncodeNumber(num).data(), 4); 140 | } 141 | 142 | void FileHandler::AddString(std::string str) 143 | { 144 | this->data += str; 145 | this->data += (unsigned char)0xFF; 146 | } 147 | -------------------------------------------------------------------------------- /server_engine/src/file_handler.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "file_handler.hpp" 4 | #include "util.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | FileHandler::FileHandler(std::string filename) 13 | { 14 | this->Load(filename); 15 | } 16 | 17 | bool FileHandler::Load(std::string filename) 18 | { 19 | std::ifstream file; 20 | std::stringstream buffer; 21 | 22 | this->exists = false; 23 | 24 | file.open(filename); 25 | if(!file.is_open() || !file.good()) 26 | { 27 | std::cout << "File handler: could not load input file." << std::endl; 28 | return false; 29 | } 30 | 31 | this->exists = true; 32 | 33 | buffer << file.rdbuf(); 34 | 35 | file.close(); 36 | 37 | this->data = buffer.str(); 38 | 39 | return true; 40 | } 41 | 42 | void FileHandler::Save() 43 | { 44 | if(this->filename.empty()) 45 | { 46 | throw std::runtime_error("File handler: could not save file - empty file name given."); 47 | } 48 | 49 | std::ofstream file; 50 | 51 | file.open(this->filename, std::ofstream::trunc); 52 | if(!file.is_open() || !file.good()) 53 | { 54 | throw std::runtime_error("Map: could not load output file."); 55 | } 56 | 57 | this->exists = true; 58 | 59 | file << this->data; 60 | 61 | file.close(); 62 | } 63 | 64 | void FileHandler::Save(std::string filename) 65 | { 66 | this->filename = filename; 67 | this->Save(); 68 | } 69 | 70 | unsigned int FileHandler::GetNumber(std::size_t num_size) 71 | { 72 | std::array bytes = { 254, 254, 254, 254 }; 73 | 74 | std::copy_n(cbegin(this->data), std::min(num_size, this->data.size()), begin(bytes)); 75 | 76 | this->data.erase(0, std::min(this->data.size(), num_size)); 77 | 78 | return DecodeNumber(bytes[0], bytes[1], bytes[2], bytes[3]); 79 | } 80 | 81 | unsigned char FileHandler::GetChar() 82 | { 83 | return this->GetNumber(1); 84 | } 85 | 86 | unsigned short FileHandler::GetShort() 87 | { 88 | return this->GetNumber(2); 89 | } 90 | 91 | unsigned int FileHandler::GetThree() 92 | { 93 | return this->GetNumber(3); 94 | } 95 | 96 | unsigned int FileHandler::GetInt() 97 | { 98 | return this->GetNumber(4); 99 | } 100 | 101 | std::string FileHandler::GetString() 102 | { 103 | std::string str = ""; 104 | 105 | if(this->data.empty()) return str; 106 | 107 | std::size_t length = this->data.find_first_of((unsigned char)0xFF); 108 | 109 | if(length > this->data.size()) return str; 110 | 111 | str = this->data.substr(0, length); 112 | this->data.erase(0, length + 1); 113 | 114 | return str; 115 | } 116 | 117 | std::string FileHandler::GetData() 118 | { 119 | return this->data; 120 | } 121 | 122 | void FileHandler::AddChar(unsigned char char_) 123 | { 124 | this->data += EncodeNumber(char_)[0]; 125 | } 126 | 127 | void FileHandler::AddShort(unsigned short num) 128 | { 129 | this->data.append((char *)EncodeNumber(num).data(), 2); 130 | } 131 | 132 | void FileHandler::AddThree(unsigned int num) 133 | { 134 | this->data.append((char *)EncodeNumber(num).data(), 3); 135 | } 136 | 137 | void FileHandler::AddInt(unsigned int num) 138 | { 139 | this->data.append((char *)EncodeNumber(num).data(), 4); 140 | } 141 | 142 | void FileHandler::AddString(std::string str) 143 | { 144 | this->data += str; 145 | this->data += (unsigned char)0xFF; 146 | } 147 | -------------------------------------------------------------------------------- /game_engine/src/input_handler.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "input_handler.hpp" 4 | 5 | #include "client.hpp" 6 | #include "map.hpp" 7 | #include "map_editor.hpp" 8 | #include "gui.hpp" 9 | 10 | #include 11 | 12 | bool InputHandler::initialized_ = false; 13 | std::map InputHandler::keys; 14 | std::map InputHandler::mouse; 15 | Direction InputHandler::direction; 16 | bool InputHandler::rewalk; 17 | 18 | InputHandler::InputHandler() 19 | { 20 | if(!this->initialized_) 21 | { 22 | this->direction = static_cast(0); 23 | this->rewalk = false; 24 | 25 | this->initialized_ = true; 26 | } 27 | } 28 | 29 | void InputHandler::ProcessEvent(ALLEGRO_EVENT event) 30 | { 31 | Client client; 32 | 33 | if(event.type == ALLEGRO_EVENT_KEY_DOWN) 34 | { 35 | this->keys[event.keyboard.keycode] = true; 36 | } 37 | if(event.type == ALLEGRO_EVENT_KEY_UP) 38 | { 39 | this->keys[event.keyboard.keycode] = false; 40 | } 41 | 42 | if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) 43 | { 44 | this->mouse[event.mouse.button] = true; 45 | } 46 | if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 47 | { 48 | this->mouse[event.mouse.button] = false; 49 | } 50 | } 51 | 52 | void InputHandler::Process() 53 | { 54 | Client client; 55 | 56 | if(client.state != Client::State::Playing && GUI().GetState() != GUI::State::Editor) return; 57 | 58 | if(client.character->anim_state == Character::AnimState::Stand || client.character->anim_state == Character::AnimState::Walk) 59 | { 60 | this->CharacterMovement(); 61 | } 62 | } 63 | 64 | void InputHandler::CharacterMovement() 65 | { 66 | Client client; 67 | 68 | bool walk = false; 69 | bool do_rewalk = false; 70 | 71 | for(int i = ALLEGRO_KEY_LEFT; i <= ALLEGRO_KEY_DOWN; ++i) 72 | { 73 | if(this->keys[i]) 74 | { 75 | if(client.character->anim_state == Character::AnimState::Stand) 76 | { 77 | walk = true; 78 | } 79 | if(client.character->anim_state == Character::AnimState::Walk) 80 | { 81 | this->rewalk = true; 82 | do_rewalk = true; 83 | } 84 | 85 | break; 86 | } 87 | } 88 | 89 | if(this->keys[ALLEGRO_KEY_UP]) this->direction = Direction::Up; 90 | else if(this->keys[ALLEGRO_KEY_RIGHT]) this->direction = Direction::Right; 91 | else if(this->keys[ALLEGRO_KEY_DOWN]) this->direction = Direction::Down; 92 | else if(this->keys[ALLEGRO_KEY_LEFT]) this->direction = Direction::Left; 93 | 94 | if((walk || this->rewalk) && client.character->anim_state == Character::AnimState::Stand && !client.character->animation.play) 95 | { 96 | if(client.character->direction != this->direction && !this->rewalk) 97 | { 98 | client.character->Face(this->direction); 99 | if(client.character->anim_state == Character::AnimState::Stand && client.character->animation.play) 100 | client.Face(this->direction); 101 | } 102 | else 103 | { 104 | unsigned short walk_x = client.character->x; 105 | unsigned short walk_y = client.character->y; 106 | 107 | if(this->direction == Direction::Up) walk_y--; 108 | if(this->direction == Direction::Right) walk_x++; 109 | if(this->direction == Direction::Down) walk_y++; 110 | if(this->direction == Direction::Left) walk_x--; 111 | 112 | if(Map().Walkable(walk_x, walk_y)) 113 | { 114 | if(direction == Direction::Up && client.character->y == 0) return; 115 | if(direction == Direction::Right && client.character->x == Map().width - 1) return; 116 | if(direction == Direction::Down && client.character->y == Map().height - 1) return; 117 | if(direction == Direction::Left && client.character->x == 0) return; 118 | 119 | client.character->Walk(this->direction); 120 | if(client.character->anim_state == Character::AnimState::Walk) 121 | client.Walk(this->direction); 122 | } 123 | } 124 | } 125 | 126 | this->rewalk = do_rewalk; 127 | } 128 | -------------------------------------------------------------------------------- /server_engine/src/handlers/account.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "account.hpp" 4 | 5 | #include "../client.hpp" 6 | #include "../database.hpp" 7 | #include "../const/packet.hpp" 8 | 9 | #include 10 | 11 | struct CreateRequest 12 | { 13 | std::string username; 14 | bool found; 15 | 16 | CreateRequest() : username(""), found(false) { } 17 | }; 18 | 19 | static int lookup_account(void *data, int argc, char **argv, char **col_name) 20 | { 21 | for(int i = 0; iusername; 28 | 29 | if(argc == 1) 30 | { 31 | if(argv[0] == username) 32 | { 33 | request->found = true; 34 | } 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | static bool is_alphanumeric(std::string str) 41 | { 42 | for(std::size_t i = 0; i < str.size(); ++i) 43 | { 44 | bool valid = false; 45 | 46 | if((str[i] >= 48 && str[i] <= 57) || (str[i] >= 65 && str[i] <= 90) || (str[i] >= 97 && str[i] <= 122))\ 47 | valid = true; 48 | 49 | if(!valid) return false; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | static bool is_email(std::string str) 56 | { 57 | for(std::size_t i = 0; i < str.size(); ++i) 58 | { 59 | bool valid = false; 60 | 61 | if((str[i] >= 48 && str[i] <= 57) || (str[i] >= 65 && str[i] <= 90) || (str[i] >= 97 && str[i] <= 122) || 62 | str[i] == '@' || str[i] == '.') 63 | valid = true; 64 | 65 | if(!valid) return false; 66 | } 67 | 68 | return true; 69 | } 70 | 71 | namespace PacketHandlers::HAccount 72 | { 73 | 74 | void Main(sf::Packet &packet, std::array data_ptr) 75 | { 76 | Client *client = (Client *)data_ptr[0]; 77 | 78 | if(client->state != Client::State::Initialized) return; 79 | 80 | unsigned char sub_id = 0; 81 | 82 | packet >> sub_id; 83 | 84 | if(sub_id == 1) // create an account 85 | { 86 | Create(packet, data_ptr); 87 | } 88 | if(sub_id == 2) // delete an account 89 | { 90 | Delete(packet, data_ptr); 91 | } 92 | } 93 | 94 | void Create(sf::Packet &packet, std::array data_ptr) 95 | { 96 | Client *client = (Client *)data_ptr[0]; 97 | std::string username, password, real_name, location, email; 98 | 99 | packet >> username; 100 | packet >> password; 101 | packet >> real_name; 102 | packet >> location; 103 | packet >> email; 104 | 105 | std::string sql_query = "SELECT username FROM accounts WHERE username='" + username + "';"; 106 | 107 | std::cout << sql_query << std::endl; 108 | 109 | Database database; 110 | std::unique_ptr request = std::make_unique(); 111 | request->username = username; 112 | 113 | bool valid_str = true; 114 | 115 | if(!is_alphanumeric(username)) valid_str = false; 116 | if(!is_alphanumeric(password)) valid_str = false; 117 | if(!is_alphanumeric(real_name)) valid_str = false; 118 | if(!is_alphanumeric(location)) valid_str = false; 119 | if(!is_email(email)) valid_str = false; 120 | 121 | int ret = 0; 122 | 123 | if(valid_str) 124 | ret = database.Execute(sql_query.c_str(), lookup_account, request.get()); 125 | 126 | unsigned char answer = 0; 127 | std::string message = ""; 128 | 129 | if(!request->found && valid_str) 130 | { 131 | sql_query = "INSERT INTO accounts VALUES ('" + username + "', '" + password + "', '" + real_name + "', '" \ 132 | + location + "', '" + email + "');"; 133 | 134 | ret = database.Execute(sql_query.c_str(), 0, 0); 135 | 136 | if(ret == 0) 137 | { 138 | message = "Account created!"; 139 | 140 | answer = 1; 141 | } 142 | } 143 | else 144 | { 145 | std::string errormsg = ""; 146 | 147 | if(!valid_str) errormsg = "Please use alphanumeric characters only"; 148 | else errormsg = "Account already exists"; 149 | 150 | message = "Could not create account of given username. -[" + errormsg + "]-"; 151 | } 152 | 153 | std::cout << message << std::endl; 154 | 155 | sf::Packet reply; 156 | reply << (unsigned char)PacketID::Account; 157 | reply << (unsigned char)1; // sub_id 158 | reply << answer; 159 | reply << message; 160 | client->Send(reply); 161 | } 162 | 163 | void Delete(sf::Packet &packet, std::array data_ptr) 164 | { 165 | 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /game_engine/src/map_cursor.cpp: -------------------------------------------------------------------------------- 1 | #include "map_cursor.hpp" 2 | 3 | #include "gfx_loader.hpp" 4 | #include "map.hpp" 5 | #include "client.hpp" 6 | 7 | #include 8 | 9 | bool MapCursor::initialized_ = false; 10 | int MapCursor::rx; 11 | int MapCursor::ry; 12 | std::string MapCursor::nickname; 13 | unsigned short MapCursor::x; 14 | unsigned short MapCursor::y; 15 | 16 | MapCursor::MapCursor() 17 | { 18 | if(!this->initialized_) 19 | { 20 | this->rx = 0; 21 | this->ry = 0; 22 | this->nickname = ""; 23 | this->x = 0; 24 | this->y = 0; 25 | 26 | this->initialized_ = true; 27 | } 28 | } 29 | 30 | void MapCursor::Render(int rx, int ry) 31 | { 32 | ALLEGRO_BITMAP *bitmap = GFXLoader().GetBitmap(2, 24); 33 | 34 | if(bitmap == NULL) return; 35 | 36 | Map map; 37 | 38 | ALLEGRO_MOUSE_STATE m_state; 39 | al_get_mouse_state(&m_state); 40 | 41 | int mx = m_state.x; 42 | int my = m_state.y; 43 | 44 | this->rx = rx; 45 | this->ry = ry; 46 | 47 | bool update = false; 48 | 49 | Character *character = Client().character; 50 | unsigned short start_x = 0; 51 | unsigned short start_y = 0; 52 | unsigned short end_x = map.width > 0? map.width - 1 : 1; 53 | unsigned short end_y = map.height > 0? map.height - 1 : 1; 54 | 55 | if(character != 0) 56 | { 57 | start_x = character->x > 16? character->x - 16 : 0; 58 | start_y = character->y > 16? character->y - 16 : 0; 59 | end_x = character->x + 16 > map.width? map.width - 1 : character->x + 16; 60 | end_y = character->y + 16 > map.height? map.height - 1 : character->y + 16; 61 | } 62 | 63 | for(unsigned short x = start_x; x <= end_x; ++x) 64 | { 65 | for(unsigned short y = start_y; y <= end_y; ++y) 66 | { 67 | if(!this->TestMousePos(mx, my, x, y)) continue; 68 | 69 | this->x = x; 70 | this->y = y; 71 | update = true; 72 | 73 | break; 74 | } 75 | 76 | if(update) break; 77 | } 78 | 79 | int screen_x = this->x * 64 - this->x * 32 - this->y * 32 + this->rx; 80 | int screen_y = this->y * 16 + this->x * 16 + this->ry; 81 | 82 | al_draw_bitmap_region(bitmap, 0, 0, 64, 32, screen_x, screen_y, 0); 83 | 84 | std::vector chars = Map().GetCharactersAt(this->x, this->y); 85 | if(chars.size() > 0) 86 | { 87 | this->nickname = chars[0]->name; 88 | } 89 | else 90 | { 91 | this->nickname = ""; 92 | } 93 | } 94 | 95 | bool MapCursor::TestMousePos(int mx, int my, unsigned short x, unsigned short y) 96 | { 97 | int screen_x = x * 64 - x * 32 - y * 32 + this->rx; 98 | int screen_y = y * 16 + x * 16 + this->ry; 99 | 100 | bool test = (mx >= screen_x + 16 && mx < screen_x + 48 && my >= screen_y + 8 && my < screen_y + 24); 101 | 102 | if(!test) 103 | test = (mx >= screen_x + 2 && mx < screen_x + 62 && my >= screen_y + 14 && my < screen_y + 18); 104 | 105 | if(!test) 106 | test = (mx >= screen_x + 26 && mx < screen_x + 38 && my >= screen_y + 2 && my < screen_y + 30); 107 | 108 | return test; 109 | } 110 | 111 | bool MapCursor::MouseOnMap() 112 | { 113 | ALLEGRO_MOUSE_STATE m_state; 114 | al_get_mouse_state(&m_state); 115 | 116 | int mx = m_state.x; 117 | int my = m_state.y; 118 | 119 | Map map; 120 | 121 | Character *character = Client().character; 122 | unsigned short start_x = 0; 123 | unsigned short start_y = 0; 124 | unsigned short end_x = map.width > 0? map.width - 1 : 1; 125 | unsigned short end_y = map.height > 0? map.height - 1 : 1; 126 | 127 | if(character != 0) 128 | { 129 | start_x = character->x > 16? character->x - 16 : 0; 130 | start_y = character->y > 16? character->y - 16 : 0; 131 | end_x = character->x + 16 > map.width? map.width - 1 : character->x + 16; 132 | end_y = character->y + 16 > map.height? map.height - 1 : character->y + 16; 133 | } 134 | 135 | for(unsigned short x = start_x; x <= end_x; ++x) 136 | { 137 | for(unsigned short y = start_y; y <= end_y; ++y) 138 | { 139 | int screen_x = x * 64 - x * 32 - y * 32 + this->rx; 140 | int screen_y = y * 16 + x * 16 + this->ry; 141 | 142 | bool test = (mx >= screen_x + 16 && mx < screen_x + 48 && my >= screen_y + 8 && my < screen_y + 24); 143 | 144 | if(!test) 145 | test = (mx >= screen_x && mx < screen_x + 64 && my >= screen_y + 14 && my < screen_y + 18); 146 | 147 | if(!test) 148 | test = (mx >= screen_x + 26 && mx < screen_x + 38 && my >= screen_y && my < screen_y + 32); 149 | 150 | if(test) return true; 151 | } 152 | } 153 | 154 | return false; 155 | } 156 | -------------------------------------------------------------------------------- /server_engine/src/client.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "client.hpp" 4 | 5 | #include "handlers/init.hpp" 6 | 7 | #include 8 | 9 | Client::Client() 10 | { 11 | this->connected = true; 12 | this->state = State::Uninitialized; 13 | this->username = ""; 14 | this->selected_character = ""; 15 | this->map_id = 0; 16 | 17 | this->transfer_data = ""; 18 | this->transfer_id = 0; 19 | this->transfer_clock.restart(); 20 | 21 | this->action_clock.restart(); 22 | this->ping_clock.restart(); 23 | 24 | this->latency = 0; 25 | } 26 | 27 | void Client::Tick() 28 | { 29 | sf::Packet packet; 30 | sf::Socket::Status status; 31 | 32 | if(!this->connected) return; 33 | 34 | if(!this->send_queue.empty()) 35 | { 36 | status = this->socket->send(this->send_queue[0]); 37 | 38 | switch(status) 39 | { 40 | case sf::Socket::Status::Done: 41 | this->send_queue.erase(this->send_queue.begin()); 42 | break; 43 | 44 | case sf::Socket::Status::NotReady: 45 | break; 46 | 47 | case sf::Socket::Status::Disconnected: 48 | this->connected = false; 49 | break; 50 | 51 | case sf::Socket::Status::Error: 52 | { 53 | this->connected = false; 54 | throw std::runtime_error("Client socket: error while sending data."); 55 | } 56 | break; 57 | 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | status = this->socket->receive(packet); 64 | 65 | switch(status) 66 | { 67 | case sf::Socket::Status::Done: 68 | this->recv_queue.push_back(packet); 69 | break; 70 | 71 | case sf::Socket::Status::NotReady: 72 | break; 73 | 74 | case sf::Socket::Status::Disconnected: 75 | this->connected = false; 76 | break; 77 | 78 | case sf::Socket::Status::Error: 79 | { 80 | throw std::runtime_error("Client socket: error while receiving data."); 81 | } 82 | break; 83 | 84 | default: 85 | break; 86 | } 87 | 88 | if(!this->recv_queue.empty()) 89 | { 90 | packet = this->Recv(); 91 | this->packet_handler.Execute(packet); 92 | } 93 | 94 | if(this->transfer_data.size() > 0 && this->transfer_clock.getElapsedTime().asMilliseconds() >= 10) 95 | { 96 | sf::Packet reply; 97 | 98 | reply << (unsigned char)PacketID::FileData; 99 | reply << (unsigned char)1; 100 | reply << (unsigned char)2; 101 | reply << this->transfer_data.substr(0, 10240); 102 | 103 | this->transfer_data.erase(0, 10240); 104 | 105 | this->Send(reply); 106 | 107 | if(this->transfer_data.size() == 0) 108 | { 109 | reply.clear(); 110 | 111 | reply << (unsigned char)PacketID::FileData; 112 | reply << (unsigned char)1; 113 | reply << (unsigned char)3; 114 | reply << this->transfer_id; 115 | 116 | this->Send(reply); 117 | 118 | this->transfer_id = 0; 119 | } 120 | } 121 | 122 | if(this->action_queue.size() > 0) 123 | { 124 | if(this->action_clock.getElapsedTime().asMilliseconds() >= this->action_queue[0].second) 125 | { 126 | this->action_clock.restart(); 127 | 128 | this->Send(this->action_queue[0].first); 129 | this->action_queue.erase(this->action_queue.begin()); 130 | } 131 | } 132 | 133 | if(this->ping_clock.getElapsedTime().asSeconds() >= 30) 134 | { 135 | sf::Packet packet; 136 | 137 | packet << (unsigned char)PacketID::Ping; 138 | 139 | this->Send(packet); 140 | 141 | this->ping_clock.restart(); 142 | } 143 | } 144 | 145 | bool Client::Connected() 146 | { 147 | return this->connected; 148 | } 149 | 150 | void Client::Send(sf::Packet packet) 151 | { 152 | this->send_queue.push_back(packet); 153 | } 154 | 155 | sf::Packet Client::Recv() 156 | { 157 | sf::Packet packet; 158 | 159 | if(!this->recv_queue.empty()) 160 | { 161 | packet = this->recv_queue[0]; 162 | this->recv_queue.erase(this->recv_queue.begin()); 163 | } 164 | 165 | return packet; 166 | } 167 | 168 | Character *Client::GetCharacter(std::string name) 169 | { 170 | for(auto &it : this->characters) 171 | { 172 | if(it->name == name) return it.get(); 173 | } 174 | 175 | return 0; 176 | } 177 | 178 | void Client::RemoveCharacter(std::string name) 179 | { 180 | for(std::size_t i = 0; i < this->characters.size(); ++i) 181 | { 182 | if(this->characters[i]->name == name) 183 | { 184 | this->characters.erase(this->characters.begin() + i); 185 | return; 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /game_engine/src/npc.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "npc.hpp" 4 | 5 | #include "gfx_loader.hpp" 6 | #include "util.hpp" 7 | 8 | #include 9 | #include 10 | 11 | NPC::NPC() 12 | { 13 | this->id = 0; 14 | this->index = 0; 15 | this->name = ""; 16 | this->map_id = 0; 17 | this->x = 0; 18 | this->y = 0; 19 | this->direction = (Direction)0; 20 | this->speed = 1; 21 | 22 | this->anim_state = AnimState::Stand; 23 | 24 | this->screen_x = 0; 25 | this->screen_y = 0; 26 | 27 | this->frame_counter = 0; 28 | } 29 | 30 | NPC::NPC(unsigned int id, unsigned int index, unsigned int map_id, unsigned short x, unsigned short y) 31 | { 32 | this->id = id; 33 | this->index = index; 34 | this->name = ""; 35 | this->map_id = map_id; 36 | this->x = x; 37 | this->y = y; 38 | this->direction = (Direction)0; 39 | this->speed = 1; 40 | 41 | this->anim_state = AnimState::Stand; 42 | 43 | this->screen_x = 0; 44 | this->screen_y = 0; 45 | 46 | this->frame_counter = 0; 47 | } 48 | 49 | void NPC::Tick() 50 | { 51 | if(this->frame_counter >= 20 - this->speed) 52 | { 53 | this->frame_counter = 0; 54 | 55 | this->animation.Tick(); 56 | } 57 | 58 | if(!this->animation.play && this->animation.current_frame != 0) 59 | { 60 | if(this->anim_state == AnimState::Walk) 61 | { 62 | this->animation.Clear(); 63 | this->anim_state = AnimState::Stand; 64 | } 65 | else 66 | { 67 | this->animation.Clear(); 68 | } 69 | } 70 | 71 | this->frame_counter++; 72 | } 73 | 74 | void NPC::Render(int rx, int ry) 75 | { 76 | GFXLoader gfx_loader; 77 | 78 | ALLEGRO_BITMAP *bitmap = NULL; 79 | 80 | unsigned int g_id = (this->id - 1) * 40 + 1; 81 | 82 | if(this->anim_state == AnimState::Stand) 83 | { 84 | if(this->direction == Direction::Up || this->direction == Direction::Left) g_id += 2; 85 | } 86 | if(this->anim_state == AnimState::Walk) 87 | { 88 | g_id += 4; 89 | 90 | if(this->direction == Direction::Up || this->direction == Direction::Left) g_id += 4; 91 | 92 | g_id += (int)this->animation.current_frame; 93 | } 94 | 95 | bitmap = gfx_loader.GetBitmap(21, g_id, true); 96 | 97 | if(bitmap == 0) return; 98 | 99 | int frame_w = al_get_bitmap_width(bitmap); 100 | int frame_h = al_get_bitmap_height(bitmap); 101 | 102 | this->screen_x = this->x * 64 - this->x * 32 - this->y * 32 + rx; 103 | this->screen_y = this->y * 16 + this->x * 16 + ry; 104 | 105 | screen_x += 32; 106 | screen_y += 16; 107 | 108 | if(frame_h > 32) 109 | { 110 | screen_y -= frame_h; 111 | screen_y += 16; 112 | if(frame_w < 64) screen_y -= 8; 113 | } 114 | if(frame_h < 32) 115 | { 116 | screen_y -= frame_h / 2; 117 | screen_y -= 8; 118 | } 119 | 120 | if(this->anim_state == AnimState::Walk) 121 | { 122 | int walk_off_x[4] = { -1, -1, 1, 1 }; 123 | int walk_off_y[4] = { 1, -1, -1, 1 }; 124 | 125 | screen_x += ((8 * (4 - (int)this->animation.current_frame)) * walk_off_x[(int)this->direction]); 126 | screen_y += ((4 * (4 - (int)this->animation.current_frame)) * walk_off_y[(int)this->direction]); 127 | } 128 | 129 | int dir = (int)this->direction; 130 | 131 | int cx = frame_w / 2; 132 | int cy = 0; 133 | float scale_offset[4] = { -1, -1, 1, 1 }; 134 | 135 | al_draw_tinted_scaled_rotated_bitmap_region(bitmap, 0, 0, frame_w, frame_h, 136 | al_map_rgb(255, 255, 255), 137 | cx, cy, screen_x, screen_y, scale_offset[dir], 1, 0, 0); 138 | } 139 | 140 | std::vector NPC::GetScreenPos() 141 | { 142 | std::vector ret; 143 | 144 | ret.push_back(this->screen_x); 145 | ret.push_back(this->screen_y); 146 | 147 | return ret; 148 | } 149 | 150 | void NPC::Talk(std::string message) 151 | { 152 | 153 | } 154 | 155 | void NPC::Face(Direction direction) 156 | { 157 | if(this->animation.play || direction == this->direction) return; 158 | 159 | this->direction = direction; 160 | 161 | this->anim_state = AnimState::Stand; 162 | this->animation.Clear(); 163 | this->animation.frames.push_back(Animation::Frame(2)); 164 | this->animation.Play(); 165 | } 166 | 167 | void NPC::Walk(Direction direction) 168 | { 169 | if(this->animation.play) return; 170 | 171 | this->direction = direction; 172 | 173 | if(this->direction == Direction::Up) this->y--; 174 | if(this->direction == Direction::Right) this->x++; 175 | if(this->direction == Direction::Down) this->y++; 176 | if(this->direction == Direction::Left) this->x--; 177 | 178 | this->anim_state = AnimState::Walk; 179 | this->animation.Clear(); 180 | this->animation.frames.push_back(Animation::Frame(1)); 181 | this->animation.frames.push_back(Animation::Frame(1)); 182 | this->animation.frames.push_back(Animation::Frame(1)); 183 | this->animation.frames.push_back(Animation::Frame(1)); 184 | this->animation.Play(); 185 | } 186 | -------------------------------------------------------------------------------- /server_engine/src/handlers/login.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "login.hpp" 4 | 5 | #include "h_character.hpp" 6 | #include "ping.hpp" 7 | #include "../client.hpp" 8 | #include "../database.hpp" 9 | #include "../server.hpp" 10 | 11 | #include 12 | #include 13 | 14 | struct LoginRequest 15 | { 16 | std::string username; 17 | std::string password; 18 | bool valid; 19 | 20 | LoginRequest() : username(""), password(""), valid(false) { } 21 | }; 22 | 23 | struct CharList 24 | { 25 | std::vector> characters; 26 | }; 27 | 28 | static int validate_account(void *data, int argc, char **argv, char **col_name) 29 | { 30 | LoginRequest *request = (LoginRequest *)data; 31 | std::string username = request->username; 32 | 33 | for(int i = 0; i < argc; i++) 34 | { 35 | std::cout << col_name[i] << ", " << (argv[i] ? argv[i] : "NULL") << std::endl; 36 | } 37 | 38 | if(argc == 1) 39 | { 40 | if(argv[0] == username) 41 | { 42 | request->valid = true; 43 | } 44 | } 45 | 46 | return 0; 47 | } 48 | 49 | static int get_characters(void *data, int argc, char **argv, char **col_name) 50 | { 51 | CharList *charlist = (CharList *)data; 52 | 53 | for(int i = 0; i < argc; i++) 54 | { 55 | std::cout << col_name[i] << ", " << (argv[i] ? argv[i] : "NULL") << std::endl; 56 | } 57 | 58 | if(argc >= 5) 59 | { 60 | std::shared_ptr character = std::shared_ptr(new Character()); 61 | character->username = argv[0]; 62 | character->name = argv[1]; 63 | character->map_id = std::atoi(argv[2]); 64 | character->x = std::atoi(argv[3]); 65 | character->y = std::atoi(argv[4]); 66 | character->direction = (Direction)std::atoi(argv[5]); 67 | character->gender = (Gender)std::atoi(argv[6]); 68 | character->speed = std::atoi(argv[7]); 69 | 70 | charlist->characters.push_back(character); 71 | } 72 | 73 | return 0; 74 | } 75 | 76 | static bool is_alphanumeric(std::string str) 77 | { 78 | for(std::size_t i = 0; i < str.size(); ++i) 79 | { 80 | bool valid = false; 81 | 82 | if((str[i] >= 48 && str[i] <= 57) || (str[i] >= 65 && str[i] <= 90) || (str[i] >= 97 && str[i] <= 122))\ 83 | valid = true; 84 | 85 | if(!valid) return false; 86 | } 87 | 88 | return true; 89 | } 90 | 91 | namespace PacketHandlers::HLogin 92 | { 93 | 94 | void Main(sf::Packet &packet, std::array data_ptr) 95 | { 96 | Client *client = (Client *)data_ptr[0]; 97 | 98 | unsigned char sub_id = 0; 99 | packet >> sub_id; 100 | 101 | if(sub_id == 1) // login request 102 | { 103 | std::string username = ""; 104 | std::string password = ""; 105 | 106 | if(client->state != Client::State::Initialized) return; 107 | 108 | packet >> username; 109 | packet >> password; 110 | 111 | std::string sql_query = "SELECT username FROM accounts WHERE username='" \ 112 | + username + "' AND password='" + password + "';"; 113 | 114 | std::cout << sql_query << std::endl; 115 | 116 | Database database; 117 | std::unique_ptr request = std::make_unique(); 118 | request->username = username; 119 | request->password = password; 120 | 121 | Client *client_logged = Server().GetClientByAcc(username); 122 | bool valid_str = is_alphanumeric(username) && is_alphanumeric(password); 123 | 124 | if(valid_str && client_logged == 0) 125 | { 126 | database.Execute(sql_query.c_str(), validate_account, request.get()); 127 | } 128 | 129 | unsigned char answer = 0; 130 | std::string message = ""; 131 | 132 | if(request->valid) 133 | { 134 | client->state = Client::State::Logged_in; 135 | client->username = username; 136 | client->packet_handler.Register(PacketID::Character, PacketHandlers::HCharacter::Main, data_ptr); 137 | answer = 1; 138 | message = "Logged in!"; 139 | 140 | sql_query = "SELECT * FROM characters WHERE username='" + client->username + "';"; 141 | std::unique_ptr charlist = std::make_unique(); 142 | database.Execute(sql_query.c_str(), get_characters, charlist.get()); 143 | 144 | client->characters = charlist->characters; 145 | } 146 | else 147 | { 148 | std::string errormsg = ""; 149 | 150 | if(client_logged != 0) errormsg = "Already logged in"; 151 | if(!valid_str) errormsg = "Please use alphanumeric characters only"; 152 | 153 | message = "Could not login! -[" + errormsg + "]-"; 154 | } 155 | 156 | std::cout << message << std::endl; 157 | 158 | sf::Packet reply; 159 | reply << (unsigned char)PacketID::Login; 160 | reply << (unsigned char)1; // sub id 161 | reply << answer; 162 | reply << message; 163 | if(request->valid) 164 | { 165 | std::size_t characters = client->characters.size(); 166 | reply << characters; 167 | for(std::size_t i = 0; i < characters; ++i) 168 | { 169 | reply << client->characters[i]->name; 170 | reply << (unsigned char)client->characters[i]->gender; 171 | } 172 | } 173 | client->Send(reply); 174 | } 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /game_engine/src/character.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "character.hpp" 4 | 5 | #include "gfx_loader.hpp" 6 | #include "client.hpp" 7 | 8 | #include 9 | #include 10 | 11 | Character::Character() 12 | { 13 | this->name = ""; 14 | this->map_id = 0; 15 | this->x = 0; 16 | this->y = 0; 17 | this->direction = (Direction)0; 18 | this->gender = Gender::Female; 19 | this->speed = 1; 20 | 21 | this->anim_state = AnimState::Stand; 22 | 23 | this->screen_x = 0; 24 | this->screen_y = 0; 25 | 26 | this->frame_counter = 0; 27 | } 28 | 29 | Character::Character(std::string name, unsigned int map_id, unsigned short x, unsigned short y) 30 | { 31 | this->name = name; 32 | this->map_id = map_id; 33 | this->x = x; 34 | this->y = y; 35 | this->direction = (Direction)0; 36 | this->gender = Gender::Female; 37 | this->speed = 1; 38 | 39 | this->anim_state = AnimState::Stand; 40 | 41 | this->screen_x = 0; 42 | this->screen_y = 0; 43 | 44 | this->frame_counter = 0; 45 | } 46 | 47 | void Character::Tick() 48 | { 49 | if(this->frame_counter >= 20 - this->speed) 50 | { 51 | this->frame_counter = 0; 52 | 53 | this->animation.Tick(); 54 | } 55 | 56 | if(!this->animation.play && this->animation.current_frame != 0) 57 | { 58 | if(this->anim_state == AnimState::Walk) 59 | { 60 | this->animation.Clear(); 61 | this->anim_state = AnimState::Stand; 62 | } 63 | else 64 | { 65 | this->animation.Clear(); 66 | } 67 | } 68 | 69 | this->frame_counter++; 70 | } 71 | 72 | void Character::Render(int rx, int ry) 73 | { 74 | GFXLoader gfx_loader; 75 | 76 | ALLEGRO_BITMAP *bitmap = NULL; 77 | int gfx_offset[3] = { 1, 1, 2 }; 78 | bitmap = gfx_loader.GetBitmap(8, gfx_offset[(int)this->anim_state]); 79 | 80 | int w = al_get_bitmap_width(bitmap); 81 | int h = al_get_bitmap_height(bitmap); 82 | 83 | int frames_per_anim[3] = { 1, 1, 4 }; 84 | int frames_total = frames_per_anim[(int)this->anim_state] * 4; 85 | 86 | int frame_w = w / frames_total; 87 | int frame_h = h; 88 | 89 | this->screen_x = this->x * 64 - this->x * 32 - this->y * 32 + rx; 90 | this->screen_y = this->y * 16 + this->x * 16 + ry; 91 | 92 | screen_x += 32; // half of the tile width 93 | screen_y -= frame_h; 94 | screen_y += 20; // correction for character position on the tile 95 | 96 | int position_off_x[4] = { -1, -1, 1, 1 }; 97 | int position_off_y[4] = { 1, -1, -1, 1 }; 98 | 99 | if(this->anim_state == AnimState::Walk) 100 | { 101 | screen_x += ((8 * (4 - (int)this->animation.current_frame)) * position_off_x[(int)this->direction]); 102 | screen_y += ((4 * (4 - (int)this->animation.current_frame)) * position_off_y[(int)this->direction]); 103 | } 104 | 105 | int dir = (int)this->direction; 106 | int gender_offset = (int)this->gender * (2 * (frame_w * frames_per_anim[(int)this->anim_state])); 107 | 108 | int dir_offset[4] = 109 | { (frame_w * frames_per_anim[(int)this->anim_state]) + gender_offset, gender_offset, gender_offset, 110 | (frame_w * frames_per_anim[(int)this->anim_state]) + gender_offset }; 111 | 112 | int frame_offset = frame_w * this->animation.current_frame; 113 | 114 | int cx = frame_w / 2; 115 | int cy = 0; 116 | float scale_offset[4] = { -1, -1, 1, 1 }; 117 | 118 | al_draw_tinted_scaled_rotated_bitmap_region(bitmap, dir_offset[dir] + frame_offset, 0, frame_w, frame_h, 119 | al_map_rgb(255, 255, 255), 120 | cx, cy, screen_x, screen_y, scale_offset[dir], 1, 0, 0); 121 | } 122 | 123 | void Character::RenderNew(int rx, int ry) 124 | { 125 | GFXLoader gfx_loader; 126 | 127 | ALLEGRO_BITMAP *bitmap = NULL; 128 | int gfx_offset[2] = { 1, 2 }; 129 | bitmap = gfx_loader.GetBitmap(8, gfx_offset[(int)this->gender], true, ".png"); 130 | 131 | int frame_w = 48; 132 | int frame_h = 84; 133 | 134 | this->screen_x = this->x * 64 - this->x * 32 - this->y * 32 + rx; 135 | this->screen_y = this->y * 16 + this->x * 16 + ry; 136 | 137 | if(this->anim_state == AnimState::Walk) 138 | { 139 | int walk_off_x[4] = { -1, -1, 1, 1 }; 140 | int walk_off_y[4] = { 1, -1, -1, 1 }; 141 | 142 | screen_x += ((8 * (4 - (int)this->animation.current_frame)) * walk_off_x[(int)this->direction]); 143 | screen_y += ((4 * (4 - (int)this->animation.current_frame)) * walk_off_y[(int)this->direction]); 144 | } 145 | 146 | screen_x += 32; // half of the tile width 147 | screen_y -= frame_h - 32; 148 | 149 | int dir = (int)this->direction; 150 | 151 | int f_offset_x = frame_w * this->animation.current_frame; 152 | int f_offset_y = 0; 153 | 154 | if(this->anim_state == AnimState::Stand) 155 | { 156 | int anim_offset_x[4] = { 1, 0, 0, 1 }; 157 | int dir_offset_x[4] = { frame_w * anim_offset_x[dir], 0, 0, frame_w * anim_offset_x[dir] }; 158 | 159 | f_offset_x += dir_offset_x[dir]; 160 | } 161 | if(this->anim_state == AnimState::Walk) 162 | { 163 | int dir_offset_y[4] = { frame_h * 2, frame_h, frame_h, frame_h * 2 }; 164 | 165 | f_offset_y += dir_offset_y[dir]; 166 | } 167 | 168 | int cx = frame_w / 2; 169 | int cy = 0; 170 | float scale_offset[4] = { -1, -1, 1, 1 }; 171 | 172 | al_draw_tinted_scaled_rotated_bitmap_region(bitmap, f_offset_x, f_offset_y, frame_w, frame_h, 173 | al_map_rgb(255, 255, 255), 174 | cx, cy, screen_x, screen_y, scale_offset[dir], 1, 0, 0); 175 | } 176 | 177 | std::vector Character::GetScreenPos() 178 | { 179 | std::vector ret; 180 | 181 | ret.push_back(this->screen_x); 182 | ret.push_back(this->screen_y); 183 | 184 | return ret; 185 | } 186 | 187 | void Character::Talk(unsigned char channel, std::string message, std::string char_name) 188 | { 189 | 190 | } 191 | 192 | void Character::Face(Direction direction) 193 | { 194 | if(this->animation.play || direction == this->direction) return; 195 | 196 | this->direction = direction; 197 | 198 | this->anim_state = AnimState::Stand; 199 | this->animation.Clear(); 200 | this->animation.frames.push_back(Animation::Frame(2)); 201 | this->animation.Play(); 202 | } 203 | 204 | void Character::Walk(Direction direction) 205 | { 206 | if(this->animation.play) return; 207 | 208 | this->direction = direction; 209 | 210 | if(this->direction == Direction::Up) this->y--; 211 | if(this->direction == Direction::Right) this->x++; 212 | if(this->direction == Direction::Down) this->y++; 213 | if(this->direction == Direction::Left) this->x--; 214 | 215 | this->anim_state = AnimState::Walk; 216 | this->animation.Clear(); 217 | this->animation.frames.push_back(Animation::Frame(1)); 218 | this->animation.frames.push_back(Animation::Frame(1)); 219 | this->animation.frames.push_back(Animation::Frame(1)); 220 | this->animation.frames.push_back(Animation::Frame(1)); 221 | this->animation.Play(); 222 | } 223 | -------------------------------------------------------------------------------- /game_engine/src/client.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "client.hpp" 4 | #include "handlers/init.hpp" 5 | 6 | #include 7 | 8 | bool Client::initialized_ = false; 9 | bool Client::connected; 10 | std::vector Client::recv_queue; 11 | std::vector Client::send_queue; 12 | 13 | std::unique_ptr Client::socket; 14 | PacketHandler Client::packet_handler; 15 | Client::State Client::state; 16 | 17 | std::vector> Client::characters; 18 | Character *Client::character; 19 | 20 | std::array Client::version; 21 | 22 | Client::Client() 23 | { 24 | if(!this->initialized_) 25 | { 26 | this->connected = false; 27 | this->state = State::Uninitialized; 28 | this->character = 0; 29 | 30 | this->version = { 0, 0, 1 }; 31 | 32 | this->initialized_ = true; 33 | } 34 | } 35 | 36 | bool Client::Connect(std::string address, unsigned short port) 37 | { 38 | sf::Socket::Status status; 39 | 40 | if(this->connected) return true; 41 | 42 | std::cout << "Client socket: Connecting to " << address << ":" << port << std::endl; 43 | this->socket.reset(new sf::TcpSocket()); 44 | status = this->socket->connect(address, port); 45 | 46 | if(status != sf::Socket::Done) 47 | { 48 | std::cout << "Client socket: can't connect." << std::endl; 49 | return false; 50 | } 51 | 52 | this->socket->setBlocking(false); 53 | this->connected = true; 54 | 55 | std::array ptr; 56 | ptr[0] = (intptr_t)this; 57 | 58 | this->packet_handler.Register(PacketID::Init, PacketHandlers::HInit::Main, ptr); 59 | 60 | this->characters.clear(); 61 | 62 | std::cout << "Client socket: Connected" << std::endl; 63 | 64 | this->Init(); 65 | 66 | return true; 67 | } 68 | 69 | void Client::Disconnect() 70 | { 71 | this->socket->disconnect(); 72 | this->connected = false; 73 | this->state = State::Uninitialized; 74 | this->characters.clear(); 75 | this->character = 0; 76 | } 77 | 78 | void Client::Tick() 79 | { 80 | sf::Packet packet; 81 | sf::Socket::Status status; 82 | 83 | if(!this->connected) return; 84 | 85 | if(!this->send_queue.empty()) 86 | { 87 | status = this->socket->send(this->send_queue[0]); 88 | 89 | switch(status) 90 | { 91 | case sf::Socket::Status::Done: 92 | this->send_queue.erase(this->send_queue.begin()); 93 | break; 94 | 95 | case sf::Socket::Status::NotReady: 96 | break; 97 | 98 | case sf::Socket::Status::Disconnected: 99 | this->connected = false; 100 | break; 101 | 102 | case sf::Socket::Status::Error: 103 | { 104 | this->connected = false; 105 | throw std::runtime_error("Client socket: error while sending data."); 106 | } 107 | break; 108 | 109 | default: 110 | break; 111 | } 112 | } 113 | 114 | status = this->socket->receive(packet); 115 | 116 | switch(status) 117 | { 118 | case sf::Socket::Status::Done: 119 | this->recv_queue.push_back(packet); 120 | break; 121 | 122 | case sf::Socket::Status::NotReady: 123 | break; 124 | 125 | case sf::Socket::Status::Disconnected: 126 | this->connected = false; 127 | break; 128 | 129 | case sf::Socket::Status::Error: 130 | { 131 | throw std::runtime_error("Client socket: error while receiving data."); 132 | } 133 | break; 134 | 135 | default: 136 | break; 137 | } 138 | 139 | 140 | if(!this->recv_queue.empty()) 141 | { 142 | packet = this->Recv(); 143 | this->packet_handler.Execute(packet); 144 | } 145 | } 146 | 147 | bool Client::Connected() 148 | { 149 | return this->connected; 150 | } 151 | 152 | void Client::Send(sf::Packet &packet) 153 | { 154 | this->send_queue.push_back(packet); 155 | } 156 | 157 | sf::Packet Client::Recv() 158 | { 159 | sf::Packet packet; 160 | 161 | if(!this->recv_queue.empty()) 162 | { 163 | packet = this->recv_queue[0]; 164 | this->recv_queue.erase(this->recv_queue.begin()); 165 | } 166 | 167 | return packet; 168 | } 169 | 170 | Character *Client::GetCharacter(std::string name) 171 | { 172 | for(std::size_t i = 0; i < this->characters.size(); ++i) 173 | { 174 | if(this->characters[i]->name == name) return this->characters[i].get(); 175 | } 176 | 177 | return 0; 178 | } 179 | 180 | void Client::RemoveCharacter(std::string name) 181 | { 182 | for(std::size_t i = 0; i < this->characters.size(); ++i) 183 | { 184 | if(this->characters[i]->name == name) 185 | { 186 | this->characters.erase(this->characters.begin() + i); 187 | return; 188 | } 189 | } 190 | } 191 | 192 | void Client::Init() 193 | { 194 | sf::Packet packet; 195 | 196 | packet << (unsigned char)PacketID::Init; 197 | 198 | for(int i = 0; i < 3; ++i) 199 | { 200 | packet << this->version[i]; 201 | } 202 | 203 | this->Send(packet); 204 | } 205 | 206 | void Client::Login(std::string username, std::string password) 207 | { 208 | sf::Packet packet; 209 | 210 | packet << (unsigned char)PacketID::Login; 211 | packet << (unsigned char)1; // sub id = login request 212 | packet << username; 213 | packet << password; 214 | 215 | this->Send(packet); 216 | } 217 | 218 | void Client::CreateAccount(std::array input_data) 219 | { 220 | sf::Packet packet; 221 | 222 | packet << (unsigned char)PacketID::Account; 223 | packet << (unsigned char)1; // sub id 224 | for(int i = 0; i < 5; ++i) 225 | { 226 | packet << input_data[i]; 227 | } 228 | 229 | this->Send(packet); 230 | } 231 | 232 | void Client::CreateCharacter(std::string name, Gender gender) 233 | { 234 | sf::Packet packet; 235 | 236 | packet << (unsigned char)PacketID::Character; 237 | packet << (unsigned char)1; // sub id - create 238 | packet << name; 239 | packet << (unsigned char)gender; 240 | 241 | this->Send(packet); 242 | } 243 | 244 | void Client::DeleteCharacter(std::string name) 245 | { 246 | sf::Packet packet; 247 | 248 | packet << (unsigned char)PacketID::Character; 249 | packet << (unsigned char)2; // sub id - delete 250 | packet << name; 251 | 252 | this->Send(packet); 253 | } 254 | 255 | void Client::CharacterList() 256 | { 257 | sf::Packet packet; 258 | 259 | packet << (unsigned char)PacketID::Character; 260 | packet << (unsigned char)3; // sub id - character list 261 | 262 | this->Send(packet); 263 | } 264 | 265 | void Client::SelectCharacter(std::string name) 266 | { 267 | sf::Packet packet; 268 | 269 | packet << (unsigned char)PacketID::Character; 270 | packet << (unsigned char)4; // sub id - select 271 | packet << name; 272 | 273 | this->Send(packet); 274 | } 275 | 276 | void Client::Talk(unsigned char channel, std::string message, std::string char_name) 277 | { 278 | sf::Packet packet; 279 | 280 | packet << (unsigned char)PacketID::Character; 281 | packet << (unsigned char)5; 282 | packet << channel; 283 | packet << message; 284 | 285 | this->Send(packet); 286 | } 287 | 288 | void Client::Face(Direction direction) 289 | { 290 | sf::Packet packet; 291 | 292 | packet << (unsigned char)PacketID::Character; 293 | packet << (unsigned char)6; 294 | packet << (unsigned char)direction; 295 | 296 | this->Send(packet); 297 | } 298 | 299 | void Client::Walk(Direction direction) 300 | { 301 | sf::Packet packet; 302 | 303 | packet << (unsigned char)PacketID::Character; 304 | packet << (unsigned char)7; 305 | packet << (unsigned char)direction; 306 | 307 | this->Send(packet); 308 | } 309 | 310 | void Client::GetInRange(std::string name) 311 | { 312 | sf::Packet packet; 313 | 314 | packet << (unsigned char)PacketID::Character; 315 | packet << (unsigned char)8; 316 | packet << name; 317 | 318 | this->Send(packet); 319 | } 320 | 321 | void Client::GetInRange(unsigned int index) 322 | { 323 | sf::Packet packet; 324 | 325 | packet << (unsigned char)PacketID::NPC; 326 | packet << (unsigned char)2; 327 | packet << index; 328 | 329 | this->Send(packet); 330 | } 331 | -------------------------------------------------------------------------------- /server_engine/src/server.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "server.hpp" 4 | 5 | #include "handlers/init.hpp" 6 | #include "const/packet.hpp" 7 | #include "map_handler.hpp" 8 | #include "database.hpp" 9 | #include "util.hpp" 10 | 11 | #include 12 | #include 13 | 14 | bool Server::initialized_ = false; 15 | sf::TcpListener Server::listener; 16 | std::vector> Server::sockets; 17 | std::vector> Server::clients; 18 | std::array Server::client_version; 19 | Config Server::config; 20 | Config Server::welcome_msg; 21 | 22 | Server::Server() 23 | { 24 | if(!this->initialized_) 25 | { 26 | this->client_version = { 0, 0, 1 }; 27 | 28 | this->welcome_msg.Load("data/welcome.ini"); 29 | 30 | this->initialized_ = true; 31 | } 32 | } 33 | 34 | Server::Server(unsigned short port) 35 | { 36 | if(!this->initialized_) 37 | { 38 | this->client_version = { 0, 0, 1 }; 39 | 40 | this->listener.listen(port); 41 | this->listener.setBlocking(false); 42 | 43 | this->welcome_msg.Load("data/welcome.ini"); 44 | 45 | this->initialized_ = true; 46 | 47 | std::cout << "Listening on port " << port << "..." << std::endl; 48 | } 49 | } 50 | 51 | void Server::Tick() 52 | { 53 | std::shared_ptr socket = std::shared_ptr(new sf::TcpSocket()); 54 | 55 | sf::Socket::Status status = this->listener.accept(*socket); 56 | 57 | if(status == sf::Socket::Done) 58 | { 59 | std::array ptr; 60 | std::shared_ptr client = std::shared_ptr(new Client()); 61 | 62 | socket->setBlocking(false); 63 | client->socket = socket; 64 | this->sockets.push_back(socket); 65 | this->clients.push_back(client); 66 | 67 | ptr[0] = (intptr_t)this->clients[this->clients.size() - 1].get(); 68 | client->packet_handler.Register(PacketID::Init, PacketHandlers::HInit::Main, ptr); 69 | 70 | std::cout << "New client accepted (" << this->clients.size() << ")" << std::endl; 71 | } 72 | else if(status == sf::Socket::Error) 73 | { 74 | throw std::runtime_error("Server: socket error."); 75 | } 76 | 77 | std::vector, int>> dead_clients; 78 | for(std::size_t i = 0; i < this->clients.size(); ++i) 79 | { 80 | this->clients[i]->Tick(); 81 | if(!this->clients[i]->Connected()) 82 | { 83 | Database database; 84 | if(this->clients[i]->state == Client::State::Logged_in) 85 | { 86 | for(std::size_t ii = 0; ii < this->clients[i]->characters.size(); ++ii) 87 | { 88 | Character *chracter = this->clients[i]->characters[ii].get(); 89 | 90 | std::string sql_query = "UPDATE characters SET "; 91 | sql_query += "map_id = " + std::to_string(chracter->map_id); 92 | sql_query += ", x = " + std::to_string(chracter->x); 93 | sql_query += ", y = " + std::to_string(chracter->y); 94 | sql_query += ", direction = " + std::to_string((int)chracter->direction); 95 | sql_query += ", gender = " + std::to_string((int)chracter->gender); 96 | 97 | sql_query += " WHERE name = '" + chracter->name + "';"; 98 | 99 | std::cout << sql_query << std::endl; 100 | 101 | database.Execute(sql_query.c_str(), 0, 0); 102 | } 103 | } 104 | if(this->clients[i]->state == Client::State::Playing) 105 | { 106 | for(std::size_t ii = 0; ii < this->clients[i]->characters.size(); ++ii) 107 | { 108 | if(this->clients[i]->characters[ii]->name == this->clients[i]->selected_character) continue; 109 | 110 | Character *character = this->clients[i]->characters[ii].get(); 111 | 112 | std::string sql_query = "UPDATE characters SET "; 113 | sql_query += "map_id = " + std::to_string(character->map_id); 114 | sql_query += ", x = " + std::to_string(character->x); 115 | sql_query += ", y = " + std::to_string(character->y); 116 | sql_query += ", direction = " + std::to_string((int)character->direction); 117 | sql_query += ", gender = " + std::to_string((int)character->gender); 118 | sql_query += ", speed = " + std::to_string(character->speed); 119 | 120 | sql_query += " WHERE name = '" + character->name + "';"; 121 | 122 | std::cout << sql_query << std::endl; 123 | 124 | database.Execute(sql_query.c_str(), 0, 0); 125 | 126 | Map *map = MapHandler().GetMap(this->clients[i]->map_id); 127 | map->DeleteCharacter(character->name); 128 | } 129 | 130 | Map *map = MapHandler().GetMap(this->clients[i]->map_id); 131 | Character *character = map->GetCharacter(this->clients[i]->selected_character); 132 | 133 | std::string sql_query = "UPDATE characters SET "; 134 | sql_query += "map_id = " + std::to_string(character->map_id); 135 | sql_query += ", x = " + std::to_string(character->x); 136 | sql_query += ", y = " + std::to_string(character->y); 137 | sql_query += ", direction = " + std::to_string((int)character->direction); 138 | sql_query += ", gender = " + std::to_string((int)character->gender); 139 | sql_query += ", speed = " + std::to_string(character->speed); 140 | 141 | sql_query += " WHERE name = '" + character->name + "';"; 142 | 143 | std::cout << sql_query << std::endl; 144 | 145 | database.Execute(sql_query.c_str(), 0, 0); 146 | 147 | sf::Packet packet; 148 | packet << (unsigned char)PacketID::Map; 149 | packet << (unsigned char)2; // leave 150 | packet << character->name; 151 | 152 | std::vector> chars_in_range; 153 | for(auto &it : map->characters) 154 | { 155 | if(it->name == character->name) continue; 156 | 157 | int len = path_length(character->x, character->y, it->x, it->y); 158 | 159 | if(len < 13) 160 | { 161 | Client *char_client = this->GetClientByChar(it->name); 162 | char_client->Send(packet); 163 | 164 | it->DeleteInRange(character->name); 165 | } 166 | } 167 | 168 | map->DeleteCharacter(character->name); 169 | } 170 | 171 | int socket_index = -1; 172 | for(std::size_t iii = 0; iii < this->sockets.size(); ++iii) 173 | { 174 | if(this->sockets[iii] == this->clients[i]->socket) 175 | { 176 | socket_index = iii; 177 | break; 178 | } 179 | } 180 | 181 | if(socket_index != -1) 182 | { 183 | this->sockets.erase(this->sockets.begin() + socket_index); 184 | this->clients.erase(this->clients.begin() + i); 185 | } 186 | 187 | std::cout << "Client disconnected." << std::endl; 188 | break; 189 | } 190 | } 191 | 192 | MapHandler map_handler; 193 | 194 | for(auto &it : map_handler.maps) 195 | { 196 | it.second.Tick(); 197 | } 198 | } 199 | 200 | Client *Server::GetClientByChar(std::string char_name) 201 | { 202 | for(std::size_t i = 0; i < this->clients.size(); ++i) 203 | { 204 | if(this->clients[i]->selected_character == "") continue; 205 | 206 | Map *map = MapHandler().GetMap(this->clients[i]->map_id); 207 | Character *character = map->GetCharacter(this->clients[i]->selected_character); 208 | 209 | if(character->name == char_name) 210 | { 211 | return this->clients[i].get(); 212 | } 213 | } 214 | 215 | return 0; 216 | } 217 | 218 | Client *Server::GetClientByAcc(std::string acc_name) 219 | { 220 | for(std::size_t i = 0; i < this->clients.size(); ++i) 221 | { 222 | if(this->clients[i]->username == "") continue; 223 | 224 | if(this->clients[i]->username == acc_name) 225 | { 226 | return this->clients[i].get(); 227 | } 228 | } 229 | 230 | return 0; 231 | } 232 | 233 | std::array Server::GetClientVersion() 234 | { 235 | return this->client_version; 236 | } 237 | -------------------------------------------------------------------------------- /game_engine/src/main.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "const/packet.hpp" 4 | #include "util.hpp" 5 | #include "config.hpp" 6 | #include "game_state.hpp" 7 | #include "client.hpp" 8 | #include "input_handler.hpp" 9 | #include "gui.hpp" 10 | #include "map.hpp" 11 | #include "map_cursor.hpp" 12 | #include "map_editor.hpp" 13 | #include "font_handler.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "imgui_impl_a5.h" 22 | #include 23 | #include 24 | #include 25 | 26 | int main(int, char**) 27 | { 28 | const float FPS = 60.0f; 29 | 30 | try 31 | { 32 | ALLEGRO_DISPLAY* display = NULL; 33 | ALLEGRO_EVENT_QUEUE* event_queue = NULL; 34 | ALLEGRO_TIMER *fps_timer = NULL; 35 | ALLEGRO_TIMER *input_timer = NULL; 36 | ALLEGRO_TIMER *update_timer = NULL; 37 | 38 | Config config("./data/config.ini"); 39 | 40 | std::vector args = GetArgs(config.GetValue("Resolution")); 41 | int screen_width = std::atoi(args[0].c_str()); 42 | int screen_height = std::atoi(args[1].c_str()); 43 | 44 | int flags = config.GetValue("Fullscreen") == "yes"? ALLEGRO_FULLSCREEN : ALLEGRO_WINDOWED; 45 | 46 | al_init(); 47 | al_install_keyboard(); 48 | al_install_mouse(); 49 | al_init_primitives_addon(); 50 | al_init_image_addon(); 51 | al_init_font_addon(); 52 | al_init_ttf_addon(); 53 | 54 | al_set_new_display_flags(flags); 55 | display = al_create_display(screen_width, screen_height); 56 | if(!display) 57 | { 58 | throw std::runtime_error("Could not create display!"); 59 | } 60 | al_set_window_title(display, "game engine"); 61 | 62 | event_queue = al_create_event_queue(); 63 | if(!event_queue) 64 | { 65 | throw std::runtime_error("Could not create event queue!"); 66 | } 67 | 68 | fps_timer = al_create_timer(1.0 / FPS); 69 | input_timer = al_create_timer(0.01); 70 | update_timer = al_create_timer(0.006); 71 | if(!fps_timer) 72 | { 73 | throw std::runtime_error("Could not create timers!"); 74 | } 75 | al_register_event_source(event_queue, al_get_display_event_source(display)); 76 | al_register_event_source(event_queue, al_get_keyboard_event_source()); 77 | al_register_event_source(event_queue, al_get_mouse_event_source()); 78 | al_register_event_source(event_queue, al_get_timer_event_source(fps_timer)); 79 | al_register_event_source(event_queue, al_get_timer_event_source(input_timer)); 80 | al_register_event_source(event_queue, al_get_timer_event_source(update_timer)); 81 | al_start_timer(fps_timer); 82 | al_start_timer(input_timer); 83 | al_start_timer(update_timer); 84 | 85 | float sx = screen_width / (float)640; 86 | float sy = screen_height / (float)480; 87 | 88 | ALLEGRO_TRANSFORM trans; 89 | al_identity_transform(&trans); 90 | al_scale_transform(&trans, sx, sy); 91 | al_use_transform(&trans); 92 | 93 | ALLEGRO_COLOR clear_color = al_map_rgb(0, 0, 0); 94 | 95 | ImGui_ImplA5_Init(display); 96 | 97 | GameState game_state; 98 | InputHandler input_handler; 99 | Client client; 100 | GFXLoader gfx_loader("./data/gfx/"); 101 | GUI gui; 102 | Map map; 103 | MapCursor map_cursor; 104 | MapEditor map_editor; 105 | FontHandler font_handler; 106 | 107 | std::array version = client.version; 108 | 109 | std::cout << "Endless Online Awaken Client v" << version[0] << "." << version[1] << "." << version[2] << 110 | " pre-alpha." << std::endl << std::endl; 111 | 112 | while(game_state.Get() != GameState::State::Exit) 113 | { 114 | ALLEGRO_EVENT event; 115 | ALLEGRO_TIMEOUT timeout; 116 | al_init_timeout(&timeout, 0.06); 117 | bool redraw = false; 118 | 119 | client.Tick(); 120 | 121 | bool get_event = al_wait_for_event_until(event_queue, &event, &timeout); 122 | if(get_event) 123 | { 124 | ImGui_ImplA5_ProcessEvent(&event); 125 | 126 | if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) game_state.Set(GameState::State::Exit); 127 | if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) 128 | { 129 | ImGui_ImplA5_InvalidateDeviceObjects(); 130 | al_acknowledge_resize(display); 131 | Imgui_ImplA5_CreateDeviceObjects(); 132 | } 133 | 134 | if(event.type == ALLEGRO_EVENT_KEY_DOWN || event.type == ALLEGRO_EVENT_KEY_UP || 135 | event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN || event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 136 | { 137 | input_handler.ProcessEvent(event); 138 | 139 | if(input_handler.keys[ALLEGRO_KEY_ESCAPE]) 140 | { 141 | if(gui.GetState() != GUI::State::MainMenu) 142 | { 143 | gui.SetState(GUI::State::MainMenu); 144 | if(client.Connected()) client.Disconnect(); 145 | game_state.Set(GameState::State::MainMenu); 146 | } 147 | else 148 | { 149 | game_state.Set(GameState::State::Exit); 150 | } 151 | } 152 | } 153 | 154 | if(event.type == ALLEGRO_EVENT_TIMER) 155 | { 156 | if(event.timer.source == fps_timer) 157 | { 158 | redraw = true; 159 | } 160 | if(event.timer.source == input_timer) 161 | { 162 | input_handler.Process(); 163 | 164 | if(input_handler.keys[ALLEGRO_KEY_F9] && gui.GetState() == GUI::State::MainMenu) 165 | { 166 | gui.SetState(GUI::State::Editor); 167 | } 168 | 169 | if(gui.GetState() == GUI::State::Editor) map_editor.ProcessInput(); 170 | } 171 | if(event.timer.source == update_timer) 172 | { 173 | map.Tick(); 174 | } 175 | } 176 | } 177 | 178 | if(redraw && al_is_event_queue_empty(event_queue)) 179 | { 180 | ImGui_ImplA5_NewFrame(); 181 | 182 | al_clear_to_color(clear_color); 183 | 184 | if(map.id != 0) 185 | { 186 | int screen_x = al_get_display_width(display) / 2 - 32;; 187 | int screen_y = (320 / 2) - 16; // 320 = render screen height + 10 188 | 189 | if(client.character != 0) 190 | { 191 | screen_x -= client.character->x * 64 - client.character->x * 32 - client.character->y * 32; 192 | screen_y -= client.character->y * 16 + client.character->x * 16; 193 | 194 | if(client.character->anim_state == Character::AnimState::Walk) 195 | { 196 | int position_off_x[4] = { -1, -1, 1, 1 }; 197 | int position_off_y[4] = { 1, -1, -1, 1 }; 198 | 199 | int dir_off_x = position_off_x[(int)client.character->direction]; 200 | int dir_off_y = position_off_y[(int)client.character->direction]; 201 | 202 | screen_x -= ((8 * (4 - (int)client.character->animation.current_frame)) * dir_off_x); 203 | screen_y -= ((4 * (4 - (int)client.character->animation.current_frame)) * dir_off_y); 204 | } 205 | } 206 | 207 | if(gui.GetState() == GUI::State::Editor) 208 | { 209 | screen_x += map_editor.render_xoff; 210 | screen_y += map_editor.render_yoff; 211 | } 212 | 213 | map.Render(screen_x, screen_y); 214 | } 215 | 216 | if(!client.Connected() && client.state != Client::State::Uninitialized) 217 | { 218 | client.state = Client::State::Uninitialized; 219 | ImGui::OpenPopup("Disconnected"); 220 | } 221 | 222 | gui.Process(); 223 | gui.Render(); 224 | 225 | al_flip_display(); 226 | } 227 | 228 | al_rest(0.0000005); 229 | } 230 | 231 | ImGui_ImplA5_Shutdown(); 232 | al_destroy_event_queue(event_queue); 233 | al_destroy_display(display); 234 | } 235 | catch(std::runtime_error rt_err) 236 | { 237 | std::cout << "Runtime error: " << rt_err.what() << std::endl; 238 | std::ofstream file("errorlog.txt", std::ios::trunc); 239 | if(file.is_open() && file.good()) 240 | { 241 | file << rt_err.what() << std::endl; 242 | file.close(); 243 | } 244 | } 245 | 246 | return 0; 247 | } 248 | -------------------------------------------------------------------------------- /game_engine/src/handlers/h_character.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "h_character.hpp" 4 | 5 | #include "h_map.hpp" 6 | #include "h_npc.hpp" 7 | #include "file_data.hpp" 8 | #include "../client.hpp" 9 | #include "../gui.hpp" 10 | #include "../map.hpp" 11 | #include "../game_state.hpp" 12 | 13 | #include 14 | 15 | namespace PacketHandlers::HCharacter 16 | { 17 | void Main(sf::Packet &packet, std::array data_ptr) 18 | { 19 | Client client; 20 | 21 | unsigned char sub_id = 0; 22 | 23 | packet >> sub_id; 24 | 25 | if(sub_id == 1) // create character 26 | { 27 | Create(packet, data_ptr); 28 | } 29 | if(sub_id == 2) 30 | { 31 | Delete(packet, data_ptr); 32 | } 33 | if(sub_id == 3) // character list 34 | { 35 | List(packet, data_ptr); 36 | } 37 | if(sub_id == 4) // select character 38 | { 39 | Select(packet, data_ptr); 40 | } 41 | if(sub_id == 5) 42 | { 43 | Talk(packet, data_ptr); 44 | } 45 | if(sub_id == 6) 46 | { 47 | Face(packet, data_ptr); 48 | } 49 | if(sub_id == 7) 50 | { 51 | Walk(packet, data_ptr); 52 | } 53 | } 54 | 55 | void Create(sf::Packet &packet, std::array data_ptr) 56 | { 57 | Client client; 58 | unsigned char answer = 0; 59 | std::string message; 60 | 61 | packet >> answer; 62 | packet >> message; 63 | 64 | if(answer == 1) 65 | { 66 | std::size_t characters = 0; 67 | 68 | packet >> characters; 69 | 70 | client.characters.clear(); 71 | for(std::size_t i = 0; i < characters; ++i) 72 | { 73 | std::shared_ptr character = std::shared_ptr(new Character()); 74 | 75 | packet >> character->name; 76 | unsigned char gender = 0; 77 | packet >> gender; 78 | character->gender = (Gender)gender; 79 | 80 | client.characters.push_back(character); 81 | } 82 | 83 | 84 | GUI().OpenPopup("Character created"); 85 | } 86 | else 87 | { 88 | GUI().OpenPopup("Server answer", message); 89 | } 90 | } 91 | 92 | void Delete(sf::Packet &packet, std::array data_ptr) 93 | { 94 | Client client; 95 | unsigned char answer = 0; 96 | std::string message = ""; 97 | 98 | packet >> answer; 99 | packet >> message; 100 | 101 | if(answer == 1) 102 | { 103 | std::string name = ""; 104 | packet >> name; 105 | 106 | client.RemoveCharacter(name); 107 | } 108 | 109 | GUI().OpenPopup("Server answer", message); 110 | } 111 | 112 | void List(sf::Packet &packet, std::array data_ptr) 113 | { 114 | Client client; 115 | 116 | std::size_t slots = 0; 117 | packet >> slots; 118 | for(std::size_t i = 0; i < slots; ++i) 119 | { 120 | std::string name = ""; 121 | unsigned char gender = 0; 122 | 123 | packet >> name; 124 | packet >> gender; 125 | 126 | std::shared_ptr character = std::shared_ptr(new Character()); 127 | character->name = name; 128 | character->gender = (Gender)gender; 129 | 130 | client.characters.push_back(character); 131 | } 132 | } 133 | 134 | void Select(sf::Packet &packet, std::array data_ptr) 135 | { 136 | Client client; 137 | unsigned char answer = 0; 138 | std::string message = ""; 139 | 140 | packet >> answer; 141 | packet >> message; 142 | 143 | if(answer == 1) 144 | { 145 | Map map; 146 | 147 | client.state = Client::State::Playing; 148 | GUI().SetState(GUI::State::Playing); 149 | GameState().Set(GameState::State::Playing); 150 | 151 | client.packet_handler.Register(PacketID::Map, PacketHandlers::HMap::Main, data_ptr); 152 | client.packet_handler.Register(PacketID::NPC, PacketHandlers::HNPC::Main, data_ptr); 153 | client.packet_handler.Register(PacketID::FileData, PacketHandlers::FileData::Main, data_ptr); 154 | 155 | Character character; 156 | packet >> character.name; 157 | packet >> character.map_id; 158 | 159 | map.Load(character.map_id); 160 | 161 | std::size_t chars_in_range = 0; 162 | 163 | packet >> chars_in_range; 164 | 165 | for(std::size_t i = 0; i < chars_in_range; ++i) 166 | { 167 | std::shared_ptr character = std::shared_ptr(new Character()); 168 | 169 | unsigned char buf = 0; 170 | packet >> character->name; 171 | packet >> character->map_id; 172 | packet >> character->x; 173 | packet >> character->y; 174 | packet >> buf; character->direction = (Direction)buf; 175 | packet >> buf; character->gender = (Gender)buf; 176 | packet >> character->speed; 177 | 178 | map.characters.push_back(character); 179 | } 180 | 181 | client.character = map.GetCharacter(character.name); 182 | 183 | std::size_t npcs_in_range = 0; 184 | 185 | packet >> npcs_in_range; 186 | 187 | for(std::size_t i = 0; i < npcs_in_range; ++i) 188 | { 189 | std::shared_ptr npc = std::shared_ptr(new NPC()); 190 | 191 | packet >> npc->id; 192 | packet >> npc->index; 193 | packet >> npc->map_id; 194 | packet >> npc->x; 195 | packet >> npc->y; 196 | unsigned char dir = 0; 197 | packet >> dir; npc->direction = (Direction)dir; 198 | packet >> npc->speed; 199 | 200 | map.npcs.push_back(npc); 201 | } 202 | } 203 | if(answer == 2) 204 | { 205 | unsigned int revision = 0; 206 | Map map; 207 | 208 | packet >> revision; 209 | 210 | while(!packet.endOfPacket()) 211 | { 212 | std::string message = ""; 213 | 214 | packet >> message; 215 | 216 | Chat().AddMessage("Server", message); 217 | } 218 | 219 | unsigned char answer = 0; 220 | 221 | if(revision == map.revision) 222 | { 223 | answer = 1; 224 | } 225 | else 226 | { 227 | answer = 2; 228 | } 229 | 230 | if(answer == 2) 231 | { 232 | sf::Packet reply; 233 | 234 | reply << (unsigned char)PacketID::FileData; 235 | reply << (unsigned char)1; // map file 236 | reply << map.id; 237 | 238 | client.Send(reply); 239 | } 240 | } 241 | 242 | std::cout << message << std::endl; 243 | } 244 | 245 | void Talk(sf::Packet &packet, std::array data_ptr) 246 | { 247 | unsigned char channel = 0; 248 | std::string char_name = ""; 249 | std::string message = ""; 250 | 251 | packet >> channel; 252 | packet >> char_name; 253 | packet >> message; 254 | 255 | Chat().AddMessage(char_name, message); 256 | } 257 | 258 | void Face(sf::Packet &packet, std::array data_ptr) 259 | { 260 | std::string name = ""; 261 | unsigned short source_x = 0; 262 | unsigned short source_y = 0; 263 | unsigned char buf = 0; 264 | 265 | packet >> name; 266 | packet >> buf; 267 | Direction direction = (Direction)buf; 268 | packet >> source_x; 269 | packet >> source_y; 270 | 271 | Character *character = Map().GetCharacter(name); 272 | 273 | if(character == 0) 274 | { 275 | Client().GetInRange(name); 276 | return; 277 | } 278 | 279 | if(character->anim_state != Character::AnimState::Walk && character->anim_state != Character::AnimState::Attack) 280 | { 281 | character->direction = direction; 282 | character->x = source_x; 283 | character->y = source_y; 284 | } 285 | 286 | character->Face(direction); 287 | } 288 | 289 | void Walk(sf::Packet &packet, std::array data_ptr) 290 | { 291 | std::string name = ""; 292 | unsigned short source_x = 0; 293 | unsigned short source_y = 0; 294 | unsigned char buf = 0; 295 | 296 | packet >> name; 297 | packet >> buf; 298 | Direction direction = (Direction)buf; 299 | packet >> source_x; 300 | packet >> source_y; 301 | 302 | Character *character = Map().GetCharacter(name); 303 | 304 | if(character == 0) 305 | { 306 | Client().GetInRange(name); 307 | return; 308 | } 309 | 310 | character->direction = direction; 311 | character->x = source_x; 312 | character->y = source_y; 313 | 314 | if(character->name == Client().character->name) 315 | { 316 | if(character->direction == Direction::Up) character->y--; 317 | if(character->direction == Direction::Right) character->x++; 318 | if(character->direction == Direction::Down) character->y++; 319 | if(character->direction == Direction::Left) character->x--; 320 | } 321 | 322 | character->Walk(direction); 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /server_engine/src/map.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "map.hpp" 4 | 5 | #include "file_handler.hpp" 6 | #include "client.hpp" 7 | #include "server.hpp" 8 | #include "util.hpp" 9 | 10 | #include 11 | #include 12 | 13 | Map::Layer::Layer() 14 | { 15 | this->type = Type::Ground; 16 | } 17 | 18 | Map::Map() 19 | { 20 | this->exists = false; 21 | this->id = 0; 22 | this->name = ""; 23 | this->revision = 0; 24 | this->width = 1; 25 | this->height = 1; 26 | this->fill_tile = 0; 27 | 28 | this->npc_clock.restart(); 29 | } 30 | 31 | Map::Map(unsigned int id) 32 | { 33 | this->Load(id); 34 | } 35 | 36 | bool Map::Load(unsigned int id) 37 | { 38 | this->Reset(); 39 | this->exists = false; 40 | 41 | this->id = id; 42 | 43 | if(this->id == 0) 44 | { 45 | throw std::runtime_error("Map: can't load map, ID #0 is reserved."); 46 | } 47 | 48 | std::string filename = "data/maps/" + std::to_string(this->id) + ".map"; 49 | FileHandler fh(filename); 50 | 51 | this->exists = fh.Exists(); 52 | 53 | if(!this->exists) return false; 54 | 55 | this->name = fh.GetString(); 56 | this->revision = fh.GetInt(); 57 | this->width = fh.GetShort(); 58 | this->height = fh.GetShort(); 59 | this->fill_tile = fh.GetInt(); 60 | 61 | unsigned char read_tile = fh.GetChar(); 62 | 63 | while(read_tile == 1) 64 | { 65 | std::shared_ptr tile = std::shared_ptr(new Tile()); 66 | 67 | tile->graphic_id = fh.GetInt(); 68 | tile->x = fh.GetShort(); 69 | tile->y = fh.GetShort(); 70 | Layer::Type layer_type = (Layer::Type)fh.GetChar(); 71 | 72 | this->layers[(Layer::Type)layer_type].tiles[tile->x][tile->y] = tile; 73 | 74 | read_tile = fh.GetChar(); 75 | } 76 | 77 | read_tile = fh.GetChar(); 78 | 79 | while(read_tile == 1) 80 | { 81 | std::shared_ptr att = std::shared_ptr(new Attribute()); 82 | 83 | att->type = (Attribute::Type)fh.GetChar(); 84 | att->x = fh.GetShort(); 85 | att->y = fh.GetShort(); 86 | 87 | this->atts[att->x][att->y] = att; 88 | 89 | read_tile = fh.GetChar(); 90 | } 91 | 92 | std::cout << "Map loaded: '" << this->name << "' " << this->width << "x" << this->height << std::endl; 93 | 94 | return true; 95 | } 96 | 97 | void Map::Save() 98 | { 99 | if(this->id == 0) 100 | { 101 | throw std::runtime_error("Map: can't save map, ID #0 is reserved."); 102 | } 103 | 104 | std::ofstream file; 105 | std::string filename = "data/maps/" + std::to_string(this->id) + ".map"; 106 | FileHandler fh; 107 | 108 | fh.AddString(this->name); 109 | fh.AddInt(++this->revision); 110 | fh.AddShort(this->width); 111 | fh.AddShort(this->height); 112 | fh.AddInt(this->fill_tile); 113 | 114 | for(auto &l : this->layers) 115 | { 116 | for(auto &t : l.second.tiles) 117 | { 118 | for(auto &tt : t.second) 119 | { 120 | std::shared_ptr tile = tt.second; 121 | 122 | if(tile == 0) continue; 123 | 124 | fh.AddChar(1); 125 | fh.AddInt(tile->graphic_id); 126 | fh.AddShort(tile->x); 127 | fh.AddShort(tile->y); 128 | fh.AddChar((unsigned int)l.first); 129 | } 130 | } 131 | } 132 | 133 | fh.AddChar(0); 134 | 135 | for(auto &a : this->atts) 136 | { 137 | for(auto &aa : a.second) 138 | { 139 | std::shared_ptr att = aa.second; 140 | 141 | if(att == 0) continue; 142 | 143 | fh.AddChar(1); 144 | fh.AddChar((unsigned int)att->type); 145 | fh.AddShort(att->x); 146 | fh.AddShort(att->y); 147 | } 148 | } 149 | 150 | fh.AddChar(0); 151 | 152 | fh.Save(filename); 153 | this->exists = fh.Exists(); 154 | } 155 | 156 | void Map::Tick() 157 | { 158 | for(auto &it : this->characters) 159 | { 160 | it->Tick(); 161 | } 162 | 163 | for(auto &it : this->npcs) 164 | { 165 | it->Tick(); 166 | 167 | /*if(it->anim_state == NPC::AnimState::Stand) 168 | { 169 | Direction direction = (Direction)RandGen().RandInt(0, 3); 170 | 171 | if(direction == Direction::Up && it->y == 0) continue; 172 | if(direction == Direction::Right && it->x == this->width - 1) continue; 173 | if(direction == Direction::Down && it->y == this->height - 1) continue; 174 | if(direction == Direction::Left && it->x == 0) continue; 175 | 176 | unsigned int walk_x = it->x; 177 | unsigned int walk_y = it->y; 178 | 179 | if(direction == Direction::Up) walk_y--; 180 | if(direction == Direction::Right) walk_x++; 181 | if(direction == Direction::Down) walk_y++; 182 | if(direction == Direction::Left) walk_x--; 183 | 184 | if(!this->Walkable(walk_x, walk_y)) continue; 185 | 186 | it->Walk(direction); 187 | 188 | std::vector> chars_in_range; 189 | for(auto &it : this->characters) 190 | { 191 | int len = path_length(it->x, it->y, it->x, it->y); 192 | 193 | if(len < 13) 194 | { 195 | chars_in_range.push_back(it); 196 | } 197 | } 198 | 199 | for(auto &charr : chars_in_range) 200 | { 201 | Client *client = Server().GetClientByChar(charr->name); 202 | 203 | sf::Packet packet; 204 | 205 | packet << (unsigned int)PacketID::NPC; 206 | packet << (unsigned int)5; // walk 207 | packet << it->index; 208 | packet << (unsigned int)it->direction; 209 | packet << it->x; 210 | packet << it->y; 211 | 212 | client->Send(packet); 213 | } 214 | }*/ 215 | } 216 | 217 | if(this->npc_clock.getElapsedTime().asMilliseconds() >= 460) this->npc_clock.restart(); 218 | } 219 | 220 | void Map::Reset() 221 | { 222 | this->id = 0; 223 | this->name.clear(); 224 | this->revision = 0; 225 | this->width = 1; 226 | this->height = 1; 227 | this->fill_tile = 0; 228 | 229 | this->layers.clear(); 230 | this->atts.clear(); 231 | this->characters.clear(); 232 | 233 | this->npc_clock.restart(); 234 | } 235 | 236 | std::vector Map::GetCharactersAt(unsigned short x, unsigned short y) 237 | { 238 | std::vector ret; 239 | 240 | for(auto &it: characters) 241 | { 242 | if(it->x == x && it->y == y) 243 | { 244 | ret.push_back(it.get()); 245 | } 246 | } 247 | 248 | return ret; 249 | } 250 | 251 | Character *Map::GetCharacter(std::string name) 252 | { 253 | for(auto &it: characters) 254 | { 255 | if(it->name == name) 256 | return it.get(); 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | void Map::DeleteCharacter(std::string name) 263 | { 264 | for(std::size_t i = 0; i < this->characters.size(); ++i) 265 | { 266 | if(this->characters[i]->name == name) 267 | { 268 | this->characters.erase(this->characters.begin() + i); 269 | return; 270 | } 271 | } 272 | } 273 | 274 | std::vector Map::GetNPCsAt(unsigned short x, unsigned short y) 275 | { 276 | std::vector ret; 277 | 278 | for(auto &it: npcs) 279 | { 280 | if(it->x == x && it->y == y) 281 | { 282 | ret.push_back(it.get()); 283 | } 284 | } 285 | 286 | return ret; 287 | } 288 | 289 | NPC *Map::GetNPC(unsigned int index) 290 | { 291 | for(auto &it: npcs) 292 | { 293 | if(it->index == index) 294 | return it.get(); 295 | } 296 | 297 | return 0; 298 | } 299 | 300 | void Map::AddNPC(std::shared_ptr npc) 301 | { 302 | npc->index = this->GenerateNPCIndex(); 303 | 304 | this->npcs.push_back(npc); 305 | 306 | std::vector> chars_in_range; 307 | for(auto &it : this->characters) 308 | { 309 | int len = path_length(npc->x, npc->y, it->x, it->y); 310 | 311 | if(len < 13) 312 | { 313 | chars_in_range.push_back(it); 314 | } 315 | } 316 | 317 | for(auto &it : chars_in_range) 318 | { 319 | Client *client = Server().GetClientByChar(it->name); 320 | 321 | it->npcs_in_range.push_back(npc); 322 | 323 | sf::Packet packet; 324 | 325 | packet << (unsigned char)PacketID::Map; 326 | packet << (unsigned char)1; // appear 327 | packet << (unsigned char)2; // npc 328 | packet << npc->id; 329 | packet << npc->index; 330 | packet << npc->map_id; 331 | packet << npc->x; 332 | packet << npc->y; 333 | packet << (unsigned char)npc->direction; 334 | packet << npc->speed; 335 | 336 | client->Send(packet); 337 | } 338 | } 339 | 340 | void Map::DeleteNPC(unsigned int index) 341 | { 342 | for(std::size_t i = 0; i < this->npcs.size(); ++i) 343 | { 344 | if(this->npcs[i]->index == index) 345 | { 346 | this->npcs.erase(this->npcs.begin() + i); 347 | return; 348 | } 349 | } 350 | } 351 | 352 | bool Map::Walkable(unsigned short x, unsigned short y, bool entity) 353 | { 354 | if(this->atts[x][y] != 0) 355 | { 356 | if(this->atts[x][y]->type == Attribute::Type::Wall) return false; 357 | } 358 | 359 | if(!entity) return true; 360 | 361 | for(auto &it: this->characters) 362 | { 363 | if(it->x == x && it->y == y) return false; 364 | } 365 | 366 | for(auto &it: this->npcs) 367 | { 368 | if(it->x == x && it->y == y) return false; 369 | } 370 | 371 | return true; 372 | } 373 | 374 | unsigned int Map::GenerateNPCIndex() 375 | { 376 | unsigned int counter = 1; 377 | 378 | for(auto &it: this->npcs) 379 | { 380 | if(it->index != counter) 381 | { 382 | return counter; 383 | } 384 | 385 | counter++; 386 | } 387 | 388 | return counter; 389 | } 390 | -------------------------------------------------------------------------------- /game_engine/src/map_editor.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "map_editor.hpp" 4 | 5 | #include "input_handler.hpp" 6 | #include "gfx_loader.hpp" 7 | #include "gui.hpp" 8 | #include "map.hpp" 9 | #include "client.hpp" 10 | #include "map_cursor.hpp" 11 | 12 | #include 13 | #include 14 | 15 | bool MapEditor::initialized_ = false; 16 | unsigned int MapEditor::graphic_id; 17 | Map::Layer::Type MapEditor::type; 18 | int MapEditor::render_xoff; 19 | int MapEditor::render_yoff; 20 | 21 | MapEditor::MapEditor() 22 | { 23 | if(!this->initialized_) 24 | { 25 | this->graphic_id = 0; 26 | this->type = Map::Layer::Type::Ground; 27 | this->render_xoff = 0; 28 | this->render_yoff = 0; 29 | 30 | this->initialized_ = true; 31 | } 32 | } 33 | 34 | void MapEditor::MakeGUI() 35 | { 36 | std::string menu_action = ""; 37 | GFXLoader gfx_loader; 38 | Map map; 39 | 40 | if(ImGui::BeginMainMenuBar()) 41 | { 42 | if(ImGui::BeginMenu("File")) 43 | { 44 | if(ImGui::MenuItem("New")) menu_action = "New"; 45 | if(ImGui::MenuItem("Load...")) menu_action = "Load"; 46 | if(ImGui::MenuItem("Save...")) menu_action = "Save"; 47 | if(ImGui::MenuItem("Save As...")) menu_action = "SaveAs"; 48 | if(ImGui::MenuItem("Exit")) menu_action = "Exit"; 49 | 50 | ImGui::EndMenu(); 51 | } 52 | 53 | ImGui::EndMainMenuBar(); 54 | } 55 | 56 | if(menu_action == "New") ImGui::OpenPopup("New"); 57 | if(menu_action == "Load") ImGui::OpenPopup("Load"); 58 | if(menu_action == "Save") 59 | { 60 | if(map.id == 0) ImGui::OpenPopup("Save As"); 61 | else if(map.id > 0) map.Save(); 62 | } 63 | if(menu_action == "SaveAs") ImGui::OpenPopup("Save As"); 64 | if(menu_action == "Exit") 65 | { 66 | map.Reset(); 67 | GUI().SetState(GUI::State::MainMenu); 68 | } 69 | 70 | if (ImGui::BeginPopup("New")) 71 | { 72 | static int i_id = 1; 73 | static int i_w = 1; 74 | static int i_h = 1; 75 | static int i_fill = 0; 76 | static char str_name[128] = ""; 77 | 78 | ImGui::Text("Create new map."); 79 | 80 | ImGui::InputInt("ID", &i_id); 81 | ImGui::InputText("Name", str_name, IM_ARRAYSIZE(str_name)); 82 | ImGui::InputInt("Width", &i_w); 83 | ImGui::InputInt("Height", &i_h); 84 | 85 | ALLEGRO_BITMAP *fill_tile = gfx_loader.GetBitmap(3, i_fill); 86 | if(fill_tile != NULL) 87 | { 88 | int w = al_get_bitmap_width(fill_tile); 89 | int h = al_get_bitmap_height(fill_tile); 90 | ImGui::Image((void*)fill_tile, ImVec2(w, h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); 91 | ImGui::SameLine(); 92 | } 93 | ImGui::InputInt("Fill tile", &i_fill); 94 | 95 | ImGui::PushStyleVar(ImGuiStyleVar_ChildWindowRounding, 5.0f); 96 | ImGui::BeginChild("Sub", ImVec2(340, 256), true); 97 | ImGui::Columns(4, "", false); 98 | int tile_id = 1; 99 | ALLEGRO_BITMAP *tile = NULL; 100 | do 101 | { 102 | tile = gfx_loader.GetBitmap(3, tile_id); 103 | if(tile != NULL) 104 | { 105 | int w = al_get_bitmap_width(tile); 106 | int h = al_get_bitmap_height(tile); 107 | 108 | if(ImGui::ImageButton((void*)tile, ImVec2(64, 32), ImVec2(0,0), ImVec2(64.0f/w, 32/h), 1, ImColor(0,0,0,255))) 109 | { 110 | i_fill = tile_id; 111 | } 112 | } 113 | tile_id++; 114 | ImGui::NextColumn(); 115 | } while(tile != NULL); 116 | ImGui::EndChild(); 117 | ImGui::PopStyleVar(); 118 | 119 | if(ImGui::Button("Create")) 120 | { 121 | map.Reset(); 122 | map.id = i_id; 123 | map.name = str_name; 124 | map.width = i_w; 125 | map.height = i_h; 126 | map.fill_tile = i_fill; 127 | 128 | this->Reset(); 129 | 130 | Character *character = new Character("Artist", i_id, 1, 1); 131 | character->speed = 18; 132 | 133 | Map().characters.push_back(std::shared_ptr(character)); 134 | Client().character = character; 135 | 136 | ImGui::CloseCurrentPopup(); 137 | } 138 | ImGui::SameLine(); 139 | if(ImGui::Button("Cancel")) ImGui::CloseCurrentPopup(); 140 | 141 | ImGui::EndPopup(); 142 | } 143 | if(ImGui::BeginPopup("Load")) 144 | { 145 | static int i_id = 1; 146 | 147 | ImGui::Text("Load map."); 148 | ImGui::InputInt("ID", &i_id); 149 | if(ImGui::Button("Load")) 150 | { 151 | map.Load(i_id); 152 | if(!map.Exists()) 153 | { 154 | map.Reset(); 155 | menu_action = "ErrorLoad"; 156 | } 157 | else 158 | { 159 | this->Reset(); 160 | 161 | Character *character = new Character("Artist", i_id, 1, 1); 162 | character->speed = 18; 163 | 164 | Map().characters.push_back(std::shared_ptr(character)); 165 | Client().character = character; 166 | 167 | ImGui::CloseCurrentPopup(); 168 | } 169 | } 170 | 171 | if(menu_action == "ErrorLoad") ImGui::OpenPopup("Error loading map"); 172 | 173 | if(ImGui::BeginPopupModal("Error loading map", NULL, ImGuiWindowFlags_NoResize)) 174 | { 175 | ImGui::Text("Could not load map file of given ID."); 176 | if(ImGui::Button("OK")) ImGui::CloseCurrentPopup(); 177 | 178 | ImGui::EndPopup(); 179 | } 180 | if(ImGui::Button("Cancel")) ImGui::CloseCurrentPopup(); 181 | 182 | ImGui::EndPopup(); 183 | } 184 | if (ImGui::BeginPopup("Save As")) 185 | { 186 | static int i_id = map.id; 187 | 188 | ImGui::InputInt("ID", &i_id); 189 | if(ImGui::Button("Save")) 190 | { 191 | map.id = i_id; 192 | map.Save(); 193 | ImGui::CloseCurrentPopup(); 194 | } 195 | ImGui::SameLine(); 196 | if(ImGui::Button("Cancel")) ImGui::CloseCurrentPopup(); 197 | 198 | ImGui::EndPopup(); 199 | } 200 | 201 | int gid_offset[2] = { 3, 4 }; 202 | 203 | ALLEGRO_BITMAP *tile = NULL; 204 | int tile_id = 1; 205 | int max_w = 0; 206 | 207 | do 208 | { 209 | tile = gfx_loader.GetBitmap(gid_offset[(int)this->type], tile_id); 210 | if(tile != NULL) 211 | { 212 | int w = al_get_bitmap_width(tile); 213 | 214 | if(w > max_w) max_w = w; 215 | } 216 | tile_id++; 217 | } while(tile != NULL); 218 | 219 | ImGuiWindowFlags flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; 220 | 221 | ImGui::SetNextWindowPos(ImVec2(10, 308)); 222 | ImGui::SetNextWindowSize(ImVec2(620, 162)); 223 | ImGui::Begin("Tile sets", 0, flags); 224 | 225 | const char* layer_names[] = { "Ground", "Object" }; 226 | static int item2 = 0; 227 | ImGui::Combo("Layers", &item2, layer_names, IM_ARRAYSIZE(layer_names)); 228 | 229 | if(item2 != (int)this->type) 230 | { 231 | this->type = (Map::Layer::Type)item2; 232 | this->graphic_id = 0; 233 | } 234 | 235 | ImGui::PushStyleVar(ImGuiStyleVar_ChildWindowRounding, 5.0f); 236 | ImGui::BeginChild("Sub", ImVec2(590, 100), true); 237 | ImGui::Columns(600 / max_w, "", false); 238 | 239 | tile_id = 1; 240 | 241 | do 242 | { 243 | tile = gfx_loader.GetBitmap(gid_offset[(std::size_t)this->type], tile_id); 244 | if(tile != NULL) 245 | { 246 | int w = al_get_bitmap_width(tile); 247 | int h = al_get_bitmap_height(tile); 248 | 249 | if(ImGui::ImageButton((void*)tile, ImVec2(w, h), ImVec2(0,0), ImVec2(w/w, h/h), 1, ImColor(0,0,0,255))) 250 | { 251 | this->graphic_id = tile_id; 252 | } 253 | } 254 | tile_id++; 255 | ImGui::NextColumn(); 256 | } while(tile != NULL); 257 | 258 | ImGui::EndChild(); 259 | ImGui::PopStyleVar(); 260 | 261 | ImGui::End(); 262 | } 263 | 264 | void MapEditor::ProcessInput() 265 | { 266 | InputHandler input_handler; 267 | MapCursor map_cursor; 268 | 269 | if(input_handler.mouse[1] && this->graphic_id != 0) 270 | { 271 | if(!map_cursor.MouseOnMap()) return; 272 | 273 | if(this->graphic_id == 0) return; 274 | 275 | Map map; 276 | std::shared_ptr tile = map.layers[this->type].tiles[map_cursor.x][map_cursor.y]; 277 | 278 | if(tile == 0) 279 | { 280 | tile = std::shared_ptr(new Map::Tile()); 281 | 282 | tile->graphic_id = this->graphic_id; 283 | tile->x = map_cursor.x; 284 | tile->y = map_cursor.y; 285 | 286 | map.layers[this->type].tiles[tile->x][tile->y] = tile; 287 | } 288 | else 289 | { 290 | if(tile->graphic_id != this->graphic_id && this->graphic_id != map.fill_tile) 291 | { 292 | tile->graphic_id = this->graphic_id; 293 | } 294 | } 295 | } 296 | if(input_handler.mouse[2]) 297 | { 298 | MapCursor map_cursor; 299 | 300 | if(!map_cursor.MouseOnMap()) return; 301 | 302 | Map map; 303 | 304 | if(map.layers[this->type].tiles[map_cursor.x][map_cursor.y] != 0) 305 | map.layers[this->type].tiles[map_cursor.x][map_cursor.y].reset(); 306 | 307 | //map.layers[this->type].tiles[map_cursor.x][map_cursor.y] = std::shared_ptr(0); 308 | } 309 | 310 | if(input_handler.keys[ALLEGRO_KEY_W]) 311 | { 312 | Map::Attribute *att = new Map::Attribute(); 313 | att->type = Map::Attribute::Type::Wall; 314 | att->x = map_cursor.x; 315 | att->y = map_cursor.y; 316 | 317 | Map map; 318 | 319 | if(map.atts[map_cursor.x][map_cursor.y] != 0) map.atts[map_cursor.x][map_cursor.y].reset(); 320 | 321 | map.atts[map_cursor.x][map_cursor.y] = std::shared_ptr(att); 322 | } 323 | if(input_handler.keys[ALLEGRO_KEY_E]) 324 | { 325 | Map map; 326 | 327 | if(map.atts[map_cursor.x][map_cursor.y] != 0) map.atts[map_cursor.x][map_cursor.y].reset(); 328 | } 329 | } 330 | 331 | void MapEditor::Reset() 332 | { 333 | this->graphic_id = 0; 334 | this->type = Map::Layer::Type::Ground; 335 | this->render_xoff = 0; 336 | this->render_yoff = 0; 337 | } 338 | -------------------------------------------------------------------------------- /game_engine/src/imgui_impl_a5.cpp: -------------------------------------------------------------------------------- 1 | // ImGui Allegro 5 bindings 2 | // In this binding, ImTextureID is used to store a 'ALLEGRO_BITMAP*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. 3 | 4 | // TODO: 5 | // - Clipboard is not supported. 6 | 7 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 8 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 9 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. 10 | // https://github.com/ocornut/imgui 11 | // by @birthggd 12 | 13 | #include // uint64_t 14 | #include // memcpy 15 | #include 16 | #include "imgui_impl_a5.h" 17 | #include 18 | #include 19 | 20 | #ifdef _WIN32 21 | #include 22 | #endif 23 | 24 | // Data 25 | static ALLEGRO_DISPLAY* g_Display = NULL; 26 | static ALLEGRO_BITMAP* g_Texture = NULL; 27 | static double g_Time = 0.0; 28 | static ALLEGRO_MOUSE_CURSOR* g_MouseCursorInvisible = NULL; 29 | static ALLEGRO_VERTEX_DECL* g_VertexDecl = NULL; 30 | 31 | #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) 32 | 33 | struct ImDrawVertAllegro 34 | { 35 | ImVec2 pos; 36 | ImVec2 uv; 37 | ALLEGRO_COLOR col; 38 | }; 39 | 40 | void ImGui_ImplA5_RenderDrawLists(ImDrawData* draw_data) 41 | { 42 | int op, src, dst; 43 | al_get_blender(&op, &src, &dst); 44 | al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); 45 | 46 | for (int n = 0; n < draw_data->CmdListsCount; n++) 47 | { 48 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 49 | 50 | // FIXME-OPT: Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats 51 | static ImVector vertices; 52 | vertices.resize(cmd_list->VtxBuffer.Size); 53 | for (int i = 0; i < cmd_list->VtxBuffer.Size; ++i) 54 | { 55 | const ImDrawVert &dv = cmd_list->VtxBuffer[i]; 56 | ImDrawVertAllegro v; 57 | v.pos = dv.pos; 58 | v.uv = dv.uv; 59 | unsigned char *c = (unsigned char*)&dv.col; 60 | v.col = al_map_rgba(c[0], c[1], c[2], c[3]); 61 | vertices[i] = v; 62 | } 63 | 64 | // FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices 65 | // You can also use '#define ImDrawIdx unsigned int' in imconfig.h and request ImGui to output 32-bit indices 66 | static ImVector indices; 67 | indices.resize(cmd_list->IdxBuffer.Size); 68 | for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i) 69 | indices[i] = (int)cmd_list->IdxBuffer.Data[i]; 70 | 71 | int idx_offset = 0; 72 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 73 | { 74 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 75 | if (pcmd->UserCallback) 76 | { 77 | pcmd->UserCallback(cmd_list, pcmd); 78 | } 79 | else 80 | { 81 | ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->TextureId; 82 | al_set_clipping_rectangle(pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z-pcmd->ClipRect.x, pcmd->ClipRect.w-pcmd->ClipRect.y); 83 | al_draw_indexed_prim(&vertices[0], g_VertexDecl, texture, &indices[idx_offset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); 84 | } 85 | idx_offset += pcmd->ElemCount; 86 | } 87 | } 88 | 89 | // Restore modified state 90 | al_set_blender(op, src, dst); 91 | al_set_clipping_rectangle(0, 0, al_get_display_width(g_Display), al_get_display_height(g_Display)); 92 | } 93 | 94 | bool Imgui_ImplA5_CreateDeviceObjects() 95 | { 96 | // Build texture atlas 97 | ImGuiIO &io = ImGui::GetIO(); 98 | unsigned char *pixels; 99 | int width, height; 100 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 101 | 102 | // Create texture 103 | int flags = al_get_new_bitmap_flags(); 104 | int fmt = al_get_new_bitmap_format(); 105 | al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR); 106 | al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE); 107 | ALLEGRO_BITMAP* img = al_create_bitmap(width, height); 108 | al_set_new_bitmap_flags(flags); 109 | al_set_new_bitmap_format(fmt); 110 | if (!img) 111 | return false; 112 | 113 | ALLEGRO_LOCKED_REGION *locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY); 114 | if (!locked_img) 115 | { 116 | al_destroy_bitmap(img); 117 | return false; 118 | } 119 | memcpy(locked_img->data, pixels, sizeof(int)*width*height); 120 | al_unlock_bitmap(img); 121 | 122 | // Convert software texture to hardware texture. 123 | ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img); 124 | al_destroy_bitmap(img); 125 | if (!cloned_img) 126 | return false; 127 | 128 | // Store our identifier 129 | io.Fonts->TexID = (void*)cloned_img; 130 | g_Texture = cloned_img; 131 | 132 | // Create an invisible mouse cursor 133 | // Because al_hide_mouse_cursor() seems to mess up with the actual inputs.. 134 | ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8,8); 135 | g_MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0); 136 | al_destroy_bitmap(mouse_cursor); 137 | 138 | return true; 139 | } 140 | 141 | void ImGui_ImplA5_InvalidateDeviceObjects() 142 | { 143 | if (g_Texture) 144 | { 145 | al_destroy_bitmap(g_Texture); 146 | ImGui::GetIO().Fonts->TexID = NULL; 147 | g_Texture = NULL; 148 | } 149 | if (g_MouseCursorInvisible) 150 | { 151 | al_destroy_mouse_cursor(g_MouseCursorInvisible); 152 | g_MouseCursorInvisible = NULL; 153 | } 154 | } 155 | 156 | bool ImGui_ImplA5_Init(ALLEGRO_DISPLAY* display) 157 | { 158 | g_Display = display; 159 | 160 | // Create custom vertex declaration. 161 | // Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats. 162 | // We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion. 163 | ALLEGRO_VERTEX_ELEMENT elems[] = 164 | { 165 | { ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, OFFSETOF(ImDrawVertAllegro, pos) }, 166 | { ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, OFFSETOF(ImDrawVertAllegro, uv) }, 167 | { ALLEGRO_PRIM_COLOR_ATTR, 0, OFFSETOF(ImDrawVertAllegro, col) }, 168 | { 0, 0, 0 } 169 | }; 170 | g_VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro)); 171 | 172 | ImGuiIO& io = ImGui::GetIO(); 173 | io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB; 174 | io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT; 175 | io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT; 176 | io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP; 177 | io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN; 178 | io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP; 179 | io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN; 180 | io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME; 181 | io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END; 182 | io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE; 183 | io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE; 184 | io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER; 185 | io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE; 186 | io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A; 187 | io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C; 188 | io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V; 189 | io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X; 190 | io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y; 191 | io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z; 192 | 193 | io.RenderDrawListsFn = ImGui_ImplA5_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. 194 | #ifdef _WIN32 195 | io.ImeWindowHandle = al_get_win_window_handle(g_Display); 196 | #endif 197 | 198 | return true; 199 | } 200 | 201 | void ImGui_ImplA5_Shutdown() 202 | { 203 | ImGui_ImplA5_InvalidateDeviceObjects(); 204 | ImGui::Shutdown(); 205 | } 206 | 207 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 208 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 209 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 210 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 211 | bool ImGui_ImplA5_ProcessEvent(ALLEGRO_EVENT *ev) 212 | { 213 | ImGuiIO &io = ImGui::GetIO(); 214 | 215 | switch (ev->type) 216 | { 217 | case ALLEGRO_EVENT_MOUSE_AXES: 218 | io.MouseWheel += ev->mouse.dz; 219 | return true; 220 | case ALLEGRO_EVENT_KEY_CHAR: 221 | if (ev->keyboard.display == g_Display) 222 | if (ev->keyboard.unichar > 0 && ev->keyboard.unichar < 0x10000) 223 | io.AddInputCharacter((unsigned short)ev->keyboard.unichar); 224 | return true; 225 | case ALLEGRO_EVENT_KEY_DOWN: 226 | case ALLEGRO_EVENT_KEY_UP: 227 | if (ev->keyboard.display == g_Display) 228 | io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN); 229 | return true; 230 | } 231 | return false; 232 | } 233 | 234 | void ImGui_ImplA5_NewFrame() 235 | { 236 | if (!g_Texture) 237 | Imgui_ImplA5_CreateDeviceObjects(); 238 | 239 | ImGuiIO &io = ImGui::GetIO(); 240 | 241 | // Setup display size (every frame to accommodate for window resizing) 242 | int w, h; 243 | w = al_get_display_width(g_Display); 244 | h = al_get_display_height(g_Display); 245 | io.DisplaySize = ImVec2((float)w, (float)h); 246 | 247 | // Setup time step 248 | double current_time = al_get_time(); 249 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); 250 | g_Time = current_time; 251 | 252 | // Setup inputs 253 | ALLEGRO_KEYBOARD_STATE keys; 254 | al_get_keyboard_state(&keys); 255 | io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL); 256 | io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT); 257 | io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR); 258 | io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN); 259 | 260 | ALLEGRO_MOUSE_STATE mouse; 261 | if (keys.display == g_Display) 262 | { 263 | al_get_mouse_state(&mouse); 264 | io.MousePos = ImVec2((float)mouse.x, (float)mouse.y); 265 | } 266 | else 267 | { 268 | io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 269 | } 270 | 271 | al_get_mouse_state(&mouse); 272 | io.MouseDown[0] = mouse.buttons & (1 << 0); 273 | io.MouseDown[1] = mouse.buttons & (1 << 1); 274 | io.MouseDown[2] = mouse.buttons & (1 << 2); 275 | 276 | // Hide OS mouse cursor if ImGui is drawing it 277 | if (io.MouseDrawCursor) 278 | { 279 | al_set_mouse_cursor(g_Display, g_MouseCursorInvisible); 280 | } 281 | else 282 | { 283 | ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT; 284 | switch (ImGui::GetMouseCursor()) 285 | { 286 | case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break; 287 | case ImGuiMouseCursor_Move: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break; 288 | case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break; 289 | case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break; 290 | case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break; 291 | case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break; 292 | } 293 | al_set_system_mouse_cursor(g_Display, cursor_id); 294 | } 295 | 296 | // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. 297 | ImGui::NewFrame(); 298 | } 299 | -------------------------------------------------------------------------------- /game_engine/src/map.cpp: -------------------------------------------------------------------------------- 1 | // Endless Online Awaken 2 | 3 | #include "map.hpp" 4 | 5 | #include "file_handler.hpp" 6 | #include "gui.hpp" 7 | #include "map_cursor.hpp" 8 | #include "font_handler.hpp" 9 | #include "client.hpp" 10 | 11 | #include 12 | #include 13 | 14 | bool Map::initialized_ = false; 15 | bool Map::exists; 16 | unsigned int Map::id; 17 | std::string Map::name; 18 | unsigned int Map::revision; 19 | unsigned short Map::width; 20 | unsigned short Map::height; 21 | unsigned int Map::fill_tile; 22 | std::map Map::layers; 23 | std::map>> Map::atts; 24 | std::vector> Map::characters; 25 | std::vector> Map::npcs; 26 | 27 | Map::Layer::Layer() 28 | { 29 | this->type = Type::Ground; 30 | } 31 | 32 | Map::Map() 33 | { 34 | if(!this->initialized_) 35 | { 36 | this->exists = false; 37 | this->id = 0; 38 | this->name = ""; 39 | this->revision = 0; 40 | this->width = 1; 41 | this->height = 1; 42 | this->fill_tile = 0; 43 | 44 | this->initialized_ = true; 45 | } 46 | } 47 | 48 | Map::Map(unsigned int id) 49 | { 50 | if(!this->initialized_) 51 | { 52 | this->initialized_ = true; 53 | } 54 | 55 | this->Load(id); 56 | } 57 | 58 | bool Map::Load(unsigned int id) 59 | { 60 | this->Reset(); 61 | this->exists = false; 62 | 63 | this->id = id; 64 | 65 | if(this->id == 0) 66 | { 67 | throw std::runtime_error("Map: can't load map, ID #0 is reserved."); 68 | } 69 | 70 | std::string filename = "data/maps/" + std::to_string(this->id) + ".map"; 71 | FileHandler fh(filename); 72 | 73 | this->exists = fh.Exists(); 74 | 75 | if(!this->exists) return false; 76 | 77 | this->name = fh.GetString(); 78 | this->revision = fh.GetInt(); 79 | this->width = fh.GetShort(); 80 | this->height = fh.GetShort(); 81 | this->fill_tile = fh.GetInt(); 82 | 83 | unsigned char read_tile = fh.GetChar(); 84 | 85 | while(read_tile == 1) 86 | { 87 | std::shared_ptr tile = std::shared_ptr(new Tile()); 88 | 89 | tile->graphic_id = fh.GetInt(); 90 | tile->x = fh.GetShort(); 91 | tile->y = fh.GetShort(); 92 | Layer::Type layer_type = (Layer::Type)fh.GetChar(); 93 | 94 | this->layers[(Layer::Type)layer_type].tiles[tile->x][tile->y] = tile; 95 | 96 | read_tile = fh.GetChar(); 97 | } 98 | 99 | read_tile = fh.GetChar(); 100 | 101 | while(read_tile == 1) 102 | { 103 | std::shared_ptr att = std::shared_ptr(new Attribute()); 104 | 105 | att->type = (Attribute::Type)fh.GetChar(); 106 | att->x = fh.GetShort(); 107 | att->y = fh.GetShort(); 108 | 109 | this->atts[att->x][att->y] = att; 110 | 111 | read_tile = fh.GetChar(); 112 | } 113 | 114 | std::cout << "Map loaded: '" << this->name << "' " << this->width << "x" << this->height << std::endl; 115 | 116 | return true; 117 | } 118 | 119 | void Map::Save() 120 | { 121 | if(this->id == 0) 122 | { 123 | throw std::runtime_error("Map: can't save map, ID #0 is reserved."); 124 | } 125 | 126 | std::ofstream file; 127 | std::string filename = "data/maps/" + std::to_string(this->id) + ".map"; 128 | FileHandler fh; 129 | 130 | fh.AddString(this->name); 131 | fh.AddInt(++this->revision); 132 | fh.AddShort(this->width); 133 | fh.AddShort(this->height); 134 | fh.AddInt(this->fill_tile); 135 | 136 | for(auto &l : this->layers) 137 | { 138 | for(auto &t : l.second.tiles) 139 | { 140 | for(auto &tt : t.second) 141 | { 142 | std::shared_ptr tile = tt.second; 143 | 144 | if(tile == 0) continue; 145 | 146 | fh.AddChar(1); 147 | fh.AddInt(tile->graphic_id); 148 | fh.AddShort(tile->x); 149 | fh.AddShort(tile->y); 150 | fh.AddChar((unsigned int)l.first); 151 | } 152 | } 153 | } 154 | 155 | fh.AddChar(0); 156 | 157 | for(auto &a : this->atts) 158 | { 159 | for(auto &aa : a.second) 160 | { 161 | std::shared_ptr att = aa.second; 162 | 163 | if(att == 0) continue; 164 | 165 | fh.AddChar(1); 166 | fh.AddChar((unsigned int)att->type); 167 | fh.AddShort(att->x); 168 | fh.AddShort(att->y); 169 | } 170 | } 171 | 172 | fh.AddChar(0); 173 | 174 | fh.Save(filename); 175 | this->exists = fh.Exists(); 176 | } 177 | 178 | void Map::Tick() 179 | { 180 | for(auto &it : this->characters) 181 | { 182 | it->Tick(); 183 | } 184 | 185 | for(auto &it : this->npcs) 186 | { 187 | it->Tick(); 188 | } 189 | } 190 | 191 | void Map::Render(int rx, int ry) 192 | { 193 | Character *character = Client().character; 194 | unsigned short start_x = 0; 195 | unsigned short start_y = 0; 196 | unsigned short end_x = this->width > 0? this->width - 1 : 1; 197 | unsigned short end_y = this->height > 0? this->height - 1 : 1; 198 | 199 | if(character != 0) 200 | { 201 | start_x = character->x > 16? character->x - 16 : 0; 202 | start_y = character->y > 16? character->y - 16 : 0; 203 | end_x = character->x + 16 > this->width? this->width - 1 : character->x + 16; 204 | end_y = character->y + 16 > this->height? this->height - 1 : character->y + 16; 205 | } 206 | 207 | if(this->fill_tile != 0) 208 | { 209 | ALLEGRO_BITMAP *tilegfx = GFXLoader().GetBitmap(3, this->fill_tile); 210 | 211 | if(tilegfx != 0) 212 | { 213 | al_hold_bitmap_drawing(true); 214 | 215 | for(unsigned short x = start_x; x <= end_x; ++x) 216 | { 217 | for(unsigned short y = start_y; y <= end_y; ++y) 218 | { 219 | int screen_x = x * 64 - x * 32 - y * 32 + rx; 220 | int screen_y = y * 16 + x * 16 + ry; 221 | 222 | al_draw_bitmap(tilegfx, screen_x, screen_y, 0); 223 | } 224 | } 225 | 226 | al_hold_bitmap_drawing(false); 227 | } 228 | } 229 | 230 | int gid_offset[2] = { 3, 4 }; 231 | bool cursor_drawn = false; 232 | 233 | for(int i = 0; i < (int)Layer::Type::Object; ++i) // render stagged tiles for ground layer only 234 | { 235 | std::map bitmaps; 236 | std::map>> tiles_stagged; 237 | 238 | for(unsigned short x = start_x; x <= end_x; ++x) 239 | { 240 | for(unsigned short y = start_y; y <= end_y; ++y) 241 | { 242 | std::shared_ptr tile = this->layers[(Layer::Type)i].tiles[x][y]; 243 | 244 | if(tile == 0) continue; 245 | 246 | ALLEGRO_BITMAP *tilegfx = NULL; 247 | 248 | if(bitmaps.find(tile->graphic_id) == bitmaps.end()) 249 | { 250 | tilegfx = GFXLoader().GetBitmap(gid_offset[i], tile->graphic_id); 251 | bitmaps[tile->graphic_id] = tilegfx; 252 | } 253 | 254 | if(tile->x >= start_x && tile->x <= end_x && tile->y >= start_y && tile->y <= end_y) 255 | tiles_stagged[tile->graphic_id].push_back(tile); 256 | } 257 | } 258 | 259 | for(auto &ts : tiles_stagged) 260 | { 261 | al_hold_bitmap_drawing(true); 262 | for(auto &tile : ts.second) 263 | { 264 | if(bitmaps[ts.first] == NULL) continue; 265 | 266 | int screen_x = tile->x * 64 - tile->x * 32 - tile->y * 32 + rx; 267 | int screen_y = tile->y * 16 + tile->x * 16 + ry; 268 | 269 | int w = al_get_bitmap_width(bitmaps[ts.first]); 270 | int h = al_get_bitmap_height(bitmaps[ts.first]); 271 | 272 | if(i == (int)Layer::Type::Object) 273 | { 274 | if(w > 64) 275 | { 276 | screen_x -= w / 2; 277 | screen_x += 32; 278 | } 279 | if(h > 32) 280 | { 281 | screen_y -= h; 282 | screen_y += 32; 283 | } 284 | if(w < 64) 285 | { 286 | screen_x -= w / 2; 287 | screen_x += 32; 288 | if(h > 32) screen_y -= 8; 289 | } 290 | if(h < 32) 291 | { 292 | screen_y -= h / 2; 293 | screen_y += 16; 294 | } 295 | } 296 | 297 | al_draw_bitmap(bitmaps[ts.first], screen_x, screen_y, 0); 298 | } 299 | al_hold_bitmap_drawing(false); 300 | } 301 | 302 | if(i == (int)Layer::Type::Ground) 303 | { 304 | MapCursor().Render(rx, ry); 305 | cursor_drawn = true; 306 | } 307 | } 308 | 309 | if(!cursor_drawn) 310 | { 311 | MapCursor().Render(rx, ry); 312 | } 313 | 314 | // object layer + characters 315 | for(unsigned short x = start_x; x <= end_x; ++x) 316 | { 317 | for(unsigned short y = start_y; y <= end_y; ++y) 318 | { 319 | std::shared_ptr tile = this->layers[Layer::Type::Object].tiles[x][y]; 320 | 321 | if(tile != 0) 322 | { 323 | ALLEGRO_BITMAP *tilegfx = GFXLoader().GetBitmap(gid_offset[(int)Layer::Type::Object], tile->graphic_id); 324 | 325 | if(tilegfx != 0) 326 | { 327 | int screen_x = tile->x * 64 - tile->x * 32 - tile->y * 32 + rx; 328 | int screen_y = tile->y * 16 + tile->x * 16 + ry; 329 | 330 | int w = al_get_bitmap_width(tilegfx); 331 | int h = al_get_bitmap_height(tilegfx); 332 | 333 | if(w > 64) 334 | { 335 | screen_x -= w / 2; 336 | screen_x += 32; 337 | } 338 | if(h > 32) 339 | { 340 | screen_y -= h; 341 | screen_y += 32; 342 | } 343 | if(w < 64) 344 | { 345 | screen_x -= w / 2; 346 | screen_x += 32; 347 | if(h > 32) screen_y -= 8; 348 | } 349 | if(h < 32) 350 | { 351 | screen_y -= h / 2; 352 | screen_y += 16; 353 | } 354 | 355 | al_draw_bitmap(tilegfx, screen_x, screen_y, 0); 356 | } 357 | } 358 | 359 | for(auto &charr : this->characters) 360 | { 361 | if(charr->x == x && charr->y == y) charr->RenderNew(rx, ry); 362 | } 363 | 364 | for(auto &npc : this->npcs) 365 | { 366 | if(npc->x == x && npc->y == y) npc->Render(rx, ry); 367 | } 368 | } 369 | } 370 | 371 | std::string nickname = MapCursor().nickname; 372 | 373 | if(nickname != "") 374 | { 375 | ALLEGRO_FONT *font = FontHandler().font; 376 | float alpha = 0.5f; 377 | ALLEGRO_COLOR color = al_map_rgba_f(1.0, 1.0, 1.0, alpha); 378 | 379 | Character *charr = this->GetCharacter(nickname); 380 | 381 | if(charr == 0) return; 382 | 383 | int text_w = al_get_text_width(font, nickname.c_str()); 384 | 385 | std::vector char_pos = charr->GetScreenPos(); 386 | al_draw_text(font, color, char_pos[0] - text_w / 2, char_pos[1] - 6, 0, nickname.c_str()); 387 | 388 | } 389 | } 390 | 391 | void Map::Reset() 392 | { 393 | this->id = 0; 394 | this->name.clear(); 395 | this->revision = 0; 396 | this->width = 1; 397 | this->height = 1; 398 | this->fill_tile = 0; 399 | 400 | this->layers.clear(); 401 | this->atts.clear(); 402 | this->characters.clear(); 403 | this->npcs.clear(); 404 | } 405 | 406 | std::vector Map::GetCharactersAt(unsigned short x, unsigned short y) 407 | { 408 | std::vector ret; 409 | 410 | for(auto &it: characters) 411 | { 412 | if(it->x == x && it->y == y) 413 | { 414 | ret.push_back(it.get()); 415 | } 416 | } 417 | 418 | return ret; 419 | } 420 | 421 | Character *Map::GetCharacter(std::string name) 422 | { 423 | for(auto &it: characters) 424 | { 425 | if(it->name == name) 426 | return it.get(); 427 | } 428 | 429 | return 0; 430 | } 431 | 432 | void Map::DeleteCharacter(std::string name) 433 | { 434 | for(std::size_t i = 0; i < this->characters.size(); ++i) 435 | { 436 | if(this->characters[i]->name == name) 437 | { 438 | this->characters.erase(this->characters.begin() + i); 439 | return; 440 | } 441 | } 442 | } 443 | 444 | std::vector Map::GetNPCsAt(unsigned short x, unsigned short y) 445 | { 446 | std::vector ret; 447 | 448 | for(auto &it: npcs) 449 | { 450 | if(it->x == x && it->y == y) 451 | { 452 | ret.push_back(it.get()); 453 | } 454 | } 455 | 456 | return ret; 457 | } 458 | 459 | NPC *Map::GetNPC(unsigned int index) 460 | { 461 | for(auto &it: npcs) 462 | { 463 | if(it->index == index) 464 | return it.get(); 465 | } 466 | 467 | return 0; 468 | } 469 | 470 | void Map::DeleteNPC(unsigned int index) 471 | { 472 | for(std::size_t i = 0; i < this->npcs.size(); ++i) 473 | { 474 | if(this->npcs[i]->index == index) 475 | { 476 | this->npcs.erase(this->npcs.begin() + i); 477 | return; 478 | } 479 | } 480 | } 481 | 482 | bool Map::Walkable(unsigned short x, unsigned short y, bool entity) 483 | { 484 | if(this->atts[x][y] != 0) 485 | { 486 | if(this->atts[x][y]->type == Attribute::Type::Wall) return false; 487 | } 488 | 489 | if(!entity) return true; 490 | 491 | for(auto &it: this->characters) 492 | { 493 | if(it->x == x && it->y == y) return false; 494 | } 495 | 496 | for(auto &it: this->npcs) 497 | { 498 | if(it->x == x && it->y == y) return false; 499 | } 500 | 501 | return true; 502 | } 503 | --------------------------------------------------------------------------------