├── .editorconfig ├── .gitattributes ├── resources ├── icon.rc ├── icon.ico ├── icon.png ├── kv6 │ ├── cp.kv6 │ ├── .gitignore │ ├── block.kv6 │ ├── intel.kv6 │ ├── spade.kv6 │ ├── grenade.kv6 │ ├── playerarms.kv6 │ ├── playerdead.kv6 │ ├── playerhead.kv6 │ ├── playerleg.kv6 │ ├── playerlegc.kv6 │ ├── playertorso.kv6 │ ├── semicasing.kv6 │ ├── semitracer.kv6 │ ├── smgcasing.kv6 │ ├── smgtracer.kv6 │ ├── playertorsoc.kv6 │ ├── shotguncasing.kv6 │ └── shotguntracer.kv6 ├── cache │ └── .gitignore ├── logs │ └── .gitignore ├── png │ ├── block.png │ ├── health.png │ ├── intel.png │ ├── player.png │ ├── splash.png │ ├── target.png │ ├── tracer.png │ ├── ui │ │ ├── bg.png │ │ ├── alert.png │ │ ├── arrow.png │ │ ├── flags.png │ │ ├── input.png │ │ ├── join.png │ │ ├── knob.png │ │ ├── ping.png │ │ ├── wait.png │ │ ├── arrow2.png │ │ ├── expanded.png │ │ ├── joystick.png │ │ ├── reload.png │ │ ├── box_check.png │ │ ├── box_empty.png │ │ └── collapsed.png │ ├── white.png │ ├── .gitignore │ ├── command.png │ ├── grenade.png │ ├── medical.png │ ├── semiammo.png │ ├── smgammo.png │ └── shotgunammo.png ├── fonts │ ├── Fixedsys.ttf │ └── Terminal.ttf ├── screenshots │ └── .gitignore ├── wav │ ├── macros_sound.wav │ └── .gitignore └── config.ini ├── docs ├── pic01.png ├── pic02.png ├── pic03.png ├── pic04.png ├── pic05.png ├── pic06.png └── icon_small.png ├── deps └── .gitignore ├── .gitignore ├── src ├── list.h ├── stb_truetype.c ├── http.c ├── rpc.h ├── grenade.h ├── font.h ├── ping.h ├── utils.h ├── entitysystem.h ├── tracer.h ├── main.h ├── particle.h ├── file.h ├── channel.h ├── cameracontroller.h ├── aabb.h ├── weapon.h ├── minheap.h ├── glx.h ├── chunk.h ├── matrix.h ├── map.h ├── hud.h ├── entitysystem.c ├── camera.h ├── model.h ├── tesselator.h ├── list.c ├── config.h ├── utils.c ├── texture.h ├── sound.h ├── window.h ├── matrix.c ├── aabb.c ├── rpc.c ├── common.h ├── minheap.c ├── tracer.c ├── player.h ├── grenade.c ├── ping.c ├── channel.c ├── file.c ├── particle.c ├── font.c ├── model_normals.h ├── CMakeLists.txt ├── glx.c └── sound.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/pic01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/pic01.png -------------------------------------------------------------------------------- /docs/pic02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/pic02.png -------------------------------------------------------------------------------- /docs/pic03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/pic03.png -------------------------------------------------------------------------------- /docs/pic04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/pic04.png -------------------------------------------------------------------------------- /docs/pic05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/pic05.png -------------------------------------------------------------------------------- /docs/pic06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/pic06.png -------------------------------------------------------------------------------- /deps/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /docs/icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/docs/icon_small.png -------------------------------------------------------------------------------- /resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/icon.ico -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/icon.png -------------------------------------------------------------------------------- /resources/kv6/cp.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/cp.kv6 -------------------------------------------------------------------------------- /resources/cache/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/kv6/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/kv6/block.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/block.kv6 -------------------------------------------------------------------------------- /resources/kv6/intel.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/intel.kv6 -------------------------------------------------------------------------------- /resources/kv6/spade.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/spade.kv6 -------------------------------------------------------------------------------- /resources/logs/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/png/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/block.png -------------------------------------------------------------------------------- /resources/png/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/health.png -------------------------------------------------------------------------------- /resources/png/intel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/intel.png -------------------------------------------------------------------------------- /resources/png/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/player.png -------------------------------------------------------------------------------- /resources/png/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/splash.png -------------------------------------------------------------------------------- /resources/png/target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/target.png -------------------------------------------------------------------------------- /resources/png/tracer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/tracer.png -------------------------------------------------------------------------------- /resources/png/ui/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/bg.png -------------------------------------------------------------------------------- /resources/png/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/white.png -------------------------------------------------------------------------------- /resources/kv6/grenade.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/grenade.kv6 -------------------------------------------------------------------------------- /resources/png/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | /*.png 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/png/command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/command.png -------------------------------------------------------------------------------- /resources/png/grenade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/grenade.png -------------------------------------------------------------------------------- /resources/png/medical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/medical.png -------------------------------------------------------------------------------- /resources/png/semiammo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/semiammo.png -------------------------------------------------------------------------------- /resources/png/smgammo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/smgammo.png -------------------------------------------------------------------------------- /resources/png/ui/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/alert.png -------------------------------------------------------------------------------- /resources/png/ui/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/arrow.png -------------------------------------------------------------------------------- /resources/png/ui/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/flags.png -------------------------------------------------------------------------------- /resources/png/ui/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/input.png -------------------------------------------------------------------------------- /resources/png/ui/join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/join.png -------------------------------------------------------------------------------- /resources/png/ui/knob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/knob.png -------------------------------------------------------------------------------- /resources/png/ui/ping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/ping.png -------------------------------------------------------------------------------- /resources/png/ui/wait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/wait.png -------------------------------------------------------------------------------- /resources/fonts/Fixedsys.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/fonts/Fixedsys.ttf -------------------------------------------------------------------------------- /resources/fonts/Terminal.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/fonts/Terminal.ttf -------------------------------------------------------------------------------- /resources/kv6/playerarms.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playerarms.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerdead.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playerdead.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerhead.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playerhead.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerleg.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playerleg.kv6 -------------------------------------------------------------------------------- /resources/kv6/playerlegc.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playerlegc.kv6 -------------------------------------------------------------------------------- /resources/kv6/playertorso.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playertorso.kv6 -------------------------------------------------------------------------------- /resources/kv6/semicasing.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/semicasing.kv6 -------------------------------------------------------------------------------- /resources/kv6/semitracer.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/semitracer.kv6 -------------------------------------------------------------------------------- /resources/kv6/smgcasing.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/smgcasing.kv6 -------------------------------------------------------------------------------- /resources/kv6/smgtracer.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/smgtracer.kv6 -------------------------------------------------------------------------------- /resources/png/shotgunammo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/shotgunammo.png -------------------------------------------------------------------------------- /resources/png/ui/arrow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/arrow2.png -------------------------------------------------------------------------------- /resources/png/ui/expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/expanded.png -------------------------------------------------------------------------------- /resources/png/ui/joystick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/joystick.png -------------------------------------------------------------------------------- /resources/png/ui/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/reload.png -------------------------------------------------------------------------------- /resources/screenshots/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /resources/kv6/playertorsoc.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/playertorsoc.kv6 -------------------------------------------------------------------------------- /resources/kv6/shotguncasing.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/shotguncasing.kv6 -------------------------------------------------------------------------------- /resources/kv6/shotguntracer.kv6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/kv6/shotguntracer.kv6 -------------------------------------------------------------------------------- /resources/png/ui/box_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/box_check.png -------------------------------------------------------------------------------- /resources/png/ui/box_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/box_empty.png -------------------------------------------------------------------------------- /resources/png/ui/collapsed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/png/ui/collapsed.png -------------------------------------------------------------------------------- /resources/wav/macros_sound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/PixSpades/standalone/resources/wav/macros_sound.wav -------------------------------------------------------------------------------- /resources/wav/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | !macros_sound.wav 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | Desktop.ini 3 | /nongithub 4 | /dist 5 | /src/*/ 6 | /src/dr_wav.c 7 | /src/hashtable.c 8 | /src/hashtable.h 9 | /src/http.h 10 | /src/ini.c 11 | /src/ini.h 12 | /src/log.c 13 | /src/log.h 14 | /src/microui.c 15 | /src/microui.h 16 | /src/parson.c 17 | /src/parson.h 18 | /src/stb_truetype.h 19 | /build/*/ 20 | *.lib 21 | *.a 22 | *.o 23 | *.vxl 24 | *.exe 25 | *.zip 26 | *.kv6 27 | *.lib 28 | *.dll 29 | -------------------------------------------------------------------------------- /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, void* ref, enum list_traverse_direction dir, int (*cmp)(void* a, 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/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 | }; 27 | 28 | void font_init(void); 29 | void font_reset(void); 30 | float font_length(float h, char* text); 31 | void font_render(float x, float y, float h, char* text); 32 | void font_centered(float x, float y, float h, char* text); 33 | void font_select(enum font_type type); 34 | 35 | #endif 36 | 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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 float cameracontroller_bodyview_zoom; 26 | 27 | void cameracontroller_death_init(int player, float x, float y, float z); 28 | 29 | void cameracontroller_fps(float dt); 30 | void cameracontroller_spectator(float dt); 31 | void cameracontroller_bodyview(float dt); 32 | void cameracontroller_selection(float dt); 33 | void cameracontroller_death(float dt); 34 | 35 | void cameracontroller_fps_render(void); 36 | void cameracontroller_spectator_render(void); 37 | void cameracontroller_bodyview_render(void); 38 | void cameracontroller_selection_render(void); 39 | void cameracontroller_death_render(void); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /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/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(void); 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 | 50 | -------------------------------------------------------------------------------- /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 | 56 | extern struct hud hud_ingame; 57 | extern struct hud hud_mapload; 58 | extern struct hud hud_serverlist; 59 | extern struct hud hud_settings; 60 | extern struct hud hud_controls; 61 | 62 | extern struct hud* hud_active; 63 | extern struct window_instance* hud_window; 64 | 65 | #define HUD_FLAG_INDEX_START 64 66 | 67 | void hud_change(struct hud* new); 68 | void hud_init(); 69 | void hud_mousemode(int mode); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /resources/config.ini: -------------------------------------------------------------------------------- 1 | 2 | [client] 3 | name = Pixelite 4 | xres = 800 5 | yres = 600 6 | vol = 10 7 | inverty = 0 8 | windowed = 1 9 | language = 0 10 | mouse_sensitivity = 10.000000 11 | show_news = 0 12 | multisamples = 0 13 | greedy_meshing = 0 14 | vsync = 0 15 | show_fps = 0 16 | voxlap_models = 0 17 | force_displaylist = 0 18 | smooth_fog = 0 19 | ambient_occlusion = 0 20 | camera_fov = 100.00000 21 | hold_down_sights = 0 22 | chat_shadow = 1 23 | show_player_arms = 0 24 | send_client_info = 1 25 | auto_gg = 1 26 | toggle_teamname = 1 27 | show_itemname = 1 28 | chat_sounds = 1 29 | macro_sounds = 0 30 | custom_macro = Hello! 31 | custom_macro2 = Cya! 32 | accuracy = /accuracy 33 | deaf = /deaf 34 | kill = /kill 35 | medkit = /medkit 36 | ratio = /ratio 37 | streak = /streak 38 | votekick_cancel = /cancel 39 | votekick_vote_yes = /y 40 | 41 | [controls] 42 | move_forward = 87 43 | move_backward = 83 44 | move_left = 65 45 | move_right = 68 46 | jump = 32 47 | crouch = 341 48 | sneak = 86 49 | sprint = 340 50 | view_map = 77 51 | reload = 82 52 | cube_color_up = 265 53 | cube_color_down = 264 54 | cube_color_left = 263 55 | cube_color_right = 262 56 | cube_color_sample = 69 57 | quit_game = 256 58 | volume_up = 334 59 | volume_down = 333 60 | view_score = 258 61 | change_team = 44 62 | change_weapon = 46 63 | screenshot = 294 64 | fullscreen = 300 65 | chat_global = 84 66 | chat_command = 47 67 | hide_hud = 295 68 | network_stats = 301 69 | last_tool = 81 70 | tool_block = 50 71 | tool_grenade = 52 72 | tool_gun = 51 73 | tool_spade = 49 74 | save_map = 298 75 | key_ratio = 72 76 | key_kill = 71 77 | key_accuracy = 59 78 | key_streak = 74 79 | key_deaf = 66 80 | key_votekick_vote_yes = 76 81 | key_votekick_cancel = 75 82 | key_medkit = 67 83 | key_custom_macro = 78 84 | -------------------------------------------------------------------------------- /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, void* ref, enum list_traverse_direction dir, int (*cmp)(void* obj, 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/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 | char kill[32]; 32 | char ratio[32]; 33 | char accuracy[32]; 34 | char streak[32]; 35 | char deaf[32]; 36 | char votekick_vote_yes[32]; 37 | char votekick_cancel[32]; 38 | char medkit[32]; 39 | char custom_macro[32]; 40 | char custom_macro2[32]; 41 | }; 42 | 43 | extern struct RENDER_OPTIONS { 44 | char name[16]; 45 | int opengl14; 46 | int color_correction; 47 | int shadow_entities; 48 | int ambient_occlusion; 49 | float render_distance; 50 | int window_width; 51 | int window_height; 52 | int multisamples; 53 | int player_arms; 54 | int fullscreen; 55 | int greedy_meshing; 56 | int vsync; 57 | float mouse_sensitivity; 58 | int show_news; 59 | int show_fps; 60 | int volume; 61 | int voxlap_models; 62 | int force_displaylist; 63 | int invert_y; 64 | int smooth_fog; 65 | float camera_fov; 66 | int hold_down_sights; 67 | int chat_shadow; 68 | int send_client_info; 69 | int auto_gg; 70 | char kill[50]; 71 | char ratio[50]; 72 | char accuracy[50]; 73 | char streak[50]; 74 | char deaf[50]; 75 | char votekick_vote_yes[50]; 76 | char votekick_cancel[50]; 77 | char medkit[50]; 78 | char custom_macro[50]; 79 | char custom_macro2[50]; 80 | int toggle_teamname; 81 | int show_itemname; 82 | int chat_sounds; 83 | int macro_sounds; 84 | } settings, settings_tmp; 85 | 86 | extern struct list config_keys; 87 | 88 | struct config_key_pair { 89 | int internal; 90 | int def; 91 | int original; 92 | int toggle; 93 | char name[24]; 94 | char display[24]; 95 | char category[24]; 96 | }; 97 | 98 | enum { 99 | CONFIG_TYPE_STRING, 100 | CONFIG_TYPE_INT, 101 | CONFIG_TYPE_FLOAT, 102 | }; 103 | 104 | struct config_setting { 105 | void* value; 106 | int type; 107 | int min; 108 | int max; 109 | char name[32]; 110 | char help[32]; 111 | int defaults[8]; 112 | int defaults_length; 113 | void (*label_callback)(char* buffer, size_t length, int value, size_t index); 114 | }; 115 | 116 | extern struct list config_settings; 117 | 118 | void config_register_key(int internal, int def, const char* name, int toggle, const char* display, 119 | const char* category); 120 | int config_key_translate(int key, int dir, int* results); 121 | struct config_key_pair* config_key(int key); 122 | void config_key_reset_togglestates(); 123 | void config_reload(void); 124 | void config_save(void); 125 | 126 | #endif 127 | 128 | -------------------------------------------------------------------------------- /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/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_minimap; 31 | extern struct texture texture_gradient; 32 | extern struct texture texture_dummy; 33 | 34 | extern struct texture texture_health; 35 | extern struct texture texture_block; 36 | extern struct texture texture_grenade; 37 | extern struct texture texture_ammo_semi; 38 | extern struct texture texture_ammo_smg; 39 | extern struct texture texture_ammo_shotgun; 40 | 41 | extern struct texture texture_color_selection; 42 | 43 | extern struct texture texture_zoom_semi; 44 | extern struct texture texture_zoom_smg; 45 | extern struct texture texture_zoom_shotgun; 46 | 47 | extern struct texture texture_white; 48 | extern struct texture texture_target; 49 | extern struct texture texture_indicator; 50 | 51 | extern struct texture texture_player; 52 | extern struct texture texture_medical; 53 | extern struct texture texture_intel; 54 | extern struct texture texture_command; 55 | extern struct texture texture_tracer; 56 | 57 | extern struct texture texture_ui_wait; 58 | extern struct texture texture_ui_join; 59 | extern struct texture texture_ui_reload; 60 | extern struct texture texture_ui_bg; 61 | extern struct texture texture_ui_input; 62 | extern struct texture texture_ui_box_empty; 63 | extern struct texture texture_ui_box_check; 64 | extern struct texture texture_ui_expanded; 65 | extern struct texture texture_ui_collapsed; 66 | extern struct texture texture_ui_flags; 67 | extern struct texture texture_ui_alert; 68 | extern struct texture texture_ui_joystick; 69 | extern struct texture texture_ui_knob; 70 | 71 | #define TEXTURE_FILTER_NEAREST 0 72 | #define TEXTURE_FILTER_LINEAR 1 73 | 74 | int texture_flag_index(const char* country); 75 | void texture_flag_offset(int index, float* u, float* v); 76 | void texture_filter(struct texture* t, int filter); 77 | void texture_init(void); 78 | int texture_create(struct texture* t, char* filename); 79 | int texture_create_buffer(struct texture* t, int width, int height, unsigned char* buff, int new); 80 | void texture_delete(struct texture* t); 81 | void texture_draw(struct texture* t, float x, float y, float w, float h); 82 | void texture_draw_sector(struct texture* t, float x, float y, float w, float h, float u, float v, float us, float vs); 83 | void texture_draw_empty(float x, float y, float w, float h); 84 | void texture_draw_empty_rotated(float x, float y, float w, float h, float angle); 85 | void texture_draw_rotated(struct texture* t, float x, float y, float w, float h, float angle); 86 | void texture_resize_pow2(struct texture* t, int min_size); 87 | unsigned int texture_block_color(int x, int y); 88 | void texture_gradient_fog(unsigned int* gradient); 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /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_switch; 94 | extern struct Sound_wav sound_empty; 95 | extern struct Sound_wav sound_intro; 96 | 97 | extern struct Sound_wav sound_debris; 98 | extern struct Sound_wav sound_bounce; 99 | extern struct Sound_wav sound_impact; 100 | extern struct Sound_wav sound_macros; 101 | extern struct Sound_wav sound_chat; 102 | 103 | void sound_volume(float vol); 104 | void sound_create_sticky(struct Sound_wav* w, struct Player* player, int player_id); 105 | void sound_create(enum sound_space option, struct Sound_wav* w, float x, float y, float z); 106 | void sound_update(void); 107 | void sound_load(struct Sound_wav* wav, char* name, float min, float max); 108 | void sound_init(void); 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /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_KILL, 91 | WINDOW_KEY_RATIO, 92 | WINDOW_KEY_ACCURACY, 93 | WINDOW_KEY_STREAK, 94 | WINDOW_KEY_DEAF, 95 | WINDOW_KEY_VOTEKICK_YES, 96 | WINDOW_KEY_VOTEKICK_CANCEL, 97 | WINDOW_KEY_MEDKIT, 98 | WINDOW_KEY_CUSTOM_MACRO, 99 | WINDOW_KEY_CUSTOM_MACRO2, 100 | }; 101 | 102 | enum { 103 | WINDOW_CURSOR_DISABLED, 104 | WINDOW_CURSOR_ENABLED, 105 | }; 106 | 107 | enum window_buttons { 108 | WINDOW_MOUSE_LMB, 109 | WINDOW_MOUSE_MMB, 110 | WINDOW_MOUSE_RMB, 111 | }; 112 | 113 | struct window_finger { 114 | #ifdef USE_SDL 115 | SDL_FingerID finger; 116 | #else 117 | int finger; 118 | #endif 119 | float down_time; 120 | int full; 121 | struct { 122 | float x, y; 123 | } start; 124 | }; 125 | 126 | extern int window_pressed_keys[64]; 127 | 128 | #define WINDOW_NOMOUSELOC -1 129 | 130 | void window_textinput(int allow); 131 | float window_time(void); 132 | void window_keyname(int keycode, char* output, size_t length); 133 | const char* window_clipboard(void); 134 | int window_key_down(int key); 135 | void window_mousemode(int mode); 136 | void window_mouseloc(double* x, double* y); 137 | void window_setmouseloc(double x, double y); 138 | void window_swapping(int value); 139 | void window_init(void); 140 | void window_fromsettings(void); 141 | void window_deinit(void); 142 | void window_update(void); 143 | int window_closed(void); 144 | int window_cpucores(); 145 | void window_title(char* suffix); 146 | 147 | #endif 148 | 149 | -------------------------------------------------------------------------------- /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 "config.h" 30 | #include "rpc.h" 31 | 32 | struct rpc { 33 | int needs_update; 34 | int players; 35 | int slots; 36 | char server_url[64]; 37 | char server_name[64]; 38 | } rpc_state; 39 | 40 | #ifdef USE_RPC 41 | static void rpc_joingame(const char* joinSecret) { 42 | log_info("discord join %s!", joinSecret); 43 | } 44 | 45 | static void rpc_joinrequest(const DiscordUser* request) { 46 | Discord_Respond(request->userId, DISCORD_REPLY_YES); 47 | } 48 | #endif 49 | 50 | void rpc_init() { 51 | #ifdef USE_RPC 52 | DiscordEventHandlers handlers; 53 | memset(&handlers, 0, sizeof(handlers)); 54 | handlers.joinGame = rpc_joingame; 55 | handlers.joinRequest = rpc_joinrequest; 56 | Discord_Initialize("DISCORD TOKEN HERE", &handlers, 1, NULL); 57 | #endif 58 | rpc_state.needs_update = 1; 59 | rpc_state.players = 0; 60 | rpc_state.slots = 0; 61 | *rpc_state.server_url = 0; 62 | *rpc_state.server_name = 0; 63 | } 64 | 65 | void rpc_deinit() { 66 | #ifdef USE_RPC 67 | Discord_Shutdown(); 68 | #endif 69 | } 70 | 71 | void rpc_setv(enum RPC_VALUE v, char* x) { 72 | switch(v) { 73 | case RPC_VALUE_SERVERNAME: 74 | if(strcmp(rpc_state.server_name, x) != 0) { 75 | strncpy(rpc_state.server_name, x, sizeof(rpc_state.server_name) - 1); 76 | rpc_state.needs_update = 1; 77 | } 78 | break; 79 | case RPC_VALUE_SERVERURL: 80 | if(strcmp(rpc_state.server_url, x) != 0) { 81 | strncpy(rpc_state.server_url, x, sizeof(rpc_state.server_url) - 1); 82 | rpc_state.needs_update = 1; 83 | } 84 | break; 85 | } 86 | } 87 | 88 | void rpc_seti(enum RPC_VALUE v, int x) { 89 | switch(v) { 90 | case RPC_VALUE_PLAYERS: 91 | if(rpc_state.players != x) { 92 | rpc_state.players = x; 93 | rpc_state.needs_update = 1; 94 | } 95 | break; 96 | case RPC_VALUE_SLOTS: 97 | if(rpc_state.slots != x) { 98 | rpc_state.slots = x; 99 | rpc_state.needs_update = 1; 100 | } 101 | break; 102 | } 103 | } 104 | 105 | void rpc_update() { 106 | #ifdef USE_RPC 107 | 108 | int online = 0; 109 | for(int k = 0; k < PLAYERS_MAX; k++) { 110 | if(players[k].connected) 111 | online++; 112 | } 113 | rpc_seti(RPC_VALUE_PLAYERS, online); 114 | 115 | if(rpc_state.needs_update) { 116 | DiscordRichPresence discordPresence; 117 | memset(&discordPresence, 0, sizeof(discordPresence)); 118 | char nick_server[128]; 119 | sprintf(nick_server, "Server: %s Nick: %s", rpc_state.server_name, settings.name); 120 | discordPresence.largeImageKey = "pic03"; 121 | discordPresence.smallImageKey = "logo"; 122 | discordPresence.largeImageText = settings.name; 123 | discordPresence.smallImageText = "BetterSpades" BETTERSPADES_VERSION; 124 | discordPresence.instance = 1; 125 | if(rpc_state.slots > 0) { 126 | discordPresence.state = "Playing"; 127 | discordPresence.partyId = "42"; 128 | discordPresence.partySize = max(rpc_state.players, 1); 129 | discordPresence.partyMax = rpc_state.slots; 130 | discordPresence.details = nick_server; 131 | discordPresence.joinSecret = rpc_state.server_url; 132 | } else { 133 | discordPresence.state = "Waiting"; 134 | } 135 | Discord_UpdatePresence(&discordPresence); 136 | rpc_state.needs_update = 0; 137 | } 138 | 139 | Discord_RunCallbacks(); 140 | #endif 141 | } 142 | 143 | -------------------------------------------------------------------------------- /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[2][10][256]; 107 | extern unsigned int chat_color[2][10]; 108 | extern float chat_timer[2][10]; 109 | extern char chat_popup[256]; 110 | extern float chat_popup_timer; 111 | extern float chat_popup_duration; 112 | extern int chat_popup_color; 113 | void chat_add(int channel, unsigned int color, const char* msg); 114 | void chat_showpopup(const char* msg, float duration, int color); 115 | const char* reason_disconnect(int code); 116 | 117 | #define SCREEN_NONE 0 118 | #define SCREEN_TEAM_SELECT 1 119 | #define SCREEN_GUN_SELECT 2 120 | 121 | extern int ms_seed; 122 | int ms_rand(void); 123 | 124 | #include 125 | #include "log.h" 126 | 127 | #define CHECK_ALLOCATION_ERROR(ret) \ 128 | if(!ret) { \ 129 | log_fatal("Critical error: memory allocation failed (%s:%d)", __func__, __LINE__); \ 130 | exit(1); \ 131 | } 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /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/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/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 | int player_can_spectate(struct Player* p); 167 | float player_section_height(int section); 168 | void player_init(void); 169 | float player_height(const struct Player* p); 170 | float player_height2(const struct Player* p); 171 | void player_reposition(struct Player* p); 172 | void player_update(float dt, int locked); 173 | void player_render_all(void); 174 | void player_render(struct Player* p, int id); 175 | void player_collision(const struct Player* p, Ray* ray, struct player_intersection* intersects); 176 | void player_reset(struct Player* p); 177 | int player_move(struct Player* p, float fsynctics, int id); 178 | int player_uncrouch(struct Player* p); 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /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/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 | ping_lan(); 95 | float ping_start = window_time(); 96 | 97 | HashTable pings; 98 | ht_setup(&pings, sizeof(uint64_t), sizeof(struct ping_entry), 64); 99 | 100 | while(1) { 101 | size_t drain = channel_size(&ping_queue); 102 | for(size_t k = 0; (k < drain) || (!pings.size && window_time() - ping_start >= 8.0F); k++) { 103 | struct ping_entry entry; 104 | channel_await(&ping_queue, &entry); 105 | 106 | uint64_t ID = IP_KEY(entry.addr); 107 | ht_insert(&pings, &ID, &entry); 108 | } 109 | 110 | char tmp[512]; 111 | ENetAddress from; 112 | 113 | ENetBuffer buf = { 114 | .data = tmp, 115 | .dataLength = sizeof(tmp), 116 | }; 117 | 118 | while(1) { 119 | int recvLength = enet_socket_receive(sock, &from, &buf, 1); 120 | uint64_t ID = IP_KEY(from); 121 | 122 | if(recvLength != 0) { 123 | struct ping_entry* entry = ht_lookup(&pings, &ID); 124 | 125 | if(entry) { 126 | if(recvLength > 0) { // received something! 127 | if(!strncmp(buf.data, "HI", recvLength)) { 128 | ping_result(NULL, window_time() - entry->time_start, entry->aos); 129 | ht_erase(&pings, &ID); 130 | } else { 131 | entry->trycount++; 132 | } 133 | } else { // connection was closed 134 | ht_erase(&pings, &ID); 135 | } 136 | } 137 | } else { // would block 138 | break; 139 | } 140 | } 141 | 142 | ht_iterate_remove(&pings, NULL, pings_retry); 143 | 144 | int length = enet_socket_receive(lan, &from, &buf, 1); 145 | if(length) { 146 | JSON_Value* js = json_parse_string(buf.data); 147 | if(js) { 148 | JSON_Object* root = json_value_get_object(js); 149 | 150 | struct serverlist_entry e; 151 | 152 | strcpy(e.country, "LAN"); 153 | e.ping = ceil((window_time() - ping_start) * 1000.0F); 154 | snprintf(e.identifier, sizeof(e.identifier) - 1, "aos://%u:%u", from.host, from.port); 155 | 156 | strncpy(e.name, json_object_get_string(root, "name"), sizeof(e.name) - 1); 157 | e.name[sizeof(e.name) - 1] = 0; 158 | strncpy(e.gamemode, json_object_get_string(root, "game_mode"), sizeof(e.gamemode) - 1); 159 | e.gamemode[sizeof(e.gamemode) - 1] = 0; 160 | strncpy(e.map, json_object_get_string(root, "map"), sizeof(e.map) - 1); 161 | e.map[sizeof(e.map) - 1] = 0; 162 | e.current = json_object_get_number(root, "players_current"); 163 | e.max = json_object_get_number(root, "players_max"); 164 | ping_result(&e, window_time() - ping_start, NULL); 165 | 166 | json_value_free(js); 167 | } 168 | } 169 | 170 | usleep(1000); 171 | } 172 | } 173 | 174 | void ping_check(char* addr, int port, char* aos) { 175 | struct ping_entry entry = { 176 | .trycount = 0, 177 | .addr.port = port, 178 | .time_start = window_time(), 179 | }; 180 | 181 | strncpy(entry.aos, aos, sizeof(entry.aos) - 1); 182 | entry.aos[sizeof(entry.aos) - 1] = 0; 183 | 184 | enet_address_set_host(&entry.addr, addr); 185 | 186 | channel_put(&ping_queue, &entry); 187 | 188 | enet_socket_send(sock, &entry.addr, &(ENetBuffer) {.data = "HELLO", .dataLength = 5}, 1); 189 | } 190 | 191 | void ping_start(void (*result)(void*, float, char*)) { 192 | ping_stop(); 193 | 194 | ping_result = result; 195 | } 196 | 197 | void ping_stop() { 198 | channel_clear(&ping_queue); 199 | } 200 | -------------------------------------------------------------------------------- /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/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 | 40 | static HashTable fonts_backed; 41 | 42 | struct __attribute__((packed)) font_backed_id { 43 | enum font_type type; 44 | float size; 45 | }; 46 | 47 | struct font_backed_data { 48 | stbtt_bakedchar* cdata; 49 | GLuint texture_id; 50 | int w, h; 51 | }; 52 | 53 | void font_init() { 54 | font_vertex_buffer = malloc(512 * 8 * sizeof(short)); 55 | CHECK_ALLOCATION_ERROR(font_vertex_buffer) 56 | font_coords_buffer = malloc(512 * 8 * sizeof(short)); 57 | CHECK_ALLOCATION_ERROR(font_coords_buffer) 58 | 59 | font_data_fixedsys = file_load("fonts/Fixedsys.ttf"); 60 | CHECK_ALLOCATION_ERROR(font_data_fixedsys) 61 | font_data_smallfnt = file_load("fonts/Terminal.ttf"); 62 | CHECK_ALLOCATION_ERROR(font_data_smallfnt) 63 | 64 | ht_setup(&fonts_backed, sizeof(struct font_backed_id), sizeof(struct font_backed_data), 8); 65 | } 66 | 67 | void font_select(enum font_type type) { 68 | font_current_type = type; 69 | } 70 | 71 | static struct font_backed_data* font_find(float h) { 72 | if(font_current_type == FONT_SMALLFNT) 73 | h *= 1.5F; 74 | 75 | struct font_backed_id id = (struct font_backed_id) { 76 | .type = font_current_type, 77 | .size = h, 78 | }; 79 | 80 | struct font_backed_data* f_cached = ht_lookup(&fonts_backed, &id); 81 | 82 | if(f_cached) 83 | return f_cached; 84 | 85 | void* file; 86 | switch(font_current_type) { 87 | case FONT_FIXEDSYS: file = font_data_fixedsys; break; 88 | case FONT_SMALLFNT: file = font_data_smallfnt; break; 89 | default: return NULL; 90 | } 91 | 92 | struct font_backed_data f; 93 | f.w = 64; 94 | f.h = 64; 95 | f.cdata = malloc((0xFF - FONT_BAKE_START) * sizeof(stbtt_bakedchar)); 96 | CHECK_ALLOCATION_ERROR(f.cdata) 97 | 98 | void* temp_bitmap = NULL; 99 | 100 | int max_size = 0; 101 | glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); 102 | 103 | while(1) { 104 | temp_bitmap = realloc(temp_bitmap, f.w * f.h); 105 | CHECK_ALLOCATION_ERROR(temp_bitmap) 106 | int res = 0; 107 | res = stbtt_BakeFontBitmap(file, 0, h, temp_bitmap, f.w, f.h, FONT_BAKE_START, 0xFF - FONT_BAKE_START, f.cdata); 108 | if(res > 0 || (f.w == max_size && f.h == max_size)) 109 | break; 110 | if(f.h > f.w) 111 | f.w *= 2; 112 | else 113 | f.h *= 2; 114 | } 115 | 116 | log_info("font texsize: %i:%ipx [size %f] type: %i", f.w, f.h, h, font_current_type); 117 | 118 | glGenTextures(1, &f.texture_id); 119 | glBindTexture(GL_TEXTURE_2D, f.texture_id); 120 | glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, f.w, f.h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); 121 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 122 | glBindTexture(GL_TEXTURE_2D, 0); 123 | 124 | free(temp_bitmap); 125 | 126 | ht_insert(&fonts_backed, &id, &f); 127 | 128 | return ht_lookup(&fonts_backed, &id); 129 | } 130 | 131 | float font_length(float h, char* text) { 132 | struct font_backed_data* font = font_find(h); 133 | 134 | if(!font) 135 | return 0.0F; 136 | 137 | stbtt_aligned_quad q; 138 | float y = h * 0.75F; 139 | float x = 0.0F; 140 | float length = 0.0F; 141 | for(size_t k = 0; k < strlen(text); k++) { 142 | if(text[k] == '\n') { 143 | length = fmax(length, x); 144 | x = 0.0F; 145 | } 146 | 147 | if(text[k] >= FONT_BAKE_START) 148 | stbtt_GetBakedQuad(font->cdata, font->w, font->h, text[k] - FONT_BAKE_START, &x, &y, &q, 1); 149 | } 150 | 151 | return fmax(length, x) + h * 0.125F; 152 | } 153 | 154 | bool font_remove_callback(void* key, void* value, void* user) { 155 | struct font_backed_data* f = (struct font_backed_data*)value; 156 | 157 | glDeleteTextures(1, &f->texture_id); 158 | free(f->cdata); 159 | 160 | return true; 161 | } 162 | 163 | void font_reset() { 164 | ht_iterate_remove(&fonts_backed, NULL, font_remove_callback); 165 | } 166 | 167 | void font_render(float x, float y, float h, char* text) { 168 | struct font_backed_data* font = font_find(h); 169 | 170 | if(!font) 171 | return; 172 | 173 | size_t k = 0; 174 | float x2 = x; 175 | float y2 = h * 0.75F; 176 | while(*text) { 177 | if(*text == '\n') { 178 | x2 = x; 179 | y2 += h; 180 | } 181 | 182 | if(*text >= FONT_BAKE_START) { 183 | stbtt_aligned_quad q; 184 | stbtt_GetBakedQuad(font->cdata, font->w, font->h, *text - FONT_BAKE_START, &x2, &y2, &q, 1); 185 | font_coords_buffer[k + 0] = q.s0 * 8192.0F; 186 | font_coords_buffer[k + 1] = q.t1 * 8192.0F; 187 | font_coords_buffer[k + 2] = q.s1 * 8192.0F; 188 | font_coords_buffer[k + 3] = q.t1 * 8192.0F; 189 | font_coords_buffer[k + 4] = q.s1 * 8192.0F; 190 | font_coords_buffer[k + 5] = q.t0 * 8192.0F; 191 | 192 | font_coords_buffer[k + 6] = q.s0 * 8192.0F; 193 | font_coords_buffer[k + 7] = q.t1 * 8192.0F; 194 | font_coords_buffer[k + 8] = q.s1 * 8192.0F; 195 | font_coords_buffer[k + 9] = q.t0 * 8192.0F; 196 | font_coords_buffer[k + 10] = q.s0 * 8192.0F; 197 | font_coords_buffer[k + 11] = q.t0 * 8192.0F; 198 | 199 | font_vertex_buffer[k + 0] = q.x0; 200 | font_vertex_buffer[k + 1] = -q.y1 + y; 201 | font_vertex_buffer[k + 2] = q.x1; 202 | font_vertex_buffer[k + 3] = -q.y1 + y; 203 | font_vertex_buffer[k + 4] = q.x1; 204 | font_vertex_buffer[k + 5] = -q.y0 + y; 205 | 206 | font_vertex_buffer[k + 6] = q.x0; 207 | font_vertex_buffer[k + 7] = -q.y1 + y; 208 | font_vertex_buffer[k + 8] = q.x1; 209 | font_vertex_buffer[k + 9] = -q.y0 + y; 210 | font_vertex_buffer[k + 10] = q.x0; 211 | font_vertex_buffer[k + 11] = -q.y0 + y; 212 | k += 12; 213 | } 214 | 215 | text++; 216 | } 217 | 218 | glMatrixMode(GL_TEXTURE); 219 | glLoadIdentity(); 220 | glScalef(1.0F / 8192.0F, 1.0F / 8192.0F, 1.0F); 221 | glMatrixMode(GL_MODELVIEW); 222 | 223 | glEnable(GL_TEXTURE_2D); 224 | glBindTexture(GL_TEXTURE_2D, font->texture_id); 225 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 226 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 227 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 228 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 229 | glEnable(GL_BLEND); 230 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 231 | 232 | glEnableClientState(GL_VERTEX_ARRAY); 233 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 234 | glVertexPointer(2, GL_SHORT, 0, font_vertex_buffer); 235 | glTexCoordPointer(2, GL_SHORT, 0, font_coords_buffer); 236 | glDrawArrays(GL_TRIANGLES, 0, k / 2); 237 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 238 | glDisableClientState(GL_VERTEX_ARRAY); 239 | 240 | glDisable(GL_BLEND); 241 | glBindTexture(GL_TEXTURE_2D, 0); 242 | glDisable(GL_TEXTURE_2D); 243 | 244 | glMatrixMode(GL_TEXTURE); 245 | glLoadIdentity(); 246 | glMatrixMode(GL_MODELVIEW); 247 | } 248 | 249 | void font_centered(float x, float y, float h, char* text) { 250 | font_render(x - font_length(h, text) / 2.0F, y, h, text); 251 | } 252 | 253 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GPL](https://img.shields.io/badge/license-GPL--3.0-red.svg)](https://github.com/xtreme8000/BetterSpades/blob/standalone/LICENSE) 2 | [![Discord](https://img.shields.io/badge/discord-join-ff00ff.svg)](https://discord.gg/tZuPt568Dp) 3 | 4 | ## ![](docs/icon_small.png) PixSpades 5 | 6 | * Fork of the game *BetterSpades* (A replicate of classic Voxlap) - See fork differences below 7 | * Has additions and improvements not in BetterSpades 8 | * Runs on very old systems back to OpenGL 1.1 (OpenGL ES support too) 9 | * Shares similar if not even better performance to Voxlap 10 | * Can run on *"embedded"* systems like a [Steam Link](https://store.steampowered.com/app/353380/Steam_Link/) 11 | 12 | ### Differences in this fork 13 | * Many bug fixes not in BetterSpades 14 | * Better default settings than BetterSpades 15 | * Toggleable client spoofing 16 | * Customizable macros (Defaults: /medkit, /deaf, /kill, /ratio, /accuracy, /streak, /cancel, /y and two customizable macros!) 17 | * Toggleable Auto GG (The client says GG for you automatically when a team wins) 18 | * Improved networkstats popup (No border, is smaller and shows you your ping and FPS) 19 | * Toggleable chat and macro sounds 20 | * Improved scoreboard with weapon names beside players ([RIF] = Rifle, [SMG] = Sub Machine Gun, [SHO] = Shotgun) 21 | * Toggleable team names 22 | * Improved user interface 23 | * Different branding from BetterSpades 24 | * Show the name of the item you're holding when you're sprinting to prevent confusion (Toggleable - Only shows tools, not guns) 25 | * Many small improvements to the game such as longer chat history, bigger fonts sizes for things that were too small etc. 26 | * Improved the player name indicator when in spectator mode 27 | * Show the '[Player]'s [Body Part]' text even when you're looking at an enemy, now you won't be confused about who's who! 28 | * Popup messages are smaller and lower on the screen and don't last as long 29 | * Bullet spread and recoil are the same as the spread and recoil in OpenSpades, balance for the win! 30 | * The tent refills your clip and magazine, so no reloading needed when you go to a tent! 31 | * When in spectator mode players don't fade into fog, so it's much easier to see them now 32 | * Other additional settings! 33 | * Always kept up to date with the main BetterSpades repository 34 | * **And more!** 35 | 36 | #### Why should I use this instead of ...? 37 | 38 | * Free of any Jagex code, they can't shut it down 39 | * Open for future expansion 40 | * Easy to use 41 | * No hidden bugs 42 | * Custom features not in BetterSpades, Voxlap or OpenSpades 43 | 44 | ### Quick usage guide 45 | 46 | You can either: 47 | * Use the client temporarily by extracting the downloaded zip into a new directory 48 | * Extract all contents to your current Ace of Spades installation directory (normally found at `C:/Ace of Spades/`), effectively replacing the old voxlap version 49 | 50 | ## System requirements 51 | 52 | | Type | min. requirement | 53 | | ------- | ---------------------------------------------------- | 54 | | OS | Windows 98 or Linux | 55 | | CPU | 1 GHz single core processor | 56 | | GPU | 64MB VRAM, Mobile Intel 945GM or equivalent | 57 | | RAM | 256MB | 58 | | Display | 800x600px | 59 | | Others | Keyboard and mouse
Dial up network connection | 60 | 61 | 62 | ## Build requirements 63 | 64 | This project uses the following libraries and files: 65 | 66 | | Name | License | Usage | GitHub | 67 | | ------------ | --------------- | ---------------------- | :------------------------------------------------: | 68 | | GLFW3 | *ZLib* | OpenGL context | [Link](https://github.com/glfw/glfw) | 69 | | OpenAL soft | *LGPL-2.1* | 3D sound environment | [Link](https://github.com/kcat/openal-soft) | 70 | | inih | *BSD-3.Clause* | .INI file parser | [Link](https://github.com/benhoyt/inih) | 71 | | stb_truetype | *Public domain* | TrueType font renderer | [Link](https://github.com/nothings/stb) | 72 | | dr_wav | *Public domain* | wav support | [Link](https://github.com/mackron/dr_libs/) | 73 | | http | *Public domain* | http client library | [Link](https://github.com/mattiasgustavsson/libs) | 74 | | LodePNG | *MIT* | png support | [Link](https://github.com/lvandeve/lodepng) | 75 | | libdeflate | *MIT* | decompression of maps | [Link](https://github.com/ebiggers/libdeflate) | 76 | | enet | *MIT* | networking library | [Link](https://github.com/lsalzman/enet) | 77 | | parson | *MIT* | JSON parser | [Link](https://github.com/kgabis/parson) | 78 | | log.c | *MIT* | logger | [Link](https://github.com/xtreme8000/log.c) | 79 | | GLEW | *MIT* | OpenGL extensions | [Link](https://github.com/nigels-com/glew) | 80 | | hashtable | *MIT* | hashtable | [Link](https://github.com/goldsborough/hashtable/) | 81 | | libvxl | *MIT* | access VXL format | [Link](https://github.com/xtreme8000/libvxl/) | 82 | | microui | *MIT* | user interface | [Link](https://github.com/rxi/microui) | 83 | 84 | You will need to compile the following by yourself, or get hold of precompiled binaries: 85 | 86 | * GLFW3 87 | * GLEW 88 | * OpenAL soft *(only needed on Windows)* 89 | * libdeflate 90 | * enet 91 | 92 | Follow the instructions on their project page, then place produced static libraries in `deps/`. 93 | 94 | 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. 95 | 96 | #### Windows 97 | 98 | 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: 99 | ``` 100 | cmake -G "MinGW Makefiles" .. 101 | mingw32-make 102 | ``` 103 | 104 | If everything went well, the client should be in the `build/BetterSpades/` subfolder. 105 | 106 | When starting `client.exe`, you will be greeted by a server list. Select a server on it to start playing! 107 | 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: 108 | 109 | ``` 110 | client.exe -aos://16777343:32887 //Connects to a local server 111 | ``` 112 | 113 | #### Linux 114 | 115 | Compilation now works the same on Linux. Just change the build system to `Unix Makefiles` or leaving it as default will work too (`cmake ..`). 116 | 117 | You can build each library yourself, or install them with your distro's package manager: 118 | ``` 119 | sudo apt install libgl1-mesa libgl1-mesa-dev libopenal1 libopenal-dev libglfw-dev libenet-dev libglew-dev 120 | ``` 121 | (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) 122 | 123 | Start the client e.g. with the following inside the `build/bin/` directory: 124 | ``` 125 | ./client 126 | ``` 127 | Or connect directly to localhost: 128 | ``` 129 | ./client -aos://16777343:32887 130 | ``` 131 | 132 | 133 | #### macOS 134 | 135 | The same instructions for Linux work on macOS aside from some minor differences. First, use Homebrew or MacPorts to grab dependencies: 136 | ``` 137 | brew install glfw enet 138 | ``` 139 | 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. 140 | 141 | ## Bug reports 142 | Bug reports should generally go to the original [BetterSpades repository](https://github.com/xtreme8000/BetterSpades/issues) unless the bug applies specifically to PixSpades. 143 | 144 | ## Licensing 145 | Please see the file named LICENSE. 146 | 147 | ## Gallery 148 | 149 | |
*quite old* |
hiesville | | 150 | | :-: | :-: | :-: | 151 | |
*grenade fun* |
*falling block animation* |
*sniping on normandie* | 152 | -------------------------------------------------------------------------------- /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 | FetchContent_MakeAvailable(cglm) 12 | 13 | FetchContent_Declare( 14 | vxl 15 | GIT_REPOSITORY https://github.com/xtreme8000/libvxl 16 | GIT_TAG origin/master 17 | ) 18 | 19 | FetchContent_MakeAvailable(vxl) 20 | 21 | macro(download_file_if_it_doesnt_exist filename url) 22 | if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) 23 | message(STATUS "Downloading ${filename}") 24 | file(DOWNLOAD ${url} ${CMAKE_CURRENT_SOURCE_DIR}/${filename} STATUS stat) 25 | list(GET stat 0 success) 26 | list(GET stat 1 error) 27 | if (NOT ${success}) 28 | message(STATUS "Downloaded ${filename} successfully") 29 | else() 30 | file(REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) 31 | message(FATAL_ERROR "Failed to download ${filename} (${error})") 32 | endif() 33 | endif() 34 | endmacro(download_file_if_it_doesnt_exist) 35 | 36 | download_file_if_it_doesnt_exist(ini.c https://raw.githubusercontent.com/benhoyt/inih/master/ini.c) 37 | download_file_if_it_doesnt_exist(ini.h https://raw.githubusercontent.com/benhoyt/inih/master/ini.h) 38 | download_file_if_it_doesnt_exist(lodepng/lodepng.c https://raw.githubusercontent.com/lvandeve/lodepng/master/lodepng.cpp) 39 | download_file_if_it_doesnt_exist(lodepng/lodepng.h https://raw.githubusercontent.com/lvandeve/lodepng/master/lodepng.h) 40 | download_file_if_it_doesnt_exist(dr_wav.c https://raw.githubusercontent.com/mackron/dr_libs/14707e8ee5aec7620781bcc3b484b8b1607aba50/dr_wav.h) 41 | download_file_if_it_doesnt_exist(stb_truetype.h https://raw.githubusercontent.com/nothings/stb/master/stb_truetype.h) 42 | download_file_if_it_doesnt_exist(parson.c https://raw.githubusercontent.com/kgabis/parson/master/parson.c) 43 | download_file_if_it_doesnt_exist(parson.h https://raw.githubusercontent.com/kgabis/parson/master/parson.h) 44 | download_file_if_it_doesnt_exist(http.h https://raw.githubusercontent.com/mattiasgustavsson/libs/main/http.h) 45 | download_file_if_it_doesnt_exist(log.h https://raw.githubusercontent.com/xtreme8000/log.c/master/src/log.h) 46 | download_file_if_it_doesnt_exist(log.c https://raw.githubusercontent.com/xtreme8000/log.c/master/src/log.c) 47 | download_file_if_it_doesnt_exist(hashtable.c https://raw.githubusercontent.com/goldsborough/hashtable/master/hashtable.c) 48 | download_file_if_it_doesnt_exist(hashtable.h https://raw.githubusercontent.com/goldsborough/hashtable/master/hashtable.h) 49 | download_file_if_it_doesnt_exist(../deps/libdeflate.h https://raw.githubusercontent.com/ebiggers/libdeflate/master/libdeflate.h) 50 | download_file_if_it_doesnt_exist(../bsresources.zip http://aos.party/bsresources.zip) 51 | download_file_if_it_doesnt_exist(microui.c https://raw.githubusercontent.com/rxi/microui/master/src/microui.c) 52 | download_file_if_it_doesnt_exist(microui.h https://raw.githubusercontent.com/rxi/microui/master/src/microui.h) 53 | 54 | list(APPEND CLIENT_SOURCES aabb.c) 55 | list(APPEND CLIENT_SOURCES camera.c) 56 | list(APPEND CLIENT_SOURCES cameracontroller.c) 57 | list(APPEND CLIENT_SOURCES chunk.c) 58 | list(APPEND CLIENT_SOURCES config.c) 59 | list(APPEND CLIENT_SOURCES dr_wav.c) 60 | list(APPEND CLIENT_SOURCES file.c) 61 | list(APPEND CLIENT_SOURCES font.c) 62 | list(APPEND CLIENT_SOURCES glx.c) 63 | list(APPEND CLIENT_SOURCES grenade.c) 64 | list(APPEND CLIENT_SOURCES http.c) 65 | list(APPEND CLIENT_SOURCES hud.c) 66 | list(APPEND CLIENT_SOURCES ini.c) 67 | list(APPEND CLIENT_SOURCES list.c) 68 | list(APPEND CLIENT_SOURCES main.c) 69 | list(APPEND CLIENT_SOURCES map.c) 70 | list(APPEND CLIENT_SOURCES matrix.c) 71 | list(APPEND CLIENT_SOURCES model.c) 72 | list(APPEND CLIENT_SOURCES network.c) 73 | list(APPEND CLIENT_SOURCES parson.c) 74 | list(APPEND CLIENT_SOURCES particle.c) 75 | list(APPEND CLIENT_SOURCES player.c) 76 | list(APPEND CLIENT_SOURCES sound.c) 77 | list(APPEND CLIENT_SOURCES stb_truetype.c) 78 | list(APPEND CLIENT_SOURCES texture.c) 79 | list(APPEND CLIENT_SOURCES tracer.c) 80 | list(APPEND CLIENT_SOURCES weapon.c) 81 | list(APPEND CLIENT_SOURCES window.c) 82 | list(APPEND CLIENT_SOURCES utils.c) 83 | list(APPEND CLIENT_SOURCES ping.c) 84 | list(APPEND CLIENT_SOURCES log.c) 85 | list(APPEND CLIENT_SOURCES minheap.c) 86 | list(APPEND CLIENT_SOURCES hashtable.c) 87 | list(APPEND CLIENT_SOURCES rpc.c) 88 | list(APPEND CLIENT_SOURCES tesselator.c) 89 | list(APPEND CLIENT_SOURCES microui.c) 90 | list(APPEND CLIENT_SOURCES channel.c) 91 | list(APPEND CLIENT_SOURCES entitysystem.c) 92 | list(APPEND CLIENT_SOURCES ${BetterSpades_SOURCE_DIR}/resources/icon.rc) 93 | 94 | add_executable(client ${CLIENT_SOURCES}) 95 | 96 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 97 | set_property(TARGET client PROPERTY WIN32_EXECUTABLE true) 98 | target_compile_definitions(client PRIVATE NDEBUG) 99 | endif() 100 | 101 | set(GIT_COMMIT_HASH "?") 102 | 103 | execute_process( 104 | COMMAND git log -1 --format=%h 105 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 106 | OUTPUT_VARIABLE GIT_COMMIT_HASH 107 | OUTPUT_STRIP_TRAILING_WHITESPACE 108 | ) 109 | 110 | include(CheckIPOSupported) 111 | check_ipo_supported(RESULT lto_supported OUTPUT error) 112 | 113 | if(lto_supported) 114 | message(STATUS "IPO / LTO enabled") 115 | set_property(TARGET client PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) 116 | else() 117 | message(STATUS "IPO / LTO not supported: <${error}>") 118 | endif() 119 | 120 | target_compile_definitions(client PRIVATE GIT_COMMIT_HASH="${GIT_COMMIT_HASH}") 121 | target_compile_definitions(client PRIVATE DR_WAV_IMPLEMENTATION) 122 | target_compile_definitions(client PRIVATE LOG_USE_COLOR) 123 | 124 | if(ENABLE_TOUCH) 125 | target_compile_definitions(client PRIVATE USE_TOUCH) 126 | endif() 127 | if(ENABLE_ANDROID_FILE) 128 | target_compile_definitions(client PRIVATE USE_ANDROID_FILE) 129 | endif() 130 | 131 | target_compile_definitions(client PRIVATE BETTERSPADES_MAJOR=${BETTERSPADES_MAJOR}) 132 | target_compile_definitions(client PRIVATE BETTERSPADES_MINOR=${BETTERSPADES_MINOR}) 133 | target_compile_definitions(client PRIVATE BETTERSPADES_PATCH=${BETTERSPADES_PATCH}) 134 | target_compile_definitions(client PRIVATE BETTERSPADES_VERSION="v${BETTERSPADES_MAJOR}.${BETTERSPADES_MINOR}.${BETTERSPADES_PATCH}") 135 | 136 | 137 | set_target_properties( 138 | client PROPERTIES 139 | RUNTIME_OUTPUT_DIRECTORY ${BetterSpades_SOURCE_DIR}/build/BetterSpades 140 | C_STANDARD 99 141 | ) 142 | 143 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${BetterSpades_SOURCE_DIR}/deps) 144 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${BetterSpades_SOURCE_DIR}/cmake/Modules) 145 | set(OpenGL_GL_PREFERENCE LEGACY) 146 | if(ENABLE_GLFW) 147 | find_package(glfw3 REQUIRED) 148 | target_link_libraries(client glfw3::glfw3) 149 | target_compile_definitions(client PRIVATE USE_GLFW) 150 | endif() 151 | if(ENABLE_SDL) 152 | find_package(SDL2 REQUIRED) 153 | target_link_libraries(client ${SDL2_LIBRARY}) 154 | target_compile_definitions(client PRIVATE USE_SDL) 155 | endif() 156 | if(ENABLE_SOUND) 157 | find_package(OpenAL REQUIRED) 158 | target_link_libraries(client ${OPENAL_LIBRARY}) 159 | target_compile_definitions(client PRIVATE USE_SOUND) 160 | endif() 161 | find_package(enet REQUIRED) 162 | find_package(deflate REQUIRED) 163 | find_package(Threads REQUIRED) 164 | if(NOT ENABLE_OPENGLES) 165 | find_package(OpenGL REQUIRED) 166 | find_package(GLEW REQUIRED) 167 | target_link_libraries(client GLEW::GLEW) 168 | else() 169 | find_package(OpenGL REQUIRED COMPONENTS EGL) 170 | target_link_libraries(client OpenGL::EGL) 171 | target_compile_definitions(client PRIVATE OPENGL_ES) 172 | endif() 173 | if(ENABLE_RPC) 174 | target_link_libraries(client discord-rpc stdc++) 175 | target_compile_definitions(client PRIVATE USE_RPC DISCORD_DISABLE_IO_THREAD) 176 | endif() 177 | 178 | target_link_libraries(client ${CMAKE_THREAD_LIBS_INIT} ${OPENGL_LIBRARIES} enet::enet deflate::deflate m cglm vxl) 179 | include_directories(client ${OPENAL_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} ${OPENGL_EGL_INCLUDE_DIRS}) 180 | 181 | add_custom_command( 182 | TARGET client 183 | POST_BUILD 184 | COMMENT "Copying resources..." 185 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${BetterSpades_SOURCE_DIR}/resources ${BetterSpades_SOURCE_DIR}/build/BetterSpades 186 | ) 187 | 188 | add_custom_command( 189 | TARGET client 190 | POST_BUILD 191 | COMMENT "Extracting additional third-party assets..." 192 | DEPENDS ${BetterSpades_SOURCE_DIR}/bsresources.zip 193 | WORKING_DIRECTORY ${BetterSpades_SOURCE_DIR}/build/BetterSpades 194 | COMMAND ${CMAKE_COMMAND} -E tar xzf ${BetterSpades_SOURCE_DIR}/bsresources.zip 195 | ) 196 | 197 | install( 198 | TARGETS client 199 | RUNTIME 200 | DESTINATION . 201 | ) 202 | 203 | install( 204 | FILES "${CMAKE_BINARY_DIR}/BetterSpades/config.ini" "${CMAKE_BINARY_DIR}/BetterSpades/OpenAL32.dll" 205 | DESTINATION . 206 | PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ 207 | GROUP_EXECUTE GROUP_READ 208 | ) 209 | 210 | install( 211 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/fonts" 212 | DESTINATION . 213 | FILES_MATCHING PATTERN "*.ttf" 214 | ) 215 | 216 | install( 217 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/kv6" 218 | DESTINATION . 219 | FILES_MATCHING PATTERN "*.kv6" 220 | ) 221 | 222 | install( 223 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/png" 224 | DESTINATION . 225 | FILES_MATCHING PATTERN "*.png" 226 | ) 227 | 228 | install( 229 | DIRECTORY "${CMAKE_BINARY_DIR}/BetterSpades/wav" 230 | DESTINATION . 231 | FILES_MATCHING PATTERN "*.wav" 232 | ) 233 | 234 | install( 235 | DIRECTORY 236 | DESTINATION "cache" 237 | ) 238 | 239 | install( 240 | DIRECTORY 241 | DESTINATION "logs" 242 | ) 243 | 244 | install( 245 | DIRECTORY 246 | DESTINATION "screenshots" 247 | ) 248 | 249 | set(CPACK_GENERATOR NSIS) 250 | set(CPACK_PACKAGE_NAME "PixSpades") 251 | set(CPACK_PACKAGE_VENDOR "github.com") 252 | set(CPACK_PACKAGE_VERSION "v${BETTERSPADES_MAJOR}.${BETTERSPADES_MINOR}.${BETTERSPADES_PATCH}") 253 | set(CPACK_PACKAGE_VERSION_MAJOR "${BETTERSPADES_MAJOR}") 254 | set(CPACK_PACKAGE_VERSION_MINOR "${BETTERSPADES_MINOR}") 255 | set(CPACK_PACKAGE_VERSION_PATCH "${BETTERSPADES_PATCH}") 256 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") 257 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") 258 | set(CPACK_STRIP_FILES TRUE) 259 | set(CPACK_NSIS_MENU_LINKS "client" "PixSpades") 260 | set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) 261 | set(CPACK_PACKAGE_CHECKSUM SHA256) 262 | 263 | INCLUDE(CPack) 264 | -------------------------------------------------------------------------------- /src/glx.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 | 23 | #include "common.h" 24 | #include "camera.h" 25 | #include "config.h" 26 | #include "map.h" 27 | #include "matrix.h" 28 | #include "texture.h" 29 | #include "glx.h" 30 | 31 | // for future opengl-es abstraction layer 32 | 33 | int glx_version = 0; 34 | 35 | int glx_fog = 0; 36 | 37 | static int glx_major_ver() { 38 | return 1; 39 | #ifdef OPENGL_ES 40 | return 2; 41 | #else 42 | return atoi(glGetString(GL_VERSION)); 43 | #endif 44 | } 45 | 46 | void glx_init() { 47 | #ifndef OPENGL_ES 48 | glx_version = glx_major_ver() >= 2; 49 | #else 50 | glx_version = 0; 51 | #endif 52 | } 53 | 54 | int glx_shader(const char* vertex, const char* fragment) { 55 | #ifndef OPENGL_ES 56 | int v, f; 57 | if(vertex) { 58 | v = glCreateShader(GL_VERTEX_SHADER); 59 | glShaderSource(v, 1, (const GLchar* const*)&vertex, NULL); 60 | glCompileShader(v); 61 | } 62 | 63 | if(fragment) { 64 | f = glCreateShader(GL_FRAGMENT_SHADER); 65 | glShaderSource(f, 1, (const GLchar* const*)&fragment, NULL); 66 | glCompileShader(f); 67 | } 68 | 69 | int program = glCreateProgram(); 70 | if(vertex) 71 | glAttachShader(program, v); 72 | if(vertex) 73 | glAttachShader(program, f); 74 | glLinkProgram(program); 75 | return program; 76 | #else 77 | return 0; 78 | #endif 79 | } 80 | 81 | void glx_displaylist_create(struct glx_displaylist* x, bool has_color, bool has_normal) { 82 | x->has_color = has_color; 83 | x->has_normal = has_normal; 84 | 85 | #ifndef OPENGL_ES 86 | if(!glx_version || settings.force_displaylist) { 87 | x->legacy = glGenLists(1); 88 | } else { 89 | glGenBuffers(1, &x->modern); 90 | } 91 | #else 92 | glGenBuffers(1, &x->modern); 93 | #endif 94 | x->buffer_size = 0; 95 | } 96 | 97 | void glx_displaylist_destroy(struct glx_displaylist* x) { 98 | #ifndef OPENGL_ES 99 | if(!glx_version || settings.force_displaylist) { 100 | glDeleteLists(x->legacy, 1); 101 | } else { 102 | glDeleteBuffers(1, &x->modern); 103 | } 104 | #else 105 | glDeleteBuffers(1, &x->modern); 106 | #endif 107 | } 108 | 109 | void glx_displaylist_update(struct glx_displaylist* x, size_t size, int type, void* color, void* vertex, void* normal) { 110 | int grow_buffer = size > x->buffer_size; 111 | x->buffer_size = max(x->buffer_size, size); 112 | x->size = size; 113 | 114 | #ifndef OPENGL_ES 115 | if(!glx_version || settings.force_displaylist) { 116 | glEnableClientState(GL_VERTEX_ARRAY); 117 | if(x->has_color) 118 | glEnableClientState(GL_COLOR_ARRAY); 119 | if(x->has_normal) 120 | glEnableClientState(GL_NORMAL_ARRAY); 121 | 122 | glNewList(x->legacy, GL_COMPILE); 123 | if(size > 0) { 124 | if(x->has_color) 125 | glColorPointer(4, GL_UNSIGNED_BYTE, 0, color); 126 | 127 | switch(type) { 128 | case GLX_DISPLAYLIST_NORMAL: glVertexPointer(3, GL_SHORT, 0, vertex); break; 129 | case GLX_DISPLAYLIST_POINTS: 130 | case GLX_DISPLAYLIST_ENHANCED: glVertexPointer(3, GL_FLOAT, 0, vertex); break; 131 | } 132 | 133 | if(x->has_normal) 134 | glNormalPointer(GL_BYTE, 0, normal); 135 | glDrawArrays((type == GLX_DISPLAYLIST_POINTS) ? GL_POINTS : GL_QUADS, 0, x->size); 136 | } 137 | glEndList(); 138 | 139 | glDisableClientState(GL_VERTEX_ARRAY); 140 | if(x->has_color) 141 | glDisableClientState(GL_COLOR_ARRAY); 142 | if(x->has_normal) 143 | glDisableClientState(GL_NORMAL_ARRAY); 144 | } else { 145 | #endif 146 | size_t len_vertex = ((type == GLX_DISPLAYLIST_NORMAL) ? sizeof(GLshort) : sizeof(GLfloat)) * 3; 147 | size_t len_color = x->has_color ? (sizeof(GLubyte) * 4) : 0; 148 | size_t len_normal = x->has_normal ? (sizeof(GLbyte) * 3) : 0; 149 | 150 | glBindBuffer(GL_ARRAY_BUFFER, x->modern); 151 | 152 | if(grow_buffer) { 153 | glBufferData(GL_ARRAY_BUFFER, x->size * (len_vertex + len_color + len_normal), NULL, GL_STATIC_DRAW); 154 | } 155 | 156 | glBufferSubData(GL_ARRAY_BUFFER, 0, x->size * len_vertex, vertex); 157 | 158 | if(x->has_color) { 159 | glBufferSubData(GL_ARRAY_BUFFER, x->size * len_vertex, x->size * len_color, color); 160 | } 161 | 162 | if(x->has_normal) { 163 | glBufferSubData(GL_ARRAY_BUFFER, x->size * (len_vertex + len_color), x->size * len_normal, normal); 164 | } 165 | 166 | glBindBuffer(GL_ARRAY_BUFFER, 0); 167 | #ifndef OPENGL_ES 168 | } 169 | #endif 170 | } 171 | 172 | void glx_displaylist_draw(struct glx_displaylist* x, int type) { 173 | #ifndef OPENGL_ES 174 | if(!glx_version || settings.force_displaylist) { 175 | glCallList(x->legacy); 176 | } else { 177 | #endif 178 | glEnableClientState(GL_VERTEX_ARRAY); 179 | glBindBuffer(GL_ARRAY_BUFFER, x->modern); 180 | 181 | size_t len_vertex = ((type == GLX_DISPLAYLIST_NORMAL) ? sizeof(GLshort) : sizeof(GLfloat)) * 3; 182 | size_t len_color = x->has_color ? (sizeof(GLubyte) * 4) : 0; 183 | size_t len_normal = x->has_normal ? (sizeof(GLbyte) * 3) : 0; 184 | 185 | switch(type) { 186 | case GLX_DISPLAYLIST_NORMAL: glVertexPointer(3, GL_SHORT, 0, NULL); break; 187 | case GLX_DISPLAYLIST_POINTS: 188 | case GLX_DISPLAYLIST_ENHANCED: glVertexPointer(3, GL_FLOAT, 0, NULL); break; 189 | } 190 | 191 | if(x->has_color) { 192 | glEnableClientState(GL_COLOR_ARRAY); 193 | glColorPointer(4, GL_UNSIGNED_BYTE, 0, (const void*)(x->size * len_vertex)); 194 | } 195 | 196 | if(x->has_normal) { 197 | glEnableClientState(GL_NORMAL_ARRAY); 198 | glNormalPointer(GL_BYTE, 0, (const void*)(x->size * (len_vertex + len_color))); 199 | } 200 | 201 | glBindBuffer(GL_ARRAY_BUFFER, 0); 202 | 203 | if(type == GLX_DISPLAYLIST_POINTS) { 204 | glDrawArrays(GL_POINTS, 0, x->size); 205 | } else { 206 | #ifdef OPENGL_ES 207 | glDrawArrays(GL_TRIANGLES, 0, x->size); 208 | #else 209 | glDrawArrays(GL_QUADS, 0, x->size); 210 | #endif 211 | } 212 | 213 | if(x->has_normal) 214 | glDisableClientState(GL_NORMAL_ARRAY); 215 | if(x->has_color) 216 | glDisableClientState(GL_COLOR_ARRAY); 217 | glDisableClientState(GL_VERTEX_ARRAY); 218 | #ifndef OPENGL_ES 219 | } 220 | #endif 221 | } 222 | 223 | void glx_enable_sphericalfog() { 224 | #ifndef OPENGL_ES 225 | if(!settings.smooth_fog) { 226 | glActiveTexture(GL_TEXTURE1); 227 | glEnable(GL_TEXTURE_2D); 228 | glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (float[]) {fog_color[0], fog_color[1], fog_color[2], 1.0F}); 229 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); 230 | glBindTexture(GL_TEXTURE_2D, texture_gradient.texture_id); 231 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 232 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 233 | glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 234 | glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 235 | glTexGenfv(GL_T, GL_EYE_PLANE, 236 | (float[]) {1.0F / settings.render_distance / 2.0F, 0.0F, 0.0F, 237 | -camera_x / settings.render_distance / 2.0F + 0.5F}); 238 | glTexGenfv(GL_S, GL_EYE_PLANE, 239 | (float[]) {0.0F, 0.0F, 1.0F / settings.render_distance / 2.0F, 240 | -camera_z / settings.render_distance / 2.0F + 0.5F}); 241 | glEnable(GL_TEXTURE_GEN_T); 242 | glEnable(GL_TEXTURE_GEN_S); 243 | glActiveTexture(GL_TEXTURE0); 244 | } else { 245 | matrix_push(matrix_model); 246 | matrix_identity(matrix_model); 247 | matrix_upload(); 248 | matrix_pop(matrix_model); 249 | 250 | glEnable(GL_LIGHTING); 251 | glEnable(GL_LIGHT1); 252 | glEnable(GL_COLOR_MATERIAL); 253 | glColorMaterial(GL_FRONT, GL_DIFFUSE); 254 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float[]) {fog_color[0], fog_color[1], fog_color[2], 1.0F}); 255 | 256 | glLightfv(GL_LIGHT1, GL_POSITION, 257 | (float[]) {camera_x, (settings.render_distance * map_size_y) / 16.0F, camera_z, 1.0F}); 258 | glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, (float[]) {0.0F, -1.0F, 0.0F}); 259 | glLightfv(GL_LIGHT1, GL_DIFFUSE, (float[]) {1.0F, 1.0F, 1.0F, 1.0F}); 260 | glLightfv(GL_LIGHT1, GL_AMBIENT, (float[]) {-fog_color[0], -fog_color[1], -fog_color[2], 1.0F}); 261 | glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, tan(16.0F / map_size_y) / PI * 180.0F); 262 | glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 128.0F); 263 | glNormal3f(0.0F, 1.0F, 0.0F); 264 | } 265 | #else 266 | matrix_push(matrix_model); 267 | matrix_identity(matrix_model); 268 | matrix_upload(); 269 | matrix_pop(matrix_model); 270 | 271 | glEnable(GL_LIGHTING); 272 | glEnable(GL_LIGHT1); 273 | glEnable(GL_COLOR_MATERIAL); 274 | // glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); 275 | float amb[4] = {0.0F, 0.0F, 0.0F, 1.0F}; 276 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb); 277 | 278 | float lpos[4] = {camera_x, (settings.render_distance * map_size_y) / 16.0F, camera_z, 1.0F}; 279 | glLightfv(GL_LIGHT1, GL_POSITION, lpos); 280 | float dir[3] = {0.0F, -1.0F, 0.0F}; 281 | glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, dir); 282 | float dif[4] = {0.0F, 0.0F, 0.0F, 1.0F}; 283 | glLightfv(GL_LIGHT1, GL_DIFFUSE, dif); 284 | float amb2[4] = {1.0F, 1.0F, 1.0F, 1.0F}; 285 | glLightfv(GL_LIGHT1, GL_AMBIENT, amb2); 286 | glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, tan(16.0F / map_size_y) / PI * 180.0F); 287 | glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 128.0F); 288 | glNormal3f(0.0F, 1.0F, 0.0F); 289 | glEnable(GL_FOG); 290 | glFogf(GL_FOG_MODE, GL_LINEAR); 291 | glFogf(GL_FOG_START, 0.0F); 292 | glFogf(GL_FOG_END, settings.render_distance); 293 | glFogfv(GL_FOG_COLOR, fog_color); 294 | #endif 295 | glx_fog = 1; 296 | } 297 | 298 | void glx_disable_sphericalfog() { 299 | #ifndef OPENGL_ES 300 | if(!settings.smooth_fog) { 301 | glActiveTexture(GL_TEXTURE1); 302 | glDisable(GL_TEXTURE_GEN_T); 303 | glDisable(GL_TEXTURE_GEN_S); 304 | glBindTexture(GL_TEXTURE_2D, 0); 305 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 306 | glDisable(GL_TEXTURE_2D); 307 | glActiveTexture(GL_TEXTURE0); 308 | } else { 309 | glDisable(GL_COLOR_MATERIAL); 310 | glDisable(GL_LIGHT1); 311 | glDisable(GL_LIGHTING); 312 | float a[4] = {0.2F, 0.2F, 0.2F, 1.0F}; 313 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, a); 314 | } 315 | #else 316 | glDisable(GL_FOG); 317 | glDisable(GL_COLOR_MATERIAL); 318 | glDisable(GL_LIGHT1); 319 | glDisable(GL_LIGHTING); 320 | float a[4] = {0.2F, 0.2F, 0.2F, 1.0F}; 321 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, a); 322 | #endif 323 | glx_fog = 0; 324 | } 325 | 326 | -------------------------------------------------------------------------------- /src/sound.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 "sound.h" 26 | #include "config.h" 27 | #include "log.h" 28 | #include "camera.h" 29 | #include "entitysystem.h" 30 | 31 | #ifdef USE_SOUND 32 | int sound_enabled = 1; 33 | #else 34 | int sound_enabled = 0; 35 | #endif 36 | 37 | struct Sound_source { 38 | int openal_handle; 39 | char local; 40 | int stick_to_player; 41 | }; 42 | 43 | struct entity_system sound_sources; 44 | 45 | struct Sound_wav sound_footstep1; 46 | struct Sound_wav sound_footstep2; 47 | struct Sound_wav sound_footstep3; 48 | struct Sound_wav sound_footstep4; 49 | 50 | struct Sound_wav sound_wade1; 51 | struct Sound_wav sound_wade2; 52 | struct Sound_wav sound_wade3; 53 | struct Sound_wav sound_wade4; 54 | 55 | struct Sound_wav sound_jump; 56 | struct Sound_wav sound_jump_water; 57 | 58 | struct Sound_wav sound_land; 59 | struct Sound_wav sound_land_water; 60 | 61 | struct Sound_wav sound_hurt_fall; 62 | 63 | struct Sound_wav sound_explode; 64 | struct Sound_wav sound_explode_water; 65 | struct Sound_wav sound_grenade_bounce; 66 | struct Sound_wav sound_grenade_pin; 67 | 68 | struct Sound_wav sound_pickup; 69 | struct Sound_wav sound_horn; 70 | 71 | struct Sound_wav sound_rifle_shoot; 72 | struct Sound_wav sound_rifle_reload; 73 | struct Sound_wav sound_smg_shoot; 74 | struct Sound_wav sound_smg_reload; 75 | struct Sound_wav sound_shotgun_shoot; 76 | struct Sound_wav sound_shotgun_reload; 77 | struct Sound_wav sound_shotgun_cock; 78 | 79 | struct Sound_wav sound_hitground; 80 | struct Sound_wav sound_hitplayer; 81 | struct Sound_wav sound_build; 82 | 83 | struct Sound_wav sound_spade_woosh; 84 | struct Sound_wav sound_spade_whack; 85 | 86 | struct Sound_wav sound_death; 87 | struct Sound_wav sound_beep1; 88 | struct Sound_wav sound_beep2; 89 | struct Sound_wav sound_switch; 90 | struct Sound_wav sound_empty; 91 | struct Sound_wav sound_intro; 92 | 93 | struct Sound_wav sound_debris; 94 | struct Sound_wav sound_bounce; 95 | struct Sound_wav sound_impact; 96 | struct Sound_wav sound_macros; 97 | struct Sound_wav sound_chat; 98 | 99 | void sound_volume(float vol) { 100 | #ifdef USE_SOUND 101 | if(sound_enabled) 102 | alListenerf(AL_GAIN, vol); 103 | #endif 104 | } 105 | 106 | static void sound_createEx(enum sound_space option, struct Sound_wav* w, float x, float y, float z, float vx, float vy, 107 | float vz, int player) { 108 | #ifdef USE_SOUND 109 | if(!sound_enabled) 110 | return; 111 | 112 | struct Sound_source s = (struct Sound_source) { 113 | .local = option == SOUND_LOCAL, 114 | .stick_to_player = player, 115 | }; 116 | 117 | alGetError(); 118 | alGenSources(1, &s.openal_handle); 119 | 120 | if(alGetError() == AL_NO_ERROR) { 121 | alSourcef(s.openal_handle, AL_PITCH, 1.0F); 122 | alSourcef(s.openal_handle, AL_GAIN, 1.0F); 123 | alSourcef(s.openal_handle, AL_REFERENCE_DISTANCE, s.local ? 0.0F : w->min * SOUND_SCALE); 124 | alSourcef(s.openal_handle, AL_MAX_DISTANCE, s.local ? 2048.0F : w->max * SOUND_SCALE); 125 | alSource3f(s.openal_handle, AL_POSITION, s.local ? 0.0F : x * SOUND_SCALE, s.local ? 0.0F : y * SOUND_SCALE, 126 | s.local ? 0.0F : z * SOUND_SCALE); 127 | alSource3f(s.openal_handle, AL_VELOCITY, s.local ? 0.0F : vx * SOUND_SCALE, s.local ? 0.0F : vy * SOUND_SCALE, 128 | s.local ? 0.0F : vz * SOUND_SCALE); 129 | alSourcei(s.openal_handle, AL_SOURCE_RELATIVE, s.local); 130 | alSourcei(s.openal_handle, AL_LOOPING, AL_FALSE); 131 | alSourcei(s.openal_handle, AL_BUFFER, w->openal_buffer); 132 | 133 | alSourcePlay(s.openal_handle); 134 | 135 | if(alGetError() == AL_NO_ERROR) { 136 | entitysys_add(&sound_sources, &s); 137 | } else { 138 | alDeleteSources(1, &s.openal_handle); 139 | } 140 | } 141 | #endif 142 | } 143 | 144 | void sound_create_sticky(struct Sound_wav* w, struct Player* player, int player_id) { 145 | sound_createEx(SOUND_WORLD, w, player->pos.x, player->pos.y, player->pos.z, 0.0F, 0.0F, 0.0F, player_id); 146 | } 147 | 148 | void sound_create(enum sound_space option, struct Sound_wav* w, float x, float y, float z) { 149 | sound_createEx(option, w, x, y, z, 0.0F, 0.0F, 0.0F, -1); 150 | } 151 | 152 | void sound_velocity(struct Sound_source* s, float vx, float vy, float vz) { 153 | #ifdef USE_SOUND 154 | if(!sound_enabled || s->local) 155 | return; 156 | alSource3f(s->openal_handle, AL_VELOCITY, vx * SOUND_SCALE, vy * SOUND_SCALE, vz * SOUND_SCALE); 157 | #endif 158 | } 159 | 160 | void sound_position(struct Sound_source* s, float x, float y, float z) { 161 | #ifdef USE_SOUND 162 | if(!sound_enabled || s->local) 163 | return; 164 | 165 | alSource3f(s->openal_handle, AL_POSITION, x * SOUND_SCALE, y * SOUND_SCALE, z * SOUND_SCALE); 166 | #endif 167 | } 168 | 169 | #ifdef USE_SOUND 170 | static bool sound_update_single(void* obj, void* user) { 171 | struct Sound_source* s = (struct Sound_source*)obj; 172 | 173 | int source_state; 174 | alGetSourcei(s->openal_handle, AL_SOURCE_STATE, &source_state); 175 | if(source_state == AL_STOPPED || (s->stick_to_player >= 0 && !players[s->stick_to_player].connected)) { 176 | alDeleteSources(1, &s->openal_handle); 177 | 178 | return true; 179 | } else { 180 | if(s->stick_to_player >= 0) { 181 | sound_position(s, players[s->stick_to_player].pos.x, players[s->stick_to_player].pos.y, 182 | players[s->stick_to_player].pos.z); 183 | sound_velocity(s, players[s->stick_to_player].physics.velocity.x, 184 | players[s->stick_to_player].physics.velocity.y, 185 | players[s->stick_to_player].physics.velocity.z); 186 | } 187 | 188 | return false; 189 | } 190 | } 191 | #endif 192 | 193 | void sound_update() { 194 | #ifdef USE_SOUND 195 | if(!sound_enabled) 196 | return; 197 | 198 | float orientation[] = { 199 | sin(camera_rot_x) * sin(camera_rot_y), 200 | cos(camera_rot_y), 201 | cos(camera_rot_x) * sin(camera_rot_y), 202 | 0.0F, 203 | 1.0F, 204 | 0.0F, 205 | }; 206 | 207 | alListener3f(AL_POSITION, camera_x * SOUND_SCALE, camera_y * SOUND_SCALE, camera_z * SOUND_SCALE); 208 | alListener3f(AL_VELOCITY, camera_vx * SOUND_SCALE, camera_vy * SOUND_SCALE, camera_vz * SOUND_SCALE); 209 | alListenerfv(AL_ORIENTATION, orientation); 210 | 211 | entitysys_iterate(&sound_sources, NULL, sound_update_single); 212 | #endif 213 | } 214 | 215 | extern short* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, 216 | uint64_t* totalFrameCount); 217 | 218 | void sound_load(struct Sound_wav* wav, char* name, float min, float max) { 219 | #ifdef USE_SOUND 220 | if(!sound_enabled) 221 | return; 222 | unsigned int channels, samplerate; 223 | uint64_t samplecount; 224 | short* samples = drwav_open_and_read_file_s16(name, &channels, &samplerate, &samplecount); 225 | if(samples == NULL) { 226 | log_fatal("Could not load sound %s", name); 227 | exit(1); 228 | } 229 | 230 | short* audio; 231 | if(channels > 1) { // convert stereo to mono 232 | audio = malloc(samplecount * sizeof(short) / 2); 233 | CHECK_ALLOCATION_ERROR(audio) 234 | for(int k = 0; k < samplecount / 2; k++) 235 | audio[k] = ((int)samples[k * 2] + (int)samples[k * 2 + 1]) / 2; // prevent overflow 236 | free(samples); 237 | } 238 | 239 | alGenBuffers(1, &wav->openal_buffer); 240 | alBufferData(wav->openal_buffer, AL_FORMAT_MONO16, (channels > 1) ? audio : samples, 241 | samplecount * sizeof(short) / channels, samplerate); 242 | 243 | wav->min = min; 244 | wav->max = max; 245 | #endif 246 | } 247 | 248 | void sound_init() { 249 | #ifdef USE_SOUND 250 | entitysys_create(&sound_sources, sizeof(struct Sound_source), 256); 251 | 252 | ALCdevice* device = alcOpenDevice(NULL); 253 | 254 | if(!device) { 255 | sound_enabled = 0; 256 | log_warn("Could not open sound device!"); 257 | return; 258 | } 259 | 260 | ALCcontext* context = alcCreateContext(device, NULL); 261 | if(!alcMakeContextCurrent(context)) { 262 | sound_enabled = 0; 263 | log_warn("Could not enter sound device context!"); 264 | return; 265 | } 266 | 267 | alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); 268 | 269 | sound_volume(settings.volume / 10.0F); 270 | 271 | sound_load(&sound_footstep1, "wav/footstep1.wav", 0.1F, 32.0F); 272 | sound_load(&sound_footstep2, "wav/footstep2.wav", 0.1F, 32.0F); 273 | sound_load(&sound_footstep3, "wav/footstep3.wav", 0.1F, 32.0F); 274 | sound_load(&sound_footstep4, "wav/footstep4.wav", 0.1F, 32.0F); 275 | 276 | sound_load(&sound_wade1, "wav/wade1.wav", 0.1F, 32.0F); 277 | sound_load(&sound_wade2, "wav/wade2.wav", 0.1F, 32.0F); 278 | sound_load(&sound_wade3, "wav/wade3.wav", 0.1F, 32.0F); 279 | sound_load(&sound_wade4, "wav/wade4.wav", 0.1F, 32.0F); 280 | 281 | sound_load(&sound_jump, "wav/jump.wav", 0.1F, 32.0F); 282 | sound_load(&sound_land, "wav/land.wav", 0.1F, 32.0F); 283 | sound_load(&sound_jump_water, "wav/waterjump.wav", 0.1F, 32.0F); 284 | sound_load(&sound_land_water, "wav/waterland.wav", 0.1F, 32.0F); 285 | 286 | sound_load(&sound_explode, "wav/explode.wav", 0.1F, 53.0F); 287 | sound_load(&sound_explode_water, "wav/waterexplode.wav", 0.1F, 53.0F); 288 | sound_load(&sound_grenade_bounce, "wav/grenadebounce.wav", 0.1F, 48.0F); 289 | sound_load(&sound_grenade_pin, "wav/pin.wav", 0.1F, 48.0F); 290 | 291 | sound_load(&sound_hurt_fall, "wav/fallhurt.wav", 0.1F, 32.0F); 292 | 293 | sound_load(&sound_pickup, "wav/pickup.wav", 0.1F, 1024.0F); 294 | sound_load(&sound_horn, "wav/horn.wav", 0.1F, 1024.0F); 295 | 296 | sound_load(&sound_rifle_shoot, "wav/semishoot.wav", 0.1F, 96.0F); 297 | sound_load(&sound_rifle_reload, "wav/semireload.wav", 0.1F, 16.0F); 298 | sound_load(&sound_smg_shoot, "wav/smgshoot.wav", 0.1F, 96.0F); 299 | sound_load(&sound_smg_reload, "wav/smgreload.wav", 0.1F, 16.0F); 300 | sound_load(&sound_shotgun_shoot, "wav/shotgunshoot.wav", 0.1F, 96.0F); 301 | sound_load(&sound_shotgun_reload, "wav/shotgunreload.wav", 0.1F, 16.0F); 302 | sound_load(&sound_shotgun_cock, "wav/cock.wav", 0.1F, 16.0F); 303 | 304 | sound_load(&sound_hitground, "wav/hitground.wav", 0.1F, 32.0F); 305 | sound_load(&sound_hitplayer, "wav/hitplayer.wav", 0.1F, 32.0F); 306 | sound_load(&sound_build, "wav/build.wav", 0.1F, 32.0F); 307 | 308 | sound_load(&sound_spade_woosh, "wav/woosh.wav", 0.1F, 32.0F); 309 | sound_load(&sound_spade_whack, "wav/whack.wav", 0.1F, 32.0F); 310 | 311 | sound_load(&sound_death, "wav/death.wav", 0.1F, 24.0F); 312 | sound_load(&sound_beep1, "wav/beep1.wav", 0.1F, 1024.0F); 313 | sound_load(&sound_beep2, "wav/beep2.wav", 0.1F, 1024.0F); 314 | sound_load(&sound_switch, "wav/switch.wav", 0.1F, 1024.0F); 315 | sound_load(&sound_empty, "wav/empty.wav", 0.1F, 1024.0F); 316 | sound_load(&sound_intro, "wav/intro.wav", 0.1F, 1024.0F); 317 | 318 | sound_load(&sound_debris, "wav/debris.wav", 0.1F, 53.0F); 319 | sound_load(&sound_bounce, "wav/bounce.wav", 0.1F, 32.0F); 320 | sound_load(&sound_impact, "wav/impact.wav", 0.1F, 53.0F); 321 | sound_load(&sound_macros, "wav/macros_sound.wav", 0.1F, 1024.0F); 322 | sound_load(&sound_chat, "wav/chat.wav", 0.1F, 1024.0F); 323 | #endif 324 | } 325 | --------------------------------------------------------------------------------