├── .editorconfig ├── .gitattributes ├── resources ├── icon.rc ├── icon.ico ├── icon.png ├── kv6 │ ├── cp.kv6 │ ├── block.kv6 │ ├── intel.kv6 │ ├── spade.kv6 │ ├── .gitignore │ ├── grenade.kv6 │ ├── playerarms.kv6 │ ├── playerdead.kv6 │ ├── playerhead.kv6 │ ├── playerleg.kv6 │ ├── playerlegc.kv6 │ ├── semicasing.kv6 │ ├── semitracer.kv6 │ ├── smgcasing.kv6 │ ├── smgtracer.kv6 │ ├── playertorso.kv6 │ ├── playertorsoc.kv6 │ ├── shotguncasing.kv6 │ └── shotguntracer.kv6 ├── png │ ├── block.png │ ├── intel.png │ ├── ui │ │ ├── bg.png │ │ ├── exit.png │ │ ├── join.png │ │ ├── knob.png │ │ ├── ping.png │ │ ├── wait.png │ │ ├── alert.png │ │ ├── arrow.png │ │ ├── arrow2.png │ │ ├── flags.png │ │ ├── input.png │ │ ├── reload.png │ │ ├── box_check.png │ │ ├── box_empty.png │ │ ├── collapsed.png │ │ ├── expanded.png │ │ └── joystick.png │ ├── white.png │ ├── command.png │ ├── grenade.png │ ├── health.png │ ├── medical.png │ ├── player.png │ ├── smgammo.png │ ├── splash.png │ ├── tracer.png │ ├── .gitignore │ ├── semiammo.png │ └── shotgunammo.png ├── cache │ └── .gitignore ├── fonts │ ├── ft88.ttf │ ├── Fixedsys.ttf │ └── Terminal.ttf ├── logs │ └── .gitignore ├── wav │ └── .gitignore ├── screenshots │ └── .gitignore └── config.ini ├── docs ├── apoc.png ├── chat.png ├── babel.png ├── custom.png ├── custom_def.png ├── icon_small.png └── playerlist.png ├── resources.override └── png │ ├── target.png │ ├── splash_icon.png │ └── splashloader.png ├── .gitignore ├── src ├── gmi.h ├── list.h ├── stb_truetype.c ├── http.c ├── rpc.h ├── grenade.h ├── ping.h ├── gmi.c ├── utils.h ├── font.h ├── entitysystem.h ├── tracer.h ├── main.h ├── particle.h ├── file.h ├── channel.h ├── cameracontroller.h ├── aabb.h ├── log.h ├── weapon.h ├── minheap.h ├── glx.h ├── chunk.h ├── matrix.h ├── map.h ├── hud.h ├── entitysystem.c ├── camera.h ├── model.h ├── tesselator.h ├── config.h ├── list.c ├── hashtable.h ├── utils.c ├── sound.h ├── window.h ├── texture.h ├── matrix.c ├── aabb.c ├── rpc.c ├── common.h ├── minheap.c ├── log.c ├── tracer.c ├── grenade.c ├── player.h ├── ping.c ├── channel.c ├── ini.h ├── file.c ├── particle.c ├── font.c ├── model_normals.h ├── CMakeLists.txt └── ini.c ├── cmake └── Modules │ ├── Findglfw3.cmake │ ├── Finddeflate.cmake │ └── Findenet.cmake ├── .clang-format ├── CMakeLists.txt └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = tab 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c text eol=crlf 2 | *.h text eol=crlf 3 | * text=auto -------------------------------------------------------------------------------- /resources/icon.rc: -------------------------------------------------------------------------------- 1 | IDI_WINLOGO ICON icon.ico 2 | GLFW_ICON ICON icon.ico -------------------------------------------------------------------------------- /docs/apoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/apoc.png -------------------------------------------------------------------------------- /docs/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/chat.png -------------------------------------------------------------------------------- /docs/babel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/babel.png -------------------------------------------------------------------------------- /docs/custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/custom.png -------------------------------------------------------------------------------- /resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/icon.ico -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/icon.png -------------------------------------------------------------------------------- /docs/custom_def.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/custom_def.png -------------------------------------------------------------------------------- /docs/icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/icon_small.png -------------------------------------------------------------------------------- /docs/playerlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/docs/playerlist.png -------------------------------------------------------------------------------- /resources/kv6/cp.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/cp.kv6 -------------------------------------------------------------------------------- /resources/kv6/block.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/block.kv6 -------------------------------------------------------------------------------- /resources/kv6/intel.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/intel.kv6 -------------------------------------------------------------------------------- /resources/kv6/spade.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/spade.kv6 -------------------------------------------------------------------------------- /resources/png/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/block.png -------------------------------------------------------------------------------- /resources/png/intel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/intel.png -------------------------------------------------------------------------------- /resources/png/ui/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/bg.png -------------------------------------------------------------------------------- /resources/png/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/white.png -------------------------------------------------------------------------------- /resources/cache/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/fonts/ft88.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/fonts/ft88.ttf -------------------------------------------------------------------------------- /resources/kv6/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/kv6/grenade.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/grenade.kv6 -------------------------------------------------------------------------------- /resources/logs/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/png/command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/command.png -------------------------------------------------------------------------------- /resources/png/grenade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/grenade.png -------------------------------------------------------------------------------- /resources/png/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/health.png -------------------------------------------------------------------------------- /resources/png/medical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/medical.png -------------------------------------------------------------------------------- /resources/png/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/player.png -------------------------------------------------------------------------------- /resources/png/smgammo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/smgammo.png -------------------------------------------------------------------------------- /resources/png/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/splash.png -------------------------------------------------------------------------------- /resources/png/tracer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/tracer.png -------------------------------------------------------------------------------- /resources/png/ui/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/exit.png -------------------------------------------------------------------------------- /resources/png/ui/join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/join.png -------------------------------------------------------------------------------- /resources/png/ui/knob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/knob.png -------------------------------------------------------------------------------- /resources/png/ui/ping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/ping.png -------------------------------------------------------------------------------- /resources/png/ui/wait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/wait.png -------------------------------------------------------------------------------- /resources/wav/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/fonts/Fixedsys.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/fonts/Fixedsys.ttf -------------------------------------------------------------------------------- /resources/fonts/Terminal.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/fonts/Terminal.ttf -------------------------------------------------------------------------------- /resources/kv6/playerarms.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playerarms.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerdead.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playerdead.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerhead.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playerhead.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerleg.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playerleg.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerlegc.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playerlegc.kv6 -------------------------------------------------------------------------------- /resources/kv6/semicasing.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/semicasing.kv6 -------------------------------------------------------------------------------- /resources/kv6/semitracer.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/semitracer.kv6 -------------------------------------------------------------------------------- /resources/kv6/smgcasing.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/smgcasing.kv6 -------------------------------------------------------------------------------- /resources/kv6/smgtracer.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/smgtracer.kv6 -------------------------------------------------------------------------------- /resources/png/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | /*.png 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/png/semiammo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/semiammo.png -------------------------------------------------------------------------------- /resources/png/ui/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/alert.png -------------------------------------------------------------------------------- /resources/png/ui/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/arrow.png -------------------------------------------------------------------------------- /resources/png/ui/arrow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/arrow2.png -------------------------------------------------------------------------------- /resources/png/ui/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/flags.png -------------------------------------------------------------------------------- /resources/png/ui/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/input.png -------------------------------------------------------------------------------- /resources/png/ui/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/reload.png -------------------------------------------------------------------------------- /resources/kv6/playertorso.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playertorso.kv6 -------------------------------------------------------------------------------- /resources/kv6/playertorsoc.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/playertorsoc.kv6 -------------------------------------------------------------------------------- /resources/png/shotgunammo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/shotgunammo.png -------------------------------------------------------------------------------- /resources/png/ui/box_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/box_check.png -------------------------------------------------------------------------------- /resources/png/ui/box_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/box_empty.png -------------------------------------------------------------------------------- /resources/png/ui/collapsed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/collapsed.png -------------------------------------------------------------------------------- /resources/png/ui/expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/expanded.png -------------------------------------------------------------------------------- /resources/png/ui/joystick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/png/ui/joystick.png -------------------------------------------------------------------------------- /resources/screenshots/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources.override/png/target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources.override/png/target.png -------------------------------------------------------------------------------- /resources/kv6/shotguncasing.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/shotguncasing.kv6 -------------------------------------------------------------------------------- /resources/kv6/shotguntracer.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources/kv6/shotguntracer.kv6 -------------------------------------------------------------------------------- /resources.override/png/splash_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources.override/png/splash_icon.png -------------------------------------------------------------------------------- /resources.override/png/splashloader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utf-4096/butterspades/HEAD/resources.override/png/splashloader.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | Desktop.ini 3 | /nongithub 4 | /dist 5 | /build 6 | *.lib 7 | *.a 8 | *.o 9 | *.vxl 10 | *.exe 11 | *.zip 12 | *.kv6 13 | *.lib 14 | *.dll 15 | /bsresources.zip 16 | -------------------------------------------------------------------------------- /src/gmi.h: -------------------------------------------------------------------------------- 1 | #ifndef GMI_H 2 | #define GMI_H 3 | 4 | enum gmi_mode { 5 | GMI_MODE_UNDETECTED, 6 | GMI_MODE_UNKNOWN, 7 | GMI_MODE_ARENA, 8 | GMI_MODE_BABEL, 9 | GMI_MODE_TDM 10 | }; 11 | 12 | extern enum gmi_mode gmi_mode; 13 | extern unsigned int gmi_tdm_kills[2]; 14 | void gmi_mode_detect_message(char* message); 15 | 16 | #endif -------------------------------------------------------------------------------- /src/list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H 2 | #define LIST_H 3 | 4 | struct list { 5 | void* data; 6 | size_t elements, element_size, mem_size; 7 | }; 8 | 9 | enum list_traverse_direction { 10 | LIST_TRAVERSE_FORWARD, 11 | LIST_TRAVERSE_BACKWARD, 12 | }; 13 | 14 | int list_created(struct list* l); 15 | void list_create(struct list* l, size_t element_size); 16 | void list_free(struct list* l); 17 | void list_sort(struct list* l, int (*cmp)(const void* obj, const void* ref)); 18 | void* list_find(struct list* l, const void* ref, enum list_traverse_direction dir, int (*cmp)(const void* a, const void* b)); 19 | void* list_get(struct list* l, size_t i); 20 | void* list_add(struct list* l, void* e); 21 | void list_remove(struct list* l, size_t i); 22 | void list_clear(struct list* l); 23 | int list_size(struct list* l); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/stb_truetype.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #define STB_TRUETYPE_IMPLEMENTATION 21 | #define STBTT_RASTERIZER_VERSION 1 22 | 23 | #include "stb_truetype.h" 24 | -------------------------------------------------------------------------------- /src/http.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #define HTTP_IMPLEMENTATION 21 | 22 | #ifdef _WIN32 23 | #define _WIN32_WINNT 0x0501 24 | #endif 25 | 26 | #include 27 | 28 | #include "http.h" 29 | -------------------------------------------------------------------------------- /src/rpc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef RPC_H 21 | #define RPC_H 22 | 23 | enum RPC_VALUE { 24 | RPC_VALUE_SERVERNAME, 25 | RPC_VALUE_PLAYERS, 26 | RPC_VALUE_SLOTS, 27 | RPC_VALUE_SERVERURL, 28 | }; 29 | 30 | void rpc_init(void); 31 | void rpc_deinit(void); 32 | void rpc_setv(enum RPC_VALUE v, char* x); 33 | void rpc_seti(enum RPC_VALUE v, int x); 34 | void rpc_update(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/grenade.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef GRENADE_H 21 | #define GRENADE_H 22 | 23 | struct Grenade { 24 | unsigned char team; 25 | float fuse_length; 26 | float created; 27 | struct Position pos; 28 | struct Velocity velocity; 29 | }; 30 | 31 | void grenade_init(void); 32 | void grenade_add(struct Grenade* g); 33 | void grenade_update(float dt); 34 | void grenade_render(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/ping.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef PING_H 21 | #define PING_H 22 | 23 | #include 24 | 25 | struct ping_entry { 26 | ENetAddress addr; 27 | char aos[64]; 28 | float time_start; 29 | int trycount; 30 | }; 31 | 32 | void ping_init(); 33 | void ping_deinit(); 34 | void ping_check(char* addr, int port, char* aos); 35 | void* ping_update(void* data); 36 | void ping_start(void (*result)(void*, float, char*)); 37 | void ping_stop(); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /cmake/Modules/Findglfw3.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # Findglfw3 6 | # ------- 7 | # 8 | # Finds the glfw3 library 9 | # 10 | # This will define the following variables:: 11 | # 12 | # glfw3_FOUND - True if the system has the glfw3 library 13 | # 14 | # and also the following imported target: 15 | # 16 | # glfw3::glfw3 17 | # 18 | find_package(PkgConfig) 19 | pkg_check_modules(PC_glfw3 QUIET glfw3) 20 | 21 | find_path(glfw3_INCLUDE_DIR 22 | NAMES GLFW/glfw3.h 23 | PATHS ${PC_glfw3_INCLUDE_DIRS} ../../deps 24 | PATH_SUFFIXES GLFW 25 | ) 26 | find_library(glfw3_LIBRARY 27 | NAMES glfw glfw3 28 | PATHS ${PC_glfw3_LIBRARY_DIRS} ../../deps 29 | ) 30 | 31 | include(FindPackageHandleStandardArgs) 32 | find_package_handle_standard_args(glfw3 33 | FOUND_VAR glfw3_FOUND 34 | REQUIRED_VARS 35 | glfw3_LIBRARY 36 | glfw3_INCLUDE_DIR 37 | ) 38 | 39 | if (glfw3_FOUND) 40 | add_library(glfw3::glfw3 STATIC IMPORTED) 41 | set_target_properties(glfw3::glfw3 PROPERTIES 42 | IMPORTED_LOCATION ${glfw3_LIBRARY} 43 | INTERFACE_INCLUDE_DIRECTORIES ${glfw3_INCLUDE_DIR} 44 | ) 45 | endif (glfw3_FOUND) 46 | -------------------------------------------------------------------------------- /src/gmi.c: -------------------------------------------------------------------------------- 1 | // #include "network.h" 2 | #include 3 | #include 4 | #include 5 | #include "gmi.h" 6 | #include "log.h" 7 | 8 | enum gmi_mode gmi_mode = GMI_MODE_UNDETECTED; 9 | unsigned int gmi_tdm_kills[] = {0, 0}; 10 | 11 | void gmi_mode_detect_message(char* message) { 12 | char* lower = malloc(sizeof(char) * strlen(message) + 1); 13 | for(unsigned int i = 0; *(message + i) != '\0'; i++) { 14 | lower[i] = tolower(message[i]); 15 | } 16 | 17 | lower[strlen(message)] = '\0'; 18 | 19 | char* ptr; 20 | if((ptr = strstr(lower, "game mode: ")) != NULL) { 21 | ptr += 11; 22 | } else if((ptr = strstr(lower, "gamemode: ")) != NULL) { 23 | ptr += 10; 24 | } else { 25 | goto end; 26 | return; 27 | } 28 | 29 | if(!strcmp(ptr, "arena") || !strcmp(ptr, "arena by yourself")) { gmi_mode = GMI_MODE_ARENA; } 30 | else if(!strcmp(ptr, "babel")) { gmi_mode = GMI_MODE_BABEL; } 31 | else if(!strcmp(ptr, "tdm")) { gmi_mode = GMI_MODE_TDM; } 32 | else { 33 | gmi_mode = GMI_MODE_UNKNOWN; 34 | log_info("unknown mode %s", ptr); 35 | goto end; 36 | } 37 | 38 | log_info("DETERMINED GAMEMODE: %s", ptr); 39 | 40 | end: 41 | free(lower); 42 | } 43 | 44 | void gmi_parse_tdm(char* message) { 45 | 46 | } -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: WebKit 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: 'false' 5 | AlignConsecutiveDeclarations: 'false' 6 | AlignTrailingComments: 'true' 7 | AllowAllParametersOfDeclarationOnNextLine: 'true' 8 | AllowShortBlocksOnASingleLine: 'true' 9 | AllowShortCaseLabelsOnASingleLine: 'true' 10 | AllowShortFunctionsOnASingleLine: Empty 11 | AllowShortIfStatementsOnASingleLine: 'false' 12 | AllowShortLoopsOnASingleLine: 'false' 13 | AlwaysBreakAfterDefinitionReturnType: None 14 | AlwaysBreakAfterReturnType: None 15 | AlwaysBreakBeforeMultilineStrings: 'false' 16 | BreakBeforeBraces: Attach 17 | BreakBeforeTernaryOperators: 'false' 18 | Cpp11BracedListStyle: 'true' 19 | ExperimentalAutoDetectBinPacking: 'false' 20 | IndentCaseLabels: 'true' 21 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 22 | Language: Cpp 23 | PointerAlignment: Left 24 | SortIncludes: 'false' 25 | SpaceAfterCStyleCast: 'false' 26 | SpaceBeforeAssignmentOperators: 'true' 27 | SpaceBeforeParens: Never 28 | SpaceInEmptyParentheses: 'false' 29 | SpacesInCStyleCastParentheses: 'false' 30 | SpacesInParentheses: 'false' 31 | SpacesInSquareBrackets: 'false' 32 | TabWidth: '4' 33 | UseTab: Always 34 | MaxEmptyLinesToKeep: 1 35 | ReflowComments: true 36 | ColumnLimit: 120 37 | 38 | ... 39 | -------------------------------------------------------------------------------- /cmake/Modules/Finddeflate.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # Finddeflate 6 | # ------- 7 | # 8 | # Finds the libdeflate library 9 | # 10 | # This will define the following variables:: 11 | # 12 | # deflate_FOUND - True if the system has the deflate library 13 | # 14 | # and also the following imported target: 15 | # 16 | # deflate::deflate 17 | # 18 | 19 | find_package(PkgConfig) 20 | pkg_check_modules(PC_deflate QUIET deflate) 21 | 22 | find_path(deflate_INCLUDE_DIR 23 | NAMES libdeflate.h 24 | PATHS ${PC_deflate_INCLUDE_DIRS} ../../deps 25 | PATH_SUFFIXES deflate 26 | ) 27 | find_library(deflate_LIBRARY 28 | NAMES deflate 29 | PATHS ${PC_deflate_LIBRARY_DIRS} ../../deps 30 | ) 31 | 32 | include(FindPackageHandleStandardArgs) 33 | find_package_handle_standard_args(deflate 34 | FOUND_VAR deflate_FOUND 35 | REQUIRED_VARS 36 | deflate_LIBRARY 37 | deflate_INCLUDE_DIR 38 | ) 39 | 40 | if (deflate_FOUND) 41 | add_library(deflate::deflate STATIC IMPORTED) 42 | set_target_properties(deflate::deflate PROPERTIES 43 | IMPORTED_LOCATION ${deflate_LIBRARY} 44 | INTERFACE_INCLUDE_DIRECTORIES ${deflate_INCLUDE_DIR} 45 | ) 46 | endif (deflate_FOUND) 47 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef UTILS_H 21 | #define UTILS_H 22 | 23 | #include 24 | #include 25 | 26 | #include "hashtable.h" 27 | 28 | int base64_decode(char* data, int len); 29 | 30 | int int_cmp(void* first_key, void* second_key, size_t key_size); 31 | size_t int_hash(void* raw_key, size_t key_size); 32 | void ht_iterate_remove(HashTable* ht, void* user, bool (*callback)(void* key, void* value, void* user)); 33 | bool ht_iterate(HashTable* ht, void* user, bool (*callback)(void* key, void* value, void* user)); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/font.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef FONT_H 21 | #define FONT_H 22 | 23 | enum font_type { 24 | FONT_FIXEDSYS, 25 | FONT_SMALLFNT, 26 | FONT_FANTASY, 27 | }; 28 | 29 | void font_init(void); 30 | void font_reset(void); 31 | float font_length(float h, char* text); 32 | void font_render(float x, float y, float h, char* text); 33 | void font_render_shadow(float x, float y, float h, char* text, float a); 34 | void font_centered(float x, float y, float h, char* text); 35 | void font_centered_shadow(float x, float y, float h, char* text, float a); 36 | void font_select(enum font_type type); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(BetterSpades C) 3 | 4 | set(BETTERSPADES_MAJOR 0) 5 | set(BETTERSPADES_MINOR 1) 6 | set(BETTERSPADES_PATCH 5) 7 | 8 | option(ENABLE_TOUCH "Enable touch support including ingame overlay" OFF) 9 | option(ENABLE_ANDROID_FILE "Use SDL's file functions" OFF) 10 | option(ENABLE_OPENGLES "Build for OpenGL ES" OFF) 11 | option(ENABLE_SDL "Build against SDL backend" OFF) 12 | option(ENABLE_GLFW "Build against GLFW3 backend" ON) 13 | option(ENABLE_SOUND "Enable sound support using OpenAL" ON) 14 | option(ENABLE_RPC "Enable Discord Rich Presence support" OFF) 15 | 16 | 17 | if((ENABLE_ANDROID_FILE OR ENABLE_TOUCH OR ENABLE_OPENGLES) AND NOT ENABLE_SDL) 18 | message(FATAL_ERROR "Enable SDL to use ENABLE_ANDROID_FILE, ENABLE_TOUCH or ENABLE_OPENGLES") 19 | endif() 20 | if(ENABLE_SDL AND ENABLE_GLFW) 21 | message(FATAL_ERROR "Only one backend must be selected") 22 | endif() 23 | if(NOT ENABLE_SDL AND NOT ENABLE_GLFW) 24 | message(FATAL_ERROR "Enable SDL or GLFW") 25 | endif() 26 | 27 | message(STATUS "Compiler is ${CMAKE_CXX_COMPILER_ID}") 28 | message(STATUS "Build type is ${CMAKE_BUILD_TYPE}") 29 | 30 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 31 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 32 | add_compile_options(-Ofast) 33 | else() 34 | add_compile_options(-Ofast -g -march=native) 35 | endif() 36 | endif() 37 | 38 | add_subdirectory(src) 39 | -------------------------------------------------------------------------------- /src/entitysystem.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef ENTITY_SYSTEM_H 21 | #define ENTITY_SYSTEM_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | struct entity_system { 28 | void* buffer; 29 | size_t count; 30 | size_t length; 31 | size_t object_size; 32 | pthread_mutex_t lock; 33 | }; 34 | 35 | void entitysys_create(struct entity_system* es, size_t object_size, size_t initial_size); 36 | 37 | void entitysys_add(struct entity_system* es, void* object); 38 | 39 | void entitysys_iterate(struct entity_system* es, void* user, bool (*callback)(void* object, void* user)); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/tracer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef TRACER_H 21 | #define TRACER_H 22 | 23 | #include "aabb.h" 24 | #include "player.h" 25 | #include "camera.h" 26 | 27 | struct Tracer { 28 | struct Camera_HitType hit; 29 | float x, y, z; 30 | Ray r; 31 | int type; 32 | float created; 33 | }; 34 | 35 | void tracer_minimap(int large, float scalef, float minimap_x, float minimap_y); 36 | void tracer_pvelocity(float* o, struct Player* p); 37 | void tracer_add(int type, float x, float y, float z, float dx, float dy, float dz); 38 | void tracer_update(float dt); 39 | void tracer_render(void); 40 | void tracer_init(void); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef MAIN_H 21 | #define MAIN_H 22 | 23 | #include "window.h" 24 | 25 | void reshape(struct window_instance* window, int width, int height); 26 | void text_input(struct window_instance* window, unsigned int codepoint); 27 | void keys(struct window_instance* window, int key, int scancode, int action, int mods); 28 | void mouse_click(struct window_instance* window, int button, int action, int mods); 29 | void mouse(struct window_instance* window, double x, double y); 30 | void mouse_scroll(struct window_instance* window, double xoffset, double yoffset); 31 | void on_error(int i, const char* s); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/particle.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef PARTICLE_H 21 | #define PARTICLE_H 22 | 23 | #include "player.h" 24 | 25 | struct Particle { 26 | float x, y, z; 27 | float vx, vy, vz; 28 | float ox, oy, oz; 29 | unsigned char type; 30 | float size; 31 | float fade; 32 | unsigned int color; 33 | }; 34 | 35 | void particle_init(void); 36 | void particle_update(float dt); 37 | void particle_render(void); 38 | void particle_create_casing(struct Player* p); 39 | void particle_create(unsigned int color, float x, float y, float z, float velocity, float velocity_y, int amount, 40 | float min_size, float max_size); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /cmake/Modules/Findenet.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # Findenet 6 | # ------- 7 | # 8 | # Finds the libenet library 9 | # 10 | # This will define the following variables:: 11 | # 12 | # enet_FOUND - True if the system has the enet library 13 | # 14 | # and also the following imported target: 15 | # 16 | # enet::enet 17 | # 18 | find_package(PkgConfig) 19 | pkg_check_modules(PC_enet QUIET enet) 20 | 21 | find_path(enet_INCLUDE_DIR 22 | NAMES enet/enet.h 23 | PATHS ${PC_enet_INCLUDE_DIRS} ../../deps 24 | PATH_SUFFIXES enet 25 | ) 26 | 27 | find_library(enet_LIBRARY 28 | NAMES enet 29 | PATHS ${PC_enet_LIBRARY_DIRS} ../../deps 30 | ) 31 | 32 | include(FindPackageHandleStandardArgs) 33 | find_package_handle_standard_args(enet 34 | FOUND_VAR enet_FOUND 35 | REQUIRED_VARS 36 | enet_LIBRARY 37 | enet_INCLUDE_DIR 38 | ) 39 | 40 | if (enet_FOUND) 41 | add_library(enet::enet STATIC IMPORTED) 42 | set_target_properties(enet::enet PROPERTIES 43 | IMPORTED_LOCATION ${enet_LIBRARY} 44 | INTERFACE_INCLUDE_DIRECTORIES ${enet_INCLUDE_DIR} 45 | ) 46 | #target_include_directories(enet::enet INTERFACE ${enet_INCLUDE_DIR}) 47 | if (WIN32) 48 | set_target_properties(enet::enet PROPERTIES 49 | INTERFACE_LINK_LIBRARIES "ws2_32;winmm" 50 | ) 51 | endif (WIN32) 52 | endif (enet_FOUND) 53 | -------------------------------------------------------------------------------- /src/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef FILE_H 21 | #define FILE_H 22 | 23 | void* file_open(const char* name, const char* mode); 24 | void file_printf(void* file, const char* fmt, ...); 25 | void file_close(void* file); 26 | int file_size(const char* name); 27 | int file_dir_exists(const char* path); 28 | int file_dir_create(const char* path); 29 | int file_exists(const char* name); 30 | unsigned char* file_load(const char* name); 31 | float buffer_readf(unsigned char* buffer, int index); 32 | unsigned int buffer_read32(unsigned char* buffer, int index); 33 | unsigned short buffer_read16(unsigned char* buffer, int index); 34 | unsigned char buffer_read8(unsigned char* buffer, int index); 35 | void file_url(char* url); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/channel.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef CHANNEL_H 21 | #define CHANNEL_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | struct channel { 28 | size_t object_size; 29 | size_t initial_length; 30 | size_t length; 31 | size_t count; 32 | size_t loc_insert; 33 | size_t loc_remove; 34 | void* queue; 35 | pthread_mutex_t lock; 36 | pthread_cond_t signal; 37 | }; 38 | 39 | bool channel_create(struct channel* ch, size_t object_size, size_t length); 40 | 41 | size_t channel_size(struct channel* ch); 42 | 43 | void channel_destroy(struct channel* ch); 44 | 45 | void channel_put(struct channel* ch, void* object); 46 | 47 | void channel_await(struct channel* ch, void* object); 48 | 49 | void channel_clear(struct channel* ch); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/cameracontroller.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef CAMERACONTROLLER_H 21 | #define CAMERACONTROLLER_H 22 | 23 | extern int cameracontroller_bodyview_mode; 24 | extern int cameracontroller_bodyview_player; 25 | extern int cameracontroller_yclamp; 26 | extern float cameracontroller_bodyview_zoom; 27 | 28 | void cameracontroller_death_init(int player, float x, float y, float z); 29 | 30 | void cameracontroller_fps(float dt); 31 | void cameracontroller_spectator(float dt); 32 | void cameracontroller_bodyview(float dt); 33 | void cameracontroller_selection(float dt); 34 | void cameracontroller_death(float dt); 35 | 36 | void cameracontroller_fps_render(void); 37 | void cameracontroller_spectator_render(void); 38 | void cameracontroller_bodyview_render(void); 39 | void cameracontroller_selection_render(void); 40 | void cameracontroller_death_render(void); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/aabb.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef AABB_H 21 | #define AABB_H 22 | 23 | #include 24 | 25 | typedef struct { 26 | union { 27 | struct { 28 | float min_x, min_y, min_z; 29 | }; 30 | float min[3]; 31 | }; 32 | union { 33 | struct { 34 | float max_x, max_y, max_z; 35 | }; 36 | float max[3]; 37 | }; 38 | } AABB; 39 | 40 | typedef struct { 41 | union { 42 | struct { 43 | float x, y, z; 44 | }; 45 | float coords[3]; 46 | } origin; 47 | union { 48 | struct { 49 | float x, y, z; 50 | }; 51 | float coords[3]; 52 | } direction; 53 | } Ray; 54 | 55 | bool aabb_intersection(AABB* a, AABB* b); 56 | bool aabb_intersection_ray(AABB* a, Ray* r, float* distance); 57 | bool aabb_intersection_terrain(AABB* a, int miny); 58 | void aabb_set_size(AABB* a, float x, float y, float z); 59 | void aabb_set_center(AABB* a, float x, float y, float z); 60 | void aabb_render(AABB* a); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See `log.c` for details. 6 | */ 7 | 8 | #ifndef LOG_H 9 | #define LOG_H 10 | 11 | #define __FILENAME__ \ 12 | (__builtin_strrchr(__FILE__, '/') \ 13 | ? (__builtin_strrchr(__FILE__, '/') + 1) \ 14 | : (__builtin_strrchr(__FILE__, '\\') \ 15 | ? __builtin_strrchr(__FILE__, '\\') + 1 \ 16 | : __FILE__)) 17 | 18 | #include 19 | #include 20 | 21 | #define LOG_VERSION "0.1.0" 22 | 23 | typedef void (*log_LockFn)(void *udata, int lock); 24 | 25 | enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; 26 | 27 | #define log_trace(...) log_log(LOG_TRACE, __FILENAME__, __LINE__, __VA_ARGS__) 28 | #define log_debug(...) log_log(LOG_DEBUG, __FILENAME__, __LINE__, __VA_ARGS__) 29 | #define log_info(...) log_log(LOG_INFO, __FILENAME__, __LINE__, __VA_ARGS__) 30 | #define log_warn(...) log_log(LOG_WARN, __FILENAME__, __LINE__, __VA_ARGS__) 31 | #define log_error(...) log_log(LOG_ERROR, __FILENAME__, __LINE__, __VA_ARGS__) 32 | #define log_fatal(...) log_log(LOG_FATAL, __FILENAME__, __LINE__, __VA_ARGS__) 33 | 34 | void log_set_udata(void *udata); 35 | void log_set_lock(log_LockFn fn); 36 | void log_set_fp(FILE *fp); 37 | void log_set_level(int level); 38 | void log_set_quiet(int enable); 39 | 40 | void log_log(int level, const char *file, int line, const char *fmt, ...); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/weapon.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef WEAPON_H 21 | #define WEAPON_H 22 | 23 | #include "player.h" 24 | #include "sound.h" 25 | #include "model.h" 26 | 27 | void weapon_update(void); 28 | void weapon_set(bool restock); 29 | void weapon_reload(void); 30 | int weapon_reloading(void); 31 | int weapon_can_reload(void); 32 | void weapon_reload_abort(void); 33 | void weapon_shoot(void); 34 | int weapon_block_damage(int gun); 35 | float weapon_delay(int gun); 36 | int weapon_ammo(int gun); 37 | int weapon_ammo_reserved(int gun); 38 | struct kv6_t* weapon_casing(int gun); 39 | float weapon_recoil_anim(int gun); 40 | struct Sound_wav* weapon_sound(int gun); 41 | struct Sound_wav* weapon_sound_reload(int gun); 42 | void weapon_spread(struct Player* p, float* d); 43 | void weapon_recoil(int gun, double* horiz_recoil, double* vert_recoil); 44 | 45 | extern float weapon_reload_start, weapon_last_shot; 46 | extern unsigned char weapon_reload_inprogress; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/minheap.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef MINHEAP_H 21 | #define MINHEAP_H 22 | 23 | #define pos_key(x, y, z) (((z) << 20) | ((x) << 8) | (y)) 24 | #define pos_keyx(key) (((key) >> 8) & 0xFFF) 25 | #define pos_keyy(key) ((key)&0xFF) 26 | #define pos_keyz(key) (((key) >> 20) & 0xFFF) 27 | 28 | struct path_vec { 29 | short x, y, z; 30 | }; 31 | 32 | struct minheap_block { 33 | uint32_t pos; 34 | }; 35 | 36 | struct minheap { 37 | int index; 38 | int length; 39 | struct minheap_block* nodes; 40 | }; 41 | 42 | int int_cmp(void* first_key, void* second_key, size_t key_size); 43 | size_t int_hash(void* raw_key, size_t key_size); 44 | 45 | void minheap_create(struct minheap* h); 46 | void minheap_clear(struct minheap* h); 47 | void minheap_destroy(struct minheap* h); 48 | int minheap_isempty(struct minheap* h); 49 | struct minheap_block minheap_extract(struct minheap* h); 50 | void minheap_set(struct minheap* h, struct minheap_block* b, int value); 51 | struct minheap_block* minheap_put(struct minheap* h, struct minheap_block* b); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/glx.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | // for future opengl es abstraction layer 21 | 22 | #ifndef GLX_H 23 | #define GLX_H 24 | 25 | #include 26 | #include 27 | 28 | extern int glx_version; 29 | extern int glx_fog; 30 | 31 | struct glx_displaylist { 32 | uint32_t legacy; 33 | uint32_t modern; 34 | size_t size; 35 | size_t buffer_size; 36 | bool has_normal; 37 | bool has_color; 38 | }; 39 | 40 | enum { 41 | GLX_DISPLAYLIST_NORMAL, 42 | GLX_DISPLAYLIST_ENHANCED, 43 | GLX_DISPLAYLIST_POINTS, 44 | }; 45 | 46 | void glx_init(void); 47 | 48 | int glx_shader(const char* vertex, const char* fragment); 49 | 50 | void glx_enable_sphericalfog(void); 51 | void glx_disable_sphericalfog(void); 52 | 53 | void glx_displaylist_create(struct glx_displaylist* x, bool has_color, bool has_normal); 54 | void glx_displaylist_destroy(struct glx_displaylist* x); 55 | void glx_displaylist_update(struct glx_displaylist* x, size_t size, int type, void* color, void* vertex, void* normal); 56 | void glx_displaylist_draw(struct glx_displaylist* x, int type); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/chunk.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef CHUNK_H 21 | #define CHUNK_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "glx.h" 29 | #include "tesselator.h" 30 | #include "libvxl.h" 31 | 32 | #define CHUNK_SIZE 16 33 | #define CHUNKS_PER_DIM (512 / CHUNK_SIZE) 34 | 35 | extern struct chunk { 36 | struct glx_displaylist display_list; 37 | int max_height; 38 | bool updated; 39 | bool created; 40 | int x, y; 41 | } chunks[CHUNKS_PER_DIM * CHUNKS_PER_DIM]; 42 | 43 | #define CHUNK_WORKERS_MAX 16 44 | 45 | void chunk_init(void); 46 | 47 | void chunk_block_update(int x, int y, int z); 48 | void chunk_update_all(void); 49 | void* chunk_generate(void* data); 50 | void chunk_generate_greedy(struct libvxl_chunk_copy* blocks, size_t start_x, size_t start_z, struct tesselator* tess, 51 | int* max_height); 52 | void chunk_generate_naive(struct libvxl_chunk_copy* blocks, struct tesselator* tess, int* max_height, int ao); 53 | void chunk_rebuild_all(void); 54 | void chunk_draw_visible(void); 55 | void chunk_queue_blocks(); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/matrix.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef MATRIX_H 21 | #define MATRIX_H 22 | 23 | #include 24 | 25 | extern mat4 matrix_view; 26 | extern mat4 matrix_model; 27 | extern mat4 matrix_projection; 28 | 29 | void matrix_multiply(mat4 m, mat4 n); 30 | void matrix_load(mat4 m, mat4 n); 31 | void matrix_rotate(mat4 m, float angle, float x, float y, float z); 32 | void matrix_translate(mat4 m, float x, float y, float z); 33 | void matrix_scale3(mat4 m, float s); 34 | void matrix_scale(mat4 m, float sx, float sy, float sz); 35 | void matrix_identity(mat4 m); 36 | void matrix_push(mat4 m); 37 | void matrix_pop(mat4 m); 38 | void matrix_vector(mat4 m, vec4 v); 39 | void matrix_ortho(mat4 m, float left, float right, float bottom, float top, float nearv, float farv); 40 | void matrix_perspective(mat4 m, float fovy, float aspect, float zNear, float zFar); 41 | void matrix_lookAt(mat4 m, double eyex, double eyey, double eyez, double centerx, double centery, double centerz, 42 | double upx, double upy, double upz); 43 | void matrix_upload(void); 44 | void matrix_upload_p(void); 45 | void matrix_pointAt(mat4 m, float dx, float dy, float dz); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/map.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef MAP_H 21 | #define MAP_H 22 | 23 | #include 24 | 25 | #include 26 | #undef pos_key 27 | 28 | extern int map_size_x; 29 | extern int map_size_y; 30 | extern int map_size_z; 31 | 32 | extern float fog_color[4]; 33 | 34 | struct Point { 35 | int x, y, z; 36 | }; 37 | 38 | void map_init(); 39 | int map_object_visible(float x, float y, float z); 40 | int map_damage(int x, int y, int z, int damage); 41 | int map_damage_get(int x, int y, int z); 42 | bool map_damage_action(int x, int y, int z); 43 | void map_damaged_voxels_render(); 44 | void map_update_physics(int x, int y, int z); 45 | float map_sunblock(int x, int y, int z); 46 | bool map_isair(int x, int y, int z); 47 | unsigned int map_get(int x, int y, int z); 48 | void map_set(int x, int y, int z, unsigned int color); 49 | int map_cube_line(int x1, int y1, int z1, int x2, int y2, int z2, struct Point* cube_array); 50 | void map_vxl_setgeom(int x, int y, int z, unsigned int t, unsigned int* map); 51 | void map_vxl_setcolor(int x, int y, int z, unsigned int t, unsigned int* map); 52 | int map_dirt_color(int x, int y, int z); 53 | int map_placedblock_color(int color); 54 | void map_vxl_load(void* v, size_t size); 55 | void map_collapsing_render(void); 56 | void map_collapsing_update(float dt); 57 | int map_height_at(int x, int z); 58 | void map_save_file(const char* filename); 59 | void map_copy_blocks(struct libvxl_chunk_copy* copy, size_t x, size_t y); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/hud.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef HUD_H 21 | #define HUD_H 22 | 23 | #include 24 | 25 | #include "microui.h" 26 | #include "texture.h" 27 | #include "window.h" 28 | 29 | struct hud { 30 | void (*init)(); 31 | void (*render_3D)(); 32 | void (*render_2D)(mu_Context* ctx, float scalex, float scaley); 33 | void (*input_keyboard)(int key, int action, int mods, int internal); 34 | void (*input_mouselocation)(double x, double y); 35 | void (*input_mouseclick)(double x, double y, int button, int action, int mods); 36 | void (*input_mousescroll)(double yoffset); 37 | void (*input_touch)(void* finger, int action, float x, float y, float dx, float dy); 38 | struct texture* (*ui_images)(int icon_id, bool* resize); 39 | char render_world; 40 | char render_localplayer; 41 | mu_Context* ctx; 42 | }; 43 | 44 | struct serverlist_entry { 45 | int current, max; 46 | char name[32]; 47 | char map[21]; 48 | char gamemode[8]; 49 | int ping; 50 | char identifier[32]; 51 | char country[4]; 52 | }; 53 | 54 | extern int screen_current; 55 | extern int show_exit; 56 | 57 | extern struct hud hud_ingame; 58 | extern struct hud hud_mapload; 59 | extern struct hud hud_serverlist; 60 | extern struct hud hud_settings; 61 | extern struct hud hud_controls; 62 | 63 | extern struct hud* hud_active; 64 | extern struct window_instance* hud_window; 65 | 66 | #define HUD_FLAG_INDEX_START 64 67 | 68 | void hud_change(struct hud* new); 69 | void hud_init(); 70 | void hud_mousemode(int mode); 71 | int hud_accent_color(); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/entitysystem.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "entitysystem.h" 26 | 27 | void entitysys_create(struct entity_system* es, size_t object_size, size_t initial_size) { 28 | assert(es != NULL && object_size > 0 && initial_size > 0); 29 | 30 | es->buffer = malloc(object_size * initial_size); 31 | es->count = 0; 32 | es->object_size = object_size; 33 | es->length = initial_size; 34 | 35 | pthread_mutex_init(&es->lock, NULL); 36 | } 37 | 38 | void entitysys_iterate(struct entity_system* es, void* user, bool (*callback)(void* object, void* user)) { 39 | assert(es != NULL && callback != NULL); 40 | 41 | pthread_mutex_lock(&es->lock); 42 | 43 | uint8_t* obj = es->buffer; 44 | for(size_t k = 0; k < es->count; k++, obj += es->object_size) { 45 | if(callback(obj, user)) { 46 | if(es->count > 1) 47 | memcpy(obj, (uint8_t*)es->buffer + es->object_size * (es->count - 1), es->object_size); 48 | 49 | es->count--; 50 | } 51 | } 52 | 53 | pthread_mutex_unlock(&es->lock); 54 | } 55 | 56 | void entitysys_add(struct entity_system* es, void* object) { 57 | assert(es != NULL && object != NULL); 58 | 59 | pthread_mutex_lock(&es->lock); 60 | 61 | if(es->count >= es->length) { 62 | es->length *= 2; 63 | es->buffer = realloc(es->buffer, es->object_size * es->length); 64 | } 65 | 66 | memcpy((uint8_t*)es->buffer + es->object_size * (es->count++), object, es->object_size); 67 | 68 | pthread_mutex_unlock(&es->lock); 69 | } 70 | -------------------------------------------------------------------------------- /src/camera.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef CAMERA_H 21 | #define CAMERA_H 22 | 23 | enum camera_mode { 24 | CAMERAMODE_SELECTION, 25 | CAMERAMODE_FPS, 26 | CAMERAMODE_SPECTATOR, 27 | CAMERAMODE_BODYVIEW, 28 | CAMERAMODE_DEATH, 29 | }; 30 | 31 | #define CAMERA_DEFAULT_FOV 70.0F 32 | #define CAMERA_MAX_FOV 100.0F 33 | 34 | extern enum camera_mode camera_mode; 35 | 36 | extern float frustum[6][4]; 37 | extern float camera_rot_x, camera_rot_y; 38 | extern float camera_x, camera_y, camera_z; 39 | extern float camera_vx, camera_vy, camera_vz; 40 | extern float camera_size; 41 | extern float camera_height; 42 | extern float camera_eye_height; 43 | extern float camera_movement_x, camera_movement_y, camera_movement_z; 44 | extern float camera_speed; 45 | 46 | struct Camera_HitType { 47 | char type; 48 | float x, y, z, distance; 49 | int xb, yb, zb; 50 | unsigned char player_id, player_section; 51 | }; 52 | 53 | #define CAMERA_HITTYPE_NONE 0 54 | #define CAMERA_HITTYPE_BLOCK 1 55 | #define CAMERA_HITTYPE_PLAYER 2 56 | 57 | void camera_hit_fromplayer(struct Camera_HitType* hit, int player_id, float range); 58 | void camera_hit(struct Camera_HitType* hit, int exclude_player, float x, float y, float z, float ray_x, float ray_y, 59 | float ray_z, float range); 60 | void camera_hit_mask(struct Camera_HitType* hit, int exclude_player, float x, float y, float z, float ray_x, 61 | float ray_y, float ray_z, float range); 62 | 63 | float camera_fov_scaled(); 64 | void camera_ExtractFrustum(void); 65 | unsigned char camera_PointInFrustum(float x, float y, float z); 66 | int camera_CubeInFrustum(float x, float y, float z, float size, float size_y); 67 | int* camera_terrain_pick(unsigned char mode); 68 | int* camera_terrain_pickEx(unsigned char mode, float x, float y, float z, float ray_x, float ray_y, float ray_z); 69 | void camera_overflow_adjust(void); 70 | void camera_apply(void); 71 | void camera_update(float dt); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /resources/config.ini: -------------------------------------------------------------------------------- 1 | [client] 2 | name = Deuce 3 | xres = 1024 4 | yres = 768 5 | vol = 10 6 | inverty = 0 7 | windowed = 1 8 | language = 0 9 | mouse_sensitivity = 5.000000 10 | show_news = 1 11 | multisamples = 0 12 | greedy_meshing = 0 13 | vsync = 1 14 | show_fps = 0 15 | voxlap_models = 0 16 | force_displaylist = 0 17 | smooth_fog = 0 18 | ambient_occlusion = 0 19 | camera_fov = 70.00000 20 | hold_down_sights = 0 21 | chat_shadow = 0.6 22 | chat_flip_on_open = 1 23 | show_player_arms = 0 24 | bg_tile = 1 25 | bg_tile_speed = 0.09 26 | ui_accent_r = 110 27 | ui_accent_g = 90 28 | ui_accent_b = 230 29 | lighten_colors = 120 30 | hud_shadows = 1 31 | show_names_in_spec = 1 32 | chat_spacing = 6 33 | spectator_speed = 1.0 34 | iron_sight = 0 35 | gmi = 0 36 | disable_raw_input = 0 37 | ui_spacing = 8 38 | ui_padding = 5 39 | 40 | [controls] 41 | move_forward = 87 42 | move_backward = 83 43 | move_left = 65 44 | move_right = 68 45 | jump = 32 46 | crouch = 341 47 | sneak = 86 48 | sprint = 340 49 | view_map = 77 50 | reload = 82 51 | cube_color_up = 265 52 | cube_color_down = 264 53 | cube_color_left = 263 54 | cube_color_right = 262 55 | cube_color_sample = 69 56 | quit_game = 256 57 | volume_up = 334 58 | volume_down = 333 59 | view_score = 258 60 | change_team = 44 61 | change_weapon = 46 62 | screenshot = 294 63 | fullscreen = 300 64 | chat_global = 84 65 | chat_command = 47 66 | hide_hud = 295 67 | network_stats = 301 68 | last_tool = 81 69 | tool_block = 50 70 | tool_grenade = 52 71 | tool_gun = 51 72 | tool_spade = 49 73 | save_map = 298 74 | -------------------------------------------------------------------------------- /src/model.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef MODEL_H 21 | #define MODEL_H 22 | 23 | #include 24 | #include 25 | 26 | #include "aabb.h" 27 | #include "glx.h" 28 | #include "tesselator.h" 29 | 30 | #define KV6_VIS_NEG_X (1 << 0) 31 | #define KV6_VIS_POS_X (1 << 1) 32 | #define KV6_VIS_NEG_Z (1 << 2) 33 | #define KV6_VIS_POS_Z (1 << 3) 34 | #define KV6_VIS_POS_Y (1 << 4) 35 | #define KV6_VIS_NEG_Y (1 << 5) 36 | 37 | struct kv6_voxel { 38 | uint16_t x, y, z; 39 | uint8_t visfaces; 40 | uint32_t color; 41 | }; 42 | 43 | struct kv6_t { 44 | uint16_t xsiz, ysiz, zsiz; 45 | float xpiv, ypiv, zpiv; 46 | bool has_display_list, colorize; 47 | struct glx_displaylist display_list[2]; 48 | struct kv6_voxel* voxels; 49 | int voxel_count; 50 | float scale; 51 | float red, green, blue; 52 | }; 53 | 54 | extern struct kv6_t model_playerdead; 55 | extern struct kv6_t model_playerhead; 56 | extern struct kv6_t model_playertorso; 57 | extern struct kv6_t model_playertorsoc; 58 | extern struct kv6_t model_playerarms; 59 | extern struct kv6_t model_playerleg; 60 | extern struct kv6_t model_playerlegc; 61 | extern struct kv6_t model_intel; 62 | extern struct kv6_t model_tent; 63 | 64 | extern struct kv6_t model_semi; 65 | extern struct kv6_t model_smg; 66 | extern struct kv6_t model_shotgun; 67 | extern struct kv6_t model_spade; 68 | extern struct kv6_t model_block; 69 | extern struct kv6_t model_grenade; 70 | 71 | extern struct kv6_t model_semi_tracer; 72 | extern struct kv6_t model_smg_tracer; 73 | extern struct kv6_t model_shotgun_tracer; 74 | 75 | extern struct kv6_t model_semi_casing; 76 | extern struct kv6_t model_smg_casing; 77 | extern struct kv6_t model_shotgun_casing; 78 | 79 | void kv6_calclight(int x, int y, int z); 80 | void kv6_rebuild_complete(void); 81 | void kv6_rebuild(struct kv6_t* kv6); 82 | void kv6_render(struct kv6_t* kv6, unsigned char team); 83 | void kv6_load(struct kv6_t* kv6, void* bytes, float scale); 84 | void kv6_init(void); 85 | 86 | extern float kv6_normals[256][3]; 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/tesselator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef TESSELATOR_H 21 | #define TESSELATOR_H 22 | 23 | #include 24 | 25 | #include "glx.h" 26 | 27 | #ifdef OPENGL_ES 28 | #define TESSELATE_TRIANGLES 29 | #else 30 | #define TESSELATE_QUADS 31 | #endif 32 | 33 | enum tesselator_vertex_type { 34 | VERTEX_INT, 35 | VERTEX_FLOAT, 36 | }; 37 | 38 | struct tesselator { 39 | void* vertices; 40 | int8_t* normals; 41 | uint32_t* colors; 42 | uint32_t quad_count; 43 | uint32_t quad_space; 44 | int has_normal; 45 | uint32_t color; 46 | int8_t normal[3]; 47 | enum tesselator_vertex_type vertex_type; 48 | }; 49 | 50 | enum tesselator_cube_face { 51 | CUBE_FACE_X_N, 52 | CUBE_FACE_X_P, 53 | CUBE_FACE_Y_N, 54 | CUBE_FACE_Y_P, 55 | CUBE_FACE_Z_N, 56 | CUBE_FACE_Z_P, 57 | }; 58 | 59 | void tesselator_create(struct tesselator* t, enum tesselator_vertex_type type, int has_normal); 60 | void tesselator_clear(struct tesselator* t); 61 | void tesselator_free(struct tesselator* t); 62 | void tesselator_draw(struct tesselator* t, int with_color); 63 | void tesselator_glx(struct tesselator* t, struct glx_displaylist* x); 64 | void tesselator_set_color(struct tesselator* t, uint32_t color); 65 | void tesselator_set_normal(struct tesselator* t, int8_t x, int8_t y, int8_t z); 66 | void tesselator_addi(struct tesselator* t, int16_t* coords, uint32_t* colors, int8_t* normals); 67 | void tesselator_addf(struct tesselator* t, float* coords, uint32_t* colors, int8_t* normals); 68 | void tesselator_addi_simple(struct tesselator* t, int16_t* coords); 69 | void tesselator_addf_simple(struct tesselator* t, float* coords); 70 | void tesselator_addi_cube_face(struct tesselator* t, enum tesselator_cube_face face, int16_t x, int16_t y, int16_t z); 71 | void tesselator_addi_cube_face_adv(struct tesselator* t, enum tesselator_cube_face face, int16_t x, int16_t y, 72 | int16_t z, int16_t sx, int16_t sy, int16_t sz); 73 | void tesselator_addf_cube_face(struct tesselator* t, enum tesselator_cube_face face, float x, float y, float z, 74 | float sz); 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef CONFIG_H 21 | #define CONFIG_H 22 | 23 | #include 24 | 25 | #include "list.h" 26 | 27 | struct config_file_entry { 28 | char section[32]; 29 | char name[32]; 30 | char value[32]; 31 | }; 32 | 33 | extern struct RENDER_OPTIONS { 34 | char name[16]; 35 | char last_address[128]; 36 | int opengl14; 37 | int color_correction; 38 | int shadow_entities; 39 | int ambient_occlusion; 40 | float render_distance; 41 | int window_width; 42 | int window_height; 43 | int multisamples; 44 | int player_arms; 45 | int fullscreen; 46 | int bg_tile; 47 | float bg_tile_speed; 48 | int ui_accent_r; 49 | int ui_accent_g; 50 | int ui_accent_b; 51 | int lighten_colors; 52 | int show_names_in_spec; 53 | int hud_shadows; 54 | int greedy_meshing; 55 | int vsync; 56 | float mouse_sensitivity; 57 | int show_news; 58 | int show_fps; 59 | int volume; 60 | int voxlap_models; 61 | int force_displaylist; 62 | int invert_y; 63 | int smooth_fog; 64 | float camera_fov; 65 | int hold_down_sights; 66 | float chat_shadow; 67 | int chat_flip_on_open; 68 | int chat_spacing; 69 | float spectator_speed; 70 | int iron_sight; 71 | int gmi; 72 | int disable_raw_input; 73 | int ui_spacing; 74 | int ui_padding; 75 | } settings, settings_tmp; 76 | 77 | extern struct list config_keys; 78 | 79 | struct config_key_pair { 80 | int internal; 81 | int def; 82 | int original; 83 | int toggle; 84 | char name[24]; 85 | char display[24]; 86 | char category[24]; 87 | }; 88 | 89 | enum { 90 | CONFIG_TYPE_STRING, 91 | CONFIG_TYPE_INT, 92 | CONFIG_TYPE_FLOAT, 93 | }; 94 | 95 | struct config_setting { 96 | void* value; 97 | int type; 98 | int min; 99 | int max; 100 | char name[32]; 101 | char help[64]; 102 | int defaults[8]; 103 | int defaults_length; 104 | void (*label_callback)(char* buffer, size_t length, int value, size_t index); 105 | }; 106 | 107 | extern struct list config_settings; 108 | 109 | void config_register_key(int internal, int def, const char* name, int toggle, const char* display, 110 | const char* category); 111 | int config_key_translate(int key, int dir, int* results); 112 | struct config_key_pair* config_key(int key); 113 | void config_key_reset_togglestates(); 114 | void config_reload(void); 115 | void config_save(void); 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | #include "list.h" 7 | 8 | int list_created(struct list* l) { 9 | assert(l != NULL); 10 | 11 | return l->element_size > 0; 12 | } 13 | 14 | void list_create(struct list* l, size_t element_size) { 15 | assert(l != NULL && element_size > 0); 16 | 17 | l->data = NULL; 18 | l->elements = 0; 19 | l->element_size = element_size; 20 | l->mem_size = 0; 21 | } 22 | 23 | void list_free(struct list* l) { 24 | assert(l != NULL); 25 | 26 | if(l->data) { 27 | free(l->data); 28 | l->data = NULL; 29 | } 30 | } 31 | 32 | void* list_find(struct list* l, const void* ref, enum list_traverse_direction dir, int (*cmp)(const void* obj, const void* ref)) { 33 | assert(l != NULL && cmp != NULL); 34 | 35 | switch(dir) { 36 | case LIST_TRAVERSE_FORWARD: 37 | for(size_t k = 0; k < l->elements; k++) { 38 | void* obj = l->data + l->element_size * k; 39 | 40 | if(cmp(obj, ref)) 41 | return obj; 42 | } 43 | break; 44 | case LIST_TRAVERSE_BACKWARD: 45 | if(!l->elements) 46 | break; 47 | 48 | size_t k = l->elements - 1; 49 | 50 | do { 51 | void* obj = l->data + l->element_size * k; 52 | 53 | if(cmp(obj, ref)) 54 | return obj; 55 | } while((k--) > 0); 56 | 57 | break; 58 | } 59 | 60 | return NULL; 61 | } 62 | 63 | void list_sort(struct list* l, int (*cmp)(const void* a, const void* b)) { 64 | assert(l != NULL && cmp != NULL); 65 | 66 | qsort(l->data, l->elements, l->element_size, cmp); 67 | } 68 | 69 | void* list_get(struct list* l, size_t i) { 70 | assert(l != NULL && i < l->elements); 71 | 72 | return l->data + i * l->element_size; 73 | } 74 | 75 | void* list_add(struct list* l, void* e) { 76 | assert(l != NULL); 77 | 78 | if((l->elements + 1) * l->element_size > l->mem_size) { 79 | l->mem_size += l->element_size * 64; 80 | l->data = realloc(l->data, l->mem_size); 81 | CHECK_ALLOCATION_ERROR(l->data) 82 | } 83 | 84 | if(e) 85 | memcpy(l->data + l->elements * l->element_size, e, l->element_size); 86 | else 87 | memset(l->data + l->elements * l->element_size, 0, l->element_size); 88 | 89 | return l->data + (l->elements++) * l->element_size; 90 | } 91 | 92 | void list_remove(struct list* l, size_t i) { 93 | assert(l != NULL && i < l->elements); 94 | 95 | if(i < l->elements - 1) 96 | memmove(list_get(l, i), list_get(l, i + 1), (l->elements - (i + 1)) * l->element_size); 97 | 98 | l->elements--; 99 | 100 | if(l->mem_size - 64 * l->element_size > 0 101 | && (l->elements + 1) * l->element_size < l->mem_size - 96 * l->element_size) { 102 | l->mem_size -= l->element_size * 64; 103 | l->data = realloc(l->data, l->mem_size); 104 | CHECK_ALLOCATION_ERROR(l->data) 105 | } 106 | } 107 | 108 | void list_clear(struct list* l) { 109 | assert(l != NULL); 110 | 111 | void* new = realloc(l->data, l->element_size * 64); 112 | 113 | if(new) { 114 | l->data = new; 115 | l->mem_size = l->element_size * 64; 116 | } 117 | 118 | l->elements = 0; 119 | } 120 | 121 | int list_size(struct list* l) { 122 | assert(l != NULL); 123 | 124 | return l->elements; 125 | } 126 | -------------------------------------------------------------------------------- /src/hashtable.h: -------------------------------------------------------------------------------- 1 | #ifndef HASHTABLE_H 2 | #define HASHTABLE_H 3 | 4 | #include 5 | #include 6 | 7 | /****************** DEFINTIIONS ******************/ 8 | 9 | #define HT_MINIMUM_CAPACITY 8 10 | #define HT_LOAD_FACTOR 5 11 | #define HT_MINIMUM_THRESHOLD (HT_MINIMUM_CAPACITY) * (HT_LOAD_FACTOR) 12 | 13 | #define HT_GROWTH_FACTOR 2 14 | #define HT_SHRINK_THRESHOLD (1 / 4) 15 | 16 | #define HT_ERROR -1 17 | #define HT_SUCCESS 0 18 | 19 | #define HT_UPDATED 1 20 | #define HT_INSERTED 0 21 | 22 | #define HT_NOT_FOUND 0 23 | #define HT_FOUND 01 24 | 25 | #define HT_INITIALIZER {0, 0, 0, 0, 0, NULL, NULL, NULL}; 26 | 27 | typedef int (*comparison_t)(void*, void*, size_t); 28 | typedef size_t (*hash_t)(void*, size_t); 29 | 30 | /****************** STRUCTURES ******************/ 31 | 32 | typedef struct HTNode { 33 | struct HTNode* next; 34 | void* key; 35 | void* value; 36 | 37 | } HTNode; 38 | 39 | typedef struct HashTable { 40 | size_t size; 41 | size_t threshold; 42 | size_t capacity; 43 | 44 | size_t key_size; 45 | size_t value_size; 46 | 47 | comparison_t compare; 48 | hash_t hash; 49 | 50 | HTNode** nodes; 51 | 52 | } HashTable; 53 | 54 | /****************** INTERFACE ******************/ 55 | 56 | /* Setup */ 57 | int ht_setup(HashTable* table, 58 | size_t key_size, 59 | size_t value_size, 60 | size_t capacity); 61 | 62 | int ht_copy(HashTable* first, HashTable* second); 63 | int ht_move(HashTable* first, HashTable* second); 64 | int ht_swap(HashTable* first, HashTable* second); 65 | 66 | /* Destructor */ 67 | int ht_destroy(HashTable* table); 68 | 69 | int ht_insert(HashTable* table, void* key, void* value); 70 | 71 | int ht_contains(HashTable* table, void* key); 72 | void* ht_lookup(HashTable* table, void* key); 73 | const void* ht_const_lookup(const HashTable* table, void* key); 74 | 75 | #define HT_LOOKUP_AS(type, table_pointer, key_pointer) \ 76 | (*(type*)ht_lookup((table_pointer), (key_pointer))) 77 | 78 | int ht_erase(HashTable* table, void* key); 79 | int ht_clear(HashTable* table); 80 | 81 | int ht_is_empty(HashTable* table); 82 | bool ht_is_initialized(HashTable* table); 83 | 84 | int ht_reserve(HashTable* table, size_t minimum_capacity); 85 | 86 | /****************** PRIVATE ******************/ 87 | 88 | void _ht_int_swap(size_t* first, size_t* second); 89 | void _ht_pointer_swap(void** first, void** second); 90 | 91 | size_t _ht_default_hash(void* key, size_t key_size); 92 | int _ht_default_compare(void* first_key, void* second_key, size_t key_size); 93 | 94 | size_t _ht_hash(const HashTable* table, void* key); 95 | bool _ht_equal(const HashTable* table, void* first_key, void* second_key); 96 | 97 | bool _ht_should_grow(HashTable* table); 98 | bool _ht_should_shrink(HashTable* table); 99 | 100 | HTNode* _ht_create_node(HashTable* table, void* key, void* value, HTNode* next); 101 | int _ht_push_front(HashTable* table, size_t index, void* key, void* value); 102 | void _ht_destroy_node(HTNode* node); 103 | 104 | int _ht_adjust_capacity(HashTable* table); 105 | int _ht_allocate(HashTable* table, size_t capacity); 106 | int _ht_resize(HashTable* table, size_t new_capacity); 107 | void _ht_rehash(HashTable* table, HTNode** old, size_t old_capacity); 108 | 109 | #endif /* HASHTABLE_H */ 110 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "utils.h" 23 | 24 | static int base64_map(char c) { 25 | if(c >= '0' && c <= '9') 26 | return c + 4; 27 | if(c >= 'A' && c <= 'Z') 28 | return c - 'A'; 29 | if(c >= 'a' && c <= 'z') 30 | return c - 'a' + 26; 31 | if(c == '+') 32 | return 62; 33 | if(c == '/') 34 | return 63; 35 | return 0; 36 | } 37 | 38 | // works in place 39 | int base64_decode(char* data, int len) { 40 | assert(data && len > 0); 41 | 42 | int buffer = 0; 43 | int buffer_len = 0; 44 | int data_index = 0; 45 | int out_index = 0; 46 | for(int k = 0; k < len; k++) { 47 | if(buffer_len + 6 < sizeof(int) * 8 && data[data_index] != '=') { 48 | buffer <<= 6; 49 | buffer |= base64_map(data[data_index++]); 50 | buffer_len += 6; 51 | } 52 | for(int b = 0; b < buffer_len / 8; b++) { 53 | data[out_index++] = (buffer >> (buffer_len - 8)); 54 | buffer_len -= 8; 55 | } 56 | } 57 | return out_index; 58 | } 59 | 60 | int int_cmp(void* first_key, void* second_key, size_t key_size) { 61 | assert(first_key && second_key); 62 | 63 | return (*(uint32_t*)first_key) != (*(uint32_t*)second_key); 64 | } 65 | 66 | size_t int_hash(void* raw_key, size_t key_size) { 67 | assert(raw_key); 68 | 69 | uint32_t x = *(uint32_t*)raw_key; 70 | x = ((x >> 16) ^ x) * 0x45d9f3b; 71 | x = ((x >> 16) ^ x) * 0x45d9f3b; 72 | x = (x >> 16) ^ x; 73 | return x; 74 | } 75 | 76 | void ht_iterate_remove(HashTable* ht, void* user, bool (*callback)(void* key, void* value, void* user)) { 77 | assert(ht && callback); 78 | 79 | bool removed = false; 80 | 81 | for(size_t chain = 0; chain < ht->capacity; chain++) { 82 | HTNode* node = ht->nodes[chain]; 83 | HTNode* prev = NULL; 84 | 85 | while(node) { 86 | if(callback(node->key, node->value, user)) { 87 | if(prev) { 88 | prev->next = node->next; 89 | } else { 90 | ht->nodes[chain] = node->next; 91 | } 92 | 93 | HTNode* del = node; 94 | node = node->next; 95 | 96 | _ht_destroy_node(del); 97 | 98 | ht->size--; 99 | removed = true; 100 | } else { 101 | prev = node; 102 | node = node->next; 103 | } 104 | } 105 | } 106 | 107 | if(removed && _ht_should_shrink(ht)) 108 | _ht_adjust_capacity(ht); 109 | } 110 | 111 | bool ht_iterate(HashTable* ht, void* user, bool (*callback)(void* key, void* value, void* user)) { 112 | assert(ht && callback); 113 | 114 | for(size_t chain = 0; chain < ht->capacity; chain++) { 115 | HTNode* node = ht->nodes[chain]; 116 | 117 | while(node) { 118 | if(!callback(node->key, node->value, user)) 119 | return true; 120 | node = node->next; 121 | } 122 | } 123 | 124 | return false; 125 | } 126 | -------------------------------------------------------------------------------- /src/sound.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef SOUND_H 21 | #define SOUND_H 22 | 23 | #ifdef USE_SOUND 24 | #if __APPLE__ 25 | #include 26 | #include 27 | #else 28 | #include 29 | #include 30 | #endif 31 | #endif 32 | 33 | #include "player.h" 34 | 35 | #define SOUND_SCALE 0.6F 36 | 37 | enum sound_space { 38 | SOUND_WORLD, 39 | SOUND_LOCAL, 40 | }; 41 | 42 | extern int sound_enabled; 43 | 44 | struct Sound_wav { 45 | int openal_buffer; 46 | float min, max; 47 | }; 48 | 49 | extern struct Sound_wav sound_footstep1; 50 | extern struct Sound_wav sound_footstep2; 51 | extern struct Sound_wav sound_footstep3; 52 | extern struct Sound_wav sound_footstep4; 53 | 54 | extern struct Sound_wav sound_wade1; 55 | extern struct Sound_wav sound_wade2; 56 | extern struct Sound_wav sound_wade3; 57 | extern struct Sound_wav sound_wade4; 58 | 59 | extern struct Sound_wav sound_jump; 60 | extern struct Sound_wav sound_jump_water; 61 | 62 | extern struct Sound_wav sound_land; 63 | extern struct Sound_wav sound_land_water; 64 | 65 | extern struct Sound_wav sound_hurt_fall; 66 | 67 | extern struct Sound_wav sound_explode; 68 | extern struct Sound_wav sound_explode_water; 69 | extern struct Sound_wav sound_grenade_bounce; 70 | extern struct Sound_wav sound_grenade_pin; 71 | 72 | extern struct Sound_wav sound_pickup; 73 | extern struct Sound_wav sound_horn; 74 | 75 | extern struct Sound_wav sound_rifle_shoot; 76 | extern struct Sound_wav sound_rifle_reload; 77 | extern struct Sound_wav sound_smg_shoot; 78 | extern struct Sound_wav sound_smg_reload; 79 | extern struct Sound_wav sound_shotgun_shoot; 80 | extern struct Sound_wav sound_shotgun_reload; 81 | extern struct Sound_wav sound_shotgun_cock; 82 | 83 | extern struct Sound_wav sound_hitground; 84 | extern struct Sound_wav sound_hitplayer; 85 | extern struct Sound_wav sound_build; 86 | 87 | extern struct Sound_wav sound_spade_woosh; 88 | extern struct Sound_wav sound_spade_whack; 89 | 90 | extern struct Sound_wav sound_death; 91 | extern struct Sound_wav sound_beep1; 92 | extern struct Sound_wav sound_beep2; 93 | extern struct Sound_wav sound_chat; 94 | extern struct Sound_wav sound_switch; 95 | extern struct Sound_wav sound_empty; 96 | extern struct Sound_wav sound_intro; 97 | 98 | extern struct Sound_wav sound_debris; 99 | extern struct Sound_wav sound_bounce; 100 | extern struct Sound_wav sound_impact; 101 | 102 | void sound_volume(float vol); 103 | void sound_create_sticky(struct Sound_wav* w, struct Player* player, int player_id); 104 | void sound_create(enum sound_space option, struct Sound_wav* w, float x, float y, float z); 105 | void sound_update(void); 106 | void sound_load(struct Sound_wav* wav, char* name, float min, float max); 107 | void sound_init(void); 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /src/window.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef WINDOW_H 21 | #define WINDOW_H 22 | 23 | #include "common.h" 24 | #include 25 | 26 | struct window_instance { 27 | void* impl; 28 | }; 29 | 30 | enum { 31 | WINDOW_PRESS, 32 | WINDOW_RELEASE, 33 | WINDOW_REPEAT, 34 | }; 35 | 36 | enum { 37 | TOUCH_DOWN, 38 | TOUCH_MOVE, 39 | TOUCH_UP, 40 | }; 41 | 42 | enum window_keys { 43 | WINDOW_KEY_UNKNOWN, 44 | WINDOW_KEY_UP, 45 | WINDOW_KEY_DOWN, 46 | WINDOW_KEY_LEFT, 47 | WINDOW_KEY_RIGHT, 48 | WINDOW_KEY_SNEAK, 49 | WINDOW_KEY_CROUCH, 50 | WINDOW_KEY_SPRINT, 51 | WINDOW_KEY_SPACE, 52 | WINDOW_KEY_CURSOR_UP, 53 | WINDOW_KEY_CURSOR_DOWN, 54 | WINDOW_KEY_CURSOR_LEFT, 55 | WINDOW_KEY_CURSOR_RIGHT, 56 | WINDOW_KEY_TAB, 57 | WINDOW_KEY_ESCAPE, 58 | WINDOW_KEY_YES, 59 | WINDOW_KEY_NO, 60 | WINDOW_KEY_RELOAD, 61 | WINDOW_KEY_TOOL1, 62 | WINDOW_KEY_TOOL2, 63 | WINDOW_KEY_TOOL3, 64 | WINDOW_KEY_TOOL4, 65 | WINDOW_KEY_PICKCOLOR, 66 | WINDOW_KEY_CHAT, 67 | WINDOW_KEY_F1, 68 | WINDOW_KEY_F2, 69 | WINDOW_KEY_F3, 70 | WINDOW_KEY_F4, 71 | WINDOW_KEY_CHANGETEAM, 72 | WINDOW_KEY_CHANGEWEAPON, 73 | WINDOW_KEY_ENTER, 74 | WINDOW_KEY_BACKSPACE, 75 | WINDOW_KEY_MAP, 76 | WINDOW_KEY_VOLUME_UP, 77 | WINDOW_KEY_VOLUME_DOWN, 78 | WINDOW_KEY_V, 79 | WINDOW_KEY_FULLSCREEN, 80 | WINDOW_KEY_SCREENSHOT, 81 | WINDOW_KEY_COMMAND, 82 | WINDOW_KEY_HIDEHUD, 83 | WINDOW_KEY_LASTTOOL, 84 | WINDOW_KEY_NETWORKSTATS, 85 | WINDOW_KEY_SHIFT, 86 | WINDOW_KEY_SAVE_MAP, 87 | WINDOW_KEY_SELECT1, 88 | WINDOW_KEY_SELECT2, 89 | WINDOW_KEY_SELECT3, 90 | WINDOW_KEY_HISTORY_PREVIOUS, 91 | WINDOW_KEY_HISTORY_NEXT, 92 | WINDOW_KEY_YCLAMP, 93 | WINDOW_KEY_SWITCH_CAMERA, 94 | WINDOW_KEY_NEXT_PLAYER 95 | }; 96 | 97 | enum { 98 | WINDOW_CURSOR_DISABLED, 99 | WINDOW_CURSOR_ENABLED, 100 | }; 101 | 102 | enum window_buttons { 103 | WINDOW_MOUSE_LMB, 104 | WINDOW_MOUSE_MMB, 105 | WINDOW_MOUSE_RMB, 106 | }; 107 | 108 | struct window_finger { 109 | #ifdef USE_SDL 110 | SDL_FingerID finger; 111 | #else 112 | int finger; 113 | #endif 114 | float down_time; 115 | int full; 116 | struct { 117 | float x, y; 118 | } start; 119 | }; 120 | 121 | extern int window_pressed_keys[64]; 122 | 123 | #define WINDOW_NOMOUSELOC -1 124 | 125 | void window_textinput(int allow); 126 | float window_time(void); 127 | void window_keyname(int keycode, char* output, size_t length); 128 | const char* window_clipboard(void); 129 | int window_key_down(int key); 130 | void window_mousemode(int mode); 131 | void window_mouseloc(double* x, double* y); 132 | void window_setmouseloc(double x, double y); 133 | void window_swapping(int value); 134 | void window_init(void); 135 | void window_fromsettings(void); 136 | void window_deinit(void); 137 | void window_update(void); 138 | int window_closed(void); 139 | int window_cpucores(); 140 | void window_title(char* suffix); 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /src/texture.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef TEXTURE_H 21 | #define TEXTURE_H 22 | 23 | struct texture { 24 | int width, height; 25 | int texture_id; 26 | unsigned char* pixels; 27 | }; 28 | 29 | extern struct texture texture_splash; 30 | extern struct texture texture_splash_icon; 31 | extern struct texture texture_minimap; 32 | extern struct texture texture_gradient; 33 | extern struct texture texture_dummy; 34 | 35 | extern struct texture texture_health; 36 | extern struct texture texture_block; 37 | extern struct texture texture_grenade; 38 | extern struct texture texture_ammo_semi; 39 | extern struct texture texture_ammo_smg; 40 | extern struct texture texture_ammo_shotgun; 41 | 42 | extern struct texture texture_color_selection; 43 | 44 | extern struct texture texture_zoom_semi; 45 | extern struct texture texture_zoom_smg; 46 | extern struct texture texture_zoom_shotgun; 47 | 48 | extern struct texture texture_white; 49 | extern struct texture texture_loader; 50 | extern struct texture texture_target; 51 | extern struct texture texture_indicator; 52 | 53 | extern struct texture texture_player; 54 | extern struct texture texture_medical; 55 | extern struct texture texture_intel; 56 | extern struct texture texture_command; 57 | extern struct texture texture_tracer; 58 | 59 | extern struct texture texture_ui_exit; 60 | extern struct texture texture_ui_wait; 61 | extern struct texture texture_ui_join; 62 | extern struct texture texture_ui_reload; 63 | extern struct texture texture_ui_bg; 64 | extern struct texture texture_ui_input; 65 | extern struct texture texture_ui_box_empty; 66 | extern struct texture texture_ui_box_check; 67 | extern struct texture texture_ui_expanded; 68 | extern struct texture texture_ui_collapsed; 69 | extern struct texture texture_ui_flags; 70 | extern struct texture texture_ui_alert; 71 | extern struct texture texture_ui_joystick; 72 | extern struct texture texture_ui_knob; 73 | 74 | #define TEXTURE_FILTER_NEAREST 0 75 | #define TEXTURE_FILTER_LINEAR 1 76 | 77 | int texture_flag_index(const char* country); 78 | void texture_flag_offset(int index, float* u, float* v); 79 | void texture_filter(struct texture* t, int filter); 80 | void texture_init(void); 81 | int texture_create(struct texture* t, char* filename); 82 | int texture_create_buffer(struct texture* t, int width, int height, unsigned char* buff, int new); 83 | void texture_delete(struct texture* t); 84 | void texture_draw(struct texture* t, float x, float y, float w, float h); 85 | void texture_draw_shadow(struct texture* t, float x, float y, float w, float h); 86 | void texture_draw_sector(struct texture* t, float x, float y, float w, float h, float u, float v, float us, float vs); 87 | void texture_draw_empty(float x, float y, float w, float h); 88 | void texture_draw_empty_rotated(float x, float y, float w, float h, float angle); 89 | void texture_draw_rotated(struct texture* t, float x, float y, float w, float h, float angle); 90 | void texture_resize_pow2(struct texture* t, int min_size); 91 | unsigned int texture_block_color(int x, int y); 92 | void texture_gradient_fog(unsigned int* gradient); 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/matrix.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "common.h" 25 | #include "matrix.h" 26 | 27 | mat4 matrix_view; 28 | mat4 matrix_model; 29 | mat4 matrix_projection; 30 | 31 | #define MATRIX_STACK_DEPTH 8 32 | 33 | mat4 matrix_stack[MATRIX_STACK_DEPTH]; 34 | int matrix_stack_index = 0; 35 | 36 | void matrix_multiply(mat4 m, mat4 n) { 37 | glmc_mat4_mul(n, m, m); 38 | } 39 | 40 | void matrix_load(mat4 m, mat4 n) { 41 | glmc_mat4_copy(n, m); 42 | } 43 | 44 | void matrix_rotate(mat4 m, float angle, float x, float y, float z) { 45 | glmc_rotate(m, angle / 180.0F * GLM_PI, (vec3) {x, y, z}); 46 | } 47 | 48 | void matrix_translate(mat4 m, float x, float y, float z) { 49 | glmc_translate(m, (vec3) {x, y, z}); 50 | } 51 | 52 | void matrix_scale3(mat4 m, float s) { 53 | glmc_scale_uni(m, s); 54 | } 55 | 56 | void matrix_scale(mat4 m, float sx, float sy, float sz) { 57 | glmc_scale(m, (vec3) {sx, sy, sz}); 58 | } 59 | 60 | void matrix_identity(mat4 m) { 61 | glmc_mat4_identity(m); 62 | } 63 | 64 | void matrix_push(mat4 m) { 65 | if(matrix_stack_index >= MATRIX_STACK_DEPTH) { 66 | log_fatal("Matrix stack overflow!"); 67 | return; 68 | } 69 | 70 | glmc_mat4_copy(m, matrix_stack[matrix_stack_index++]); 71 | } 72 | 73 | void matrix_pop(mat4 m) { 74 | if(matrix_stack_index < 1) { 75 | log_fatal("Matrix stack underflow!"); 76 | return; 77 | } 78 | 79 | glmc_mat4_copy(matrix_stack[--matrix_stack_index], m); 80 | } 81 | 82 | void matrix_vector(mat4 m, vec4 v) { 83 | glmc_mat4_mulv(m, v, v); 84 | 85 | v[0] /= v[3]; 86 | v[1] /= v[3]; 87 | v[2] /= v[3]; 88 | } 89 | 90 | void matrix_pointAt(mat4 m, float dx, float dy, float dz) { 91 | float l = sqrt(dx * dx + dy * dy + dz * dz); 92 | if(l) { 93 | dx /= l; 94 | dy /= l; 95 | dz /= l; 96 | } 97 | float rx = -atan2(dz, dx) * GLM_1_PI * 180.0F; 98 | matrix_rotate(m, rx, 0.0F, 1.0F, 0.0F); 99 | if(dy) { 100 | float ry = asin(dy) * GLM_1_PI * 180.0F; 101 | matrix_rotate(m, ry, 0.0F, 0.0F, 1.0F); 102 | } 103 | } 104 | 105 | void matrix_ortho(mat4 m, float left, float right, float bottom, float top, float nearv, float farv) { 106 | glmc_ortho(left, right, bottom, top, nearv, farv, m); 107 | } 108 | 109 | void matrix_perspective(mat4 m, float fovy, float aspect, float zNear, float zFar) { 110 | glmc_perspective(fovy / 180.0F * GLM_PI, aspect, zNear, zFar, m); 111 | } 112 | 113 | void matrix_lookAt(mat4 m, double eyex, double eyey, double eyez, double centerx, double centery, double centerz, 114 | double upx, double upy, double upz) { 115 | glmc_lookat((vec3) {eyex, eyey, eyez}, (vec3) {centerx, centery, centerz}, (vec3) {upx, upy, upz}, m); 116 | // matrix_translate(-eyex, -eyey, -eyez); 117 | } 118 | 119 | void matrix_upload() { 120 | glMatrixMode(GL_MODELVIEW); 121 | glLoadMatrixf((float*)matrix_view); 122 | glMultMatrixf((float*)matrix_model); 123 | } 124 | 125 | void matrix_upload_p() { 126 | glMatrixMode(GL_PROJECTION); 127 | glLoadMatrixf((float*)matrix_projection); 128 | } 129 | -------------------------------------------------------------------------------- /src/aabb.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "common.h" 25 | #include "map.h" 26 | #include "aabb.h" 27 | #include "tesselator.h" 28 | #include "matrix.h" 29 | 30 | void aabb_render(AABB* a) { } 31 | 32 | // see: https://tavianator.com/2011/ray_box.html 33 | bool aabb_intersection_ray(AABB* a, Ray* r, float* distance) { 34 | double inv_x = 1.0 / r->direction.x; 35 | double tx1 = (a->min_x - r->origin.x) * inv_x; 36 | double tx2 = (a->max_x - r->origin.x) * inv_x; 37 | 38 | double tmin = fmin(tx1, tx2); 39 | double tmax = fmax(tx1, tx2); 40 | 41 | double inv_y = 1.0 / r->direction.y; 42 | double ty1 = (a->min_y - r->origin.y) * inv_y; 43 | double ty2 = (a->max_y - r->origin.y) * inv_y; 44 | 45 | tmin = fmax(tmin, fmin(fmin(ty1, ty2), tmax)); 46 | tmax = fmin(tmax, fmax(fmax(ty1, ty2), tmin)); 47 | 48 | double inv_z = 1.0 / r->direction.z; 49 | double tz1 = (a->min_z - r->origin.z) * inv_z; 50 | double tz2 = (a->max_z - r->origin.z) * inv_z; 51 | 52 | tmin = fmax(tmin, fmin(fmin(tz1, tz2), tmax)); 53 | tmax = fmin(tmax, fmax(fmax(tz1, tz2), tmin)); 54 | 55 | if(distance) 56 | *distance = fmax(tmin, 0.0) * len3D(r->direction.x, r->direction.y, r->direction.z); 57 | 58 | return tmax > fmax(tmin, 0.0); 59 | } 60 | 61 | void aabb_set_center(AABB* a, float x, float y, float z) { 62 | float size_x = a->max_x - a->min_x; 63 | float size_y = a->max_y - a->min_y; 64 | float size_z = a->max_z - a->min_z; 65 | 66 | a->min_x = x - size_x / 2; 67 | a->min_y = y - size_y / 2; 68 | a->min_z = z - size_z / 2; 69 | a->max_x = x + size_x / 2; 70 | a->max_y = y + size_y / 2; 71 | a->max_z = z + size_z / 2; 72 | } 73 | 74 | void aabb_set_size(AABB* a, float x, float y, float z) { 75 | a->max_x = a->min_x + x; 76 | a->max_y = a->min_y + y; 77 | a->max_z = a->min_z + z; 78 | } 79 | 80 | bool aabb_intersection(AABB* a, AABB* b) { 81 | return (a->min_x <= b->max_x && b->min_x <= a->max_x) && (a->min_y <= b->max_y && b->min_y <= a->max_y) 82 | && (a->min_z <= b->max_z && b->min_z <= a->max_z); 83 | } 84 | 85 | bool aabb_intersection_terrain(AABB* a, int miny) { 86 | AABB terrain_cube; 87 | 88 | int min_x = min(max(floor(a->min_x) - 1, 0), map_size_x); 89 | int min_y = min(max(floor(a->min_y) - 1, miny), map_size_y); 90 | int min_z = min(max(floor(a->min_z) - 1, 0), map_size_z); 91 | 92 | int max_x = min(max(ceil(a->max_x) + 1, 0), map_size_x); 93 | int max_y = min(max(ceil(a->max_y) + 1, 0), map_size_y); 94 | int max_z = min(max(ceil(a->max_z) + 1, 0), map_size_z); 95 | 96 | for(int x = min_x; x < max_x; x++) { 97 | for(int z = min_z; z < max_z; z++) { 98 | for(int y = min_y; y < max_y; y++) { 99 | if(!map_isair(x, y, z)) { 100 | terrain_cube.min_x = x; 101 | terrain_cube.min_y = y; 102 | terrain_cube.min_z = z; 103 | terrain_cube.max_x = x + 1; 104 | terrain_cube.max_y = y + 1; 105 | terrain_cube.max_z = z + 1; 106 | 107 | if(aabb_intersection(a, &terrain_cube)) 108 | return true; 109 | } 110 | } 111 | } 112 | } 113 | 114 | return false; 115 | } 116 | -------------------------------------------------------------------------------- /src/rpc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #ifdef USE_RPC 23 | #include 24 | #endif 25 | 26 | #include "common.h" 27 | #include "log.h" 28 | #include "player.h" 29 | #include "rpc.h" 30 | 31 | struct rpc { 32 | int needs_update; 33 | int players; 34 | int slots; 35 | char server_url[64]; 36 | char server_name[64]; 37 | } rpc_state; 38 | 39 | #ifdef USE_RPC 40 | static void rpc_joingame(const char* joinSecret) { 41 | log_info("discord join %s!", joinSecret); 42 | } 43 | 44 | static void rpc_joinrequest(const DiscordUser* request) { 45 | Discord_Respond(request->userId, DISCORD_REPLY_YES); 46 | } 47 | #endif 48 | 49 | void rpc_init() { 50 | #ifdef USE_RPC 51 | DiscordEventHandlers handlers; 52 | memset(&handlers, 0, sizeof(handlers)); 53 | handlers.joinGame = rpc_joingame; 54 | handlers.joinRequest = rpc_joinrequest; 55 | Discord_Initialize("DISCORD TOKEN HERE", &handlers, 1, NULL); 56 | #endif 57 | rpc_state.needs_update = 1; 58 | rpc_state.players = 0; 59 | rpc_state.slots = 0; 60 | *rpc_state.server_url = 0; 61 | *rpc_state.server_name = 0; 62 | } 63 | 64 | void rpc_deinit() { 65 | #ifdef USE_RPC 66 | Discord_Shutdown(); 67 | #endif 68 | } 69 | 70 | void rpc_setv(enum RPC_VALUE v, char* x) { 71 | switch(v) { 72 | case RPC_VALUE_SERVERNAME: 73 | if(strcmp(rpc_state.server_name, x) != 0) { 74 | strncpy(rpc_state.server_name, x, sizeof(rpc_state.server_name) - 1); 75 | rpc_state.needs_update = 1; 76 | } 77 | break; 78 | case RPC_VALUE_SERVERURL: 79 | if(strcmp(rpc_state.server_url, x) != 0) { 80 | strncpy(rpc_state.server_url, x, sizeof(rpc_state.server_url) - 1); 81 | rpc_state.needs_update = 1; 82 | } 83 | break; 84 | } 85 | } 86 | 87 | void rpc_seti(enum RPC_VALUE v, int x) { 88 | switch(v) { 89 | case RPC_VALUE_PLAYERS: 90 | if(rpc_state.players != x) { 91 | rpc_state.players = x; 92 | rpc_state.needs_update = 1; 93 | } 94 | break; 95 | case RPC_VALUE_SLOTS: 96 | if(rpc_state.slots != x) { 97 | rpc_state.slots = x; 98 | rpc_state.needs_update = 1; 99 | } 100 | break; 101 | } 102 | } 103 | 104 | void rpc_update() { 105 | #ifdef USE_RPC 106 | 107 | int online = 0; 108 | for(int k = 0; k < PLAYERS_MAX; k++) { 109 | if(players[k].connected) 110 | online++; 111 | } 112 | rpc_seti(RPC_VALUE_PLAYERS, online); 113 | 114 | if(rpc_state.needs_update) { 115 | DiscordRichPresence discordPresence; 116 | memset(&discordPresence, 0, sizeof(discordPresence)); 117 | discordPresence.largeImageKey = "pic03"; 118 | discordPresence.smallImageKey = "logo"; 119 | discordPresence.smallImageText = BETTERSPADES_VERSION; 120 | discordPresence.instance = 1; 121 | if(rpc_state.slots > 0) { 122 | discordPresence.state = "Playing"; 123 | discordPresence.partyId = "42"; 124 | discordPresence.partySize = max(rpc_state.players, 1); 125 | discordPresence.partyMax = rpc_state.slots; 126 | discordPresence.details = rpc_state.server_name; 127 | discordPresence.joinSecret = rpc_state.server_url; 128 | } else { 129 | discordPresence.state = "Waiting"; 130 | } 131 | Discord_UpdatePresence(&discordPresence); 132 | rpc_state.needs_update = 0; 133 | } 134 | 135 | Discord_UpdateConnection(); 136 | Discord_RunCallbacks(); 137 | #endif 138 | } 139 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef COMMON_H 21 | #define COMMON_H 22 | 23 | #ifndef OPENGL_ES 24 | #define GLEW_STATIC 25 | #include 26 | #else 27 | #ifdef USE_SDL 28 | #include 29 | #endif 30 | #define glColor3f(r, g, b) glColor4f(r, g, b, 1.0F) 31 | #define glColor3ub(r, g, b) glColor4ub(r, g, b, 255) 32 | #define glDepthRange(a, b) glDepthRangef(a, b) 33 | #define glClearDepth(a) glClearDepthf(a) 34 | #endif 35 | 36 | #ifdef USE_GLFW 37 | #include 38 | #endif 39 | 40 | #ifdef USE_SDL 41 | #define SDL_MAIN_HANDLED 42 | #include 43 | #endif 44 | 45 | #ifdef USE_RPC 46 | #include 47 | #endif 48 | 49 | #ifdef _WIN32 50 | #define OS_WINDOWS 51 | #endif 52 | 53 | #ifdef __linux__ 54 | #define OS_LINUX 55 | #include 56 | #endif 57 | 58 | #ifdef __APPLE__ 59 | #define OS_APPLE 60 | #endif 61 | 62 | #ifdef __HAIKU__ 63 | #define OS_HAIKU 64 | #endif 65 | 66 | #ifndef min 67 | #define min(a, b) ((a) < (b) ? (a) : (b)) 68 | #endif 69 | #ifndef max 70 | #define max(a, b) ((a) > (b) ? (a) : (b)) 71 | #endif 72 | 73 | #define absf(a) (((a) > 0) ? (a) : -(a)) 74 | 75 | #define distance2D(x1, y1, x2, y2) (((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1))) 76 | #define distance3D(x1, y1, z1, x2, y2, z2) \ 77 | (((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1)) + ((z2) - (z1)) * ((z2) - (z1))) 78 | #define angle3D(x1, y1, z1, x2, y2, z2) acos((x1) * (x2) + (y1) * (y2) + (z1) * (z2)) // vectors should be normalized 79 | #define len2D(x, y) sqrt(pow(x, 2) + pow(y, 2)) 80 | #define len3D(x, y, z) sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2)) 81 | 82 | #define rgba(r, g, b, a) (((int)(a) << 24) | ((int)(b) << 16) | ((int)(g) << 8) | (int)(r)) 83 | #define rgb(r, g, b) (((b) << 16) | ((g) << 8) | (r)) 84 | #define rgb2bgr(col) rgb(blue(col), green(col), red(col)) 85 | #define red(col) ((col)&0xFF) 86 | #define green(col) (((col) >> 8) & 0xFF) 87 | #define blue(col) (((col) >> 16) & 0xFF) 88 | #define alpha(col) (((col) >> 24) & 0xFF) 89 | 90 | #define PI 3.1415F 91 | #define DOUBLEPI (PI * 2.0F) 92 | #define HALFPI (PI * 0.5F) 93 | #define EPSILON 0.005F 94 | 95 | #define MOUSE_SENSITIVITY 0.002F 96 | 97 | #define CHAT_NO_INPUT 0 98 | #define CHAT_ALL_INPUT 1 99 | #define CHAT_TEAM_INPUT 2 100 | 101 | extern int chat_input_mode; 102 | extern float last_cy; 103 | 104 | extern int fps; 105 | 106 | extern char chat[3][128][256]; 107 | extern unsigned int chat_color[3][128]; 108 | extern float chat_timer[3][128]; 109 | extern unsigned int chat_history_pos; 110 | extern char chat_popup[256]; 111 | extern float chat_popup_timer; 112 | extern float chat_popup_duration; 113 | extern int chat_popup_color; 114 | void chat_add(int channel, unsigned int color, const char* msg); 115 | void chat_clear(int channel); 116 | void chat_showpopup(const char* msg, float duration, int color); 117 | const char* reason_disconnect(int code); 118 | 119 | #define SCREEN_NONE 0 120 | #define SCREEN_TEAM_SELECT 1 121 | #define SCREEN_GUN_SELECT 2 122 | 123 | extern int ms_seed; 124 | int ms_rand(void); 125 | 126 | #include 127 | #include "log.h" 128 | 129 | #define CHECK_ALLOCATION_ERROR(ret) \ 130 | if(!ret) { \ 131 | log_fatal("Critical error: memory allocation failed (%s:%d)", __func__, __LINE__); \ 132 | exit(1); \ 133 | } 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /src/minheap.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "minheap.h" 27 | 28 | static void nodes_swap(struct minheap* h, int a, int b) { 29 | struct minheap_block tmp; 30 | tmp = h->nodes[a]; 31 | h->nodes[a] = h->nodes[b]; 32 | h->nodes[b] = tmp; 33 | } 34 | 35 | void minheap_create(struct minheap* h) { 36 | h->index = 0; 37 | h->length = 256; 38 | h->nodes = malloc(sizeof(struct minheap_block) * h->length); 39 | } 40 | 41 | void minheap_clear(struct minheap* h) { 42 | h->index = 0; 43 | h->length = 256; 44 | h->nodes = realloc(h->nodes, sizeof(struct minheap_block) * h->length); 45 | } 46 | 47 | void minheap_destroy(struct minheap* h) { 48 | free(h->nodes); 49 | } 50 | 51 | int minheap_isempty(struct minheap* h) { 52 | return h->index <= 0; 53 | } 54 | 55 | struct minheap_block minheap_extract(struct minheap* h) { 56 | struct minheap_block min = h->nodes[0]; 57 | 58 | h->nodes[0] = h->nodes[--h->index]; 59 | 60 | // now heapify at root node 61 | int k = 0; 62 | while(1) { 63 | int smallest = k; 64 | if(k * 2 + 1 < h->index 65 | && pos_keyy(h->nodes[k * 2 + 1].pos) 66 | < pos_keyy(h->nodes[smallest].pos)) // does left child exist and is less than parent? 67 | smallest = k * 2 + 1; 68 | if(k * 2 + 2 < h->index 69 | && pos_keyy(h->nodes[k * 2 + 2].pos) 70 | < pos_keyy(h->nodes[smallest].pos)) // does right child exist and is less than parent? 71 | smallest = k * 2 + 2; 72 | if(smallest == k) // parent is smallest, finished! 73 | break; 74 | nodes_swap(h, k, smallest); 75 | k = smallest; 76 | } 77 | 78 | return min; 79 | } 80 | 81 | static void minheap_increase(struct minheap* h, struct minheap_block* b, int value) { 82 | b->pos = pos_key(pos_keyx(b->pos), value, pos_keyy(b->pos)); 83 | 84 | int k = b - h->nodes; 85 | while(1) { 86 | int smallest = k; 87 | if(k * 2 + 1 < h->index 88 | && pos_keyy(h->nodes[k * 2 + 1].pos) 89 | < pos_keyy(h->nodes[smallest].pos)) // does left child exist and is less than parent? 90 | smallest = k * 2 + 1; 91 | if(k * 2 + 2 < h->index 92 | && pos_keyy(h->nodes[k * 2 + 2].pos) 93 | < pos_keyy(h->nodes[smallest].pos)) // does right child exist and is less than parent? 94 | smallest = k * 2 + 2; 95 | if(smallest == k) // parent is smallest, finished! 96 | break; 97 | nodes_swap(h, k, smallest); 98 | k = smallest; 99 | } 100 | } 101 | 102 | static void minheap_decrease(struct minheap* h, struct minheap_block* b, int value) { 103 | b->pos = pos_key(pos_keyx(b->pos), value, pos_keyy(b->pos)); 104 | 105 | int k = b - h->nodes; 106 | while(k > 0) { 107 | if(pos_keyy(h->nodes[k].pos) < pos_keyy(h->nodes[(k - 1) / 2].pos)) { // is child less than parent? 108 | nodes_swap(h, k, (k - 1) / 2); 109 | k = (k - 1) / 2; // continue at parent 110 | } else { 111 | break; 112 | } 113 | } 114 | } 115 | 116 | void minheap_set(struct minheap* h, struct minheap_block* b, int value) { 117 | if(value > pos_keyy(b->pos)) 118 | minheap_increase(h, b, value); 119 | else 120 | minheap_decrease(h, b, value); 121 | } 122 | 123 | struct minheap_block* minheap_put(struct minheap* h, struct minheap_block* b) { 124 | if(h->index >= h->length) { // grow buffer 125 | h->length *= 2; 126 | h->nodes = realloc(h->nodes, sizeof(struct minheap_block) * h->length); 127 | } 128 | 129 | h->nodes[h->index++] = *b; // place new node at end of heap 130 | 131 | int k = h->index - 1; 132 | while(k > 0) { 133 | if(pos_keyy(h->nodes[k].pos) < pos_keyy(h->nodes[(k - 1) / 2].pos)) { // is child less than parent? 134 | nodes_swap(h, k, (k - 1) / 2); 135 | k = (k - 1) / 2; // continue at parent 136 | } else { 137 | break; 138 | } 139 | } 140 | 141 | return h->nodes + k; 142 | } 143 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 rxi 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "log.h" 31 | 32 | #ifdef WIN32 33 | #include 34 | #endif 35 | 36 | pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 37 | 38 | static struct { 39 | FILE* fp; 40 | int level; 41 | int quiet; 42 | } L; 43 | 44 | static const char* level_names[] = { 45 | "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" 46 | }; 47 | 48 | #ifdef LOG_USE_COLOR 49 | #ifdef WIN32 50 | static const WORD level_colors[] = { 51 | 10, 11, 10, 6, 12, 12 52 | }; 53 | #else 54 | static const char* level_colors[] = { 55 | "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" 56 | }; 57 | #endif 58 | #endif 59 | 60 | static void lock(void) { 61 | pthread_mutex_lock(&m); 62 | } 63 | 64 | static void unlock(void) { 65 | pthread_mutex_unlock(&m); 66 | } 67 | 68 | void log_set_fp(FILE* fp) { 69 | L.fp = fp; 70 | } 71 | 72 | void log_set_level(int level) { 73 | L.level = level; 74 | } 75 | 76 | void log_set_quiet(int enable) { 77 | L.quiet = enable ? 1 : 0; 78 | } 79 | 80 | void log_log(int level, const char* file, int line, const char* fmt, ...) { 81 | if(level < L.level) 82 | return; 83 | 84 | /* Get current time */ 85 | time_t t = time(NULL); 86 | struct tm* lt = localtime(&t); 87 | 88 | /* Acquire lock */ 89 | lock(); 90 | 91 | /* Log to stderr */ 92 | if(!L.quiet) { 93 | va_list args; 94 | char buf[16]; 95 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", lt)] = '\0'; 96 | 97 | #ifdef LOG_USE_COLOR 98 | #ifdef WIN32 99 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 100 | CONSOLE_SCREEN_BUFFER_INFO consoleInfo; 101 | WORD saved_attributes; 102 | 103 | GetConsoleScreenBufferInfo(hConsole, &consoleInfo); 104 | saved_attributes = consoleInfo.wAttributes; 105 | 106 | // Force set to grey for this purpose, but keep the previous colour settings and revert 107 | // back to them after the logging has completed, since the user who may have changed colours 108 | // for their own logging prior to log_log called 109 | SetConsoleTextAttribute(hConsole, 7); 110 | fprintf(stderr, "%s ", buf); 111 | SetConsoleTextAttribute(hConsole, level_colors[level]); 112 | fprintf(stderr, "%s", level_names[level]); 113 | 114 | if (strlen(level_names[level]) == 5) { 115 | fprintf(stderr, " "); 116 | } else { 117 | fprintf(stderr, " "); 118 | } 119 | SetConsoleTextAttribute(hConsole, 8 /*GREY*/); 120 | fprintf(stderr, "%s:%d: ", file, line); 121 | 122 | // Revert back colour settings 123 | SetConsoleTextAttribute(hConsole, saved_attributes); 124 | #else 125 | fprintf( 126 | stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", 127 | buf, level_colors[level], level_names[level], file, line); 128 | #endif 129 | #else 130 | fprintf(stderr, "%s %-5s %s:%d: ", buf, level_names[level], file, line); 131 | #endif 132 | va_start(args, fmt); 133 | vfprintf(stderr, fmt, args); 134 | va_end(args); 135 | fprintf(stderr, "\n"); 136 | } 137 | 138 | /* Log to file */ 139 | if(L.fp) { 140 | va_list args; 141 | char buf[32]; 142 | buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0'; 143 | fprintf(L.fp, "%s %-5s %s:%d: ", buf, level_names[level], file, line); 144 | va_start(args, fmt); 145 | vfprintf(L.fp, fmt, args); 146 | va_end(args); 147 | fprintf(L.fp, "\n"); 148 | } 149 | 150 | /* Release lock */ 151 | unlock(); 152 | } 153 | -------------------------------------------------------------------------------- /src/tracer.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "common.h" 25 | #include "matrix.h" 26 | #include "window.h" 27 | #include "tracer.h" 28 | #include "model.h" 29 | #include "camera.h" 30 | #include "texture.h" 31 | #include "config.h" 32 | #include "sound.h" 33 | #include "entitysystem.h" 34 | 35 | struct entity_system tracers; 36 | 37 | void tracer_pvelocity(float* o, struct Player* p) { 38 | o[0] = o[0] * 256.0F / 32.0F + p->physics.velocity.x; 39 | o[1] = o[1] * 256.0F / 32.0F + p->physics.velocity.y; 40 | o[2] = o[2] * 256.0F / 32.0F + p->physics.velocity.z; 41 | } 42 | 43 | struct tracer_minimap_info { 44 | int large; 45 | float scalef; 46 | float minimap_x; 47 | float minimap_y; 48 | }; 49 | 50 | static bool tracer_minimap_single(void* obj, void* user) { 51 | struct Tracer* t = (struct Tracer*)obj; 52 | struct tracer_minimap_info* info = (struct tracer_minimap_info*)user; 53 | 54 | if(info->large) { 55 | float ang = -atan2(t->r.direction.z, t->r.direction.x) - HALFPI; 56 | texture_draw_rotated(&texture_tracer, info->minimap_x + t->r.origin.x * info->scalef, 57 | info->minimap_y - t->r.origin.z * info->scalef, 15 * info->scalef, 15 * info->scalef, ang); 58 | } else { 59 | float tracer_x = t->r.origin.x - info->minimap_x; 60 | float tracer_y = t->r.origin.z - info->minimap_y; 61 | if(tracer_x > 0.0F && tracer_x < 128.0F && tracer_y > 0.0F && tracer_y < 128.0F) { 62 | float ang = -atan2(t->r.direction.z, t->r.direction.x) - HALFPI; 63 | texture_draw_rotated(&texture_tracer, settings.window_width - 143 * info->scalef + tracer_x * info->scalef, 64 | (585 - tracer_y) * info->scalef, 15 * info->scalef, 15 * info->scalef, ang); 65 | } 66 | } 67 | 68 | return false; 69 | } 70 | 71 | void tracer_minimap(int large, float scalef, float minimap_x, float minimap_y) { 72 | entitysys_iterate(&tracers, 73 | &(struct tracer_minimap_info) { 74 | .large = large, 75 | .scalef = scalef, 76 | .minimap_x = minimap_x, 77 | .minimap_y = minimap_y, 78 | }, 79 | tracer_minimap_single); 80 | } 81 | 82 | void tracer_add(int type, float x, float y, float z, float dx, float dy, float dz) { 83 | struct Tracer t = (struct Tracer) { 84 | .type = type, 85 | .x = t.r.origin.x = x + dx / 4.0F, 86 | .y = t.r.origin.y = y + dy / 4.0F, 87 | .z = t.r.origin.z = z + dz / 4.0F, 88 | .r.direction.x = dx, 89 | .r.direction.y = dy, 90 | .r.direction.z = dz, 91 | .created = window_time(), 92 | }; 93 | 94 | float len = len3D(dx, dy, dz); 95 | camera_hit(&t.hit, -1, t.x, t.y, t.z, dx / len, dy / len, dz / len, 128.0F); 96 | 97 | entitysys_add(&tracers, &t); 98 | } 99 | 100 | static bool tracer_render_single(void* obj, void* user) { 101 | struct Tracer* t = (struct Tracer*)obj; 102 | 103 | matrix_push(matrix_model); 104 | matrix_translate(matrix_model, t->r.origin.x, t->r.origin.y, t->r.origin.z); 105 | matrix_pointAt(matrix_model, t->r.direction.x, t->r.direction.y, t->r.direction.z); 106 | matrix_rotate(matrix_model, 90.0F, 0.0F, 1.0F, 0.0F); 107 | matrix_upload(); 108 | kv6_render( 109 | (struct kv6_t*[]) { 110 | &model_semi_tracer, 111 | &model_smg_tracer, 112 | &model_shotgun_tracer, 113 | }[t->type], 114 | TEAM_SPECTATOR); 115 | matrix_pop(matrix_model); 116 | 117 | return false; 118 | } 119 | 120 | void tracer_render() { 121 | entitysys_iterate(&tracers, NULL, tracer_render_single); 122 | } 123 | 124 | static bool tracer_update_single(void* obj, void* user) { 125 | struct Tracer* t = (struct Tracer*)obj; 126 | float dt = *(float*)user; 127 | 128 | float len = distance3D(t->x, t->y, t->z, t->r.origin.x, t->r.origin.y, t->r.origin.z); 129 | 130 | // 128.0[m] / 256.0[m/s] = 0.5[s] 131 | if((t->hit.type != CAMERA_HITTYPE_NONE && len > pow(t->hit.distance, 2)) || window_time() - t->created > 0.5F) { 132 | if(t->hit.type != CAMERA_HITTYPE_NONE) 133 | sound_create(SOUND_WORLD, &sound_impact, t->r.origin.x, t->r.origin.y, t->r.origin.z); 134 | 135 | return true; 136 | } else { 137 | t->r.origin.x += t->r.direction.x * 32.0F * dt; 138 | t->r.origin.y += t->r.direction.y * 32.0F * dt; 139 | t->r.origin.z += t->r.direction.z * 32.0F * dt; 140 | } 141 | 142 | return false; 143 | } 144 | 145 | void tracer_update(float dt) { 146 | entitysys_iterate(&tracers, &dt, tracer_update_single); 147 | } 148 | 149 | void tracer_init() { 150 | entitysys_create(&tracers, sizeof(struct Tracer), PLAYERS_MAX); 151 | } 152 | -------------------------------------------------------------------------------- /src/grenade.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "window.h" 23 | #include "particle.h" 24 | #include "matrix.h" 25 | #include "model.h" 26 | #include "sound.h" 27 | #include "grenade.h" 28 | #include "map.h" 29 | #include "entitysystem.h" 30 | 31 | struct entity_system grenades; 32 | 33 | void grenade_init() { 34 | entitysys_create(&grenades, sizeof(struct Grenade), 32); 35 | } 36 | 37 | void grenade_add(struct Grenade* g) { 38 | g->created = window_time(); 39 | 40 | entitysys_add(&grenades, g); 41 | } 42 | 43 | static int grenade_clipworld(int x, int y, int z) { 44 | if(x < 0) 45 | x += map_size_x; 46 | if(y < 0) 47 | y += map_size_z; 48 | if(x >= map_size_x) 49 | x -= map_size_x; 50 | if(y >= map_size_z) 51 | y -= map_size_z; 52 | 53 | int sz; 54 | 55 | if(z < 0) 56 | return 0; 57 | sz = (int)z; 58 | if(sz == map_size_y - 1) 59 | sz = map_size_y - 2; 60 | else if(sz >= map_size_y - 1) 61 | return 1; 62 | else if(sz < 0) 63 | return 0; 64 | return !map_isair((int)x, (map_size_y - 1) - sz, (int)y); 65 | } 66 | 67 | static int grenade_move(struct Grenade* g, float dt) { 68 | float tmp; 69 | tmp = g->pos.z; 70 | g->pos.z = 63.0F - g->pos.y; 71 | g->pos.y = tmp; 72 | tmp = g->velocity.z; 73 | g->velocity.z = -g->velocity.y; 74 | g->velocity.y = tmp; 75 | 76 | struct Position fpos = g->pos; // old position 77 | 78 | // do velocity & gravity (friction is negligible) 79 | float f = dt * 32.0F; 80 | g->velocity.z += dt; 81 | g->pos.x += g->velocity.x * f; 82 | g->pos.y += g->velocity.y * f; 83 | g->pos.z += g->velocity.z * f; 84 | // do rotation 85 | // FIX ME: Loses orientation after 45 degree bounce off wall 86 | // if(g->v.x > 0.1f || g->v.x < -0.1f || g->v.y > 0.1f || g->v.y < -0.1f) 87 | // { 88 | // f *= -0.5; 89 | // } 90 | // make it bounce (accurate) 91 | int ret = 0; 92 | 93 | int lpx = floor(g->pos.x); 94 | int lpy = floor(g->pos.y); 95 | int lpz = floor(g->pos.z); 96 | 97 | if(grenade_clipworld(lpx, lpy, lpz)) { // hit a wall 98 | 99 | ret = 1; 100 | if(fabs(g->velocity.x) > 0.1F || fabs(g->velocity.y) > 0.1F || fabs(g->velocity.z) > 0.1F) 101 | ret = 2; // play sound 102 | 103 | int lp2x = floor(fpos.x); 104 | int lp2y = floor(fpos.y); 105 | int lp2z = floor(fpos.z); 106 | if(lpz != lp2z && ((lpx == lp2x && lpy == lp2y) || !grenade_clipworld(lpx, lpy, lp2z))) 107 | g->velocity.z *= -1; 108 | else if(lpx != lp2x && ((lpy == lp2y && lpz == lp2z) || !grenade_clipworld(lp2x, lpy, lpz))) 109 | g->velocity.x *= -1; 110 | else if(lpy != lp2y && ((lpx == lp2x && lpz == lp2z) || !grenade_clipworld(lpx, lp2y, lpz))) 111 | g->velocity.y *= -1; 112 | g->pos = fpos; // set back to old position 113 | g->velocity.x *= 0.36F; 114 | g->velocity.y *= 0.36F; 115 | g->velocity.z *= 0.36F; 116 | } 117 | 118 | tmp = g->pos.y; 119 | g->pos.y = 63.0F - g->pos.z; 120 | g->pos.z = tmp; 121 | tmp = g->velocity.y; 122 | g->velocity.y = -g->velocity.z; 123 | g->velocity.z = tmp; 124 | 125 | return ret; 126 | } 127 | 128 | static int grenade_inwater(struct Grenade* g) { 129 | return g->pos.y < 1.0F; 130 | } 131 | 132 | bool grenade_render_single(void* obj, void* user) { 133 | struct Grenade* g = (struct Grenade*)obj; 134 | 135 | // TODO: position grenade on ground properly 136 | matrix_push(matrix_model); 137 | matrix_translate(matrix_model, g->pos.x, 138 | g->pos.y + (model_grenade.zpiv + model_grenade.zsiz * 2) * model_grenade.scale, g->pos.z); 139 | if(fabs(g->velocity.x) > 0.05F || fabs(g->velocity.y) > 0.05F || fabs(g->velocity.z) > 0.05F) 140 | matrix_rotate(matrix_model, -window_time() * 720.0F, -g->velocity.z, 0.0F, g->velocity.x); 141 | matrix_upload(); 142 | 143 | kv6_calclight(g->pos.x, g->pos.y, g->pos.z); 144 | 145 | kv6_render(&model_grenade, g->team); 146 | matrix_pop(matrix_model); 147 | return false; 148 | } 149 | 150 | void grenade_render() { 151 | entitysys_iterate(&grenades, NULL, grenade_render_single); 152 | } 153 | 154 | bool grenade_update_single(void* obj, void* user) { 155 | struct Grenade* g = (struct Grenade*)obj; 156 | float dt = *(float*)user; 157 | 158 | if(window_time() - g->created > g->fuse_length) { 159 | sound_create(SOUND_WORLD, grenade_inwater(g) ? &sound_explode_water : &sound_explode, g->pos.x, g->pos.y, 160 | g->pos.z); 161 | particle_create(grenade_inwater(g) ? map_get(g->pos.x, 0, g->pos.z) : 0x505050, g->pos.x, g->pos.y + 1.5F, 162 | g->pos.z, 20.0F, 1.5F, 64, 0.1F, 0.5F); 163 | 164 | return true; 165 | } else { 166 | if(grenade_move(g, dt) == 2) 167 | sound_create(SOUND_WORLD, &sound_grenade_bounce, g->pos.x, g->pos.y, g->pos.z); 168 | 169 | return false; 170 | } 171 | } 172 | 173 | void grenade_update(float dt) { 174 | entitysys_iterate(&grenades, &dt, grenade_update_single); 175 | } 176 | -------------------------------------------------------------------------------- /src/player.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef PLAYER_H 21 | #define PLAYER_H 22 | 23 | #include 24 | 25 | #include "aabb.h" 26 | #include "network.h" 27 | 28 | #define PLAYERS_MAX 256 // just because 32 players are not enough 29 | #define TEAM_1 0 30 | #define TEAM_2 1 31 | #define TEAM_SPECTATOR 255 32 | 33 | extern struct GameState { 34 | struct Team { 35 | char name[11]; 36 | unsigned char red, green, blue; 37 | } team_1; 38 | struct Team team_2; 39 | unsigned char gamemode_type; 40 | union Gamemodes gamemode; 41 | struct { 42 | unsigned char team_capturing, tent; 43 | float progress, rate, update; 44 | } progressbar; 45 | } gamestate; 46 | 47 | #define GAMEMODE_CTF 0 48 | #define GAMEMODE_TC 1 49 | 50 | extern int button_map[3]; 51 | 52 | extern unsigned char local_player_id; 53 | extern unsigned char local_player_health; 54 | extern unsigned char local_player_blocks; 55 | extern unsigned char local_player_grenades; 56 | extern unsigned char local_player_ammo, local_player_ammo_reserved; 57 | extern unsigned char local_player_respawn_time; 58 | extern float local_player_death_time; 59 | extern unsigned char local_player_respawn_cnt_last; 60 | extern unsigned char local_player_newteam; 61 | extern unsigned char local_player_lasttool; 62 | 63 | extern float local_player_last_damage_timer; 64 | extern float local_player_last_damage_x; 65 | extern float local_player_last_damage_y; 66 | extern float local_player_last_damage_z; 67 | 68 | extern char local_player_drag_active; 69 | extern int local_player_drag_x; 70 | extern int local_player_drag_y; 71 | extern int local_player_drag_z; 72 | 73 | extern int player_intersection_type; 74 | extern int player_intersection_player; 75 | extern float player_intersection_dist; 76 | 77 | struct player_intersection { 78 | bool head; 79 | bool torso; 80 | bool leg_left; 81 | bool leg_right; 82 | bool arms; 83 | union { 84 | struct { 85 | float head; 86 | float torso; 87 | float leg_left; 88 | float leg_right; 89 | float arms; 90 | }; 91 | float values[5]; 92 | } distance; 93 | }; 94 | 95 | bool player_intersection_exists(struct player_intersection* s); 96 | int player_intersection_choose(struct player_intersection* s, float* distance); 97 | 98 | extern struct Player { 99 | char name[17]; 100 | struct Position { 101 | float x, y, z; 102 | } pos; 103 | struct Orientation { 104 | float x, y, z; 105 | } orientation; 106 | AABB bb_2d; 107 | struct Orientation orientation_smooth; 108 | struct Position gun_pos; 109 | struct Position casing_dir; 110 | float gun_shoot_timer; 111 | int ammo, ammo_reserved; 112 | float spade_use_timer; 113 | unsigned char spade_used, spade_use_type; 114 | unsigned int score; 115 | unsigned char team, weapon, held_item; 116 | unsigned char alive, connected; 117 | float item_showup, item_disabled, items_show_start; 118 | unsigned char items_show; 119 | union { 120 | unsigned int packed; 121 | struct { 122 | unsigned char red, green, blue; 123 | }; 124 | } block; 125 | struct { 126 | union { 127 | unsigned char packed; // useful to load PacketInput quickly 128 | struct { 129 | unsigned char up : 1; 130 | unsigned char down : 1; 131 | unsigned char left : 1; 132 | unsigned char right : 1; 133 | unsigned char jump : 1; 134 | unsigned char crouch : 1; 135 | unsigned char sneak : 1; 136 | unsigned char sprint : 1; 137 | }; 138 | } keys; 139 | union { 140 | unsigned char packed; 141 | struct { 142 | unsigned char lmb : 1; 143 | unsigned char rmb : 1; 144 | float lmb_start, rmb_start; 145 | }; 146 | } buttons; 147 | } input; 148 | 149 | struct { 150 | unsigned char jump, airborne, wade; 151 | float lastclimb; 152 | struct Velocity { 153 | float x, y, z; 154 | } velocity; 155 | struct Position eye; 156 | } physics; 157 | 158 | struct { 159 | float feet_started, feet_started_cycle; 160 | char feet_cylce; 161 | float tool_started; 162 | } sound; 163 | } players[PLAYERS_MAX]; 164 | // pyspades/pysnip/piqueserver sometimes uses ids that are out of range 165 | 166 | void player_on_held_item_change(struct Player* p); 167 | int player_can_spectate(struct Player* p); 168 | float player_section_height(int section); 169 | void player_init(void); 170 | float player_height(const struct Player* p); 171 | float player_height2(const struct Player* p); 172 | void player_reposition(struct Player* p); 173 | void player_update(float dt, int locked); 174 | void player_render_all(void); 175 | void player_render(struct Player* p, int id); 176 | void player_collision(const struct Player* p, Ray* ray, struct player_intersection* intersects); 177 | void player_reset(struct Player* p); 178 | int player_move(struct Player* p, float fsynctics, int id); 179 | int player_uncrouch(struct Player* p); 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /src/ping.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "window.h" 27 | #include "ping.h" 28 | #include "common.h" 29 | #include "parson.h" 30 | #include "list.h" 31 | #include "hud.h" 32 | #include "channel.h" 33 | #include "hashtable.h" 34 | #include "utils.h" 35 | 36 | struct channel ping_queue; 37 | ENetSocket sock, lan; 38 | pthread_t ping_thread; 39 | void (*ping_result)(void*, float time_delta, char* aos); 40 | 41 | void ping_init() { 42 | channel_create(&ping_queue, sizeof(struct ping_entry), 64); 43 | 44 | sock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); 45 | enet_socket_set_option(sock, ENET_SOCKOPT_NONBLOCK, 1); 46 | 47 | lan = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); 48 | enet_socket_set_option(lan, ENET_SOCKOPT_NONBLOCK, 1); 49 | enet_socket_set_option(lan, ENET_SOCKOPT_BROADCAST, 1); 50 | 51 | pthread_create(&ping_thread, NULL, ping_update, NULL); 52 | } 53 | 54 | void ping_deinit() { 55 | enet_socket_destroy(sock); 56 | enet_socket_destroy(lan); 57 | } 58 | 59 | static void ping_lan() { 60 | ENetAddress addr = {.host = 0xFFFFFFFF}; // 255.255.255.255 61 | 62 | ENetBuffer buffer = { 63 | .data = "HELLOLAN", 64 | .dataLength = 8, 65 | }; 66 | 67 | for(addr.port = 32882; addr.port < 32892; addr.port++) 68 | enet_socket_send(lan, &addr, &buffer, 1); 69 | } 70 | 71 | static bool pings_retry(void* key, void* value, void* user) { 72 | struct ping_entry* entry = (struct ping_entry*)value; 73 | 74 | if(window_time() - entry->time_start > 2.0F) { // timeout 75 | // try up to 3 times after first failed attempt 76 | if(entry->trycount >= 3) { 77 | return true; 78 | } else { 79 | enet_socket_send(sock, &entry->addr, &(ENetBuffer) {.data = "HELLO", .dataLength = 5}, 1); 80 | entry->time_start = window_time(); 81 | entry->trycount++; 82 | log_warn("Ping timeout on %s, retrying", entry->aos); 83 | } 84 | } 85 | 86 | return false; 87 | } 88 | 89 | #define IP_KEY(addr) (((uint64_t)addr.host << 16) | (addr.port)); 90 | 91 | void* ping_update(void* data) { 92 | pthread_detach(pthread_self()); 93 | 94 | float ping_start = window_time(); 95 | 96 | HashTable pings; 97 | ht_setup(&pings, sizeof(uint64_t), sizeof(struct ping_entry), 64); 98 | 99 | while(1) { 100 | size_t drain = channel_size(&ping_queue); 101 | for(size_t k = 0; (k < drain) || (!pings.size && window_time() - ping_start >= 8.0F); k++) { 102 | struct ping_entry entry; 103 | channel_await(&ping_queue, &entry); 104 | 105 | uint64_t ID = IP_KEY(entry.addr); 106 | ht_insert(&pings, &ID, &entry); 107 | } 108 | 109 | char tmp[512]; 110 | ENetAddress from; 111 | 112 | ENetBuffer buf = { 113 | .data = tmp, 114 | .dataLength = sizeof(tmp), 115 | }; 116 | 117 | while(1) { 118 | int recvLength = enet_socket_receive(sock, &from, &buf, 1); 119 | uint64_t ID = IP_KEY(from); 120 | 121 | if(recvLength != 0) { 122 | struct ping_entry* entry = ht_lookup(&pings, &ID); 123 | 124 | if(entry) { 125 | if(recvLength > 0) { // received something! 126 | if(!strncmp(buf.data, "HI", recvLength)) { 127 | ping_result(NULL, window_time() - entry->time_start, entry->aos); 128 | ht_erase(&pings, &ID); 129 | } else { 130 | entry->trycount++; 131 | } 132 | } else { // connection was closed 133 | ht_erase(&pings, &ID); 134 | } 135 | } 136 | } else { // would block 137 | break; 138 | } 139 | } 140 | 141 | ht_iterate_remove(&pings, NULL, pings_retry); 142 | 143 | int length = enet_socket_receive(lan, &from, &buf, 1); 144 | if(length) { 145 | JSON_Value* js = json_parse_string(buf.data); 146 | if(js) { 147 | JSON_Object* root = json_value_get_object(js); 148 | 149 | struct serverlist_entry e; 150 | 151 | strcpy(e.country, "LAN"); 152 | e.ping = ceil((window_time() - ping_start) * 1000.0F); 153 | snprintf(e.identifier, sizeof(e.identifier) - 1, "aos://%u:%u", from.host, from.port); 154 | 155 | strncpy(e.name, json_object_get_string(root, "name"), sizeof(e.name) - 1); 156 | e.name[sizeof(e.name) - 1] = 0; 157 | strncpy(e.gamemode, json_object_get_string(root, "game_mode"), sizeof(e.gamemode) - 1); 158 | e.gamemode[sizeof(e.gamemode) - 1] = 0; 159 | strncpy(e.map, json_object_get_string(root, "map"), sizeof(e.map) - 1); 160 | e.map[sizeof(e.map) - 1] = 0; 161 | e.current = json_object_get_number(root, "players_current"); 162 | e.max = json_object_get_number(root, "players_max"); 163 | ping_result(&e, window_time() - ping_start, NULL); 164 | 165 | json_value_free(js); 166 | } 167 | } 168 | 169 | usleep(1000); 170 | } 171 | } 172 | 173 | void ping_check(char* addr, int port, char* aos) { 174 | struct ping_entry entry = { 175 | .trycount = 0, 176 | .addr.port = port, 177 | .time_start = window_time(), 178 | }; 179 | 180 | strncpy(entry.aos, aos, sizeof(entry.aos) - 1); 181 | entry.aos[sizeof(entry.aos) - 1] = 0; 182 | 183 | enet_address_set_host(&entry.addr, addr); 184 | 185 | channel_put(&ping_queue, &entry); 186 | 187 | enet_socket_send(sock, &entry.addr, &(ENetBuffer) {.data = "HELLO", .dataLength = 5}, 1); 188 | } 189 | 190 | void ping_start(void (*result)(void*, float, char*)) { 191 | ping_stop(); 192 | 193 | ping_result = result; 194 | } 195 | 196 | void ping_stop() { 197 | channel_clear(&ping_queue); 198 | } 199 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ButterSpades 4 | --------------- 5 | **Windows**: [64bit](https://butter.penguins.win/download/) - [32bit](https://butter.penguins.win/download32/) 6 | 7 | 8 | ButterSpades is a fork which aims to improve the overall UI and feel of [BetterSpades](https://github.com/xtreme8000/BetterSpades). 9 | 10 | ## What's different 11 | - In-game settings/controls menu 12 | - Better UI scaling (HUD/Main UI) 13 | - Configurable UI background and color accents 14 | - Chat colors and killfeed (OpenSpades compatible) 15 | - Adaptive chat size 16 | - HUD shadows 17 | - Spectator Y-Clamp 18 | 19 | ## Previews 20 | 21 | |
*Apocalypse on Babel* |
*Babel* |
*Chat* | 22 | | :-: | :-: | :-: | 23 | |
***Player list*** |
***Customizable UI*** |
***Background and color scheme*** | 24 | 25 | ## System requirements 26 | 27 | | Type | min. requirement | 28 | | ------- | ---------------------------------------------------- | 29 | | OS | Windows 98 or Linux | 30 | | CPU | 1 GHz single core processor | 31 | | GPU | 64MB VRAM, Mobile Intel 945GM or equivalent | 32 | | RAM | 256MB | 33 | | Display | 800x600px | 34 | | Others | Keyboard and mouse
Dial up network connection | 35 | 36 | 37 | ## Build requirements 38 | 39 | This project uses the following libraries and files: 40 | 41 | | Name | License | Usage | GitHub | 42 | | ------------ | --------------- | ---------------------- | :------------------------------------------------: | 43 | | GLFW3 | *ZLib* | OpenGL context | [Link](https://github.com/glfw/glfw) | 44 | | OpenAL soft | *LGPL-2.1* | 3D sound environment | [Link](https://github.com/kcat/openal-soft) | 45 | | inih | *BSD-3.Clause* | .INI file parser | [Link](https://github.com/benhoyt/inih) | 46 | | stb_truetype | *Public domain* | TrueType font renderer | [Link](https://github.com/nothings/stb) | 47 | | dr_wav | *Public domain* | wav support | [Link](https://github.com/mackron/dr_libs/) | 48 | | http | *Public domain* | http client library | [Link](https://github.com/mattiasgustavsson/libs) | 49 | | LodePNG | *MIT* | png support | [Link](https://github.com/lvandeve/lodepng) | 50 | | libdeflate | *MIT* | decompression of maps | [Link](https://github.com/ebiggers/libdeflate) | 51 | | enet | *MIT* | networking library | [Link](https://github.com/lsalzman/enet) | 52 | | parson | *MIT* | JSON parser | [Link](https://github.com/kgabis/parson) | 53 | | log.c | *MIT* | logger | [Link](https://github.com/xtreme8000/log.c) | 54 | | GLEW | *MIT* | OpenGL extensions | [Link](https://github.com/nigels-com/glew) | 55 | | hashtable | *MIT* | hashtable | [Link](https://github.com/goldsborough/hashtable/) | 56 | | libvxl | *MIT* | access VXL format | [Link](https://github.com/xtreme8000/libvxl/) | 57 | | microui | *MIT* | user interface | [Link](https://github.com/rxi/microui) | 58 | 59 | You will need to compile the following by yourself, or get hold of precompiled binaries: 60 | 61 | * GLFW3 62 | * GLEW 63 | * OpenAL soft *(only needed on Windows)* 64 | * libdeflate 65 | * enet 66 | 67 | Follow the instructions on their project page, then place produced static libraries in `deps/`. 68 | 69 | All other requirements of the above list (like single file libs) will be downloaded by CMake automatically and **don't** need to be taken care of. Because state of copyright of 0.75 assets is unknown, CMake will also download additional assets from [*here*](http://aos.party/bsresources.zip) which are not part of this repository. 70 | 71 | #### Windows 72 | 73 | This project uses CMake to generate all Makefiles automatically. It's best to use MinGW-w64 for GCC on Windows. You can generate the required files by opening `cmd.exe` in the `build/` directory and typing: 74 | ``` 75 | cmake -G "MinGW Makefiles" .. 76 | mingw32-make 77 | ``` 78 | 79 | If everything went well, the client should be in the `build/BetterSpades/` subfolder. 80 | 81 | When starting `client.exe`, you will be greeted by a server list. Select a server on it to start playing! 82 | You can also start the client the same way as you did with the voxlap version by opening cmd and putting an `aos://` link in as the first argument: 83 | 84 | ``` 85 | client.exe -aos://16777343:32887 //Connects to a local server 86 | ``` 87 | 88 | #### Linux 89 | 90 | Compilation now works the same on Linux. Just change the build system to `Unix Makefiles` or leaving it as default will work too (`cmake ..`). 91 | 92 | You can build each library yourself, or install them with your distro's package manager: 93 | ``` 94 | sudo apt install libgl1-mesa libgl1-mesa-dev libopenal1 libopenal-dev libglfw-dev libenet-dev libglew-dev 95 | ``` 96 | (this does not include [libdeflate](https://github.com/ebiggers/libdeflate) which is a requirement too, see [_Wiki/Building_](https://github.com/xtreme8000/BetterSpades/wiki/Building) for more details) 97 | 98 | Start the client e.g. with the following inside the `build/bin/` directory: 99 | ``` 100 | ./client 101 | ``` 102 | Or connect directly to localhost: 103 | ``` 104 | ./client -aos://16777343:32887 105 | ``` 106 | 107 | 108 | #### macOS 109 | 110 | The same instructions for Linux work on macOS aside from some minor differences. First, use Homebrew or MacPorts to grab dependencies: 111 | ``` 112 | brew install glfw enet 113 | ``` 114 | The development headers for OpenAL and OpenGL don't have to be installed since they come with macOS by default. [libdeflate](https://github.com/ebiggers/libdeflate) should be installed and placed manually in a way similar to Linux. See [_Wiki/Building_](https://github.com/xtreme8000/BetterSpades/wiki/Building) for more details. 115 | -------------------------------------------------------------------------------- /src/channel.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "channel.h" 26 | 27 | static void channel_sanity_checks(struct channel* ch) { 28 | assert(ch != NULL); 29 | 30 | assert(ch->queue != NULL); 31 | assert(ch->object_size > 0); 32 | assert(ch->loc_remove < ch->length); 33 | assert(ch->loc_insert < ch->length); 34 | assert(ch->count <= ch->length); 35 | assert(ch->length >= ch->initial_length); 36 | 37 | if(ch->loc_remove < ch->loc_insert) { 38 | assert(ch->loc_insert - ch->loc_remove == ch->count); 39 | } else if(ch->loc_insert < ch->loc_remove) { 40 | assert(ch->loc_insert + (ch->length - ch->loc_remove) == ch->count); 41 | } else { 42 | assert(ch->count == ch->length || ch->count == 0); 43 | } 44 | } 45 | 46 | bool channel_create(struct channel* ch, size_t object_size, size_t length) { 47 | assert(ch != NULL && object_size > 0 && length > 0); 48 | 49 | ch->object_size = object_size; 50 | ch->initial_length = length; 51 | ch->length = ch->initial_length; 52 | ch->count = 0; 53 | ch->queue = malloc(object_size * length); 54 | ch->loc_insert = 0; 55 | ch->loc_remove = 0; 56 | 57 | if(!ch->queue) 58 | return false; 59 | 60 | if(pthread_mutex_init(&ch->lock, NULL)) { 61 | free(ch->queue); 62 | return false; 63 | } 64 | 65 | if(pthread_cond_init(&ch->signal, NULL)) { 66 | free(ch->queue); 67 | pthread_mutex_destroy(&ch->lock); 68 | return false; 69 | } 70 | 71 | return true; 72 | } 73 | 74 | size_t channel_size(struct channel* ch) { 75 | assert(ch != NULL); 76 | 77 | pthread_mutex_lock(&ch->lock); 78 | size_t res = ch->count; 79 | pthread_mutex_unlock(&ch->lock); 80 | return res; 81 | } 82 | 83 | void channel_destroy(struct channel* ch) { 84 | assert(ch != NULL); 85 | 86 | free(ch->queue); 87 | pthread_cond_destroy(&ch->signal); 88 | pthread_mutex_destroy(&ch->lock); 89 | } 90 | 91 | // call once buffer is full 92 | static void channel_grow(struct channel* ch) { 93 | assert(ch != NULL); 94 | 95 | size_t length = ch->length * 2; 96 | 97 | ch->queue = realloc(ch->queue, ch->object_size * length); 98 | 99 | if(ch->loc_insert <= ch->loc_remove) { 100 | size_t object_count = ch->length - ch->loc_remove; 101 | size_t new_remove_loc = length - object_count; 102 | 103 | memcpy((uint8_t*)ch->queue + new_remove_loc * ch->object_size, 104 | (uint8_t*)ch->queue + ch->loc_remove * ch->object_size, object_count * ch->object_size); 105 | 106 | ch->loc_remove = new_remove_loc; 107 | } 108 | 109 | ch->length = length; 110 | 111 | channel_sanity_checks(ch); 112 | } 113 | 114 | // call once only 25% of elements left, we will halve the buffer, so its filled exactly by 50% 115 | static void channel_shrink(struct channel* ch) { 116 | assert(ch != NULL); 117 | 118 | size_t length = ch->length / 2; 119 | 120 | /* Is the run of elements ending in the to be removed section? Note, that there are only 25% of elements left, so 121 | * the run can't wrap around to the left. If yes, move all elements to the start. */ 122 | if(ch->loc_insert > length && ch->loc_remove < ch->loc_insert) { 123 | memmove(ch->queue, (uint8_t*)ch->queue + ch->loc_remove * ch->object_size, ch->count * ch->object_size); 124 | ch->loc_remove = 0; 125 | ch->loc_insert = ch->count; 126 | 127 | /* Is the run of elements wrapping at the buffer's borders? If yes, copy the right part to the new ending 128 | * (middle). We won't override existing data, since all elements will only occupy 50% once shrinked. */ 129 | } else if(ch->loc_insert < ch->loc_remove) { 130 | size_t object_count = ch->length - ch->loc_remove; 131 | size_t new_remove_loc = length - object_count; 132 | 133 | memcpy((uint8_t*)ch->queue + new_remove_loc * ch->object_size, 134 | (uint8_t*)ch->queue + ch->loc_remove * ch->object_size, object_count * ch->object_size); 135 | 136 | ch->loc_remove = new_remove_loc; 137 | } 138 | 139 | ch->length = length; 140 | ch->queue = realloc(ch->queue, ch->object_size * ch->length); 141 | ch->loc_remove %= ch->length; 142 | ch->loc_insert %= ch->length; 143 | 144 | channel_sanity_checks(ch); 145 | } 146 | 147 | void channel_put(struct channel* ch, void* object) { 148 | assert(ch != NULL && object != NULL); 149 | 150 | pthread_mutex_lock(&ch->lock); 151 | channel_sanity_checks(ch); 152 | 153 | if(ch->count >= ch->length) 154 | channel_grow(ch); 155 | 156 | memcpy((uint8_t*)ch->queue + ch->loc_insert * ch->object_size, object, ch->object_size); 157 | ch->loc_insert = (ch->loc_insert + 1) % ch->length; 158 | ch->count++; 159 | 160 | channel_sanity_checks(ch); 161 | 162 | pthread_cond_signal(&ch->signal); 163 | pthread_mutex_unlock(&ch->lock); 164 | } 165 | 166 | void channel_await(struct channel* ch, void* object) { 167 | assert(ch != NULL && object != NULL); 168 | 169 | pthread_mutex_lock(&ch->lock); 170 | channel_sanity_checks(ch); 171 | 172 | while(!ch->count) 173 | pthread_cond_wait(&ch->signal, &ch->lock); 174 | 175 | memcpy(object, (uint8_t*)ch->queue + ch->loc_remove * ch->object_size, ch->object_size); 176 | ch->loc_remove = (ch->loc_remove + 1) % ch->length; 177 | ch->count--; 178 | 179 | if(ch->length / 2 >= ch->initial_length && ch->count <= ch->length / 4) 180 | channel_shrink(ch); 181 | 182 | channel_sanity_checks(ch); 183 | 184 | pthread_cond_signal(&ch->signal); 185 | pthread_mutex_unlock(&ch->lock); 186 | } 187 | 188 | void channel_clear(struct channel* ch) { 189 | assert(ch != NULL); 190 | 191 | pthread_mutex_lock(&ch->lock); 192 | ch->count = 0; 193 | ch->loc_remove = 0; 194 | ch->loc_insert = 0; 195 | 196 | pthread_cond_signal(&ch->signal); 197 | pthread_mutex_unlock(&ch->lock); 198 | } 199 | -------------------------------------------------------------------------------- /src/ini.h: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | SPDX-License-Identifier: BSD-3-Clause 4 | 5 | Copyright (C) 2009-2020, Ben Hoyt 6 | 7 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 8 | home page for more info: 9 | 10 | https://github.com/benhoyt/inih 11 | 12 | */ 13 | 14 | #ifndef INI_H 15 | #define INI_H 16 | 17 | /* Make this header file easier to include in C++ code */ 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #include 23 | 24 | /* Nonzero if ini_handler callback should accept lineno parameter. */ 25 | #ifndef INI_HANDLER_LINENO 26 | #define INI_HANDLER_LINENO 0 27 | #endif 28 | 29 | /* Visibility symbols, required for Windows DLLs */ 30 | #ifndef INI_API 31 | #if defined _WIN32 || defined __CYGWIN__ 32 | # ifdef INI_SHARED_LIB 33 | # ifdef INI_SHARED_LIB_BUILDING 34 | # define INI_API __declspec(dllexport) 35 | # else 36 | # define INI_API __declspec(dllimport) 37 | # endif 38 | # else 39 | # define INI_API 40 | # endif 41 | #else 42 | # if defined(__GNUC__) && __GNUC__ >= 4 43 | # define INI_API __attribute__ ((visibility ("default"))) 44 | # else 45 | # define INI_API 46 | # endif 47 | #endif 48 | #endif 49 | 50 | /* Typedef for prototype of handler function. */ 51 | #if INI_HANDLER_LINENO 52 | typedef int (*ini_handler)(void* user, const char* section, 53 | const char* name, const char* value, 54 | int lineno); 55 | #else 56 | typedef int (*ini_handler)(void* user, const char* section, 57 | const char* name, const char* value); 58 | #endif 59 | 60 | /* Typedef for prototype of fgets-style reader function. */ 61 | typedef char* (*ini_reader)(char* str, int num, void* stream); 62 | 63 | /* Parse given INI-style file. May have [section]s, name=value pairs 64 | (whitespace stripped), and comments starting with ';' (semicolon). Section 65 | is "" if name=value pair parsed before any section heading. name:value 66 | pairs are also supported as a concession to Python's configparser. 67 | 68 | For each name=value pair parsed, call handler function with given user 69 | pointer as well as section, name, and value (data only valid for duration 70 | of handler call). Handler should return nonzero on success, zero on error. 71 | 72 | Returns 0 on success, line number of first error on parse error (doesn't 73 | stop on first error), -1 on file open error, or -2 on memory allocation 74 | error (only when INI_USE_STACK is zero). 75 | */ 76 | INI_API int ini_parse(const char* filename, ini_handler handler, void* user); 77 | 78 | /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't 79 | close the file when it's finished -- the caller must do that. */ 80 | INI_API int ini_parse_file(FILE* file, ini_handler handler, void* user); 81 | 82 | /* Same as ini_parse(), but takes an ini_reader function pointer instead of 83 | filename. Used for implementing custom or string-based I/O (see also 84 | ini_parse_string). */ 85 | INI_API int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, 86 | void* user); 87 | 88 | /* Same as ini_parse(), but takes a zero-terminated string with the INI data 89 | instead of a file. Useful for parsing INI data from a network socket or 90 | already in memory. */ 91 | INI_API int ini_parse_string(const char* string, ini_handler handler, void* user); 92 | 93 | /* Nonzero to allow multi-line value parsing, in the style of Python's 94 | configparser. If allowed, ini_parse() will call the handler with the same 95 | name for each subsequent line parsed. */ 96 | #ifndef INI_ALLOW_MULTILINE 97 | #define INI_ALLOW_MULTILINE 1 98 | #endif 99 | 100 | /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of 101 | the file. See https://github.com/benhoyt/inih/issues/21 */ 102 | #ifndef INI_ALLOW_BOM 103 | #define INI_ALLOW_BOM 1 104 | #endif 105 | 106 | /* Chars that begin a start-of-line comment. Per Python configparser, allow 107 | both ; and # comments at the start of a line by default. */ 108 | #ifndef INI_START_COMMENT_PREFIXES 109 | #define INI_START_COMMENT_PREFIXES ";#" 110 | #endif 111 | 112 | /* Nonzero to allow inline comments (with valid inline comment characters 113 | specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match 114 | Python 3.2+ configparser behaviour. */ 115 | #ifndef INI_ALLOW_INLINE_COMMENTS 116 | #define INI_ALLOW_INLINE_COMMENTS 1 117 | #endif 118 | #ifndef INI_INLINE_COMMENT_PREFIXES 119 | #define INI_INLINE_COMMENT_PREFIXES ";" 120 | #endif 121 | 122 | /* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ 123 | #ifndef INI_USE_STACK 124 | #define INI_USE_STACK 1 125 | #endif 126 | 127 | /* Maximum line length for any line in INI file (stack or heap). Note that 128 | this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ 129 | #ifndef INI_MAX_LINE 130 | #define INI_MAX_LINE 200 131 | #endif 132 | 133 | /* Nonzero to allow heap line buffer to grow via realloc(), zero for a 134 | fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is 135 | zero. */ 136 | #ifndef INI_ALLOW_REALLOC 137 | #define INI_ALLOW_REALLOC 0 138 | #endif 139 | 140 | /* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK 141 | is zero. */ 142 | #ifndef INI_INITIAL_ALLOC 143 | #define INI_INITIAL_ALLOC 200 144 | #endif 145 | 146 | /* Stop parsing on first error (default is to keep parsing). */ 147 | #ifndef INI_STOP_ON_FIRST_ERROR 148 | #define INI_STOP_ON_FIRST_ERROR 0 149 | #endif 150 | 151 | /* Nonzero to call the handler at the start of each new section (with 152 | name and value NULL). Default is to only call the handler on 153 | each name=value pair. */ 154 | #ifndef INI_CALL_HANDLER_ON_NEW_SECTION 155 | #define INI_CALL_HANDLER_ON_NEW_SECTION 0 156 | #endif 157 | 158 | /* Nonzero to allow a name without a value (no '=' or ':' on the line) and 159 | call the handler with value NULL in this case. Default is to treat 160 | no-value lines as an error. */ 161 | #ifndef INI_ALLOW_NO_VALUE 162 | #define INI_ALLOW_NO_VALUE 0 163 | #endif 164 | 165 | /* Nonzero to use custom ini_malloc, ini_free, and ini_realloc memory 166 | allocation functions (INI_USE_STACK must also be 0). These functions must 167 | have the same signatures as malloc/free/realloc and behave in a similar 168 | way. ini_realloc is only needed if INI_ALLOW_REALLOC is set. */ 169 | #ifndef INI_CUSTOM_ALLOCATOR 170 | #define INI_CUSTOM_ALLOCATOR 0 171 | #endif 172 | 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #endif /* INI_H */ 179 | -------------------------------------------------------------------------------- /src/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | #include "log.h" 30 | #include "file.h" 31 | 32 | struct file_handle { 33 | void* internal; 34 | int type; 35 | }; 36 | 37 | enum { 38 | FILE_STD, 39 | FILE_SDL, 40 | }; 41 | 42 | void file_url(char* url) { 43 | char cmd[strlen(url) + 16]; 44 | #ifdef OS_WINDOWS 45 | sprintf(cmd, "start %s", url); 46 | system(cmd); 47 | #endif 48 | #if defined(OS_LINUX) || defined(OS_APPLE) 49 | sprintf(cmd, "xdg-open %s", url); 50 | system(cmd); 51 | #endif 52 | #ifdef OS_HAIKU 53 | sprintf(cmd, "open %s", url); 54 | system(cmd); 55 | #endif 56 | } 57 | 58 | int file_dir_exists(const char* path) { 59 | #ifndef USE_ANDROID_FILE 60 | DIR* d = opendir(path); 61 | #else 62 | char str[256]; 63 | sprintf(str, "/sdcard/BetterSpades/%s", path); 64 | DIR* d = opendir(str); 65 | #endif 66 | if(d) { 67 | closedir(d); 68 | return 1; 69 | } else { 70 | return 0; 71 | } 72 | } 73 | 74 | int file_dir_create(const char* path) { 75 | #ifndef USE_ANDROID_FILE 76 | #ifdef OS_WINDOWS 77 | mkdir(path); 78 | #else 79 | mkdir(path, 0755); 80 | #endif 81 | #else 82 | char str[256]; 83 | sprintf(str, "/sdcard/BetterSpades/%s", path); 84 | mkdir(str); 85 | #endif 86 | return 1; 87 | } 88 | 89 | int file_exists(const char* name) { 90 | #ifdef USE_ANDROID_FILE 91 | void* f = file_open(name, "rb"); 92 | if(f == NULL) 93 | return 0; 94 | file_close(f); 95 | return 1; 96 | #else 97 | return !access(name, F_OK); 98 | #endif 99 | } 100 | 101 | int file_size(const char* name) { 102 | #ifdef USE_ANDROID_FILE 103 | struct file_handle* f = (struct file_handle*)file_open(name, "rb"); 104 | if(!f) 105 | return 0; 106 | if(f->type == FILE_SDL) { 107 | int size = SDL_RWsize((struct SDL_RWops*)f->internal); 108 | file_close(f); 109 | return size; 110 | } 111 | if(f->type == FILE_STD) { 112 | fseek(f->internal, 0, SEEK_END); 113 | int size = ftell(f->internal); 114 | file_close(f); 115 | return size; 116 | } 117 | return 0; 118 | #else 119 | FILE* f = fopen(name, "rb"); 120 | if(!f) 121 | return 0; 122 | fseek(f, 0, SEEK_END); 123 | int size = ftell(f); 124 | fclose(f); 125 | return size; 126 | #endif 127 | } 128 | 129 | unsigned char* file_load(const char* name) { 130 | #ifdef USE_ANDROID_FILE 131 | int size = file_size(name); 132 | struct file_handle* f = (struct file_handle*)file_open(name, "rb"); 133 | if(!f) 134 | return NULL; 135 | unsigned char* data = malloc(size + 1); 136 | CHECK_ALLOCATION_ERROR(data) 137 | data[size] = 0; 138 | if(f->type == FILE_SDL) { 139 | int offset = 0; 140 | while(1) { 141 | int read = SDL_RWread((struct SDL_RWops*)f->internal, data + offset, 1, size - offset); 142 | if(!read) 143 | break; 144 | offset += read; 145 | } 146 | SDL_RWclose((struct SDL_RWops*)f->internal); 147 | if(!offset) { 148 | free(data); 149 | return NULL; 150 | } 151 | } 152 | if(f->type == FILE_STD) { 153 | fread(data, size, 1, f->internal); 154 | fclose(f->internal); 155 | } 156 | return data; 157 | #else 158 | FILE* f; 159 | f = fopen(name, "rb"); 160 | if(!f) { 161 | log_fatal("ERROR: failed to open '%s', exiting", name); 162 | exit(1); 163 | } 164 | fseek(f, 0, SEEK_END); 165 | int size = ftell(f); 166 | unsigned char* data = malloc(size + 1); 167 | CHECK_ALLOCATION_ERROR(data) 168 | data[size] = 0; 169 | fseek(f, 0, SEEK_SET); 170 | fread(data, size, 1, f); 171 | fclose(f); 172 | return data; 173 | #endif 174 | } 175 | 176 | void* file_open(const char* name, const char* mode) { 177 | #ifdef USE_ANDROID_FILE 178 | struct file_handle* handle = malloc(sizeof(struct file_handle)); 179 | handle->internal = (strchr(mode, 'r') != NULL) ? SDL_RWFromFile(name, mode) : NULL; 180 | handle->type = FILE_SDL; 181 | if(!handle->internal) { 182 | char str[256]; 183 | sprintf(str, "/sdcard/BetterSpades/%s", name); 184 | handle->internal = fopen(str, mode); 185 | handle->type = FILE_STD; 186 | // log_warn("open %s %i",str,handle->internal); 187 | } 188 | if(!handle->internal) { 189 | free(handle); 190 | return NULL; 191 | } 192 | return handle; 193 | #else 194 | return fopen(name, mode); 195 | #endif 196 | } 197 | 198 | void file_printf(void* file, const char* fmt, ...) { 199 | va_list args; 200 | va_start(args, fmt); 201 | #ifdef USE_ANDROID_FILE 202 | struct file_handle* f = (struct file_handle*)file; 203 | if(f->type == FILE_SDL) { 204 | char str[256]; 205 | vsprintf(str, fmt, args); 206 | int written = 0; 207 | int total = strlen(str); 208 | while(written < total) 209 | written += SDL_RWwrite((struct SDL_RWops*)f->internal, str + written, 1, total - written); 210 | } 211 | if(f->type == FILE_STD) { 212 | log_warn("%i %i", f->internal, f); 213 | vfprintf((FILE*)f->internal, fmt, args); 214 | } 215 | #else 216 | vfprintf((FILE*)file, fmt, args); 217 | #endif 218 | va_end(args); 219 | } 220 | 221 | void file_close(void* file) { 222 | #ifdef USE_ANDROID_FILE 223 | struct file_handle* f = (struct file_handle*)file; 224 | if(f->type == FILE_SDL) { 225 | SDL_RWclose((struct SDL_RWops*)f->internal); 226 | } 227 | if(f->type == FILE_STD) { 228 | fclose((FILE*)f->internal); 229 | } 230 | free(f); 231 | #else 232 | fclose((FILE*)file); 233 | #endif 234 | } 235 | 236 | float buffer_readf(unsigned char* buffer, int index) { 237 | return ((float*)(buffer + index))[0]; 238 | } 239 | 240 | unsigned int buffer_read32(unsigned char* buffer, int index) { 241 | return (buffer[index + 3] << 24) | (buffer[index + 2] << 16) | (buffer[index + 1] << 8) | buffer[index]; 242 | } 243 | 244 | unsigned short buffer_read16(unsigned char* buffer, int index) { 245 | return (buffer[index + 1] << 8) | buffer[index]; 246 | } 247 | 248 | unsigned char buffer_read8(unsigned char* buffer, int index) { 249 | return buffer[index]; 250 | } 251 | -------------------------------------------------------------------------------- /src/particle.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "common.h" 25 | #include "window.h" 26 | #include "camera.h" 27 | #include "map.h" 28 | #include "matrix.h" 29 | #include "particle.h" 30 | #include "model.h" 31 | #include "weapon.h" 32 | #include "config.h" 33 | #include "tesselator.h" 34 | #include "entitysystem.h" 35 | 36 | struct entity_system particles; 37 | struct tesselator particle_tesselator; 38 | 39 | void particle_init() { 40 | entitysys_create(&particles, sizeof(struct Particle), 256); 41 | tesselator_create(&particle_tesselator, VERTEX_FLOAT, 0); 42 | } 43 | 44 | static bool particle_update_single(void* obj, void* user) { 45 | struct Particle* p = (struct Particle*)obj; 46 | float dt = *(float*)user; 47 | float size = p->size * (1.0F - ((float)(window_time() - p->fade) / 2.0F)); 48 | 49 | if(size < 0.01F) { 50 | return true; 51 | } else { 52 | float acc_y = -32.0F * dt; 53 | 54 | if(map_isair(p->x, p->y + acc_y * dt - p->size / 2.0F, p->z) && !p->y + acc_y * dt < 0.0F) { 55 | p->vy += acc_y; 56 | } 57 | 58 | float movement_x = p->vx * dt; 59 | float movement_y = p->vy * dt; 60 | float movement_z = p->vz * dt; 61 | bool on_ground = false; 62 | 63 | if(!map_isair(p->x + movement_x, p->y, p->z)) { 64 | movement_x = 0.0F; 65 | p->vx = -p->vx * 0.6F; 66 | on_ground = true; 67 | } 68 | if(!map_isair(p->x + movement_x, p->y + movement_y, p->z)) { 69 | movement_y = 0.0F; 70 | p->vy = -p->vy * 0.6F; 71 | on_ground = true; 72 | } 73 | if(!map_isair(p->x + movement_x, p->y + movement_y, p->z + movement_z)) { 74 | movement_z = 0.0F; 75 | p->vz = -p->vz * 0.6F; 76 | on_ground = true; 77 | } 78 | 79 | float pow1_tys = 0.999991F + (2.55114F * dt - 2.30093F) * dt; 80 | float pow4_tys = 1.0F + (0.413432 * dt - 0.916185F) * dt; 81 | 82 | // air and ground friction 83 | if(on_ground) { 84 | p->vx *= pow1_tys; // pow(0.1F, dt); 85 | p->vy *= pow1_tys; // pow(0.1F, dt); 86 | p->vz *= pow1_tys; // pow(0.1F, dt); 87 | 88 | if(abs(p->vx) < 0.1F) 89 | p->vx = 0.0F; 90 | if(abs(p->vy) < 0.1F) 91 | p->vy = 0.0F; 92 | if(abs(p->vz) < 0.1F) 93 | p->vz = 0.0F; 94 | } else { 95 | p->vx *= pow4_tys; // pow(0.4F, dt); 96 | p->vy *= pow4_tys; // pow(0.4F, dt); 97 | p->vz *= pow4_tys; // pow(0.4F, dt); 98 | } 99 | 100 | p->x += movement_x; 101 | p->y += movement_y; 102 | p->z += movement_z; 103 | 104 | return false; 105 | } 106 | } 107 | 108 | void particle_update(float dt) { 109 | entitysys_iterate(&particles, &dt, particle_update_single); 110 | } 111 | 112 | static bool particle_render_single(void* obj, void* user) { 113 | struct Particle* p = (struct Particle*)obj; 114 | struct tesselator* tess = (struct tesselator*)user; 115 | 116 | if(distance2D(camera_x, camera_z, p->x, p->z) > settings.render_distance * settings.render_distance) 117 | return false; 118 | 119 | float size = p->size / 2.0F * (1.0F - ((float)(window_time() - p->fade) / 2.0F)); 120 | 121 | if(p->type == 255) { 122 | tesselator_set_color(tess, p->color); 123 | 124 | tesselator_addf_cube_face(tess, CUBE_FACE_X_N, p->x - size, p->y - size, p->z - size, size * 2.0F); 125 | tesselator_addf_cube_face(tess, CUBE_FACE_X_P, p->x - size, p->y - size, p->z - size, size * 2.0F); 126 | tesselator_addf_cube_face(tess, CUBE_FACE_Y_N, p->x - size, p->y - size, p->z - size, size * 2.0F); 127 | tesselator_addf_cube_face(tess, CUBE_FACE_Y_P, p->x - size, p->y - size, p->z - size, size * 2.0F); 128 | tesselator_addf_cube_face(tess, CUBE_FACE_Z_N, p->x - size, p->y - size, p->z - size, size * 2.0F); 129 | tesselator_addf_cube_face(tess, CUBE_FACE_Z_P, p->x - size, p->y - size, p->z - size, size * 2.0F); 130 | } else { 131 | struct kv6_t* casing = weapon_casing(p->type); 132 | 133 | if(casing) { 134 | matrix_push(matrix_model); 135 | matrix_identity(matrix_model); 136 | matrix_translate(matrix_model, p->x, p->y, p->z); 137 | matrix_pointAt(matrix_model, p->ox, p->oy * max(1.0F - (window_time() - p->fade) / 0.5F, 0.0F), p->oz); 138 | matrix_rotate(matrix_model, 90.0F, 0.0F, 1.0F, 0.0F); 139 | matrix_upload(); 140 | kv6_render(casing, TEAM_SPECTATOR); 141 | matrix_pop(matrix_model); 142 | } 143 | } 144 | 145 | return false; 146 | } 147 | 148 | void particle_render() { 149 | tesselator_clear(&particle_tesselator); 150 | 151 | entitysys_iterate(&particles, &particle_tesselator, particle_render_single); 152 | 153 | matrix_upload(); 154 | tesselator_draw(&particle_tesselator, 1); 155 | } 156 | 157 | void particle_create_casing(struct Player* p) { 158 | entitysys_add(&particles, 159 | &(struct Particle) { 160 | .size = 0.1F, 161 | .x = p->gun_pos.x, 162 | .y = p->gun_pos.y, 163 | .z = p->gun_pos.z, 164 | .ox = p->orientation.x, 165 | .oy = p->orientation.y, 166 | .oz = p->orientation.z, 167 | .vx = p->casing_dir.x * 3.5F, 168 | .vy = p->casing_dir.y * 3.5F, 169 | .vz = p->casing_dir.z * 3.5F, 170 | .fade = window_time(), 171 | .type = p->weapon, 172 | .color = 0x00FFFF, 173 | }); 174 | } 175 | 176 | void particle_create(unsigned int color, float x, float y, float z, float velocity, float velocity_y, int amount, 177 | float min_size, float max_size) { 178 | for(int k = 0; k < amount; k++) { 179 | float vx = (((float)rand() / (float)RAND_MAX) * 2.0F - 1.0F); 180 | float vy = (((float)rand() / (float)RAND_MAX) * 2.0F - 1.0F); 181 | float vz = (((float)rand() / (float)RAND_MAX) * 2.0F - 1.0F); 182 | float len = len3D(vx, vy, vz); 183 | 184 | vx = (vx / len) * velocity; 185 | vy = (vy / len) * velocity * velocity_y; 186 | vz = (vz / len) * velocity; 187 | 188 | entitysys_add(&particles, 189 | &(struct Particle) { 190 | .size = ((float)rand() / (float)RAND_MAX) * (max_size - min_size) + min_size, 191 | .x = x, 192 | .y = y, 193 | .z = z, 194 | .vx = vx, 195 | .vy = vy, 196 | .vz = vz, 197 | .fade = window_time(), 198 | .color = color, 199 | .type = 255, 200 | }); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/font.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "common.h" 25 | #include "file.h" 26 | #include "hashtable.h" 27 | #include "font.h" 28 | #include "stb_truetype.h" 29 | #include "utils.h" 30 | 31 | #define FONT_BAKE_START 31 32 | 33 | static short* font_vertex_buffer; 34 | static short* font_coords_buffer; 35 | static enum font_type font_current_type = FONT_FIXEDSYS; 36 | 37 | static void* font_data_fixedsys; 38 | static void* font_data_smallfnt; 39 | static void* font_data_fantasy; 40 | 41 | static HashTable fonts_backed; 42 | 43 | struct __attribute__((packed)) font_backed_id { 44 | enum font_type type; 45 | float size; 46 | }; 47 | 48 | struct font_backed_data { 49 | stbtt_bakedchar* cdata; 50 | GLuint texture_id; 51 | int w, h; 52 | }; 53 | 54 | void font_init() { 55 | font_vertex_buffer = malloc(512 * 8 * sizeof(short)); 56 | CHECK_ALLOCATION_ERROR(font_vertex_buffer) 57 | font_coords_buffer = malloc(512 * 8 * sizeof(short)); 58 | CHECK_ALLOCATION_ERROR(font_coords_buffer) 59 | 60 | font_data_fixedsys = file_load("fonts/Fixedsys.ttf"); 61 | CHECK_ALLOCATION_ERROR(font_data_fixedsys) 62 | font_data_smallfnt = file_load("fonts/Terminal.ttf"); 63 | CHECK_ALLOCATION_ERROR(font_data_smallfnt) 64 | font_data_fantasy = file_load("fonts/ft88.ttf"); 65 | CHECK_ALLOCATION_ERROR(font_data_fantasy) 66 | 67 | ht_setup(&fonts_backed, sizeof(struct font_backed_id), sizeof(struct font_backed_data), 8); 68 | } 69 | 70 | void font_select(enum font_type type) { 71 | font_current_type = type; 72 | } 73 | 74 | static struct font_backed_data* font_find(float h) { 75 | if(font_current_type == FONT_SMALLFNT) { 76 | h *= 1.5F; 77 | } 78 | 79 | struct font_backed_id id = (struct font_backed_id) { 80 | .type = font_current_type, 81 | .size = h, 82 | }; 83 | 84 | struct font_backed_data* f_cached = ht_lookup(&fonts_backed, &id); 85 | 86 | if(f_cached) 87 | return f_cached; 88 | 89 | void* file; 90 | switch(font_current_type) { 91 | case FONT_FIXEDSYS: file = font_data_fixedsys; break; 92 | case FONT_SMALLFNT: file = font_data_smallfnt; break; 93 | case FONT_FANTASY: file = font_data_fantasy; break; 94 | default: return NULL; 95 | } 96 | 97 | struct font_backed_data f; 98 | f.w = 64; 99 | f.h = 64; 100 | f.cdata = malloc((0xFF - FONT_BAKE_START) * sizeof(stbtt_bakedchar)); 101 | CHECK_ALLOCATION_ERROR(f.cdata) 102 | 103 | void* temp_bitmap = NULL; 104 | 105 | int max_size = 0; 106 | glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); 107 | 108 | while(1) { 109 | temp_bitmap = realloc(temp_bitmap, f.w * f.h); 110 | CHECK_ALLOCATION_ERROR(temp_bitmap) 111 | int res = 0; 112 | res = stbtt_BakeFontBitmap(file, 0, h, temp_bitmap, f.w, f.h, FONT_BAKE_START, 0xFF - FONT_BAKE_START, f.cdata); 113 | if(res > 0 || (f.w == max_size && f.h == max_size)) 114 | break; 115 | if(f.h > f.w) 116 | f.w *= 2; 117 | else 118 | f.h *= 2; 119 | } 120 | 121 | log_info("font texsize: %i:%ipx [size %f] type: %i", f.w, f.h, h, font_current_type); 122 | 123 | glGenTextures(1, &f.texture_id); 124 | glBindTexture(GL_TEXTURE_2D, f.texture_id); 125 | glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, f.w, f.h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); 126 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 127 | glBindTexture(GL_TEXTURE_2D, 0); 128 | 129 | free(temp_bitmap); 130 | 131 | ht_insert(&fonts_backed, &id, &f); 132 | 133 | return ht_lookup(&fonts_backed, &id); 134 | } 135 | 136 | float font_length(float h, char* text) { 137 | struct font_backed_data* font = font_find(h); 138 | 139 | if(!font) 140 | return 0.0F; 141 | 142 | stbtt_aligned_quad q; 143 | float y = h * 0.75F; 144 | float x = 0.0F; 145 | float length = 0.0F; 146 | for(size_t k = 0; k < strlen(text); k++) { 147 | if(text[k] == '\n') { 148 | length = fmax(length, x); 149 | x = 0.0F; 150 | } 151 | 152 | if(text[k] >= FONT_BAKE_START) 153 | stbtt_GetBakedQuad(font->cdata, font->w, font->h, text[k] - FONT_BAKE_START, &x, &y, &q, 1); 154 | } 155 | 156 | return fmax(length, x) + h * 0.125F; 157 | } 158 | 159 | bool font_remove_callback(void* key, void* value, void* user) { 160 | struct font_backed_data* f = (struct font_backed_data*)value; 161 | 162 | glDeleteTextures(1, &f->texture_id); 163 | free(f->cdata); 164 | 165 | return true; 166 | } 167 | 168 | void font_reset() { 169 | ht_iterate_remove(&fonts_backed, NULL, font_remove_callback); 170 | } 171 | 172 | void font_render(float x, float y, float h, char* text) { 173 | struct font_backed_data* font = font_find(h); 174 | 175 | if(!font) 176 | return; 177 | 178 | size_t k = 0; 179 | float x2 = x; 180 | float y2 = h * 0.75F; 181 | while(*text) { 182 | if(*text == '\n') { 183 | x2 = x; 184 | y2 += h; 185 | } 186 | 187 | if(*text >= FONT_BAKE_START) { 188 | stbtt_aligned_quad q; 189 | stbtt_GetBakedQuad(font->cdata, font->w, font->h, *text - FONT_BAKE_START, &x2, &y2, &q, 1); 190 | font_coords_buffer[k + 0] = q.s0 * 8192.0F; 191 | font_coords_buffer[k + 1] = q.t1 * 8192.0F; 192 | font_coords_buffer[k + 2] = q.s1 * 8192.0F; 193 | font_coords_buffer[k + 3] = q.t1 * 8192.0F; 194 | font_coords_buffer[k + 4] = q.s1 * 8192.0F; 195 | font_coords_buffer[k + 5] = q.t0 * 8192.0F; 196 | 197 | font_coords_buffer[k + 6] = q.s0 * 8192.0F; 198 | font_coords_buffer[k + 7] = q.t1 * 8192.0F; 199 | font_coords_buffer[k + 8] = q.s1 * 8192.0F; 200 | font_coords_buffer[k + 9] = q.t0 * 8192.0F; 201 | font_coords_buffer[k + 10] = q.s0 * 8192.0F; 202 | font_coords_buffer[k + 11] = q.t0 * 8192.0F; 203 | 204 | font_vertex_buffer[k + 0] = q.x0; 205 | font_vertex_buffer[k + 1] = -q.y1 + y; 206 | font_vertex_buffer[k + 2] = q.x1; 207 | font_vertex_buffer[k + 3] = -q.y1 + y; 208 | font_vertex_buffer[k + 4] = q.x1; 209 | font_vertex_buffer[k + 5] = -q.y0 + y; 210 | 211 | font_vertex_buffer[k + 6] = q.x0; 212 | font_vertex_buffer[k + 7] = -q.y1 + y; 213 | font_vertex_buffer[k + 8] = q.x1; 214 | font_vertex_buffer[k + 9] = -q.y0 + y; 215 | font_vertex_buffer[k + 10] = q.x0; 216 | font_vertex_buffer[k + 11] = -q.y0 + y; 217 | k += 12; 218 | } 219 | 220 | text++; 221 | } 222 | 223 | glMatrixMode(GL_TEXTURE); 224 | glLoadIdentity(); 225 | glScalef(1.0F / 8192.0F, 1.0F / 8192.0F, 1.0F); 226 | glMatrixMode(GL_MODELVIEW); 227 | 228 | glEnable(GL_TEXTURE_2D); 229 | glBindTexture(GL_TEXTURE_2D, font->texture_id); 230 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 231 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 232 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 233 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 234 | glEnable(GL_BLEND); 235 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 236 | 237 | glEnableClientState(GL_VERTEX_ARRAY); 238 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 239 | glVertexPointer(2, GL_SHORT, 0, font_vertex_buffer); 240 | glTexCoordPointer(2, GL_SHORT, 0, font_coords_buffer); 241 | glDrawArrays(GL_TRIANGLES, 0, k / 2); 242 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 243 | glDisableClientState(GL_VERTEX_ARRAY); 244 | 245 | glDisable(GL_BLEND); 246 | glBindTexture(GL_TEXTURE_2D, 0); 247 | glDisable(GL_TEXTURE_2D); 248 | 249 | glMatrixMode(GL_TEXTURE); 250 | glLoadIdentity(); 251 | glMatrixMode(GL_MODELVIEW); 252 | } 253 | 254 | void font_render_shadow(float x, float y, float h, char* text, float a) { 255 | float color[4]; 256 | glGetFloatv(GL_CURRENT_COLOR, color); 257 | 258 | glColor4f(0.F, 0.F, 0.F, a); 259 | font_render(x, y - 1.F, h, text); 260 | font_render(x, y - 2.F, h, text); 261 | 262 | glColor4f(color[0], color[1], color[2], color[3]); 263 | font_render(x, y, h, text); 264 | } 265 | 266 | void font_centered(float x, float y, float h, char* text) { 267 | font_render(x - font_length(h, text) / 2.0F, y, h, text); 268 | } 269 | 270 | void font_centered_shadow(float x, float y, float h, char* text, float a) { 271 | font_render_shadow(x - font_length(h, text) / 2.0F, y, h, text, a); 272 | } 273 | -------------------------------------------------------------------------------- /src/model_normals.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020 ByteBit 3 | 4 | This file is part of BetterSpades. 5 | 6 | BetterSpades is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | BetterSpades is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with BetterSpades. If not, see . 18 | */ 19 | 20 | #ifndef MODEL_NORMALS_H 21 | #define MODEL_NORMALS_H 22 | 23 | float kv6_normals[256][3] 24 | = {{0.08847, 0.00000, -0.99608}, {-0.11277, 0.10331, -0.98824}, {0.01723, -0.19630, -0.98039}, 25 | {0.14158, 0.18467, -0.97255}, {-0.25930, -0.04587, -0.96471}, {0.24514, -0.15594, -0.95686}, 26 | {-0.08183, 0.30441, -0.94902}, {-0.15575, -0.29988, -0.94118}, {0.33723, 0.12315, -0.93333}, 27 | {-0.35012, 0.14452, -0.92549}, {0.16843, -0.35994, -0.91765}, {0.12421, 0.39601, -0.90980}, 28 | {-0.37361, -0.21652, -0.90196}, {0.43739, -0.09616, -0.89412}, {-0.26638, 0.37889, -0.88627}, 29 | {-0.06141, -0.47391, -0.87843}, {0.37622, 0.31708, -0.87059}, {-0.50521, 0.02089, -0.86275}, 30 | {0.36773, -0.36594, -0.85490}, {-0.02455, 0.53093, -0.84706}, {-0.34842, -0.41752, -0.83922}, 31 | {0.55075, 0.07410, -0.83137}, {-0.46565, 0.32399, -0.82353}, {0.12697, -0.56439, -0.81569}, 32 | {0.29304, 0.51139, -0.80784}, {-0.57162, -0.18236, -0.80000}, {0.55404, -0.25598, -0.79216}, 33 | {-0.23950, 0.57227, -0.78431}, {-0.21328, -0.59296, -0.77647}, {0.56625, 0.29760, -0.76863}, 34 | {-0.62757, 0.16543, -0.76078}, {0.35592, -0.55354, -0.75294}, {0.11297, 0.65732, -0.74510}, 35 | {-0.53416, -0.41368, -0.73725}, {0.68174, -0.05648, -0.72941}, {-0.47015, 0.50823, -0.72157}, 36 | {0.00342, -0.70042, -0.71373}, {0.47592, 0.52463, -0.70588}, {-0.71300, -0.06608, -0.69804}, 37 | {0.57641, -0.43747, -0.69020}, {-0.13084, 0.71922, -0.68235}, {-0.39321, -0.62484, -0.67451}, 38 | {0.71885, 0.19701, -0.66667}, {-0.66931, 0.34348, -0.65882}, {0.26387, -0.71176, -0.65098}, 39 | {0.28872, 0.70924, -0.64314}, {-0.69787, -0.33073, -0.63529}, {0.74409, -0.22941, -0.62745}, 40 | {-0.39687, 0.67719, -0.61961}, {-0.16608, -0.77341, -0.61176}, {0.64979, 0.46158, -0.60392}, 41 | {-0.79676, 0.09930, -0.59608}, {0.52417, -0.61581, -0.58824}, {0.02968, 0.81380, -0.58039}, 42 | {-0.57548, -0.58396, -0.57255}, {0.82422, 0.04214, -0.56471}, {-0.64031, 0.52906, -0.55686}, 43 | {0.11549, -0.82779, -0.54902}, {0.47690, 0.69260, -0.54118}, {-0.82436, -0.18968, -0.53333}, 44 | {0.74025, -0.41940, -0.52549}, {-0.26401, 0.81384, -0.51765}, {-0.35702, -0.78271, -0.50980}, 45 | {0.79620, 0.33778, -0.50196}, {-0.81951, 0.29026, -0.49412}, {0.41029, -0.77149, -0.48627}, 46 | {0.21969, 0.85020, -0.47843}, {-0.73984, -0.48082, -0.47059}, {0.87440, -0.14589, -0.46275}, 47 | {-0.54871, 0.70142, -0.45490}, {-0.06951, -0.89180, -0.44706}, {0.65649, 0.61328, -0.43922}, 48 | {-0.90213, -0.00880, -0.43137}, {0.67391, -0.60537, -0.42353}, {-0.08835, 0.90521, -0.41569}, 49 | {-0.54844, -0.72998, -0.40784}, {0.90091, 0.16843, -0.40000}, {-0.78095, 0.48614, -0.39216}, 50 | {0.24835, -0.88917, -0.38431}, {0.41896, 0.82628, -0.37647}, {-0.87002, -0.32738, -0.36863}, 51 | {0.86552, -0.34743, -0.36078}, {-0.40482, 0.84354, -0.35294}, {-0.27215, -0.89824, -0.34510}, 52 | {0.80988, 0.47995, -0.33725}, {-0.92410, 0.19373, -0.32941}, {0.55211, -0.76926, -0.32157}, 53 | {0.11283, 0.94279, -0.31373}, {-0.72198, -0.62063, -0.30588}, {0.95408, -0.03014, -0.29804}, 54 | {-0.68488, 0.66838, -0.29020}, {0.05366, -0.95781, -0.28235}, {0.60886, 0.74426, -0.27451}, 55 | {-0.95388, -0.13783, -0.26667}, {0.79823, -0.54391, -0.25882}, {-0.22166, 0.94227, -0.25098}, 56 | {-0.47403, -0.84628, -0.24314}, {0.92302, 0.30442, -0.23529}, {-0.88794, 0.39979, -0.22745}, 57 | {0.38540, -0.89624, -0.21961}, {0.32179, 0.92283, -0.21176}, {-0.86210, -0.46389, -0.20392}, 58 | {0.95059, -0.24068, -0.19608}, {-0.53920, 0.82087, -0.18824}, {-0.15713, -0.97096, -0.18039}, 59 | {0.77284, 0.61069, -0.17255}, {-0.98372, 0.07184, -0.16471}, {0.67770, -0.71841, -0.15686}, 60 | {-0.01446, 0.98873, -0.14902}, {-0.65798, -0.73968, -0.14118}, {0.98590, 0.10107, -0.13333}, 61 | {-0.79607, 0.59205, -0.12549}, {0.18725, -0.97524, -0.11765}, {0.52116, 0.84636, -0.10980}, 62 | {-0.95680, -0.27227, -0.10196}, {0.89012, -0.44589, -0.09412}, {-0.35541, 0.93072, -0.08627}, 63 | {-0.36687, -0.92696, -0.07843}, {0.89720, 0.43595, -0.07059}, {-0.95655, 0.28474, -0.06275}, 64 | {0.51323, -0.85649, -0.05490}, {0.20019, 0.97863, -0.04706}, {-0.80894, -0.58658, -0.03922}, 65 | {0.99299, -0.11394, -0.03137}, {-0.65538, 0.75493, -0.02353}, {-0.02670, -0.99952, -0.01569}, 66 | {0.69492, 0.71905, -0.00784}, {-0.99815, -0.06079, 0.00000}, {0.77705, -0.62939, 0.00784}, 67 | {-0.14781, 0.98889, 0.01569}, {-0.55891, -0.82889, 0.02353}, {0.97182, 0.23361, 0.03137}, 68 | {-0.87415, 0.48407, 0.03922}, {0.31748, -0.94710, 0.04706}, {0.40549, 0.91245, 0.05490}, 69 | {-0.91492, -0.39872, 0.06275}, {0.94347, -0.32385, 0.07059}, {-0.47665, 0.87559, 0.07843}, 70 | {-0.23982, -0.96698, 0.08627}, {0.82943, 0.55063, 0.09412}, {-0.98277, 0.15414, 0.10196}, 71 | {0.62003, -0.77686, 0.10980}, {0.06751, 0.99076, 0.11765}, {-0.71833, -0.68429, 0.12549}, 72 | {0.99088, 0.01933, 0.13333}, {-0.74289, 0.65436, 0.14118}, {0.10564, -0.98317, 0.14902}, 73 | {0.58551, 0.79535, 0.15686}, {-0.96773, -0.19071, 0.16471}, {0.84125, -0.51237, 0.17255}, 74 | {-0.27382, 0.94471, 0.18039}, {-0.43558, -0.88025, 0.18824}, {0.91435, 0.35428, 0.19608}, 75 | {-0.91204, 0.35582, 0.20392}, {0.43142, -0.87695, 0.21176}, {0.27377, 0.93639, 0.21961}, 76 | {-0.83285, -0.50461, 0.22745}, {0.95314, -0.19014, 0.23529}, {-0.57324, 0.78248, 0.24314}, 77 | {-0.10565, -0.96221, 0.25098}, {0.72631, 0.63678, 0.25882}, {-0.96356, 0.02103, 0.26667}, 78 | {0.69470, -0.66486, 0.27451}, {-0.06300, 0.95724, 0.28235}, {-0.59869, -0.74656, 0.29020}, 79 | {0.94337, 0.14572, 0.29804}, {-0.79197, 0.52841, 0.30588}, {0.22643, -0.92212, 0.31373}, 80 | {0.45466, 0.83059, 0.32157}, {-0.89375, -0.30446, 0.32941}, {0.86215, -0.37810, 0.33725}, 81 | {-0.37916, 0.85857, 0.34510}, {-0.29944, -0.88644, 0.35294}, {0.81695, 0.44992, 0.36078}, 82 | {-0.90332, 0.21936, 0.36863}, {0.51615, -0.76932, 0.37647}, {0.13859, 0.91274, 0.38431}, 83 | {-0.71617, -0.57734, 0.39216}, {0.91469, -0.05784, 0.40000}, {-0.63299, 0.65802, 0.40784}, 84 | {0.02218, -0.90924, 0.41569}, {0.59544, 0.68269, 0.42353}, {-0.89653, -0.10077, 0.43137}, 85 | {0.72607, -0.52906, 0.43922}, {-0.17724, 0.87677, 0.44706}, {-0.45951, -0.76283, 0.45490}, 86 | {0.85023, 0.25095, 0.46275}, {-0.79273, 0.38747, 0.47059}, {0.32126, -0.81725, 0.47843}, 87 | {0.31361, 0.81559, 0.48627}, {-0.77822, -0.38758, 0.49412}, {0.83131, -0.23865, 0.50196}, 88 | {-0.44938, 0.73359, 0.50980}, {-0.16328, -0.83987, 0.51765}, {0.68387, 0.50615, 0.52549}, 89 | {-0.84129, 0.08822, 0.53333}, {0.55744, -0.62959, 0.54118}, {0.01416, 0.83569, 0.54902}, 90 | {-0.57136, -0.60287, 0.55686}, {0.82324, 0.05822, 0.56471}, {-0.64211, 0.50979, 0.57255}, 91 | {0.12824, -0.80418, 0.58039}, {0.44554, 0.67489, 0.58824}, {-0.77882, -0.19528, 0.59608}, 92 | {0.70101, -0.37929, 0.60392}, {-0.25873, 0.74753, 0.61176}, {-0.31173, -0.72035, 0.61961}, 93 | {0.71074, 0.31804, 0.62745}, {-0.73285, 0.24358, 0.63529}, {0.37268, -0.66894, 0.64314}, 94 | {0.17553, 0.73852, 0.65098}, {-0.62267, -0.42218, 0.65882}, {0.73745, -0.10829, 0.66667}, 95 | {-0.46614, 0.57249, 0.67451}, {-0.04259, -0.72978, 0.68235}, {0.51906, 0.50419, 0.69020}, 96 | {-0.71575, -0.02094, 0.69804}, {0.53607, -0.46299, 0.70588}, {-0.08161, 0.69565, 0.71373}, 97 | {-0.40500, -0.56152, 0.72157}, {0.66985, 0.13880, 0.72941}, {-0.58041, 0.34580, 0.73726}, 98 | {0.19190, -0.63875, 0.74510}, {0.28611, 0.59264, 0.75294}, {-0.60285, -0.24036, 0.76078}, 99 | {0.59818, -0.22669, 0.76863}, {-0.28366, 0.56270, 0.77647}, {-0.16828, -0.59710, 0.78431}, 100 | {0.51888, 0.32133, 0.79216}, {-0.58952, 0.11164, 0.80000}, {0.35293, -0.47205, 0.80784}, 101 | {0.05754, 0.57563, 0.81569}, {-0.42289, -0.37810, 0.82353}, {0.55567, -0.00672, 0.83137}, 102 | {-0.39651, 0.37215, 0.83922}, {0.04006, -0.52999, 0.84706}, {0.32060, 0.40787, 0.85490}, 103 | {-0.49894, -0.08205, 0.86275}, {0.41192, -0.26907, 0.87059}, {-0.11847, 0.46295, 0.87843}, 104 | {-0.21843, -0.40842, 0.88627}, {0.42248, 0.14853, 0.89412}, {-0.39713, 0.16957, 0.90196}, 105 | {0.17136, -0.37801, 0.90980}, {0.12351, 0.37772, 0.91765}, {-0.32999, -0.18594, 0.92549}, 106 | {0.34968, -0.08132, 0.93333}, {-0.19099, 0.27876, 0.94118}, {-0.04428, -0.31209, 0.94902}, 107 | {0.22441, 0.18454, 0.95686}, {-0.26295, 0.01406, 0.96471}, {0.16295, -0.16612, 0.97255}, 108 | {-0.00672, 0.19694, 0.98039}, {-0.09940, -0.11623, 0.98824}, {0.08782, 0.01074, 0.99608}, 109 | {0.00000, 0.00000, 1.00000}}; 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | 3 | FetchContent_Declare( 4 | cglm 5 | GIT_REPOSITORY https://github.com/recp/cglm 6 | GIT_TAG v0.8.5 7 | ) 8 | 9 | set(CGLM_STATIC ON CACHE INTERNAL "") 10 | set(CGLM_USE_C99 ON CACHE INTERNAL "") 11 | set(MIRRORS https://butter.penguins.win/mirror) 12 | FetchContent_MakeAvailable(cglm) 13 | 14 | FetchContent_Declare( 15 | vxl 16 | GIT_REPOSITORY https://github.com/xtreme8000/libvxl 17 | GIT_TAG origin/master 18 | ) 19 | 20 | FetchContent_MakeAvailable(vxl) 21 | 22 | macro(download_file_if_it_doesnt_exist filename url) 23 | set(argn ${ARGN}) 24 | list(LENGTH argn no_fallback) 25 | if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) 26 | message(STATUS "Downloading ${filename}") 27 | file(DOWNLOAD ${url} ${CMAKE_CURRENT_SOURCE_DIR}/${filename} STATUS stat) 28 | list(GET stat 0 success) 29 | list(GET stat 1 error) 30 | if (NOT ${success}) 31 | message(STATUS "Downloaded ${filename} successfully") 32 | else() 33 | file(REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) 34 | message(WARNING "Failed to download ${filename} (${error})") 35 | 36 | if(${no_fallback} EQUAL 0) 37 | foreach(mirror ${MIRRORS}) 38 | string(SHA256 mirror_url_hash ${url}) 39 | set(mirror_url ${mirror}/${mirror_url_hash}) 40 | message(STATUS "Trying alternate URL ${mirror_url}") 41 | download_file_if_it_doesnt_exist(${filename} ${mirror_url} 1) 42 | if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) 43 | # Success 44 | break() 45 | endif() 46 | endforeach() 47 | 48 | if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) 49 | # Everything failed, exit 50 | message(FATAL_ERROR "Failed to download ${filename} from all sources.") 51 | endif() 52 | endif() 53 | endif() 54 | endif() 55 | endmacro(download_file_if_it_doesnt_exist) 56 | 57 | download_file_if_it_doesnt_exist(../bsresources.zip http://aos.party/bsresources.zip) 58 | 59 | list(APPEND CLIENT_SOURCES aabb.c) 60 | list(APPEND CLIENT_SOURCES camera.c) 61 | list(APPEND CLIENT_SOURCES cameracontroller.c) 62 | list(APPEND CLIENT_SOURCES chunk.c) 63 | list(APPEND CLIENT_SOURCES config.c) 64 | list(APPEND CLIENT_SOURCES dr_wav.c) 65 | list(APPEND CLIENT_SOURCES file.c) 66 | list(APPEND CLIENT_SOURCES font.c) 67 | list(APPEND CLIENT_SOURCES glx.c) 68 | list(APPEND CLIENT_SOURCES grenade.c) 69 | list(APPEND CLIENT_SOURCES http.c) 70 | list(APPEND CLIENT_SOURCES gmi.c) 71 | list(APPEND CLIENT_SOURCES hud.c) 72 | list(APPEND CLIENT_SOURCES ini.c) 73 | list(APPEND CLIENT_SOURCES list.c) 74 | list(APPEND CLIENT_SOURCES main.c) 75 | list(APPEND CLIENT_SOURCES map.c) 76 | list(APPEND CLIENT_SOURCES matrix.c) 77 | list(APPEND CLIENT_SOURCES model.c) 78 | list(APPEND CLIENT_SOURCES network.c) 79 | list(APPEND CLIENT_SOURCES parson.c) 80 | list(APPEND CLIENT_SOURCES particle.c) 81 | list(APPEND CLIENT_SOURCES player.c) 82 | list(APPEND CLIENT_SOURCES sound.c) 83 | list(APPEND CLIENT_SOURCES stb_truetype.c) 84 | list(APPEND CLIENT_SOURCES texture.c) 85 | list(APPEND CLIENT_SOURCES tracer.c) 86 | list(APPEND CLIENT_SOURCES weapon.c) 87 | list(APPEND CLIENT_SOURCES window.c) 88 | list(APPEND CLIENT_SOURCES utils.c) 89 | list(APPEND CLIENT_SOURCES ping.c) 90 | list(APPEND CLIENT_SOURCES log.c) 91 | list(APPEND CLIENT_SOURCES minheap.c) 92 | list(APPEND CLIENT_SOURCES hashtable.c) 93 | list(APPEND CLIENT_SOURCES rpc.c) 94 | list(APPEND CLIENT_SOURCES tesselator.c) 95 | list(APPEND CLIENT_SOURCES microui.c) 96 | list(APPEND CLIENT_SOURCES channel.c) 97 | list(APPEND CLIENT_SOURCES entitysystem.c) 98 | list(APPEND CLIENT_SOURCES ${BetterSpades_SOURCE_DIR}/resources/icon.rc) 99 | 100 | add_executable(client ${CLIENT_SOURCES}) 101 | 102 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 103 | set_property(TARGET client PROPERTY WIN32_EXECUTABLE true) 104 | target_compile_definitions(client PRIVATE NDEBUG) 105 | endif() 106 | 107 | set(GIT_COMMIT_HASH "?") 108 | 109 | execute_process( 110 | COMMAND git describe --always --dirty 111 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 112 | OUTPUT_VARIABLE GIT_COMMIT_HASH 113 | OUTPUT_STRIP_TRAILING_WHITESPACE 114 | ) 115 | 116 | include(CheckIPOSupported) 117 | check_ipo_supported(RESULT lto_supported OUTPUT error) 118 | 119 | if(lto_supported) 120 | message(STATUS "IPO / LTO enabled") 121 | set_property(TARGET client PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) 122 | else() 123 | message(STATUS "IPO / LTO not supported: <${error}>") 124 | endif() 125 | 126 | target_compile_definitions(client PRIVATE GIT_COMMIT_HASH="${GIT_COMMIT_HASH}") 127 | target_compile_definitions(client PRIVATE DR_WAV_IMPLEMENTATION) 128 | target_compile_definitions(client PRIVATE LOG_USE_COLOR) 129 | 130 | if(ENABLE_TOUCH) 131 | target_compile_definitions(client PRIVATE USE_TOUCH) 132 | endif() 133 | if(ENABLE_ANDROID_FILE) 134 | target_compile_definitions(client PRIVATE USE_ANDROID_FILE) 135 | endif() 136 | 137 | target_compile_definitions(client PRIVATE BETTERSPADES_MAJOR=${BETTERSPADES_MAJOR}) 138 | target_compile_definitions(client PRIVATE BETTERSPADES_MINOR=${BETTERSPADES_MINOR}) 139 | target_compile_definitions(client PRIVATE BETTERSPADES_PATCH=${BETTERSPADES_PATCH}) 140 | target_compile_definitions(client PRIVATE BETTERSPADES_VERSION="v${BETTERSPADES_MAJOR}.${BETTERSPADES_MINOR}.${BETTERSPADES_PATCH}") 141 | 142 | 143 | set_target_properties( 144 | client PROPERTIES 145 | RUNTIME_OUTPUT_DIRECTORY ${BetterSpades_SOURCE_DIR}/build/BetterSpades 146 | C_STANDARD 99 147 | ) 148 | 149 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${BetterSpades_SOURCE_DIR}/deps) 150 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${BetterSpades_SOURCE_DIR}/cmake/Modules) 151 | set(OpenGL_GL_PREFERENCE LEGACY) 152 | if(ENABLE_GLFW) 153 | find_package(glfw3 REQUIRED) 154 | target_link_libraries(client glfw3::glfw3) 155 | target_compile_definitions(client PRIVATE USE_GLFW) 156 | endif() 157 | if(ENABLE_SDL) 158 | find_package(SDL2 REQUIRED) 159 | target_link_libraries(client ${SDL2_LIBRARY}) 160 | target_compile_definitions(client PRIVATE USE_SDL) 161 | endif() 162 | if(ENABLE_SOUND) 163 | find_package(OpenAL REQUIRED) 164 | target_link_libraries(client ${OPENAL_LIBRARY}) 165 | target_compile_definitions(client PRIVATE USE_SOUND) 166 | endif() 167 | find_package(enet REQUIRED) 168 | find_package(deflate REQUIRED) 169 | find_package(Threads REQUIRED) 170 | if(NOT ENABLE_OPENGLES) 171 | find_package(OpenGL REQUIRED) 172 | find_package(GLEW REQUIRED) 173 | target_link_libraries(client GLEW::GLEW) 174 | else() 175 | find_package(OpenGL REQUIRED COMPONENTS EGL) 176 | target_link_libraries(client OpenGL::EGL) 177 | target_compile_definitions(client PRIVATE OPENGL_ES) 178 | endif() 179 | if(ENABLE_RPC) 180 | target_link_libraries(client discord-rpc stdc++) 181 | target_compile_definitions(client PRIVATE USE_RPC DISCORD_DISABLE_IO_THREAD) 182 | endif() 183 | if(DEFINED ENV{BUILD_NUMBER}) 184 | target_compile_definitions(client PRIVATE JENKINS_BUILD="$ENV{BUILD_NUMBER}") 185 | endif() 186 | 187 | 188 | if(WIN32) 189 | target_compile_definitions(client PRIVATE LIBDEFLATE_STATIC) 190 | endif() 191 | 192 | target_link_libraries(client ${CMAKE_THREAD_LIBS_INIT} ${OPENGL_LIBRARIES} enet::enet deflate::deflate m cglm vxl) 193 | target_include_directories(client PRIVATE ${OPENAL_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} ${OPENGL_EGL_INCLUDE_DIRS}) 194 | 195 | add_custom_command( 196 | TARGET client 197 | POST_BUILD 198 | COMMENT "Copying resources..." 199 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${BetterSpades_SOURCE_DIR}/resources ${BetterSpades_SOURCE_DIR}/build/BetterSpades 200 | ) 201 | 202 | add_custom_command( 203 | TARGET client 204 | POST_BUILD 205 | COMMENT "Extracting additional third-party assets..." 206 | DEPENDS ${BetterSpades_SOURCE_DIR}/bsresources.zip 207 | WORKING_DIRECTORY ${BetterSpades_SOURCE_DIR}/build/BetterSpades 208 | COMMAND ${CMAKE_COMMAND} -E tar xzf ${BetterSpades_SOURCE_DIR}/bsresources.zip 209 | ) 210 | 211 | add_custom_command( 212 | TARGET client 213 | POST_BUILD 214 | COMMENT "Copying overrides..." 215 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${BetterSpades_SOURCE_DIR}/resources.override ${BetterSpades_SOURCE_DIR}/build/BetterSpades 216 | ) 217 | 218 | install( 219 | TARGETS client 220 | RUNTIME 221 | DESTINATION . 222 | ) 223 | 224 | install( 225 | FILES "${CMAKE_BINARY_DIR}/BetterSpades/config.ini" "${CMAKE_BINARY_DIR}/BetterSpades/OpenAL32.dll" 226 | DESTINATION . 227 | PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ 228 | GROUP_EXECUTE GROUP_READ 229 | ) 230 | 231 | install( 232 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/fonts" 233 | DESTINATION . 234 | FILES_MATCHING PATTERN "*.ttf" 235 | ) 236 | 237 | install( 238 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/kv6" 239 | DESTINATION . 240 | FILES_MATCHING PATTERN "*.kv6" 241 | ) 242 | 243 | install( 244 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/png" 245 | DESTINATION . 246 | FILES_MATCHING PATTERN "*.png" 247 | ) 248 | 249 | install( 250 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/wav" 251 | DESTINATION . 252 | FILES_MATCHING PATTERN "*.wav" 253 | ) 254 | 255 | install( 256 | DIRECTORY 257 | DESTINATION "cache" 258 | ) 259 | 260 | install( 261 | DIRECTORY 262 | DESTINATION "logs" 263 | ) 264 | 265 | install( 266 | DIRECTORY 267 | DESTINATION "screenshots" 268 | ) 269 | 270 | set(CPACK_GENERATOR NSIS) 271 | set(CPACK_PACKAGE_NAME "BetterSpades") 272 | set(CPACK_PACKAGE_VENDOR "github.com") 273 | set(CPACK_PACKAGE_VERSION "v${BETTERSPADES_MAJOR}.${BETTERSPADES_MINOR}.${BETTERSPADES_PATCH}") 274 | set(CPACK_PACKAGE_VERSION_MAJOR "${BETTERSPADES_MAJOR}") 275 | set(CPACK_PACKAGE_VERSION_MINOR "${BETTERSPADES_MINOR}") 276 | set(CPACK_PACKAGE_VERSION_PATCH "${BETTERSPADES_PATCH}") 277 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") 278 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") 279 | set(CPACK_STRIP_FILES TRUE) 280 | set(CPACK_NSIS_MENU_LINKS "client" "BetterSpades") 281 | set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) 282 | set(CPACK_PACKAGE_CHECKSUM SHA256) 283 | 284 | INCLUDE(CPack) 285 | -------------------------------------------------------------------------------- /src/ini.c: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | SPDX-License-Identifier: BSD-3-Clause 4 | 5 | Copyright (C) 2009-2020, Ben Hoyt 6 | 7 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 8 | home page for more info: 9 | 10 | https://github.com/benhoyt/inih 11 | 12 | */ 13 | 14 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 15 | #define _CRT_SECURE_NO_WARNINGS 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ini.h" 23 | 24 | #if !INI_USE_STACK 25 | #if INI_CUSTOM_ALLOCATOR 26 | #include 27 | void* ini_malloc(size_t size); 28 | void ini_free(void* ptr); 29 | void* ini_realloc(void* ptr, size_t size); 30 | #else 31 | #include 32 | #define ini_malloc malloc 33 | #define ini_free free 34 | #define ini_realloc realloc 35 | #endif 36 | #endif 37 | 38 | #define MAX_SECTION 50 39 | #define MAX_NAME 50 40 | 41 | /* Used by ini_parse_string() to keep track of string parsing state. */ 42 | typedef struct { 43 | const char* ptr; 44 | size_t num_left; 45 | } ini_parse_string_ctx; 46 | 47 | /* Strip whitespace chars off end of given string, in place. Return s. */ 48 | static char* rstrip(char* s) 49 | { 50 | char* p = s + strlen(s); 51 | while (p > s && isspace((unsigned char)(*--p))) 52 | *p = '\0'; 53 | return s; 54 | } 55 | 56 | /* Return pointer to first non-whitespace char in given string. */ 57 | static char* lskip(const char* s) 58 | { 59 | while (*s && isspace((unsigned char)(*s))) 60 | s++; 61 | return (char*)s; 62 | } 63 | 64 | /* Return pointer to first char (of chars) or inline comment in given string, 65 | or pointer to NUL at end of string if neither found. Inline comment must 66 | be prefixed by a whitespace character to register as a comment. */ 67 | static char* find_chars_or_comment(const char* s, const char* chars) 68 | { 69 | #if INI_ALLOW_INLINE_COMMENTS 70 | int was_space = 0; 71 | while (*s && (!chars || !strchr(chars, *s)) && 72 | !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { 73 | was_space = isspace((unsigned char)(*s)); 74 | s++; 75 | } 76 | #else 77 | while (*s && (!chars || !strchr(chars, *s))) { 78 | s++; 79 | } 80 | #endif 81 | return (char*)s; 82 | } 83 | 84 | /* Similar to strncpy, but ensures dest (size bytes) is 85 | NUL-terminated, and doesn't pad with NULs. */ 86 | static char* strncpy0(char* dest, const char* src, size_t size) 87 | { 88 | /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */ 89 | size_t i; 90 | for (i = 0; i < size - 1 && src[i]; i++) 91 | dest[i] = src[i]; 92 | dest[i] = '\0'; 93 | return dest; 94 | } 95 | 96 | /* See documentation in header file. */ 97 | int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, 98 | void* user) 99 | { 100 | /* Uses a fair bit of stack (use heap instead if you need to) */ 101 | #if INI_USE_STACK 102 | char line[INI_MAX_LINE]; 103 | size_t max_line = INI_MAX_LINE; 104 | #else 105 | char* line; 106 | size_t max_line = INI_INITIAL_ALLOC; 107 | #endif 108 | #if INI_ALLOW_REALLOC && !INI_USE_STACK 109 | char* new_line; 110 | size_t offset; 111 | #endif 112 | char section[MAX_SECTION] = ""; 113 | char prev_name[MAX_NAME] = ""; 114 | 115 | char* start; 116 | char* end; 117 | char* name; 118 | char* value; 119 | int lineno = 0; 120 | int error = 0; 121 | 122 | #if !INI_USE_STACK 123 | line = (char*)ini_malloc(INI_INITIAL_ALLOC); 124 | if (!line) { 125 | return -2; 126 | } 127 | #endif 128 | 129 | #if INI_HANDLER_LINENO 130 | #define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) 131 | #else 132 | #define HANDLER(u, s, n, v) handler(u, s, n, v) 133 | #endif 134 | 135 | /* Scan through stream line by line */ 136 | while (reader(line, (int)max_line, stream) != NULL) { 137 | #if INI_ALLOW_REALLOC && !INI_USE_STACK 138 | offset = strlen(line); 139 | while (offset == max_line - 1 && line[offset - 1] != '\n') { 140 | max_line *= 2; 141 | if (max_line > INI_MAX_LINE) 142 | max_line = INI_MAX_LINE; 143 | new_line = ini_realloc(line, max_line); 144 | if (!new_line) { 145 | ini_free(line); 146 | return -2; 147 | } 148 | line = new_line; 149 | if (reader(line + offset, (int)(max_line - offset), stream) == NULL) 150 | break; 151 | if (max_line >= INI_MAX_LINE) 152 | break; 153 | offset += strlen(line + offset); 154 | } 155 | #endif 156 | 157 | lineno++; 158 | 159 | start = line; 160 | #if INI_ALLOW_BOM 161 | if (lineno == 1 && (unsigned char)start[0] == 0xEF && 162 | (unsigned char)start[1] == 0xBB && 163 | (unsigned char)start[2] == 0xBF) { 164 | start += 3; 165 | } 166 | #endif 167 | start = lskip(rstrip(start)); 168 | 169 | if (strchr(INI_START_COMMENT_PREFIXES, *start)) { 170 | /* Start-of-line comment */ 171 | } 172 | #if INI_ALLOW_MULTILINE 173 | else if (*prev_name && *start && start > line) { 174 | #if INI_ALLOW_INLINE_COMMENTS 175 | end = find_chars_or_comment(start, NULL); 176 | if (*end) 177 | *end = '\0'; 178 | rstrip(start); 179 | #endif 180 | /* Non-blank line with leading whitespace, treat as continuation 181 | of previous name's value (as per Python configparser). */ 182 | if (!HANDLER(user, section, prev_name, start) && !error) 183 | error = lineno; 184 | } 185 | #endif 186 | else if (*start == '[') { 187 | /* A "[section]" line */ 188 | end = find_chars_or_comment(start + 1, "]"); 189 | if (*end == ']') { 190 | *end = '\0'; 191 | strncpy0(section, start + 1, sizeof(section)); 192 | *prev_name = '\0'; 193 | #if INI_CALL_HANDLER_ON_NEW_SECTION 194 | if (!HANDLER(user, section, NULL, NULL) && !error) 195 | error = lineno; 196 | #endif 197 | } 198 | else if (!error) { 199 | /* No ']' found on section line */ 200 | error = lineno; 201 | } 202 | } 203 | else if (*start) { 204 | /* Not a comment, must be a name[=:]value pair */ 205 | end = find_chars_or_comment(start, "=:"); 206 | if (*end == '=' || *end == ':') { 207 | *end = '\0'; 208 | name = rstrip(start); 209 | value = end + 1; 210 | #if INI_ALLOW_INLINE_COMMENTS 211 | end = find_chars_or_comment(value, NULL); 212 | if (*end) 213 | *end = '\0'; 214 | #endif 215 | value = lskip(value); 216 | rstrip(value); 217 | 218 | /* Valid name[=:]value pair found, call handler */ 219 | strncpy0(prev_name, name, sizeof(prev_name)); 220 | if (!HANDLER(user, section, name, value) && !error) 221 | error = lineno; 222 | } 223 | else if (!error) { 224 | /* No '=' or ':' found on name[=:]value line */ 225 | #if INI_ALLOW_NO_VALUE 226 | *end = '\0'; 227 | name = rstrip(start); 228 | if (!HANDLER(user, section, name, NULL) && !error) 229 | error = lineno; 230 | #else 231 | error = lineno; 232 | #endif 233 | } 234 | } 235 | 236 | #if INI_STOP_ON_FIRST_ERROR 237 | if (error) 238 | break; 239 | #endif 240 | } 241 | 242 | #if !INI_USE_STACK 243 | ini_free(line); 244 | #endif 245 | 246 | return error; 247 | } 248 | 249 | /* See documentation in header file. */ 250 | int ini_parse_file(FILE* file, ini_handler handler, void* user) 251 | { 252 | return ini_parse_stream((ini_reader)fgets, file, handler, user); 253 | } 254 | 255 | /* See documentation in header file. */ 256 | int ini_parse(const char* filename, ini_handler handler, void* user) 257 | { 258 | FILE* file; 259 | int error; 260 | 261 | file = fopen(filename, "r"); 262 | if (!file) 263 | return -1; 264 | error = ini_parse_file(file, handler, user); 265 | fclose(file); 266 | return error; 267 | } 268 | 269 | /* An ini_reader function to read the next line from a string buffer. This 270 | is the fgets() equivalent used by ini_parse_string(). */ 271 | static char* ini_reader_string(char* str, int num, void* stream) { 272 | ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream; 273 | const char* ctx_ptr = ctx->ptr; 274 | size_t ctx_num_left = ctx->num_left; 275 | char* strp = str; 276 | char c; 277 | 278 | if (ctx_num_left == 0 || num < 2) 279 | return NULL; 280 | 281 | while (num > 1 && ctx_num_left != 0) { 282 | c = *ctx_ptr++; 283 | ctx_num_left--; 284 | *strp++ = c; 285 | if (c == '\n') 286 | break; 287 | num--; 288 | } 289 | 290 | *strp = '\0'; 291 | ctx->ptr = ctx_ptr; 292 | ctx->num_left = ctx_num_left; 293 | return str; 294 | } 295 | 296 | /* See documentation in header file. */ 297 | int ini_parse_string(const char* string, ini_handler handler, void* user) { 298 | ini_parse_string_ctx ctx; 299 | 300 | ctx.ptr = string; 301 | ctx.num_left = strlen(string); 302 | return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, 303 | user); 304 | } 305 | --------------------------------------------------------------------------------