diff --git a/.ci/i686-w64-mingw32.txt b/.ci/i686-w64-mingw32.txt index 3fa260c56..783095616 100644 --- a/.ci/i686-w64-mingw32.txt +++ b/.ci/i686-w64-mingw32.txt @@ -4,6 +4,7 @@ cpp = 'i686-w64-mingw32-g++' ar = 'i686-w64-mingw32-ar' strip = 'i686-w64-mingw32-strip' windres = 'i686-w64-mingw32-windres' +nasm = 'nasm' [host_machine] system = 'windows' diff --git a/.ci/x86_64-w64-mingw32.txt b/.ci/x86_64-w64-mingw32.txt index 30b736e1c..c61705200 100644 --- a/.ci/x86_64-w64-mingw32.txt +++ b/.ci/x86_64-w64-mingw32.txt @@ -4,6 +4,7 @@ cpp = 'x86_64-w64-mingw32-g++' ar = 'x86_64-w64-mingw32-ar' strip = 'x86_64-w64-mingw32-strip' windres = 'x86_64-w64-mingw32-windres' +nasm = 'nasm' [host_machine] system = 'windows' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 07268db02..de4215172 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: build on: push: - branches: [master, aqtion, alpha-aqtion, ci] + branches: [master, aqtion, aqtion-alpha, ci] pull_request: - branches: [master, aqtion, alpha-aqtion] + branches: [master, aqtion, aqtion-alpha] workflow_dispatch: env: @@ -19,14 +19,10 @@ env: -Dvariable-fps=true -Dwerror=false -Daqtion-build=true - -Ddiscord-sdk=true - -Davcodec=disabled -# Disabled avcodec for now, because AQtion doesn't use it, but it's there if we do cinematics one day + -Ddiscord-sdk=false MESON_ARGS_WIN: >- - -Dlibpng:werror=false -Dsdl2=disabled - -Dvorbis:werror=false -Dwayland=disabled -Dwrap_mode=forcefallback -Dx11=disabled @@ -55,9 +51,9 @@ jobs: #arch: ["i686", "x86_64"] arch: ["x86_64"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: subprojects/packagecache key: ${{ hashFiles('subprojects/*.wrap') }} @@ -65,7 +61,8 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y gcc-mingw-w64 meson nasm uuid-dev + sudo apt-get install -y gcc-mingw-w64 nasm python3-pip ninja-build + sudo python3 -m pip install meson - name: Build run: | @@ -74,7 +71,7 @@ jobs: meson compile -vC builddir - name: Generate Win Mingw archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-mingw-${{ matrix.arch }} path: | @@ -89,9 +86,9 @@ jobs: #arch: ["x86", "x64"] arch: ["x64"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: subprojects/packagecache key: ${{ hashFiles('subprojects/*.wrap') }} @@ -111,7 +108,7 @@ jobs: meson compile -C builddir - name: Generate Win MSVC archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-msvc-${{ matrix.arch }} path: | @@ -126,7 +123,7 @@ jobs: matrix: cc: [gcc, clang] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: | @@ -134,7 +131,9 @@ jobs: sudo apt-get install -y python3 python3-pip libsdl2-dev libopenal-dev \ libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-openssl-dev libx11-dev libxi-dev \ - libogg-dev libvorbis-dev uuid-dev patchelf + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev \ + uuid-dev patchelf pip3 install meson ninja - name: Build @@ -153,7 +152,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Linux x64 archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-lin-${{ matrix.cc }} path: | @@ -168,7 +167,7 @@ jobs: matrix: cc: [gcc, clang] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: | @@ -177,7 +176,9 @@ jobs: libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-openssl-dev libx11-dev libxi-dev \ libwayland-dev wayland-protocols libdecor-0-dev \ - libogg-dev libvorbis-dev uuid-dev patchelf + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev \ + uuid-dev patchelf - name: Build run: | @@ -195,7 +196,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Linux x64 archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-lin-wayland-${{ matrix.cc }} path: | @@ -209,7 +210,7 @@ jobs: matrix: cc: [gcc] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # - name: Install dependencies # run: | @@ -222,7 +223,7 @@ jobs: - name: Build run: | - meson setup ${{ env.MESON_ARGS }} ${{ env.MESON_ARGS_LINUX }} builddir + meson setup ${{ env.MESON_ARGS }} ${{ env.MESON_ARGS_LINUX_X11 }} builddir meson compile -vC builddir env: CC: ${{ matrix.cc }} @@ -232,7 +233,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Linux ARM archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-lin-arm64 path: | @@ -241,16 +242,13 @@ jobs: builddir/gamearm.so darwin: - runs-on: macos-latest - strategy: - matrix: - arch: [x86_64] + runs-on: macos-13 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install dependencies run: | - brew install pkg-config meson libpng sdl2 openal-soft zlib curl libvorbis jpeg-turbo + brew install pkg-config meson libpng sdl2 openal-soft zlib curl ffmpeg jpeg-turbo - name: Build run: | @@ -266,41 +264,41 @@ jobs: chmod +x builddir/q2pro* - name: Generate Mac archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: q2pro-darwin-${{ matrix.arch }} + name: q2pro-darwin-x86_64 path: | builddir/q2pro builddir/q2proded builddir/gamex86_64.dylib - # Github does not support Apple Silicon yet - # macARM64: - # runs-on: macos-latest - # steps: - # - uses: actions/checkout@v2 - - # - name: Setup Homebrew for ARM64 and dependencies - # run: | - # arch -arm64 brew install meson libpng jpeg sdl2 openal-soft zlib curl libvorbis - - # - name: Build - # run: | - # meson setup ${{ env.MESON_ARGS }} builddir - # ninja -vC builddir - # env: - # CC: "gcc" - # PKG_CONFIG_PATH: "/opt/homebrew/Cellar/openal-soft/1.22.2/lib/pkgconfig/:/opt/homebrew/Cellar/jpeg/9e/lib/pkgconfig/" - # CFLAGS: "-target arm64-apple-macos11" - - # - name: Set binaries as executable - # run: | - # chmod +x builddir/q2pro* - - # - name: Generate Mac archives - # uses: actions/upload-artifact@v3 - # with: - # name: q2pro-mac-arm64 - # path: | - # builddir/q2pro - # builddir/q2proded + darwin-arm64: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + brew install pkg-config meson libpng sdl2 openal-soft zlib curl ffmpeg jpeg-turbo + + - name: Build + run: | + meson setup ${{ env.MESON_ARGS }} ${{ env.MESON_ARGS_MAC }} builddir + meson compile -vC builddir + env: + CC: "gcc" + PKG_CONFIG_PATH: "/opt/homebrew/opt/openal-soft/lib/pkgconfig" + CFLAGS: "-target arm64-apple-macos11" + + - name: Set binaries as executable + run: | + chmod +x builddir/q2pro* + + - name: Generate Mac archives + uses: actions/upload-artifact@v4 + with: + name: q2pro-darwin-arm64 + path: | + builddir/q2pro + builddir/q2proded + builddir/gamex86_64.dylib diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed4e7c7a1..60aff21af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: actionquake/q2pro ref: ${{ github.ref }} @@ -101,6 +101,13 @@ jobs: name: q2pro-darwin-x86_64 skip_unpack: true + - name: Download Darwin arm64 build artifacts + uses: dawidd6/action-download-artifact@v2 + with: + workflow: build.yml + name: q2pro-darwin-arm64 + skip_unpack: true + - name: Upload dist tarball to release uses: softprops/action-gh-release@v1 env: @@ -117,6 +124,7 @@ jobs: q2pro-lin-wayland-gcc.zip q2pro-lin-wayland-clang.zip q2pro-darwin-x86_64.zip + q2pro-darwin-arm64.zip diff --git a/INSTALL.md b/INSTALL.md index ae9821253..0fb5c5f73 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -16,6 +16,9 @@ network protocol level. The rest of dependencies are optional. For JPEG support libjpeg-turbo is required, plain libjpeg will not work. Most Linux distributions already provide libjpeg-turbo in place of libjpeg. +For playing back cinematics in Ogg Theora format and music in Ogg Vorbis format +FFmpeg libraries are required. + To install the *full* set of dependencies for building Q2PRO on Debian or Ubuntu use the following command: @@ -23,7 +26,8 @@ Ubuntu use the following command: libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-gnutls-dev libx11-dev libxi-dev \ libwayland-dev wayland-protocols libdecor-0-dev \ - libogg-dev libvorbis-dev + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev Users of other distributions should look for equivalent development packages and install them. @@ -85,8 +89,7 @@ Q2PRO supports playback of background music ripped off original CD in Ogg Vorbis format. Music files should be placed in `music` subdirectory of the game directory in format `music/trackNN.ogg`, where `NN` corresponds to CD track number. `NN` should be typically in range 02-11 (track 01 is data track on -original CD and should never be used). Placing music in packfile will also -work. +original CD and should never be used). Note that so-called ‘GOG’ naming convention where music tracks are named ‘Track01’ to ‘Track21’ is not supported. diff --git a/README.md b/README.md index ac160e3fb..b8dfcf74e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ Features include: * recording from demos, forward and backward seeking * server side multiview demos and GTV capabilities -For building Q2PRO, consult the INSTALL file. +For building Q2PRO, consult the INSTALL.md file. + +Nightly Windows builds are available at https://skuller.net/q2pro/ For information on using and configuring Q2PRO, refer to client and server manuals available in doc/ subdirectory. diff --git a/doc/client.asciidoc b/doc/client.asciidoc index 8525239c1..5fd230901 100644 --- a/doc/client.asciidoc +++ b/doc/client.asciidoc @@ -107,7 +107,10 @@ cl_gun:: cl_footsteps:: Controls footstep sounds. When using Q2PRO protocol, disabling this saves some bandwidth since the server stops sending footstep events at all. - Default value is 1 (enabled). + Default value is 1. + - 0 — footsteps disabled + - 1 — use custom footsteps per surface (if found) + - 2 — use default footstep sound cl_updaterate:: Specifies the perferred update rate requested from Q2PRO servers. Only used @@ -265,6 +268,9 @@ cl_gun_y:: cl_gun_z:: Specifies custom gun model offset. Default value is 0. +cl_muzzleflashes:: + Specifies if muzzleflash effects are enabled. Default value is 1. + Sound Subsystem ~~~~~~~~~~~~~~~ diff --git a/inc/client/client.h b/inc/client/client.h index 6a3a3a0da..f7a35dd7e 100644 --- a/inc/client/client.h +++ b/inc/client/client.h @@ -100,6 +100,8 @@ void Con_Close(bool force); void SCR_BeginLoadingPlaque(void); void SCR_EndLoadingPlaque(void); +int SCR_CheckForCinematic(const char *name); + void SCR_ModeChanged(void); void SCR_UpdateScreen(void); @@ -150,5 +152,6 @@ float V_CalcFov(float fov_x, float width, float height); #define SCR_BeginLoadingPlaque() (void)0 #define SCR_EndLoadingPlaque() (void)0 +#define SCR_CheckForCinematic(name) Q_ERR_SUCCESS #endif // !USE_CLIENT diff --git a/inc/client/sound/sound.h b/inc/client/sound/sound.h index b99df01bf..33ec925df 100644 --- a/inc/client/sound/sound.h +++ b/inc/client/sound/sound.h @@ -38,9 +38,12 @@ void S_BeginRegistration(void); qhandle_t S_RegisterSound(const char *sample); void S_EndRegistration(void); +#define MAX_RAW_SAMPLES 8192 + void S_RawSamples(int samples, int rate, int width, int channels, const byte *data); +int S_GetSampleRate(void); -#if USE_OGG +#if USE_AVCODEC void OGG_Play(void); void OGG_Stop(void); void OGG_Update(void); diff --git a/inc/common/bsp.h b/inc/common/bsp.h index 4fa5276d6..34b57bfb6 100644 --- a/inc/common/bsp.h +++ b/inc/common/bsp.h @@ -64,12 +64,12 @@ typedef struct { } mvertex_t; typedef struct { - mvertex_t *v[2]; + uint32_t v[2]; } medge_t; typedef struct { - medge_t *edge; - int vert; + uint32_t edge: 31; + uint32_t vert: 1; } msurfedge_t; #define SURF_TRANS_MASK (SURF_TRANS33 | SURF_TRANS66) @@ -110,6 +110,7 @@ typedef struct mface_s { unsigned dlightframe; uint64_t dlightbits; + struct lightmap_s *light_m; struct entity_s *entity; struct mface_s *next; } mface_t; diff --git a/inc/common/common.h b/inc/common/common.h index ac0a884b5..2067aebaa 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -119,17 +119,17 @@ void G_InitializeExtensions(void); #if USE_DEBUG #define Com_DPrintf(...) \ - if (developer && developer->integer > 0) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 0) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDPrintf(...) \ - if (developer && developer->integer > 1) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 1) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDDPrintf(...) \ - if (developer && developer->integer > 2) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 2) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDDDPrintf(...) \ - if (developer && developer->integer > 3) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 3) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define Com_DPrintf(...) ((void)0) #define Com_DDPrintf(...) ((void)0) diff --git a/inc/common/hash_map.h b/inc/common/hash_map.h index 6c629ecf9..bd6961253 100644 --- a/inc/common/hash_map.h +++ b/inc/common/hash_map.h @@ -22,11 +22,11 @@ typedef struct hash_map_s hash_map_t; hash_map_t *HashMap_CreateImpl(const uint32_t key_size, const uint32_t value_size, uint32_t (*hasher)(const void *const), - qboolean (*comp)(const void *const, const void *const)); + bool (*comp)(const void *const, const void *const)); void HashMap_Destroy(hash_map_t *map); -void HashMap_Reserve(hash_map_t *map, int capacity); -qboolean HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value); -qboolean HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key); +void HashMap_Reserve(hash_map_t *map, uint32_t capacity); +bool HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value); +bool HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key); void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *const key); uint32_t HashMap_Size(hash_map_t *map); void *HashMap_GetKeyImpl(hash_map_t *map, uint32_t index); @@ -119,7 +119,7 @@ static inline uint32_t HashStr(const void *const val) return hval; } -static inline qboolean HashStrCmp(const void *const a, const void *const b) +static inline bool HashStrCmp(const void *const a, const void *const b) { const char *str_a = *(const char **)a; const char *str_b = *(const char **)b; diff --git a/inc/common/msg.h b/inc/common/msg.h index f8d7b8e4b..b52aec7b6 100644 --- a/inc/common/msg.h +++ b/inc/common/msg.h @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/protocol.h" #include "common/sizebuf.h" -#define MAX_PACKETENTITY_BYTES 64 // rough estimate +#define MAX_PACKETENTITY_BYTES 64 // 62 bytes worst case + margin // entity and player states are pre-quantized before sending to make delta // comparsion easier @@ -200,9 +200,9 @@ static inline int MSG_PackSolid16(const vec3_t mins, const vec3_t maxs) int zd = -mins[2] / 8; int zu = (maxs[2] + 32) / 8; - clamp(x, 1, 31); - clamp(zd, 1, 31); - clamp(zu, 1, 63); + x = Q_clip(x, 1, 31); + zd = Q_clip(zd, 1, 31); + zu = Q_clip(zu, 1, 63); return (zu << 10) | (zd << 5) | x; } @@ -213,9 +213,9 @@ static inline uint32_t MSG_PackSolid32_Ver1(const vec3_t mins, const vec3_t maxs int zd = -mins[2]; int zu = maxs[2] + 32768; - clamp(x, 1, 255); - clamp(zd, 0, 255); - clamp(zu, 0, 65535); + x = Q_clip(x, 1, 255); + zd = Q_clip_uint8(zd); + zu = Q_clip_uint16(zu); return ((uint32_t)zu << 16) | (zd << 8) | x; } @@ -227,10 +227,10 @@ static inline uint32_t MSG_PackSolid32_Ver2(const vec3_t mins, const vec3_t maxs int zd = -mins[2]; int zu = maxs[2] + 32; - clamp(x, 1, 255); - clamp(y, 1, 255); - clamp(zd, 0, 255); - clamp(zu, 0, 255); + x = Q_clip(x, 1, 255); + y = Q_clip(y, 1, 255); + zd = Q_clip_uint8(zd); + zu = Q_clip_uint8(zu); return MakeLittleLong(x, y, zd, zu); } diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index fd43c2f2c..09d6ede1a 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -22,17 +22,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/net/net.h" #include "common/sizebuf.h" -typedef enum netchan_type_e { +typedef enum { NETCHAN_OLD, NETCHAN_NEW } netchan_type_t; -typedef struct netchan_s { +typedef struct { netchan_type_t type; int protocol; - size_t maxpacketlen; - - bool fatal_error; + unsigned maxpacketlen; netsrc_t sock; @@ -43,12 +41,12 @@ typedef struct netchan_s { unsigned last_received; // for timeouts unsigned last_sent; // for retransmits - netadr_t remote_address; int qport; // qport value to write when transmitting + netadr_t remote_address; sizebuf_t message; // writing buffer for reliable data - size_t reliable_length; + unsigned reliable_length; bool reliable_ack_pending; // set to true each time reliable is received bool fragment_pending; @@ -64,22 +62,11 @@ typedef struct netchan_s { int last_reliable_sequence; // sequence number of last send int fragment_sequence; - byte *message_buf; // leave space for header - // message is copied to this buffer when it is first transfered byte *reliable_buf; // unacked reliable message sizebuf_t fragment_in; - byte *fragment_in_buf; - sizebuf_t fragment_out; - byte *fragment_out_buf; - - // common methods - size_t (*Transmit)(struct netchan_s *, size_t, const void *, int); - size_t (*TransmitNextFragment)(struct netchan_s *); - bool (*Process)(struct netchan_s *); - bool (*ShouldUpdate)(struct netchan_s *); } netchan_t; extern cvar_t *net_qport; @@ -89,9 +76,13 @@ extern cvar_t *net_chantype; void Netchan_Init(void); void Netchan_OutOfBand(netsrc_t sock, const netadr_t *adr, const char *format, ...) q_printf(3, 4); -void Netchan_Setup(netchan_t *netchan, netsrc_t sock, netchan_type_t type, +void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol); -void Netchan_Close(netchan_t *netchan); +int Netchan_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets); +int Netchan_TransmitNextFragment(netchan_t *chan); +bool Netchan_Process(netchan_t *chan); +bool Netchan_ShouldUpdate(netchan_t *chan); +void Netchan_Close(netchan_t *chan); #define OOB_PRINT(sock, addr, data) \ NET_SendPacket(sock, CONST_STR_LEN("\xff\xff\xff\xff" data), addr) diff --git a/inc/common/protocol.h b/inc/common/protocol.h index 94ae3e5ac..27db7bc43 100644 --- a/inc/common/protocol.h +++ b/inc/common/protocol.h @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // protocol.h -- communications protocols // -#define MAX_MSGLEN 0x10000 // max length of a message, 64k +#define MAX_MSGLEN 0x8000 // max length of a message, 32 KiB #define PROTOCOL_VERSION_OLD 26 #define PROTOCOL_VERSION_DEFAULT 34 @@ -342,44 +342,44 @@ typedef enum { // entity_state_t communication // try to pack the common update flags into the first byte -#define U_ORIGIN1 BIT(0) -#define U_ORIGIN2 BIT(1) -#define U_ANGLE2 BIT(2) -#define U_ANGLE3 BIT(3) -#define U_FRAME8 BIT(4) // frame is a byte -#define U_EVENT BIT(5) -#define U_REMOVE BIT(6) // REMOVE this entity, don't add it -#define U_MOREBITS1 BIT(7) // read one additional byte +#define U_ORIGIN1 BIT_ULL(0) +#define U_ORIGIN2 BIT_ULL(1) +#define U_ANGLE2 BIT_ULL(2) +#define U_ANGLE3 BIT_ULL(3) +#define U_FRAME8 BIT_ULL(4) // frame is a byte +#define U_EVENT BIT_ULL(5) +#define U_REMOVE BIT_ULL(6) // REMOVE this entity, don't add it +#define U_MOREBITS1 BIT_ULL(7) // read one additional byte // second byte -#define U_NUMBER16 BIT(8) // NUMBER8 is implicit if not set -#define U_ORIGIN3 BIT(9) -#define U_ANGLE1 BIT(10) -#define U_MODEL BIT(11) -#define U_RENDERFX8 BIT(12) // fullbright, etc -#define U_ANGLE16 BIT(13) -#define U_EFFECTS8 BIT(14) // autorotate, trails, etc -#define U_MOREBITS2 BIT(15) // read one additional byte +#define U_NUMBER16 BIT_ULL(8) // NUMBER8 is implicit if not set +#define U_ORIGIN3 BIT_ULL(9) +#define U_ANGLE1 BIT_ULL(10) +#define U_MODEL BIT_ULL(11) +#define U_RENDERFX8 BIT_ULL(12) // fullbright, etc +#define U_ANGLE16 BIT_ULL(13) +#define U_EFFECTS8 BIT_ULL(14) // autorotate, trails, etc +#define U_MOREBITS2 BIT_ULL(15) // read one additional byte // third byte -#define U_SKIN8 BIT(16) -#define U_FRAME16 BIT(17) // frame is a short -#define U_RENDERFX16 BIT(18) // 8 + 16 = 32 -#define U_EFFECTS16 BIT(19) // 8 + 16 = 32 -#define U_MODEL2 BIT(20) // weapons, flags, etc -#define U_MODEL3 BIT(21) -#define U_MODEL4 BIT(22) -#define U_MOREBITS3 BIT(23) // read one additional byte +#define U_SKIN8 BIT_ULL(16) +#define U_FRAME16 BIT_ULL(17) // frame is a short +#define U_RENDERFX16 BIT_ULL(18) // 8 + 16 = 32 +#define U_EFFECTS16 BIT_ULL(19) // 8 + 16 = 32 +#define U_MODEL2 BIT_ULL(20) // weapons, flags, etc +#define U_MODEL3 BIT_ULL(21) +#define U_MODEL4 BIT_ULL(22) +#define U_MOREBITS3 BIT_ULL(23) // read one additional byte // fourth byte -#define U_OLDORIGIN BIT(24) // FIXME: get rid of this -#define U_SKIN16 BIT(25) -#define U_SOUND BIT(26) -#define U_SOLID BIT(27) -#define U_MODEL16 BIT(28) -#define U_MOREFX8 BIT(29) -#define U_ALPHA BIT(30) -#define U_MOREBITS4 BIT(31) // read one additional byte +#define U_OLDORIGIN BIT_ULL(24) // FIXME: get rid of this +#define U_SKIN16 BIT_ULL(25) +#define U_SOUND BIT_ULL(26) +#define U_SOLID BIT_ULL(27) +#define U_MODEL16 BIT_ULL(28) +#define U_MOREFX8 BIT_ULL(29) +#define U_ALPHA BIT_ULL(30) +#define U_MOREBITS4 BIT_ULL(31) // read one additional byte // fifth byte #define U_SCALE BIT_ULL(32) diff --git a/inc/common/sizebuf.h b/inc/common/sizebuf.h index 076a1bb52..91348c15f 100644 --- a/inc/common/sizebuf.h +++ b/inc/common/sizebuf.h @@ -22,12 +22,12 @@ typedef struct { bool allowoverflow; bool allowunderflow; bool overflowed; // set to true if the buffer size failed - byte *data; - size_t maxsize; - size_t cursize; - size_t readcount; + uint32_t maxsize; + uint32_t cursize; + uint32_t readcount; uint32_t bits_buf; uint32_t bits_left; + byte *data; const char *tag; // for debugging } sizebuf_t; @@ -40,12 +40,13 @@ void SZ_WriteShort(sizebuf_t *sb, int c); void SZ_WriteLong(sizebuf_t *sb, int c); void SZ_WriteString(sizebuf_t *sb, const char *s); -static inline void *SZ_Write(sizebuf_t *buf, const void *data, size_t len) +static inline void SZ_Write(sizebuf_t *buf, const void *data, size_t len) { - return memcpy(SZ_GetSpace(buf, len), data, len); + if (len) + memcpy(SZ_GetSpace(buf, len), data, len); } -static inline size_t SZ_Remaining(const sizebuf_t *buf) +static inline uint32_t SZ_Remaining(const sizebuf_t *buf) { if (buf->readcount > buf->cursize) return 0; diff --git a/inc/common/utils.h b/inc/common/utils.h index 7966ce477..23a9bcac0 100644 --- a/inc/common/utils.h +++ b/inc/common/utils.h @@ -81,3 +81,18 @@ static inline size_t CS_SIZE(const cs_remap_t *csr, int cs) return MAX_QPATH; } + +#if USE_FPS +typedef struct frametime_s { + int time; // variable server frame time + int div; // BASE_FRAMETIME/frametime +} frametime_t; + +// Compute frametime based on requested frame rate +static inline frametime_t Com_ComputeFrametime(int rate) +{ + int framediv = Q_clip(rate / BASE_FRAMERATE, 1, MAX_FRAMEDIV); + return (frametime_t){ .time = BASE_FRAMETIME / framediv, .div = framediv }; +} + +#endif // USE_FPS diff --git a/inc/common/zone.h b/inc/common/zone.h index 703e73009..443a5efc2 100644 --- a/inc/common/zone.h +++ b/inc/common/zone.h @@ -45,6 +45,7 @@ void Z_Init(void); void Z_Free(void *ptr); void Z_Freep(void *ptr); void *Z_Realloc(void *ptr, size_t size); +void *Z_ReallocArray(void *ptr, size_t nmemb, size_t size); void *Z_Malloc(size_t size) q_malloc; void *Z_Mallocz(size_t size) q_malloc; void *Z_TagMalloc(size_t size, memtag_t tag) q_malloc; diff --git a/inc/shared/platform.h b/inc/shared/platform.h index 9a1ef79c8..2544523ad 100644 --- a/inc/shared/platform.h +++ b/inc/shared/platform.h @@ -107,6 +107,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #else #define q_sentinel #endif +#define q_cold __attribute__((cold)) #define q_likely(x) __builtin_expect(!!(x), 1) #define q_unlikely(x) __builtin_expect(!!(x), 0) @@ -138,6 +139,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define q_noinline #define q_malloc #define q_sentinel +#define q_cold #define q_likely(x) (x) #define q_unlikely(x) (x) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 04591ec69..95368dba5 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -228,7 +228,7 @@ void Q_strncatz (char *dest, const char *src, size_t size ); void Com_LPrintf(print_type_t type, const char *fmt, ...) q_printf(2, 3); void Com_Error(error_type_t code, const char *fmt, ...) -q_noreturn q_printf(2, 3); +q_cold q_noreturn q_printf(2, 3); #define Com_Printf(...) Com_LPrintf(PRINT_ALL, __VA_ARGS__) #define Com_WPrintf(...) Com_LPrintf(PRINT_WARNING, __VA_ARGS__) @@ -239,10 +239,16 @@ q_noreturn q_printf(2, 3); do { if (!(expr)) Com_Error(ERR_FATAL, "%s: assertion `%s' failed", __func__, #expr); } while (0) // game print flags -#define PRINT_LOW 0 // pickup messages -#define PRINT_MEDIUM 1 // death messages -#define PRINT_HIGH 2 // critical messages -#define PRINT_CHAT 3 // chat messages +enum { + PRINT_LOW, // pickup messages + PRINT_MEDIUM, // death messages + PRINT_HIGH, // critical messages + PRINT_CHAT, // chat messages +// KEX + PRINT_TYPEWRITER, + PRINT_CENTER, +// KEX +}; // destination class for gi.multicast() typedef enum { @@ -449,12 +455,65 @@ void Q_srand(uint32_t seed); uint32_t Q_rand(void); uint32_t Q_rand_uniform(uint32_t n); -#define clamp(a,b,c) ((a)<(b)?(a)=(b):(a)>(c)?(a)=(c):(a)) -#define cclamp(a,b,c) ((b)>(c)?clamp(a,c,b):clamp(a,b,c)) - static inline int Q_clip(int a, int b, int c) { - return clamp(a, b, c); + if (a < b) + return b; + if (a > c) + return c; + return a; +} + +static inline float Q_clipf(float a, float b, float c) +{ +#if defined(__GNUC__) && defined(__SSE__) + __asm__("maxss %1, %0 \n\t" + "minss %2, %0 \n\t" + : "+&x"(a) : "xm"(b), "xm"(c)); + return a; +#else + if (a < b) + return b; + if (a > c) + return c; + return a; +#endif +} + +static inline float Q_circ_clipf(float a, float b, float c) +{ + return b > c ? Q_clipf(a, c, b) : Q_clipf(a, b, c); +} + +static inline int8_t Q_clip_int8(int a) +{ + return ((a + 0x80U) & ~0xFF) ? (a >> 31) ^ 0x7F : a; +} + +static inline int16_t Q_clip_int16(int a) +{ + return ((a + 0x8000U) & ~0xFFFF) ? (a >> 31) ^ 0x7FFF : a; +} + +static inline int32_t Q_clip_int32(int64_t a) +{ + return ((a + 0x80000000ULL) & ~0xFFFFFFFFULL) ? (a >> 63) ^ 0x7FFFFFFF : a; +} + +#ifdef _LP64 +#define Q_clipl_int32(a) Q_clip_int32(a) +#else +#define Q_clipl_int32(a) (a) +#endif + +static inline uint8_t Q_clip_uint8(int a) +{ + return (a & ~0xFF) ? ~a >> 31 : a; +} + +static inline uint16_t Q_clip_uint16(int a) +{ + return (a & ~0xFFFF) ? ~a >> 31 : a; } #ifndef max @@ -577,9 +636,29 @@ char *Q_strcasestr(const char *s1, const char *s2); #define Q_stricmpn Q_strncasecmp #define Q_stristr Q_strcasestr +#ifdef HAVE_STRCHRNUL +#define Q_strchrnul strchrnul +#else char *Q_strchrnul(const char *s, int c); +#endif + +#ifdef HAVE_MEMCCPY +#define Q_memccpy memccpy +#else void *Q_memccpy(void *dst, const void *src, int c, size_t size); +#endif + +#ifdef HAVE_STRNLEN +#define Q_strnlen strnlen +#else size_t Q_strnlen(const char *s, size_t maxlen); +#endif + +#ifdef _WIN32 +#define Q_atoi(s) atoi(s) +#else +int Q_atoi(const char *s); +#endif char *COM_SkipPath(const char *pathname); size_t COM_StripExtension(char *out, const char *in, size_t size); @@ -663,6 +742,11 @@ static inline float LongToFloat(uint32_t l) return dat.f; } +static inline int32_t SignExtend(uint32_t v, int bits) +{ + return (int32_t)(v << (32 - bits)) >> (32 - bits); +} + #if USE_LITTLE_ENDIAN #define BigShort ShortSwap #define BigLong LongSwap @@ -1110,10 +1194,14 @@ enum { MZ_BLUEHYPERBLASTER, MZ_PHALANX, +// KEX + MZ_BFG2, + MZ_PHALANX2, + //ROGUE MZ_ETF_RIFLE = 30, - MZ_UNUSED, - MZ_SHOTGUN2, + MZ_PROX, // KEX + MZ_SHOTGUN2, // MZ_ETF_RIFLE_2 in KEX MZ_HEATBEAM, MZ_BLASTER2, MZ_TRACKER, diff --git a/inc/system/pthread.h b/inc/system/pthread.h index 62b88e524..bb6fc18e7 100644 --- a/inc/system/pthread.h +++ b/inc/system/pthread.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define WIN32_LEAN_AND_MEAN #include +#include #include #define PTHREAD_MUTEX_INITIALIZER {0} @@ -30,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc., typedef void pthread_attr_t; typedef void pthread_mutexattr_t; typedef void pthread_condattr_t; -typedef unsigned int pthread_t; typedef struct { SRWLOCK srw; @@ -40,6 +40,37 @@ typedef struct { CONDITION_VARIABLE cond; } pthread_cond_t; +typedef struct { + void *(*func)(void *); + void *arg, *ret; + HANDLE handle; +} pthread_t; + +static unsigned __stdcall thread_func(void *arg) +{ + pthread_t *t = arg; + t->ret = t->func(t->arg); + return 0; +} + +static inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + thread->func = start_routine; + thread->arg = arg; + thread->handle = (HANDLE)_beginthreadex(NULL, 0, thread_func, thread, 0, NULL); + return thread->handle ? 0 : EAGAIN; +} + +static inline int pthread_join(pthread_t thread, void **retval) +{ + int ret = WaitForSingleObject(thread.handle, INFINITE); + CloseHandle(thread.handle); + if (retval) + *retval = thread.ret; + return ret ? EINVAL : 0; +} + static inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) { InitializeSRWLock(&mutex->srw); @@ -90,11 +121,6 @@ static inline int pthread_cond_destroy(pthread_cond_t *cond) return 0; } -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg); - -int pthread_join(pthread_t thread, void **retval); - #else #include #endif diff --git a/meson.build b/meson.build index cfbc5fc5d..dd69434a1 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project('q2pro', 'c', version: run_command(find_program('python3'), 'version.py', check: true).stdout().strip(), meson_version: '>= 0.59.0', default_options: [ - 'c_std=gnu99', + meson.version().version_compare('>=1.3.0') ? 'c_std=gnu11,c11' : 'c_std=gnu11', 'buildtype=debugoptimized', ], ) @@ -324,7 +324,7 @@ fallback_opt = ['default_library=static'] zlib = dependency('zlib', required: get_option('zlib'), - default_options: fallback_opt, + default_options: fallback_opt + [ 'tests=disabled' ], ) if not zlib.found() @@ -364,7 +364,7 @@ game_deps = [zlib] jpeg = dependency('libjpeg', required: get_option('libjpeg'), - default_options: fallback_opt, + default_options: fallback_opt + [ 'jpeg-turbo=disabled', 'tests=disabled' ] ) if jpeg.found() @@ -409,21 +409,6 @@ if host_machine.system() == 'darwin' client_deps += opengl endif -ogg = dependency('ogg', - required: get_option('ogg'), - default_options: fallback_opt, -) -vorbisfile = dependency('vorbisfile', - required: get_option('ogg'), - default_options: fallback_opt, -) -if ogg.found() and vorbisfile.found() - client_src += 'src/client/sound/ogg.c' - client_deps += ogg.partial_dependency(compile_args: true, includes: true) - client_deps += vorbisfile - config.set10('USE_OGG', true) -endif - # require FFmpeg >= 5.1.3 avcodec_opt = get_option('avcodec') avcodec = dependency('libavcodec', version: '>= 59.37.100', required: avcodec_opt) @@ -432,7 +417,7 @@ avutil = dependency('libavutil', version: '>= 57.28.100', required: avcodec_opt) swresample = dependency('libswresample', version: '>= 4.7.100', required: avcodec_opt) swscale = dependency('libswscale', version: '>= 6.7.100', required: avcodec_opt) if avcodec.found() and avformat.found() and avutil.found() and swresample.found() and swscale.found() - client_src += 'src/client/ffcin.c' + client_src += ['src/client/ffcin.c', 'src/client/sound/ogg.c'] client_deps += [avcodec, avformat, avutil, swresample, swscale] config.set10('USE_AVCODEC', true) else @@ -616,7 +601,6 @@ summary({ 'md5' : config.get('USE_MD5', 0) != 0, 'mvd-client' : config.get('USE_MVD_CLIENT', 0) != 0, 'mvd-server' : config.get('USE_MVD_SERVER', 0) != 0, - 'ogg' : config.get('USE_OGG', 0) != 0, 'openal' : config.get('USE_OPENAL', 0) != 0, 'packetdup-hack' : config.get('USE_PACKETDUP', 0) != 0, 'save-games' : config.get('USE_SAVEGAMES', 0) != 0, diff --git a/meson_options.txt b/meson_options.txt index 55bbfb4fb..729b33e83 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -106,11 +106,6 @@ option('mvd-server', description: 'Enable local MVD recording and MVD/GTV server functionality. '+ 'Use this for hosting a GTV-capable game server.') -option('ogg', - type: 'feature', - value: 'auto', - description: 'Ogg Vorbis music and sound effects support') - option('openal', type: 'feature', value: 'auto', diff --git a/src/client/ascii.c b/src/client/ascii.c index b574b50e9..a5e42c533 100644 --- a/src/client/ascii.c +++ b/src/client/ascii.c @@ -111,19 +111,19 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (token[0] == 'x') { if (token[1] == 'l') { token = COM_Parse(&s); - x = atoi(token) / 8; + x = Q_atoi(token) / 8; continue; } if (token[1] == 'r') { token = COM_Parse(&s); - x = TH_WIDTH + atoi(token) / 8; + x = TH_WIDTH + Q_atoi(token) / 8; continue; } if (token[1] == 'v') { token = COM_Parse(&s); - x = TH_WIDTH / 2 - 20 + atoi(token) / 8; + x = TH_WIDTH / 2 - 20 + Q_atoi(token) / 8; continue; } } @@ -131,19 +131,19 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (token[0] == 'y') { if (token[1] == 't') { token = COM_Parse(&s); - y = atoi(token) / 8; + y = Q_atoi(token) / 8; continue; } if (token[1] == 'b') { token = COM_Parse(&s); - y = TH_HEIGHT + atoi(token) / 8; + y = TH_HEIGHT + Q_atoi(token) / 8; continue; } if (token[1] == 'v') { token = COM_Parse(&s); - y = TH_HEIGHT / 2 - 15 + atoi(token) / 8; + y = TH_HEIGHT / 2 - 15 + Q_atoi(token) / 8; continue; } } @@ -160,25 +160,25 @@ static void TH_DrawLayoutString(char *dst, const char *s) int score, ping, time; token = COM_Parse(&s); - x = TH_WIDTH / 2 - 20 + atoi(token) / 8; + x = TH_WIDTH / 2 - 20 + Q_atoi(token) / 8; token = COM_Parse(&s); - y = TH_HEIGHT / 2 - 15 + atoi(token) / 8; + y = TH_HEIGHT / 2 - 15 + Q_atoi(token) / 8; token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); token = COM_Parse(&s); - time = atoi(token); + time = Q_atoi(token); len = strlen(ci->name); TH_DrawString(dst, x + 4, y, ci->name, len); @@ -196,22 +196,22 @@ static void TH_DrawLayoutString(char *dst, const char *s) int score, ping; token = COM_Parse(&s); - x = TH_WIDTH / 2 - 20 + atoi(token) / 8; + x = TH_WIDTH / 2 - 20 + Q_atoi(token) / 8; token = COM_Parse(&s); - y = TH_HEIGHT / 2 - 15 + atoi(token) / 8; + y = TH_HEIGHT / 2 - 15 + Q_atoi(token) / 8; token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); if (ping > 999) ping = 999; @@ -230,11 +230,11 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "num")) { // draw a number token = COM_Parse(&s); - width = atoi(token); + width = Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for num: %i", __func__, value); } value = cl.frame.ps.stats[value]; TH_DrawNumber(dst, x, y, width, value); @@ -243,13 +243,13 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "stat_string")) { token = COM_Parse(&s); - index = atoi(token); + index = Q_atoi(token); if (index < 0 || index >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid string index", __func__); + Com_Error(ERR_DROP, "%s: invalid string index for stat_string: %i", __func__, index); } index = cl.frame.ps.stats[index]; if (index < 0 || index >= cl.csr.end) { - Com_Error(ERR_DROP, "%s: invalid string index", __func__); + Com_Error(ERR_DROP, "%s: invalid string index for stat_string: %i", __func__, index); } len = strlen(cl.configstrings[index]); TH_DrawString(dst, x, y, cl.configstrings[index], len); @@ -272,9 +272,9 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "if")) { token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for if: %i", __func__, value); } value = cl.frame.ps.stats[value]; if (!value) { // skip to endif diff --git a/src/client/cin.c b/src/client/cin.c index 2e62f0281..82fe354d5 100644 --- a/src/client/cin.c +++ b/src/client/cin.c @@ -56,6 +56,16 @@ typedef struct { static cinematic_t cin; +/* +================== +SCR_InitCinematics +================== +*/ +void SCR_InitCinematics(void) +{ + // nothing to do here +} + /* ================== SCR_StopCinematic @@ -63,6 +73,9 @@ SCR_StopCinematic */ void SCR_StopCinematic(void) { + if (cin.pic) + R_UpdateRawPic(0, 0, NULL); + Z_Free(cin.pic); FS_CloseFile(cin.file); memset(&cin, 0, sizeof(cin)); @@ -445,3 +458,21 @@ void SCR_PlayCinematic(const char *name) finish: SCR_FinishCinematic(); } + +/* +================== +SCR_CheckForCinematic + +Called by the server to check for cinematic existence. +Name should be in format "video/.cin". +================== +*/ +int SCR_CheckForCinematic(const char *name) +{ + int ret = FS_LoadFile(name, NULL); + + if (ret == Q_ERR(EFBIG)) + ret = Q_ERR_SUCCESS; + + return ret; +} diff --git a/src/client/client.h b/src/client/client.h index a694f19b2..287b1d2b3 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -75,6 +75,7 @@ typedef struct centity_s { centity_state_t prev; // will always be valid, but might just be a copy of current vec3_t mins, maxs; + float radius; // from mid point int serverframe; // if not current, this ent isn't in the frame @@ -138,10 +139,10 @@ typedef struct { // variable server FPS #if USE_FPS -#define CL_FRAMETIME cl.frametime +#define CL_FRAMETIME cl.frametime.time #define CL_1_FRAMETIME cl.frametime_inv -#define CL_FRAMEDIV cl.framediv -#define CL_FRAMESYNC !(cl.frame.number % cl.framediv) +#define CL_FRAMEDIV cl.frametime.div +#define CL_FRAMESYNC !(cl.frame.number % cl.frametime.div) #define CL_KEYPS &cl.keyframe.ps #define CL_OLDKEYPS &cl.oldkeyframe.ps #define CL_KEYLERPFRAC cl.keylerpfrac @@ -272,9 +273,8 @@ typedef struct client_state_s { pmoveParams_t pmp; #if USE_FPS - int frametime; // variable server frame time + frametime_t frametime; float frametime_inv; // 1/frametime - int framediv; // BASE_FRAMETIME/frametime #endif qboolean view_predict; @@ -311,6 +311,17 @@ typedef struct client_state_s { cvarsync_t cvarsync[CVARSYNC_MAX]; bool need_powerscreen_scale; + + // data for view weapon + struct { + struct { + qhandle_t model; + int time; + float roll, scale; + vec3_t offset; + } muzzle; + } weapon; + } client_state_t; extern client_state_t cl; @@ -375,8 +386,8 @@ typedef struct { typedef struct { int framenum; + unsigned msglen; int64_t filepos; - size_t msglen; byte data[1]; } demosnap_t; @@ -488,7 +499,7 @@ typedef struct client_static_s { connstate_t state; netstream_t stream; - size_t msglen; + unsigned msglen; player_packed_t ps; entity_packed_t entities[MAX_EDICTS]; @@ -542,14 +553,14 @@ extern cvar_t *cl_enhanced_footsteps; #if USE_DEBUG #define SHOWNET(level, ...) \ - if (cl_shownet->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (cl_shownet->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWCLAMP(level, ...) \ - if (cl_showclamp->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (cl_showclamp->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWMISS(...) \ - if (cl_showmiss->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (cl_showmiss->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) extern cvar_t *cl_shownet; extern cvar_t *cl_showmiss; extern cvar_t *cl_showclamp; @@ -800,6 +811,26 @@ typedef struct cl_sustain_s { void (*think)(struct cl_sustain_s *self); } cl_sustain_t; +typedef enum { + MFLASH_MACHN, + MFLASH_SHOTG2, + MFLASH_SHOTG, + MFLASH_ROCKET, + MFLASH_RAIL, + MFLASH_LAUNCH, + MFLASH_ETF_RIFLE, + MFLASH_DIST, + MFLASH_BOOMER, + MFLASH_BLAST, // 0 = orange, 1 = blue, 2 = green + MFLASH_BFG, + MFLASH_BEAMER, + + MFLASH_TOTAL +} cl_muzzlefx_t; + +void CL_AddWeaponMuzzleFX(cl_muzzlefx_t fx, const vec3_t offset, float scale); +void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, int skin, float scale); + void CL_SmokeAndFlash(const vec3_t origin); void CL_DrawBeam(const vec3_t org, const vec3_t end, qhandle_t model); void CL_PlayFootstepSfx(int step_id, int entnum, float volume, float attenuation); @@ -872,7 +903,6 @@ void CL_TeleportParticles(const vec3_t org); void CL_ParticleEffect(const vec3_t org, const vec3_t dir, int color, int count); void CL_ParticleEffect2(const vec3_t org, const vec3_t dir, int color, int count); cparticle_t *CL_AllocParticle(void); -void CL_RunParticles(void); void CL_AddParticles(void); cdlight_t *CL_AllocDlight(int key); void CL_AddDLights(void); @@ -894,7 +924,7 @@ void CL_ParticleSteamEffect(const vec3_t org, const vec3_t dir, int color, int c void CL_TrackerTrail(const vec3_t start, const vec3_t end, int particleColor); void CL_TagTrail(const vec3_t start, const vec3_t end, int color); void CL_ColorFlash(const vec3_t pos, int ent, int intensity, float r, float g, float b); -void CL_Tracker_Shell(const vec3_t origin); +void CL_Tracker_Shell(const centity_t *cent, const vec3_t origin); void CL_MonsterPlasma_Shell(const vec3_t origin); void CL_ColorExplosionParticles(const vec3_t org, int color, int run); void CL_ParticleSmokeEffect(const vec3_t org, const vec3_t dir, int color, int count, int magnitude); @@ -978,16 +1008,15 @@ extern vrect_t scr_vrect; // position of render window void SCR_Init(void); void SCR_Shutdown(void); void SCR_UpdateScreen(void); -void SCR_SizeUp(void); -void SCR_SizeDown(void); -void SCR_CenterPrint(const char *str); +void SCR_CenterPrint(const char *str, bool typewrite); +void SCR_ClearCenterPrints(void); void SCR_BeginLoadingPlaque(void); void SCR_EndLoadingPlaque(void); -void SCR_TouchPics(void); void SCR_RegisterMedia(void); void SCR_ModeChanged(void); void SCR_LagSample(void); void SCR_LagClear(void); +void init_lag_graph_dimensions(void); void SCR_SetCrosshairColor(void); float SCR_FadeAlpha(unsigned startTime, unsigned visTime, unsigned fadeTime); @@ -1003,6 +1032,18 @@ int SCR_GetCinematicCrop(unsigned framenum, int64_t filesize); // // cin.c // + +#if USE_AVCODEC + +typedef struct { + const char *ext; + const char *fmt; + int codec_id; +} avformat_t; + +#endif + +void SCR_InitCinematics(void); void SCR_StopCinematic(void); void SCR_FinishCinematic(void); void SCR_RunCinematic(void); diff --git a/src/client/console.c b/src/client/console.c index 1110853c8..05be1de31 100644 --- a/src/client/console.c +++ b/src/client/console.c @@ -366,16 +366,12 @@ If the line width has changed, reformat the buffer. */ void Con_CheckResize(void) { - int width; - con.scale = R_ClampScale(con_scale); con.vidWidth = Q_rint(r_config.width * con.scale); con.vidHeight = Q_rint(r_config.height * con.scale); - width = con.vidWidth / CHAR_WIDTH - 2; - - con.linewidth = clamp(width, 0, CON_LINEWIDTH); + con.linewidth = Q_clip(con.vidWidth / CHAR_WIDTH - 2, 0, CON_LINEWIDTH); con.prompt.inputLine.visibleChars = con.linewidth; con.prompt.widthInChars = con.linewidth; con.chatPrompt.inputLine.visibleChars = con.linewidth; diff --git a/src/client/demo.c b/src/client/demo.c index 858737f4c..31840c692 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -61,7 +61,7 @@ bool CL_WriteDemoMessage(sizebuf_t *buf) if (ret != buf->cursize) goto fail; - Com_DDPrintf("%s: wrote %zu bytes\n", __func__, buf->cursize); + Com_DDPrintf("%s: wrote %u bytes\n", __func__, buf->cursize); SZ_Clear(buf); return true; @@ -104,7 +104,7 @@ static void emit_packet_entities(server_frame_t *from, server_frame_t *to) oldent = newent = NULL; while (newindex < to->numEntities || oldindex < from_num_entities) { if (newindex >= to->numEntities) { - newnum = 9999; + newnum = MAX_EDICTS; } else { i = (to->firstEntity + newindex) & PARSE_ENTITIES_MASK; newent = &cl.entityStates[i]; @@ -112,7 +112,7 @@ static void emit_packet_entities(server_frame_t *from, server_frame_t *to) } if (oldindex >= from_num_entities) { - oldnum = 9999; + oldnum = MAX_EDICTS; } else { i = (from->firstEntity + oldindex) & PARSE_ENTITIES_MASK; oldent = &cl.entityStates[i]; @@ -225,13 +225,13 @@ void CL_EmitDemoFrame(void) emit_delta_frame(oldframe, &cl.frame, lastframe, FRAME_CUR); if (cls.demo.buffer.cursize + msg_write.cursize > cls.demo.buffer.maxsize) { - Com_DPrintf("Demo frame overflowed (%zu + %zu > %zu)\n", + Com_DPrintf("Demo frame overflowed (%u + %u > %u)\n", cls.demo.buffer.cursize, msg_write.cursize, cls.demo.buffer.maxsize); cls.demo.frames_dropped++; // warn the user if drop rate is too high if (cls.demo.frames_written < 10 && cls.demo.frames_dropped == 50) - Com_WPrintf("Too many demo frames don't fit into %zu bytes.\n" + Com_WPrintf("Too many demo frames don't fit into %u bytes.\n" "Try to increase 'cl_demomsglen' value and restart recording.\n", cls.demo.buffer.maxsize); } else { @@ -755,6 +755,7 @@ static void CL_PlayDemo_f(void) cls.state = ca_connected; Q_strlcpy(cls.servername, COM_SkipPath(name), sizeof(cls.servername)); cls.serverAddress.type = NA_LOOPBACK; + cl.csr = cs_remap_old; Con_Popup(true); SCR_UpdateScreen(); @@ -857,10 +858,10 @@ void CL_EmitDemoSnapshot(void) snap->msglen = msg_write.cursize; memcpy(snap->data, msg_write.data, msg_write.cursize); - cls.demo.snapshots = Z_Realloc(cls.demo.snapshots, sizeof(snap) * ALIGN(cls.demo.numsnapshots + 1, MIN_SNAPSHOTS)); + cls.demo.snapshots = Z_Realloc(cls.demo.snapshots, sizeof(cls.demo.snapshots[0]) * ALIGN(cls.demo.numsnapshots + 1, MIN_SNAPSHOTS)); cls.demo.snapshots[cls.demo.numsnapshots++] = snap; - Com_DPrintf("[%d] snaplen %zu\n", cls.demo.frames_read, msg_write.cursize); + Com_DPrintf("[%d] snaplen %u\n", cls.demo.frames_read, msg_write.cursize); SZ_Clear(&msg_write); @@ -983,7 +984,7 @@ static void CL_Seek_f(void) return; } - clamp(percent, 0, 100); + percent = Q_clipf(percent, 0, 100); dest = cls.demo.file_offset + cls.demo.file_size * percent / 100; byte_seek = true; diff --git a/src/client/download.c b/src/client/download.c index bae8849c4..a9d61b301 100644 --- a/src/client/download.c +++ b/src/client/download.c @@ -91,13 +91,20 @@ int CL_QueueDownload(const char *path, dltype_t type) CL_IgnoreDownload Returns true if specified path matches against an entry in download ignore -list. +list. Path should be converted to lower case by the caller. =============== */ bool CL_IgnoreDownload(const char *path) { string_entry_t *entry; + if (!strncmp(path, CONST_STR_LEN("save/"))) + return true; + if (!strncmp(path, CONST_STR_LEN("music/"))) + return true; + if (!strncmp(path, CONST_STR_LEN("video/"))) + return true; + for (entry = cls.download.ignores; entry; entry = entry->next) { if (Com_WildCmp(entry->string, path)) { return true; @@ -309,8 +316,7 @@ static bool inflate_udp_download(byte *data, int size, int decompressed_size) int ret; // initialize stream if not done yet - if (!z->state) - Q_assert(inflateInit2(z, -MAX_WBITS) == Z_OK); + Q_assert(z->state || inflateInit2(z, -MAX_WBITS) == Z_OK); if (!size) return true; diff --git a/src/client/effects.c b/src/client/effects.c index 3ea54a111..f37e7b083 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -164,7 +164,6 @@ void CL_MuzzleFlash(void) centity_t *pl; float volume; char soundname[MAX_QPATH]; - int mk23snd,mp5snd,m4snd,m3snd,hcsnd,ssgsnd; #if USE_DEBUG if (developer->integer) @@ -188,17 +187,20 @@ void CL_MuzzleFlash(void) switch (mz.weapon) { case MZ_BLASTER: // MK23 #if USE_AQTION - mk23snd = atoi(cl_mk23_sound->string); + // New muzzleflash items to test: + // example: CL_AddWeaponMuzzleFX(MFLASH_BLAST, (const vec3_t) { 27.0f, 7.4f, -6.6f }, 8.0f); + //mk23snd = atoi(cl_mk23_sound->string); + //CL_AddWeaponMuzzleFX(MFLASH_BLAST, (const vec3_t) { 27.0f, 7.4f, -6.6f }, 8.0f); - if (mk23snd > MAX_WEAPON_SOUND || mk23snd <= MIN_WEAPON_SOUND) { - mk23snd = MIN_WEAPON_SOUND; + if (cl_mk23_sound->integer > MAX_WEAPON_SOUND || cl_mk23_sound->integer <= MIN_WEAPON_SOUND) { + cl_mk23_sound->integer = MIN_WEAPON_SOUND; } - if (mk23snd == 0) { + if (cl_mk23_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire%i.wav", mk23snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire%i.wav", cl_mk23_sound->integer); break; } #else @@ -207,17 +209,15 @@ void CL_MuzzleFlash(void) case MZ_MACHINEGUN: // MP5/10 Submachinegun #if USE_AQTION - mp5snd = atoi(cl_mp5_sound->string); - - if (mp5snd > MAX_WEAPON_SOUND || mp5snd <= MIN_WEAPON_SOUND) { - mp5snd = MIN_WEAPON_SOUND; + if (cl_mp5_sound->integer > MAX_WEAPON_SOUND || cl_mp5_sound->integer <= MIN_WEAPON_SOUND) { + cl_mp5_sound->integer = MIN_WEAPON_SOUND; } - if (mp5snd == 0) { + if (cl_mp5_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire%i.wav", mp5snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire%i.wav", cl_mp5_sound->integer); break; } #else @@ -226,17 +226,15 @@ void CL_MuzzleFlash(void) case MZ_ROCKET: // M4 Assault Rifle #if USE_AQTION - m4snd = atoi(cl_m4_sound->string); - - if (m4snd > MAX_WEAPON_SOUND || m4snd <= MIN_WEAPON_SOUND) { - m4snd = MIN_WEAPON_SOUND; + if (cl_m4_sound->integer > MAX_WEAPON_SOUND || cl_m4_sound->integer <= MIN_WEAPON_SOUND) { + cl_m4_sound->integer = MIN_WEAPON_SOUND; } - if (m4snd == 0) { + if (cl_m4_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire%i.wav", m4snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire%i.wav", cl_m4_sound->integer); break; } #else @@ -245,17 +243,15 @@ void CL_MuzzleFlash(void) case MZ_SHOTGUN: // M3 Shotgun #if USE_AQTION - m3snd = atoi(cl_m3_sound->string); - - if (m3snd > MAX_WEAPON_SOUND || m3snd <= MIN_WEAPON_SOUND) { - m3snd = MIN_WEAPON_SOUND; + if (cl_m3_sound->integer > MAX_WEAPON_SOUND || cl_m3_sound->integer <= MIN_WEAPON_SOUND) { + cl_m3_sound->integer = MIN_WEAPON_SOUND; } - if (m3snd == 0) { + if (cl_m3_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b%i.wav", m3snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b%i.wav", cl_m3_sound->integer); break; } #else @@ -264,17 +260,15 @@ void CL_MuzzleFlash(void) case MZ_SSHOTGUN: // Handcannon -- needs adjustment for single barrel vs double #if USE_AQTION - hcsnd = atoi(cl_hc_sound->string); - - if (hcsnd > MAX_WEAPON_SOUND || hcsnd <= MIN_WEAPON_SOUND) { - hcsnd = MIN_WEAPON_SOUND; + if (cl_hc_sound->integer > MAX_WEAPON_SOUND || cl_hc_sound->integer <= MIN_WEAPON_SOUND) { + cl_hc_sound->integer = MIN_WEAPON_SOUND; } - if (hcsnd == 0) { + if (cl_hc_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire%i.wav", hcsnd); + Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire%i.wav", cl_hc_sound->integer); break; } #else @@ -283,17 +277,15 @@ void CL_MuzzleFlash(void) case MZ_HYPERBLASTER: // SSG 3000 Sniper Rifle #if USE_AQTION - ssgsnd = atoi(cl_ssg_sound->string); - - if (ssgsnd > MAX_WEAPON_SOUND || ssgsnd <= MIN_WEAPON_SOUND) { - ssgsnd = MIN_WEAPON_SOUND; + if (cl_ssg_sound->integer > MAX_WEAPON_SOUND || cl_ssg_sound->integer <= MIN_WEAPON_SOUND) { + cl_ssg_sound->integer = MIN_WEAPON_SOUND; } - if (ssgsnd == 0) { + if (cl_ssg_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire%i.wav", ssgsnd); + Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire%i.wav", cl_ssg_sound->integer); break; } #else @@ -330,20 +322,27 @@ CL_MuzzleFlash2 void CL_MuzzleFlash2(void) { centity_t *ent; - vec3_t origin; - const vec_t *ofs; + vec3_t ofs, origin, flash_origin; cdlight_t *dl; vec3_t forward, right; char soundname[MAX_QPATH]; + float scale; // locate the origin ent = &cl_entities[mz.entity]; AngleVectors(ent->current.angles, forward, right, NULL); - ofs = monster_flash_offset[mz.weapon]; + + scale = ent->current.scale; + if (!scale) + scale = 1.0f; + + VectorScale(monster_flash_offset[mz.weapon], scale, ofs); origin[0] = ent->current.origin[0] + forward[0] * ofs[0] + right[0] * ofs[1]; origin[1] = ent->current.origin[1] + forward[1] * ofs[0] + right[1] * ofs[1]; origin[2] = ent->current.origin[2] + forward[2] * ofs[0] + right[2] * ofs[1] + ofs[2]; + VectorMA(origin, 4.0f * scale, forward, flash_origin); + dl = CL_AllocDlight(mz.entity); VectorCopy(origin, dl->origin); dl->radius = 200 + (Q_rand() & 31); @@ -376,6 +375,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 18.0f * scale); break; case MZ2_SOLDIER_MACHINEGUN_1: @@ -391,6 +391,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 13.0f * scale); break; case MZ2_GUNNER_MACHINEGUN_1: @@ -405,6 +406,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 24.0f * scale); break; case MZ2_ACTOR_MACHINEGUN_1: @@ -419,6 +421,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_BOSS2_MACHINEGUN_L1: @@ -432,6 +435,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_SOLDIER_BLASTER_1: @@ -446,12 +450,14 @@ void CL_MuzzleFlash2(void) case MZ2_TURRET_BLASTER: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_FLYER_BLASTER_1: case MZ2_FLYER_BLASTER_2: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_MEDIC_BLASTER_1: @@ -469,17 +475,20 @@ void CL_MuzzleFlash2(void) case MZ2_MEDIC_HYPERBLASTER1_12: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_HOVER_BLASTER_1: case MZ2_HOVER_BLASTER_2: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_FLOAT_BLASTER_1: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_SOLDIER_SHOTGUN_1: @@ -494,6 +503,7 @@ void CL_MuzzleFlash2(void) VectorSet(dl->color, 1, 1, 0); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_SHOTG, 0, 17.0f * scale); break; case MZ2_TANK_BLASTER_1: @@ -501,6 +511,7 @@ void CL_MuzzleFlash2(void) case MZ2_TANK_BLASTER_3: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 24.0f * scale); break; case MZ2_TANK_MACHINEGUN_1: @@ -527,12 +538,14 @@ void CL_MuzzleFlash2(void) CL_SmokeAndFlash(origin); Q_snprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + Q_rand() % 5); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 20.0f * scale); break; case MZ2_CHICK_ROCKET_1: case MZ2_TURRET_ROCKET: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ROCKET, 0, 16.0f * scale); break; case MZ2_TANK_ROCKET_1: @@ -540,6 +553,7 @@ void CL_MuzzleFlash2(void) case MZ2_TANK_ROCKET_3: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ROCKET, 0, 28.0f * scale); break; case MZ2_SUPERTANK_ROCKET_1: @@ -555,6 +569,7 @@ void CL_MuzzleFlash2(void) // case MZ2_CARRIER_ROCKET_4: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ROCKET, 0, 28.0f * scale); break; case MZ2_GUNNER_GRENADE_1: @@ -569,6 +584,7 @@ void CL_MuzzleFlash2(void) case MZ2_SUPERTANK_GRENADE_2: VectorSet(dl->color, 1, 0.5f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_LAUNCH, 0, 18.0f * scale); break; case MZ2_GLADIATOR_RAILGUN_1: @@ -580,11 +596,13 @@ void CL_MuzzleFlash2(void) case MZ2_ARACHNID_RAIL_UP1: case MZ2_ARACHNID_RAIL_UP2: VectorSet(dl->color, 0.5f, 0.5f, 1.0f); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_RAIL, 0, 32.0f * scale); break; case MZ2_MAKRON_BFG: VectorSet(dl->color, 0.5f, 1, 0.5f); //S_StartSound (NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BFG, 0, 64.0f * scale); break; case MZ2_MAKRON_BLASTER_1: @@ -606,6 +624,7 @@ void CL_MuzzleFlash2(void) case MZ2_MAKRON_BLASTER_17: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 22.0f * scale); break; case MZ2_JORG_MACHINEGUN_L1: @@ -618,6 +637,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_JORG_MACHINEGUN_R1: @@ -629,10 +649,12 @@ void CL_MuzzleFlash2(void) VectorSet(dl->color, 1, 1, 0); CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_JORG_BFG_1: VectorSet(dl->color, 0.5f, 1, 0.5f); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BFG, 0, 64.0f * scale); break; case MZ2_BOSS2_MACHINEGUN_R1: @@ -645,6 +667,7 @@ void CL_MuzzleFlash2(void) VectorSet(dl->color, 1, 1, 0); CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_STALKER_BLASTER: @@ -701,11 +724,13 @@ void CL_MuzzleFlash2(void) case MZ2_MEDIC_HYPERBLASTER2_12: VectorSet(dl->color, 0, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 2, 22.0f * scale); break; case MZ2_WIDOW_DISRUPTOR: VectorSet(dl->color, -1, -1, -1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_DIST, 0, 32.0f * scale); break; case MZ2_WIDOW_PLASMABEAM: @@ -728,6 +753,7 @@ void CL_MuzzleFlash2(void) dl->radius = 300 + (Q_rand() & 100); VectorSet(dl->color, 1, 1, 0); dl->die = cl.time + 200; + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BEAMER, 0, 32.0f * scale); break; case MZ2_SOLDIER_RIPPER_1: @@ -741,6 +767,7 @@ void CL_MuzzleFlash2(void) case MZ2_SOLDIER_RIPPER_9: VectorSet(dl->color, 1, 0.5f, 0.5f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BOOMER, 0, 32.0f * scale); break; case MZ2_SOLDIER_HYPERGUN_1: @@ -754,17 +781,20 @@ void CL_MuzzleFlash2(void) case MZ2_SOLDIER_HYPERGUN_9: VectorSet(dl->color, 0, 0, 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 1, 8.0f * scale); break; case MZ2_GUARDIAN_BLASTER: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 16.0f * scale); break; case MZ2_GUNCMDR_CHAINGUN_1: case MZ2_GUNCMDR_CHAINGUN_2: VectorSet(dl->color, 0, 0, 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("guncmdr/gcdratck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ETF_RIFLE, 0, 16.0f * scale); break; case MZ2_GUNCMDR_GRENADE_MORTAR_1: @@ -775,6 +805,7 @@ void CL_MuzzleFlash2(void) case MZ2_GUNCMDR_GRENADE_FRONT_3: VectorSet(dl->color, 1, 0.5f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("guncmdr/gcdratck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_LAUNCH, 0, 18.0f * scale); break; } } diff --git a/src/client/entities.c b/src/client/entities.c index 820a6b49b..3e72c4f78 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -79,7 +79,7 @@ entity_update_old(centity_t *ent, const centity_state_t *state, const vec_t *ori // check for new event if (state->event != ent->current.event) ent->event_frame = cl.frame.number; // new - else if (cl.frame.number - ent->event_frame >= cl.framediv) + else if (cl.frame.number - ent->event_frame >= cl.frametime.div) ent->event_frame = cl.frame.number; // refreshed else event = 0; // duplicated @@ -113,7 +113,7 @@ entity_update_old(centity_t *ent, const centity_state_t *state, const vec_t *ori // start alias model animation if (state->frame != ent->current.frame) { ent->prev_frame = ent->current.frame; - ent->anim_start = cl.servertime - cl.frametime; + ent->anim_start = cl.servertime - cl.frametime.time; } #endif @@ -160,9 +160,11 @@ static void parse_entity_update(const centity_state_t *state) MSG_UnpackSolid32_Ver1(state->solid, ent->mins, ent->maxs); else MSG_UnpackSolid16(state->solid, ent->mins, ent->maxs); + ent->radius = Distance(ent->maxs, ent->mins) * 0.5f; } else { VectorClear(ent->mins); VectorClear(ent->maxs); + ent->radius = 0; } // work around Q2PRO server bandwidth optimization @@ -222,22 +224,6 @@ static void parse_entity_event(int number) break; case EV_FOOTSTEP: if (cl_footsteps->integer) { - if (strcmp(cl_enhanced_footsteps->string, "0") == 0) { - CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); - //S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[Q_rand() & 3], 1, ATTN_NORM, 0); - } else { - int r = Q_rand() % 12; - if ( r == cl_laststep ) { - if ( r < 11) { - r++; //use next step if same as last time was generated - } else { - r = 0; //use first stepsound if 12 where used twice - } - } - CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); - //S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[r], 1, ATTN_NORM, 0); - cl_laststep = r; - } CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); } break; @@ -312,6 +298,8 @@ static void set_active_state(void) CL_UpdateFrameTimes(); + IN_Activate(); + if (!cls.demo.playback) { EXEC_TRIGGER(cl_beginmapcmd); Cmd_ExecTrigger("#cl_enterlevel"); @@ -401,7 +389,7 @@ void CL_DeltaFrame(void) framenum = cl.frame.number - cl.serverdelta; cl.servertime = framenum * CL_FRAMETIME; #if USE_FPS - cl.keyservertime = (framenum / cl.framediv) * BASE_FRAMETIME; + cl.keyservertime = (framenum / cl.frametime.div) * BASE_FRAMETIME; #endif // rebuild the list of solid entities for this frame @@ -448,7 +436,7 @@ void CL_DeltaFrame(void) #if USE_FPS if (CL_FRAMESYNC) - check_player_lerp(&cl.oldkeyframe, &cl.keyframe, cl.framediv); + check_player_lerp(&cl.oldkeyframe, &cl.keyframe, cl.frametime.div); #endif CL_CheckPredictionError(); @@ -623,9 +611,9 @@ static void CL_AddPacketEntities(void) } #if USE_AQTION - if (IS_INDICATOR(renderfx) && !cl_indicators->integer && cls.demo.playback) { - goto skip; - } + if (IS_INDICATOR(renderfx) && !cl_indicators->integer && cls.demo.playback) { + goto skip; + } #endif if ((effects & EF_GIB) && !cl_gibs->integer) goto skip; @@ -933,14 +921,13 @@ static void CL_AddPacketEntities(void) // remaster powerscreen is tiny and needs scaling if (cl.need_powerscreen_scale) { - vec3_t forward, mid, size, tmp; + vec3_t forward, mid, tmp; VectorCopy(ent.origin, tmp); - VectorSubtract(cent->maxs, cent->mins, size); VectorAvg(cent->mins, cent->maxs, mid); VectorAdd(ent.origin, mid, ent.origin); AngleVectors(ent.angles, forward, NULL, NULL); - VectorMA(ent.origin, size[1] * 0.5f, forward, ent.origin); - ent.scale = VectorLength(size) * 0.4f; + VectorMA(ent.origin, cent->maxs[0], forward, ent.origin); + ent.scale = cent->radius * 0.8f; ent.flags |= RF_FULLBRIGHT; V_AddEntity(&ent); VectorCopy(tmp, ent.origin); @@ -1012,7 +999,7 @@ static void CL_AddPacketEntities(void) float intensity = 50 + (500 * (sin(cl.time / 500.0f) + 1.0f)); V_AddLight(ent.origin, intensity, -1.0f, -1.0f, -1.0f); } else { - CL_Tracker_Shell(cent->lerp_origin); + CL_Tracker_Shell(cent, ent.origin); V_AddLight(ent.origin, 155, -1.0f, -1.0f, -1.0f); } } else if (effects & EF_TRACKER) { @@ -1141,6 +1128,35 @@ static void CL_AddViewWeapon(void) gun.flags |= flags | RF_TRANSLUCENT; V_AddEntity(&gun); } + + // add muzzle flash + if (!cl.weapon.muzzle.model) + return; + + if (cl.time - cl.weapon.muzzle.time > 50) { + cl.weapon.muzzle.model = 0; + return; + } + + gun.flags = RF_FULLBRIGHT | RF_DEPTHHACK | RF_WEAPONMODEL | RF_TRANSLUCENT; + gun.alpha = 1.0f; + gun.model = cl.weapon.muzzle.model; + gun.skinnum = 0; + gun.scale = cl.weapon.muzzle.scale; + gun.backlerp = 0.0f; + gun.frame = gun.oldframe = 0; + + vec3_t forward, right, up; + AngleVectors(gun.angles, forward, right, up); + + VectorMA(gun.origin, cl.weapon.muzzle.offset[0], forward, gun.origin); + VectorMA(gun.origin, cl.weapon.muzzle.offset[1], right, gun.origin); + VectorMA(gun.origin, cl.weapon.muzzle.offset[2], up, gun.origin); + + VectorCopy(cl.refdef.viewangles, gun.angles); + gun.angles[2] += cl.weapon.muzzle.roll; + + V_AddEntity(&gun); } static void CL_SetupFirstPersonView(void) @@ -1291,7 +1307,7 @@ void CL_CalcViewValues(void) float backlerp = lerp - 1.0f; VectorMA(cl.predicted_origin, backlerp, cl.prediction_error, cl.refdef.vieworg); - LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); + LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); // smooth out stair climbing if (cl.predicted_step < 127 * 0.125f) { @@ -1301,16 +1317,16 @@ void CL_CalcViewValues(void) cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01f; } - if (cl_predict_crouch->integer == 2 || (cl_predict_crouch->integer && cl.view_predict)) - { + if (cl_predict_crouch->integer == 2 || (cl_predict_crouch->integer && cl.view_predict)) + { #if USE_FPS - viewoffset[2] = cl.predicted_viewheight[1]; - viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * cl.keylerpfrac; + viewoffset[2] = cl.predicted_viewheight[1]; + viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * cl.keylerpfrac; #else - viewoffset[2] = cl.predicted_viewheight[1]; - viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * lerp; + viewoffset[2] = cl.predicted_viewheight[1]; + viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * lerp; #endif - } + } } else { int i; @@ -1321,7 +1337,7 @@ void CL_CalcViewValues(void) lerp * (ps->pmove.origin[i] - ops->pmove.origin[i])); } - LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); + LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); } // if not running a demo or on a locked frame, add the local angle movement diff --git a/src/client/ffcin.c b/src/client/ffcin.c index 6d845f205..85c81e0e8 100644 --- a/src/client/ffcin.c +++ b/src/client/ffcin.c @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #define MAX_PACKETS 2048 // max packets in queue -#define MAX_SAMPLES 8192 // max audio samples in frame typedef struct { AVFifo *pkt_list; @@ -39,6 +38,7 @@ typedef struct { unsigned timestamp; int stream_idx; AVFrame *frame; + bool eof; } DecoderState; typedef struct { @@ -66,6 +66,35 @@ typedef struct { static cinematic_t cin; +static const avformat_t formats[] = { + { ".ogv", "ogg", AV_CODEC_ID_THEORA }, + { ".mkv", "matroska", AV_CODEC_ID_NONE }, + { ".mp4", "mp4", AV_CODEC_ID_H264 }, + { ".cin", "idcin", AV_CODEC_ID_IDCIN }, +}; + +static int supported; + +/* +================== +SCR_InitCinematics +================== +*/ +void SCR_InitCinematics(void) +{ + for (int i = 0; i < q_countof(formats); i++) { + const avformat_t *f = &formats[i]; + if (!av_find_input_format(f->fmt)) + continue; + if (f->codec_id != AV_CODEC_ID_NONE && + !avcodec_find_decoder(f->codec_id)) + continue; + supported |= BIT(i); + } + + Com_DPrintf("Supported cinematic formats: %#x\n", supported); +} + static void packet_queue_destroy(PacketQueue *q); /* @@ -75,6 +104,9 @@ SCR_StopCinematic */ void SCR_StopCinematic(void) { + if (cin.video.frame) + R_UpdateRawPic(0, 0, NULL); + avcodec_free_context(&cin.video.dec_ctx); avcodec_free_context(&cin.audio.dec_ctx); @@ -104,7 +136,7 @@ Called when either the cinematic completes, or it is aborted void SCR_FinishCinematic(void) { // stop cinematic, but keep static pic - if (cin.video.frame) { + if (cin.fmt_ctx) { SCR_StopCinematic(); SCR_BeginLoadingPlaque(); } @@ -198,7 +230,7 @@ static int process_audio(void) AVFrame *out = cin.audio.frame; int ret; - out->nb_samples = MAX_SAMPLES; + out->nb_samples = MAX_RAW_SAMPLES; ret = swr_convert_frame(cin.swr_ctx, out, in); if (ret < 0) { Com_EPrintf("Error converting audio: %s\n", av_err2str(ret)); @@ -216,7 +248,7 @@ static int decode_frames(DecoderState *s) AVCodecContext *dec = s->dec_ctx; int ret, video_frames = 0; - if (!dec) + if (!dec || s->eof) return 0; // naive decoding loop: keep reading frames until PTS >= current time @@ -224,19 +256,31 @@ static int decode_frames(DecoderState *s) // no A/V synchronization while (s->timestamp < cls.realtime - cin.start_time) { ret = avcodec_receive_frame(dec, frame); - if (ret == AVERROR_EOF) - return ret; + if (ret == AVERROR_EOF) { + Com_DPrintf("%s from %s decoder\n", av_err2str(ret), + av_get_media_type_string(dec->codec->type)); + s->eof = true; + return 0; + } // do we need a packet? if (ret == AVERROR(EAGAIN)) { - if (packet_queue_get(&s->queue, pkt)) - return cin.eof ? AVERROR_EOF : ret; - - // submit the packet to the decoder - ret = avcodec_send_packet(dec, pkt); - av_packet_unref(pkt); + if (packet_queue_get(&s->queue, pkt) < 0) { + if (cin.eof) { + // enter draining mode + ret = avcodec_send_packet(dec, NULL); + } else { + // wait for more packets... + return 0; + } + } else { + // submit the packet to the decoder + ret = avcodec_send_packet(dec, pkt); + av_packet_unref(pkt); + } if (ret < 0) { - Com_EPrintf("Error submitting a packet for decoding: %s\n", av_err2str(ret)); + Com_EPrintf("Error submitting %s packet for decoding: %s\n", + av_get_media_type_string(dec->codec->type), av_err2str(ret)); return ret; } @@ -244,7 +288,8 @@ static int decode_frames(DecoderState *s) } if (ret < 0) { - Com_EPrintf("Error during decoding: %s\n", av_err2str(ret)); + Com_EPrintf("Error during decoding %s: %s\n", + av_get_media_type_string(dec->codec->type), av_err2str(ret)); return ret; } @@ -306,6 +351,7 @@ static bool SCR_ReadNextFrame(void) ret = av_read_frame(cin.fmt_ctx, pkt); // idcin demuxer returns AVERROR(EIO) on EOF packet... if (ret == AVERROR_EOF || ret == AVERROR(EIO)) { + Com_DPrintf("%s from demuxer\n", av_err2str(ret)); cin.eof = true; break; } @@ -328,12 +374,11 @@ static bool SCR_ReadNextFrame(void) } } - ret = decode_frames(&cin.video); - if (ret < 0 && ret != AVERROR(EAGAIN)) + if (decode_frames(&cin.video) < 0) return false; - - ret = decode_frames(&cin.audio); - if (ret < 0 && ret != AVERROR(EAGAIN)) + if (decode_frames(&cin.audio) < 0) + return false; + if (cin.video.eof && cin.audio.eof) return false; return true; @@ -373,7 +418,7 @@ void SCR_DrawCinematic(void) { R_DrawFill8(0, 0, r_config.width, r_config.height, 0); - if (cin.width > 0 && cin.height > cin.crop) { + if (cin.width > 0 && cin.height > cin.crop && !cin.video.eof) { float scale_w = (float)r_config.width / cin.width; float scale_h = (float)r_config.height / (cin.height - cin.crop); float scale = min(scale_w, scale_h); @@ -404,6 +449,8 @@ static bool open_codec_context(enum AVMediaType type) Com_EPrintf("Couldn't find video stream\n"); return false; } + // if there is no audio, pretend it hit EOF + cin.audio.eof = true; return true; } @@ -412,7 +459,7 @@ static bool open_codec_context(enum AVMediaType type) dec = avcodec_find_decoder(st->codecpar->codec_id); if (!dec) { - Com_EPrintf("Failed to find %s codec\n", av_get_media_type_string(type)); + Com_EPrintf("Failed to find %s codec %s\n", av_get_media_type_string(type), avcodec_get_name(st->codecpar->codec_id)); return false; } @@ -425,12 +472,14 @@ static bool open_codec_context(enum AVMediaType type) ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); if (ret < 0) { Com_EPrintf("Failed to copy %s codec parameters to decoder context\n", av_get_media_type_string(type)); + avcodec_free_context(&dec_ctx); return false; } ret = avcodec_open2(dec_ctx, dec, NULL); if (ret < 0) { Com_EPrintf("Failed to open %s codec\n", av_get_media_type_string(type)); + avcodec_free_context(&dec_ctx); return false; } @@ -488,13 +537,17 @@ static bool open_codec_context(enum AVMediaType type) return false; } + int sample_rate = S_GetSampleRate(); + if (!sample_rate) + sample_rate = dec_ctx->sample_rate; + if (dec_ctx->ch_layout.nb_channels >= 2) out->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; else out->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; out->format = AV_SAMPLE_FMT_S16; - out->sample_rate = dec_ctx->sample_rate; - out->nb_samples = MAX_SAMPLES; + out->sample_rate = sample_rate; + out->nb_samples = MAX_RAW_SAMPLES; ret = av_frame_get_buffer(out, 0); if (ret < 0) { @@ -525,6 +578,7 @@ static bool SCR_StartCinematic(const char *name) int ret; FS_NormalizePathBuffer(normalized, name, sizeof(normalized)); + *COM_FileExtension(normalized) = 0; // open from filesystem only. since packfiles are downloadable, videos from // packfiles can pose security risk due to huge lavf/lavc attack surface. @@ -535,26 +589,25 @@ static bool SCR_StartCinematic(const char *name) break; } - if (Q_snprintf(fullname, sizeof(fullname), "%s/video/%s", path, normalized) >= sizeof(fullname)) { - Com_EPrintf("Oversize cinematic name\n"); - return false; - } + for (int i = 0; i < q_countof(formats); i++) { + if (!(supported & BIT(i))) + continue; - ret = avformat_open_input(&cin.fmt_ctx, fullname, NULL, NULL); + if (Q_snprintf(fullname, sizeof(fullname), "%s/video/%s%s", + path, normalized, formats[i].ext) >= sizeof(fullname)) { + ret = AVERROR(ENAMETOOLONG); + goto done; + } - // if .cin doesn't exist, check for .ogv - if (ret == AVERROR(ENOENT)) { - *COM_FileExtension(fullname) = 0; - Q_strlcat(fullname, ".ogv", sizeof(fullname)); ret = avformat_open_input(&cin.fmt_ctx, fullname, NULL, NULL); + if (ret != AVERROR(ENOENT)) + goto done; } - - if (ret != AVERROR(ENOENT)) - break; } +done: if (ret < 0) { - Com_EPrintf("Couldn't open video/%s: %s\n", normalized, av_err2str(ret)); + Com_EPrintf("Couldn't open %s: %s\n", ret == AVERROR(ENOENT) ? name : fullname, av_err2str(ret)); return false; } @@ -640,3 +693,33 @@ void SCR_PlayCinematic(const char *name) finish: SCR_FinishCinematic(); } + +/* +================== +SCR_CheckForCinematic + +Called by the server to check for cinematic existence. +Name should be in format "video/.cin". +================== +*/ +int SCR_CheckForCinematic(const char *name) +{ + int len = strlen(name); + int ret = Q_ERR(ENOENT); + + Q_assert(len >= 4); + + for (int i = 0; i < q_countof(formats); i++) { + if (!(supported & BIT(i))) + continue; + ret = FS_LoadFileEx(va("%.*s%s", len - 4, name, formats[i].ext), + NULL, FS_TYPE_REAL, TAG_FREE); + if (ret != Q_ERR(ENOENT)) + break; + } + + if (ret == Q_ERR(EFBIG)) + ret = Q_ERR_SUCCESS; + + return ret; +} diff --git a/src/client/gtv.c b/src/client/gtv.c index 2faf05e33..1ce647b6f 100644 --- a/src/client/gtv.c +++ b/src/client/gtv.c @@ -219,8 +219,6 @@ static void write_message(gtv_serverop_t op) void CL_GTV_WriteMessage(byte *data, size_t len) { - int bits; - if (cls.gtv.state != ca_active) return; @@ -241,15 +239,13 @@ void CL_GTV_WriteMessage(byte *data, size_t len) break; case svc_layout: case svc_stufftext: - bits = ((len >> 8) & 7) << SVCMD_BITS; - SZ_WriteByte(&cls.gtv.message, mvd_unicast | bits); + SZ_WriteByte(&cls.gtv.message, mvd_unicast | (len >> 8 << SVCMD_BITS)); SZ_WriteByte(&cls.gtv.message, len & 255); SZ_WriteByte(&cls.gtv.message, cl.clientNum); SZ_Write(&cls.gtv.message, data, len); break; default: - bits = ((len >> 8) & 7) << SVCMD_BITS; - SZ_WriteByte(&cls.gtv.message, mvd_multicast_all | bits); + SZ_WriteByte(&cls.gtv.message, mvd_multicast_all | (len >> 8 << SVCMD_BITS)); SZ_WriteByte(&cls.gtv.message, len & 255); SZ_Write(&cls.gtv.message, data, len); break; diff --git a/src/client/input.c b/src/client/input.c index e1b1bad42..61469ed56 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -45,6 +45,7 @@ static cvar_t *freelook; static cvar_t *lookspring; static cvar_t *lookstrafe; static cvar_t *sensitivity; +static cvar_t *oldsens; static cvar_t *m_pitch; static cvar_t *m_yaw; @@ -251,7 +252,7 @@ static void KeyDown(kbutton_t *b) c = Cmd_Argv(1); if (c[0]) - k = atoi(c); + k = Q_atoi(c); else k = -1; // typed manually at the console for continuous down @@ -272,7 +273,7 @@ static void KeyDown(kbutton_t *b) // save timestamp c = Cmd_Argv(2); - b->downtime = atoi(c); + b->downtime = Q_atoi(c); if (!b->downtime) { b->downtime = com_eventTime - 100; } @@ -288,7 +289,7 @@ static void KeyUp(kbutton_t *b) c = Cmd_Argv(1); if (c[0]) - k = atoi(c); + k = Q_atoi(c); else { // typed manually at the console, assume for unsticking, so clear all b->down[0] = b->down[1] = 0; @@ -310,7 +311,7 @@ static void KeyUp(kbutton_t *b) // save timestamp c = Cmd_Argv(2); - uptime = atoi(c); + uptime = Q_atoi(c); if (!uptime) { b->msec += 10; } else if (uptime > b->downtime) { @@ -386,7 +387,7 @@ static void IN_UseUp(void) static void IN_Impulse(void) { - in_impulse = atoi(Cmd_Argv(1)); + in_impulse = Q_atoi(Cmd_Argv(1)); } static void IN_CenterView(void) @@ -417,7 +418,6 @@ Returns the fraction of the frame that the key was down static float CL_KeyState(kbutton_t *key) { unsigned msec = key->msec; - float val; if (key->state & 1) { // still down @@ -431,9 +431,7 @@ static float CL_KeyState(kbutton_t *key) return (float)(key->state & 1); } - val = (float)msec / cl.cmd.msec; - - return clamp(val, 0, 1); + return Q_clipf((float)msec / cl.cmd.msec, 0, 1); } //========================================================================== @@ -567,11 +565,11 @@ static void CL_BaseMove(vec3_t move) static void CL_ClampSpeed(vec3_t move) { - float speed = 400; // default (maximum) running speed + const float speed = 400; // default (maximum) running speed - clamp(move[0], -speed, speed); - clamp(move[1], -speed, speed); - clamp(move[2], -speed, speed); + move[0] = Q_clipf(move[0], -speed, speed); + move[1] = Q_clipf(move[1], -speed, speed); + move[2] = Q_clipf(move[2], -speed, speed); } static void CL_ClampPitch(void) @@ -586,7 +584,7 @@ static void CL_ClampPitch(void) if (angle > 180) angle -= 360; // wrapped - clamp(angle, -89, 89); + angle = Q_clipf(angle, -89, 89); cl.viewangles[PITCH] = angle - pitch; } @@ -715,6 +713,7 @@ void CL_RegisterInput(void) lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE); lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE); sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE); + oldsens = Cvar_Get("oldsens", sensitivity->string, CVAR_NOARCHIVE); m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE); m_yaw = Cvar_Get("m_yaw", "0.022", 0); @@ -869,7 +868,8 @@ CL_SendDefaultCmd */ static void CL_SendDefaultCmd(void) { - size_t cursize q_unused, checksumIndex; + int cursize q_unused; + uint32_t checksumIndex; usercmd_t *cmd, *oldcmd; client_history_t *history; int version; @@ -941,10 +941,10 @@ static void CL_SendDefaultCmd(void) // // deliver the message // - cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); + cursize = Netchan_Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer) { - Com_Printf("%zu ", cursize); + Com_Printf("%i ", cursize); } #endif @@ -961,7 +961,7 @@ static void CL_SendBatchedCmd(void) int i, j, seq, bits q_unused; int numCmds, numDups; int totalCmds, totalMsec; - size_t cursize q_unused; + int cursize q_unused; usercmd_t *cmd, *oldcmd; client_history_t *history, *oldest; byte *patch; @@ -1041,12 +1041,12 @@ static void CL_SendBatchedCmd(void) // // deliver the message // - cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); + cursize = Netchan_Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer == 1) { - Com_Printf("%zu(%i) ", cursize, totalCmds); + Com_Printf("%i(%i) ", cursize, totalCmds); } else if (cl_showpackets->integer == 2) { - Com_Printf("%zu(%i) ", cursize, totalMsec); + Com_Printf("%i(%i) ", cursize, totalMsec); } else if (cl_showpackets->integer == 3) { Com_Printf(" | "); } @@ -1058,7 +1058,7 @@ static void CL_SendBatchedCmd(void) static void CL_SendKeepAlive(void) { client_history_t *history; - size_t cursize q_unused; + int cursize q_unused; // archive this packet history = &cl.history[cls.netchan.outgoing_sequence & CMD_MASK]; @@ -1070,10 +1070,10 @@ static void CL_SendKeepAlive(void) cl.lastTransmitCmdNumber = cl.cmdNumber; cl.lastTransmitCmdNumberReal = cl.cmdNumber; - cursize = cls.netchan.Transmit(&cls.netchan, 0, "", 1); + cursize = Netchan_Transmit(&cls.netchan, 0, NULL, 1); #if USE_DEBUG if (cl_showpackets->integer) { - Com_Printf("%zu ", cursize); + Com_Printf("%i ", cursize); } #endif } @@ -1140,7 +1140,7 @@ void CL_SendCmd(void) CL_SendReliable(); // just keepalive or update reliable - if (cls.netchan.ShouldUpdate(&cls.netchan)) { + if (Netchan_ShouldUpdate(&cls.netchan)) { CL_SendKeepAlive(); } diff --git a/src/client/main.c b/src/client/main.c index 86a72d980..205fb5f9f 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1753,8 +1753,7 @@ static void CL_FollowIP_f(void) if (Cmd_Argc() > 1) { // optional second argument references less recent address - j = atoi(Cmd_Argv(1)) + 1; - clamp(j, 1, RECENT_ADDR); + j = Q_clip(Q_atoi(Cmd_Argv(1)), 0, RECENT_ADDR - 1) + 1; } else { j = 1; } @@ -1865,6 +1864,7 @@ void CL_ClearState(void) S_StopAllSounds(); OGG_Stop(); SCR_StopCinematic(); + SCR_ClearCenterPrints(); CL_ClearEffects(); CL_ClearTEnts(); #ifdef AQTION_EXTENSION @@ -1931,7 +1931,7 @@ void CL_Disconnect(error_type_t type) MSG_WriteByte(clc_stringcmd); MSG_WriteData("disconnect", 11); - cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 3); + Netchan_Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 3); SZ_Clear(&msg_write); @@ -2023,7 +2023,11 @@ static int SortPlayers(const void *v1, const void *v2) const playerStatus_t *p1 = (const playerStatus_t *)v1; const playerStatus_t *p2 = (const playerStatus_t *)v2; - return p2->score - p1->score; + if (p1->score < p2->score) + return 1; + if (p1->score > p2->score) + return -1; + return 0; } /* @@ -2058,8 +2062,8 @@ static void CL_ParseStatusResponse(serverStatus_t *status, const char *string) status->numPlayers = 0; while (status->numPlayers < MAX_STATUS_PLAYERS) { player = &status->players[status->numPlayers]; - player->score = atoi(COM_Parse(&s)); - player->ping = atoi(COM_Parse(&s)); + player->score = Q_atoi(COM_Parse(&s)); + player->ping = Q_atoi(COM_Parse(&s)); Q_strlcpy(player->name, COM_Parse(&s), sizeof(player->name)); if (!s) break; @@ -2454,7 +2458,7 @@ static void CL_ConnectionlessPacket(void) return; } - cls.challenge = atoi(Cmd_Argv(1)); + cls.challenge = Q_atoi(Cmd_Argv(1)); cls.state = ca_connecting; cls.connect_time -= CONNECT_INSTANT; // fire immediately //cls.connect_count = 0; @@ -2551,12 +2555,12 @@ static void CL_ConnectionlessPacket(void) if (!strncmp(s, "ac=", 3)) { s += 3; if (*s) { - anticheat = atoi(s); + anticheat = Q_atoi(s); } } else if (!strncmp(s, "nc=", 3)) { s += 3; if (*s) { - type = atoi(s); + type = Q_atoi(s); if (type != NETCHAN_OLD && type != NETCHAN_NEW) { Com_Error(ERR_DISCONNECT, "Server returned invalid netchan type"); @@ -2586,7 +2590,7 @@ static void CL_ConnectionlessPacket(void) if (anticheat) { MSG_WriteByte(clc_nop); MSG_FlushTo(&cls.netchan.message); - cls.netchan.Transmit(&cls.netchan, 0, "", 3); + Netchan_Transmit(&cls.netchan, 0, NULL, 3); S_StopAllSounds(); cls.connect_count = -1; Com_Printf("Loading anticheat, this may take a few moments...\n"); @@ -2594,7 +2598,7 @@ static void CL_ConnectionlessPacket(void) if (!Sys_GetAntiCheatAPI()) { Com_Printf("Trying to connect without anticheat.\n"); } else { - Com_LPrintf(PRINT_NOTICE, "Anticheat loaded successfully.\n"); + Com_NPrintf("Anticheat loaded successfully.\n"); } } #else @@ -2608,6 +2612,7 @@ static void CL_ConnectionlessPacket(void) cls.state = ca_connected; cls.connect_count = 0; Q_strlcpy(cl.mapname, mapname, sizeof(cl.mapname)); // for levelshot screen + cl.csr = cs_remap_old; return; } @@ -2688,7 +2693,7 @@ static void CL_PacketEvent(void) return; } - if (!cls.netchan.Process(&cls.netchan)) + if (!Netchan_Process(&cls.netchan)) return; // wasn't accepted for some reason #if USE_ICMP @@ -2940,7 +2945,7 @@ static void CL_Precache_f(void) return; } - precache_spawncount = atoi(Cmd_Argv(1)); + precache_spawncount = Q_atoi(Cmd_Argv(1)); CL_ResetPrecacheCheck(); CL_RequestNextDownload(); @@ -4631,7 +4636,9 @@ void CL_Init(void) Q_assert(inflateInit2(&cls.z, -MAX_WBITS) == Z_OK); #endif + SCR_InitCinematics(); OGG_Init(); + CL_LoadDownloadIgnores(); CL_LoadStuffTextWhiteList(); diff --git a/src/client/newfx.c b/src/client/newfx.c index 4842c31bb..08d03bd8a 100644 --- a/src/client/newfx.c +++ b/src/client/newfx.c @@ -343,11 +343,21 @@ void CL_TrackerTrail(const vec3_t start, const vec3_t end, int particleColor) } } -void CL_Tracker_Shell(const vec3_t origin) +void CL_Tracker_Shell(const centity_t *ent, const vec3_t origin) { - vec3_t dir; + vec3_t org, dir, mid; int i; cparticle_t *p; + float radius; + + if (cl.csr.extended) { + VectorAvg(ent->mins, ent->maxs, mid); + VectorAdd(origin, mid, org); + radius = ent->radius; + } else { + VectorCopy(origin, org); + radius = 40.0f; + } for (i = 0; i < 300; i++) { p = CL_AllocParticle(); @@ -366,7 +376,7 @@ void CL_Tracker_Shell(const vec3_t origin) dir[2] = crand(); VectorNormalize(dir); - VectorMA(origin, 40, dir, p->org); + VectorMA(org, radius, dir, p->org); } } @@ -944,7 +954,7 @@ void CL_PowerSplash(void) dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); - VectorMA(org, 45.0f, dir, p->org); + VectorMA(org, ent->radius, dir, p->org); VectorScale(dir, 40.0f, p->vel); VectorClear(p->accel); diff --git a/src/client/parse.c b/src/client/parse.c index a9db71301..a9a7702f8 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -87,10 +87,10 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex = 0; oldstate = NULL; if (!oldframe) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -116,7 +116,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -137,7 +137,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -157,7 +157,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -179,7 +179,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, } // any remaining entities in the old frame are copied over - while (oldnum != 99999) { + while (oldnum != MAX_EDICTS) { // one or more entities from the old packet are unchanged SHOWNET(3, " unchanged: %i\n", oldnum); CL_ParseDeltaEntity(frame, oldnum, oldstate, 0); @@ -187,7 +187,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -335,7 +335,7 @@ static void CL_ParseFrame(int extrabits) } } - SHOWNET(2, "%3zu:playerinfo\n", msg_read.readcount - 1); + SHOWNET(2, "%3u:playerinfo\n", msg_read.readcount - 1); // parse playerstate bits = MSG_ReadWord(); @@ -399,7 +399,7 @@ static void CL_ParseFrame(int extrabits) } } - SHOWNET(2, "%3zu:packetentities\n", msg_read.readcount - 1); + SHOWNET(2, "%3u:packetentities\n", msg_read.readcount - 1); CL_ParsePacketEntities(oldframe, &frame); @@ -410,7 +410,7 @@ static void CL_ParseFrame(int extrabits) if (cl_shownet->integer > 2) { int seq = cls.netchan.incoming_acknowledged & CMD_MASK; int rtt = cls.demo.playback ? 0 : cls.realtime - cl.history[seq].sent; - Com_LPrintf(PRINT_DEVELOPER, "%3zu:frame:%d delta:%d rtt:%d\n", + Com_LPrintf(PRINT_DEVELOPER, "%3u:frame:%d delta:%d rtt:%d\n", msg_read.readcount - 1, frame.number, frame.delta, rtt); } #endif @@ -604,9 +604,8 @@ static void CL_ParseServerData(void) #if USE_FPS // setup default frame times - cl.frametime = BASE_FRAMETIME; - cl.frametime_inv = BASE_1_FRAMETIME; - cl.framediv = 1; + cl.frametime = Com_ComputeFrametime(BASE_FRAMERATE); + cl.frametime_inv = cl.frametime.div * BASE_1_FRAMETIME; #endif // setup default server state @@ -627,7 +626,7 @@ static void CL_ParseServerData(void) "R1Q2 server reports unsupported protocol version %d.\n" "Assuming it really uses our current client version %d.\n" "Things will break if it does not!\n", i, PROTOCOL_VERSION_R1Q2_CURRENT); - clamp(i, PROTOCOL_VERSION_R1Q2_MINIMUM, PROTOCOL_VERSION_R1Q2_CURRENT); + i = Q_clip(i, PROTOCOL_VERSION_R1Q2_MINIMUM, PROTOCOL_VERSION_R1Q2_CURRENT); } Com_DPrintf("Using minor R1Q2 protocol version %d\n", i); cls.protocolVersion = i; @@ -1083,7 +1082,10 @@ static void CL_ParsePrint(void) SHOWNET(2, " %i \"%s\"\n", level, Com_MakePrintable(s)); if (level != PRINT_CHAT) { - Com_Printf("%s", s); + if (cl.csr.extended && (level == PRINT_TYPEWRITER || level == PRINT_CENTER)) + SCR_CenterPrint(s, level == PRINT_TYPEWRITER); + else + Com_Printf("%s", s); if (!cls.demo.playback && cl.serverstate != ss_broadcast) { COM_strclr(s); Cmd_ExecTrigger(s); @@ -1139,7 +1141,7 @@ static void CL_ParseCenterPrint(void) MSG_ReadString(s, sizeof(s)); SHOWNET(2, " \"%s\"\n", Com_MakePrintable(s)); - SCR_CenterPrint(s); + SCR_CenterPrint(s, false); if (!cls.demo.playback && cl.serverstate != ss_broadcast) { COM_strclr(s); @@ -1215,7 +1217,8 @@ static void CL_ParseZPacket(void) #if USE_ZLIB sizebuf_t temp; byte buffer[MAX_MSGLEN]; - int ret, inlen, outlen; + uInt inlen, outlen; + int ret; if (msg_read.data != msg_read_buffer) { Com_Error(ERR_DROP, "%s: recursively entered", __func__); @@ -1230,9 +1233,9 @@ static void CL_ParseZPacket(void) inflateReset(&cls.z); cls.z.next_in = MSG_ReadData(inlen); - cls.z.avail_in = (uInt)inlen; + cls.z.avail_in = inlen; cls.z.next_out = buffer; - cls.z.avail_out = (uInt)outlen; + cls.z.avail_out = outlen; ret = inflate(&cls.z, Z_FINISH); if (ret != Z_STREAM_END) { Com_Error(ERR_DROP, "%s: inflate() failed with error %d", __func__, ret); @@ -1254,22 +1257,17 @@ static void CL_ParseZPacket(void) #if USE_FPS static void set_server_fps(int value) { - int framediv = value / BASE_FRAMERATE; - - clamp(framediv, 1, MAX_FRAMEDIV); - - cl.frametime = BASE_FRAMETIME / framediv; - cl.frametime_inv = framediv * BASE_1_FRAMETIME; - cl.framediv = framediv; + cl.frametime = Com_ComputeFrametime(value); + cl.frametime_inv = cl.frametime.div * BASE_1_FRAMETIME; // fix time delta if (cls.state == ca_active) { - int delta = cl.frame.number - cl.servertime / cl.frametime; - cl.serverdelta = Q_align(delta, framediv); + int delta = cl.frame.number - cl.servertime / cl.frametime.time; + cl.serverdelta = Q_align(delta, cl.frametime.div); } Com_DPrintf("client framediv=%d time=%d delta=%d\n", - framediv, cl.servertime, cl.serverdelta); + cl.frametime.div, cl.servertime, cl.serverdelta); } #endif @@ -1379,12 +1377,12 @@ CL_ParseServerMessage void CL_ParseServerMessage(void) { int cmd, index, extrabits; - size_t readcount; + uint32_t readcount; uint64_t bits; #if USE_DEBUG if (cl_shownet->integer == 1) { - Com_LPrintf(PRINT_DEVELOPER, "%zu ", msg_read.cursize); + Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); } else if (cl_shownet->integer > 1) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } @@ -1398,7 +1396,7 @@ void CL_ParseServerMessage(void) while (1) { readcount = msg_read.readcount; if (readcount == msg_read.cursize) { - SHOWNET(1, "%3zu:END OF MESSAGE\n", readcount); + SHOWNET(1, "%3u:END OF MESSAGE\n", readcount); break; } @@ -1409,16 +1407,19 @@ void CL_ParseServerMessage(void) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; - if (cmd == svc_extend) + if (cmd == svc_extend) cmd = MSG_ReadByte(); - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands switch (cmd) { default: badbyte: - Com_Error(ERR_DROP, "%s: illegible server message: %d", __func__, cmd); + Com_Error(ERR_DROP, "%s: illegible server message: %d", __func__, cmd); + #if USE_AQTION + Com_Printf("Please update your AQtion client to the latest version in Steam\n"); + #endif break; case svc_nop: @@ -1570,7 +1571,7 @@ void CL_ParseServerMessage(void) // if recording demos, copy off protocol invariant stuff if (cls.demo.recording && !cls.demo.paused) { - size_t len = msg_read.readcount - readcount; + uint32_t len = msg_read.readcount - readcount; // it is very easy to overflow standard 1390 bytes // demo frame with modern servers... attempt to preserve @@ -1604,7 +1605,7 @@ bool CL_SeekDemoMessage(void) #if USE_DEBUG if (cl_shownet->integer == 1) { - Com_LPrintf(PRINT_DEVELOPER, "%zu ", msg_read.cursize); + Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); } else if (cl_shownet->integer > 1) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } @@ -1617,12 +1618,12 @@ bool CL_SeekDemoMessage(void) // while (1) { if (msg_read.readcount == msg_read.cursize) { - SHOWNET(1, "%3zu:END OF MESSAGE\n", msg_read.readcount); + SHOWNET(1, "%3u:END OF MESSAGE\n", msg_read.readcount); break; } cmd = MSG_ReadByte(); - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands switch (cmd) { diff --git a/src/client/precache.c b/src/client/precache.c index cf442098c..ed87e5fa9 100644 --- a/src/client/precache.c +++ b/src/client/precache.c @@ -233,12 +233,12 @@ void CL_RegisterBspModels(void) Com_Error(ERR_DROP, "Couldn't load %s: %s", name, BSP_ErrorString(ret)); } - if (cl.bsp->checksum != atoi(cl.configstrings[cl.csr.mapchecksum])) { + if (cl.bsp->checksum != Q_atoi(cl.configstrings[cl.csr.mapchecksum])) { if (cls.demo.playback) { Com_WPrintf("Local map version differs from demo: %i != %s\n", cl.bsp->checksum, cl.configstrings[CS_MAPCHECKSUM]); } else { - Com_Error(ERR_DROP, "Local map version differs from server: %i != %s\nRecommend removing %s locally and reconnecting", + Com_Error(ERR_DROP, "Local map version differs from server: %i != %s\nRecommend removing %s locally and reconnecting\n", cl.bsp->checksum, cl.configstrings[CS_MAPCHECKSUM], cl.bsp->name); } } @@ -422,12 +422,12 @@ void CL_UpdateConfigstring(int index) const char *s = cl.configstrings[index]; if (index == cl.csr.maxclients) { - cl.maxclients = atoi(s); + cl.maxclients = Q_atoi(s); return; } if (index == cl.csr.airaccel) { - cl.pmp.airaccelerate = cl.pmp.qwmode || atoi(s); + cl.pmp.airaccelerate = cl.pmp.qwmode || Q_atoi(s); return; } diff --git a/src/client/screen.c b/src/client/screen.c index 511b920ca..0e52077bd 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -59,10 +59,12 @@ static struct { int hud_x, hud_y; int hud_width, hud_height; float hud_scale; + int lag_draw_scale; } scr; static cvar_t *scr_viewsize; static cvar_t *scr_centertime; +static cvar_t *scr_printspeed; static cvar_t *scr_showpause; #if USE_DEBUG static cvar_t *scr_showstats; @@ -76,6 +78,7 @@ static cvar_t *scr_lag_y; static cvar_t *scr_lag_draw; static cvar_t *scr_lag_min; static cvar_t *scr_lag_max; +static cvar_t *scr_lag_draw_scale; static cvar_t *scr_alpha; static cvar_t *scr_hudborder_x; @@ -191,18 +194,16 @@ void SCR_DrawStringMulti(int x, int y, int flags, size_t maxlen, char *p; size_t len; - while (*s) { + while (*s && maxlen) { p = strchr(s, '\n'); if (!p) { SCR_DrawStringEx(x, y, flags, maxlen, s, font); break; } - len = p - s; - if (len > maxlen) { - len = maxlen; - } + len = min(p - s, maxlen); SCR_DrawStringEx(x, y, flags, len, s, font); + maxlen -= len; y += CHAR_HEIGHT; s = p + 1; @@ -402,9 +403,24 @@ CENTER PRINTING =============================================================================== */ -static char scr_centerstring[MAX_STRING_CHARS]; -static unsigned scr_centertime_start; // for slow victory printing -static int scr_center_lines; +#define MAX_CENTERPRINTS_REAL 4 +#define MAX_CENTERPRINTS (cl.csr.extended ? MAX_CENTERPRINTS_REAL : 1) + +typedef struct { + char string[MAX_STRING_CHARS - 8]; + uint32_t start; + uint16_t lines; + uint16_t typewrite; // msec to typewrite (0 if instant) +} centerprint_t; + +static centerprint_t scr_centerprints[MAX_CENTERPRINTS_REAL]; +static unsigned scr_centerhead, scr_centertail; + +void SCR_ClearCenterPrints(void) +{ + memset(scr_centerprints, 0, sizeof(scr_centerprints)); + scr_centerhead = scr_centertail = 0; +} /* ============== @@ -414,53 +430,99 @@ Called for important messages that should stay in the center of the screen for a few moments ============== */ -void SCR_CenterPrint(const char *str) +void SCR_CenterPrint(const char *str, bool typewrite) { - const char *s; + centerprint_t *cp; + const char *s; - scr_centertime_start = cls.realtime; - if (!strcmp(scr_centerstring, str)) { + // refresh duplicate message + cp = &scr_centerprints[(scr_centerhead - 1) & (MAX_CENTERPRINTS - 1)]; + if (!strcmp(cp->string, str)) { + if (cp->start) + cp->start = cls.realtime; + if (scr_centertail == scr_centerhead) + scr_centertail--; return; } - Q_strlcpy(scr_centerstring, str, sizeof(scr_centerstring)); + cp = &scr_centerprints[scr_centerhead & (MAX_CENTERPRINTS - 1)]; + Q_strlcpy(cp->string, str, sizeof(cp->string)); // count the number of lines for centering - scr_center_lines = 1; - s = str; + cp->lines = 1; + s = cp->string; while (*s) { if (*s == '\n') - scr_center_lines++; + cp->lines++; s++; } + cp->start = 0; // not yet displayed + cp->typewrite = 0; + + // for typewritten strings set minimum display time, + // but no longer than 30 sec + if (typewrite && scr_printspeed->value > 0) { + size_t nb_chars = strlen(cp->string) - cp->lines + 2; + cp->typewrite = min(nb_chars * 1000 / scr_printspeed->value + 300, 30000); + } + // echo it to the console - Com_Printf("%s\n", scr_centerstring); + Com_Printf("%s\n", cp->string); Con_ClearNotify_f(); + + scr_centerhead++; + if (scr_centerhead - scr_centertail > MAX_CENTERPRINTS) + scr_centertail++; } static void SCR_DrawCenterString(void) { + centerprint_t *cp; int y; float alpha; + size_t maxlen; - Cvar_ClampValue(scr_centertime, 0.3f, 10.0f); - - alpha = SCR_FadeAlpha(scr_centertime_start, scr_centertime->value * 1000, 300); - if (!alpha) { + if (!scr_centertime->integer) { + scr_centertail = scr_centerhead; return; } + while (1) { + if (scr_centertail == scr_centerhead) + return; + cp = &scr_centerprints[scr_centertail & (MAX_CENTERPRINTS - 1)]; + if (!cp->start) + cp->start = cls.realtime; + alpha = SCR_FadeAlpha(cp->start, scr_centertime->integer + cp->typewrite, 300); + if (alpha > 0) + break; + scr_centertail++; + } + R_SetAlpha(alpha * scr_alpha->value); - y = scr.hud_y + (scr.hud_height / 4 - scr_center_lines * 8 / 2); + y = scr.hud_height / 4 - cp->lines * CHAR_HEIGHT / 2; + + if (cp->typewrite) + maxlen = scr_printspeed->value * 0.001f * (cls.realtime - cp->start); + else + maxlen = MAX_STRING_CHARS; - SCR_DrawStringMulti(scr.hud_x + (scr.hud_width / 2), y, UI_CENTER, - MAX_STRING_CHARS, scr_centerstring, scr.font_pic); + SCR_DrawStringMulti(scr.hud_width / 2, y, UI_CENTER, + maxlen, cp->string, scr.font_pic); R_SetAlpha(scr_alpha->value); } +static void scr_centertime_changed(cvar_t *self) +{ + if (self->value > 0) + self->integer = 1000 * Cvar_ClampValue(self, 1.0f, 30.0f); + else + self->integer = 0; +} + /* =============================================================================== @@ -469,8 +531,15 @@ LAGOMETER =============================================================================== */ -#define LAG_WIDTH 48 -#define LAG_HEIGHT 48 +#define LAG_WIDTH 48 +#define LAG_HEIGHT 48 +int DRAW_LAG_WIDTH; +int DRAW_LAG_HEIGHT; +// Scaling support for lag graph +void init_lag_graph_dimensions(void) { + DRAW_LAG_WIDTH = LAG_WIDTH * scr_lag_draw_scale->integer; + DRAW_LAG_HEIGHT = LAG_HEIGHT * scr_lag_draw_scale->integer; +} #define LAG_WARN_BIT BIT(30) #define LAG_CRIT_BIT BIT(31) @@ -524,13 +593,13 @@ static void SCR_LagDraw(int x, int y) if (v_range < 1) return; - for (i = 0; i < LAG_WIDTH; i++) { + for (i = 0; i < DRAW_LAG_WIDTH; i++) { j = lag.head - i - 1; if (j < 0) { break; } - v = lag.samples[j % LAG_WIDTH]; + v = lag.samples[j % DRAW_LAG_WIDTH]; if (v & LAG_CRIT_BIT) { c = LAG_CRIT; @@ -541,10 +610,9 @@ static void SCR_LagDraw(int x, int y) } v &= ~(LAG_WARN_BIT | LAG_CRIT_BIT); - v = (v - v_min) * LAG_HEIGHT / v_range; - clamp(v, 0, LAG_HEIGHT); + v = Q_clip((v - v_min) * LAG_HEIGHT / v_range, 0, LAG_HEIGHT); - R_DrawFill8(x + LAG_WIDTH - i - 1, y + LAG_HEIGHT - v, 1, v, c); + R_DrawFill8(x + DRAW_LAG_WIDTH - i - 1, y + DRAW_LAG_HEIGHT - v, 1, v, c); } } @@ -553,17 +621,19 @@ static void SCR_DrawNet(void) int x = scr_lag_x->integer + scr.hud_x; int y = scr_lag_y->integer + scr.hud_y; + init_lag_graph_dimensions(); + if (scr_lag_x->integer < 0) { - x += scr.hud_width - LAG_WIDTH + 1; + x += scr.hud_width - DRAW_LAG_WIDTH + 1; } if (scr_lag_y->integer < 0) { - y += scr.hud_height - LAG_HEIGHT + 1; + y += scr.hud_height - DRAW_LAG_HEIGHT + 1; } // draw ping graph if (scr_lag_draw->integer) { if (scr_lag_draw->integer > 1) { - R_DrawFill8(x, y, LAG_WIDTH, LAG_HEIGHT, 4); + R_DrawFill8(x, y, DRAW_LAG_WIDTH, DRAW_LAG_HEIGHT, 4); } SCR_LagDraw(x, y); } @@ -571,7 +641,7 @@ static void SCR_DrawNet(void) // draw phone jack if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged >= CMD_BACKUP) { if ((cls.realtime >> 8) & 3) { - R_DrawStretchPic(x, y, LAG_WIDTH, LAG_HEIGHT, scr.net_pic); + R_DrawStretchPic(x, y, DRAW_LAG_WIDTH, DRAW_LAG_HEIGHT, scr.net_pic); } } } @@ -654,8 +724,8 @@ static void SCR_Draw_f(void) flags = UI_IGNORECOLOR; s = Cmd_Argv(1); - x = atoi(Cmd_Argv(2)); - y = atoi(Cmd_Argv(3)); + x = Q_atoi(Cmd_Argv(2)); + y = Q_atoi(Cmd_Argv(3)); if (x < 0) { flags |= UI_RIGHT; @@ -1266,6 +1336,13 @@ static void scr_scale_changed(cvar_t *self) scr_crosshair_changed(scr_crosshair); } +static void scr_lag_draw_scale_changed(cvar_t *self) +{ + scr.lag_draw_scale = R_ClampScale(self); + + DRAW_LAG_WIDTH = LAG_WIDTH * scr_lag_draw_scale->value; + DRAW_LAG_HEIGHT = LAG_HEIGHT * scr_lag_draw_scale->value; +} static const cmdreg_t scr_cmds[] = { { "timerefresh", SCR_TimeRefresh_f }, @@ -1288,6 +1365,9 @@ void SCR_Init(void) scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE); scr_showpause = Cvar_Get("scr_showpause", "1", 0); scr_centertime = Cvar_Get("scr_centertime", "2.5", 0); + scr_centertime->changed = scr_centertime_changed; + scr_centertime->changed(scr_centertime); + scr_printspeed = Cvar_Get("scr_printspeed", "16", 0); scr_demobar = Cvar_Get("scr_demobar", "1", 0); scr_font = Cvar_Get("scr_font", "conchars", 0); scr_font->changed = scr_font_changed; @@ -1304,6 +1384,9 @@ void SCR_Init(void) scr_chathud_x = Cvar_Get("scr_chathud_x", "8", 0); scr_chathud_y = Cvar_Get("scr_chathud_y", "-64", 0); + scr_lag_draw_scale = Cvar_Get("scr_lag_draw_scale", "1", 0); + scr_lag_draw_scale->changed = scr_lag_draw_scale_changed; + xhair_dot = Cvar_Get("xhair_dot", "1",0); xhair_length = Cvar_Get("xhair_length","4",0); xhair_gap = Cvar_Get("xhair_gap", "10",0); @@ -1355,6 +1438,7 @@ void SCR_Init(void) scr_scale_changed(scr_scale); scr_crosshair_changed(scr_crosshair); + scr_lag_draw_scale_changed(scr_lag_draw_scale); scr.initialized = true; } @@ -1658,19 +1742,19 @@ static void SCR_ExecuteLayoutString(const char *s) if (token[0] == 'x') { if (token[1] == 'l') { token = COM_Parse(&s); - x = scr.hud_x + atoi(token); + x = Q_atoi(token); continue; } if (token[1] == 'r') { token = COM_Parse(&s); - x = scr.hud_x + scr.hud_width + atoi(token); + x = scr.hud_width + Q_atoi(token); continue; } if (token[1] == 'v') { token = COM_Parse(&s); - x = scr.hud_x + scr.hud_width / 2 - 160 + atoi(token); + x = scr.hud_width / 2 - 160 + Q_atoi(token); continue; } } @@ -1678,19 +1762,19 @@ static void SCR_ExecuteLayoutString(const char *s) if (token[0] == 'y') { if (token[1] == 't') { token = COM_Parse(&s); - y = scr.hud_y + atoi(token); + y = Q_atoi(token); continue; } if (token[1] == 'b') { token = COM_Parse(&s); - y = scr.hud_y + scr.hud_height + atoi(token); + y = scr.hud_height + Q_atoi(token); continue; } if (token[1] == 'v') { token = COM_Parse(&s); - y = scr.hud_y + scr.hud_height / 2 - 120 + atoi(token); + y = scr.hud_height / 2 - 120 + Q_atoi(token); continue; } } @@ -1699,19 +1783,19 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "pic")) { // draw a pic from a stat number token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for pic: %i", __func__, value); } value = cl.frame.ps.stats[value]; if (value < 0 || value >= cl.csr.max_images) { - Com_Error(ERR_DROP, "%s: invalid pic index", __func__); + Com_Error(ERR_DROP, "%s: invalid pic index for pic: %i", __func__, value); } token = cl.configstrings[cl.csr.images + value]; if (token[0]) { qhandle_t pic = cl.image_precache[value]; // hack for action mod scope scaling - if (Com_WildCmp("scope?x", token)) { + if (Com_WildCmp("scope?x", token) || Com_WildCmp("scopes/*/scope?x", token)) { int x = scr.hud_x + (scr.hud_width - scr.scope_width) / 2; int y = scr.hud_y + (scr.hud_height - scr.scope_height) / 2; @@ -1732,25 +1816,25 @@ static void SCR_ExecuteLayoutString(const char *s) int score, ping, time; token = COM_Parse(&s); - x = scr.hud_x + scr.hud_width / 2 - 160 + atoi(token); + x = scr.hud_width / 2 - 160 + Q_atoi(token); token = COM_Parse(&s); - y = scr.hud_y + scr.hud_height / 2 - 120 + atoi(token); + y = scr.hud_height / 2 - 120 + Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); token = COM_Parse(&s); - time = atoi(token); + time = Q_atoi(token); HUD_DrawAltString(x + 32, y, ci->name); HUD_DrawString(x + 32, y + CHAR_HEIGHT, "Score: "); @@ -1773,22 +1857,22 @@ static void SCR_ExecuteLayoutString(const char *s) int score, ping; token = COM_Parse(&s); - x = scr.hud_x + scr.hud_width / 2 - 160 + atoi(token); + x = scr.hud_width / 2 - 160 + Q_atoi(token); token = COM_Parse(&s); - y = scr.hud_y + scr.hud_height / 2 - 120 + atoi(token); + y = scr.hud_height / 2 - 120 + Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); if (ping > 999) ping = 999; @@ -1812,11 +1896,11 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "num")) { // draw a number token = COM_Parse(&s); - width = atoi(token); + width = Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for num: %i", __func__, value); } value = cl.frame.ps.stats[value]; HUD_DrawNumber(x, y, 0, width, value); @@ -1884,13 +1968,13 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strncmp(token, "stat_", 5)) { char *cmd = token + 5; token = COM_Parse(&s); - index = atoi(token); + index = Q_atoi(token); if (index < 0 || index >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for stat_: %i", __func__, index); } index = cl.frame.ps.stats[index]; if (index < 0 || index >= cl.csr.end) { - Com_Error(ERR_DROP, "%s: invalid string index", __func__); + Com_Error(ERR_DROP, "%s: invalid string index for stat_: %i", __func__, index); } token = cl.configstrings[index]; if (!strcmp(cmd, "string")) @@ -1946,9 +2030,9 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "if")) { token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for if: %i", __func__, value); } value = cl.frame.ps.stats[value]; if (!value) { // skip to endif @@ -2343,7 +2427,7 @@ static void SCR_DrawGhud(void) // float mult = 300 / link->distance; - clamp(mult, 0.25, 5); + Q_clip(mult, 0.25, 5); int sizex = element->size[0] * mult; int sizey = element->size[1] * mult; diff --git a/src/client/sound/al.c b/src/client/sound/al.c index 8195d014b..dbedea738 100644 --- a/src/client/sound/al.c +++ b/src/client/sound/al.c @@ -398,9 +398,9 @@ static void AL_StreamStop(void) Q_assert(!s_stream_buffers); } -static bool AL_NeedRawSamples(void) +static int AL_NeedRawSamples(void) { - return s_stream_buffers < 48; + return s_stream_buffers < 32 ? MAX_RAW_SAMPLES : 0; } static bool AL_RawSamples(int samples, int rate, int width, int channels, const byte *data, float volume) diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index 2746d7d6e..927a62491 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -22,8 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PAINTBUFFER_SIZE 2048 -#define MAX_RAW_SAMPLES 8192 - typedef struct { float left; float right; @@ -74,13 +72,15 @@ static sfxcache_t *DMA_UploadSfx(sfx_t *sfx) sc->channels = s_info.channels; sc->size = size; + Q_assert(stepscale == 1 || s_info.samples <= MAX_SFX_SAMPLES); + // resample / decimate to the current source rate if (stepscale == 1) // fast special case memcpy(sc->data, s_info.data, size); else if (sc->width == 1 && sc->channels == 1) RESAMPLE sc->data[i] = s_info.data[j]; else if (sc->width == 2 && sc->channels == 2) - RESAMPLE WL32(sc->data + i * 4, RL32(s_info.data + j * 4)); + RESAMPLE memcpy(sc->data + i * 4, s_info.data + j * 4, 4); else RESAMPLE ((uint16_t *)sc->data)[i] = ((uint16_t *)s_info.data)[j]; @@ -154,9 +154,11 @@ static bool DMA_RawSamples(int samples, int rate, int width, int channels, const #undef RESAMPLE -static bool DMA_NeedRawSamples(void) +static int DMA_NeedRawSamples(void) { - return s_rawend - s_paintedtime < MAX_RAW_SAMPLES - 2048; + int avail = MAX_RAW_SAMPLES - (s_rawend - s_paintedtime); + avail = Q_clip(avail, 0, MAX_RAW_SAMPLES); + return avail & ~127; } static void DMA_DropRawSamples(void) @@ -187,8 +189,8 @@ static void TransferStereo16(samplepair_t *samp, int endtime) // write a linear blast of samples int16_t *out = (int16_t *)dma.buffer + (lpos << 1); for (int i = 0; i < count; i++, samp++, out += 2) { - out[0] = clip16(samp->left); - out[1] = clip16(samp->right); + out[0] = Q_clip_int16(samp->left); + out[1] = Q_clip_int16(samp->right); } ltime += count; @@ -209,7 +211,7 @@ static void TransferStereo(samplepair_t *samp, int endtime) while (count--) { val = *p; p += step; - out[out_idx] = clip16(val); + out[out_idx] = Q_clip_int16(val); out_idx = (out_idx + 1) & out_mask; } } else if (dma.samplebits == 8) { @@ -217,7 +219,7 @@ static void TransferStereo(samplepair_t *samp, int endtime) while (count--) { val = *p; p += step; - out[out_idx] = (clip16(val) >> 8) + 128; + out[out_idx] = (Q_clip_int16(val) >> 8) + 128; out_idx = (out_idx + 1) & out_mask; } } @@ -804,7 +806,7 @@ static int DMA_GetTime(void) if (s_paintedtime > 0x40000000) { // time to chop things off to avoid 32 bit limits buffers = 0; - s_paintedtime = fullsamples; + s_rawend = s_paintedtime = fullsamples; S_StopAllSounds(); } } @@ -818,6 +820,7 @@ static void DMA_Update(void) int i; channel_t *ch; int samples, soundtime, endtime; + float sec; // update spatialization for dynamic sounds for (i = 0, ch = s_channels; i < s_numchannels; i++, ch++) { @@ -870,7 +873,10 @@ static void DMA_Update(void) } // mix ahead of current position - endtime = soundtime + Cvar_ClampValue(s_mixahead, 0, 1) * dma.speed; + sec = Cvar_ClampValue(s_mixahead, 0, 1); + if (!cls.active) + sec = max(sec, 0.125f); + endtime = soundtime + sec * dma.speed; // mix to an even submission block size endtime = ALIGN(endtime, dma.submission_chunk); @@ -882,6 +888,11 @@ static void DMA_Update(void) snddma.submit(); } +static int DMA_GetSampleRate(void) +{ + return dma.speed; +} + const sndapi_t snd_dma = { .init = DMA_Init, .shutdown = DMA_Shutdown, @@ -896,4 +907,5 @@ const sndapi_t snd_dma = { .get_begin_ofs = DMA_DriftBeginofs, .play_channel = DMA_Spatialize, .stop_all_sounds = DMA_ClearBuffer, + .get_sample_rate = DMA_GetSampleRate, }; diff --git a/src/client/sound/main.c b/src/client/sound/main.c index 223c90c30..026299906 100644 --- a/src/client/sound/main.c +++ b/src/client/sound/main.c @@ -788,6 +788,13 @@ void S_RawSamples(int samples, int rate, int width, int channels, const byte *da s_api.raw_samples(samples, rate, width, channels, data, 1.0f); } +int S_GetSampleRate(void) +{ + if (s_started && s_api.get_sample_rate) + return s_api.get_sample_rate(); + return 0; +} + // ======================================================================= // Update sound buffer // ======================================================================= diff --git a/src/client/sound/mem.c b/src/client/sound/mem.c index 4479a5d66..b6d93705a 100644 --- a/src/client/sound/mem.c +++ b/src/client/sound/mem.c @@ -62,7 +62,7 @@ static bool GetWavinfo(sizebuf_t *sz) tag = SZ_ReadLong(sz); -#if USE_OGG +#if USE_AVCODEC if (tag == MakeLittleLong('O','g','g','S') || !COM_CompareExtension(s_info.name, ".ogg")) { sz->readcount = 0; return OGG_Load(sz); @@ -135,8 +135,8 @@ static bool GetWavinfo(sizebuf_t *sz) // calculate length in samples s_info.samples = chunk_len / (s_info.width * s_info.channels); - if (!s_info.samples) { - Com_DPrintf("%s has zero length\n", s_info.name); + if (s_info.samples < 1 || s_info.samples > MAX_SFX_SAMPLES) { + Com_DPrintf("%s has bad number of samples\n", s_info.name); return false; } @@ -258,7 +258,7 @@ sfxcache_t *S_LoadSound(sfx_t *s) sc = s_api.upload_sfx(s); -#if USE_OGG +#if USE_AVCODEC if (s_info.format != FORMAT_PCM) FS_FreeTempMem(s_info.data); #endif diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 3510e15a6..216c666df 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -16,22 +16,20 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define OV_EXCLUDE_STATIC_CALLBACKS - #include "sound.h" -#include -#ifndef USE_BIG_ENDIAN -#define USE_BIG_ENDIAN 0 -#endif +#include +#include +#include typedef struct { - bool initialized; - OggVorbis_File vf; - qhandle_t f; - int channels; - int rate; - char path[MAX_QPATH]; + AVFormatContext *fmt_ctx; + AVCodecContext *dec_ctx; + AVPacket *pkt; + AVFrame *frame_in; + AVFrame *frame_out; + struct SwrContext *swr_ctx; + int stream_index; } ogg_state_t; static ogg_state_t ogg; @@ -44,63 +42,195 @@ static void **tracklist; static int trackcount; static int trackindex; -static size_t my_read(void *buf, size_t size, size_t nmemb, void *stream) -{ - if (!size || !nmemb) { - errno = 0; - return 0; - } +static char extensions[MAX_QPATH]; +static int supported; - if (size > INT_MAX / nmemb) { - errno = EINVAL; - return 0; - } +static const avformat_t formats[] = { + { ".flac", "flac", AV_CODEC_ID_FLAC }, + { ".opus", "ogg", AV_CODEC_ID_OPUS }, + { ".ogg", "ogg", AV_CODEC_ID_VORBIS }, + { ".mp3", "mp3", AV_CODEC_ID_MP3 }, + { ".wav", "wav", AV_CODEC_ID_NONE } +}; - int ret = FS_Read(buf, size * nmemb, ogg.f); - if (ret < 0) { - errno = EIO; - return 0; +static void init_formats(void) +{ + for (int i = 0; i < q_countof(formats); i++) { + const avformat_t *f = &formats[i]; + if (!av_find_input_format(f->fmt)) + continue; + if (f->codec_id != AV_CODEC_ID_NONE && + !avcodec_find_decoder(f->codec_id)) + continue; + supported |= BIT(i); + if (*extensions) + Q_strlcat(extensions, ";", sizeof(extensions)); + Q_strlcat(extensions, f->ext, sizeof(extensions)); } - errno = 0; - return ret / size; + Com_DPrintf("Supported music formats: %#x\n", supported); } static void ogg_stop(void) { - ov_clear(&ogg.vf); - FS_CloseFile(ogg.f); + avcodec_free_context(&ogg.dec_ctx); + avformat_close_input(&ogg.fmt_ctx); + av_packet_free(&ogg.pkt); + av_frame_free(&ogg.frame_in); + av_frame_free(&ogg.frame_out); + swr_free(&ogg.swr_ctx); + memset(&ogg, 0, sizeof(ogg)); } -static void ogg_play(void) +static AVFormatContext *ogg_open(const char *name, bool autoplay) { - int ret = ov_open_callbacks(&ogg, &ogg.vf, NULL, 0, (ov_callbacks){ my_read }); + char normalized[MAX_QPATH]; + char fullname[MAX_OSPATH]; + const char *path = NULL, *ext; + AVFormatContext *fmt_ctx = NULL; + int ret; + + fullname[0] = 0; + + if (FS_NormalizePathBuffer(normalized, name, sizeof(normalized)) >= sizeof(normalized)) { + ret = AVERROR(ENAMETOOLONG); + goto done; + } + + ext = COM_FileExtension(normalized); + + // open from filesystem only. since packfiles are downloadable, music from + // packfiles can pose security risk due to huge lavf/lavc attack surface. + while (1) { + path = FS_NextPath(path); + if (!path) { + ret = AVERROR(ENOENT); + break; + } + + // try original filename if it has an extension + if (*ext) { + if (Q_snprintf(fullname, sizeof(fullname), "%s/music/%s", path, normalized) >= sizeof(fullname)) { + ret = AVERROR(ENAMETOOLONG); + break; + } + + ret = avformat_open_input(&fmt_ctx, fullname, NULL, NULL); + if (ret != AVERROR(ENOENT)) + break; + } + + // try to append different extensions + for (int i = 0; i < q_countof(formats); i++) { + if (!(supported & BIT(i))) + continue; + + if (!Q_stricmp(ext, formats[i].ext)) + continue; + + if (Q_snprintf(fullname, sizeof(fullname), "%s/music/%s%s", + path, normalized, formats[i].ext) >= sizeof(fullname)) { + ret = AVERROR(ENAMETOOLONG); + goto done; + } + + ret = avformat_open_input(&fmt_ctx, fullname, NULL, NULL); + if (ret != AVERROR(ENOENT)) + goto done; + } + } + + if (ret == AVERROR(ENOENT) && autoplay) + return NULL; + +done: if (ret < 0) { - Com_EPrintf("%s does not appear to be an Ogg bitstream (error %d)\n", ogg.path, ret); - goto fail; + Com_LPrintf(ret == AVERROR(ENOENT) ? PRINT_ALL : PRINT_ERROR, + "Couldn't open %s: %s\n", ret == AVERROR(ENOENT) || + !*fullname ? normalized : fullname, av_err2str(ret)); + return NULL; } - vorbis_info *vi = ov_info(&ogg.vf, -1); - if (!vi) { - Com_EPrintf("Couldn't get info on %s\n", ogg.path); - goto fail; + return fmt_ctx; +} + +static bool ogg_play_(void) +{ + AVStream *st; + const AVCodec *dec; + AVCodecContext *dec_ctx; + int ret; + + ret = avformat_find_stream_info(ogg.fmt_ctx, NULL); + if (ret < 0) { + Com_EPrintf("Couldn't find stream info: %s\n", av_err2str(ret)); + return false; } - if (vi->channels < 1 || vi->channels > 2) { - Com_EPrintf("%s has bad number of channels\n", ogg.path); - goto fail; +#if USE_DEBUG + if (developer->integer) + av_dump_format(ogg.fmt_ctx, 0, ogg.fmt_ctx->url, 0); +#endif + + ret = av_find_best_stream(ogg.fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); + if (ret < 0) { + Com_EPrintf("Couldn't find audio stream\n"); + return false; } - Com_DPrintf("Playing %s\n", ogg.path); + ogg.stream_index = ret; + st = ogg.fmt_ctx->streams[ogg.stream_index]; - ogg.initialized = true; - ogg.channels = vi->channels; - ogg.rate = vi->rate; - return; + dec = avcodec_find_decoder(st->codecpar->codec_id); + if (!dec) { + Com_EPrintf("Failed to find audio codec %s\n", avcodec_get_name(st->codecpar->codec_id)); + return false; + } -fail: - ogg_stop(); + ogg.dec_ctx = dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) { + Com_EPrintf("Failed to allocate audio codec context\n"); + return false; + } + + ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); + if (ret < 0) { + Com_EPrintf("Failed to copy audio codec parameters to decoder context\n"); + return false; + } + + ret = avcodec_open2(dec_ctx, dec, NULL); + if (ret < 0) { + Com_EPrintf("Failed to open audio codec\n"); + return false; + } + + dec_ctx->pkt_timebase = st->time_base; + + ogg.pkt = av_packet_alloc(); + ogg.frame_in = av_frame_alloc(); + ogg.frame_out = av_frame_alloc(); + ogg.swr_ctx = swr_alloc(); + if (!ogg.pkt || !ogg.frame_in || !ogg.frame_out || !ogg.swr_ctx) { + Com_EPrintf("Couldn't allocate memory\n"); + return false; + } + + Com_DPrintf("Playing %s\n", ogg.fmt_ctx->url); + return true; +} + +static void ogg_play(AVFormatContext *fmt_ctx) +{ + if (!fmt_ctx) + return; + + Q_assert(!ogg.fmt_ctx); + ogg.fmt_ctx = fmt_ctx; + + if (!ogg_play_()) + ogg_stop(); } static void shuffle(void) @@ -128,22 +258,13 @@ void OGG_Play(void) if (ogg_shuffle->integer && trackcount) { if (trackindex == 0) shuffle(); - Q_strlcpy(ogg.path, tracklist[trackindex], sizeof(ogg.path)); + s = tracklist[trackindex]; trackindex = (trackindex + 1) % trackcount; } else if (COM_IsUint(s)) { - Q_snprintf(ogg.path, sizeof(ogg.path), "music/track%02d.ogg", atoi(s)); - } else { - Q_snprintf(ogg.path, sizeof(ogg.path), "music/%s.ogg", s); - } - - int ret = FS_OpenFile(ogg.path, &ogg.f, FS_MODE_READ); - if (!ogg.f) { - if (ret != Q_ERR(ENOENT)) - Com_EPrintf("Couldn't open %s: %s\n", ogg.path, Q_ErrorString(ret)); - return; + s = va("track%02d", Q_atoi(s)); } - ogg_play(); + ogg_play(ogg_open(s, true)); } void OGG_Stop(void) @@ -154,187 +275,396 @@ void OGG_Stop(void) s_api.drop_raw_samples(); } -void OGG_Update(void) +static int read_packet(AVPacket *pkt) { - if (!ogg.initialized) - return; + while (1) { + int ret = av_read_frame(ogg.fmt_ctx, pkt); + if (ret < 0) + return ret; + if (pkt->stream_index == ogg.stream_index) + return ret; + av_packet_unref(pkt); + } +} - if (!s_started) - return; +static int decode_frame_(void) +{ + AVCodecContext *dec = ogg.dec_ctx; + AVPacket *pkt = ogg.pkt; + + while (1) { + int ret = avcodec_receive_frame(dec, ogg.frame_in); + + if (ret == AVERROR(EAGAIN)) { + ret = read_packet(pkt); + if (ret == AVERROR_EOF) { + ret = avcodec_send_packet(dec, NULL); + } else if (ret >= 0) { + ret = avcodec_send_packet(dec, pkt); + av_packet_unref(pkt); + } + if (ret < 0) + return ret; + continue; + } - if (!s_active) - return; + return ret; + } +} - while (s_api.need_raw_samples()) { - byte buffer[4096]; - int samples; +static bool decode_frame(void) +{ + int ret = decode_frame_(); + if (ret >= 0) + return true; - samples = ov_read(&ogg.vf, (char *)buffer, sizeof(buffer), USE_BIG_ENDIAN, 2, 1, NULL); - if (samples == 0 && (OGG_Play(), ogg.initialized)) - samples = ov_read(&ogg.vf, (char *)buffer, sizeof(buffer), USE_BIG_ENDIAN, 2, 1, NULL); + if (ret == AVERROR_EOF) + Com_DPrintf("%s decoding audio\n", av_err2str(ret)); + else + Com_EPrintf("Error decoding audio: %s\n", av_err2str(ret)); - if (samples <= 0) - break; + // play next file + OGG_Play(); - vorbis_info *vi = ov_info(&ogg.vf, -1); - if (!vi || vi->channels < 1 || vi->channels > 2) - break; + return ogg.dec_ctx && decode_frame_() >= 0; +} - ogg.channels = vi->channels; - ogg.rate = vi->rate; +static int convert_samples(AVFrame *in) +{ + AVFrame *out = ogg.frame_out; + int ret; + + // exit if not configured yet + if (out->format < 0) + return 0; - if (!s_api.raw_samples(samples >> vi->channels, vi->rate, 2, - vi->channels, buffer, ogg_volume->value)) { - s_api.drop_raw_samples(); + out->nb_samples = s_api.need_raw_samples(); + ret = swr_convert_frame(ogg.swr_ctx, out, in); + if (ret < 0) + return ret; + if (!out->nb_samples) + return 0; + + Com_DDDPrintf("%d raw samples\n", out->nb_samples); + + if (!s_api.raw_samples(out->nb_samples, out->sample_rate, 2, + out->ch_layout.nb_channels, + out->data[0], ogg_volume->value)) + s_api.drop_raw_samples(); + + return 1; +} + +static int reconfigure_swr(void) +{ + AVFrame *in = ogg.frame_in; + AVFrame *out = ogg.frame_out; + int sample_rate = S_GetSampleRate(); + + if (!sample_rate) + sample_rate = out->sample_rate; + if (!sample_rate) + sample_rate = in->sample_rate; + + swr_close(ogg.swr_ctx); + av_frame_unref(out); + + out->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; + out->format = AV_SAMPLE_FMT_S16; + out->sample_rate = sample_rate; + out->nb_samples = MAX_RAW_SAMPLES; + + return av_frame_get_buffer(out, 0); +} + +void OGG_Update(void) +{ + if (!s_started || !s_active || !ogg.dec_ctx) + return; + + while (s_api.need_raw_samples() > 0) { + int ret = convert_samples(NULL); + + // if swr buffer is empty, decode more input + if (ret == 0) { + if (!decode_frame()) + break; + + // now that we have a frame, configure output + if (ogg.frame_out->format < 0) + ret = reconfigure_swr(); + + if (ret >= 0) { + ret = convert_samples(ogg.frame_in); + if (ret == AVERROR_INPUT_CHANGED) { + ret = reconfigure_swr(); + if (ret >= 0) + ret = convert_samples(ogg.frame_in); + } + } + } + + if (ret < 0) { + Com_EPrintf("Error converting audio: %s\n", av_err2str(ret)); + OGG_Stop(); break; } } } -static size_t my_read_sz(void *buf, size_t size, size_t nmemb, void *datasource) +static int sz_read_packet(void *opaque, uint8_t *buf, int size) { - sizebuf_t *sz = datasource; - size_t bytes; - - if (!size || !nmemb) { - errno = 0; - return 0; - } + sizebuf_t *sz = opaque; - if (size > SIZE_MAX / nmemb) { - errno = EINVAL; - return 0; - } + if (size < 0) + return AVERROR(EINVAL); - bytes = min(size * nmemb, sz->cursize - sz->readcount); - if (bytes) { - memcpy(buf, sz->data + sz->readcount, bytes); - sz->readcount += bytes; - } + size = min(size, sz->cursize - sz->readcount); + if (!size) + return AVERROR_EOF; - errno = 0; - return bytes / size; + memcpy(buf, sz->data + sz->readcount, size); + sz->readcount += size; + return size; } -static int my_seek_sz(void *datasource, ogg_int64_t offset, int whence) +static int64_t sz_seek(void *opaque, int64_t offset, int whence) { - sizebuf_t *sz = datasource; + sizebuf_t *sz = opaque; switch (whence) { case SEEK_SET: if (offset < 0) - goto fail; + return AVERROR(EINVAL); sz->readcount = min(offset, sz->cursize); break; case SEEK_CUR: - if (offset < -(ogg_int64_t)sz->readcount) - goto fail; - sz->readcount += min(offset, (ogg_int64_t)(sz->cursize - sz->readcount)); + if (offset < -(int64_t)sz->readcount) + return AVERROR(EINVAL); + sz->readcount += min(offset, (int64_t)(sz->cursize - sz->readcount)); break; case SEEK_END: sz->readcount = sz->cursize; break; default: - fail: - errno = EINVAL; - return -1; + return AVERROR(EINVAL); } - errno = 0; - return 0; -} - -static long my_tell_sz(void *datasource) -{ - sizebuf_t *sz = datasource; return sz->readcount; } bool OGG_Load(sizebuf_t *sz) { - ov_callbacks cb = { - my_read_sz, - my_seek_sz, - NULL, - my_tell_sz - }; - - OggVorbis_File vf; - int ret = ov_open_callbacks(sz, &vf, NULL, 0, cb); - if (ret < 0) { - Com_DPrintf("%s does not appear to be an Ogg bitstream (error %d)\n", s_info.name, ret); + AVFormatContext *fmt_ctx = NULL; + AVIOContext *avio_ctx = NULL; + uint8_t *avio_ctx_buffer = NULL; + const size_t avio_ctx_buffer_size = 4096; + AVPacket *pkt = NULL; + AVFrame *frame = NULL, *out = NULL; + struct SwrContext *swr_ctx = NULL; + AVCodecContext *dec_ctx = NULL; + AVStream *st; + bool res = false; + int ret, sample_rate; + + const AVInputFormat *fmt = av_find_input_format("ogg"); + if (!fmt) { + Com_DPrintf("Ogg input format not found\n"); + return false; + } + + const AVCodec *dec = avcodec_find_decoder(AV_CODEC_ID_VORBIS); + if (!dec) { + Com_DPrintf("Vorbis decoder not found\n"); return false; } - vorbis_info *vi = ov_info(&vf, 0); - if (!vi) { - Com_DPrintf("Couldn't get info on %s\n", s_info.name); + fmt_ctx = avformat_alloc_context(); + if (!fmt_ctx) { + Com_DPrintf("Failed to allocate format context\n"); + return false; + } + + avio_ctx_buffer = av_malloc(avio_ctx_buffer_size); + if (!avio_ctx_buffer) { + Com_DPrintf("Failed to allocate avio buffer\n"); + goto fail; + } + + avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, + 0, sz, sz_read_packet, NULL, sz_seek); + if (!avio_ctx) { + Com_DPrintf("Failed to allocate avio context\n"); goto fail; } - if (vi->channels < 1 || vi->channels > 2) { + fmt_ctx->pb = avio_ctx; + + ret = avformat_open_input(&fmt_ctx, NULL, fmt, NULL); + if (ret < 0) { + Com_DPrintf("Couldn't open %s: %s\n", s_info.name, av_err2str(ret)); + goto fail; + } + + if (fmt_ctx->nb_streams != 1) { + Com_DPrintf("Multiple streams in %s\n", s_info.name); + goto fail; + } + + st = fmt_ctx->streams[0]; + if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { + Com_DPrintf("First stream is not Vorbis in %s\n", s_info.name); + goto fail; + } + + if (st->codecpar->ch_layout.nb_channels < 1 || st->codecpar->ch_layout.nb_channels > 2) { Com_DPrintf("%s has bad number of channels\n", s_info.name); goto fail; } - if (vi->rate < 8000 || vi->rate > 48000) { + if (st->codecpar->sample_rate < 8000 || st->codecpar->sample_rate > 48000) { Com_DPrintf("%s has bad rate\n", s_info.name); goto fail; } - ogg_int64_t samples = ov_pcm_total(&vf, 0); - if (samples < 1 || samples > MAX_LOADFILE >> vi->channels) { + if (st->duration < 1 || st->duration > MAX_SFX_SAMPLES) { Com_DPrintf("%s has bad number of samples\n", s_info.name); goto fail; } - int size = samples << vi->channels; + dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) { + Com_DPrintf("Failed to allocate codec context\n"); + goto fail; + } + + ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); + if (ret < 0) { + Com_DPrintf("Failed to copy codec parameters to decoder context\n"); + goto fail; + } + + ret = avcodec_open2(dec_ctx, dec, NULL); + if (ret < 0) { + Com_DPrintf("Failed to open codec\n"); + goto fail; + } + + dec_ctx->pkt_timebase = st->time_base; + + pkt = av_packet_alloc(); + frame = av_frame_alloc(); + out = av_frame_alloc(); + swr_ctx = swr_alloc(); + if (!pkt || !frame || !out || !swr_ctx) { + Com_DPrintf("Failed to allocate memory\n"); + goto fail; + } + + sample_rate = S_GetSampleRate(); + if (!sample_rate) + sample_rate = dec_ctx->sample_rate; + + ret = av_channel_layout_copy(&out->ch_layout, &dec_ctx->ch_layout); + if (ret < 0) { + Com_DPrintf("Failed to copy channel layout\n"); + goto fail; + } + out->format = AV_SAMPLE_FMT_S16; + out->sample_rate = sample_rate; + out->nb_samples = MAX_RAW_SAMPLES; + + ret = av_frame_get_buffer(out, 0); + if (ret < 0) { + Com_DPrintf("Failed to allocate audio buffer\n"); + goto fail; + } + + int64_t nb_samples = st->duration; + + if (out->sample_rate != dec_ctx->sample_rate) { + nb_samples = av_rescale_rnd(st->duration + 2, out->sample_rate, dec_ctx->sample_rate, AV_ROUND_UP) + 2; + Q_assert(nb_samples <= INT_MAX >> out->ch_layout.nb_channels); + } + + int bufsize = nb_samples << out->ch_layout.nb_channels; int offset = 0; + bool eof = false; - s_info.channels = vi->channels; - s_info.rate = vi->rate; + s_info.channels = out->ch_layout.nb_channels; + s_info.rate = out->sample_rate; s_info.width = 2; s_info.loopstart = -1; - s_info.data = FS_AllocTempMem(size); - - while (offset < size) { - int bitstream; + s_info.data = FS_AllocTempMem(bufsize); + + while (!eof) { + ret = avcodec_receive_frame(dec_ctx, frame); + + if (ret == AVERROR(EAGAIN)) { + ret = av_read_frame(fmt_ctx, pkt); + if (ret == AVERROR_EOF) { + ret = avcodec_send_packet(dec_ctx, NULL); + } else if (ret >= 0) { + ret = avcodec_send_packet(dec_ctx, pkt); + av_packet_unref(pkt); + } + if (ret < 0) + break; + continue; + } - ret = ov_read(&vf, (char *)s_info.data + offset, size - offset, USE_BIG_ENDIAN, 2, 1, &bitstream); - if (ret == 0 || bitstream) + out->nb_samples = MAX_RAW_SAMPLES; + if (ret == AVERROR_EOF) { + ret = swr_convert_frame(swr_ctx, out, NULL); + eof = true; + } else if (ret >= 0) { + ret = swr_convert_frame(swr_ctx, out, frame); + } + if (ret < 0) break; - if (ret < 0) { - Com_DPrintf("Error %d decoding %s\n", ret, s_info.name); - FS_FreeTempMem(s_info.data); - goto fail; + int size = out->nb_samples << out->ch_layout.nb_channels; + if (size > bufsize - offset) { + size = bufsize - offset; + eof = true; } - offset += ret; + memcpy(s_info.data + offset, out->data[0], size); + offset += size; } - s_info.samples = offset >> s_info.channels; + if (ret < 0) { + Com_DPrintf("Error decoding %s: %s\n", s_info.name, av_err2str(ret)); + Z_Freep(&s_info.data); + goto fail; + } - ov_clear(&vf); - return true; + s_info.samples = offset >> s_info.channels; + res = true; fail: - ov_clear(&vf); - return false; + avformat_close_input(&fmt_ctx); + if (avio_ctx) + av_freep(&avio_ctx->buffer); + avio_context_free(&avio_ctx); + avcodec_free_context(&dec_ctx); + av_packet_free(&pkt); + av_frame_free(&frame); + av_frame_free(&out); + swr_free(&swr_ctx); + + return res; } void OGG_LoadTrackList(void) { FS_FreeList(tracklist); - tracklist = FS_ListFiles("music", ".ogg", FS_SEARCH_SAVEPATH, &trackcount); + tracklist = FS_ListFiles("music", extensions, FS_SEARCH_STRIPEXT, &trackcount); trackindex = 0; } static void OGG_Play_f(void) { - char buffer[MAX_QPATH]; - qhandle_t f; - if (Cmd_Argc() < 3) { Com_Printf("Usage: %s %s \n", Cmd_Argv(0), Cmd_Argv(1)); return; @@ -350,24 +680,23 @@ static void OGG_Play_f(void) return; } - f = FS_EasyOpenFile(buffer, sizeof(buffer), FS_MODE_READ, - "music/", Cmd_Argv(2), ".ogg"); - if (!f) + AVFormatContext *fmt_ctx = ogg_open(Cmd_Argv(2), false); + if (!fmt_ctx) return; OGG_Stop(); - Q_strlcpy(ogg.path, buffer, sizeof(ogg.path)); - ogg.f = f; - ogg_play(); + ogg_play(fmt_ctx); } static void OGG_Info_f(void) { - if (ogg.initialized) { - Com_Printf("Playing %s, %d Hz, %d ch\n", ogg.path, ogg.rate, ogg.channels); - } else if (ogg.path[0]) { - Com_Printf("Would play %s, but it failed to load.\n", ogg.path); + AVCodecContext *dec = ogg.dec_ctx; + + if (dec) { + Com_Printf("Playing %s, %s, %d Hz, %d ch\n", + COM_SkipPath(ogg.fmt_ctx->url), dec->codec->name, + dec->sample_rate, dec->ch_layout.nb_channels); } else { Com_Printf("Playback stopped.\n"); } @@ -383,7 +712,7 @@ static void OGG_Cmd_c(genctx_t *ctx, int argnum) } if (argnum == 2 && !strcmp(Cmd_Argv(1), "play")) - FS_File_g("music", ".ogg", FS_SEARCH_STRIPEXT, ctx); + FS_File_g("music", extensions, FS_SEARCH_STRIPEXT, ctx); } static void OGG_Cmd_f(void) @@ -430,6 +759,8 @@ void OGG_Init(void) Cmd_Register(c_ogg); + init_formats(); + OGG_LoadTrackList(); } diff --git a/src/client/sound/qal.c b/src/client/sound/qal.c index ebe610ce4..834cfd900 100644 --- a/src/client/sound/qal.c +++ b/src/client/sound/qal.c @@ -142,6 +142,8 @@ void QAL_Shutdown(void) static const char *const al_drivers[] = { #ifdef _WIN32 "soft_oal", "openal32" +#elif defined(__APPLE__) + "libopenal.dylib.1", "libopenal.dylib" #else "libopenal.so.1", "libopenal.so" #endif diff --git a/src/client/sound/sound.h b/src/client/sound/sound.h index 917ae0c95..6d1824009 100644 --- a/src/client/sound/sound.h +++ b/src/client/sound/sound.h @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/sound/dma.h" #endif +#define MAX_SFX_SAMPLES ((1 << 23) - 1) + typedef struct sfxcache_s { int length; int loopstart; @@ -115,12 +117,13 @@ typedef struct { void (*delete_sfx)(sfx_t *s); void (*page_in_sfx)(sfx_t *s); bool (*raw_samples)(int samples, int rate, int width, int channels, const byte *data, float volume); - bool (*need_raw_samples)(void); + int (*need_raw_samples)(void); void (*drop_raw_samples)(void); int (*get_begin_ofs)(float timeofs); void (*play_channel)(channel_t *ch); void (*stop_channel)(channel_t *ch); void (*stop_all_sounds)(void); + int (*get_sample_rate)(void); } sndapi_t; #if USE_SNDDMA @@ -164,12 +167,6 @@ extern cvar_t *s_show; extern cvar_t *s_underwater; extern cvar_t *s_underwater_gain_hf; -// clip integer to [-0x8000, 0x7FFF] range (stolen from FFmpeg) -static inline int clip16(int v) -{ - return ((v + 0x8000U) & ~0xFFFF) ? (v >> 31) ^ 0x7FFF : v; -} - #define S_IsFullVolume(ch) \ ((ch)->entnum == -1 || (ch)->entnum == listener_entnum || (ch)->dist_mult == 0) @@ -187,6 +184,6 @@ void S_BuildSoundList(int *sounds); float S_GetEntityLoopVolume(const centity_state_t *ent); float S_GetEntityLoopDistMult(const centity_state_t *ent); -#if USE_OGG +#if USE_AVCODEC bool OGG_Load(sizebuf_t *sz); #endif diff --git a/src/client/tent.c b/src/client/tent.c index 4f6b85e58..005652ed5 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -34,9 +34,6 @@ qhandle_t cl_sfx_watrexp; qhandle_t cl_sfx_footsteps[12]; qhandle_t cl_sfx_landing[8]; -qhandle_t cl_sfx_lightning; -qhandle_t cl_sfx_disrexp; - //qhandle_t cl_mod_explode; qhandle_t cl_mod_smoke; qhandle_t cl_mod_flash; @@ -52,8 +49,12 @@ qhandle_t cl_mod_lightning; qhandle_t cl_mod_heatbeam; qhandle_t cl_mod_explo4_big; +qhandle_t cl_mod_muzzles[MFLASH_TOTAL]; + qhandle_t cl_img_flare; +static cvar_t *cl_muzzleflashes; + #define MAX_FOOTSTEP_SFX 9 typedef struct { @@ -81,6 +82,10 @@ static int CL_FindFootstepSurface(int entnum) if (cl_num_footsteps <= FOOTSTEP_RESERVED_COUNT) return footstep_id; + // allow custom footsteps to be disabled + if (cl_footsteps->integer >= 2) + return footstep_id; + // use an X/Y only mins/maxs copy of the entity, // since we don't want it to get caught inside of any geometry above or below const vec3_t trace_mins = { cent->mins[0], cent->mins[1], 0 }; @@ -156,8 +161,15 @@ void CL_PlayFootstepSfx(int step_id, int entnum, float volume, float attenuation if (!sfx->num_sfx) return; // no footsteps, not even fallbacks - // pick a random footstep sound, but avoid playing the same one twice in a row - sfx_num = Q_rand_uniform(sfx->num_sfx); + // check if cl_enhanced_footsteps->string is "0" and sfx->num_sfx has more than four items + if (strcmp(cl_enhanced_footsteps->string, "0") == 0 && sfx->num_sfx > 4) { + // pick a random footstep sound from the first four items, important for compatibility with players using the old four stepsounds + sfx_num = Q_rand_uniform(4); + } else { + // pick a random footstep sound + sfx_num = Q_rand_uniform(sfx->num_sfx); + } + // avoid playing the same one twice in a row footstep_sfx = sfx->sfx[sfx_num]; if (footstep_sfx == cl_last_footstep) footstep_sfx = sfx->sfx[(sfx_num + 1) % sfx->num_sfx]; @@ -230,6 +242,36 @@ static void CL_RegisterFootsteps(void) } } +static void CL_RegisterAQtionSounds(void) +{ + int i; + char name[MAX_QPATH]; + + // Register all AQtion gun sounds + char gunsounds[][64] = {"mk23fire", "mp5fire", "m4a1fire", "shotgf1b", "cannon_fire", "ssgfire"}; + size_t guncount = sizeof(gunsounds) / sizeof(gunsounds[0]); + + for (size_t j = 0; j < guncount; j++) { + Q_snprintf(name, sizeof(name), "weapons/%s.wav", gunsounds[j]); + S_RegisterSound(name); + for (i = MIN_WEAPON_SOUND; i < MAX_WEAPON_SOUND; i++) { + Q_snprintf(name, sizeof(name), "weapons/%s%i.wav", gunsounds[j], i + 1); + S_RegisterSound(name); + } + } + Com_DPrintf("%s: All gun sounds precached\n", __func__); + + // Register all AQtion hit sounds + char hitsounds[][64] = {"aphelmet", "apvest", "body", "chest", "headshot", "leg", "stomach", "vest"}; + size_t hitsoundcount = sizeof(hitsounds) / sizeof(hitsounds[0]); + + for (size_t j = 0; j < hitsoundcount; j++) { + Q_snprintf(name, sizeof(name), "hitsounds/%s.wav", hitsounds[j]); + S_RegisterSound(name); + } + Com_DPrintf("%s: All hit sounds precached\n", __func__); +} + /* ================= CL_RegisterTEntSounds @@ -263,22 +305,7 @@ void CL_RegisterTEntSounds(void) } CL_RegisterFootsteps(); - - cl_sfx_lightning = S_RegisterSound("weapons/tesla.wav"); - cl_sfx_disrexp = S_RegisterSound("weapons/disrupthit.wav"); - - // Register all AQtion gun sounds - char gunsounds[][64] = {"mk23fire", "mp5fire", "m4a1fire", "shotgf1b", "cannon_fire", "ssgfire"}; - size_t guncount = sizeof(gunsounds) / sizeof(gunsounds[0]); - - for (size_t j = 0; j < guncount; j++) { - Q_snprintf(name, sizeof(name), "weapons/%s.wav", gunsounds[j]); - S_RegisterSound(name); - for (i = MIN_WEAPON_SOUND; i < MAX_WEAPON_SOUND; i++) { - Q_snprintf(name, sizeof(name), "weapons/%s%i.wav", gunsounds[j], i + 1); - S_RegisterSound(name); - } - } + CL_RegisterAQtionSounds(); } /* @@ -307,6 +334,19 @@ void CL_RegisterTEntModels(void) cl_mod_heatbeam = R_RegisterModel("models/proj/beam/tris.md2"); cl_mod_explo4_big = R_RegisterModel("models/objects/r_explode2/tris.md2"); + cl_mod_muzzles[MFLASH_MACHN] = R_RegisterModel("models/weapons/v_machn/flash/tris.md2"); + cl_mod_muzzles[MFLASH_SHOTG2] = R_RegisterModel("models/weapons/v_shotg2/flash/tris.md2"); + cl_mod_muzzles[MFLASH_SHOTG] = R_RegisterModel("models/weapons/v_shotg/flash/tris.md2"); + cl_mod_muzzles[MFLASH_ROCKET] = R_RegisterModel("models/weapons/v_rocket/flash/tris.md2"); + cl_mod_muzzles[MFLASH_RAIL] = R_RegisterModel("models/weapons/v_rail/flash/tris.md2"); + cl_mod_muzzles[MFLASH_LAUNCH] = R_RegisterModel("models/weapons/v_launch/flash/tris.md2"); + cl_mod_muzzles[MFLASH_ETF_RIFLE] = R_RegisterModel("models/weapons/v_etf_rifle/flash/tris.md2"); + cl_mod_muzzles[MFLASH_DIST] = R_RegisterModel("models/weapons/v_dist/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BOOMER] = R_RegisterModel("models/weapons/v_boomer/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BLAST] = R_RegisterModel("models/weapons/v_blast/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BFG] = R_RegisterModel("models/weapons/v_bfg/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BEAMER] = R_RegisterModel("models/weapons/v_beamer/flash/tris.md2"); + cl_img_flare = R_RegisterSprite("misc/flare.tga"); // check for remaster powerscreen model (ugly!) @@ -328,7 +368,6 @@ EXPLOSION MANAGEMENT typedef struct { enum { ex_free, - ex_explosion, ex_misc, ex_flash, ex_mflash, @@ -414,6 +453,54 @@ static void CL_BFGExplosion(const vec3_t pos) ex->frames = 4; } +void CL_AddWeaponMuzzleFX(cl_muzzlefx_t fx, const vec3_t offset, float scale) +{ + if (!cl_muzzleflashes->integer) + return; + if (mz.entity != cl.frame.clientNum + 1) + return; + + Q_assert(fx < q_countof(cl_mod_muzzles)); + + if (!cl_mod_muzzles[fx]) + return; + + cl.weapon.muzzle.model = cl_mod_muzzles[fx]; + cl.weapon.muzzle.scale = scale; + if (fx == MFLASH_MACHN || fx == MFLASH_BEAMER) + cl.weapon.muzzle.roll = Q_rand() % 360; + else + cl.weapon.muzzle.roll = 0; + VectorCopy(offset, cl.weapon.muzzle.offset); + cl.weapon.muzzle.time = cl.servertime - CL_FRAMETIME; +} + +void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, int skin, float scale) +{ + explosion_t *ex; + + if (!cl_muzzleflashes->integer) + return; + + Q_assert(fx < q_countof(cl_mod_muzzles)); + + if (!cl_mod_muzzles[fx]) + return; + + ex = CL_AllocExplosion(); + VectorCopy(origin, ex->ent.origin); + VectorCopy(angles, ex->ent.angles); + ex->type = ex_mflash; + ex->ent.flags = RF_TRANSLUCENT | RF_NOSHADOW | RF_FULLBRIGHT; + ex->ent.alpha = 1.0f; + ex->start = cl.servertime - CL_FRAMETIME; + ex->ent.model = cl_mod_muzzles[fx]; + ex->ent.skinnum = skin; + ex->ent.scale = scale; + if (fx != MFLASH_BOOMER) + ex->ent.angles[2] = Q_rand() % 360; +} + /* ================= CL_SmokeAndFlash @@ -451,16 +538,21 @@ static void CL_AddExplosions(void) for (i = 0, ex = cl_explosions; i < MAX_EXPLOSIONS; i++, ex++) { if (ex->type == ex_free) continue; + + if (ex->type == ex_mflash) { + if (cl.time - ex->start > 50) + ex->type = ex_free; + else + V_AddEntity(&ex->ent); + continue; + } + frac = (cl.time - ex->start) * BASE_1_FRAMETIME; f = floor(frac); ent = &ex->ent; switch (ex->type) { - case ex_mflash: - if (f >= ex->frames - 1) - ex->type = ex_free; - break; case ex_misc: case ex_light: if (f >= ex->frames - 1) { @@ -507,7 +599,7 @@ static void CL_AddExplosions(void) ent->flags |= RF_TRANSLUCENT; break; default: - break; + Q_assert(!"bad type"); } if (ex->type == ex_free) @@ -1429,7 +1521,7 @@ void CL_ParseTEnt(void) break; case TE_LIGHTNING: - S_StartSound(NULL, te.entity1, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0); + //S_StartSound(NULL, te.entity1, CHAN_WEAPON, NULL, 1, ATTN_NORM, 0); VectorClear(te.offset); CL_ParseBeam(cl_mod_lightning); break; @@ -1497,7 +1589,7 @@ void CL_ParseTEnt(void) case TE_TRACKER_EXPLOSION: CL_ColorFlash(te.pos1, 0, 150, -1, -1, -1); CL_ColorExplosionParticles(te.pos1, 0, 1); - S_StartSound(te.pos1, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0); + //S_StartSound(te.pos1, 0, 0, NULL, 1, ATTN_NORM, 0); break; case TE_TELEPORT_EFFECT: @@ -1582,6 +1674,7 @@ void CL_ClearTEnts(void) void CL_InitTEnts(void) { + cl_muzzleflashes = Cvar_Get("cl_muzzleflashes", "1", 0); cl_railtrail_type = Cvar_Get("cl_railtrail_type", "0", 0); cl_railtrail_time = Cvar_Get("cl_railtrail_time", "1.0", 0); cl_railtrail_time->changed = cl_timeout_changed; diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c index 05035b3f1..7d368b504 100644 --- a/src/client/ui/menu.c +++ b/src/client/ui/menu.c @@ -877,6 +877,7 @@ static menuSound_t MenuList_SetColumn(menuList_t *l, int value) } if (l->sort) { l->sort(l); + MenuList_AdjustPrestep(l); } return QMS_SILENT; } @@ -913,7 +914,7 @@ static menuSound_t MenuList_PrevColumn(menuList_t *l) return MenuList_FindColumn(l, 1); do { - if (col < 0) { + if (col == 0) { col = l->numcolumns - 1; } else { col--; @@ -1482,9 +1483,6 @@ void MenuList_Sort(menuList_t *l, int offset, int (*cmpfunc)(const void *, const break; } } - - if (n) - MenuList_AdjustPrestep(l); } /* @@ -1500,15 +1498,14 @@ static menuSound_t Slider_DoSlide(menuSlider_t *s, int dir); static void Slider_Push(menuSlider_t *s) { s->modified = false; - s->curvalue = s->cvar->value; - cclamp(s->curvalue, s->minvalue, s->maxvalue); + s->curvalue = Q_circ_clipf(s->cvar->value, s->minvalue, s->maxvalue); } static void Slider_Pop(menuSlider_t *s) { if (s->modified) { - cclamp(s->curvalue, s->minvalue, s->maxvalue); - Cvar_SetValue(s->cvar, s->curvalue, FROM_MENU); + float val = Q_circ_clipf(s->curvalue, s->minvalue, s->maxvalue); + Cvar_SetValue(s->cvar, val, FROM_MENU); } } @@ -1537,8 +1534,7 @@ static menuSound_t Slider_Click(menuSlider_t *s) float pos; int x; - pos = (s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue); - clamp(pos, 0, 1); + pos = Q_clipf((s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue), 0, 1); x = CHAR_WIDTH + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos; @@ -1580,9 +1576,8 @@ static menuSound_t Slider_MouseMove(menuSlider_t *s) return QMS_NOTHANDLED; pos = (uis.mouseCoords[0] - (s->generic.x + RCOLUMN_OFFSET + CHAR_WIDTH)) * (1.0f / (SLIDER_RANGE * CHAR_WIDTH)); - clamp(pos, 0, 1); - value = pos * (s->maxvalue - s->minvalue); + value = Q_clipf(pos, 0, 1) * (s->maxvalue - s->minvalue); steps = Q_rint(value / s->step); s->modified = true; @@ -1617,9 +1612,7 @@ Slider_DoSlide static menuSound_t Slider_DoSlide(menuSlider_t *s, int dir) { s->modified = true; - s->curvalue += dir * s->step; - - cclamp(s->curvalue, s->minvalue, s->maxvalue); + s->curvalue = Q_circ_clipf(s->curvalue + dir * s->step, s->minvalue, s->maxvalue); if (s->generic.change) { menuSound_t sound = s->generic.change(&s->generic); @@ -1659,8 +1652,7 @@ static void Slider_Draw(menuSlider_t *s) UI_DrawChar(RCOLUMN_OFFSET + s->generic.x + i * CHAR_WIDTH + CHAR_WIDTH, s->generic.y, flags | UI_LEFT, 130); - pos = (s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue); - clamp(pos, 0, 1); + pos = Q_clipf((s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue), 0, 1); UI_DrawChar(CHAR_WIDTH + RCOLUMN_OFFSET + s->generic.x + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos, s->generic.y, flags | UI_LEFT, 131); } diff --git a/src/client/ui/playerconfig.c b/src/client/ui/playerconfig.c index a1b67c644..c53ddf428 100644 --- a/src/client/ui/playerconfig.c +++ b/src/client/ui/playerconfig.c @@ -43,7 +43,7 @@ typedef struct m_player_s { unsigned time; unsigned oldTime; - char *pmnames[MAX_PLAYERMODELS]; + char *pmnames[MAX_PLAYERMODELS + 1]; } m_player_t; static m_player_t m_player; @@ -203,7 +203,7 @@ static menuSound_t Change(menuCommon_t *self) static void Pop(menuFrameWork_t *self) { - char scratch[MAX_OSPATH]; + char scratch[MAX_QPATH]; Cvar_SetEx("name", m_player.name.field.text, FROM_CONSOLE); diff --git a/src/client/ui/playermodels.c b/src/client/ui/playermodels.c index e60c6aa7a..f4bc2e621 100644 --- a/src/client/ui/playermodels.c +++ b/src/client/ui/playermodels.c @@ -30,13 +30,13 @@ PLAYER MODELS static bool IconOfSkinExists(char *skin, char **pcxfiles, int npcxfiles) { int i; - char scratch[MAX_OSPATH]; + char scratch[MAX_QPATH]; COM_StripExtension(scratch, skin, sizeof(scratch)); Q_strlcat(scratch, "_i.pcx", sizeof(scratch)); for (i = 0; i < npcxfiles; i++) { - if (strcmp(pcxfiles[i], scratch) == 0) + if (Q_stricmp(pcxfiles[i], scratch) == 0) return true; } @@ -51,69 +51,30 @@ static int pmicmpfnc(const void *_a, const void *_b) /* ** sort by male, female, then alphabetical */ - if (strcmp(a->directory, "male") == 0) + if (Q_stricmp(a->directory, "male") == 0) return -1; - else if (strcmp(b->directory, "male") == 0) + if (Q_stricmp(b->directory, "male") == 0) return 1; - if (strcmp(a->directory, "female") == 0) + if (Q_stricmp(a->directory, "female") == 0) return -1; - else if (strcmp(b->directory, "female") == 0) + if (Q_stricmp(b->directory, "female") == 0) return 1; - return strcmp(a->directory, b->directory); + return Q_stricmp(a->directory, b->directory); } void PlayerModel_Load(void) { char scratch[MAX_QPATH]; - int ndirs = 0; - char *dirnames[MAX_PLAYERMODELS]; - int i, j; - char **list; - char *s, *p; - int numFiles; + int i, ndirs; + char **dirnames; playerModelInfo_t *pmi; - uis.numPlayerModels = 0; + Q_assert(!uis.numPlayerModels); // get a list of directories - if (!(list = (char **)FS_ListFiles(NULL, "players/*/tris.md2", FS_SEARCH_BYFILTER, &numFiles))) { - return; - } - - for (i = 0; i < numFiles; i++) { - if (Q_strlcpy(scratch, list[i], sizeof(scratch)) >= sizeof(scratch)) - continue; - - // make short name for the model - if (!(s = strchr(scratch, '/'))) - continue; - s++; - - if (!(p = strchr(s, '/'))) - continue; - *p = 0; - - for (j = 0; j < ndirs; j++) { - if (!strcmp(dirnames[j], s)) { - break; - } - } - - if (j != ndirs) { - continue; - } - - dirnames[ndirs++] = UI_CopyString(s); - if (ndirs == MAX_PLAYERMODELS) { - break; - } - } - - FS_FreeList((void **)list); - - if (!ndirs) { + if (!(dirnames = (char **)FS_ListFiles("players", NULL, FS_SEARCH_DIRSONLY, &ndirs))) { return; } @@ -128,14 +89,14 @@ void PlayerModel_Load(void) // verify the existence of tris.md2 Q_concat(scratch, sizeof(scratch), "players/", dirnames[i], "/tris.md2"); if (!FS_FileExists(scratch)) { - goto skip; + continue; } // verify the existence of at least one pcx skin Q_concat(scratch, sizeof(scratch), "players/", dirnames[i]); pcxnames = (char **)FS_ListFiles(scratch, ".pcx", 0, &npcxfiles); if (!pcxnames) { - goto skip; + continue; } // count valid skins, which consist of a skin with a matching "_i" icon @@ -149,7 +110,7 @@ void PlayerModel_Load(void) if (!nskins) { FS_FreeList((void **)pcxnames); - goto skip; + continue; } skinnames = UI_Malloc(sizeof(char *) * (nskins + 1)); @@ -171,13 +132,14 @@ void PlayerModel_Load(void) pmi = &uis.pmi[uis.numPlayerModels++]; pmi->nskins = nskins; pmi->skindisplaynames = skinnames; - pmi->directory = dirnames[i]; - continue; + pmi->directory = UI_CopyString(dirnames[i]); -skip: - Z_Free(dirnames[i]); + if (uis.numPlayerModels == MAX_PLAYERMODELS) + break; } + FS_FreeList((void **)dirnames); + qsort(uis.pmi, uis.numPlayerModels, sizeof(uis.pmi[0]), pmicmpfnc); } diff --git a/src/client/ui/q2pro.menu b/src/client/ui/q2pro.menu index 6c3512428..1a9d2c8a6 100644 --- a/src/client/ui/q2pro.menu +++ b/src/client/ui/q2pro.menu @@ -163,6 +163,7 @@ begin screen pairs "HUD scale" scr_scale auto 0 1x 1 2x 2 4x 4 pairs "console scale" con_scale auto 0 1x 1 2x 2 4x 4 pairs "menu scale" ui_scale auto 0 1x 1 2x 2 4x 4 + pairs "Lag graph scale" scr_lag_draw_scale default 1 2x 2 3x 3 blank action --align "crosshair setup..." pushmenu crosshair end diff --git a/src/client/ui/script.c b/src/client/ui/script.c index 40d274ccf..bd464843d 100644 --- a/src/client/ui/script.c +++ b/src/client/ui/script.c @@ -421,7 +421,7 @@ static void Parse_Toggle(menuFrameWork_t *menu) b++; } if (*b) { - bit = atoi(b); + bit = Q_atoi(b); if (bit < 0 || bit >= 32) { Com_Printf("Invalid bit number: %d\n", bit); return; @@ -472,7 +472,7 @@ static void Parse_Field(menuFrameWork_t *menu) status = cmd_optarg; break; case 'w': - width = atoi(cmd_optarg); + width = Q_atoi(cmd_optarg); if (width < 1 || width > 32) { Com_Printf("Invalid width\n"); return; diff --git a/src/client/ui/servers.c b/src/client/ui/servers.c index 522aaf423..246165641 100644 --- a/src/client/ui/servers.c +++ b/src/client/ui/servers.c @@ -192,12 +192,10 @@ static serverslot_t *FindSlot(const netadr_t *search, int *index_p) static uint32_t ColorForStatus(const serverStatus_t *status, unsigned ping) { - ui_colorpingmax = Cvar_Get("ui_colorpingmax", "50", 0); - - if (atoi(Info_ValueForKey(status->infostring, "needpass")) >= 1) - return U32_RED; + if (Q_atoi(Info_ValueForKey(status->infostring, "needpass")) >= 1) + return uis.color.disabled.u32; - if (atoi(Info_ValueForKey(status->infostring, "anticheat")) >= 2) + if (Q_atoi(Info_ValueForKey(status->infostring, "anticheat")) >= 2) return uis.color.disabled.u32; if (Q_stricmp(Info_ValueForKey(status->infostring, "NoFake"), "ENABLED") == 0) @@ -717,14 +715,13 @@ static void FinishPingStage(void) static void CalcPingRate(void) { extern cvar_t *info_rate; + + // don't allow more than 100 packets/sec int rate = Cvar_ClampInteger(ui_pingrate, 0, 100); // assume average 450 bytes per reply packet if (!rate) - rate = info_rate->integer / 450; - - // don't allow more than 100 packets/sec - clamp(rate, 1, 100); + rate = Q_clip(info_rate->integer / 450, 1, 100); // drop rate by stage m_servers.pingtime = (1000 * PING_STAGES) / (rate * m_servers.pingstage); @@ -826,8 +823,8 @@ static int namecmp(serverslot_t *s1, serverslot_t *s2, int col) static int pingcmp(serverslot_t *s1, serverslot_t *s2) { - int n1 = atoi(UI_GetColumn(s1->name, COL_RTT)); - int n2 = atoi(UI_GetColumn(s2->name, COL_RTT)); + int n1 = Q_atoi(UI_GetColumn(s1->name, COL_RTT)); + int n2 = Q_atoi(UI_GetColumn(s2->name, COL_RTT)); return (n1 - n2) * m_servers.list.sortdir; } diff --git a/src/client/ui/ui.c b/src/client/ui/ui.c index 9be1aa46f..eaaf0908f 100644 --- a/src/client/ui/ui.c +++ b/src/client/ui/ui.c @@ -394,8 +394,8 @@ UI_MouseEvent */ void UI_MouseEvent(int x, int y) { - clamp(x, 0, r_config.width - 1); - clamp(y, 0, r_config.height - 1); + x = Q_clip(x, 0, r_config.width - 1); + y = Q_clip(y, 0, r_config.height - 1); uis.mouseCoords[0] = Q_rint(x * uis.scale); uis.mouseCoords[1] = Q_rint(y * uis.scale); diff --git a/src/client/view.c b/src/client/view.c index 5af9c5da7..22c40bbcf 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -44,6 +44,13 @@ static cvar_t *cl_stats; cvar_t *cl_adjustfov; +#if USE_AQTION +static cvar_t *cl_zoom_autosens; +static cvar_t *cl_zoom_2x; +static cvar_t *cl_zoom_4x; +static cvar_t *cl_zoom_6x; +#endif + int r_numdlights; dlight_t r_dlights[MAX_DLIGHTS]; @@ -344,6 +351,29 @@ float V_CalcFov(float fov_x, float width, float height) return a; } +#if USE_AQTION +static void cl_zoom_autosens_changed(float fov) +{ + cvar_t *sensitivity = Cvar_Get("sensitivity", "0", CVAR_ARCHIVE); + cvar_t *oldsens = Cvar_Get("oldsens", "0", CVAR_NOARCHIVE); + + // Anchor value so we return to it after zooming + oldsens->value = atof(sensitivity->string); + + // Adjust sensitivity based on zoom level + if (cl.fov_x >= 90.0f) { // No zoom + Cvar_Set("sensitivity", oldsens->string); + } else if (cl.fov_x == 45.0f && cl_zoom_2x->value) { // 2x scope + Cvar_Set("sensitivity", cl_zoom_2x->string); + } else if (cl.fov_x == 20.0f && cl_zoom_4x->value) { // 4x scope + Cvar_Set("sensitivity", cl_zoom_4x->string); + } else if (cl.fov_x == 10.0f && cl_zoom_6x->value) { // 6x scope + Cvar_Set("sensitivity", cl_zoom_6x->string); + } else { // Safe default back to 1x + Cvar_Set("sensitivity", oldsens->string); + } +} +#endif /* ================== @@ -399,6 +429,11 @@ void V_RenderView(void) cl.refdef.fov_y = V_CalcFov(cl.refdef.fov_x, cl.refdef.width, cl.refdef.height); } + #if USE_AQTION + if (cl_zoom_autosens->value) + cl_zoom_autosens_changed(cl.fov_x); + #endif + cl.refdef.time = cl.time * 0.001f; if (cl.frame.areabytes) { @@ -487,6 +522,13 @@ void V_Init(void) cl_add_blend->changed = cl_add_blend_changed; cl_adjustfov = Cvar_Get("cl_adjustfov", "1", 0); + + #if USE_AQTION + cl_zoom_autosens = Cvar_Get("cl_zoom_autosens", "0", CVAR_ARCHIVE); + cl_zoom_2x = Cvar_Get("cl_zoom_2x", "0", CVAR_ARCHIVE); + cl_zoom_4x = Cvar_Get("cl_zoom_4x", "0", CVAR_ARCHIVE); + cl_zoom_6x = Cvar_Get("cl_zoom_6x", "0", CVAR_ARCHIVE); + #endif } void V_Shutdown(void) diff --git a/src/common/bsp.c b/src/common/bsp.c index 26fe782a4..016aaf949 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -326,7 +326,7 @@ LOAD(Edges) DEBUG("bad vertnum"); return Q_ERR_INVALID_FORMAT; } - out->v[j] = bsp->vertices + vertnum; + out->v[j] = vertnum; } } @@ -357,7 +357,7 @@ LOAD(SurfEdges) return Q_ERR_INVALID_FORMAT; } - out->edge = bsp->edges + index; + out->edge = index; out->vert = vert; } @@ -1305,6 +1305,8 @@ static size_t BSP_ParseExtensionHeader(bsp_t *bsp, lump_t *out, const byte *buf, break; } + Com_DDPrintf("Found %s lump\n", e->name); + if (e->parse_header) extrasize += e->parse_header(bsp, buf + ofs, len); @@ -1407,6 +1409,10 @@ int BSP_Load(const char *name, bsp_t **bsp_p) lump_ofs[i] = ofs; lump_count[i] = count; + // account for terminating NUL for EntString lump + if (!info->lump) + count++; + // round to cacheline memsize += ALIGN(count * info->memsize, 64); maxpos = max(maxpos, end); @@ -1495,8 +1501,9 @@ HELPER FUNCTIONS #if USE_REF static lightpoint_t *light_point; +static int light_mask; -static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const vec3_t p1, const vec3_t p2, int nolm_mask) +static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const vec3_t p1, const vec3_t p2) { vec_t d1, d2, frac, midf, s, t; vec3_t mid; @@ -1521,13 +1528,13 @@ static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const v LerpVector(p1, p2, frac, mid); // check near side - if (BSP_RecursiveLightPoint(node->children[side], p1f, midf, p1, mid, nolm_mask)) + if (BSP_RecursiveLightPoint(node->children[side], p1f, midf, p1, mid)) return true; for (i = 0, surf = node->firstface; i < node->numfaces; i++, surf++) { if (!surf->lightmap) continue; - if (surf->drawflags & nolm_mask) + if (surf->drawflags & light_mask) continue; s = DotProduct(surf->lm_axis[0], mid) + surf->lm_offset[0]; @@ -1546,7 +1553,7 @@ static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const v } // check far side - return BSP_RecursiveLightPoint(node->children[side ^ 1], midf, p2f, mid, p2, nolm_mask); + return BSP_RecursiveLightPoint(node->children[side ^ 1], midf, p2f, mid, p2); } return false; @@ -1557,8 +1564,9 @@ void BSP_LightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, m light_point = point; light_point->surf = NULL; light_point->fraction = 1; + light_mask = nolm_mask; - BSP_RecursiveLightPoint(headnode, 0, 1, start, end, nolm_mask); + BSP_RecursiveLightPoint(headnode, 0, 1, start, end); } void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, @@ -1570,6 +1578,7 @@ void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const ve light_point = point; light_point->surf = NULL; light_point->fraction = 1; + light_mask = nolm_mask; // subtract origin offset VectorSubtract(start, origin, start_l); @@ -1583,7 +1592,7 @@ void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const ve } // sweep the line through the model - if (!BSP_RecursiveLightPoint(headnode, 0, 1, start_l, end_l, nolm_mask)) + if (!BSP_RecursiveLightPoint(headnode, 0, 1, start_l, end_l)) return; // rotate plane normal into the worlds frame of reference @@ -1711,7 +1720,7 @@ mmodel_t *BSP_InlineModel(bsp_t *bsp, const char *name) Q_assert(name); Q_assert(name[0] == '*'); - num = atoi(name + 1); + num = Q_atoi(name + 1); if (num < 1 || num >= bsp->nummodels) { Com_Error(ERR_DROP, "%s: bad number: %d", __func__, num); } diff --git a/src/common/cmd.c b/src/common/cmd.c index 509c457e3..86227379b 100644 --- a/src/common/cmd.c +++ b/src/common/cmd.c @@ -56,7 +56,7 @@ bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" */ static void Cmd_Wait_f(void) { - int count = atoi(Cmd_Argv(1)); + int count = Q_atoi(Cmd_Argv(1)); cmd_current->waitCount += max(count, 1); } @@ -1752,7 +1752,7 @@ static char *unescape_string(char *dst, const char *src) src += 2; break; default: - if (src[0] >= '0' && src[1] <= '7') { + if (src[1] >= '0' && src[1] <= '7') { *p++ = strtoul(&src[1], (char **)&src, 8); src -= 2; } else { diff --git a/src/common/cmodel.c b/src/common/cmodel.c index 1b91f0c5a..dc386cb7a 100644 --- a/src/common/cmodel.c +++ b/src/common/cmodel.c @@ -732,14 +732,17 @@ static void CM_RecursiveHullCheck(mnode_t *node, float p1f, float p2f, const vec frac2 = 0; } + frac = Q_clipf(frac, 0, 1); + frac2 = Q_clipf(frac2, 0, 1); + // move up to the node - midf = p1f + (p2f - p1f) * clamp(frac, 0, 1); + midf = p1f + (p2f - p1f) * frac; LerpVector(p1, p2, frac, mid); CM_RecursiveHullCheck(node->children[side], p1f, midf, p1, mid); // go past the node - midf = p1f + (p2f - p1f) * clamp(frac2, 0, 1); + midf = p1f + (p2f - p1f) * frac2; LerpVector(p1, p2, frac2, mid); CM_RecursiveHullCheck(node->children[side ^ 1], midf, p2f, mid, p2); diff --git a/src/common/cvar.c b/src/common/cvar.c index b52e5a642..2399b4b29 100644 --- a/src/common/cvar.c +++ b/src/common/cvar.c @@ -158,10 +158,10 @@ static void parse_string_value(cvar_t *var) if (s[0] == '0' && s[1] == 'x') { long v = strtol(s, NULL, 16); - var->integer = clamp(v, INT_MIN, INT_MAX); + var->integer = Q_clipl_int32(v); var->value = (float)var->integer; } else { - var->integer = atoi(s); + var->integer = Q_atoi(s); var->value = atof(s); if (var->value != 0.0f && !isnormal(var->value)) var->value = 0.0f; diff --git a/src/common/features.h b/src/common/features.h index 5086eed02..abc00b839 100644 --- a/src/common/features.h +++ b/src/common/features.h @@ -25,6 +25,9 @@ static const char *Com_GetFeatures(void) #if USE_AUTOREPLY "auto-reply " #endif +#if USE_AVCODEC + "avcodec " +#endif #if USE_CLIENT_GTV "client-gtv " #endif @@ -52,15 +55,15 @@ static const char *Com_GetFeatures(void) #if USE_MD3 "md3 " #endif +#if USE_MD5 + "md5 " +#endif #if USE_MVD_CLIENT "mvd-client " #endif #if USE_MVD_SERVER "mvd-server " #endif -#if USE_OGG - "ogg " -#endif #if USE_OPENAL "openal " #endif diff --git a/src/common/files.c b/src/common/files.c index f5e3349b0..5c1779757 100644 --- a/src/common/files.c +++ b/src/common/files.c @@ -70,8 +70,8 @@ QUAKE FILESYSTEM #if USE_DEBUG #define FS_DPrintf(...) \ - if (fs_debug && fs_debug->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (fs_debug && fs_debug->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define FS_DPrintf(...) #endif diff --git a/src/common/hash_map.c b/src/common/hash_map.c index 2766e5e11..226039375 100644 --- a/src/common/hash_map.c +++ b/src/common/hash_map.c @@ -32,7 +32,7 @@ typedef struct hash_map_s { uint32_t key_size; uint32_t value_size; uint32_t (*hasher)(const void *const); - qboolean (*comp)(const void *const, const void *const); + bool (*comp)(const void *const, const void *const); uint32_t *hash_to_index; uint32_t *index_chain; void *keys; @@ -69,7 +69,7 @@ static void HashMap_Rehash(hash_map_t *map, const uint32_t new_size) if (map->hash_size >= new_size) return; map->hash_size = new_size; - map->hash_to_index = Z_Realloc(map->hash_to_index, map->hash_size * sizeof(uint32_t)); + map->hash_to_index = Z_ReallocArray(map->hash_to_index, map->hash_size, sizeof(uint32_t)); memset(map->hash_to_index, 0xFF, map->hash_size * sizeof(uint32_t)); for (uint32_t i = 0; i < map->num_entries; ++i) { void *key = HashMap_GetKeyImpl(map, i); @@ -87,9 +87,9 @@ HashMap_ExpandKeyValueStorage */ static void HashMap_ExpandKeyValueStorage(hash_map_t *map, const uint32_t new_size) { - map->keys = Z_Realloc(map->keys, new_size * map->key_size); - map->values = Z_Realloc(map->values, new_size * map->value_size); - map->index_chain = Z_Realloc(map->index_chain, new_size * sizeof(uint32_t)); + map->keys = Z_ReallocArray(map->keys, new_size, map->key_size); + map->values = Z_ReallocArray(map->values, new_size, map->value_size); + map->index_chain = Z_ReallocArray(map->index_chain, new_size, sizeof(uint32_t)); map->key_value_storage_size = new_size; } @@ -100,9 +100,9 @@ HashMap_CreateImpl */ hash_map_t *HashMap_CreateImpl(const uint32_t key_size, const uint32_t value_size, uint32_t (*hasher)(const void *const), - qboolean (*comp)(const void *const, const void *const)) + bool (*comp)(const void *const, const void *const)) { - hash_map_t *map = Z_Mallocz(sizeof(hash_map_t)); + hash_map_t *map = Z_Mallocz(sizeof(*map)); map->key_size = key_size; map->value_size = value_size; map->hasher = hasher; @@ -129,7 +129,7 @@ void HashMap_Destroy(hash_map_t *map) HashMap_Reserve ================= */ -void HashMap_Reserve(hash_map_t *map, int capacity) +void HashMap_Reserve(hash_map_t *map, uint32_t capacity) { const uint32_t new_key_value_storage_size = Q_npot32(capacity); if (map->key_value_storage_size < new_key_value_storage_size) @@ -144,7 +144,7 @@ void HashMap_Reserve(hash_map_t *map, int capacity) HashMap_InsertImpl ================= */ -qboolean HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value) +bool HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value) { Q_assert(map->key_size == key_size); Q_assert(map->value_size == value_size); @@ -182,7 +182,7 @@ qboolean HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint HashMap_EraseImpl ================= */ -qboolean HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key) +bool HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key) { Q_assert(key_size == map->key_size); if (map->num_entries == 0) @@ -217,7 +217,7 @@ qboolean HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void if (map->hash_to_index[last_hash_index] == last_index) map->hash_to_index[last_hash_index] = map->index_chain[last_index]; else { - qboolean found = false; + bool found = false; for (uint32_t last_storage_index = map->hash_to_index[last_hash_index]; last_storage_index != UINT32_MAX; last_storage_index = map->index_chain[last_storage_index]) { if (map->index_chain[last_storage_index] == last_index) { @@ -256,7 +256,6 @@ HashMap_LookupImpl void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *const key) { Q_assert(map->key_size == key_size); - if (map->num_entries == 0) return NULL; @@ -266,7 +265,7 @@ void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *c while (storage_index != UINT32_MAX) { const void *const storage_key = HashMap_GetKeyImpl(map, storage_index); if (map->comp ? map->comp(key, storage_key) : (memcmp(key, storage_key, key_size) == 0)) - return (byte *)map->values + (storage_index * map->value_size); + return HashMap_GetValueImpl(map, storage_index); storage_index = map->index_chain[storage_index]; } diff --git a/src/common/msg.c b/src/common/msg.c index b008604b0..29c6d2a90 100644 --- a/src/common/msg.c +++ b/src/common/msg.c @@ -450,11 +450,6 @@ void MSG_WriteDir(const vec3_t dir) MSG_WriteByte(best); } -static inline int clip_byte(int v) -{ - return clamp(v, 0, 255); -} - void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, const entity_state_extension_t *ext) { // allow 0 to accomodate empty baselines @@ -482,14 +477,14 @@ void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, const entity out->event = in->event; if (ext) { out->morefx = ext->morefx; - out->alpha = clip_byte(ext->alpha * 255.0f); - out->scale = clip_byte(ext->scale * 16.0f); - out->loop_volume = clip_byte(ext->loop_volume * 255.0f); + out->alpha = Q_clip_uint8(ext->alpha * 255.0f); + out->scale = Q_clip_uint8(ext->scale * 16.0f); + out->loop_volume = Q_clip_uint8(ext->loop_volume * 255.0f); // encode ATTN_STATIC (192) as 0, and ATTN_LOOP_NONE (-1) as 192 if (ext->loop_attenuation == ATTN_LOOP_NONE) { out->loop_attenuation = 192; } else { - out->loop_attenuation = clip_byte(ext->loop_attenuation * 64.0f); + out->loop_attenuation = Q_clip_uint8(ext->loop_attenuation * 64.0f); if (out->loop_attenuation == 192) out->loop_attenuation = 0; } @@ -786,17 +781,7 @@ void MSG_WriteDeltaEntity(const entity_packed_t *from, MSG_WriteByte(to->scale); } -static inline int OFFSET2CHAR(float x) -{ - int v = x * 4; - return clamp(v, -128, 127); -} - -static inline int BLEND2BYTE(float x) -{ - int v = x * 255; - return clamp(v, 0, 255); -} +#define OFFSET2CHAR(x) Q_clip_int8((x) * 4) void MSG_PackPlayer(player_packed_t *out, const player_state_t *in) { @@ -811,7 +796,7 @@ void MSG_PackPlayer(player_packed_t *out, const player_state_t *in) out->gunindex = in->gunindex; out->gunframe = in->gunframe; for (i = 0; i < 4; i++) - out->blend[i] = BLEND2BYTE(in->blend[i]); + out->blend[i] = Q_clip_uint8(in->blend[i] * 255); out->fov = (int)in->fov; out->rdflags = in->rdflags; for (i = 0; i < MAX_STATS; i++) @@ -2007,7 +1992,7 @@ int MSG_ReadBits(int bits) msg_read.bits_left = bits_left - bits; if (sgn) { - return (int32_t)(value << (32 - bits)) >> (32 - bits); + return SignExtend(value, bits); } return value; diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 1c1e6c0ef..ef25f947c 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -85,11 +85,11 @@ unacknowledged reliable static cvar_t *showpackets; static cvar_t *showdrop; #define SHOWPACKET(...) \ - if (showpackets->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (showpackets->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWDROP(...) \ - if (showdrop->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (showdrop->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define SHOWPACKET(...) #define SHOWDROP(...) @@ -120,16 +120,13 @@ Netchan_Init */ void Netchan_Init(void) { - int port; - #if USE_DEBUG showpackets = Cvar_Get("showpackets", "0", 0); showdrop = Cvar_Get("showdrop", "0", 0); #endif // pick a port value that should be nice and random - port = Sys_Milliseconds() & 0xffff; - net_qport = Cvar_Get("qport", va("%d", port), 0); + net_qport = Cvar_Get("qport", va("%d", Sys_Milliseconds() & 0xffff), 0); net_maxmsglen = Cvar_Get("net_maxmsglen", va("%d", MAX_PACKETLEN_WRITABLE_DEFAULT), 0); net_maxmsglen->changed = net_maxmsglen_changed; net_chantype = Cvar_Get("net_chantype", "1", 0); @@ -166,12 +163,6 @@ void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, const char *forma // ============================================================================ -static size_t NetchanOld_TransmitNextFragment(netchan_t *netchan) -{ - Q_assert(!"not implemented"); - return 0; -} - /* =============== NetchanOld_Transmit @@ -182,20 +173,13 @@ transmition / retransmition of the reliable messages. A 0 length will still generate a packet and deal with the reliable messages. ================ */ -static size_t NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) +static int NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; bool send_reliable; int i, w1, w2; -// check for message overflow - if (chan->message.overflowed) { - chan->fatal_error = true; - Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); - return 0; - } - send_reliable = false; // if the remote side dropped the last reliable message, resend it @@ -207,7 +191,7 @@ static size_t NetchanOld_Transmit(netchan_t *chan, size_t length, const void *da // if the reliable transmit buffer is empty, copy the current message out if (!chan->reliable_length && chan->message.cursize) { send_reliable = true; - memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + memcpy(chan->reliable_buf, chan->message.data, chan->message.cursize); chan->reliable_length = chan->message.cursize; chan->message.cursize = 0; chan->reliable_sequence ^= 1; @@ -250,7 +234,7 @@ static size_t NetchanOld_Transmit(netchan_t *chan, size_t length, const void *da else Com_WPrintf("%s: dumped unreliable\n", NET_AdrToString(&chan->remote_address)); - SHOWPACKET("send %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("send %4u : s=%d ack=%d rack=%d", send.cursize, chan->outgoing_sequence, chan->incoming_sequence, @@ -311,7 +295,7 @@ static bool NetchanOld_Process(netchan_t *chan) sequence &= OLD_MASK; sequence_ack &= OLD_MASK; - SHOWPACKET("recv %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("recv %4u : s=%d ack=%d rack=%d", msg_read.cursize, sequence, sequence_ack, @@ -370,32 +354,22 @@ static bool NetchanOld_Process(netchan_t *chan) return true; } -/* -=============== -NetchanOld_ShouldUpdate -================ -*/ -static bool NetchanOld_ShouldUpdate(netchan_t *chan) -{ - return chan->message.cursize - || chan->reliable_ack_pending - || com_localTime - chan->last_sent > 1000; -} - // ============================================================================ /* =============== -NetchanNew_TransmitNextFragment +Netchan_TransmitNextFragment ================ */ -static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) +int Netchan_TransmitNextFragment(netchan_t *chan) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; bool send_reliable, more_fragments; int w1, w2, offset; - size_t fragment_length; + unsigned fragment_length; + + Q_assert(chan->type); send_reliable = chan->reliable_length; @@ -439,8 +413,8 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) // write fragment contents SZ_Write(&send, chan->fragment_out.data + chan->fragment_out.readcount, fragment_length); - SHOWPACKET("send %4zu : s=%d ack=%d rack=%d " - "fragment_offset=%zu more_fragments=%d", + SHOWPACKET("send %4u : s=%d ack=%d rack=%d " + "fragment_offset=%u more_fragments=%d", send.cursize, chan->outgoing_sequence, chan->incoming_sequence, @@ -473,22 +447,15 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) NetchanNew_Transmit ================ */ -static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) +static int NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; bool send_reliable; int i, w1, w2; -// check for message overflow - if (chan->message.overflowed) { - chan->fatal_error = true; - Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); - return 0; - } - if (chan->fragment_pending) { - return NetchanNew_TransmitNextFragment(chan); + return Netchan_TransmitNextFragment(chan); } send_reliable = false; @@ -502,7 +469,7 @@ static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *da // if the reliable transmit buffer is empty, copy the current message out if (!chan->reliable_length && chan->message.cursize) { send_reliable = true; - memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + memcpy(chan->reliable_buf, chan->message.data, chan->message.cursize); chan->reliable_length = chan->message.cursize; chan->message.cursize = 0; chan->reliable_sequence ^= 1; @@ -519,7 +486,7 @@ static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *da SZ_Write(&chan->fragment_out, data, length); else Com_WPrintf("%s: dumped unreliable\n", NET_AdrToString(&chan->remote_address)); - return NetchanNew_TransmitNextFragment(chan); + return Netchan_TransmitNextFragment(chan); } // write the packet header @@ -552,7 +519,7 @@ static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *da // add the unreliable part SZ_Write(&send, data, length); - SHOWPACKET("send %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("send %4u : s=%d ack=%d rack=%d", send.cursize, chan->outgoing_sequence, chan->incoming_sequence, @@ -583,7 +550,7 @@ static bool NetchanNew_Process(netchan_t *chan) { int sequence, sequence_ack, fragment_offset; bool reliable_message, reliable_ack, fragmented_message, more_fragments; - size_t length; + unsigned length; // get sequence numbers MSG_BeginReading(); @@ -616,7 +583,7 @@ static bool NetchanNew_Process(netchan_t *chan) return false; } - SHOWPACKET("recv %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("recv %4u : s=%d ack=%d rack=%d", msg_read.cursize, sequence, sequence_ack, reliable_ack); if (fragmented_message) { SHOWPACKET(" fragment_offset=%d more_fragments=%d", @@ -718,12 +685,34 @@ static bool NetchanNew_Process(netchan_t *chan) return true; } +bool Netchan_Process(netchan_t *chan) +{ + if (chan->type) + return NetchanNew_Process(chan); + + return NetchanOld_Process(chan); +} + +int Netchan_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) +{ + // overflow is detected externally now, so this should never happen. + if (chan->message.overflowed) { + Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); + return 0; + } + + if (chan->type) + return NetchanNew_Transmit(chan, length, data, numpackets); + + return NetchanOld_Transmit(chan, length, data, numpackets); +} + /* ============== -NetchanNew_ShouldUpdate +Netchan_ShouldUpdate ============== */ -static bool NetchanNew_ShouldUpdate(netchan_t *chan) +bool Netchan_ShouldUpdate(netchan_t *chan) { return chan->message.cursize || chan->reliable_ack_pending @@ -740,9 +729,10 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol) { memtag_t tag = sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL; + byte *buf; Q_assert(chan); - Q_assert(!chan->message_buf); + Q_assert(!chan->reliable_buf); Q_assert(adr); Q_assert(maxpacketlen >= MIN_PACKETLEN); Q_assert(maxpacketlen <= MAX_PACKETLEN_WRITABLE); @@ -760,31 +750,15 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, switch (type) { case NETCHAN_OLD: - chan->Process = NetchanOld_Process; - chan->Transmit = NetchanOld_Transmit; - chan->TransmitNextFragment = NetchanOld_TransmitNextFragment; - chan->ShouldUpdate = NetchanOld_ShouldUpdate; - - chan->message_buf = Z_TagMalloc(maxpacketlen * 2, tag); - chan->reliable_buf = chan->message_buf + maxpacketlen; - - SZ_Init(&chan->message, chan->message_buf, maxpacketlen); + chan->reliable_buf = buf = Z_TagMalloc(maxpacketlen * 2, tag); + SZ_Init(&chan->message, buf + maxpacketlen, maxpacketlen); break; case NETCHAN_NEW: - chan->Process = NetchanNew_Process; - chan->Transmit = NetchanNew_Transmit; - chan->TransmitNextFragment = NetchanNew_TransmitNextFragment; - chan->ShouldUpdate = NetchanNew_ShouldUpdate; - - chan->message_buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); - chan->reliable_buf = chan->message_buf + MAX_MSGLEN; - chan->fragment_in_buf = chan->message_buf + MAX_MSGLEN * 2; - chan->fragment_out_buf = chan->message_buf + MAX_MSGLEN * 3; - - SZ_Init(&chan->message, chan->message_buf, MAX_MSGLEN); - SZ_TagInit(&chan->fragment_in, chan->fragment_in_buf, MAX_MSGLEN, "nc_frg_in"); - SZ_TagInit(&chan->fragment_out, chan->fragment_out_buf, MAX_MSGLEN, "nc_frg_out"); + chan->reliable_buf = buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); + SZ_Init(&chan->message, buf + MAX_MSGLEN, MAX_MSGLEN); + SZ_TagInit(&chan->fragment_in, buf + MAX_MSGLEN * 2, MAX_MSGLEN, "nc_frg_in"); + SZ_TagInit(&chan->fragment_out, buf + MAX_MSGLEN * 3, MAX_MSGLEN, "nc_frg_out"); break; default: @@ -800,6 +774,6 @@ Netchan_Close void Netchan_Close(netchan_t *chan) { Q_assert(chan); - Z_Free(chan->message_buf); + Z_Free(chan->reliable_buf); memset(chan, 0, sizeof(*chan)); } diff --git a/src/common/pmove.c b/src/common/pmove.c index 3b07f1f01..285d81f4d 100644 --- a/src/common/pmove.c +++ b/src/common/pmove.c @@ -373,8 +373,8 @@ static void PM_AddCurrents(vec3_t wishvel) wishvel[2] = 0; // limit horizontal speed when on a ladder - clamp(wishvel[0], -25, 25); - clamp(wishvel[1], -25, 25); + wishvel[0] = Q_clipf(wishvel[0], -25, 25); + wishvel[1] = Q_clipf(wishvel[1], -25, 25); } // @@ -1012,7 +1012,7 @@ static void PM_ClampAngles(void) } // don't let the player look up or down more than 90 degrees - clamp(pm->viewangles[PITCH], -89, 89); + pm->viewangles[PITCH] = Q_clipf(pm->viewangles[PITCH], -89, 89); } AngleVectors(pm->viewangles, pml.forward, pml.right, pml.up); } diff --git a/src/common/sizebuf.c b/src/common/sizebuf.c index 212fab3a5..686c57e40 100644 --- a/src/common/sizebuf.c +++ b/src/common/sizebuf.c @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., void SZ_TagInit(sizebuf_t *buf, void *data, size_t size, const char *tag) { + Q_assert(size <= INT32_MAX); memset(buf, 0, sizeof(*buf)); buf->data = data; buf->maxsize = size; @@ -31,6 +32,7 @@ void SZ_TagInit(sizebuf_t *buf, void *data, size_t size, const char *tag) void SZ_Init(sizebuf_t *buf, void *data, size_t size) { + Q_assert(size <= INT32_MAX); memset(buf, 0, sizeof(*buf)); buf->data = data; buf->maxsize = size; @@ -59,7 +61,7 @@ void *SZ_GetSpace(sizebuf_t *buf, size_t len) if (len > buf->maxsize - buf->cursize) { if (len > buf->maxsize) { Com_Error(ERR_FATAL, - "%s: %s: %zu is > full buffer size %zu", + "%s: %s: %zu is > full buffer size %u", __func__, buf->tag, len, buf->maxsize); } diff --git a/src/common/tests.c b/src/common/tests.c index d3f31e067..907a387cc 100644 --- a/src/common/tests.c +++ b/src/common/tests.c @@ -49,7 +49,7 @@ static void Com_Activate_f(void) return; } - act = atoi(Cmd_Argv(1)); + act = Q_atoi(Cmd_Argv(1)); if (act < ACT_MINIMIZED || act > ACT_ACTIVATED) { Com_Printf("Bad mode\n"); return; @@ -90,7 +90,7 @@ static void Com_Crash_f(void) { static byte buf1[16]; byte buf2[16], *buf3; - int i = atoi(Cmd_Argv(1)); + int i = Q_atoi(Cmd_Argv(1)); switch (i) { case 1: @@ -148,7 +148,7 @@ static void Com_PrintJunk_f(void) buf[Q_rand() % (sizeof(buf) - 1)] = ' '; if (Cmd_Argc() > 1) - count = atoi(Cmd_Argv(1)); + count = Q_atoi(Cmd_Argv(1)); else count = 1; diff --git a/src/common/utils.c b/src/common/utils.c index ad5dd218b..c8073244f 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -207,7 +207,7 @@ color_index_t Com_ParseColor(const char *s) color_index_t i; if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); if (i < 0 || i >= COLOR_COUNT) { return COLOR_NONE; } diff --git a/src/common/zone.c b/src/common/zone.c index 9addeb5ff..e5f941fb7 100644 --- a/src/common/zone.c +++ b/src/common/zone.c @@ -197,6 +197,12 @@ void *Z_Realloc(void *ptr, size_t size) return z + 1; } +void *Z_ReallocArray(void *ptr, size_t nmemb, size_t size) +{ + Q_assert(!size || nmemb <= INT_MAX / size); + return Z_Realloc(ptr, nmemb * size); +} + /* ======================== Z_Stats_f diff --git a/src/game/g_ai.c b/src/game/g_ai.c index bfda9c967..b4fd347a7 100644 --- a/src/game/g_ai.c +++ b/src/game/g_ai.c @@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "g_local.h" bool FindTarget(edict_t *self); -extern cvar_t *maxclients; bool ai_checkattack(edict_t *self, float dist); @@ -59,9 +58,7 @@ void AI_SetSightClient(void) if (check > game.maxclients) check = 1; ent = &g_edicts[check]; - if (ent->inuse - && ent->health > 0 - && !(ent->flags & FL_NOTARGET)) { + if (ent->inuse && ent->health > 0 && !(ent->flags & FL_NOTARGET)) { level.sight_client = ent; return; // got one } @@ -380,10 +377,9 @@ bool FindTarget(edict_t *self) int r; if (self->monsterinfo.aiflags & AI_GOOD_GUY) { - if (self->goalentity && self->goalentity->inuse && self->goalentity->classname) { + if (self->goalentity && self->goalentity->inuse && self->goalentity->classname) if (strcmp(self->goalentity->classname, "target_actor") == 0) return false; - } //FIXME look for monsters? return false; @@ -403,9 +399,8 @@ bool FindTarget(edict_t *self) heardit = false; if ((level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1)) { client = level.sight_entity; - if (client->enemy == self->enemy) { + if (client->enemy == self->enemy) return false; - } } else if (level.sound_entity_framenum >= (level.framenum - 1)) { client = level.sound_entity; heardit = true; @@ -451,18 +446,15 @@ bool FindTarget(edict_t *self) if (client->light_level <= 5) return false; - if (!visible(self, client)) { + if (!visible(self, client)) return false; - } if (r == RANGE_NEAR) { - if (client->show_hostile < level.framenum && !infront(self, client)) { + if (client->show_hostile < level.framenum && !infront(self, client)) return false; - } } else if (r == RANGE_MID) { - if (!infront(self, client)) { + if (!infront(self, client)) return false; - } } self->enemy = client; @@ -491,9 +483,8 @@ bool FindTarget(edict_t *self) VectorSubtract(client->s.origin, self->s.origin, temp); - if (VectorLength(temp) > 1000) { // too far to hear + if (VectorLength(temp) > 1000) // too far to hear return false; - } // check area portals - if they are different and not connected then we can't hear it if (client->areanum != self->areanum) @@ -581,17 +572,16 @@ bool M_CheckAttack(edict_t *self) if (enemy_range == RANGE_FAR) return false; - if (self->monsterinfo.aiflags & AI_STAND_GROUND) { + if (self->monsterinfo.aiflags & AI_STAND_GROUND) chance = 0.4f; - } else if (enemy_range == RANGE_MELEE) { + else if (enemy_range == RANGE_MELEE) chance = 0.2f; - } else if (enemy_range == RANGE_NEAR) { + else if (enemy_range == RANGE_NEAR) chance = 0.1f; - } else if (enemy_range == RANGE_MID) { + else if (enemy_range == RANGE_MID) chance = 0.02f; - } else { + else return false; - } if (skill->value == 0) chance *= 0.5f; @@ -962,6 +952,6 @@ void ai_run(edict_t *self, float dist) G_FreeEdict(tempgoal); - if (self) + if (self->inuse) self->goalentity = save; } diff --git a/src/game/g_chase.c b/src/game/g_chase.c index f33dc2611..c2d971f8c 100644 --- a/src/game/g_chase.c +++ b/src/game/g_chase.c @@ -115,7 +115,7 @@ void ChaseNext(edict_t *ent) i = ent->client->chase_target - g_edicts; do { i++; - if (i > maxclients->value) + if (i > game.maxclients) i = 1; e = g_edicts + i; if (!e->inuse) @@ -140,7 +140,7 @@ void ChasePrev(edict_t *ent) do { i--; if (i < 1) - i = maxclients->value; + i = game.maxclients; e = g_edicts + i; if (!e->inuse) continue; @@ -157,7 +157,7 @@ void GetChaseTarget(edict_t *ent) int i; edict_t *other; - for (i = 1; i <= maxclients->value; i++) { + for (i = 1; i <= game.maxclients; i++) { other = g_edicts + i; if (other->inuse && !other->client->resp.spectator) { ent->client->chase_target = other; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 7744e26a1..0d548f6b1 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -72,8 +72,8 @@ void SelectNextItem(edict_t *ent, int itflags) } // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (cl->pers.selected_item + i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (cl->pers.selected_item + i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -103,8 +103,8 @@ void SelectPrevItem(edict_t *ent, int itflags) } // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (cl->pers.selected_item + MAX_ITEMS - i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (cl->pers.selected_item + game.num_items - i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -164,7 +164,7 @@ void Cmd_Give_f(edict_t *ent) if (give_all || Q_stricmp(gi.argv(1), "health") == 0) { if (gi.argc() == 3) - ent->health = atoi(gi.argv(2)); + ent->health = Q_atoi(gi.argv(2)); else ent->health = ent->max_health; if (!give_all) @@ -258,7 +258,7 @@ void Cmd_Give_f(edict_t *ent) if (it->flags & IT_AMMO) { if (gi.argc() == 3) - ent->client->pers.inventory[index] = atoi(gi.argv(2)); + ent->client->pers.inventory[index] = Q_atoi(gi.argv(2)); else ent->client->pers.inventory[index] += it->quantity; } else { @@ -477,8 +477,8 @@ void Cmd_WeapPrev_f(edict_t *ent) selected_weapon = ITEM_INDEX(cl->pers.weapon); // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (selected_weapon + i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (selected_weapon + i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -512,8 +512,8 @@ void Cmd_WeapNext_f(edict_t *ent) selected_weapon = ITEM_INDEX(cl->pers.weapon); // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (selected_weapon + MAX_ITEMS - i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (selected_weapon + game.num_items - i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -633,10 +633,10 @@ void Cmd_Players_f(edict_t *ent) int count; char small[64]; char large[1280]; - int index[256]; + int index[MAX_CLIENTS]; count = 0; - for (i = 0; i < maxclients->value; i++) + for (i = 0; i < game.maxclients; i++) if (game.clients[i].pers.connected) { index[count] = i; count++; @@ -672,7 +672,7 @@ void Cmd_Wave_f(edict_t *ent) { int i; - i = atoi(gi.argv(1)); + i = Q_atoi(gi.argv(1)); // can't wave when ducked if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) @@ -808,7 +808,7 @@ void Cmd_PlayerList_f(edict_t *ent) // connect time, ping, score, name *text = 0; - for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++) { + for (i = 0, e2 = g_edicts + 1; i < game.maxclients; i++, e2++) { if (!e2->inuse) continue; diff --git a/src/game/g_combat.c b/src/game/g_combat.c index ba921fd8d..6ff9e31d8 100644 --- a/src/game/g_combat.c +++ b/src/game/g_combat.c @@ -34,8 +34,7 @@ bool CanDamage(edict_t *targ, edict_t *inflictor) // bmodels need special checking because their origin is 0,0,0 if (targ->movetype == MOVETYPE_PUSH) { - VectorAdd(targ->absmin, targ->absmax, dest); - VectorScale(dest, 0.5f, dest); + VectorAvg(targ->absmin, targ->absmax, dest); trace = gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID); if (trace.fraction == 1.0f) return true; @@ -515,8 +514,8 @@ void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t if (!ent->takedamage) continue; - VectorAdd(ent->mins, ent->maxs, v); - VectorMA(ent->s.origin, 0.5f, v, v); + VectorAvg(ent->mins, ent->maxs, v); + VectorAdd(ent->s.origin, v, v); VectorSubtract(inflictor->s.origin, v, v); points = damage - 0.5f * VectorLength(v); if (ent == attacker) diff --git a/src/game/g_func.c b/src/game/g_func.c index 3c3595825..c4653ec1e 100644 --- a/src/game/g_func.c +++ b/src/game/g_func.c @@ -97,7 +97,7 @@ void Move_Begin(edict_t *ent) return; } VectorScale(ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity); - frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); + frames = floorf((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME; ent->nextthink = level.framenum + frames; ent->think = Move_Final; @@ -105,7 +105,7 @@ void Move_Begin(edict_t *ent) void Think_AccelMove(edict_t *ent); -void Move_Calc(edict_t *ent, const vec3_t dest, void(*func)(edict_t*)) +void Move_Calc(edict_t *ent, const vec3_t dest, void (*func)(edict_t *)) { VectorClear(ent->velocity); VectorSubtract(dest, ent->s.origin, ent->moveinfo.dir); @@ -181,7 +181,7 @@ void AngleMove_Begin(edict_t *ent) return; } - frames = floor(traveltime / FRAMETIME); + frames = floorf(traveltime / FRAMETIME); // scale the destdelta vector by the time spent traveling to get velocity VectorScale(destdelta, 1.0f / traveltime, ent->avelocity); @@ -191,7 +191,7 @@ void AngleMove_Begin(edict_t *ent) ent->think = AngleMove_Final; } -void AngleMove_Calc(edict_t *ent, void(*func)(edict_t*)) +void AngleMove_Calc(edict_t *ent, void (*func)(edict_t *)) { VectorClear(ent->avelocity); ent->moveinfo.endfunc = func; @@ -378,7 +378,7 @@ void plat_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -744,7 +744,7 @@ void SP_func_button(edict_t *ent) abs_movedir[0] = fabsf(ent->movedir[0]); abs_movedir[1] = fabsf(ent->movedir[1]); abs_movedir[2] = fabsf(ent->movedir[2]); - dist = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip; + dist = DotProduct(abs_movedir, ent->size) - st.lip; VectorMA(ent->pos1, dist, ent->movedir, ent->pos2); ent->use = button_use; @@ -1019,7 +1019,7 @@ void door_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -1106,7 +1106,7 @@ void SP_func_door(edict_t *ent) abs_movedir[0] = fabsf(ent->movedir[0]); abs_movedir[1] = fabsf(ent->movedir[1]); abs_movedir[2] = fabsf(ent->movedir[2]); - ent->moveinfo.distance = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip; + ent->moveinfo.distance = DotProduct(abs_movedir, ent->size) - st.lip; VectorMA(ent->pos1, ent->moveinfo.distance, ent->movedir, ent->pos2); // if it starts open, switch the positions @@ -1323,7 +1323,7 @@ void SP_func_water(edict_t *self) abs_movedir[0] = fabsf(self->movedir[0]); abs_movedir[1] = fabsf(self->movedir[1]); abs_movedir[2] = fabsf(self->movedir[2]); - self->moveinfo.distance = abs_movedir[0] * self->size[0] + abs_movedir[1] * self->size[1] + abs_movedir[2] * self->size[2] - st.lip; + self->moveinfo.distance = DotProduct(abs_movedir, self->size) - st.lip; VectorMA(self->pos1, self->moveinfo.distance, self->movedir, self->pos2); // if it starts open, switch the positions @@ -1380,7 +1380,7 @@ void train_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -1818,7 +1818,7 @@ void door_secret_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -1866,9 +1866,7 @@ void SP_func_door_secret(edict_t *ent) if (!ent->wait) ent->wait = 5; - ent->moveinfo.accel = - ent->moveinfo.decel = - ent->moveinfo.speed = 50; + ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = 50; // calculate positions AngleVectors(ent->s.angles, forward, right, up); diff --git a/src/game/g_items.c b/src/game/g_items.c index 3c08ed3ee..3315c8088 100644 --- a/src/game/g_items.c +++ b/src/game/g_items.c @@ -1933,7 +1933,7 @@ void SP_item_health_mega(edict_t *self) void InitItems(void) { - game.num_items = sizeof(itemlist) / sizeof(itemlist[0]) - 1; + game.num_items = q_countof(itemlist) - 1; } /* diff --git a/src/game/g_local.h b/src/game/g_local.h index 11e3723d7..bed1319ab 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -247,6 +247,11 @@ typedef struct gitem_s { const char *const *precaches; // array of all models, sounds, and images this item will use } gitem_t; +typedef struct precache_s { + struct precache_s *next; + void (*func)(void); +} precache_t; + // // this structure is left intact through an entire game // it should be initialized at dll load time, and read/written to @@ -277,6 +282,8 @@ typedef struct { bool autosaved; cs_remap_t csr; + + precache_t *precaches; } game_locals_t; // @@ -431,7 +438,6 @@ extern game_export_t globals; extern spawn_temp_t st; extern int sm_meat_index; -extern int snd_fry; //extern int jacket_armor_index; //extern int combat_armor_index; @@ -788,6 +794,12 @@ void ChaseNext(edict_t *ent); void ChasePrev(edict_t *ent); void GetChaseTarget(edict_t *ent); +// +// g_spawn.c +// +void G_AddPrecache(void (*func)(void)); +void G_RefreshPrecaches(void); + //============================================================================ // client_t->anim_priority diff --git a/src/game/g_main.c b/src/game/g_main.c index b873c9523..aef457e01 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -25,7 +25,6 @@ game_export_t globals; spawn_temp_t st; int sm_meat_index; -int snd_fry; int meansOfDeath; edict_t *g_edicts; @@ -99,6 +98,8 @@ void ShutdownGame(void) { gi.dprintf("==== ShutdownGame ====\n"); + memset(&game, 0, sizeof(game)); + gi.FreeTags(TAG_LEVEL); gi.FreeTags(TAG_GAME); } @@ -140,8 +141,8 @@ void InitGame(void) // latched vars sv_cheats = gi.cvar("cheats", "0", CVAR_SERVERINFO | CVAR_LATCH); - gi.cvar("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); - gi.cvar("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH); + gi.cvar("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH); + gi.cvar("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH); maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); maxspectators = gi.cvar("maxspectators", "4", CVAR_SERVERINFO); @@ -200,8 +201,7 @@ void InitGame(void) game.helpmessage2[0] = 0; // initialize all entities for this game - game.maxentities = maxentities->value; - clamp(game.maxentities, (int)maxclients->value + 1, game.csr.max_edicts); + game.maxentities = Q_clip(maxentities->value, (int)maxclients->value + 1, game.csr.max_edicts); g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME); globals.edicts = g_edicts; globals.max_edicts = game.maxentities; @@ -295,7 +295,7 @@ void ClientEndServerFrames(void) // calc the player views now that all pushing // and damage has been added - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { ent = g_edicts + 1 + i; if (!ent->inuse || !ent->client) continue; @@ -431,7 +431,7 @@ void CheckDMRules(void) } if (fraglimit->value) { - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { cl = game.clients + i; if (!g_edicts[i + 1].inuse) continue; @@ -463,7 +463,7 @@ void ExitLevel(void) level.intermission_framenum = 0; // clear some things before going to next level - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { ent = g_edicts + 1 + i; if (!ent->inuse) continue; @@ -519,7 +519,7 @@ void G_RunFrame(void) } } - if (i > 0 && i <= maxclients->value) { + if (i > 0 && i <= game.maxclients) { ClientBeginServerFrame(ent); continue; } diff --git a/src/game/g_misc.c b/src/game/g_misc.c index ad32a8338..ee3c9aec4 100644 --- a/src/game/g_misc.c +++ b/src/game/g_misc.c @@ -65,9 +65,9 @@ void VelocityForDamage(int damage, vec3_t v) void ClipGibVelocity(edict_t *ent) { - clamp(ent->velocity[0], -300, 300); - clamp(ent->velocity[1], -300, 300); - clamp(ent->velocity[2], 200, 500); // always some upwards + ent->velocity[0] = Q_clipf(ent->velocity[0], -300, 300); + ent->velocity[1] = Q_clipf(ent->velocity[1], -300, 300); + ent->velocity[2] = Q_clipf(ent->velocity[2], 200, 500); // always some upwards } /* @@ -1506,18 +1506,12 @@ static void func_clock_format_countdown(edict_t *self) } if (self->style == 1) { - Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60); - if (self->message[3] == ' ') - self->message[3] = '0'; + Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%02i", self->health / 60, self->health % 60); return; } if (self->style == 2) { - Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60); - if (self->message[3] == ' ') - self->message[3] = '0'; - if (self->message[6] == ' ') - self->message[6] = '0'; + Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%02i:%02i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60); return; } } @@ -1543,13 +1537,9 @@ void func_clock_think(edict_t *self) gmtime = time(NULL); ltime = localtime(&gmtime); if (ltime) - Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec); + Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%02i:%02i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec); else strcpy(self->message, "00:00:00"); - if (self->message[3] == ' ') - self->message[3] = '0'; - if (self->message[6] == ' ') - self->message[6] = '0'; } self->enemy->message = self->message; @@ -1607,7 +1597,7 @@ void SP_func_clock(edict_t *self) } if ((self->spawnflags & 1) && (!self->count)) - self->count = 60 * 60;; + self->count = 60 * 60; func_clock_reset(self); diff --git a/src/game/g_monster.c b/src/game/g_monster.c index 33422d815..9b8b415a7 100644 --- a/src/game/g_monster.c +++ b/src/game/g_monster.c @@ -419,11 +419,10 @@ void monster_triggered_spawn(edict_t *self) monster_start_go(self); - if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET)) { + if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET)) FoundTarget(self); - } else { + else self->enemy = NULL; - } } void monster_triggered_spawn_use(edict_t *self, edict_t *other, edict_t *activator) diff --git a/src/game/g_phys.c b/src/game/g_phys.c index 10029b7e3..ef365f798 100644 --- a/src/game/g_phys.c +++ b/src/game/g_phys.c @@ -66,13 +66,14 @@ SV_CheckVelocity */ void SV_CheckVelocity(edict_t *ent) { - int i; + float speed = sv_maxvelocity->value; // // bound velocity // - for (i = 0; i < 3; i++) - clamp(ent->velocity[i], -sv_maxvelocity->value, sv_maxvelocity->value); + ent->velocity[0] = Q_clipf(ent->velocity[0], -speed, speed); + ent->velocity[1] = Q_clipf(ent->velocity[1], -speed, speed); + ent->velocity[2] = Q_clipf(ent->velocity[2], -speed, speed); } /* @@ -418,7 +419,7 @@ bool SV_Push(edict_t *pusher, vec3_t move, vec3_t amove) || check->movetype == MOVETYPE_NOCLIP) continue; - if (!check->area.prev) + if (!check->area.next) continue; // not linked in anywhere // if the entity is standing on the pusher, it will definitely be moved diff --git a/src/game/g_save.c b/src/game/g_save.c index 7562f80d3..dfa4053c3 100644 --- a/src/game/g_save.c +++ b/src/game/g_save.c @@ -973,7 +973,7 @@ void ReadLevel(const char *filename) // wipe all the entities memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); - globals.num_edicts = maxclients->value + 1; + globals.num_edicts = game.maxclients + 1; i = read_int(f); if (i != SAVE_MAGIC2) { @@ -1016,7 +1016,7 @@ void ReadLevel(const char *filename) gzclose(f); // mark all clients as unconnected - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { ent = &g_edicts[i + 1]; ent->client = game.clients + i; ent->client->pers.connected = false; @@ -1043,4 +1043,7 @@ void ReadLevel(const char *filename) } } } + + // refresh global precache indices + G_RefreshPrecaches(); } diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 7171603fb..a886f3719 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -346,6 +346,7 @@ void ED_CallSpawn(edict_t *ent) if (!ent->classname) { gi.dprintf("ED_CallSpawn: NULL classname\n"); + G_FreeEdict(ent); return; } @@ -368,7 +369,9 @@ void ED_CallSpawn(edict_t *ent) return; } } + gi.dprintf("%s doesn't have a spawn function\n", ent->classname); + G_FreeEdict(ent); } /* @@ -432,7 +435,7 @@ static bool ED_ParseField(const spawn_field_t *fields, const char *key, const ch ((float *)(b + f->ofs))[2] = vec[2]; break; case F_INT: - *(int *)(b + f->ofs) = atoi(value); + *(int *)(b + f->ofs) = Q_atoi(value); break; case F_FLOAT: *(float *)(b + f->ofs) = atof(value); @@ -554,6 +557,64 @@ void G_FindTeams(void) gi.dprintf("%i teams with %i entities\n", c, c2); } +/* +============== +G_AddPrecache + +Register new global precache function and call it (once). +============== +*/ +void G_AddPrecache(void (*func)(void)) +{ + precache_t *prec; + + for (prec = game.precaches; prec; prec = prec->next) + if (prec->func == func) + return; + + prec = gi.TagMalloc(sizeof(*prec), TAG_GAME); + prec->func = func; + prec->next = game.precaches; + game.precaches = prec; + + prec->func(); +} + +/* +============== +G_RefreshPrecaches + +Called from ReadLevel() to refresh all global precache indices registered by +spawn functions. +============== +*/ +void G_RefreshPrecaches(void) +{ + precache_t *prec; + + for (prec = game.precaches; prec; prec = prec->next) + prec->func(); +} + +/* +============== +G_FreePrecaches + +Free precache functions from previous level. +============== +*/ +static void G_FreePrecaches(void) +{ + precache_t *prec, *next; + + for (prec = game.precaches; prec; prec = next) { + next = prec->next; + gi.TagFree(prec); + } + + game.precaches = NULL; +} + /* ============== SpawnEntities @@ -568,17 +629,18 @@ void SpawnEntities(const char *mapname, const char *entities, const char *spawnp int inhibit; char *com_token; int i; - float skill_level; + int skill_level; - skill_level = floor(skill->value); - clamp(skill_level, 0, 3); + skill_level = Q_clip(skill->value, 0, 3); if (skill->value != skill_level) - gi.cvar_forceset("skill", va("%f", skill_level)); + gi.cvar_forceset("skill", va("%d", skill_level)); SaveClientData(); gi.FreeTags(TAG_LEVEL); + G_FreePrecaches(); + memset(&level, 0, sizeof(level)); memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); @@ -808,6 +870,11 @@ static const char *const lightstyles[] = { "abcdefghijklmnopqrrqponmlkjihgfedcba", }; +static void worldspawn_precache(void) +{ + sm_meat_index = gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); +} + /*QUAKED worldspawn (0 0 0) ? Only used for the world. @@ -859,7 +926,7 @@ void SP_worldspawn(edict_t *ent) else gi.configstring(CS_CDTRACK, va("%i", ent->sounds)); - gi.configstring(game.csr.maxclients, va("%i", (int)(maxclients->value))); + gi.configstring(game.csr.maxclients, va("%i", game.maxclients)); // status bar program if (deathmatch->value) @@ -880,8 +947,7 @@ void SP_worldspawn(edict_t *ent) else gi.cvar_set("sv_gravity", st.gravity); - snd_fry = gi.soundindex("player/fry.wav"); // standing in lava / slime - + gi.soundindex("player/fry.wav"); // standing in lava / slime gi.soundindex("player/lava_in.wav"); gi.soundindex("player/burn1.wav"); gi.soundindex("player/burn2.wav"); @@ -959,7 +1025,7 @@ void SP_worldspawn(edict_t *ent) gi.soundindex("infantry/inflies1.wav"); - sm_meat_index = gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); + gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); gi.modelindex("models/objects/gibs/arm/tris.md2"); gi.modelindex("models/objects/gibs/bone/tris.md2"); gi.modelindex("models/objects/gibs/bone2/tris.md2"); @@ -967,6 +1033,8 @@ void SP_worldspawn(edict_t *ent) gi.modelindex("models/objects/gibs/skull/tris.md2"); gi.modelindex("models/objects/gibs/head2/tris.md2"); + G_AddPrecache(worldspawn_precache); + // // Setup light animation tables. 'a' is total darkness, 'z' is doublebright. // diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index 36b07625f..4381400a0 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -89,7 +89,7 @@ static bool StringToFilter(char *s, ipfilter_t *f) num[j++] = *s++; } num[j] = 0; - b.bytes[i] = atoi(num); + b.bytes[i] = Q_atoi(num); if (b.bytes[i] != 0) m.bytes[i] = 255; diff --git a/src/game/g_target.c b/src/game/g_target.c index bc9de6f8f..886fd86f3 100644 --- a/src/game/g_target.c +++ b/src/game/g_target.c @@ -460,7 +460,7 @@ void target_crosslevel_target_think(edict_t *self) void SP_target_crosslevel_target(edict_t *self) { - if (! self->delay) + if (!self->delay) self->delay = 1; self->svflags = SVF_NOCLIENT; @@ -640,12 +640,8 @@ void target_lightramp_think(edict_t *self) if (diff < self->speed) { self->nextthink = level.framenum + 1; } else if (self->spawnflags & 1) { - char temp; - - temp = self->movedir[0]; - self->movedir[0] = self->movedir[1]; - self->movedir[1] = temp; - self->movedir[2] *= -1; + SWAP(float, self->movedir[0], self->movedir[1]); + self->movedir[2] = -self->movedir[2]; } } @@ -726,7 +722,7 @@ void target_earthquake_think(edict_t *self) self->last_move_framenum = level.framenum + 0.5f * BASE_FRAMERATE; } - for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++) { + for (i = 1, e = g_edicts + i; i <= game.maxclients; i++, e++) { if (!e->inuse) continue; if (!e->client) diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c index 3ae40327a..80dd39e63 100644 --- a/src/game/g_trigger.c +++ b/src/game/g_trigger.c @@ -351,8 +351,6 @@ trigger_push #define PUSH_ONCE 1 -static int windsound; - void trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { if (strcmp(other->classname, "grenade") == 0) { @@ -365,7 +363,7 @@ void trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface VectorCopy(other->velocity, other->client->oldvelocity); if (other->fly_sound_debounce_framenum < level.framenum) { other->fly_sound_debounce_framenum = level.framenum + 1.5f * BASE_FRAMERATE; - gi.sound(other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0); + gi.sound(other, CHAN_AUTO, gi.soundindex("misc/windfly.wav"), 1, ATTN_NORM, 0); } } } @@ -380,7 +378,7 @@ Pushes the player void SP_trigger_push(edict_t *self) { InitTrigger(self); - windsound = gi.soundindex("misc/windfly.wav"); + gi.soundindex("misc/windfly.wav"); self->touch = trigger_push_touch; if (!self->speed) self->speed = 1000; @@ -434,10 +432,8 @@ void hurt_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf else self->timestamp = level.framenum + 0.1f * BASE_FRAMERATE; - if (!(self->spawnflags & 4)) { - if ((level.framenum % 10) == 0) - gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); - } + if (!(self->spawnflags & 4) && !(level.framenum % BASE_FRAMERATE)) + gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); if (self->spawnflags & 8) dflags = DAMAGE_NO_PROTECTION; @@ -495,7 +491,7 @@ void SP_trigger_gravity(edict_t *self) } InitTrigger(self); - self->gravity = atoi(st.gravity); + self->gravity = Q_atoi(st.gravity); self->touch = trigger_gravity_touch; } diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 1f542a10a..f685c504e 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -72,7 +72,7 @@ findradius (origin, radius) edict_t *findradius(edict_t *from, vec3_t org, float rad) { vec3_t eorg; - int j; + vec3_t mid; if (!from) from = g_edicts; @@ -83,9 +83,9 @@ edict_t *findradius(edict_t *from, vec3_t org, float rad) continue; if (from->solid == SOLID_NOT) continue; - for (j = 0; j < 3; j++) - eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j]) * 0.5f); - if (VectorLength(eorg) > rad) + VectorAvg(from->mins, from->maxs, mid); + VectorAdd(from->s.origin, mid, eorg); + if (Distance(eorg, org) > rad) continue; return from; } @@ -236,13 +236,12 @@ static const vec3_t MOVEDIR_DOWN = { 0, 0, -1 }; void G_SetMovedir(vec3_t angles, vec3_t movedir) { - if (VectorCompare(angles, VEC_UP)) { + if (VectorCompare(angles, VEC_UP)) VectorCopy(MOVEDIR_UP, movedir); - } else if (VectorCompare(angles, VEC_DOWN)) { + else if (VectorCompare(angles, VEC_DOWN)) VectorCopy(MOVEDIR_DOWN, movedir); - } else { + else AngleVectors(angles, movedir, NULL, NULL); - } VectorClear(angles); } @@ -360,7 +359,7 @@ void G_FreeEdict(edict_t *ed) { gi.unlinkentity(ed); // unlink from world - if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE)) { + if ((ed - g_edicts) <= (game.maxclients + BODY_QUEUE_SIZE)) { // gi.dprintf("tried to free special edict\n"); return; } @@ -380,13 +379,13 @@ G_TouchTriggers void G_TouchTriggers(edict_t *ent) { int i, num; - edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS_OLD], *hit; // dead things don't activate triggers! if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) return; - num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); + num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, q_countof(touch), AREA_TRIGGERS); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) @@ -411,9 +410,9 @@ to force all entities it covers to immediately touch it void G_TouchSolids(edict_t *ent) { int i, num; - edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS_OLD], *hit; - num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID); + num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, q_countof(touch), AREA_SOLID); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 87b571427..3e78e7a14 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -34,10 +34,8 @@ static void check_dodge(edict_t *self, vec3_t start, vec3_t dir, int speed) float eta; // easy mode only ducks one quarter the time - if (skill->value == 0) { - if (random() > 0.25f) - return; - } + if (skill->value == 0 && random() > 0.25f) + return; VectorMA(start, 8192, dir, end); tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self)) { @@ -277,6 +275,7 @@ Fires a single blaster bolt. Used by the blaster and hyper blaster. */ void blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { + vec_t *normal = NULL; int mod; if (other == self->owner) @@ -290,20 +289,20 @@ void blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *s if (self->owner->client) PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); + if (plane) + normal = plane->normal; + if (other->takedamage) { if (self->spawnflags & 1) mod = MOD_HYPERBLASTER; else mod = MOD_BLASTER; - T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod); + T_Damage(other, self, self->owner, self->velocity, self->s.origin, normal, self->dmg, 1, DAMAGE_ENERGY, mod); } else { gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_BLASTER); gi.WritePosition(self->s.origin); - if (!plane) - gi.WriteDir(vec3_origin); - else - gi.WriteDir(plane->normal); + gi.WriteDir(normal); gi.multicast(self->s.origin, MULTICAST_PVS); } @@ -376,8 +375,8 @@ void Grenade_Explode(edict_t *ent) vec3_t v; vec3_t dir; - VectorAdd(ent->enemy->mins, ent->enemy->maxs, v); - VectorMA(ent->enemy->s.origin, 0.5f, v, v); + VectorAvg(ent->enemy->mins, ent->enemy->maxs, v); + VectorAdd(ent->enemy->s.origin, v, v); VectorSubtract(ent->s.origin, v, v); points = ent->dmg - 0.5f * VectorLength(v); VectorSubtract(ent->enemy->s.origin, ent->s.origin, dir); @@ -548,7 +547,7 @@ void rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *sur VectorMA(ent->s.origin, -0.02f, ent->velocity, origin); if (other->takedamage) { - T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET); + T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, plane ? plane->normal : NULL, ent->dmg, 0, 0, MOD_ROCKET); } else { // don't throw any debris in net games if (!deathmatch->value && !coop->value) { @@ -635,7 +634,7 @@ void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick) } else { //ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc) if (((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) || - (tr.ent->solid == SOLID_BBOX)) && (lastfrac + tr.fraction > 0)) + (tr.ent->solid == SOLID_BBOX)) && (lastfrac + tr.fraction > 0)) ignore = tr.ent; else ignore = NULL; @@ -692,8 +691,8 @@ void bfg_explode(edict_t *self) if (!CanDamage(ent, self->owner)) continue; - VectorAdd(ent->mins, ent->maxs, v); - VectorMA(ent->s.origin, 0.5f, v, v); + VectorAvg(ent->mins, ent->maxs, v); + VectorAdd(ent->s.origin, v, v); VectorSubtract(self->s.origin, v, v); dist = VectorLength(v); points = self->radius_dmg * (1.0f - sqrtf(dist / self->dmg_radius)); @@ -729,7 +728,7 @@ void bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) // core explosion - prevents firing it into the wall/floor if (other->takedamage) - T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST); + T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane ? plane->normal : NULL, 200, 0, 0, MOD_BFG_BLAST); T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST); gi.sound(self, CHAN_VOICE, gi.soundindex("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0); diff --git a/src/game/m_berserk.c b/src/game/m_berserk.c index d0c534577..8a02b0c80 100644 --- a/src/game/m_berserk.c +++ b/src/game/m_berserk.c @@ -158,7 +158,8 @@ void berserk_run(edict_t *self) void berserk_attack_spike(edict_t *self) { - vec3_t aim = {MELEE_DISTANCE, 0, -24}; + vec3_t aim = { MELEE_DISTANCE, 0, -24 }; + fire_hit(self, aim, (15 + (Q_rand() % 6)), 400); // Faster attack -- upwards and backwards } @@ -181,9 +182,8 @@ const mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_f void berserk_attack_club(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], -4 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], -4); fire_hit(self, aim, (5 + (Q_rand() % 6)), 400); // Slower attack } @@ -376,6 +376,16 @@ void berserk_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag self->monsterinfo.currentmove = &berserk_move_death2; } +static void berserk_precache(void) +{ + sound_pain = gi.soundindex("berserk/berpain2.wav"); + sound_die = gi.soundindex("berserk/berdeth2.wav"); + sound_idle = gi.soundindex("berserk/beridle1.wav"); + sound_punch = gi.soundindex("berserk/attack.wav"); + sound_search = gi.soundindex("berserk/bersrch1.wav"); + sound_sight = gi.soundindex("berserk/sight.wav"); +} + /*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_berserk(edict_t *self) @@ -386,12 +396,7 @@ void SP_monster_berserk(edict_t *self) } // pre-caches - sound_pain = gi.soundindex("berserk/berpain2.wav"); - sound_die = gi.soundindex("berserk/berdeth2.wav"); - sound_idle = gi.soundindex("berserk/beridle1.wav"); - sound_punch = gi.soundindex("berserk/attack.wav"); - sound_search = gi.soundindex("berserk/bersrch1.wav"); - sound_sight = gi.soundindex("berserk/sight.wav"); + G_AddPrecache(berserk_precache); self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2"); VectorSet(self->mins, -16, -16, -24); diff --git a/src/game/m_boss2.c b/src/game/m_boss2.c index 0311de7da..fde1f6eb0 100644 --- a/src/game/m_boss2.c +++ b/src/game/m_boss2.c @@ -547,6 +547,15 @@ bool Boss2_CheckAttack(edict_t *self) return false; } +static void boss2_precache(void) +{ + sound_pain1 = gi.soundindex("bosshovr/bhvpain1.wav"); + sound_pain2 = gi.soundindex("bosshovr/bhvpain2.wav"); + sound_pain3 = gi.soundindex("bosshovr/bhvpain3.wav"); + sound_death = gi.soundindex("bosshovr/bhvdeth1.wav"); + sound_search1 = gi.soundindex("bosshovr/bhvunqv1.wav"); +} + /*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight */ void SP_monster_boss2(edict_t *self) @@ -556,11 +565,7 @@ void SP_monster_boss2(edict_t *self) return; } - sound_pain1 = gi.soundindex("bosshovr/bhvpain1.wav"); - sound_pain2 = gi.soundindex("bosshovr/bhvpain2.wav"); - sound_pain3 = gi.soundindex("bosshovr/bhvpain3.wav"); - sound_death = gi.soundindex("bosshovr/bhvdeth1.wav"); - sound_search1 = gi.soundindex("bosshovr/bhvunqv1.wav"); + G_AddPrecache(boss2_precache); self->s.sound = gi.soundindex("bosshovr/bhvengn1.wav"); diff --git a/src/game/m_boss31.c b/src/game/m_boss31.c index 3fdeae472..b8f144dc6 100644 --- a/src/game/m_boss31.c +++ b/src/game/m_boss31.c @@ -374,14 +374,14 @@ const mmove_t jorg_move_end_attack1 = {FRAME_attak115, FRAME_attak118, jorg_fram void jorg_reattack1(edict_t *self) { - if (visible(self, self->enemy)) + if (visible(self, self->enemy)) { if (random() < 0.9f) self->monsterinfo.currentmove = &jorg_move_attack1; else { self->s.sound = 0; self->monsterinfo.currentmove = &jorg_move_end_attack1; } - else { + } else { self->s.sound = 0; self->monsterinfo.currentmove = &jorg_move_end_attack1; } @@ -394,7 +394,6 @@ void jorg_attack1(edict_t *self) void jorg_pain(edict_t *self, edict_t *other, float kick, int damage) { - if (self->health < (self->max_health / 2)) self->s.skinnum = 1; @@ -603,15 +602,8 @@ bool Jorg_CheckAttack(edict_t *self) void MakronPrecache(void); -/*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight -*/ -void SP_monster_jorg(edict_t *self) +static void jorg_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("boss3/bs3pain1.wav"); sound_pain2 = gi.soundindex("boss3/bs3pain2.wav"); sound_pain3 = gi.soundindex("boss3/bs3pain3.wav"); @@ -628,6 +620,18 @@ void SP_monster_jorg(edict_t *self) sound_death_hit = gi.soundindex("boss3/d_hit.wav"); MakronPrecache(); +} + +/*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight +*/ +void SP_monster_jorg(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(jorg_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_boss32.c b/src/game/m_boss32.c index f71ffb999..9df873585 100644 --- a/src/game/m_boss32.c +++ b/src/game/m_boss32.c @@ -768,7 +768,7 @@ void SP_monster_makron(edict_t *self) return; } - MakronPrecache(); + G_AddPrecache(MakronPrecache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_brain.c b/src/game/m_brain.c index 3a1c59318..09258fe24 100644 --- a/src/game/m_brain.c +++ b/src/game/m_brain.c @@ -163,12 +163,12 @@ static const mframe_t brain_frames_walk1[] = { }; const mmove_t brain_move_walk1 = {FRAME_walk101, FRAME_walk111, brain_frames_walk1, NULL}; -void brain_walk(edict_t *self) { +void brain_walk(edict_t *self) +{ self->monsterinfo.currentmove = &brain_move_walk1; } -static const mframe_t brain_frames_defense[] = -{ +static const mframe_t brain_frames_defense[] = { { ai_move, 0, NULL }, { ai_move, 0, NULL }, { ai_move, 0, NULL }, @@ -181,8 +181,7 @@ static const mframe_t brain_frames_defense[] = }; const mmove_t brain_move_defense = {FRAME_defens01, FRAME_defens08, brain_frames_defense, NULL}; -static const mframe_t brain_frames_pain3[] = -{ +static const mframe_t brain_frames_pain3[] = { { ai_move, -2, NULL }, { ai_move, 2, NULL }, { ai_move, 1, NULL }, @@ -192,8 +191,7 @@ static const mframe_t brain_frames_pain3[] = }; const mmove_t brain_move_pain3 = {FRAME_pain301, FRAME_pain306, brain_frames_pain3, brain_run}; -static const mframe_t brain_frames_pain2[] = -{ +static const mframe_t brain_frames_pain2[] = { { ai_move, -2, NULL }, { ai_move, 0, NULL }, { ai_move, 0, NULL }, @@ -205,8 +203,7 @@ static const mframe_t brain_frames_pain2[] = }; const mmove_t brain_move_pain2 = {FRAME_pain201, FRAME_pain208, brain_frames_pain2, brain_run}; -static const mframe_t brain_frames_pain1[] = -{ +static const mframe_t brain_frames_pain1[] = { { ai_move, -6, NULL }, { ai_move, -2, NULL }, { ai_move, -6, NULL }, @@ -235,7 +232,8 @@ const mmove_t brain_move_pain1 = {FRAME_pain101, FRAME_pain121, brain_frames_pai // DUCK // -void brain_duck_down(edict_t *self) { +void brain_duck_down(edict_t *self) +{ if (self->monsterinfo.aiflags & AI_DUCKED) return; self->monsterinfo.aiflags |= AI_DUCKED; @@ -244,22 +242,23 @@ void brain_duck_down(edict_t *self) { gi.linkentity(self); } -void brain_duck_hold(edict_t *self) { +void brain_duck_hold(edict_t *self) +{ if (level.framenum >= self->monsterinfo.pause_framenum) self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; else self->monsterinfo.aiflags |= AI_HOLD_FRAME; } -void brain_duck_up(edict_t *self) { +void brain_duck_up(edict_t *self) +{ self->monsterinfo.aiflags &= ~AI_DUCKED; self->maxs[2] += 32; self->takedamage = DAMAGE_AIM; gi.linkentity(self); } -static const mframe_t brain_frames_duck[] = -{ +static const mframe_t brain_frames_duck[] = { { ai_move, 0, NULL }, { ai_move, -2, brain_duck_down }, { ai_move, 17, brain_duck_hold }, @@ -271,7 +270,8 @@ static const mframe_t brain_frames_duck[] = }; const mmove_t brain_move_duck = {FRAME_duck01, FRAME_duck08, brain_frames_duck, brain_run}; -void brain_dodge(edict_t *self, edict_t *attacker, float eta) { +void brain_dodge(edict_t *self, edict_t *attacker, float eta) +{ if (random() > 0.25f) return; @@ -282,8 +282,7 @@ void brain_dodge(edict_t *self, edict_t *attacker, float eta) { self->monsterinfo.currentmove = &brain_move_duck; } -static const mframe_t brain_frames_death2[] = -{ +static const mframe_t brain_frames_death2[] = { { ai_move, 0, NULL }, { ai_move, 0, NULL }, { ai_move, 0, NULL }, @@ -292,8 +291,7 @@ static const mframe_t brain_frames_death2[] = }; const mmove_t brain_move_death2 = {FRAME_death201, FRAME_death205, brain_frames_death2, brain_dead}; -static const mframe_t brain_frames_death1[] = -{ +static const mframe_t brain_frames_death1[] = { { ai_move, 0, NULL }, { ai_move, 0, NULL }, { ai_move, -2, NULL }, @@ -319,32 +317,33 @@ const mmove_t brain_move_death1 = {FRAME_death101, FRAME_death118, brain_frames_ // MELEE // -void brain_swing_right(edict_t *self) { +void brain_swing_right(edict_t *self) +{ gi.sound(self, CHAN_BODY, sound_melee1, 1, ATTN_NORM, 0); } -void brain_hit_right(edict_t *self) { - vec3_t aim; +void brain_hit_right(edict_t *self) +{ + vec3_t aim = { MELEE_DISTANCE, self->maxs[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 8); if (fire_hit(self, aim, (15 + (Q_rand() % 5)), 40)) gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0); } -void brain_swing_left(edict_t *self) { +void brain_swing_left(edict_t *self) +{ gi.sound(self, CHAN_BODY, sound_melee2, 1, ATTN_NORM, 0); } -void brain_hit_left(edict_t *self) { - vec3_t aim; +void brain_hit_left(edict_t *self) +{ + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 8); if (fire_hit(self, aim, (15 + (Q_rand() % 5)), 40)) gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0); } -static const mframe_t brain_frames_attack1[] = -{ +static const mframe_t brain_frames_attack1[] = { { ai_charge, 8, NULL }, { ai_charge, 3, NULL }, { ai_charge, 5, NULL }, @@ -366,22 +365,24 @@ static const mframe_t brain_frames_attack1[] = }; const mmove_t brain_move_attack1 = {FRAME_attak101, FRAME_attak118, brain_frames_attack1, brain_run}; -void brain_chest_open(edict_t *self) { +void brain_chest_open(edict_t *self) +{ self->spawnflags &= ~65536; self->monsterinfo.power_armor_type = POWER_ARMOR_NONE; gi.sound(self, CHAN_BODY, sound_chest_open, 1, ATTN_NORM, 0); } -void brain_tentacle_attack(edict_t *self) { - vec3_t aim; +void brain_tentacle_attack(edict_t *self) +{ + vec3_t aim = { MELEE_DISTANCE, 0, 8 }; - VectorSet(aim, MELEE_DISTANCE, 0, 8); if (fire_hit(self, aim, (10 + (Q_rand() % 5)), -600) && skill->value > 0) self->spawnflags |= 65536; gi.sound(self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0); } -void brain_chest_closed(edict_t *self) { +void brain_chest_closed(edict_t *self) +{ self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN; if (self->spawnflags & 65536) { self->spawnflags &= ~65536; @@ -389,8 +390,7 @@ void brain_chest_closed(edict_t *self) { } } -static const mframe_t brain_frames_attack2[] = -{ +static const mframe_t brain_frames_attack2[] = { { ai_charge, 5, NULL }, { ai_charge, -4, NULL }, { ai_charge, -4, NULL }, @@ -411,7 +411,8 @@ static const mframe_t brain_frames_attack2[] = }; const mmove_t brain_move_attack2 = {FRAME_attak201, FRAME_attak217, brain_frames_attack2, brain_run}; -void brain_melee(edict_t *self) { +void brain_melee(edict_t *self) +{ if (random() <= 0.5f) self->monsterinfo.currentmove = &brain_move_attack1; else @@ -422,8 +423,7 @@ void brain_melee(edict_t *self) { // RUN // -static const mframe_t brain_frames_run[] = -{ +static const mframe_t brain_frames_run[] = { { ai_run, 9, NULL }, { ai_run, 2, NULL }, { ai_run, 3, NULL }, @@ -438,7 +438,8 @@ static const mframe_t brain_frames_run[] = }; const mmove_t brain_move_run = {FRAME_walk101, FRAME_walk111, brain_frames_run, NULL}; -void brain_run(edict_t *self) { +void brain_run(edict_t *self) +{ self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN; if (self->monsterinfo.aiflags & AI_STAND_GROUND) self->monsterinfo.currentmove = &brain_move_stand; @@ -446,7 +447,8 @@ void brain_run(edict_t *self) { self->monsterinfo.currentmove = &brain_move_run; } -void brain_pain(edict_t *self, edict_t *other, float kick, int damage) { +void brain_pain(edict_t *self, edict_t *other, float kick, int damage) +{ float r; if (self->health < (self->max_health / 2)) @@ -472,7 +474,8 @@ void brain_pain(edict_t *self, edict_t *other, float kick, int damage) { } } -void brain_dead(edict_t *self) { +void brain_dead(edict_t *self) +{ VectorSet(self->mins, -16, -16, -24); VectorSet(self->maxs, 16, 16, -8); self->movetype = MOVETYPE_TOSS; @@ -481,7 +484,8 @@ void brain_dead(edict_t *self) { gi.linkentity(self); } -void brain_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { +void brain_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ int n; self->s.effects = 0; @@ -512,14 +516,8 @@ void brain_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, self->monsterinfo.currentmove = &brain_move_death2; } -/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_brain(edict_t *self) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - +static void brain_precache(void) +{ sound_chest_open = gi.soundindex("brain/brnatck1.wav"); sound_tentacles_extend = gi.soundindex("brain/brnatck2.wav"); sound_tentacles_retract = gi.soundindex("brain/brnatck3.wav"); @@ -534,6 +532,18 @@ void SP_monster_brain(edict_t *self) { sound_melee1 = gi.soundindex("brain/melee1.wav"); sound_melee2 = gi.soundindex("brain/melee2.wav"); sound_melee3 = gi.soundindex("brain/melee3.wav"); +} + +/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_brain(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(brain_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_chick.c b/src/game/m_chick.c index 3cf243fcf..95071b0b1 100644 --- a/src/game/m_chick.c +++ b/src/game/m_chick.c @@ -417,9 +417,8 @@ void chick_dodge(edict_t *self, edict_t *attacker, float eta) void ChickSlash(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 10 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 10); gi.sound(self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0); fire_hit(self, aim, (10 + (Q_rand() % 6)), 100); } @@ -579,15 +578,8 @@ void chick_sight(edict_t *self, edict_t *other) gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); } -/*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_chick(edict_t *self) +static void chick_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_missile_prelaunch = gi.soundindex("chick/chkatck1.wav"); sound_missile_launch = gi.soundindex("chick/chkatck2.wav"); sound_melee_swing = gi.soundindex("chick/chkatck3.wav"); @@ -603,6 +595,18 @@ void SP_monster_chick(edict_t *self) sound_pain3 = gi.soundindex("chick/chkpain3.wav"); sound_sight = gi.soundindex("chick/chksght1.wav"); sound_search = gi.soundindex("chick/chksrch1.wav"); +} + +/*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_chick(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(chick_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_flipper.c b/src/game/m_flipper.c index 1a63e0c84..dced1f519 100644 --- a/src/game/m_flipper.c +++ b/src/game/m_flipper.c @@ -168,9 +168,8 @@ const mmove_t flipper_move_pain1 = {FRAME_flppn201, FRAME_flppn205, flipper_fram void flipper_bite(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, 0, 0 }; - VectorSet(aim, MELEE_DISTANCE, 0, 0); fire_hit(self, aim, 5, 0); } @@ -339,15 +338,8 @@ void flipper_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag self->monsterinfo.currentmove = &flipper_move_death; } -/*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_flipper(edict_t *self) +static void flipper_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("flipper/flppain1.wav"); sound_pain2 = gi.soundindex("flipper/flppain2.wav"); sound_death = gi.soundindex("flipper/flpdeth1.wav"); @@ -356,6 +348,18 @@ void SP_monster_flipper(edict_t *self) sound_idle = gi.soundindex("flipper/flpidle1.wav"); sound_search = gi.soundindex("flipper/flpsrch1.wav"); sound_sight = gi.soundindex("flipper/flpsght1.wav"); +} + +/*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_flipper(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(flipper_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_float.c b/src/game/m_float.c index e91d4316b..bbe7285b7 100644 --- a/src/game/m_float.c +++ b/src/game/m_float.c @@ -495,7 +495,8 @@ void floater_walk(edict_t *self) void floater_wham(edict_t *self) { - vec3_t aim = {MELEE_DISTANCE, 0, 0}; + vec3_t aim = { MELEE_DISTANCE, 0, 0 }; + gi.sound(self, CHAN_WEAPON, sound_attack3, 1, ATTN_NORM, 0); fire_hit(self, aim, 5 + Q_rand() % 6, -50); } @@ -582,6 +583,17 @@ void floater_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag BecomeExplosion1(self); } +static void floater_precache(void) +{ + sound_attack2 = gi.soundindex("floater/fltatck2.wav"); + sound_attack3 = gi.soundindex("floater/fltatck3.wav"); + sound_death1 = gi.soundindex("floater/fltdeth1.wav"); + sound_idle = gi.soundindex("floater/fltidle1.wav"); + sound_pain1 = gi.soundindex("floater/fltpain1.wav"); + sound_pain2 = gi.soundindex("floater/fltpain2.wav"); + sound_sight = gi.soundindex("floater/fltsght1.wav"); +} + /*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_floater(edict_t *self) @@ -591,13 +603,7 @@ void SP_monster_floater(edict_t *self) return; } - sound_attack2 = gi.soundindex("floater/fltatck2.wav"); - sound_attack3 = gi.soundindex("floater/fltatck3.wav"); - sound_death1 = gi.soundindex("floater/fltdeth1.wav"); - sound_idle = gi.soundindex("floater/fltidle1.wav"); - sound_pain1 = gi.soundindex("floater/fltpain1.wav"); - sound_pain2 = gi.soundindex("floater/fltpain2.wav"); - sound_sight = gi.soundindex("floater/fltsght1.wav"); + G_AddPrecache(floater_precache); gi.soundindex("floater/fltatck1.wav"); diff --git a/src/game/m_flyer.c b/src/game/m_flyer.c index c9c00f15b..96d33e5bf 100644 --- a/src/game/m_flyer.c +++ b/src/game/m_flyer.c @@ -398,18 +398,16 @@ const mmove_t flyer_move_attack2 = {FRAME_attak201, FRAME_attak217, flyer_frames void flyer_slash_left(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 0 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 0); fire_hit(self, aim, 5, 0); gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0); } void flyer_slash_right(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->maxs[0], 0 }; - VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 0); fire_hit(self, aim, 5, 0); gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0); } @@ -525,6 +523,17 @@ void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, BecomeExplosion1(self); } +static void flyer_precache(void) +{ + sound_sight = gi.soundindex("flyer/flysght1.wav"); + sound_idle = gi.soundindex("flyer/flysrch1.wav"); + sound_pain1 = gi.soundindex("flyer/flypain1.wav"); + sound_pain2 = gi.soundindex("flyer/flypain2.wav"); + sound_slash = gi.soundindex("flyer/flyatck2.wav"); + sound_sproing = gi.soundindex("flyer/flyatck1.wav"); + sound_die = gi.soundindex("flyer/flydeth1.wav"); +} + /*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_flyer(edict_t *self) @@ -540,13 +549,7 @@ void SP_monster_flyer(edict_t *self) self->target = NULL; } - sound_sight = gi.soundindex("flyer/flysght1.wav"); - sound_idle = gi.soundindex("flyer/flysrch1.wav"); - sound_pain1 = gi.soundindex("flyer/flypain1.wav"); - sound_pain2 = gi.soundindex("flyer/flypain2.wav"); - sound_slash = gi.soundindex("flyer/flyatck2.wav"); - sound_sproing = gi.soundindex("flyer/flyatck1.wav"); - sound_die = gi.soundindex("flyer/flydeth1.wav"); + G_AddPrecache(flyer_precache); gi.soundindex("flyer/flyatck3.wav"); diff --git a/src/game/m_gladiator.c b/src/game/m_gladiator.c index 99b1acc0c..1b5ac6611 100644 --- a/src/game/m_gladiator.c +++ b/src/game/m_gladiator.c @@ -118,9 +118,8 @@ void gladiator_run(edict_t *self) void GaldiatorMelee(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], -4 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], -4); if (fire_hit(self, aim, (20 + (Q_rand() % 5)), 300)) gi.sound(self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0); else @@ -313,15 +312,8 @@ void gladiator_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int dam self->monsterinfo.currentmove = &gladiator_move_death; } -/*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight -*/ -void SP_monster_gladiator(edict_t *self) +static void gladiator_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("gladiator/pain.wav"); sound_pain2 = gi.soundindex("gladiator/gldpain2.wav"); sound_die = gi.soundindex("gladiator/glddeth2.wav"); @@ -332,6 +324,18 @@ void SP_monster_gladiator(edict_t *self) sound_idle = gi.soundindex("gladiator/gldidle1.wav"); sound_search = gi.soundindex("gladiator/gldsrch1.wav"); sound_sight = gi.soundindex("gladiator/sight.wav"); +} + +/*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight +*/ +void SP_monster_gladiator(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(gladiator_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_gunner.c b/src/game/m_gunner.c index ba70980d4..0fb400a65 100644 --- a/src/game/m_gunner.c +++ b/src/game/m_gunner.c @@ -537,6 +537,17 @@ void gunner_refire_chain(edict_t *self) self->monsterinfo.currentmove = &gunner_move_endfire_chain; } +static void gunner_precache(void) +{ + sound_death = gi.soundindex("gunner/death1.wav"); + sound_pain = gi.soundindex("gunner/gunpain2.wav"); + sound_pain2 = gi.soundindex("gunner/gunpain1.wav"); + sound_idle = gi.soundindex("gunner/gunidle1.wav"); + sound_open = gi.soundindex("gunner/gunatck1.wav"); + sound_search = gi.soundindex("gunner/gunsrch1.wav"); + sound_sight = gi.soundindex("gunner/sight1.wav"); +} + /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_gunner(edict_t *self) @@ -546,13 +557,7 @@ void SP_monster_gunner(edict_t *self) return; } - sound_death = gi.soundindex("gunner/death1.wav"); - sound_pain = gi.soundindex("gunner/gunpain2.wav"); - sound_pain2 = gi.soundindex("gunner/gunpain1.wav"); - sound_idle = gi.soundindex("gunner/gunidle1.wav"); - sound_open = gi.soundindex("gunner/gunatck1.wav"); - sound_search = gi.soundindex("gunner/gunsrch1.wav"); - sound_sight = gi.soundindex("gunner/sight1.wav"); + G_AddPrecache(gunner_precache); gi.soundindex("gunner/gunatck2.wav"); gi.soundindex("gunner/gunatck3.wav"); diff --git a/src/game/m_hover.c b/src/game/m_hover.c index 74eb340fa..95c492548 100644 --- a/src/game/m_hover.c +++ b/src/game/m_hover.c @@ -534,6 +534,17 @@ void hover_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, self->monsterinfo.currentmove = &hover_move_death1; } +static void hover_precache(void) +{ + sound_pain1 = gi.soundindex("hover/hovpain1.wav"); + sound_pain2 = gi.soundindex("hover/hovpain2.wav"); + sound_death1 = gi.soundindex("hover/hovdeth1.wav"); + sound_death2 = gi.soundindex("hover/hovdeth2.wav"); + sound_sight = gi.soundindex("hover/hovsght1.wav"); + sound_search1 = gi.soundindex("hover/hovsrch1.wav"); + sound_search2 = gi.soundindex("hover/hovsrch2.wav"); +} + /*QUAKED monster_hover (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_hover(edict_t *self) @@ -543,13 +554,7 @@ void SP_monster_hover(edict_t *self) return; } - sound_pain1 = gi.soundindex("hover/hovpain1.wav"); - sound_pain2 = gi.soundindex("hover/hovpain2.wav"); - sound_death1 = gi.soundindex("hover/hovdeth1.wav"); - sound_death2 = gi.soundindex("hover/hovdeth2.wav"); - sound_sight = gi.soundindex("hover/hovsght1.wav"); - sound_search1 = gi.soundindex("hover/hovsrch1.wav"); - sound_search2 = gi.soundindex("hover/hovsrch2.wav"); + G_AddPrecache(hover_precache); gi.soundindex("hover/hovatck1.wav"); diff --git a/src/game/m_infantry.c b/src/game/m_infantry.c index b2bad416c..e9c8e431f 100644 --- a/src/game/m_infantry.c +++ b/src/game/m_infantry.c @@ -484,9 +484,8 @@ void infantry_swing(edict_t *self) void infantry_smack(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, 0, 0 }; - VectorSet(aim, MELEE_DISTANCE, 0, 0); if (fire_hit(self, aim, (5 + (Q_rand() % 5)), 50)) gi.sound(self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0); } @@ -511,15 +510,8 @@ void infantry_attack(edict_t *self) self->monsterinfo.currentmove = &infantry_move_attack1; } -/*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_infantry(edict_t *self) +static void infantry_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("infantry/infpain1.wav"); sound_pain2 = gi.soundindex("infantry/infpain2.wav"); sound_die1 = gi.soundindex("infantry/infdeth1.wav"); @@ -533,6 +525,18 @@ void SP_monster_infantry(edict_t *self) sound_sight = gi.soundindex("infantry/infsght1.wav"); sound_search = gi.soundindex("infantry/infsrch1.wav"); sound_idle = gi.soundindex("infantry/infidle1.wav"); +} + +/*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_infantry(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(infantry_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_insane.c b/src/game/m_insane.c index 130a87bed..edec16a5c 100644 --- a/src/game/m_insane.c +++ b/src/game/m_insane.c @@ -576,15 +576,8 @@ void insane_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage } } -/*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND -*/ -void SP_misc_insane(edict_t *self) +static void insane_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_fist = gi.soundindex("insane/insane11.wav"); sound_shake = gi.soundindex("insane/insane5.wav"); sound_moan = gi.soundindex("insane/insane7.wav"); @@ -596,6 +589,18 @@ void SP_misc_insane(edict_t *self) sound_scream[5] = gi.soundindex("insane/insane8.wav"); sound_scream[6] = gi.soundindex("insane/insane9.wav"); sound_scream[7] = gi.soundindex("insane/insane10.wav"); +} + +/*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND +*/ +void SP_misc_insane(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(insane_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_medic.c b/src/game/m_medic.c index a79456f87..7bfc713bf 100644 --- a/src/game/m_medic.c +++ b/src/game/m_medic.c @@ -668,15 +668,8 @@ bool medic_checkattack(edict_t *self) return M_CheckAttack(self); } -/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_medic(edict_t *self) +static void medic_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_idle1 = gi.soundindex("medic/idle.wav"); sound_pain1 = gi.soundindex("medic/medpain1.wav"); sound_pain2 = gi.soundindex("medic/medpain2.wav"); @@ -687,6 +680,18 @@ void SP_monster_medic(edict_t *self) sound_hook_hit = gi.soundindex("medic/medatck3.wav"); sound_hook_heal = gi.soundindex("medic/medatck4.wav"); sound_hook_retract = gi.soundindex("medic/medatck5.wav"); +} + +/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_medic(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(medic_precache); gi.soundindex("medic/medatck1.wav"); diff --git a/src/game/m_move.c b/src/game/m_move.c index 2ee04150e..c46d77b64 100644 --- a/src/game/m_move.c +++ b/src/game/m_move.c @@ -30,8 +30,6 @@ is not a staircase. ============= */ -int c_yes, c_no; - bool M_CheckBottom(edict_t *ent) { vec3_t mins, maxs, start, stop; @@ -54,11 +52,9 @@ bool M_CheckBottom(edict_t *ent) goto realcheck; } - c_yes++; return true; // we got out easy realcheck: - c_no++; // // check it for real... // @@ -88,7 +84,6 @@ bool M_CheckBottom(edict_t *ent) return false; } - c_yes++; return true; } @@ -365,7 +360,7 @@ SV_NewChaseDir void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) { float deltax, deltay; - float d[3]; + float d1, d2; float tdir, olddir, turnaround; //FIXME: how did we get here with no enemy @@ -378,42 +373,37 @@ void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) deltax = enemy->s.origin[0] - actor->s.origin[0]; deltay = enemy->s.origin[1] - actor->s.origin[1]; if (deltax > 10) - d[1] = 0; + d1 = 0; else if (deltax < -10) - d[1] = 180; + d1 = 180; else - d[1] = DI_NODIR; + d1 = DI_NODIR; if (deltay < -10) - d[2] = 270; + d2 = 270; else if (deltay > 10) - d[2] = 90; + d2 = 90; else - d[2] = DI_NODIR; + d2 = DI_NODIR; // try direct route - if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - if (d[1] == 0) - tdir = d[2] == 90 ? 45 : 315; + if (d1 != DI_NODIR && d2 != DI_NODIR) { + if (d1 == 0) + tdir = d2 == 90 ? 45 : 315; else - tdir = d[2] == 90 ? 135 : 215; + tdir = d2 == 90 ? 135 : 215; if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } // try other directions - if (((Q_rand() & 3) & 1) || fabsf(deltay) > fabsf(deltax)) { - tdir = d[1]; - d[1] = d[2]; - d[2] = tdir; - } + if ((Q_rand() & 1) || fabsf(deltay) > fabsf(deltax)) + SWAP(float, d1, d2); - if (d[1] != DI_NODIR && d[1] != turnaround - && SV_StepDirection(actor, d[1], dist)) + if (d1 != DI_NODIR && d1 != turnaround && SV_StepDirection(actor, d1, dist)) return; - if (d[2] != DI_NODIR && d[2] != turnaround - && SV_StepDirection(actor, d[2], dist)) + if (d2 != DI_NODIR && d2 != turnaround && SV_StepDirection(actor, d2, dist)) return; /* there is no direct path to the player, so pick another direction */ @@ -477,7 +467,7 @@ void M_MoveToGoal(edict_t *ent, float dist) return; // if the next step hits the enemy, return immediately - if (ent->enemy && SV_CloseEnough(ent, ent->enemy, dist)) + if (ent->enemy && SV_CloseEnough(ent, ent->enemy, dist)) return; // bump around... diff --git a/src/game/m_mutant.c b/src/game/m_mutant.c index 5b94fcaad..d624b62ff 100644 --- a/src/game/m_mutant.c +++ b/src/game/m_mutant.c @@ -241,9 +241,8 @@ void mutant_run(edict_t *self) void mutant_hit_left(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 8); if (fire_hit(self, aim, (10 + (Q_rand() % 5)), 100)) gi.sound(self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0); else @@ -252,9 +251,8 @@ void mutant_hit_left(edict_t *self) void mutant_hit_right(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->maxs[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 8); if (fire_hit(self, aim, (10 + (Q_rand() % 5)), 100)) gi.sound(self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0); else @@ -566,15 +564,8 @@ void mutant_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage // SPAWN // -/*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_mutant(edict_t *self) +static void mutant_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_swing = gi.soundindex("mutant/mutatck1.wav"); sound_hit = gi.soundindex("mutant/mutatck2.wav"); sound_hit2 = gi.soundindex("mutant/mutatck3.wav"); @@ -588,6 +579,18 @@ void SP_monster_mutant(edict_t *self) sound_step2 = gi.soundindex("mutant/step2.wav"); sound_step3 = gi.soundindex("mutant/step3.wav"); sound_thud = gi.soundindex("mutant/thud1.wav"); +} + +/*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_mutant(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(mutant_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_parasite.c b/src/game/m_parasite.c index 45ac48859..570a5704e 100644 --- a/src/game/m_parasite.c +++ b/src/game/m_parasite.c @@ -422,15 +422,8 @@ End Death Stuff === */ -/*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_parasite(edict_t *self) +static void parasite_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("parasite/parpain1.wav"); sound_pain2 = gi.soundindex("parasite/parpain2.wav"); sound_die = gi.soundindex("parasite/pardeth1.wav"); @@ -442,6 +435,18 @@ void SP_monster_parasite(edict_t *self) sound_tap = gi.soundindex("parasite/paridle1.wav"); sound_scratch = gi.soundindex("parasite/paridle2.wav"); sound_search = gi.soundindex("parasite/parsrch1.wav"); +} + +/*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_parasite(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(parasite_precache); self->s.modelindex = gi.modelindex("models/monsters/parasite/tris.md2"); VectorSet(self->mins, -16, -16, -24); diff --git a/src/game/m_soldier.c b/src/game/m_soldier.c index 58f3f0226..033336416 100644 --- a/src/game/m_soldier.c +++ b/src/game/m_soldier.c @@ -1067,9 +1067,16 @@ void soldier_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag // SPAWN // -void SP_monster_soldier_x(edict_t *self) +static void soldier_precache_x(void) { + sound_idle = gi.soundindex("soldier/solidle1.wav"); + sound_sight1 = gi.soundindex("soldier/solsght1.wav"); + sound_sight2 = gi.soundindex("soldier/solsrch1.wav"); + sound_cock = gi.soundindex("infantry/infatck3.wav"); +} +static void SP_monster_soldier_x(edict_t *self) +{ self->s.modelindex = gi.modelindex("models/monsters/soldier/tris.md2"); self->monsterinfo.scale = MODEL_SCALE; VectorSet(self->mins, -16, -16, -24); @@ -1077,10 +1084,7 @@ void SP_monster_soldier_x(edict_t *self) self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; - sound_idle = gi.soundindex("soldier/solidle1.wav"); - sound_sight1 = gi.soundindex("soldier/solsght1.wav"); - sound_sight2 = gi.soundindex("soldier/solsrch1.wav"); - sound_cock = gi.soundindex("infantry/infatck3.wav"); + G_AddPrecache(soldier_precache_x); self->mass = 100; @@ -1102,6 +1106,12 @@ void SP_monster_soldier_x(edict_t *self) walkmonster_start(self); } +static void soldier_precache_light(void) +{ + sound_pain_light = gi.soundindex("soldier/solpain2.wav"); + sound_death_light = gi.soundindex("soldier/soldeth2.wav"); +} + /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_soldier_light(edict_t *self) @@ -1113,8 +1123,8 @@ void SP_monster_soldier_light(edict_t *self) SP_monster_soldier_x(self); - sound_pain_light = gi.soundindex("soldier/solpain2.wav"); - sound_death_light = gi.soundindex("soldier/soldeth2.wav"); + G_AddPrecache(soldier_precache_light); + gi.modelindex("models/objects/laser/tris.md2"); gi.soundindex("misc/lasfly.wav"); gi.soundindex("soldier/solatck2.wav"); @@ -1124,6 +1134,12 @@ void SP_monster_soldier_light(edict_t *self) self->gib_health = -30; } +static void soldier_precache(void) +{ + sound_pain = gi.soundindex("soldier/solpain1.wav"); + sound_death = gi.soundindex("soldier/soldeth1.wav"); +} + /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_soldier(edict_t *self) @@ -1135,8 +1151,8 @@ void SP_monster_soldier(edict_t *self) SP_monster_soldier_x(self); - sound_pain = gi.soundindex("soldier/solpain1.wav"); - sound_death = gi.soundindex("soldier/soldeth1.wav"); + G_AddPrecache(soldier_precache); + gi.soundindex("soldier/solatck1.wav"); self->s.skinnum = 2; @@ -1144,6 +1160,12 @@ void SP_monster_soldier(edict_t *self) self->gib_health = -30; } +static void soldier_precache_ss(void) +{ + sound_pain_ss = gi.soundindex("soldier/solpain3.wav"); + sound_death_ss = gi.soundindex("soldier/soldeth3.wav"); +} + /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_soldier_ss(edict_t *self) @@ -1155,8 +1177,8 @@ void SP_monster_soldier_ss(edict_t *self) SP_monster_soldier_x(self); - sound_pain_ss = gi.soundindex("soldier/solpain3.wav"); - sound_death_ss = gi.soundindex("soldier/soldeth3.wav"); + G_AddPrecache(soldier_precache_ss); + gi.soundindex("soldier/solatck3.wav"); self->s.skinnum = 4; diff --git a/src/game/m_supertank.c b/src/game/m_supertank.c index 7f7077f58..14fa1fcde 100644 --- a/src/game/m_supertank.c +++ b/src/game/m_supertank.c @@ -624,6 +624,17 @@ void supertank_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int dam // monster_supertank // +static void supertank_precache(void) +{ + sound_pain1 = gi.soundindex("bosstank/btkpain1.wav"); + sound_pain2 = gi.soundindex("bosstank/btkpain2.wav"); + sound_pain3 = gi.soundindex("bosstank/btkpain3.wav"); + sound_death = gi.soundindex("bosstank/btkdeth1.wav"); + sound_search1 = gi.soundindex("bosstank/btkunqv1.wav"); + sound_search2 = gi.soundindex("bosstank/btkunqv2.wav"); + tread_sound = gi.soundindex("bosstank/btkengn1.wav"); +} + /*QUAKED monster_supertank (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight */ void SP_monster_supertank(edict_t *self) @@ -633,15 +644,9 @@ void SP_monster_supertank(edict_t *self) return; } - sound_pain1 = gi.soundindex("bosstank/btkpain1.wav"); - sound_pain2 = gi.soundindex("bosstank/btkpain2.wav"); - sound_pain3 = gi.soundindex("bosstank/btkpain3.wav"); - sound_death = gi.soundindex("bosstank/btkdeth1.wav"); - sound_search1 = gi.soundindex("bosstank/btkunqv1.wav"); - sound_search2 = gi.soundindex("bosstank/btkunqv2.wav"); + G_AddPrecache(supertank_precache); // self->s.sound = gi.soundindex ("bosstank/btkengn1.wav"); - tread_sound = gi.soundindex("bosstank/btkengn1.wav"); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_tank.c b/src/game/m_tank.c index 24bdaf47b..e49c90d10 100644 --- a/src/game/m_tank.c +++ b/src/game/m_tank.c @@ -734,6 +734,18 @@ void tank_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, // monster_tank // +static void tank_precache(void) +{ + sound_pain = gi.soundindex("tank/tnkpain2.wav"); + sound_thud = gi.soundindex("tank/tnkdeth2.wav"); + sound_idle = gi.soundindex("tank/tnkidle1.wav"); + sound_die = gi.soundindex("tank/death.wav"); + sound_step = gi.soundindex("tank/step.wav"); + sound_windup = gi.soundindex("tank/tnkatck4.wav"); + sound_strike = gi.soundindex("tank/tnkatck5.wav"); + sound_sight = gi.soundindex("tank/sight1.wav"); +} + /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight */ /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight @@ -751,14 +763,7 @@ void SP_monster_tank(edict_t *self) self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; - sound_pain = gi.soundindex("tank/tnkpain2.wav"); - sound_thud = gi.soundindex("tank/tnkdeth2.wav"); - sound_idle = gi.soundindex("tank/tnkidle1.wav"); - sound_die = gi.soundindex("tank/death.wav"); - sound_step = gi.soundindex("tank/step.wav"); - sound_windup = gi.soundindex("tank/tnkatck4.wav"); - sound_strike = gi.soundindex("tank/tnkatck5.wav"); - sound_sight = gi.soundindex("tank/sight1.wav"); + G_AddPrecache(tank_precache); gi.soundindex("tank/tnkatck1.wav"); gi.soundindex("tank/tnkatk2a.wav"); diff --git a/src/game/p_client.c b/src/game/p_client.c index 88de3994b..2c3163c47 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -656,7 +656,7 @@ float PlayersRangeFromSpot(edict_t *spot) bestplayerdistance = 9999999; - for (n = 1; n <= maxclients->value; n++) { + for (n = 1; n <= game.maxclients; n++) { player = &g_edicts[n]; if (!player->inuse) @@ -974,7 +974,7 @@ void spectator_respawn(edict_t *ent) } // count spectators - for (i = 1, numspec = 0; i <= maxclients->value; i++) + for (i = 1, numspec = 0; i <= game.maxclients; i++) if (g_edicts[i].inuse && g_edicts[i].client->pers.spectator) numspec++; @@ -1130,7 +1130,7 @@ void PutClientInServer(edict_t *ent) if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV)) { client->ps.fov = 90; } else { - client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov")); + client->ps.fov = Q_atoi(Info_ValueForKey(client->pers.userinfo, "fov")); if (client->ps.fov < 1) client->ps.fov = 90; else if (client->ps.fov > 160) @@ -1349,7 +1349,7 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV)) { ent->client->ps.fov = 90; } else { - ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov")); + ent->client->ps.fov = Q_atoi(Info_ValueForKey(userinfo, "fov")); if (ent->client->ps.fov < 1) ent->client->ps.fov = 90; else if (ent->client->ps.fov > 160) @@ -1359,7 +1359,7 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) // handedness s = Info_ValueForKey(userinfo, "hand"); if (strlen(s)) { - ent->client->pers.hand = atoi(s); + ent->client->pers.hand = Q_atoi(s); } // save off the userinfo in case we want to check something later @@ -1402,7 +1402,7 @@ qboolean ClientConnect(edict_t *ent, char *userinfo) } // count spectators - for (i = numspec = 0; i < maxclients->value; i++) + for (i = numspec = 0; i < game.maxclients; i++) if (g_edicts[i + 1].inuse && g_edicts[i + 1].client->pers.spectator) numspec++; @@ -1665,7 +1665,7 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) } // update chase cam if being followed - for (i = 1; i <= maxclients->value; i++) { + for (i = 1; i <= game.maxclients; i++) { other = g_edicts + i; if (other->inuse && other->client->chase_target == ent) UpdateChaseCam(other); diff --git a/src/game/p_hud.c b/src/game/p_hud.c index b9c8c6661..540bffd52 100644 --- a/src/game/p_hud.c +++ b/src/game/p_hud.c @@ -87,7 +87,7 @@ void BeginIntermission(edict_t *targ) game.autosaved = false; // respawn any dead clients - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; @@ -100,7 +100,7 @@ void BeginIntermission(edict_t *targ) if (strchr(level.changemap, '*')) { if (coop->value) { - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; @@ -144,7 +144,7 @@ void BeginIntermission(edict_t *targ) } // move all clients to the intermission point - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; @@ -508,7 +508,7 @@ void G_CheckChaseStats(edict_t *ent) int i; gclient_t *cl; - for (i = 1; i <= maxclients->value; i++) { + for (i = 1; i <= game.maxclients; i++) { cl = g_edicts[i].client; if (!g_edicts[i].inuse || cl->chase_target != ent) continue; diff --git a/src/game/p_view.c b/src/game/p_view.c index c11b0974c..123a72660 100644 --- a/src/game/p_view.c +++ b/src/game/p_view.c @@ -138,10 +138,7 @@ void P_DamageFeedback(edict_t *player) if (client->damage_alpha < 0) client->damage_alpha = 0; client->damage_alpha += count * 0.01f; - if (client->damage_alpha < 0.2f) - client->damage_alpha = 0.2f; - if (client->damage_alpha > 0.6f) - client->damage_alpha = 0.6f; // don't go too saturated + client->damage_alpha = Q_clipf(client->damage_alpha, 0.2f, 0.6f); // don't go too saturated // the color of the blend will vary based on how much was absorbed // by different armors @@ -149,9 +146,9 @@ void P_DamageFeedback(edict_t *player) if (client->damage_parmor) VectorMA(v, (float)client->damage_parmor / realcount, power_color, v); if (client->damage_armor) - VectorMA(v, (float)client->damage_armor / realcount, acolor, v); + VectorMA(v, (float)client->damage_armor / realcount, acolor, v); if (client->damage_blood) - VectorMA(v, (float)client->damage_blood / realcount, bcolor, v); + VectorMA(v, (float)client->damage_blood / realcount, bcolor, v); VectorCopy(v, client->damage_blend); // @@ -300,11 +297,9 @@ void SV_CalcViewOffset(edict_t *ent) // absolutely bound offsets // so the view can never be outside the player box - clamp(v[0], -14, 14); - clamp(v[1], -14, 14); - clamp(v[2], -22, 30); - - VectorCopy(v, ent->client->ps.viewoffset); + ent->client->ps.viewoffset[0] = Q_clipf(v[0], -14, 14); + ent->client->ps.viewoffset[1] = Q_clipf(v[1], -14, 14); + ent->client->ps.viewoffset[2] = Q_clipf(v[2], -22, 30); } /* @@ -334,7 +329,7 @@ void SV_CalcGunOffset(edict_t *ent) delta -= 360; if (delta < -180) delta += 360; - clamp(delta, -45, 45); + delta = Q_clipf(delta, -45, 45); if (i == YAW) ent->client->ps.gunangles[ROLL] += 0.1f * delta; ent->client->ps.gunangles[i] += 0.2f * delta; @@ -750,7 +745,7 @@ void G_SetClientSound(edict_t *ent) weap = ""; if (ent->waterlevel && (ent->watertype & (CONTENTS_LAVA | CONTENTS_SLIME))) - ent->s.sound = snd_fry; + ent->s.sound = gi.soundindex("player/fry.wav"); else if (strcmp(weap, "weapon_railgun") == 0) ent->s.sound = gi.soundindex("weapons/rg_hum.wav"); else if (strcmp(weap, "weapon_bfg") == 0) diff --git a/src/game/p_weapon.c b/src/game/p_weapon.c index d11286181..23410bf65 100644 --- a/src/game/p_weapon.c +++ b/src/game/p_weapon.c @@ -1234,7 +1234,7 @@ void weapon_bfg_fire(edict_t *ent) ent->client->ps.gunframe++; - PlayerNoise(ent, start, PNOISE_WEAPON); + PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON); return; } diff --git a/src/refresh/draw.c b/src/refresh/draw.c index 461431ca8..f14150880 100644 --- a/src/refresh/draw.c +++ b/src/refresh/draw.c @@ -338,7 +338,7 @@ void Draw_Stats(void) int x = 10, y = 10; R_SetScale(1.0f / get_auto_scale()); - R_DrawFill8(8, 8, 24*8, 20*10+2, 4); + R_DrawFill8(8, 8, 25*8, 21*10+2, 4); Draw_Stringf(x, y, "Nodes visible : %i", c.nodesVisible); y += 10; Draw_Stringf(x, y, "Nodes culled : %i", c.nodesCulled); y += 10; @@ -352,6 +352,7 @@ void Draw_Stats(void) Draw_Stringf(x, y, "Tris drawn : %i", c.trisDrawn); y += 10; Draw_Stringf(x, y, "Tex switches : %i", c.texSwitches); y += 10; Draw_Stringf(x, y, "Tex uploads : %i", c.texUploads); y += 10; + Draw_Stringf(x, y, "LM texels : %i", c.lightTexels); y += 10; Draw_Stringf(x, y, "Batches drawn : %i", c.batchesDrawn); y += 10; Draw_Stringf(x, y, "Faces / batch : %.1f", c.batchesDrawn ? (float)c.facesDrawn / c.batchesDrawn : 0.0f); y += 10; Draw_Stringf(x, y, "Tris / batch : %.1f", c.batchesDrawn ? (float)c.facesTris / c.batchesDrawn : 0.0f); y += 10; @@ -366,13 +367,24 @@ void Draw_Stats(void) void Draw_Lightmaps(void) { - int i, x, y; + int block = lm.block_size; + int rows = 0, cols = 0; + + while (block) { + rows = max(r_config.height / block, 1); + cols = max(lm.nummaps / rows, 1); + if (cols * block <= r_config.width) + break; + block >>= 1; + } - for (i = 0; i < lm.nummaps; i++) { - x = i & 1; - y = i >> 1; - _GL_StretchPic(256 * x, 256 * y, 256, 256, - 0, 0, 1, 1, U32_WHITE, lm.texnums[i], 0); + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int k = j * cols + i; + if (k < lm.nummaps) + _GL_StretchPic(block * i, block * j, block, block, + 0, 0, 1, 1, U32_WHITE, lm.texnums[k], 0); + } } } diff --git a/src/refresh/gl.h b/src/refresh/gl.h index b0bf00375..dd5c91e6d 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -178,6 +178,7 @@ typedef struct { int facesTris; int texSwitches; int texUploads; + int lightTexels; int trisDrawn; int batchesDrawn; int nodesCulled; @@ -222,7 +223,6 @@ extern cvar_t *gl_nobind; extern cvar_t *gl_test; #endif extern cvar_t *gl_cull_nodes; -extern cvar_t *gl_hash_faces; extern cvar_t *gl_clear; extern cvar_t *gl_novis; extern cvar_t *gl_lockpvs; @@ -321,18 +321,12 @@ typedef struct { /* Vertex */ typedef struct { - vec2_t st; vec3_t normal; uint32_t start; /* start weight */ uint32_t count; /* weight count */ } md5_vertex_t; -/* Triangle */ -typedef struct { - int index[3]; -} md5_triangle_t; - /* Weight */ typedef struct { int joint; @@ -348,6 +342,7 @@ typedef struct { int num_weights; md5_vertex_t *vertices; + maliastc_t *tcoords; QGL_INDEX_TYPE *indices; md5_weight_t *weights; } md5_mesh_t; @@ -414,23 +409,30 @@ qhandle_t R_RegisterModel(const char *name); &glr.fd.lightstyles[gl_static.lightstylemap[(i)]] #define LM_MAX_LIGHTMAPS 32 -#define LM_BLOCK_WIDTH 512 -#define LM_BLOCK_HEIGHT 512 +#define LM_BLOCK_WIDTH (1 << 10) + +typedef struct lightmap_s { + int mins[2]; + int maxs[2]; + byte *buffer; +} lightmap_t; typedef struct { - int inuse[LM_BLOCK_WIDTH]; - byte buffer[LM_BLOCK_WIDTH * LM_BLOCK_HEIGHT * 4]; bool dirty; - int comp; + int comp, block_size, block_shift; float add, modulate, scale; - int nummaps; + int nummaps, maxmaps; + int inuse[LM_BLOCK_WIDTH]; GLuint texnums[LM_MAX_LIGHTMAPS]; + lightmap_t lightmaps[LM_MAX_LIGHTMAPS]; + byte buffer[0x4000000]; } lightmap_builder_t; extern lightmap_builder_t lm; void GL_AdjustColor(vec3_t color); void GL_PushLights(mface_t *surf); +void GL_UploadLightmaps(void); void GL_RebuildLighting(void); void GL_FreeWorld(void); @@ -587,7 +589,7 @@ void GL_ForceTexture(GLuint tmu, GLuint texnum); void GL_BindTexture(GLuint tmu, GLuint texnum); void GL_CommonStateBits(GLbitfield bits); void GL_ScrollSpeed(vec2_t scroll, GLbitfield bits); -void GL_DrawOutlines(GLsizei count, QGL_INDEX_TYPE *indices); +void GL_DrawOutlines(GLsizei count, const QGL_INDEX_TYPE *indices); void GL_Ortho(GLfloat xmin, GLfloat xmax, GLfloat ymin, GLfloat ymax, GLfloat znear, GLfloat zfar); void GL_Frustum(GLfloat fov_x, GLfloat fov_y, GLfloat reflect_x); void GL_Setup2D(void); @@ -671,7 +673,6 @@ void GL_DrawBeams(void); void GL_BindArrays(void); void GL_Flush3D(void); -void GL_DrawFace(mface_t *surf); void GL_AddAlphaFace(mface_t *face, entity_t *ent); void GL_AddSolidFace(mface_t *face); diff --git a/src/refresh/images.c b/src/refresh/images.c index 342072613..29b8d41df 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -659,7 +659,8 @@ static int my_jpeg_start_decompress(j_decompress_ptr cinfo, byte *rawdata, size_ return Q_ERR_INVALID_FORMAT; } - if (cinfo->output_width > MAX_TEXTURE_SIZE || cinfo->output_height > MAX_TEXTURE_SIZE) { + if (cinfo->output_width < 1 || cinfo->output_width > MAX_TEXTURE_SIZE || + cinfo->output_height < 1 || cinfo->output_height > MAX_TEXTURE_SIZE) { Com_SetLastError("invalid image dimensions"); return Q_ERR_INVALID_FORMAT; } @@ -737,7 +738,7 @@ static int my_jpeg_compress(j_compress_ptr cinfo, JSAMPARRAY row_pointers, scree cinfo->in_color_space = s->bpp == 4 ? JCS_EXT_RGBA : JCS_RGB; jpeg_set_defaults(cinfo); - jpeg_set_quality(cinfo, clamp(s->param, 0, 100), TRUE); + jpeg_set_quality(cinfo, Q_clip(s->param, 0, 100), TRUE); jpeg_start_compress(cinfo, TRUE); jpeg_write_scanlines(cinfo, row_pointers, s->height); @@ -845,7 +846,7 @@ static int my_png_read_header(png_structp png_ptr, png_infop info_ptr, return Q_ERR_FAILURE; } - if (w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) { + if (w < 1 || h < 1 || w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) { Com_SetLastError("invalid image dimensions"); return Q_ERR_INVALID_FORMAT; } @@ -919,7 +920,7 @@ IMG_LOAD(PNG) if (rawlen < 8) return Q_ERR_FILE_TOO_SMALL; - if (!png_check_sig(rawdata, 8)) + if (png_sig_cmp(rawdata, 0, 8)) return Q_ERR_UNKNOWN_FORMAT; my_err.filename = image->name; @@ -976,7 +977,7 @@ static int my_png_write_image(png_structp png_ptr, png_infop info_ptr, png_init_io(png_ptr, s->fp); png_set_IHDR(png_ptr, info_ptr, s->width, s->height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - png_set_compression_level(png_ptr, clamp(s->param, 0, 9)); + png_set_compression_level(png_ptr, Q_clip(s->param, 0, 9)); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, s->bpp == 4 ? PNG_TRANSFORM_STRIP_FILLER_AFTER : 0, NULL); return 0; @@ -1283,7 +1284,7 @@ static void IMG_ScreenShotJPG_f(void) } if (Cmd_Argc() > 2) { - quality = atoi(Cmd_Argv(2)); + quality = Q_atoi(Cmd_Argv(2)); } else { quality = r_screenshot_quality->integer; } @@ -1304,7 +1305,7 @@ static void IMG_ScreenShotPNG_f(void) } if (Cmd_Argc() > 2) { - compression = atoi(Cmd_Argv(2)); + compression = Q_atoi(Cmd_Argv(2)); } else { compression = r_screenshot_compression->integer; } @@ -1414,6 +1415,7 @@ static void IMG_List_f(void) "\nFlags legend:\n" "T: transparent\n" "S: scrap\n" + "G: glowmap\n" "*: permanent\n" ); return; @@ -1441,7 +1443,7 @@ static void IMG_List_f(void) Com_Printf("%c%c%c%c %4i %4i %s: %s\n", types[image->type > IT_MAX ? IT_MAX : image->type], (image->flags & IF_TRANSPARENT) ? 'T' : ' ', - (image->flags & IF_SCRAP) ? 'S' : ' ', + (image->flags & IF_SCRAP) ? 'S' : image->glow_texnum ? 'G' : ' ', (image->flags & IF_PERMANENT) ? '*' : ' ', image->upload_width, image->upload_height, @@ -1663,7 +1665,9 @@ static void print_error(const char *name, imageflags_t flags, int err) msg = Com_GetLastError(); break; case Q_ERR(ENOENT): - if (flags & IF_PERMANENT) { + if (flags == -1) { + return; + } else if (flags & IF_PERMANENT) { // ugly hack for console code if (strcmp(name, "pics/conchars.pcx")) level = PRINT_WARNING; @@ -1754,7 +1758,7 @@ static void check_for_glow_map(image_t *image) ret = load_image_data(&temporary, IM_PCX, false, &glow_pic); if (ret < 0) { - print_error(temporary.name, 0, ret); + print_error(temporary.name, -1, ret); return; } diff --git a/src/refresh/main.c b/src/refresh/main.c index 6cb87207c..c13561f80 100644 --- a/src/refresh/main.c +++ b/src/refresh/main.c @@ -76,7 +76,6 @@ cvar_t *gl_cull_nodes; cvar_t *gl_cull_models; cvar_t *gl_clear; cvar_t *gl_finish; -cvar_t *gl_hash_faces; cvar_t *gl_novis; cvar_t *gl_lockpvs; cvar_t *gl_lightmap; @@ -434,8 +433,7 @@ static void GL_OccludeFlares(void) GL_StateBits(GLS_DEPTHMASK_FALSE); GL_ArrayBits(GLA_VERTEX); qglColorMask(0, 0, 0, 0); - GL_ActiveTexture(0); - qglDisable(GL_TEXTURE_2D); + GL_BindTexture(0, TEXNUM_WHITE); GL_VertexPointer(3, 0, &points[0][0]); for (i = 0, e = glr.fd.entities; i < glr.fd.num_entities; i++, e++) { @@ -462,7 +460,6 @@ static void GL_OccludeFlares(void) q->pending = true; } - qglEnable(GL_TEXTURE_2D); qglColorMask(1, 1, 1, 1); } @@ -938,7 +935,6 @@ static void GL_Register(void) #endif gl_cull_nodes = Cvar_Get("gl_cull_nodes", "1", 0); gl_cull_models = Cvar_Get("gl_cull_models", "1", 0); - gl_hash_faces = Cvar_Get("gl_hash_faces", "1", 0); gl_clear = Cvar_Get("gl_clear", "0", 0); gl_finish = Cvar_Get("gl_finish", "0", 0); gl_novis = Cvar_Get("gl_novis", "0", 0); diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index 384e03ccb..43c3eddc3 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -18,8 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gl.h" -typedef void (*tessfunc_t)(const maliasmesh_t *); - static int oldframenum; static int newframenum; static float frontlerp; @@ -29,7 +27,6 @@ static vec3_t oldscale; static vec3_t newscale; static vec3_t translate; static vec_t shellscale; -static tessfunc_t tessfunc; static vec4_t color; static vec3_t shadedir; @@ -389,9 +386,9 @@ static void setup_color(void) } } - for (i = 0; i < 3; i++) { - clamp(color[i], 0, 1); - } + color[0] = Q_clipf(color[0], 0, 1); + color[1] = Q_clipf(color[1], 0, 1); + color[2] = Q_clipf(color[2], 0, 1); } if (flags & RF_TRANSLUCENT) { @@ -419,7 +416,7 @@ static void setup_celshading(void) celscale = 1.0f - Distance(origin, glr.fd.vieworg) / 700.0f; } -static void draw_celshading(QGL_INDEX_TYPE *indices, int num_indices) +static void draw_celshading(const QGL_INDEX_TYPE *indices, int num_indices) { if (celscale < 0.01f || celscale > 1) return; @@ -492,7 +489,7 @@ static void setup_shadow(void) GL_MultMatrix(shadowmatrix, tmp, matrix); } -static void draw_shadow(QGL_INDEX_TYPE *indices, int num_indices) +static void draw_shadow(const QGL_INDEX_TYPE *indices, int num_indices) { if (shadowmatrix[15] < 0.5f) return; @@ -553,22 +550,32 @@ static image_t *skin_for_mesh(image_t **skins, int num_skins) return skins[ent->skinnum]; } -static void draw_alias_mesh(const maliasmesh_t *mesh) +static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, + const maliastc_t *tcoords, int num_verts, + image_t **skins, int num_skins) { glStateBits_t state = GLS_INTENSITY_ENABLE; - image_t *skin = skin_for_mesh(mesh->skins, mesh->numskins); + image_t *skin = skin_for_mesh(skins, num_skins); // fall back to entity matrix GL_LoadMatrix(glr.entmatrix); + // avoid drawing hidden faces for transparent gun + if ((glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_FULLBRIGHT)) == (RF_TRANSLUCENT | RF_WEAPONMODEL)) { + GL_StateBits(GLS_DEFAULT); + GL_ArrayBits(GLA_VERTEX); + GL_BindTexture(0, TEXNUM_WHITE); + GL_VertexPointer(3, dotshading ? VERTEX_SIZE : 4, tess.vertices); + qglColorMask(0, 0, 0, 0); + qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); + qglColorMask(1, 1, 1, 1); + } + if (dotshading) state |= GLS_SHADE_SMOOTH; if (glr.ent->flags & RF_TRANSLUCENT) - state |= GLS_BLEND_BLEND; - - if ((glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL)) == RF_TRANSLUCENT) - state |= GLS_DEPTHMASK_FALSE; + state |= GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE; if (skin->glow_texnum) state |= GLS_GLOWMAP_ENABLE; @@ -580,9 +587,6 @@ static void draw_alias_mesh(const maliasmesh_t *mesh) if (skin->glow_texnum) GL_BindTexture(2, skin->glow_texnum); - (*tessfunc)(mesh); - c.trisDrawn += mesh->numtris; - if (dotshading) { GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); GL_VertexPointer(3, VERTEX_SIZE, tess.vertices); @@ -593,21 +597,21 @@ static void draw_alias_mesh(const maliasmesh_t *mesh) GL_Color(color[0], color[1], color[2], color[3]); } - GL_TexCoordPointer(2, 0, (GLfloat *)mesh->tcoords); + GL_TexCoordPointer(2, 0, tcoords->st); - GL_LockArrays(mesh->numverts); + GL_LockArrays(num_verts); - qglDrawElements(GL_TRIANGLES, mesh->numindices, QGL_INDEX_ENUM, - mesh->indices); + qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); + c.trisDrawn += num_indices / 3; - draw_celshading(mesh->indices, mesh->numindices); + draw_celshading(indices, num_indices); - if (gl_showtris->integer) { - GL_DrawOutlines(mesh->numindices, mesh->indices); + if (gl_showtris->integer & BIT(1)) { + GL_DrawOutlines(num_indices, indices); } // FIXME: unlock arrays before changing matrix? - draw_shadow(mesh->indices, mesh->numindices); + draw_shadow(indices, num_indices); GL_UnlockArrays(); } @@ -699,31 +703,6 @@ static void lerp_alias_skeleton(const md5_model_t *model) static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, const md5_joint_t *skel) { - glStateBits_t state = GLS_INTENSITY_ENABLE; - image_t *skin = skin_for_mesh(model->skins, model->num_skins); - - // fall back to entity matrix - GL_LoadMatrix(glr.entmatrix); - - if (dotshading) - state |= GLS_SHADE_SMOOTH; - - if (glr.ent->flags & RF_TRANSLUCENT) - state |= GLS_BLEND_BLEND; - - if ((glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL)) == RF_TRANSLUCENT) - state |= GLS_DEPTHMASK_FALSE; - - if (skin->glow_texnum) - state |= GLS_GLOWMAP_ENABLE; - - GL_StateBits(state); - - GL_BindTexture(0, skin->texnum); - - if (skin->glow_texnum) - GL_BindTexture(2, skin->glow_texnum); - if (glr.ent->flags & RF_SHELL_MASK) tess_shell_skel(mesh, skel); else if (dotshading) @@ -731,34 +710,9 @@ static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, else tess_plain_skel(mesh, skel); - c.trisDrawn += mesh->num_indices / 3; - - if (dotshading) { - GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); - GL_VertexPointer(3, VERTEX_SIZE, tess.vertices); - GL_ColorFloatPointer(4, VERTEX_SIZE, tess.vertices + 4); - } else { - GL_ArrayBits(GLA_VERTEX | GLA_TC); - GL_VertexPointer(3, 4, tess.vertices); - GL_Color(color[0], color[1], color[2], color[3]); - } - - GL_TexCoordPointer(2, sizeof(mesh->vertices[0]) / sizeof(float), mesh->vertices->st); - - GL_LockArrays(mesh->num_verts); - - qglDrawElements(GL_TRIANGLES, mesh->num_indices, QGL_INDEX_ENUM, mesh->indices); - - draw_celshading(mesh->indices, mesh->num_indices); - - if (gl_showtris->integer) { - GL_DrawOutlines(mesh->num_indices, mesh->indices); - } - - // FIXME: unlock arrays before changing matrix? - draw_shadow(mesh->indices, mesh->num_indices); - - GL_UnlockArrays(); + draw_alias_mesh(mesh->indices, mesh->num_indices, + mesh->tcoords, mesh->num_verts, + model->skins, model->num_skins); } static void draw_alias_skeleton(const md5_model_t *model) @@ -812,6 +766,7 @@ void GL_DrawAliasModel(const model_t *model) { const entity_t *ent = glr.ent; glCullResult_t cull; + void (*tessfunc)(const maliasmesh_t *); int i; newframenum = ent->frame; @@ -877,8 +832,13 @@ void GL_DrawAliasModel(const model_t *model) draw_alias_skeleton(model->skeleton); else #endif - for (i = 0; i < model->nummeshes; i++) - draw_alias_mesh(&model->meshes[i]); + for (i = 0; i < model->nummeshes; i++) { + const maliasmesh_t *mesh = &model->meshes[i]; + (*tessfunc)(mesh); + draw_alias_mesh(mesh->indices, mesh->numindices, + mesh->tcoords, mesh->numverts, + mesh->skins, mesh->numskins); + } if (ent->flags & RF_DEPTHHACK) GL_DepthRange(0, 1); diff --git a/src/refresh/models.c b/src/refresh/models.c index 7d8d2ba03..4e0421832 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -89,11 +89,15 @@ static void MOD_List_f(void) continue; } size_t model_size = model->hunk.mapped; + int flag = ' '; #if USE_MD5 - model_size += model->skeleton_hunk.mapped; + if (model->skeleton) { + model_size += model->skeleton_hunk.mapped; + flag = '*'; + } #endif - Com_Printf("%c %8zu : %s\n", types[model->type], - model_size, model->name); + Com_Printf("%c%c %8zu : %s\n", types[model->type], + flag, model_size, model->name); bytes += model_size; count++; } @@ -233,10 +237,10 @@ static const char *MOD_ValidateMD2(const dmd2header_t *header, size_t length) ENSURE(header->framesize >= sizeof(dmd2frame_t) + (header->num_xyz - 1) * sizeof(dmd2trivertx_t), "too small frame size"); ENSURE(header->framesize <= MD2_MAX_FRAMESIZE, "too big frame size"); - ENSURE(header->ofs_tris + (uint64_t)header->num_tris * sizeof(dmd2triangle_t) <= length, "bad tris offset"); - ENSURE(header->ofs_st + (uint64_t)header->num_st * sizeof(dmd2stvert_t) <= length, "bad st offset"); - ENSURE(header->ofs_frames + (uint64_t)header->num_frames * header->framesize <= length, "bad frames offset"); - ENSURE(header->ofs_skins + (uint64_t)MD2_MAX_SKINNAME * header->num_skins <= length, "bad skins offset"); + ENSURE((uint64_t)header->ofs_tris + header->num_tris * sizeof(dmd2triangle_t) <= length, "bad tris offset"); + ENSURE((uint64_t)header->ofs_st + header->num_st * sizeof(dmd2stvert_t) <= length, "bad st offset"); + ENSURE((uint64_t)header->ofs_frames + header->num_frames * header->framesize <= length, "bad frames offset"); + ENSURE((uint64_t)header->ofs_skins + MD2_MAX_SKINNAME * header->num_skins <= length, "bad skins offset"); ENSURE(!(header->ofs_tris % q_alignof(dmd2triangle_t)), "odd tris offset"); ENSURE(!(header->ofs_st % q_alignof(dmd2stvert_t)), "odd st offset"); @@ -487,10 +491,10 @@ static const char *MOD_ValidateMD3Mesh(const model_t *model, const dmd3mesh_t *h ENSURE(header->num_tris <= TESS_MAX_INDICES / 3, "too many tris"); ENSURE(header->num_skins <= MD3_MAX_SKINS, "too many skins"); - ENSURE(header->ofs_skins + (uint64_t)header->num_skins * sizeof(dmd3skin_t) <= length, "bad skins offset"); - ENSURE(header->ofs_verts + (uint64_t)header->num_verts * model->numframes * sizeof(dmd3vertex_t) <= length, "bad verts offset"); - ENSURE(header->ofs_tcs + (uint64_t)header->num_verts * sizeof(dmd3coord_t) <= length, "bad tcs offset"); - ENSURE(header->ofs_indexes + (uint64_t)header->num_tris * 3 * sizeof(uint32_t) <= length, "bad indexes offset"); + ENSURE((uint64_t)header->ofs_skins + header->num_skins * sizeof(dmd3skin_t) <= length, "bad skins offset"); + ENSURE((uint64_t)header->ofs_verts + header->num_verts * model->numframes * sizeof(dmd3vertex_t) <= length, "bad verts offset"); + ENSURE((uint64_t)header->ofs_tcs + header->num_verts * sizeof(dmd3coord_t) <= length, "bad tcs offset"); + ENSURE((uint64_t)header->ofs_indexes + header->num_tris * 3 * sizeof(uint32_t) <= length, "bad indexes offset"); ENSURE(!(header->ofs_skins % q_alignof(dmd3skin_t)), "odd skins offset"); ENSURE(!(header->ofs_verts % q_alignof(dmd3vertex_t)), "odd verts offset"); @@ -609,7 +613,7 @@ static const char *MOD_ValidateMD3(const dmd3header_t *header, size_t length) { ENSURE(header->num_frames >= 1, "too few frames"); ENSURE(header->num_frames <= MD3_MAX_FRAMES, "too many frames"); - ENSURE(header->ofs_frames + (uint64_t)header->num_frames * sizeof(dmd3frame_t) <= length, "bad frames offset"); + ENSURE((uint64_t)header->ofs_frames + header->num_frames * sizeof(dmd3frame_t) <= length, "bad frames offset"); ENSURE(!(header->ofs_frames % q_alignof(dmd3frame_t)), "odd frames offset"); ENSURE(header->num_meshes >= 1, "too few meshes"); ENSURE(header->num_meshes <= MD3_MAX_MESHES, "too many meshes"); @@ -931,6 +935,7 @@ static bool MOD_LoadMD5Mesh(model_t *model, const char *path) MD5_UINT(&num_verts); MD5_ENSURE(num_verts <= TESS_MAX_VERTICES, "too many verts"); OOM_CHECK(mesh->vertices = MD5_Malloc(num_verts * sizeof(mesh->vertices[0]))); + OOM_CHECK(mesh->tcoords = MD5_Malloc(num_verts * sizeof(mesh->tcoords[0]))); mesh->num_verts = num_verts; for (j = 0; j < num_verts; j++) { @@ -940,13 +945,13 @@ static bool MOD_LoadMD5Mesh(model_t *model, const char *path) MD5_UINT(&vert_index); MD5_ENSURE(vert_index < num_verts, "bad vert index"); - md5_vertex_t *vert = &mesh->vertices[vert_index]; - + maliastc_t *tc = &mesh->tcoords[vert_index]; MD5_EXPECT("("); - MD5_FLOAT(&vert->st[0]); - MD5_FLOAT(&vert->st[1]); + MD5_FLOAT(&tc->st[0]); + MD5_FLOAT(&tc->st[1]); MD5_EXPECT(")"); + md5_vertex_t *vert = &mesh->vertices[vert_index]; MD5_UINT(&vert->start); MD5_UINT(&vert->count); } @@ -1317,8 +1322,12 @@ static void MOD_LoadMD5(model_t *model) // build md5 path if (Q_strlcat(skin_path, "md5/", sizeof(skin_path)) < sizeof(skin_path) && - Q_strlcat(skin_path, skin_name, sizeof(skin_path)) < sizeof(skin_path)) + Q_strlcat(skin_path, skin_name, sizeof(skin_path)) < sizeof(skin_path)) { model->skeleton->skins[i] = IMG_Find(skin_path, IT_SKIN, IF_NONE); + } else { + Com_WPrintf("MD5 skin path too long: %s\n", skin_path); + model->skeleton->skins[i] = R_NOTEXTURE; + } } Hunk_End(&model->skeleton_hunk); @@ -1390,7 +1399,7 @@ qhandle_t R_RegisterModel(const char *name) if (*name == '*') { // inline bsp model - index = atoi(name + 1); + index = Q_atoi(name + 1); return ~index; } diff --git a/src/refresh/qgl.c b/src/refresh/qgl.c index 8d85b8c01..008225779 100644 --- a/src/refresh/qgl.c +++ b/src/refresh/qgl.c @@ -65,6 +65,7 @@ static const glsection_t sections[] = { QGL_FN(GetString), QGL_FN(IsEnabled), QGL_FN(LineWidth), + QGL_FN(PixelStorei), QGL_FN(PolygonOffset), QGL_FN(ReadPixels), QGL_FN(Scissor), diff --git a/src/refresh/qgl.h b/src/refresh/qgl.h index 579ad04ab..7671ca4ca 100644 --- a/src/refresh/qgl.h +++ b/src/refresh/qgl.h @@ -62,6 +62,7 @@ QGLAPI void (APIENTRYP qglGetIntegerv)(GLenum pname, GLint *data); QGLAPI const GLubyte *(APIENTRYP qglGetString)(GLenum name); QGLAPI GLboolean (APIENTRYP qglIsEnabled)(GLenum cap); QGLAPI void (APIENTRYP qglLineWidth)(GLfloat width); +QGLAPI void (APIENTRYP qglPixelStorei)(GLenum pname, GLint param); QGLAPI void (APIENTRYP qglPolygonOffset)(GLfloat factor, GLfloat units); QGLAPI void (APIENTRYP qglReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); QGLAPI void (APIENTRYP qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height); diff --git a/src/refresh/sky.c b/src/refresh/sky.c index 670e1c1e8..1e301d8f7 100644 --- a/src/refresh/sky.c +++ b/src/refresh/sky.c @@ -33,7 +33,7 @@ static const vec3_t skyclip[6] = { }; // 1 = s, 2 = t, 3 = 2048 -static const int st_to_vec[6][3] = { +static const int8_t st_to_vec[6][3] = { { 3, -1, 2 }, { -3, 1, 2 }, @@ -45,7 +45,7 @@ static const int st_to_vec[6][3] = { }; // s = [0]/[2], t = [1]/[2] -static const int vec_to_st[6][3] = { +static const int8_t vec_to_st[6][3] = { { -2, 3, 1 }, { 2, 3, -1 }, @@ -239,6 +239,8 @@ void R_AddSkySurface(mface_t *fa) vec3_t temp; msurfedge_t *surfedge; mvertex_t *vert; + medge_t *edge; + bsp_t *bsp = gl_static.world.cache; if (fa->numsurfedges > MAX_CLIP_VERTS) { Com_DPrintf("%s: too many verts\n", __func__); @@ -252,13 +254,15 @@ void R_AddSkySurface(mface_t *fa) SetupRotationMatrix(skymatrix, skyaxis, glr.fd.time * skyrotate); for (i = 0; i < fa->numsurfedges; i++, surfedge++) { - vert = surfedge->edge->v[surfedge->vert]; + edge = bsp->edges + surfedge->edge; + vert = bsp->vertices + edge->v[surfedge->vert]; VectorSubtract(vert->point, glr.fd.vieworg, temp); SkyInverseRotate(verts[i], temp); } } else { for (i = 0; i < fa->numsurfedges; i++, surfedge++) { - vert = surfedge->edge->v[surfedge->vert]; + edge = bsp->edges + surfedge->edge; + vert = bsp->vertices + edge->v[surfedge->vert]; VectorSubtract(vert->point, glr.fd.vieworg, verts[i]); } } @@ -310,17 +314,8 @@ static void MakeSkyVec(float s, float t, int axis, vec_t *out) } // avoid bilerp seam - s = (s + 1) * 0.5f; - t = (t + 1) * 0.5f; - - if (s < sky_min) - s = sky_min; - else if (s > sky_max) - s = sky_max; - if (t < sky_min) - t = sky_min; - else if (t > sky_max) - t = sky_max; + s = Q_clipf((s + 1) * 0.5f, sky_min, sky_max); + t = Q_clipf((t + 1) * 0.5f, sky_min, sky_max); out[3] = s; out[4] = 1.0f - t; @@ -337,7 +332,7 @@ R_DrawSkyBox */ void R_DrawSkyBox(void) { - static const int skytexorder[6] = {0, 2, 1, 3, 4, 5}; + static const uint8_t skytexorder[6] = {0, 2, 1, 3, 4, 5}; vec5_t verts[4]; int i; diff --git a/src/refresh/state.c b/src/refresh/state.c index 420453952..320a2b3fd 100644 --- a/src/refresh/state.c +++ b/src/refresh/state.c @@ -270,7 +270,7 @@ void GL_Setup3D(bool waterwarp) qglClear(GL_DEPTH_BUFFER_BIT | gl_static.stencil_buffer_bit); } -void GL_DrawOutlines(GLsizei count, QGL_INDEX_TYPE *indices) +void GL_DrawOutlines(GLsizei count, const QGL_INDEX_TYPE *indices) { GL_BindTexture(0, TEXNUM_WHITE); GL_StateBits(GLS_DEPTHMASK_FALSE | GLS_TEXTURE_REPLACE); diff --git a/src/refresh/surf.c b/src/refresh/surf.c index f993f10f2..46583e4d9 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -94,16 +94,16 @@ DYNAMIC BLOCKLIGHTS ============================================================================= */ -#define MAX_SURFACE_EXTENTS 2048 -#define MAX_LIGHTMAP_EXTENTS ((MAX_SURFACE_EXTENTS >> 4) + 1) +#define MAX_LIGHTMAP_EXTENTS 513 #define MAX_BLOCKLIGHTS (MAX_LIGHTMAP_EXTENTS * MAX_LIGHTMAP_EXTENTS) static float blocklights[MAX_BLOCKLIGHTS * 3]; -static void put_blocklights(byte *out, int smax, int tmax, int stride) +static void put_blocklights(mface_t *surf) { float *bl, add, modulate, scale = lm.scale; - int i, j; + int i, j, smax, tmax, stride = 1 << lm.block_shift; + byte *out; if (gl_static.use_shaders) { add = 0; @@ -113,6 +113,11 @@ static void put_blocklights(byte *out, int smax, int tmax, int stride) modulate = lm.modulate; } + smax = surf->lm_width; + tmax = surf->lm_height; + + out = surf->light_m->buffer + (surf->light_t << lm.block_shift) + surf->light_s * 4; + for (i = 0, bl = blocklights; i < tmax; i++, out += stride) { byte *dst; for (j = 0, dst = out; j < smax; j++, bl += 3, dst += 4) { @@ -185,12 +190,12 @@ static void add_dynamic_lights(mface_t *surf) } } -static void add_light_styles(mface_t *surf, int size) +static void add_light_styles(mface_t *surf) { lightstyle_t *style; byte *src; float *bl; - int i, j; + int i, j, size = surf->lm_width * surf->lm_height; if (!surf->numstyles) { // should this ever happen? @@ -236,15 +241,10 @@ static void add_light_styles(mface_t *surf, int size) static void update_dynamic_lightmap(mface_t *surf) { - byte temp[MAX_BLOCKLIGHTS * 4]; - int smax, tmax, size; - - smax = surf->lm_width; - tmax = surf->lm_height; - size = smax * tmax; + int s0, t0, s1, t1; // add all the lightmaps - add_light_styles(surf, size); + add_light_styles(surf); // add all the dynamic lights if (surf->dlightframe == glr.dlightframe) { @@ -254,29 +254,31 @@ static void update_dynamic_lightmap(mface_t *surf) } // put into texture format - put_blocklights(temp, smax, tmax, smax * 4); + put_blocklights(surf); + + // add to dirty region + s0 = surf->light_s; + t0 = surf->light_t; + + s1 = s0 + surf->lm_width; + t1 = t0 + surf->lm_height; + + lightmap_t *m = surf->light_m; - // upload lightmap subimage - GL_ForceTexture(1, surf->texnum[1]); - qglTexSubImage2D(GL_TEXTURE_2D, 0, - surf->light_s, surf->light_t, smax, tmax, - GL_RGBA, GL_UNSIGNED_BYTE, temp); + m->mins[0] = min(m->mins[0], s0); + m->mins[1] = min(m->mins[1], t0); - c.texUploads++; + m->maxs[0] = max(m->maxs[0], s1); + m->maxs[1] = max(m->maxs[1], t1); } +// updates lightmaps in RAM void GL_PushLights(mface_t *surf) { lightstyle_t *style; int i; - if (!surf->lightmap) { - return; - } - if (surf->drawflags & gl_static.nolm_mask) { - return; - } - if (!surf->texnum[1]) { + if (!surf->light_m) { return; } @@ -296,6 +298,51 @@ void GL_PushLights(mface_t *surf) } } +static void clear_dirty_region(lightmap_t *m) +{ + m->mins[0] = lm.block_size; + m->mins[1] = lm.block_size; + m->maxs[0] = 0; + m->maxs[1] = 0; +} + +// uploads dirty lightmap regions to GL +void GL_UploadLightmaps(void) +{ + lightmap_t *m; + bool set = false; + int i; + + for (i = 0, m = lm.lightmaps; i < lm.nummaps; i++, m++) { + int x, y, w, h; + + if (m->mins[0] >= m->maxs[0] || m->mins[1] >= m->maxs[1]) + continue; + + x = m->mins[0]; + y = m->mins[1]; + w = m->maxs[0] - x; + h = m->maxs[1] - y; + + if (!set) { + qglPixelStorei(GL_UNPACK_ROW_LENGTH, lm.block_size); + set = true; + } + + // upload lightmap subimage + GL_ForceTexture(1, lm.texnums[i]); + qglTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, + GL_RGBA, GL_UNSIGNED_BYTE, + m->buffer + (y << lm.block_shift) + x * 4); + clear_dirty_region(m); + c.texUploads++; + c.lightTexels += w * h; + } + + if (set) + qglPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +} + /* ============================================================================= @@ -305,17 +352,11 @@ LIGHTMAPS BUILDING */ #define LM_AllocBlock(w, h, s, t) \ - GL_AllocBlock(LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, lm.inuse, w, h, s, t) + GL_AllocBlock(lm.block_size, lm.block_size, lm.inuse, w, h, s, t) static void LM_InitBlock(void) { - int i; - - for (i = 0; i < LM_BLOCK_WIDTH; i++) { - lm.inuse[i] = 0; - } - - lm.dirty = false; + memset(lm.inuse, 0, sizeof(lm.inuse)); } static void LM_UploadBlock(void) @@ -324,21 +365,28 @@ static void LM_UploadBlock(void) return; } - GL_ForceTexture(1, lm.texnums[lm.nummaps++]); - qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); + Q_assert(lm.nummaps < lm.maxmaps); + + lightmap_t *m = &lm.lightmaps[lm.nummaps]; + clear_dirty_region(m); + + GL_ForceTexture(1, lm.texnums[lm.nummaps]); + qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, + lm.block_size, lm.block_size, 0, + GL_RGBA, GL_UNSIGNED_BYTE, m->buffer); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + lm.nummaps++; + lm.dirty = false; } static void build_style_map(int dynamic) { - static const lightstyle_t fake = { 1 }; int i; if (!dynamic) { // make all styles fullbright - glr.fd.lightstyles = (lightstyle_t *)&fake; memset(gl_static.lightstylemap, 0, sizeof(gl_static.lightstylemap)); return; } @@ -355,28 +403,54 @@ static void build_style_map(int dynamic) } } +static bool no_lightmaps(void) +{ + return gl_fullbright->integer || gl_vertexlight->integer; +} + static void LM_BeginBuilding(void) { + bsp_t *bsp = gl_static.world.cache; + int size_shift, bits; + + // start up with fullbright styles + build_style_map(0); + // lightmap textures are not deleted from memory when changing maps, // they are merely reused - lm.nummaps = 0; + lm.nummaps = lm.maxmaps = 0; + lm.dirty = false; - LM_InitBlock(); + if (no_lightmaps()) + return; - // start up with fullbright styles - build_style_map(0); + // use larger lightmaps for DECOUPLED_LM maps + bits = 8 + bsp->lm_decoupled * 2; + + lm.block_size = 1 << bits; + lm.block_shift = bits + 2; + + size_shift = bits * 2 + 2; + lm.maxmaps = min(sizeof(lm.buffer) >> size_shift, LM_MAX_LIGHTMAPS); + + for (int i = 0; i < lm.maxmaps; i++) + lm.lightmaps[i].buffer = lm.buffer + (i << size_shift); + + Com_DDPrintf("%s: %d lightmaps, %d block size\n", __func__, lm.maxmaps, lm.block_size); + + LM_InitBlock(); } static void LM_EndBuilding(void) { + // vertex lighting implies fullbright styles + if (no_lightmaps()) + return; + // upload the last lightmap LM_UploadBlock(); LM_InitBlock(); - // vertex lighting implies fullbright styles - if (gl_fullbright->integer || gl_vertexlight->integer) - return; - // now build the real lightstyle map build_style_map(gl_dynamic->integer); @@ -385,33 +459,29 @@ static void LM_EndBuilding(void) static void build_primary_lightmap(mface_t *surf) { - int smax, tmax, size; - - smax = surf->lm_width; - tmax = surf->lm_height; - size = smax * tmax; - // add all the lightmaps - add_light_styles(surf, size); + add_light_styles(surf); surf->dlightframe = 0; // put into texture format - put_blocklights(lm.buffer + surf->light_t * LM_BLOCK_WIDTH * 4 + surf->light_s * 4, - smax, tmax, LM_BLOCK_WIDTH * 4); + put_blocklights(surf); } static void LM_BuildSurface(mface_t *surf, vec_t *vbo) { int smax, tmax, s, t; + if (lm.nummaps >= lm.maxmaps) + return; // can't have any more + smax = surf->lm_width; tmax = surf->lm_height; if (!LM_AllocBlock(smax, tmax, &s, &t)) { LM_UploadBlock(); - if (lm.nummaps == LM_MAX_LIGHTMAPS) { - Com_EPrintf("%s: LM_MAX_LIGHTMAPS exceeded\n", __func__); + if (lm.nummaps >= lm.maxmaps) { + Com_EPrintf("%s: too many lightmaps\n", __func__); return; } LM_InitBlock(); @@ -427,6 +497,7 @@ static void LM_BuildSurface(mface_t *surf, vec_t *vbo) // store the surface lightmap parameters surf->light_s = s; surf->light_t = t; + surf->light_m = &lm.lightmaps[lm.nummaps]; surf->texnum[1] = lm.texnums[lm.nummaps]; // build the primary lightmap @@ -437,7 +508,8 @@ static void LM_RebuildSurfaces(void) { bsp_t *bsp = gl_static.world.cache; mface_t *surf; - int i, texnum; + lightmap_t *m; + int i; build_style_map(gl_dynamic->integer); @@ -445,40 +517,21 @@ static void LM_RebuildSurfaces(void) return; } - GL_ForceTexture(1, lm.texnums[0]); - texnum = lm.texnums[0]; - for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { - if (!surf->lightmap) { - continue; - } - if (surf->drawflags & gl_static.nolm_mask) { - continue; - } - if (!surf->texnum[1]) { - continue; + if (surf->light_m) { + build_primary_lightmap(surf); } - - if (surf->texnum[1] != texnum) { - // done with previous lightmap - qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, - LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); - GL_ForceTexture(1, surf->texnum[1]); - texnum = surf->texnum[1]; - - c.texUploads++; - } - - build_primary_lightmap(surf); } - // upload the last lightmap - qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, - LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); - - c.texUploads++; + // upload all lightmaps + for (i = 0, m = lm.lightmaps; i < lm.nummaps; i++, m++) { + GL_ForceTexture(1, lm.texnums[i]); + qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, + lm.block_size, lm.block_size, 0, + GL_RGBA, GL_UNSIGNED_BYTE, m->buffer); + clear_dirty_region(m); + c.texUploads++; + } } @@ -584,8 +637,8 @@ static void build_surface_poly(mface_t *surf, vec_t *vbo) src_surfedge = surf->firstsurfedge; for (i = 0; i < surf->numsurfedges; i++) { - src_edge = src_surfedge->edge; - src_vert = src_edge->v[src_surfedge->vert]; + src_edge = bsp->edges + src_surfedge->edge; + src_vert = bsp->vertices + src_edge->v[src_surfedge->vert]; src_surfedge++; // vertex coordinates @@ -654,6 +707,9 @@ static void sample_surface_verts(mface_t *surf, vec_t *vbo) vec3_t color; byte *dst; + if (surf->drawflags & SURF_COLOR_MASK) + return; + glr.lightpoint.surf = surf; for (i = 0; i < surf->numsurfedges; i++) { @@ -696,7 +752,7 @@ static void build_surface_light(mface_t *surf, vec_t *vbo) // validate lightmap extents if (smax < 1 || tmax < 1 || smax > MAX_LIGHTMAP_EXTENTS || tmax > MAX_LIGHTMAP_EXTENTS) { - Com_EPrintf("%s: bad lightmap extents\n", __func__); + Com_WPrintf("Bad lightmap extents: %d x %d\n", smax, tmax); surf->lightmap = NULL; // don't use this lightmap return; } @@ -705,7 +761,7 @@ static void build_surface_light(mface_t *surf, vec_t *vbo) size = smax * tmax; ofs = surf->lightmap - bsp->lightmap; if (surf->numstyles * size * 3 > bsp->numlightmapbytes - ofs) { - Com_EPrintf("%s: bad surface lightmap\n", __func__); + Com_WPrintf("Bad surface lightmap\n"); surf->lightmap = NULL; // don't use this lightmap return; } @@ -728,8 +784,8 @@ static void normalize_surface_lmtc(mface_t *surf, vec_t *vbo) for (i = 0; i < surf->numsurfedges; i++) { vbo[6] += s; vbo[7] += t; - vbo[6] *= 1.0f / LM_BLOCK_WIDTH; - vbo[7] *= 1.0f / LM_BLOCK_HEIGHT; + vbo[6] *= 1.0f / lm.block_size; + vbo[7] *= 1.0f / lm.block_size; vbo += VERTEX_SIZE; } @@ -817,6 +873,9 @@ static void upload_world_surfaces(void) if (!qglActiveTexture || (!qglClientActiveTexture && !gl_static.use_shaders)) Cvar_Set("gl_vertexlight", "1"); + // begin building lightmaps + LM_BeginBuilding(); + if (!gl_static.world.vertices) qglBindBuffer(GL_ARRAY_BUFFER, gl_static.world.bufnum); @@ -841,11 +900,12 @@ static void upload_world_surfaces(void) tess.numverts += surf->numsurfedges; } + surf->light_m = NULL; // start with no lightmap surf->firstvert = currvert; build_surface_poly(surf, vbo); build_surface_light(surf, vbo); - if (surf->texnum[1]) + if (surf->light_m) normalize_surface_lmtc(surf, vbo); else duplicate_surface_lmtc(surf, vbo); @@ -861,6 +921,9 @@ static void upload_world_surfaces(void) qglBindBuffer(GL_ARRAY_BUFFER, 0); } + // end building lightmaps + LM_EndBuilding(); + gl_fullbright->modified = false; gl_vertexlight->modified = false; } @@ -891,17 +954,18 @@ void GL_RebuildLighting(void) if (!gl_static.world.cache) return; - // if doing vertex lighting, rebuild all surfaces - if (gl_fullbright->integer || gl_vertexlight->integer) { + // rebuild all surfaces if toggling lightmaps off/on + if (gl_fullbright->modified || gl_vertexlight->modified) { upload_world_surfaces(); return; } - // if did vertex lighting previously, rebuild all surfaces and lightmaps - if (gl_fullbright->modified || gl_vertexlight->modified) { - LM_BeginBuilding(); + if (gl_fullbright->integer) + return; + + // rebuild all surfaces if doing vertex lighting (and not fullbright) + if (gl_vertexlight->integer) { upload_world_surfaces(); - LM_EndBuilding(); return; } @@ -933,7 +997,7 @@ void GL_LoadWorld(const char *name) bsp_t *bsp; mtexinfo_t *info; mface_t *surf; - int i, ret; + int i, n64surfs, ret; ret = BSP_Load(name, &bsp); if (!bsp) { @@ -975,13 +1039,15 @@ void GL_LoadWorld(const char *name) // calculate vertex buffer size in bytes size = 0; - for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { + for (i = n64surfs = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { // hack surface flags into drawflags for faster access surf->drawflags |= surf->texinfo->c.flags & ~DSURF_PLANEBACK; // don't count sky surfaces if (surf->drawflags & (SURF_SKY | SURF_NODRAW)) continue; + if (surf->drawflags & SURF_N64_UV) + n64surfs++; size += surf->numsurfedges * VERTEX_SIZE * sizeof(vec_t); } @@ -1002,18 +1068,16 @@ void GL_LoadWorld(const char *name) // only supported in DECOUPLED_LM maps because vanilla maps have broken // lightofs for liquids/alphas. legacy renderer doesn't support lightmapped // liquids too. - if (bsp->lm_decoupled && gl_static.use_shaders) { + if ((bsp->lm_decoupled || n64surfs > 100) && gl_static.use_shaders) { gl_static.nolm_mask = SURF_NOLM_MASK_REMASTER; } - // begin building lightmaps - LM_BeginBuilding(); + glr.fd.lightstyles = &(lightstyle_t){ 1 }; // post process all surfaces upload_world_surfaces(); - // end building lightmaps - LM_EndBuilding(); + glr.fd.lightstyles = NULL; GL_ShowErrors(__func__); } diff --git a/src/refresh/tess.c b/src/refresh/tess.c index 2784ecdca..4237c9a2f 100644 --- a/src/refresh/tess.c +++ b/src/refresh/tess.c @@ -57,7 +57,7 @@ void GL_Flush2D(void) qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); - if (gl_showtris->integer > 1) { + if (gl_showtris->integer & BIT(2)) { GL_DrawOutlines(tess.numindices, tess.indices); } @@ -147,7 +147,7 @@ void GL_DrawParticles(void) qglDrawArrays(GL_TRIANGLES, 0, numverts); - if (gl_showtris->integer) { + if (gl_showtris->integer & BIT(2)) { GL_DrawOutlines(numverts, NULL); } } while (total); @@ -374,7 +374,7 @@ void GL_Flush3D(void) qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); - if (gl_showtris->integer) { + if (gl_showtris->integer & BIT(0)) { GL_DrawOutlines(tess.numindices, tess.indices); } @@ -422,7 +422,7 @@ static image_t *GL_TextureAnimation(mtexinfo_t *tex) return tex->image; } -void GL_DrawFace(mface_t *surf) +static void GL_DrawFace(mface_t *surf) { int numtris = surf->numsurfedges - 2; int numindices = numtris * 3; diff --git a/src/refresh/texture.c b/src/refresh/texture.c index fa150b436..716e10dd3 100644 --- a/src/refresh/texture.c +++ b/src/refresh/texture.c @@ -893,7 +893,7 @@ static void GL_InitParticleTexture(void) dst[0] = 255; dst[1] = 255; dst[2] = 255; - dst[3] = 255 * clamp(f, 0, 1 - shape * 0.2f); + dst[3] = 255 * Q_clipf(f, 0, 1 - shape * 0.2f); dst += 4; } } @@ -946,7 +946,7 @@ static void GL_InitBeamTexture(void) dst[0] = 255; dst[1] = 255; dst[2] = 255; - dst[3] = 255 * clamp(f, 0, 1); + dst[3] = 255 * Q_clipf(f, 0, 1); dst += 4; } } diff --git a/src/refresh/world.c b/src/refresh/world.c index 633ac7635..fb7117c2f 100644 --- a/src/refresh/world.c +++ b/src/refresh/world.c @@ -331,13 +331,11 @@ void GL_LightPoint(const vec3_t origin, vec3_t color) void R_LightPoint(const vec3_t origin, vec3_t color) { - int i; - GL_LightPoint(origin, color); - for (i = 0; i < 3; i++) { - clamp(color[i], 0, 1); - } + color[0] = Q_clipf(color[0], 0, 1); + color[1] = Q_clipf(color[1], 0, 1); + color[2] = Q_clipf(color[2], 0, 1); } static void GL_MarkLeaves(void) @@ -481,6 +479,8 @@ void GL_DrawBspModel(mmodel_t *model) GL_BindArrays(); + GL_ClearSolidFaces(); + // draw visible faces last = model->firstface + model->numfaces; for (face = model->firstface; face < last; face++) { @@ -495,19 +495,25 @@ void GL_DrawBspModel(mmodel_t *model) continue; } + if (gl_dynamic->integer) { + GL_PushLights(face); + } + if (face->drawflags & SURF_TRANS_MASK) { if (model->drawframe != glr.drawframe) GL_AddAlphaFace(face, ent); continue; } - if (gl_dynamic->integer) { - GL_PushLights(face); - } + GL_AddSolidFace(face); + } - GL_DrawFace(face); + if (gl_dynamic->integer) { + GL_UploadLightmaps(); } + GL_DrawSolidFaces(); + GL_Flush3D(); // protect against infinite loop if the same inline model @@ -582,20 +588,16 @@ static inline void GL_DrawNode(mnode_t *node) continue; } - if (face->drawflags & SURF_TRANS_MASK) { - GL_AddAlphaFace(face, &gl_world); - continue; - } - if (gl_dynamic->integer) { GL_PushLights(face); } - if (gl_hash_faces->integer) { - GL_AddSolidFace(face); - } else { - GL_DrawFace(face); + if (face->drawflags & SURF_TRANS_MASK) { + GL_AddAlphaFace(face, &gl_world); + continue; } + + GL_AddSolidFace(face); } c.nodesDrawn++; @@ -645,14 +647,16 @@ void GL_DrawWorld(void) GL_BindArrays(); - if (gl_hash_faces->integer) - GL_ClearSolidFaces(); + GL_ClearSolidFaces(); GL_WorldNode_r(gl_static.world.cache->nodes, gl_cull_nodes->integer ? NODE_CLIPPED : NODE_UNCLIPPED); - if (gl_hash_faces->integer) - GL_DrawSolidFaces(); + if (gl_dynamic->integer) { + GL_UploadLightmaps(); + } + + GL_DrawSolidFaces(); GL_Flush3D(); diff --git a/src/server/ac.c b/src/server/ac.c index 02131c794..e55cf6cbe 100644 --- a/src/server/ac.c +++ b/src/server/ac.c @@ -90,7 +90,7 @@ typedef struct { bool ping_pending; unsigned last_ping; netstream_t stream; - size_t msglen; + unsigned msglen; } ac_locals_t; typedef struct { @@ -972,7 +972,7 @@ static bool AC_ParseMessage(void) } if (msg_read.readcount > msg_read.cursize) { - Com_WPrintf("ANTICHEAT: Read %zu bytes past end of message %d\n", + Com_WPrintf("ANTICHEAT: Read %u bytes past end of message %d\n", msg_read.readcount - msg_read.cursize, cmd); } @@ -1576,7 +1576,7 @@ void AC_Info_f(void) filesubstring = Cmd_Argv(2); if (COM_IsUint(substring)) { - clientID = atoi(substring); + clientID = Q_atoi(substring); if (clientID < 0 || clientID >= sv_maxclients->integer) { Com_Printf("Invalid client ID.\n"); return; diff --git a/src/server/commands.c b/src/server/commands.c index 0660e4f6f..011a142ba 100644 --- a/src/server/commands.c +++ b/src/server/commands.c @@ -125,7 +125,7 @@ client_t *SV_GetPlayer(const char *s, bool partial) // numeric values are just slot numbers if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); if (i < 0 || i >= sv_maxclients->integer) { Com_Printf("Bad client slot number: %d\n", i); return NULL; @@ -631,7 +631,7 @@ static void dump_protocols(void) "--- --------------- ----- ----- ------ ---- ----\n"); FOR_EACH_CLIENT(cl) { - Com_Printf("%3i %-15.15s %5d %5d %6zu %s %s\n", + Com_Printf("%3i %-15.15s %5d %5d %6u %s %s\n", cl->number, cl->name, cl->protocol, cl->version, cl->netchan.maxpacketlen, cl->has_zlib ? "yes" : "no ", @@ -773,7 +773,7 @@ void SV_PrintMiscInfo(void) sv_client->version_string ? sv_client->version_string : "-"); Com_Printf("protocol (maj/min) %d/%d\n", sv_client->protocol, sv_client->version); - Com_Printf("maxmsglen %zu\n", sv_client->netchan.maxpacketlen); + Com_Printf("maxmsglen %u\n", sv_client->netchan.maxpacketlen); Com_Printf("zlib support %s\n", sv_client->has_zlib ? "yes" : "no"); Com_Printf("netchan type %s\n", sv_client->netchan.type ? "new" : "old"); Com_Printf("ping %d\n", sv_client->ping); @@ -1046,7 +1046,7 @@ static bool parse_mask(char *s, netadr_t *addr, netadr_t *mask) Com_Printf("Please specify a mask after '/'.\n"); return false; } - bits = atoi(p); + bits = Q_atoi(p); } else { bits = -1; } @@ -1144,7 +1144,7 @@ void SV_DelMatch_f(list_t *list) // numeric values are just slot numbers if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); match = LIST_INDEX(addrmatch_t, i - 1, list, entry); if (match) { goto remove; @@ -1271,7 +1271,7 @@ static void SV_DelStuffCmd(list_t *list, int arg, const char *what) } if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); stuff = LIST_INDEX(stuffcmd_t, i - 1, list, entry); if (!stuff) { Com_Printf("No such %scmd index: %d\n", what, i); @@ -1469,7 +1469,7 @@ static void SV_DelFilterCmd_f(void) } if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); filter = LIST_INDEX(filtercmd_t, i - 1, &sv_filterlist, entry); if (!filter) { Com_Printf("No such filtercmd index: %d\n", i); @@ -1591,7 +1591,7 @@ static void SV_DelCvarBan(list_t *list, const char *what) } if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); ban = LIST_INDEX(cvarban_t, i - 1, list, entry); if (!ban) { Com_Printf("No such %sban index: %d\n", what, i); diff --git a/src/server/entities.c b/src/server/entities.c index a8e4e3271..9cdbbddba 100644 --- a/src/server/entities.c +++ b/src/server/entities.c @@ -62,7 +62,7 @@ static void SV_EmitPacketEntities(client_t *client, } if (newindex >= to->num_entities) { - newnum = 9999; + newnum = MAX_EDICTS; } else { i = (to->first_entity + newindex) % svs.num_entities; newent = &svs.entities[i]; @@ -70,7 +70,7 @@ static void SV_EmitPacketEntities(client_t *client, } if (oldindex >= from_num_entities) { - oldnum = 9999; + oldnum = MAX_EDICTS; } else { i = (from->first_entity + oldindex) % svs.num_entities; oldent = &svs.entities[i]; diff --git a/src/server/init.c b/src/server/init.c index 82596dcdb..29e8777ac 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -40,18 +40,12 @@ void SV_ClientReset(client_t *client) static void set_frame_time(void) { #if USE_FPS - int framediv; - if (g_features->integer & GMF_VARIABLE_FPS) - framediv = sv_fps->integer / BASE_FRAMERATE; + sv.frametime = Com_ComputeFrametime(sv_fps->integer); else - framediv = 1; - - clamp(framediv, 1, MAX_FRAMEDIV); + sv.frametime = Com_ComputeFrametime(BASE_FRAMERATE); - sv.framerate = framediv * BASE_FRAMERATE; - sv.frametime = BASE_FRAMETIME / framediv; - sv.framediv = framediv; + sv.framerate = sv.frametime.div * BASE_FRAMERATE; Cvar_SetInteger(sv_fps, sv.framerate, FROM_CODE); #endif @@ -109,7 +103,7 @@ clients along with it. */ void SV_SpawnServer(const mapcmd_t *cmd) { - int i; + int i, j; client_t *client; SCR_BeginLoadingPlaque(); // for local system @@ -161,10 +155,16 @@ void SV_SpawnServer(const mapcmd_t *cmd) sv.cm = cmd->cm; sprintf(sv.configstrings[svs.csr.mapchecksum], "%d", sv.cm.checksum); + // model indices 0 and 255 are reserved + if (sv.cm.cache->nummodels > svs.csr.max_models - 2) + Com_Error(ERR_DROP, "Too many inline models"); + // set inline model names Q_concat(sv.configstrings[svs.csr.models + 1], MAX_QPATH, "maps/", cmd->server, ".bsp"); - for (i = 1; i < sv.cm.cache->nummodels; i++) { - sprintf(sv.configstrings[svs.csr.models + 1 + i], "*%d", i); + for (i = 1, j = 2; i < sv.cm.cache->nummodels; i++, j++) { + if (j == MODELINDEX_PLAYER) + j++; // skip reserved index + sprintf(sv.configstrings[svs.csr.models + j], "*%d", i); } } else { // no real map @@ -224,31 +224,6 @@ void SV_SpawnServer(const mapcmd_t *cmd) Com_Printf("-------------------------------------\n"); } -static int check_cinematic(const char *expanded) -{ - int ret; - -#if USE_AVCODEC - // open from filesystem only - ret = FS_LoadFileEx(expanded, NULL, FS_TYPE_REAL, TAG_FREE); - - // if .cin doesn't exist, check for .ogv - if (ret == Q_ERR(ENOENT)) { - char tmp[MAX_QPATH]; - COM_StripExtension(tmp, expanded, sizeof(tmp)); - Q_strlcat(tmp, ".ogv", sizeof(tmp)); - ret = FS_LoadFileEx(tmp, NULL, FS_TYPE_REAL, TAG_FREE); - } -#else - ret = FS_LoadFile(expanded, NULL); -#endif - - if (ret == Q_ERR(EFBIG)) - ret = Q_ERR_SUCCESS; - - return ret; -} - static bool check_server(mapcmd_t *cmd, const char *server, bool nextserver) { char expanded[MAX_QPATH]; @@ -278,7 +253,7 @@ static bool check_server(mapcmd_t *cmd, const char *server, bool nextserver) if (!sv_cinematics->integer && nextserver) return false; // skip it if (Q_concat(expanded, sizeof(expanded), "video/", s) < sizeof(expanded)) { - ret = COM_DEDICATED ? Q_ERR_SUCCESS : check_cinematic(expanded); + ret = SCR_CheckForCinematic(expanded); } cmd->state = ss_cinematic; } else { @@ -387,7 +362,7 @@ void SV_InitGame(unsigned mvd_spawn) #if USE_FPS // set up default frametime for main loop - sv.frametime = BASE_FRAMETIME; + sv.frametime = Com_ComputeFrametime(BASE_FRAMERATE); #endif } diff --git a/src/server/main.c b/src/server/main.c index f49d368d2..f7eae92a6 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -533,7 +533,7 @@ static void SVC_Info(void) if (sv_maxclients->integer == 1) return; // ignore in single player - version = atoi(Cmd_Argv(1)); + version = Q_atoi(Cmd_Argv(1)); if (version < PROTOCOL_VERSION_DEFAULT || version > PROTOCOL_VERSION_AQTION) return; // ignore invalid versions @@ -638,9 +638,9 @@ typedef struct { static bool parse_basic_params(conn_params_t *p) { - p->protocol = atoi(Cmd_Argv(1)); - p->qport = atoi(Cmd_Argv(2)) ; - p->challenge = atoi(Cmd_Argv(3)); + p->protocol = Q_atoi(Cmd_Argv(1)); + p->qport = Q_atoi(Cmd_Argv(2)) ; + p->challenge = Q_atoi(Cmd_Argv(3)); // check for invalid protocol version if (p->protocol < PROTOCOL_VERSION_OLD || @@ -738,7 +738,7 @@ static bool parse_packet_length(conn_params_t *p) if (p->protocol >= PROTOCOL_VERSION_R1Q2) { s = Cmd_Argv(5); if (*s) { - p->maxlength = atoi(s); + p->maxlength = Q_atoi(s); if (p->maxlength < 0 || p->maxlength > MAX_PACKETLEN_WRITABLE) return reject("Invalid maximum message length.\n"); @@ -769,10 +769,9 @@ static bool parse_enhanced_params(conn_params_t *p) // set minor protocol version s = Cmd_Argv(6); if (*s) { - p->version = atoi(s); - clamp(p->version, - PROTOCOL_VERSION_R1Q2_MINIMUM, - PROTOCOL_VERSION_R1Q2_CURRENT); + p->version = Q_clip(Q_atoi(s), + PROTOCOL_VERSION_R1Q2_MINIMUM, + PROTOCOL_VERSION_R1Q2_CURRENT); } else { p->version = PROTOCOL_VERSION_R1Q2_MINIMUM; } @@ -782,7 +781,7 @@ static bool parse_enhanced_params(conn_params_t *p) // set netchan type s = Cmd_Argv(6); if (*s) { - p->nctype = atoi(s); + p->nctype = Q_atoi(s); if (p->nctype < NETCHAN_OLD || p->nctype > NETCHAN_NEW) return reject("Invalid netchan type.\n"); } else { @@ -791,15 +790,14 @@ static bool parse_enhanced_params(conn_params_t *p) // set zlib s = Cmd_Argv(7); - p->has_zlib = !*s || atoi(s); + p->has_zlib = !*s || Q_atoi(s); // set minor protocol version s = Cmd_Argv(8); if (*s) { - p->version = atoi(s); - clamp(p->version, - PROTOCOL_VERSION_Q2PRO_MINIMUM, - PROTOCOL_VERSION_Q2PRO_CURRENT); + p->version = Q_clip(Q_atoi(s), + PROTOCOL_VERSION_Q2PRO_MINIMUM, + PROTOCOL_VERSION_Q2PRO_CURRENT); if (p->version == PROTOCOL_VERSION_Q2PRO_RESERVED) { p->version--; // never use this version } @@ -811,7 +809,7 @@ static bool parse_enhanced_params(conn_params_t *p) // set netchan type s = Cmd_Argv(6); if (*s) { - p->nctype = atoi(s); + p->nctype = Q_atoi(s); if (p->nctype < NETCHAN_OLD || p->nctype > NETCHAN_NEW) return reject("Invalid netchan type.\n"); } @@ -826,8 +824,7 @@ static bool parse_enhanced_params(conn_params_t *p) // set minor protocol version s = Cmd_Argv(8); if (*s) { - p->version = atoi(s); - clamp(p->version, + p->version = Q_clip(Q_atoi(s), PROTOCOL_VERSION_AQTION_MINIMUM, PROTOCOL_VERSION_AQTION_CURRENT); } @@ -1154,7 +1151,7 @@ static void SVC_DirectConnect(void) Q_strlcpy(newcl->reconnect_var, params.reconnect_var, sizeof(newcl->reconnect_var)); Q_strlcpy(newcl->reconnect_val, params.reconnect_val, sizeof(newcl->reconnect_val)); #if USE_FPS - newcl->framediv = sv.framediv; + newcl->framediv = sv.frametime.div; newcl->settings[CLS_FPS] = BASE_FRAMERATE; #endif @@ -1586,7 +1583,7 @@ static void SV_PacketEvent(void) netchan->remote_address.port = net_from.port; } - if (!netchan->Process(netchan)) + if (!Netchan_Process(netchan)) break; if (client->state == cs_zombie) @@ -1612,7 +1609,7 @@ static void SV_PacketEvent(void) static void update_client_mtu(client_t *client, int ee_info) { netchan_t *netchan = &client->netchan; - size_t newpacketlen; + unsigned newpacketlen; // sanity check discovered MTU if (ee_info < 576 || ee_info > 4096) @@ -1632,7 +1629,7 @@ static void update_client_mtu(client_t *client, int ee_info) if (newpacketlen >= netchan->maxpacketlen) return; - Com_Printf("Fixing up maxmsglen for %s: %zu --> %zu\n", + Com_Printf("Fixing up maxmsglen for %s: %u --> %u\n", client->name, netchan->maxpacketlen, newpacketlen); netchan->maxpacketlen = newpacketlen; } @@ -1836,7 +1833,7 @@ static void SV_RunGameFrame(void) #endif if (msg_write.cursize) { - Com_WPrintf("Game left %zu bytes " + Com_WPrintf("Game left %u bytes " "in multicast buffer, cleared.\n", msg_write.cursize); SZ_Clear(&msg_write); @@ -2075,8 +2072,7 @@ void SV_UserinfoChanged(client_t *cl) // rate command val = Info_ValueForKey(cl->userinfo, "rate"); if (*val) { - cl->rate = atoi(val); - clamp(cl->rate, sv_min_rate->integer, sv_max_rate->integer); + cl->rate = Q_clip(Q_atoi(val), sv_min_rate->integer, sv_max_rate->integer); } else { cl->rate = 5000; } @@ -2095,8 +2091,7 @@ void SV_UserinfoChanged(client_t *cl) // msg command val = Info_ValueForKey(cl->userinfo, "msg"); if (*val) { - cl->messagelevel = atoi(val); - clamp(cl->messagelevel, PRINT_LOW, PRINT_CHAT + 1); + cl->messagelevel = Q_clip(Q_atoi(val), PRINT_LOW, 256); } } @@ -2317,7 +2312,8 @@ void SV_Init(void) #if USE_FPS // set up default frametime for main loop - sv.frametime = BASE_FRAMETIME; + sv.framerate = BASE_FRAMERATE; + sv.frametime = Com_ComputeFrametime(sv.framerate); #endif // set up default pmove parameters @@ -2371,9 +2367,9 @@ static void SV_FinalMessage(const char *message, error_type_t type) } netchan = &client->netchan; while (netchan->fragment_pending) { - netchan->TransmitNextFragment(netchan); + Netchan_TransmitNextFragment(netchan); } - netchan->Transmit(netchan, msg_write.cursize, msg_write.data, 1); + Netchan_Transmit(netchan, msg_write.cursize, msg_write.data, 1); } } @@ -2438,7 +2434,8 @@ void SV_Shutdown(const char *finalmsg, error_type_t type) #if USE_FPS // set up default frametime for main loop - sv.frametime = BASE_FRAMETIME; + sv.framerate = BASE_FRAMERATE; + sv.frametime = Com_ComputeFrametime(sv.framerate); #endif sv_client = NULL; diff --git a/src/server/mvd.c b/src/server/mvd.c index 7ef44d89e..b7b08aee9 100644 --- a/src/server/mvd.c +++ b/src/server/mvd.c @@ -142,7 +142,7 @@ static char dummy_buffer_text[MAX_STRING_CHARS]; static void dummy_wait_f(void) { - int count = atoi(Cmd_Argv(1)); + int count = Q_atoi(Cmd_Argv(1)); dummy_buffer.waitCount += max(count, 1); } @@ -1124,7 +1124,6 @@ void SV_MvdMulticast(int leafnum, multicast_t to) { mvd_ops_t op; sizebuf_t *buf; - int bits; // do nothing if not active if (!mvd.active) { @@ -1141,9 +1140,8 @@ void SV_MvdMulticast(int leafnum, multicast_t to) op = mvd_multicast_all + to; buf = to < MULTICAST_ALL_R ? &mvd.datagram : &mvd.message; - bits = (msg_write.cursize >> 8) & 7; - SZ_WriteByte(buf, op | (bits << SVCMD_BITS)); + SZ_WriteByte(buf, op | (msg_write.cursize >> 8 << SVCMD_BITS)); SZ_WriteByte(buf, msg_write.cursize & 255); if (op != mvd_multicast_all && op != mvd_multicast_all_r) { @@ -1194,7 +1192,6 @@ void SV_MvdUnicast(edict_t *ent, int clientNum, bool reliable) { mvd_ops_t op; sizebuf_t *buf; - int bits; // do nothing if not active if (!mvd.active) { @@ -1225,8 +1222,7 @@ void SV_MvdUnicast(edict_t *ent, int clientNum, bool reliable) } // write it - bits = (msg_write.cursize >> 8) & 7; - SZ_WriteByte(buf, op | (bits << SVCMD_BITS)); + SZ_WriteByte(buf, op | (msg_write.cursize >> 8 << SVCMD_BITS)); SZ_WriteByte(buf, msg_write.cursize & 255); SZ_WriteByte(buf, clientNum); SZ_Write(buf, msg_write.data, msg_write.cursize); diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index fb70bde36..f781b0994 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -60,7 +60,7 @@ typedef struct gtv_s { netstream_t stream; char address[MAX_QPATH]; byte *data; - size_t msglen; + unsigned msglen; unsigned flags; #if USE_ZLIB bool z_act; // true when actively inflating @@ -255,7 +255,7 @@ mvd_t *MVD_SetChannel(int arg) } else #endif if (COM_IsUint(s)) { - id = atoi(s); + id = Q_atoi(s); FOR_EACH_MVD(mvd) { if (mvd->id == id) { return mvd; @@ -355,7 +355,7 @@ static gtv_t *gtv_set_conn(int arg) } if (COM_IsUint(s)) { - id = atoi(s); + id = Q_atoi(s); FOR_EACH_GTV(gtv) { if (gtv->id == id) { return gtv; @@ -557,7 +557,7 @@ static void demo_emit_snapshot(mvd_t *mvd) int64_t pos; char *from, *to; size_t len; - int i, bits; + int i; if (mvd_snaps->integer <= 0) return; @@ -610,8 +610,7 @@ static void demo_emit_snapshot(mvd_t *mvd) for (cs = player->configstrings; cs; cs = cs->next) len += 4 + strlen(cs->string); - bits = (len >> 8) & 7; - MSG_WriteByte(mvd_unicast | (bits << SVCMD_BITS)); + MSG_WriteByte(mvd_unicast | (len >> 8 << SVCMD_BITS)); MSG_WriteByte(len & 255); MSG_WriteByte(i); for (cs = player->configstrings; cs; cs = cs->next) { @@ -624,8 +623,7 @@ static void demo_emit_snapshot(mvd_t *mvd) // write layout if (mvd->clientNum != -1) { len = 2 + strlen(mvd->layout); - bits = (len >> 8) & 7; - MSG_WriteByte(mvd_unicast | (bits << SVCMD_BITS)); + MSG_WriteByte(mvd_unicast | (len >> 8 << SVCMD_BITS)); MSG_WriteByte(len & 255); MSG_WriteByte(mvd->clientNum); MSG_WriteByte(svc_layout); @@ -639,12 +637,12 @@ static void demo_emit_snapshot(mvd_t *mvd) memcpy(snap->data, msg_write.data, msg_write.cursize); if (!mvd->snapshots) - mvd->snapshots = MVD_Malloc(sizeof(snap) * MIN_SNAPSHOTS); + mvd->snapshots = MVD_Malloc(sizeof(mvd->snapshots[0]) * MIN_SNAPSHOTS); else - mvd->snapshots = Z_Realloc(mvd->snapshots, sizeof(snap) * ALIGN(mvd->numsnapshots + 1, MIN_SNAPSHOTS)); + mvd->snapshots = Z_Realloc(mvd->snapshots, sizeof(mvd->snapshots[0]) * ALIGN(mvd->numsnapshots + 1, MIN_SNAPSHOTS)); mvd->snapshots[mvd->numsnapshots++] = snap; - Com_DPrintf("[%d] snaplen %zu\n", mvd->framenum, msg_write.cursize); + Com_DPrintf("[%d] snaplen %u\n", mvd->framenum, msg_write.cursize); SZ_Clear(&msg_write); @@ -1697,8 +1695,7 @@ void MVD_Spawn(void) #if USE_FPS // just fixed base FPS sv.framerate = BASE_FRAMERATE; - sv.frametime = BASE_FRAMETIME; - sv.framediv = 1; + sv.frametime = Com_ComputeFrametime(sv.framerate); #endif // set externally visible server name @@ -2203,7 +2200,7 @@ static void MVD_Skip_f(void) return; } - count = atoi(Cmd_Argv(2)); + count = Q_atoi(Cmd_Argv(2)); if (count < 1) { count = 1; } @@ -2265,7 +2262,7 @@ static void MVD_Seek_f(void) return; } - clamp(percent, 0, 100); + percent = Q_clipf(percent, 0, 100); dest = gtv->demoofs + gtv->demosize * percent / 100; byte_seek = true; @@ -2458,7 +2455,7 @@ static void MVD_Control_f(void) Cmd_PrintHelp(options); return; case 'l': - loop = atoi(cmd_optarg); + loop = Q_atoi(cmd_optarg); if (loop < 0) { Com_Printf("Invalid value for %s option.\n", cmd_optopt); Cmd_PrintHint(); @@ -2539,7 +2536,7 @@ static void MVD_Play_f(void) "Prepend slash to specify raw path.\n"); return; case 'l': - loop = atoi(cmd_optarg); + loop = Q_atoi(cmd_optarg); if (loop < 0) { Com_Printf("Invalid value for %s option.\n", cmd_optopt); Cmd_PrintHint(); diff --git a/src/server/mvd/client.h b/src/server/mvd/client.h index 87310706f..27dc782a9 100644 --- a/src/server/mvd/client.h +++ b/src/server/mvd/client.h @@ -115,8 +115,8 @@ typedef enum { typedef struct { int framenum; + unsigned msglen; int64_t filepos; - size_t msglen; byte data[1]; } mvd_snap_t; @@ -144,7 +144,7 @@ typedef struct mvd_s { // delay buffer fifo_t delay; - size_t msglen; + unsigned msglen; unsigned num_packets, min_packets; unsigned underflows, overflows; int framenum; diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index b13052e31..6e2668520 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -1028,7 +1028,7 @@ static mvd_player_t *MVD_SetPlayer(mvd_client_t *client, const char *s) // numeric values are just slot numbers if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); if (i < 0 || i >= mvd->maxclients) { SV_ClientPrintf(client->cl, PRINT_HIGH, "[MVD] Player slot number %d is invalid.\n", i); @@ -1231,7 +1231,7 @@ static void MVD_AutoFollow_f(mvd_client_t *client) memset(client->chase_bitmap, 0, sizeof(client->chase_bitmap)); for (i = 2; i < argc; i++) { - j = atoi(Cmd_Argv(i)); + j = Q_atoi(Cmd_Argv(i)); if (j >= 0 && j < mvd->maxclients) Q_SetBit(client->chase_bitmap, j); } @@ -1785,8 +1785,8 @@ static void MVD_GameInit(void) Com_EPrintf("Couldn't load %s for the Waiting Room: %s\n", buffer, BSP_ErrorString(ret)); Cvar_Reset(mvd_default_map); - strcpy(buffer, "maps/q2dm1.bsp"); - checksum = 80717714; + strcpy(buffer, "maps/wfall.bsp"); + checksum = 917713192; VectorSet(mvd->spawnOrigin, 984, 192, 784); VectorSet(mvd->spawnAngles, 25, 72, 0); } else { @@ -1947,9 +1947,9 @@ static void MVD_GameClientUserinfoChanged(edict_t *ent, char *userinfo) mvd_client_t *client = EDICT_MVDCL(ent); int fov; - client->uf = atoi(Info_ValueForKey(userinfo, "uf")); + client->uf = Q_atoi(Info_ValueForKey(userinfo, "uf")); - fov = atoi(Info_ValueForKey(userinfo, "fov")); + fov = Q_atoi(Info_ValueForKey(userinfo, "fov")); if (fov < 1) { fov = 90; } else if (fov > 160) { diff --git a/src/server/mvd/parse.c b/src/server/mvd/parse.c index d5fd9e1cf..4d250ad2a 100644 --- a/src/server/mvd/parse.c +++ b/src/server/mvd/parse.c @@ -27,8 +27,8 @@ static bool match_ended_hack; #if USE_DEBUG #define SHOWNET(level, ...) \ - if (mvd_shownet->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (mvd_shownet->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) static const char *MVD_ServerCommandString(int cmd) { @@ -257,7 +257,8 @@ static void MVD_UnicastString(mvd_t *mvd, bool reliable, mvd_player_t *player) char string[MAX_QPATH]; mvd_cs_t *cs; byte *data; - size_t readcount, length; + size_t length; + uint32_t readcount; data = msg_read.data + msg_read.readcount - 1; readcount = msg_read.readcount - 1; @@ -302,7 +303,7 @@ static void MVD_UnicastPrint(mvd_t *mvd, bool reliable, mvd_player_t *player) { int level; byte *data; - size_t readcount, length; + uint32_t readcount, length; mvd_client_t *client; client_t *cl; mvd_player_t *target; @@ -342,7 +343,7 @@ static void MVD_UnicastStuff(mvd_t *mvd, bool reliable, mvd_player_t *player) { char string[8]; byte *data; - size_t readcount, length; + uint32_t readcount, length; if (mvd->demoseeking) { MSG_ReadString(NULL, 0); @@ -370,7 +371,7 @@ layouts, etc. Give up as soon as unknown command byte is encountered. static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) { int clientNum; - size_t length, last; + uint32_t length, last; mvd_player_t *player; byte *data; bool reliable; @@ -396,7 +397,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) while (msg_read.readcount < last) { cmd = MSG_ReadByte(); - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); switch (cmd) { case svc_layout: @@ -412,7 +413,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) MVD_UnicastStuff(mvd, reliable, player); break; default: - SHOWNET(1, "%3zu:SKIPPING UNICAST\n", msg_read.readcount - 1); + SHOWNET(1, "%3u:SKIPPING UNICAST\n", msg_read.readcount - 1); // send remaining data and return data = msg_read.data + msg_read.readcount - 1; length = last - msg_read.readcount + 1; @@ -423,7 +424,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) } } - SHOWNET(1, "%3zu:END OF UNICAST\n", msg_read.readcount); + SHOWNET(1, "%3u:END OF UNICAST\n", msg_read.readcount); if (msg_read.readcount > last) { MVD_Destroyf(mvd, "%s: read past end of unicast", __func__); @@ -789,11 +790,11 @@ static void MVD_ParseFrame(mvd_t *mvd) if (!mvd->demoseeking) CM_SetPortalStates(&mvd->cm, data, length); - SHOWNET(1, "%3zu:playerinfo\n", msg_read.readcount); + SHOWNET(1, "%3u:playerinfo\n", msg_read.readcount); MVD_ParsePacketPlayers(mvd); - SHOWNET(1, "%3zu:packetentities\n", msg_read.readcount); + SHOWNET(1, "%3u:packetentities\n", msg_read.readcount); MVD_ParsePacketEntities(mvd); - SHOWNET(1, "%3zu:frame:%u\n", msg_read.readcount, mvd->framenum); + SHOWNET(1, "%3u:frame:%u\n", msg_read.readcount, mvd->framenum); MVD_PlayerToEntityStates(mvd); // update clients now so that effects datagram that @@ -957,7 +958,7 @@ static void MVD_ParseServerData(mvd_t *mvd, int extrabits) } // parse maxclients - index = atoi(mvd->configstrings[mvd->csr->maxclients]); + index = Q_atoi(mvd->configstrings[mvd->csr->maxclients]); if (index < 1 || index > MAX_CLIENTS) { MVD_Destroyf(mvd, "Invalid maxclients"); } @@ -1006,8 +1007,8 @@ static void MVD_ParseServerData(mvd_t *mvd, int extrabits) if (ret) { Com_EPrintf("[%s] =!= Couldn't load %s: %s\n", mvd->name, string, BSP_ErrorString(ret)); // continue with null visibility - } else if (mvd->cm.cache->checksum != atoi(mvd->configstrings[CS_MAPCHECKSUM])) { - Com_EPrintf("[%s] =!= Local map version differs from server!\nRecommend removing that file and reconnecting", mvd->name); + } else if (mvd->cm.cache->checksum != Q_atoi(mvd->configstrings[mvd->csr->mapchecksum])) { + Com_EPrintf("[%s] =!= Local map version differs from server!\nRecommend removing %s locally and reconnecting\n", mvd->name, mvd->mapname); CM_FreeMap(&mvd->cm); } @@ -1058,7 +1059,7 @@ bool MVD_ParseMessage(mvd_t *mvd) #if USE_DEBUG if (mvd_shownet->integer == 1) { - Com_LPrintf(PRINT_DEVELOPER, "%zu ", msg_read.cursize); + Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); } else if (mvd_shownet->integer > 1) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } @@ -1073,7 +1074,7 @@ bool MVD_ParseMessage(mvd_t *mvd) MVD_Destroyf(mvd, "Read past end of message"); } if (msg_read.readcount == msg_read.cursize) { - SHOWNET(1, "%3zu:END OF MESSAGE\n", msg_read.readcount); + SHOWNET(1, "%3u:END OF MESSAGE\n", msg_read.readcount); break; } @@ -1081,7 +1082,7 @@ bool MVD_ParseMessage(mvd_t *mvd) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MVD_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MVD_ServerCommandString(cmd)); switch (cmd) { case mvd_serverdata: @@ -1115,7 +1116,7 @@ bool MVD_ParseMessage(mvd_t *mvd) case mvd_nop: break; default: - MVD_Destroyf(mvd, "Illegible command at %zu: %d", + MVD_Destroyf(mvd, "Illegible command at %u: %d", msg_read.readcount - 1, cmd); } } diff --git a/src/server/save.c b/src/server/save.c index 210ff008a..f95ff8472 100644 --- a/src/server/save.c +++ b/src/server/save.c @@ -25,9 +25,21 @@ with this program; if not, write to the Free Software Foundation, Inc., #define SAVE_CURRENT ".current" #define SAVE_AUTO "save0" +typedef enum { + SAVE_MANUAL, // manual save + SAVE_LEVEL_START, // autosave at level start + SAVE_AUTOSAVE // remaster "autosave" +} savetype_t; + +typedef enum { + LOAD_NONE, // not a savegame load + LOAD_NORMAL, // regular savegame, or remaster "autosave" + LOAD_LEVEL_START, // autosave at level start +} loadtype_t; + static cvar_t *sv_noreload; -static int write_server_file(bool autosave) +static int write_server_file(savetype_t autosave) { char name[MAX_OSPATH]; cvar_t *var; @@ -70,7 +82,7 @@ static int write_server_file(bool autosave) if (Q_snprintf(name, MAX_OSPATH, "%s/save/" SAVE_CURRENT "/game.ssv", fs_gamedir) >= MAX_OSPATH) return -1; - ge->WriteGame(name, autosave); + ge->WriteGame(name, autosave == SAVE_LEVEL_START); return 0; } @@ -274,9 +286,12 @@ char *SV_GetSaveInfo(const char *dir) autosave = MSG_ReadByte(); MSG_ReadString(name, sizeof(name)); - if (autosave) + if (autosave == SAVE_LEVEL_START) return Z_CopyString(va("ENTERING %s", name)); + if (autosave == SAVE_AUTOSAVE) + return Z_CopyString(va("AUTOSAVE %s", name)); + // get current year t = time(NULL); tm = localtime(&t); @@ -322,10 +337,10 @@ static int read_server_file(void) // read the comment field MSG_ReadLong64(); - if (MSG_ReadByte()) - cmd.loadgame = 2; // autosave + if (MSG_ReadByte() == SAVE_LEVEL_START) + cmd.loadgame = LOAD_LEVEL_START; else - cmd.loadgame = 1; // regular savegame + cmd.loadgame = LOAD_NORMAL; MSG_ReadString(NULL, 0); // read the mapcmd @@ -505,7 +520,7 @@ void SV_AutoSaveEnd(void) return; // save server state - if (write_server_file(true)) { + if (write_server_file(SAVE_LEVEL_START)) { Com_EPrintf("Couldn't write server file.\n"); return; } @@ -533,12 +548,12 @@ void SV_CheckForSavegame(const mapcmd_t *cmd) if (read_level_file()) { // only warn when loading a regular savegame. autosave without level // file is ok and simply starts the map from the beginning. - if (cmd->loadgame == 1) + if (cmd->loadgame == LOAD_NORMAL) Com_EPrintf("Couldn't read level file.\n"); return; } - if (cmd->loadgame) { + if (cmd->loadgame == LOAD_NORMAL) { // called from SV_Loadgame_f ge->RunFrame(); ge->RunFrame(); @@ -622,6 +637,7 @@ static void SV_Loadgame_f(void) static void SV_Savegame_f(void) { char *dir; + savetype_t type; if (sv.state != ss_game) { Com_Printf("You must be in a game to save.\n"); @@ -649,15 +665,21 @@ static void SV_Savegame_f(void) } } - if (Cmd_Argc() != 2) { - Com_Printf("Usage: %s \n", Cmd_Argv(0)); - return; - } + if (!strcmp(Cmd_Argv(0), "autosave")) { + dir = "save1"; + type = SAVE_AUTOSAVE; + } else { + if (Cmd_Argc() != 2) { + Com_Printf("Usage: %s \n", Cmd_Argv(0)); + return; + } - dir = Cmd_Argv(1); - if (!COM_IsPath(dir)) { - Com_Printf("Bad savedir.\n"); - return; + dir = Cmd_Argv(1); + if (!COM_IsPath(dir)) { + Com_Printf("Bad savedir.\n"); + return; + } + type = SAVE_MANUAL; } // archive current level, including all client edicts. @@ -669,7 +691,7 @@ static void SV_Savegame_f(void) } // save server state - if (write_server_file(false)) { + if (write_server_file(type)) { Com_Printf("Couldn't write server file.\n"); return; } @@ -690,6 +712,7 @@ static void SV_Savegame_f(void) } static const cmdreg_t c_savegames[] = { + { "autosave", SV_Savegame_f }, { "save", SV_Savegame_f, SV_Savegame_c }, { "load", SV_Loadgame_f, SV_Savegame_c }, { NULL } diff --git a/src/server/send.c b/src/server/send.c index 6e420d209..6396193be 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -71,7 +71,7 @@ static bool SV_RateDrop(client_t *client) } #if USE_FPS - total = total * sv.framediv / client->framediv; + total = total * sv.frametime.div / client->framediv; #endif if (total > client->rate) { @@ -86,7 +86,7 @@ static bool SV_RateDrop(client_t *client) return false; } -static void SV_CalcSendTime(client_t *client, size_t size) +static void SV_CalcSendTime(client_t *client, unsigned size) { // never drop over the loopback if (!client->rate) { @@ -358,7 +358,7 @@ static int compress_message(client_t *client) deflateReset(&svs.z); if (ret != Z_STREAM_END) { - Com_WPrintf("Error %d compressing %zu bytes message for %s\n", + Com_WPrintf("Error %d compressing %u bytes message for %s\n", ret, msg_write.cursize, client->name); return 0; } @@ -405,11 +405,11 @@ void SV_ClientAddMessage(client_t *client, int flags) if ((flags & MSG_COMPRESS) && (len = compress_message(client)) && len < msg_write.cursize) { client->AddMessage(client, get_compressed_data(), len, flags & MSG_RELIABLE); - SV_DPrintf(0, "Compressed %sreliable message to %s: %zu into %d\n", + SV_DPrintf(0, "Compressed %sreliable message to %s: %u into %d\n", (flags & MSG_RELIABLE) ? "" : "un", client->name, msg_write.cursize, len); } else { client->AddMessage(client, msg_write.data, msg_write.cursize, flags & MSG_RELIABLE); - SV_DPrintf(1, "Added %sreliable message to %s: %zu bytes\n", + SV_DPrintf(1, "Added %sreliable message to %s: %u bytes\n", (flags & MSG_RELIABLE) ? "" : "un", client->name, msg_write.cursize); } @@ -565,7 +565,7 @@ static void emit_snd(client_t *client, message_packet_t *msg) } } -static inline void write_snd(client_t *client, message_packet_t *msg, size_t maxsize) +static inline void write_snd(client_t *client, message_packet_t *msg, unsigned maxsize) { // if this msg fits, write it if (msg_write.cursize + MAX_SOUND_PACKET <= maxsize) { @@ -575,7 +575,7 @@ static inline void write_snd(client_t *client, message_packet_t *msg, size_t max List_Insert(&client->msg_free_list, &msg->entry); } -static inline void write_msg(client_t *client, message_packet_t *msg, size_t maxsize) +static inline void write_msg(client_t *client, message_packet_t *msg, unsigned maxsize) { // if this msg fits, write it if (msg_write.cursize + msg->cursize <= maxsize) { @@ -584,7 +584,7 @@ static inline void write_msg(client_t *client, message_packet_t *msg, size_t max free_msg_packet(client, msg); } -static inline void write_unreliables(client_t *client, size_t maxsize) +static inline void write_unreliables(client_t *client, unsigned maxsize) { message_packet_t *msg, *next; @@ -621,7 +621,7 @@ static void add_message_old(client_t *client, byte *data, } // this should be the only place data is ever written to netchan message for old clients -static void write_reliables_old(client_t *client, size_t maxsize) +static void write_reliables_old(client_t *client, unsigned maxsize) { message_packet_t *msg, *next; int count; @@ -654,7 +654,7 @@ static void write_reliables_old(client_t *client, size_t maxsize) } // unreliable portion doesn't fit, then throw out low priority effects -static void repack_unreliables(client_t *client, size_t maxsize) +static void repack_unreliables(client_t *client, unsigned maxsize) { message_packet_t *msg, *next; @@ -713,7 +713,7 @@ static void repack_unreliables(client_t *client, size_t maxsize) static void write_datagram_old(client_t *client) { message_packet_t *msg; - size_t maxsize, cursize; + unsigned maxsize, cursize; // determine how much space is left for unreliable data maxsize = client->netchan.maxpacketlen; @@ -734,7 +734,7 @@ static void write_datagram_old(client_t *client) // and the player_state_t client->WriteFrame(client); if (msg_write.cursize > maxsize) { - size_t size = msg_write.cursize; + unsigned size = msg_write.cursize; int len = 0; // try to compress if it has a chance to fit @@ -745,11 +745,11 @@ static void write_datagram_old(client_t *client) SZ_Clear(&msg_write); if (len > 0 && len <= maxsize) { - SV_DPrintf(0, "Frame %d compressed for %s: %zu into %d\n", + SV_DPrintf(0, "Frame %d compressed for %s: %u into %d\n", client->framenum, client->name, size, len); SZ_Write(&msg_write, get_compressed_data(), len); } else { - SV_DPrintf(0, "Frame %d overflowed for %s: %zu > %zu (comp %d)\n", + SV_DPrintf(0, "Frame %d overflowed for %s: %u > %u (comp %d)\n", client->framenum, client->name, size, maxsize, len); } } @@ -770,7 +770,7 @@ static void write_datagram_old(client_t *client) #if USE_DEBUG if (sv_pad_packets->integer > 0) { - size_t pad = min(MAX_PACKETLEN - 8, sv_pad_packets->integer); + int pad = min(MAX_PACKETLEN - 8, sv_pad_packets->integer); while (msg_write.cursize < pad) MSG_WriteByte(svc_nop); @@ -778,10 +778,10 @@ static void write_datagram_old(client_t *client) #endif // send the datagram - cursize = client->netchan.Transmit(&client->netchan, - msg_write.cursize, - msg_write.data, - client->numpackets); + cursize = Netchan_Transmit(&client->netchan, + msg_write.cursize, + msg_write.data, + client->numpackets); // record the size for rate estimation SV_CalcSendTime(client, cursize); @@ -812,7 +812,7 @@ static void add_message_new(client_t *client, byte *data, static void write_datagram_new(client_t *client) { - size_t cursize; + int cursize; // send over all the relevant entity_state_t // and the player_state_t @@ -836,7 +836,7 @@ static void write_datagram_new(client_t *client) #if USE_DEBUG if (sv_pad_packets->integer > 0) { - size_t pad = min(msg_write.maxsize, sv_pad_packets->integer); + int pad = min(msg_write.maxsize, sv_pad_packets->integer); while (msg_write.cursize < pad) MSG_WriteByte(svc_nop); @@ -844,10 +844,10 @@ static void write_datagram_new(client_t *client) #endif // send the datagram - cursize = client->netchan.Transmit(&client->netchan, - msg_write.cursize, - msg_write.data, - client->numpackets); + cursize = Netchan_Transmit(&client->netchan, + msg_write.cursize, + msg_write.data, + client->numpackets); // record the size for rate estimation SV_CalcSendTime(client, cursize); @@ -878,8 +878,8 @@ static void finish_frame(client_t *client) #if USE_DEBUG && USE_FPS static void check_key_sync(client_t *client) { - int div = sv.framediv / client->framediv; - int key1 = !(sv.framenum % sv.framediv); + int div = sv.frametime.div / client->framediv; + int key1 = !(sv.framenum % sv.frametime.div); int key2 = !(client->framenum % div); if (key1 != key2) { @@ -901,7 +901,7 @@ Clients in earlier connection state are handled in SV_SendAsyncPackets. void SV_SendClientMessages(void) { client_t *client; - size_t cursize; + int cursize; // send a message to each connected client FOR_EACH_CLIENT(client) { @@ -931,7 +931,7 @@ void SV_SendClientMessages(void) // don't write any frame data until all fragments are sent if (client->netchan.fragment_pending) { client->frameflags |= FF_SUPPRESSED; - cursize = client->netchan.TransmitNextFragment(&client->netchan); + cursize = Netchan_TransmitNextFragment(&client->netchan); SV_CalcSendTime(client, cursize); goto advance; } @@ -1001,7 +1001,7 @@ void SV_SendAsyncPackets(void) bool retransmit; client_t *client; netchan_t *netchan; - size_t cursize; + int cursize; FOR_EACH_CLIENT(client) { // don't overrun bandwidth @@ -1013,8 +1013,8 @@ void SV_SendAsyncPackets(void) // make sure all fragments are transmitted first if (netchan->fragment_pending) { - cursize = netchan->TransmitNextFragment(netchan); - SV_DPrintf(1, "%s: frag: %zu\n", client->name, cursize); + cursize = Netchan_TransmitNextFragment(netchan); + SV_DPrintf(1, "%s: frag: %d\n", client->name, cursize); goto calctime; } @@ -1041,8 +1041,8 @@ void SV_SendAsyncPackets(void) if (netchan->message.cursize || netchan->reliable_ack_pending || netchan->reliable_length || retransmit) { - cursize = netchan->Transmit(netchan, 0, "", 1); - SV_DPrintf(1, "%s: send: %zu\n", client->name, cursize); + cursize = Netchan_Transmit(netchan, 0, NULL, 1); + SV_DPrintf(1, "%s: send: %d\n", client->name, cursize); calctime: SV_CalcSendTime(client, cursize); } diff --git a/src/server/server.h b/src/server/server.h index 224456ad8..ed3f90b45 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -62,8 +62,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #if USE_DEBUG #define SV_DPrintf(level,...) \ - if (sv_debug && sv_debug->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (sv_debug && sv_debug->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define SV_DPrintf(...) #endif @@ -138,9 +138,9 @@ typedef struct { // variable server FPS #if USE_FPS #define SV_FRAMERATE sv.framerate -#define SV_FRAMETIME sv.frametime -#define SV_FRAMEDIV sv.framediv -#define SV_FRAMESYNC !(sv.framenum % sv.framediv) +#define SV_FRAMETIME sv.frametime.time +#define SV_FRAMEDIV sv.frametime.div +#define SV_FRAMESYNC !(sv.framenum % sv.frametime.div) #define SV_CLIENTSYNC(cl) !(sv.framenum % (cl)->framediv) #else #define SV_FRAMERATE BASE_FRAMERATE @@ -160,8 +160,7 @@ typedef struct { #if USE_FPS int framerate; - int frametime; - int framediv; + frametime_t frametime; #endif int framenum; @@ -225,10 +224,10 @@ typedef enum { #define MSG_POOLSIZE 1024 #define MSG_TRESHOLD (62 - sizeof(list_t)) // keep message_packet_t 64 bytes aligned -#define MSG_RELIABLE 1 -#define MSG_CLEAR 2 -#define MSG_COMPRESS 4 -#define MSG_COMPRESS_AUTO 8 +#define MSG_RELIABLE BIT(0) +#define MSG_CLEAR BIT(1) +#define MSG_COMPRESS BIT(2) +#define MSG_COMPRESS_AUTO BIT(3) #define ZPACKET_HEADER 5 @@ -490,7 +489,7 @@ typedef struct server_static_s { #if USE_ZLIB z_stream z; // for compressing messages at once byte *z_buffer; - size_t z_buffer_size; + unsigned z_buffer_size; #endif cs_remap_t csr; @@ -679,6 +678,7 @@ void SV_MvdStartSound(int entnum, int channel, int flags, void SV_MvdRecord_f(void); void SV_MvdStop_f(void); +void SV_ListSounds_f(void); #else #define SV_MvdRegister() (void)0 #define SV_MvdPreInit() (void)0 diff --git a/src/server/user.c b/src/server/user.c index dc5fd48e3..e7e5cab68 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -178,7 +178,7 @@ static void write_configstring_stream(void) length = Q_strnlen(string, MAX_QPATH); // check if this configstring will overflow - if (msg_write.cursize + length + 4 > msg_write.maxsize) { + if (msg_write.cursize + length + 5 > msg_write.maxsize) { MSG_WriteShort(sv_client->csr->end); SV_ClientAddMessage(sv_client, MSG_GAMESTATE); MSG_WriteByte(svc_configstringstream); @@ -472,16 +472,14 @@ void SV_New_f(void) return; // send gamestate - if (sv_client->netchan.type == NETCHAN_NEW) { - if (sv_client->version >= PROTOCOL_VERSION_Q2PRO_EXTENDED_LIMITS) { - write_configstring_stream(); - write_baseline_stream(); - } else { - write_gamestate(); - } - } else { + if (sv_client->netchan.type == NETCHAN_OLD) { write_configstrings(); write_baselines(); + } else if (sv_client->version >= PROTOCOL_VERSION_Q2PRO_EXTENDED_LIMITS) { + write_configstring_stream(); + write_baseline_stream(); + } else { + write_gamestate(); } // send next command @@ -645,7 +643,7 @@ static void SV_BeginDownload_f(void) len = FS_NormalizePath(name); if (Cmd_Argc() > 2) - offset = atoi(Cmd_Argv(2)); // downloaded offset + offset = Q_atoi(Cmd_Argv(2)); // downloaded offset // hacked by zoid to allow more conrol over download // first off, no .. or global allow check @@ -813,7 +811,7 @@ static void SV_NextServer_f(void) if (sv.state == ss_pic && !Cvar_VariableInteger("coop")) return; // ss_pic can be nextserver'd in coop mode - if (atoi(Cmd_Argv(1)) != sv.spawncount) + if (Q_atoi(Cmd_Argv(1)) != sv.spawncount) return; // leftover from last server sv.spawncount ^= 1; // make sure another doesn't sneak in @@ -893,7 +891,7 @@ static void SV_PacketdupHack_f(void) int numdups = sv_client->numpackets - 1; if (Cmd_Argc() > 1) { - numdups = atoi(Cmd_Argv(1)); + numdups = Q_atoi(Cmd_Argv(1)); if (numdups < 0 || numdups > sv_packetdup_hack->integer) { SV_ClientPrintf(sv_client, PRINT_HIGH, "Packetdup of %d is not allowed on this server.\n", numdups); @@ -1590,7 +1588,7 @@ static void SV_ParseDeltaUserinfo(void) #if USE_FPS void SV_AlignKeyFrames(client_t *client) { - int framediv = sv.framediv / client->framediv; + int framediv = sv.frametime.div / client->framediv; int framenum = sv.framenum / client->framediv; int frameofs = framenum % framediv; int newnum = frameofs + Q_align(client->framenum, framediv); @@ -1608,15 +1606,12 @@ static void set_client_fps(int value) if (!value) value = sv.framerate; - framediv = value / BASE_FRAMERATE; - - clamp(framediv, 1, MAX_FRAMEDIV); - - framediv = sv.framediv / Q_gcd(sv.framediv, framediv); + framediv = Q_clip(value / BASE_FRAMERATE, 1, MAX_FRAMEDIV); + framediv = sv.frametime.div / Q_gcd(sv.frametime.div, framediv); framerate = sv.framerate / framediv; Com_DDPrintf("[%d] client div=%d, server div=%d, rate=%d\n", - sv.framenum, framediv, sv.framediv, framerate); + sv.framenum, framediv, sv.frametime.div, framerate); sv_client->framediv = framediv; diff --git a/src/server/world.c b/src/server/world.c index 1ba33f3ac..7f3edd576 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -115,7 +115,7 @@ void SV_ClearWorld(void) // make sure all entities are unlinked for (i = 0; i < ge->max_edicts; i++) { ent = EDICT_NUM(i); - ent->area.prev = ent->area.next = NULL; + ent->area.next = ent->area.prev = NULL; } } @@ -228,10 +228,10 @@ void PF_UnlinkEdict(edict_t *ent) { if (!ent) Com_Error(ERR_DROP, "%s: NULL", __func__); - if (!ent->area.prev) + if (!ent->area.next) return; // not linked in anywhere List_Remove(&ent->area); - ent->area.prev = ent->area.next = NULL; + ent->area.next = ent->area.prev = NULL; } static uint32_t SV_PackSolid32(edict_t *ent) @@ -276,7 +276,7 @@ void PF_LinkEdict(edict_t *ent) if (!ent) Com_Error(ERR_DROP, "%s: NULL", __func__); - if (ent->area.prev) + if (ent->area.next) PF_UnlinkEdict(ent); // unlink from old position if (ent == ge->edicts) @@ -437,37 +437,22 @@ Returns a headnode that can be used for testing or clipping an object of mins/maxs size. ================ */ -static mnode_t *SV_HullForEntity(edict_t *ent) +static mnode_t *SV_HullForEntity(edict_t *ent, bool triggers) { - if (ent->solid == SOLID_BSP) { + if (ent->solid == SOLID_BSP || (triggers && ent->solid == SOLID_TRIGGER)) { + bsp_t *bsp = sv.cm.cache; int i = ent->s.modelindex - 1; - // explicit hulls in the BSP model - if (i <= 0 || i >= sv.cm.cache->nummodels) - Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i); - - return sv.cm.cache->models[i].headnode; - } - - // create a temp hull from bounding box sizes - return CM_HeadnodeForBox(ent->mins, ent->maxs); -} - -/* -============= -SV_HullForEntity2 - -Can be used to clip to SOLID_TRIGGER by its BSP tree -============= -*/ -static mnode_t *SV_HullForEntity2(edict_t *ent) -{ - if (ent->solid == SOLID_BSP || ent->solid == SOLID_TRIGGER) { - int i = ent->s.modelindex - 1; + // account for "hole" in configstring namespace + if (i >= MODELINDEX_PLAYER && bsp->nummodels >= MODELINDEX_PLAYER) + i--; // explicit hulls in the BSP model - if (i > 0 && i < sv.cm.cache->nummodels) - return sv.cm.cache->models[i].headnode; + if (i > 0 && i < bsp->nummodels) + return bsp->models[i].headnode; + + if (!triggers) + Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i); } // create a temp hull from bounding box sizes @@ -491,7 +476,7 @@ SV_PointContents */ int SV_PointContents(const vec3_t p) { - edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS_OLD], *hit; int i, num; int contents; @@ -499,13 +484,13 @@ int SV_PointContents(const vec3_t p) contents = CM_PointContents(p, SV_WorldNodes()); // or in contents from all the other entities - num = SV_AreaEdicts(p, p, touch, MAX_EDICTS, AREA_SOLID); + num = SV_AreaEdicts(p, p, touch, q_countof(touch), AREA_SOLID); for (i = 0; i < num; i++) { hit = touch[i]; // might intersect, so do an exact clip - contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit), + contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit, false), hit->s.origin, hit->s.angles); } @@ -572,7 +557,7 @@ static void SV_ClipMoveToEntities(const vec3_t start, const vec3_t mins, // might intersect, so do an exact clip CM_TransformedBoxTrace(&trace, start, end, mins, maxs, - SV_HullForEntity(touch), contentmask, + SV_HullForEntity(touch, false), contentmask, touch->s.origin, touch->s.angles); CM_ClipEntity(tr, &trace, touch); @@ -632,7 +617,7 @@ trace_t q_gameabi SV_Clip(const vec3_t start, const vec3_t mins, CM_BoxTrace(&trace, start, end, mins, maxs, SV_WorldNodes(), contentmask); else CM_TransformedBoxTrace(&trace, start, end, mins, maxs, - SV_HullForEntity2(clip), contentmask, + SV_HullForEntity(clip, true), contentmask, clip->s.origin, clip->s.angles); trace.ent = clip; return trace; diff --git a/src/shared/m_flash.c b/src/shared/m_flash.c index 13d9438ac..827918559 100644 --- a/src/shared/m_flash.c +++ b/src/shared/m_flash.c @@ -24,111 +24,126 @@ with this program; if not, write to the Free Software Foundation, Inc., // the game needs it to source shot locations, the client // needs it to position muzzle flashes const vec3_t monster_flash_offset[MZ2_LAST] = { - [MZ2_TANK_BLASTER_1] = { 20.7f, -18.5f, 28.7f }, - [MZ2_TANK_BLASTER_2] = { 16.6f, -21.5f, 30.1f }, - [MZ2_TANK_BLASTER_3] = { 11.8f, -23.9f, 32.1f }, + [MZ2_TANK_BLASTER_1] = { 28.7f, -18.5f, 28.7f }, + [MZ2_TANK_BLASTER_2] = { 24.6f, -21.5f, 30.1f }, + [MZ2_TANK_BLASTER_3] = { 19.8f, -23.9f, 32.1f }, [MZ2_TANK_MACHINEGUN_1] = { 22.9f, -0.7f, 25.3f }, [MZ2_TANK_MACHINEGUN_2] = { 22.2f, 6.2f, 22.3f }, [MZ2_TANK_MACHINEGUN_3] = { 19.4f, 13.1f, 18.6f }, [MZ2_TANK_MACHINEGUN_4] = { 19.4f, 18.8f, 18.6f }, - [MZ2_TANK_MACHINEGUN_5] = { 17.9f, 25, 18.6f }, + [MZ2_TANK_MACHINEGUN_5] = { 17.9f, 25.0f, 18.6f }, [MZ2_TANK_MACHINEGUN_6] = { 14.1f, 30.5f, 20.6f }, [MZ2_TANK_MACHINEGUN_7] = { 9.3f, 35.3f, 22.1f }, [MZ2_TANK_MACHINEGUN_8] = { 4.7f, 38.4f, 22.1f }, [MZ2_TANK_MACHINEGUN_9] = { -1.1f, 40.4f, 24.1f }, [MZ2_TANK_MACHINEGUN_10] = { -6.5f, 41.2f, 24.1f }, [MZ2_TANK_MACHINEGUN_11] = { 3.2f, 40.1f, 24.7f }, - [MZ2_TANK_MACHINEGUN_12] = { 11.7f, 36.7f, 26 }, - [MZ2_TANK_MACHINEGUN_13] = { 18.9f, 31.3f, 26 }, + [MZ2_TANK_MACHINEGUN_12] = { 11.7f, 36.7f, 26.0f }, + [MZ2_TANK_MACHINEGUN_13] = { 18.9f, 31.3f, 26.0f }, [MZ2_TANK_MACHINEGUN_14] = { 24.4f, 24.4f, 26.4f }, [MZ2_TANK_MACHINEGUN_15] = { 27.1f, 17.1f, 27.2f }, - [MZ2_TANK_MACHINEGUN_16] = { 28.5f, 9.1f, 28 }, - [MZ2_TANK_MACHINEGUN_17] = { 27.1f, 2.2f, 28 }, - [MZ2_TANK_MACHINEGUN_18] = { 24.9f, -2.8f, 28 }, - [MZ2_TANK_MACHINEGUN_19] = { 21.6f, -7, 26.4f }, + [MZ2_TANK_MACHINEGUN_16] = { 28.5f, 9.1f, 28.0f }, + [MZ2_TANK_MACHINEGUN_17] = { 27.1f, 2.2f, 28.0f }, + [MZ2_TANK_MACHINEGUN_18] = { 24.9f, -2.8f, 28.0f }, + [MZ2_TANK_MACHINEGUN_19] = { 21.6f, -7.0f, 26.4f }, [MZ2_TANK_ROCKET_1] = { 6.2f, 29.1f, 49.1f }, [MZ2_TANK_ROCKET_2] = { 6.9f, 23.8f, 49.1f }, [MZ2_TANK_ROCKET_3] = { 8.3f, 17.8f, 49.5f }, + [MZ2_INFANTRY_MACHINEGUN_1] = { 26.6f, 7.1f, 13.1f }, [MZ2_INFANTRY_MACHINEGUN_2] = { 18.2f, 7.5f, 15.4f }, [MZ2_INFANTRY_MACHINEGUN_3] = { 17.2f, 10.3f, 17.9f }, - [MZ2_INFANTRY_MACHINEGUN_4] = { 17, 12.8f, 20.1f }, + [MZ2_INFANTRY_MACHINEGUN_4] = { 17.0f, 12.8f, 20.1f }, [MZ2_INFANTRY_MACHINEGUN_5] = { 15.1f, 14.1f, 21.8f }, [MZ2_INFANTRY_MACHINEGUN_6] = { 11.8f, 17.2f, 23.1f }, - [MZ2_INFANTRY_MACHINEGUN_7] = { 11.4f, 20.2f, 21 }, - [MZ2_INFANTRY_MACHINEGUN_8] = { 9, 23, 18.9f }, + [MZ2_INFANTRY_MACHINEGUN_7] = { 11.4f, 20.2f, 21.0f }, + [MZ2_INFANTRY_MACHINEGUN_8] = { 9.0f, 23.0f, 18.9f }, [MZ2_INFANTRY_MACHINEGUN_9] = { 13.9f, 18.6f, 17.7f }, [MZ2_INFANTRY_MACHINEGUN_10] = { 15.4f, 15.6f, 15.8f }, [MZ2_INFANTRY_MACHINEGUN_11] = { 10.2f, 15.2f, 25.1f }, [MZ2_INFANTRY_MACHINEGUN_12] = { -1.9f, 15.1f, 28.2f }, - [MZ2_INFANTRY_MACHINEGUN_13] = { -12.4f, 13, 20.2f }, - [MZ2_SOLDIER_BLASTER_1] = { 12.72f, 9.24f, 9.36f }, - [MZ2_SOLDIER_BLASTER_2] = { 25.32f, 4.32f, 22.8f }, - [MZ2_SOLDIER_SHOTGUN_1] = { 12.72f, 9.24f, 9.36f }, - [MZ2_SOLDIER_SHOTGUN_2] = { 25.32f, 4.32f, 22.8f }, - [MZ2_SOLDIER_MACHINEGUN_1] = { 12.72f, 9.24f, 9.36f }, - [MZ2_SOLDIER_MACHINEGUN_2] = { 25.32f, 4.32f, 22.8f }, - [MZ2_GUNNER_MACHINEGUN_1] = { 34.615f, 4.485f, 22.54f }, - [MZ2_GUNNER_MACHINEGUN_2] = { 33.465f, 2.875f, 23.805f }, - [MZ2_GUNNER_MACHINEGUN_3] = { 32.43f, 2.875f, 25.53f }, - [MZ2_GUNNER_MACHINEGUN_4] = { 32.43f, 4.14f, 25.3f }, - [MZ2_GUNNER_MACHINEGUN_5] = { 30.935f, 2.3f, 26.91f }, - [MZ2_GUNNER_MACHINEGUN_6] = { 30.475f, 0.69f, 23.92f }, - [MZ2_GUNNER_MACHINEGUN_7] = { 30.935f, 0.575f, 24.725f }, - [MZ2_GUNNER_MACHINEGUN_8] = { 33.35f, 2.76f, 22.425f }, - [MZ2_GUNNER_GRENADE_1] = { 5.29f, -19.32f, 8.395f }, - [MZ2_GUNNER_GRENADE_2] = { 5.29f, -19.32f, 8.395f }, - [MZ2_GUNNER_GRENADE_3] = { 5.29f, -19.32f, 8.395f }, - [MZ2_GUNNER_GRENADE_4] = { 5.29f, -19.32f, 8.395f }, - [MZ2_CHICK_ROCKET_1] = { 24.8f, -9, 39 }, - [MZ2_FLYER_BLASTER_1] = { 12.1f, 13.4f, -14.5f }, - [MZ2_FLYER_BLASTER_2] = { 12.1f, -7.4f, -14.5f }, - [MZ2_MEDIC_BLASTER_1] = { 12.1f, 5.4f, 16.5f }, + [MZ2_INFANTRY_MACHINEGUN_13] = { -12.4f, 13.0f, 20.2f }, + + [MZ2_SOLDIER_BLASTER_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, + [MZ2_SOLDIER_BLASTER_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, + + [MZ2_GUNNER_MACHINEGUN_1] = { 30.1f * 1.15f, 3.9f * 1.15f, 19.6f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_2] = { 29.1f * 1.15f, 2.5f * 1.15f, 20.7f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_3] = { 28.2f * 1.15f, 2.5f * 1.15f, 22.2f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_4] = { 28.2f * 1.15f, 3.6f * 1.15f, 22.0f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_5] = { 26.9f * 1.15f, 2.0f * 1.15f, 23.4f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_6] = { 26.5f * 1.15f, 0.6f * 1.15f, 20.8f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_7] = { 26.9f * 1.15f, 0.5f * 1.15f, 21.5f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_8] = { 29.0f * 1.15f, 2.4f * 1.15f, 19.5f * 1.15f }, + [MZ2_GUNNER_GRENADE_1] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + [MZ2_GUNNER_GRENADE_2] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + [MZ2_GUNNER_GRENADE_3] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + [MZ2_GUNNER_GRENADE_4] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + + [MZ2_CHICK_ROCKET_1] = { 24.8f, -9.0f, 39.0f }, + + [MZ2_FLYER_BLASTER_1] = { 14.1f, 13.4f, -7.0f }, + [MZ2_FLYER_BLASTER_2] = { 14.1f, -13.4f, -7.0f }, + + [MZ2_MEDIC_BLASTER_1] = { 44.0f, 3.0f, 14.4f }, + [MZ2_GLADIATOR_RAILGUN_1] = { 30, 18, 28 }, - [MZ2_HOVER_BLASTER_1] = { 32.5f, -0.8f, 10 }, + + [MZ2_HOVER_BLASTER_1] = { 1.7f, 7.0f, 11.3f }, + [MZ2_ACTOR_MACHINEGUN_1] = { 18.4f, 7.4f, 9.6f }, - [MZ2_SUPERTANK_MACHINEGUN_1] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_2] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_3] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_4] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_5] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_6] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_ROCKET_1] = { 16, -22.5f, 91.2f }, - [MZ2_SUPERTANK_ROCKET_2] = { 16, -33.4f, 86.7f }, - [MZ2_SUPERTANK_ROCKET_3] = { 16, -42.8f, 83.3f }, + + [MZ2_SUPERTANK_MACHINEGUN_1] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_2] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_3] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_4] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_5] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_6] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_ROCKET_1] = { 16.0f, -22.5f, 108.7f }, + [MZ2_SUPERTANK_ROCKET_2] = { 16.0f, -33.4f, 106.7f }, + [MZ2_SUPERTANK_ROCKET_3] = { 16.0f, -42.8f, 104.7f }, + [MZ2_BOSS2_MACHINEGUN_L1] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L2] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L3] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L4] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L5] = { 32, -40, 70 }, + [MZ2_BOSS2_ROCKET_1] = { 22, 16, 10 }, [MZ2_BOSS2_ROCKET_2] = { 22, 8, 10 }, [MZ2_BOSS2_ROCKET_3] = { 22, -8, 10 }, [MZ2_BOSS2_ROCKET_4] = { 22, -16, 10 }, + [MZ2_FLOAT_BLASTER_1] = { 32.5f, -0.8f, 10 }, - [MZ2_SOLDIER_BLASTER_3] = { 24.96f, 12.12f, -3.24f }, - [MZ2_SOLDIER_SHOTGUN_3] = { 24.96f, 12.12f, -3.24f }, - [MZ2_SOLDIER_MACHINEGUN_3] = { 24.96f, 12.12f, -3.24f }, - [MZ2_SOLDIER_BLASTER_4] = { 9.12f, 11.16f, 0.96f }, - [MZ2_SOLDIER_SHOTGUN_4] = { 9.12f, 11.16f, 0.96f }, - [MZ2_SOLDIER_MACHINEGUN_4] = { 9.12f, 11.16f, 0.96f }, - [MZ2_SOLDIER_BLASTER_5] = { 36.6f, 11.88f, -22.44f }, - [MZ2_SOLDIER_SHOTGUN_5] = { 36.6f, 11.88f, -22.44f }, - [MZ2_SOLDIER_MACHINEGUN_5] = { 36.6f, 11.88f, -22.44f }, - [MZ2_SOLDIER_BLASTER_6] = { 33.12f, 4.08f, -12.48f }, - [MZ2_SOLDIER_SHOTGUN_6] = { 33.12f, 4.08f, -12.48f }, - [MZ2_SOLDIER_MACHINEGUN_6] = { 33.12f, 4.08f, -12.48f }, - [MZ2_SOLDIER_BLASTER_7] = { 34.68f, 5.52f, -9.72f }, - [MZ2_SOLDIER_SHOTGUN_7] = { 34.68f, 5.52f, -9.72f }, - [MZ2_SOLDIER_MACHINEGUN_7] = { 34.68f, 5.52f, -9.72f }, - [MZ2_SOLDIER_BLASTER_8] = { 37.8f, 11.52f, 12.12f }, - [MZ2_SOLDIER_SHOTGUN_8] = { 41.4f, 11.52f, 7.32f }, - [MZ2_SOLDIER_MACHINEGUN_8] = { 41.4f, 11.52f, 7.32f }, + + [MZ2_SOLDIER_BLASTER_3] = { 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_3] = { 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_3] = { 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f }, + [MZ2_SOLDIER_BLASTER_4] = { 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_4] = { 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_4] = { 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f }, + [MZ2_SOLDIER_BLASTER_5] = { 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_5] = { 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_5] = { 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f }, + [MZ2_SOLDIER_BLASTER_6] = { 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_6] = { 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_6] = { 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f }, + [MZ2_SOLDIER_BLASTER_7] = { 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_7] = { 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_7] = { 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f }, + [MZ2_SOLDIER_BLASTER_8] = { 31.5f * 1.2f, 9.6f * 1.2f, 10.1f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_8] = { 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_8] = { 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f }, + [MZ2_MAKRON_BFG] = { 17, -19.5f, 62.9f }, [MZ2_MAKRON_BLASTER_1] = { -3.6f, -24.1f, 59.5f }, [MZ2_MAKRON_BLASTER_2] = { -1.6f, -19.3f, 59.5f }, [MZ2_MAKRON_BLASTER_3] = { -0.1f, -14.4f, 59.5f }, - [MZ2_MAKRON_BLASTER_4] = { 2, -7.6f, 59.5f }, + [MZ2_MAKRON_BLASTER_4] = { 2.0f, -7.6f, 59.5f }, [MZ2_MAKRON_BLASTER_5] = { 3.4f, 1.3f, 59.5f }, [MZ2_MAKRON_BLASTER_6] = { 3.7f, 11.1f, 59.5f }, [MZ2_MAKRON_BLASTER_7] = { -0.3f, 22.3f, 59.5f }, @@ -142,7 +157,8 @@ const vec3_t monster_flash_offset[MZ2_LAST] = { [MZ2_MAKRON_BLASTER_15] = { 4.2f, -14.1f, 59.5f }, [MZ2_MAKRON_BLASTER_16] = { 2.4f, -18.8f, 59.5f }, [MZ2_MAKRON_BLASTER_17] = { -1.8f, -25.5f, 59.5f }, - [MZ2_MAKRON_RAILGUN_1] = { -17.3f, 7.8f, 72.4f }, + [MZ2_MAKRON_RAILGUN_1] = { 18.1f, 7.8f, 74.4f }, + [MZ2_JORG_MACHINEGUN_L1] = { 78.5f, -47.1f, 96 }, [MZ2_JORG_MACHINEGUN_L2] = { 78.5f, -47.1f, 96 }, [MZ2_JORG_MACHINEGUN_L3] = { 78.5f, -47.1f, 96 }, @@ -156,22 +172,24 @@ const vec3_t monster_flash_offset[MZ2_LAST] = { [MZ2_JORG_MACHINEGUN_R5] = { 78.5f, 46.7f, 96 }, [MZ2_JORG_MACHINEGUN_R6] = { 78.5f, 46.7f, 96 }, [MZ2_JORG_BFG_1] = { 6.3f, -9, 111.2f }, + [MZ2_BOSS2_MACHINEGUN_R1] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R2] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R3] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R4] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R5] = { 32, 40, 70 }, + [MZ2_CARRIER_MACHINEGUN_L1] = { 56, -32, 32 }, [MZ2_CARRIER_MACHINEGUN_R1] = { 56, 32, 32 }, [MZ2_CARRIER_GRENADE] = { 42, 24, 50 }, - [MZ2_TURRET_MACHINEGUN] = { 16, 0, 0 }, - [MZ2_TURRET_ROCKET] = { 16, 0, 0 }, - [MZ2_TURRET_BLASTER] = { 16, 0, 0 }, + [MZ2_TURRET_MACHINEGUN] = { 20, 0, 0 }, + [MZ2_TURRET_ROCKET] = { 20, 0, 0 }, + [MZ2_TURRET_BLASTER] = { 20, 0, 0 }, [MZ2_STALKER_BLASTER] = { 24, 0, 6 }, - [MZ2_DAEDALUS_BLASTER] = { 32.5f, -0.8f, 10 }, - [MZ2_MEDIC_BLASTER_2] = { 12.1f, 5.4f, 16.5f }, + [MZ2_DAEDALUS_BLASTER] = { 1.7f, 7.0f, 11.3f }, + [MZ2_MEDIC_BLASTER_2] = { 44.0f, 3.0f, 14.4f }, [MZ2_CARRIER_RAILGUN] = { 32, 0, 6 }, - [MZ2_WIDOW_DISRUPTOR] = { 57.72f, 14.5f, 88.81f }, + [MZ2_WIDOW_DISRUPTOR] = { 64.72f, 14.50f, 88.81f }, [MZ2_WIDOW_BLASTER] = { 56, 32, 32 }, [MZ2_WIDOW_RAIL] = { 62, -20, 84 }, [MZ2_WIDOW_PLASMABEAM] = { 32, 0, 6 }, @@ -218,22 +236,22 @@ const vec3_t monster_flash_offset[MZ2_LAST] = { [MZ2_CARRIER_ROCKET_2] = { 0, 0, -5 }, [MZ2_CARRIER_ROCKET_3] = { 0, 0, -5 }, [MZ2_CARRIER_ROCKET_4] = { 0, 0, -5 }, - [MZ2_WIDOW2_BEAMER_1] = { 69, -17.63f, 93.77f }, - [MZ2_WIDOW2_BEAMER_2] = { 69, -17.08f, 89.82f }, - [MZ2_WIDOW2_BEAMER_3] = { 69, -18.4f, 90.7f }, - [MZ2_WIDOW2_BEAMER_4] = { 69, -18.34f, 94.32f }, - [MZ2_WIDOW2_BEAMER_5] = { 69, -18.3f, 97.98f }, + [MZ2_WIDOW2_BEAMER_1] = { 69.00f, -17.63f, 93.77f }, + [MZ2_WIDOW2_BEAMER_2] = { 69.00f, -17.08f, 89.82f }, + [MZ2_WIDOW2_BEAMER_3] = { 69.00f, -18.40f, 90.70f }, + [MZ2_WIDOW2_BEAMER_4] = { 69.00f, -18.34f, 94.32f }, + [MZ2_WIDOW2_BEAMER_5] = { 69.00f, -18.30f, 97.98f }, [MZ2_WIDOW2_BEAM_SWEEP_1] = { 45.04f, -59.02f, 92.24f }, - [MZ2_WIDOW2_BEAM_SWEEP_2] = { 50.68f, -54.7f, 91.96f }, + [MZ2_WIDOW2_BEAM_SWEEP_2] = { 50.68f, -54.70f, 91.96f }, [MZ2_WIDOW2_BEAM_SWEEP_3] = { 56.57f, -47.72f, 91.65f }, [MZ2_WIDOW2_BEAM_SWEEP_4] = { 61.75f, -38.75f, 91.38f }, [MZ2_WIDOW2_BEAM_SWEEP_5] = { 65.55f, -28.76f, 91.24f }, - [MZ2_WIDOW2_BEAM_SWEEP_6] = { 67.79f, -18.9f, 91.22f }, - [MZ2_WIDOW2_BEAM_SWEEP_7] = { 68.6f, -9.52f, 91.23f }, + [MZ2_WIDOW2_BEAM_SWEEP_6] = { 67.79f, -18.90f, 91.22f }, + [MZ2_WIDOW2_BEAM_SWEEP_7] = { 68.60f, -9.52f, 91.23f }, [MZ2_WIDOW2_BEAM_SWEEP_8] = { 68.08f, 0.18f, 91.32f }, [MZ2_WIDOW2_BEAM_SWEEP_9] = { 66.14f, 9.79f, 91.44f }, [MZ2_WIDOW2_BEAM_SWEEP_10] = { 62.77f, 18.91f, 91.65f }, - [MZ2_WIDOW2_BEAM_SWEEP_11] = { 58.29f, 27.11f, 92 }, + [MZ2_WIDOW2_BEAM_SWEEP_11] = { 58.29f, 27.11f, 92.00f }, [MZ2_SOLDIER_RIPPER_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, [MZ2_SOLDIER_RIPPER_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, diff --git a/src/shared/shared.c b/src/shared/shared.c index 07507af47..a0843d8f1 100644 --- a/src/shared/shared.c +++ b/src/shared/shared.c @@ -915,6 +915,7 @@ size_t Q_scnprintf(char *dest, size_t size, const char *fmt, ...) return ret; } +#ifndef HAVE_STRCHRNUL char *Q_strchrnul(const char *s, int c) { while (*s && *s != c) { @@ -922,7 +923,9 @@ char *Q_strchrnul(const char *s, int c) } return (char *)s; } +#endif +#ifndef HAVE_MEMCCPY /* =============== Q_memccpy @@ -944,12 +947,22 @@ void *Q_memccpy(void *dst, const void *src, int c, size_t size) return NULL; } +#endif +#ifndef HAVE_STRNLEN size_t Q_strnlen(const char *s, size_t maxlen) { char *p = memchr(s, 0, maxlen); return p ? p - s : maxlen; } +#endif + +#ifndef _WIN32 +int Q_atoi(const char *s) +{ + return Q_clipl_int32(strtol(s, NULL, 10)); +} +#endif /* ===================================================================== diff --git a/src/unix/meson.build b/src/unix/meson.build index d6e82d16a..924f9263a 100644 --- a/src/unix/meson.build +++ b/src/unix/meson.build @@ -29,3 +29,15 @@ if not config.has('USE_SDL') and not config.has('USE_X11') and not config.has('U warning('No video drivers enabled, client will not be built') client_deps += disabler() endif + +test_funcs = [ + 'memccpy', + 'strchrnul', + 'strnlen', +] + +foreach func: test_funcs + if cc.has_function(func, args: '-D_GNU_SOURCE', prefix: '#include ') + config.set('HAVE_' + func.to_upper(), true) + endif +endforeach diff --git a/src/unix/video/sdl.c b/src/unix/video/sdl.c index 6d780fe44..1be4b1d6c 100644 --- a/src/unix/video/sdl.c +++ b/src/unix/video/sdl.c @@ -233,7 +233,7 @@ static int get_dpi_scale(void) int scale_x = (sdl.width + sdl.win_width / 2) / sdl.win_width; int scale_y = (sdl.height + sdl.win_height / 2) / sdl.win_height; if (scale_x == scale_y) - return clamp(scale_x, 1, 10); + return Q_clip(scale_x, 1, 10); } return 1; diff --git a/src/unix/video/wayland.c b/src/unix/video/wayland.c index 5362cb590..a9f507d23 100644 --- a/src/unix/video/wayland.c +++ b/src/unix/video/wayland.c @@ -890,10 +890,8 @@ static void handle_relative_motion(void *data, struct zwp_relative_pointer_v1 *z wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { if (Key_GetDest() & KEY_MENU) { - wl.abs_mouse_x += dx; - wl.abs_mouse_y += dy; - clamp(wl.abs_mouse_x, 0, wl_fixed_from_int(wl.width * wl.scale_factor) - 1); - clamp(wl.abs_mouse_y, 0, wl_fixed_from_int(wl.height * wl.scale_factor) - 1); + wl.abs_mouse_x = Q_clip(wl.abs_mouse_x + dx, 0, wl_fixed_from_int(wl.width * wl.scale_factor) - 1); + wl.abs_mouse_y = Q_clip(wl.abs_mouse_y + dy, 0, wl_fixed_from_int(wl.height * wl.scale_factor) - 1); UI_MouseEvent(wl_fixed_to_int(wl.abs_mouse_x), wl_fixed_to_int(wl.abs_mouse_y)); } diff --git a/src/unix/video/x11.c b/src/unix/video/x11.c index cc853863c..1e1f3c2fc 100644 --- a/src/unix/video/x11.c +++ b/src/unix/video/x11.c @@ -302,7 +302,7 @@ static bool init(void) int scale_x = Q_rint(dpi_x / 96.0f); int scale_y = Q_rint(dpi_y / 96.0f); if (scale_x == scale_y) - x11.dpi_scale = clamp(scale_x, 1, 10); + x11.dpi_scale = Q_clip(scale_x, 1, 10); } XSizeHints hints = { diff --git a/src/windows/ac.c b/src/windows/ac.c index cd33508e5..9bac4c42e 100644 --- a/src/windows/ac.c +++ b/src/windows/ac.c @@ -36,7 +36,7 @@ bool Sys_GetAntiCheatAPI(void) if (anticheatInit) { anticheatApi = anticheatInit(); if (!anticheatApi) { - Com_LPrintf(PRINT_ERROR, "Anticheat failed to reinitialize!\n"); + Com_EPrintf("Anticheat failed to reinitialize!\n"); FreeLibrary(anticheatHandle); anticheatHandle = NULL; anticheatInit = NULL; @@ -48,15 +48,14 @@ bool Sys_GetAntiCheatAPI(void) reInit: anticheatHandle = LoadLibrary("anticheat"); if (!anticheatHandle) { - Com_LPrintf(PRINT_ERROR, "Anticheat failed to load.\n"); + Com_EPrintf("Anticheat failed to load.\n"); return false; } //this should never fail unless the anticheat.dll is bad anticheatInit = (FNINIT)GetProcAddress(anticheatHandle, "Initialize"); if (!anticheatInit) { - Com_LPrintf(PRINT_ERROR, - "Couldn't get API of anticheat.dll!\n" + Com_EPrintf("Couldn't get API of anticheat.dll!\n" "Please check you are using a valid " "anticheat.dll from http://antiche.at/"); FreeLibrary(anticheatHandle); @@ -77,7 +76,7 @@ bool Sys_GetAntiCheatAPI(void) goto reInit; } - Com_LPrintf(PRINT_ERROR, "Anticheat failed to initialize.\n"); + Com_EPrintf("Anticheat failed to initialize.\n"); return false; } diff --git a/src/windows/client.c b/src/windows/client.c index c68e1bc69..7cc023a0b 100644 --- a/src/windows/client.c +++ b/src/windows/client.c @@ -349,7 +349,7 @@ int Win_GetDpiScale(void) int dpi = win.GetDpiForWindow(win.wnd); if (dpi) { int scale = (dpi + USER_DEFAULT_SCREEN_DPI / 2) / USER_DEFAULT_SCREEN_DPI; - return clamp(scale, 1, 10); + return Q_clip(scale, 1, 10); } } return 1; @@ -621,7 +621,7 @@ static void mouse_wheel_event(int delta) if (Key_GetDest() & KEY_CONSOLE) { SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0); - clamp(lines, 1, 9); + lines = Q_clip(lines, 1, 9); } else { lines = 1; } diff --git a/src/windows/meson.build b/src/windows/meson.build index 6dbf65be1..624f0cdd4 100644 --- a/src/windows/meson.build +++ b/src/windows/meson.build @@ -1,7 +1,7 @@ windows = import('windows') common_src += files('system.c', 'hunk.c') -client_src += files('client.c', 'wgl.c', 'pthread.c') +client_src += files('client.c', 'wgl.c') common_deps += cc.find_library('ws2_32') client_deps += cc.find_library('opengl32') diff --git a/src/windows/pthread.c b/src/windows/pthread.c deleted file mode 100644 index 4e4b5a8cf..000000000 --- a/src/windows/pthread.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright (C) 2023 Andrey Nazarov - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "client.h" -#include "shared/list.h" -#include "system/pthread.h" -#include - -typedef struct { - list_t entry; - void *(*func)(void *); - void *arg, *ret; - HANDLE handle; - DWORD id; -} winthread_t; - -static LIST_DECL(threads); -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -static winthread_t *find_thread(pthread_t thread) -{ - winthread_t *t; - - LIST_FOR_EACH(winthread_t, t, &threads, entry) - if (t->id == thread) - return t; - - return NULL; -} - -static unsigned __stdcall thread_func(void *arg) -{ - winthread_t *t = arg; - t->ret = t->func(t->arg); - return 0; -} - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg) -{ - int ret = 0; - pthread_mutex_lock(&mutex); - winthread_t *t = malloc(sizeof(*t)); - if (!t) { - ret = EAGAIN; - goto done; - } - t->func = start_routine; - t->arg = arg; - t->handle = (HANDLE)_beginthreadex(NULL, 0, thread_func, t, 0, thread); - if (!t->handle) { - free(t); - ret = EAGAIN; - goto done; - } - t->id = *thread; - List_Append(&threads, &t->entry); -done: - pthread_mutex_unlock(&mutex); - return ret; -} - -int pthread_join(pthread_t thread, void **retval) -{ - int ret = 0; - pthread_mutex_lock(&mutex); - winthread_t *t = find_thread(thread); - if (!t) { - ret = ESRCH; - goto done; - } - WaitForSingleObject(t->handle, INFINITE); - CloseHandle(t->handle); - List_Remove(&t->entry); - if (retval) - *retval = t->ret; - free(t); -done: - pthread_mutex_unlock(&mutex); - return ret; -} diff --git a/subprojects/libcurl.wrap b/subprojects/libcurl.wrap index 879a511da..eedb518b3 100644 --- a/subprojects/libcurl.wrap +++ b/subprojects/libcurl.wrap @@ -1,11 +1,11 @@ [wrap-file] -directory = curl-8.4.0 -source_url = https://curl.se/download/curl-8.4.0.tar.xz -source_filename = curl-8.4.0.tar.xz -source_hash = 16c62a9c4af0f703d28bda6d7bbf37ba47055ad3414d70dec63e2e6336f2a82d -patch_url = https://skuller.net/meson/libcurl_8.4.0-1_patch.zip -patch_filename = libcurl_8.4.0-1_patch.zip -patch_hash = a4115c0e9ea51b25ec19461420b0b396350056c72bb6832aed4a339a62f11502 +directory = curl-8.6.0 +source_url = https://curl.se/download/curl-8.6.0.tar.xz +source_filename = curl-8.6.0.tar.xz +source_hash = 3ccd55d91af9516539df80625f818c734dc6f2ecf9bada33c76765e99121db15 +patch_url = https://skuller.net/meson/libcurl_8.6.0-1_patch.zip +patch_filename = libcurl_8.6.0-1_patch.zip +patch_hash = 0bfb2990a3db9b83ed359a62c68aa25a8007853b8872480d90a040fd3736761d [provide] libcurl = libcurl_dep diff --git a/subprojects/libjpeg-turbo.wrap b/subprojects/libjpeg-turbo.wrap index 024732366..77d491fc7 100644 --- a/subprojects/libjpeg-turbo.wrap +++ b/subprojects/libjpeg-turbo.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = libjpeg-turbo-2.1.5.1 -source_url = https://downloads.sourceforge.net/libjpeg-turbo/libjpeg-turbo-2.1.5.1.tar.gz -source_filename = libjpeg-turbo-2.1.5.1.tar.gz -source_hash = 2fdc3feb6e9deb17adec9bafa3321419aa19f8f4e5dea7bf8486844ca22207bf -patch_filename = libjpeg-turbo_2.1.5.1-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_2.1.5.1-1/get_patch -patch_hash = 7daf69a0795f0fe3aecf2d1bcde78266d7a60a36df8573fe3b442e0adcbb4ca0 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libjpeg-turbo_2.1.5.1-1/libjpeg-turbo-2.1.5.1.tar.gz -wrapdb_version = 2.1.5.1-1 +directory = libjpeg-turbo-3.0.2 +source_url = https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.2/libjpeg-turbo-3.0.2.tar.gz +source_filename = libjpeg-turbo-3.0.2.tar.gz +source_hash = c2ce515a78d91b09023773ef2770d6b0df77d674e144de80d63e0389b3a15ca6 +patch_filename = libjpeg-turbo_3.0.2-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_3.0.2-1/get_patch +patch_hash = 271788065332bcb52d504edc86466dc802a705c64b825e018ed927371ac53cf1 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libjpeg-turbo_3.0.2-1/libjpeg-turbo-3.0.2.tar.gz +wrapdb_version = 3.0.2-1 [provide] -dependency_names = libjpeg +dependency_names = libjpeg, libturbojpeg diff --git a/subprojects/libpng.wrap b/subprojects/libpng.wrap index 8ba5a95f0..7548f2e4d 100644 --- a/subprojects/libpng.wrap +++ b/subprojects/libpng.wrap @@ -1,11 +1,12 @@ [wrap-file] -directory = libpng-1.6.40 -source_url = https://downloads.sourceforge.net/libpng/libpng-1.6.40.tar.xz -source_filename = libpng-1.6.40.tar.xz -source_hash = 535b479b2467ff231a3ec6d92a525906fb8ef27978be4f66dbe05d3f3a01b3a1 -patch_url = https://skuller.net/meson/libpng_1.6.40-1_patch.zip -patch_filename = libpng_1.6.40-1_patch.zip -patch_hash = aeffbd55f18ec363354080f927ef19d52bb29ccc75cc1ed53e7cb916acf5f0ae +directory = libpng-1.6.42 +source_url = https://downloads.sourceforge.net/libpng/libpng-1.6.42.tar.xz +source_filename = libpng-1.6.42.tar.xz +source_hash = c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450 +patch_filename = libpng_1.6.42-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libpng_1.6.42-1/get_patch +patch_hash = b5c709da83556da3e970550d1b5bd2286f44da88db34be8215d17765bcbb356a +wrapdb_version = 1.6.42-1 [provide] libpng = libpng_dep diff --git a/subprojects/ogg.wrap b/subprojects/ogg.wrap deleted file mode 100644 index 120b7c4cd..000000000 --- a/subprojects/ogg.wrap +++ /dev/null @@ -1,12 +0,0 @@ -[wrap-file] -directory = libogg-1.3.5 -source_url = https://downloads.xiph.org/releases/ogg/libogg-1.3.5.tar.xz -source_filename = libogg-1.3.5.tar.xz -source_hash = c4d91be36fc8e54deae7575241e03f4211eb102afb3fc0775fbbc1b740016705 -patch_filename = ogg_1.3.5-5_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/ogg_1.3.5-5/get_patch -patch_hash = 16b9d2a2b1b0a6edcaedf6521de786ba3e08f7416fe818967f6d75a621ae8156 -wrapdb_version = 1.3.5-5 - -[provide] -ogg = libogg_dep diff --git a/subprojects/openal-soft.wrap b/subprojects/openal-soft.wrap index 8292a54cd..89aefc3d9 100644 --- a/subprojects/openal-soft.wrap +++ b/subprojects/openal-soft.wrap @@ -1,6 +1,6 @@ [wrap-file] directory = openal-soft-1.22.2 -source_url = https://openal-soft.org/openal-releases/openal-soft-1.22.2.tar.bz2 +source_url = https://github.com/kcat/openal-soft/releases/download/1.22.2/openal-soft-1.22.2.tar.bz2 source_filename = openal-soft-1.22.2.tar.bz2 source_hash = ae94cc95cda76b7cc6e92e38c2531af82148e76d3d88ce996e2928a1ea7c3d20 patch_url = https://skuller.net/meson/openal-soft_1.22.2-1_patch.zip diff --git a/subprojects/vorbis.wrap b/subprojects/vorbis.wrap deleted file mode 100644 index 7425c11ec..000000000 --- a/subprojects/vorbis.wrap +++ /dev/null @@ -1,14 +0,0 @@ -[wrap-file] -directory = libvorbis-1.3.7 -source_url = https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz -source_filename = libvorbis-1.3.7.tar.xz -source_hash = b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b -patch_filename = vorbis_1.3.7-4_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/vorbis_1.3.7-4/get_patch -patch_hash = 979e22b24b16c927040700dfd8319cd6ba29bf52a14dbc66b1cb4ea60504f14a -wrapdb_version = 1.3.7-4 - -[provide] -vorbis = vorbis_dep -vorbisfile = vorbisfile_dep -vorbisenc = vorbisenc_dep diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap index 589cb26b0..851fe2b4d 100644 --- a/subprojects/zlib.wrap +++ b/subprojects/zlib.wrap @@ -1,12 +1,12 @@ [wrap-file] -directory = zlib-1.3 -source_url = https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.xz -source_filename = zlib-1.3.tar.xz -source_hash = 8a9ba2898e1d0d774eca6ba5b4627a11e5588ba85c8851336eb38de4683050a7 -patch_filename = zlib_1.3-3_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3-3/get_patch -patch_hash = dcb86003e945761dc47aed34b6179003c5e68ddbca4cf71ebc5875ae57b76b8e -wrapdb_version = 1.3-3 +directory = zlib-1.3.1 +source_url = https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.xz +source_filename = zlib-1.3.1.tar.xz +source_hash = 38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32 +patch_filename = zlib_1.3.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3.1-1/get_patch +patch_hash = e79b98eb24a75392009cec6f99ca5cdca9881ff20bfa174e8b8926d5c7a47095 +wrapdb_version = 1.3.1-1 [provide] zlib = zlib_dep