mirror of
https://github.com/jndean/IPUDOOM.git
synced 2026-03-21 15:09:45 +00:00
Stripped down init versin of CPU Doom, specifically microdoom by atroche
This commit is contained in:
22
Makefile
Normal file
22
Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
CPU_OBJ = $(addprefix build/obj/, i_system.o d_mode.o i_main.o i_timer.o m_argv.o m_misc.o net_common.o net_dedicated.o net_io.o net_packet.o net_query.o net_sdl.o net_server.o net_structrw.o aes_prng.o d_event.o d_iwad.o d_loop.o d_mode.o gusconf.o i_cdmus.o i_input.o i_joystick.o i_sdlmusic.o i_sdlsound.o i_sound.o i_timer.o i_video.o i_videohr.o midifile.o mus2mid.o m_bbox.o m_cheat.o m_config.o m_controls.o m_fixed.o net_client.o sha1.o memio.o tables.o v_video.o w_checksum.o w_main.o w_wad.o w_file.o w_file_stdc.o w_file_posix.o w_merge.o z_zone.o net_loop.o am_map.o d_items.o d_main.o d_net.o doomdef.o doomstat.o dstrings.o f_wipe.o g_game.o hu_lib.o hu_stuff.o info.o m_menu.o m_random.o p_ceilng.o p_doors.o p_enemy.o p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o s_sound.o sounds.o st_lib.o st_stuff.o statdump.o wi_stuff.o)
|
||||
|
||||
CFLAGS = -I /usr/local/include/SDL2 -I/usr/include/libpng16 -I src \
|
||||
-D_REENTRANT -lSDL2 -lSDL2_mixer -lSDL2_net -lpng16 -lz \
|
||||
-Wall -Werror \
|
||||
-O2
|
||||
|
||||
all: build build/doom
|
||||
|
||||
build/doom: $(CPU_OBJ)
|
||||
gcc $^ $(CFLAGS) -o build/doom
|
||||
|
||||
build/obj/%.o: src/%.c
|
||||
gcc $(CFLAGS) $^ -c -o $@
|
||||
|
||||
build:
|
||||
mkdir -p build/obj
|
||||
|
||||
clean:
|
||||
rm -r build/
|
||||
956
src/aes_prng.c
Normal file
956
src/aes_prng.c
Normal file
@@ -0,0 +1,956 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// This implements a cryptographically secure pseudorandom number
|
||||
// generator for implementing secure demos. The approach taken is to
|
||||
// use the AES (Rijndael) stream cipher in "counter" mode, encrypting
|
||||
// an incrementing counter. The cipher key acts as the random seed.
|
||||
// Cryptanalysis of AES used in this way has shown it to be an
|
||||
// effective PRNG (see: Empirical Evidence concerning AES, Hellekalek
|
||||
// & Wegenkittl, 2003).
|
||||
//
|
||||
// AES implementation is taken from the Linux kernel's AES
|
||||
// implementation, found in crypto/aes_generic.c. It has been hacked
|
||||
// up to work independently.
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "SDL2/SDL_endian.h"
|
||||
#include "aes_prng.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
/*
|
||||
* Cryptographic API.
|
||||
*
|
||||
* AES Cipher Algorithm.
|
||||
*
|
||||
* Based on Brian Gladman's code.
|
||||
*
|
||||
* Linux developers:
|
||||
* Alexander Kjeldaas <astor@fast.no>
|
||||
* Herbert Valerio Riedel <hvr@hvrlab.org>
|
||||
* Kyle McMartin <kyle@debian.org>
|
||||
* Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
* Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
|
||||
* All rights reserved.
|
||||
*
|
||||
* LICENSE TERMS
|
||||
*
|
||||
* The free distribution and use of this software in both source and binary
|
||||
* form is allowed (with or without changes) provided that:
|
||||
*
|
||||
* 1. distributions of this source code include the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
*
|
||||
* 2. distributions in binary form include the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other associated materials;
|
||||
*
|
||||
* 3. the copyright holder's name is not used to endorse products
|
||||
* built using this software without specific written permission.
|
||||
*
|
||||
* ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
* may be distributed under the terms of the GNU General Public License (GPL),
|
||||
* in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* This software is provided 'as is' with no explicit or implied warranties
|
||||
* in respect of its properties, including, but not limited to, correctness
|
||||
* and/or fitness for purpose.
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AES_MIN_KEY_SIZE 16
|
||||
#define AES_MAX_KEY_SIZE 32
|
||||
#define AES_KEYSIZE_128 16
|
||||
#define AES_KEYSIZE_192 24
|
||||
#define AES_KEYSIZE_256 32
|
||||
#define AES_BLOCK_SIZE 16
|
||||
#define AES_MAX_KEYLENGTH (15 * 16)
|
||||
#define AES_MAX_KEYLENGTH_U32 (AES_MAX_KEYLENGTH / sizeof(uint32_t))
|
||||
|
||||
/*
|
||||
* Please ensure that the first two fields are 16-byte aligned
|
||||
* relative to the start of the structure, i.e., don't move them!
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t key_enc[AES_MAX_KEYLENGTH_U32];
|
||||
uint32_t key_dec[AES_MAX_KEYLENGTH_U32];
|
||||
uint32_t key_length;
|
||||
} aes_context_t;
|
||||
|
||||
static inline uint8_t get_byte(const uint32_t x, const unsigned n)
|
||||
{
|
||||
return x >> (n << 3);
|
||||
}
|
||||
|
||||
static const uint32_t rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
|
||||
|
||||
static const uint32_t crypto_ft_tab[4][256] = {
|
||||
{
|
||||
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
|
||||
0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
|
||||
0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
|
||||
0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
|
||||
0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
|
||||
0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
|
||||
0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
|
||||
0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
|
||||
0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
|
||||
0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
|
||||
0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
|
||||
0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
|
||||
0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
|
||||
0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
|
||||
0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
|
||||
0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
|
||||
0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
|
||||
0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
|
||||
0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
|
||||
0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
|
||||
0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
|
||||
0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
|
||||
0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
|
||||
0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
|
||||
0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
|
||||
0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
|
||||
0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
|
||||
0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
|
||||
0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
|
||||
0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
|
||||
0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
|
||||
0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
|
||||
0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
|
||||
0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
|
||||
0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
|
||||
0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
|
||||
0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
|
||||
0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
|
||||
0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
|
||||
0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
|
||||
0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
|
||||
0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
|
||||
0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
|
||||
0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
|
||||
0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
|
||||
0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
|
||||
0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
|
||||
0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
|
||||
0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
|
||||
0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
|
||||
0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
|
||||
0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
|
||||
0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
|
||||
0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
|
||||
0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
|
||||
0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
|
||||
0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
|
||||
0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
|
||||
0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
|
||||
0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
|
||||
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
|
||||
0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
|
||||
0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
|
||||
0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c,
|
||||
}, {
|
||||
0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d,
|
||||
0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
|
||||
0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
|
||||
0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
|
||||
0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
|
||||
0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
|
||||
0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea,
|
||||
0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
|
||||
0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
|
||||
0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
|
||||
0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908,
|
||||
0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
|
||||
0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e,
|
||||
0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
|
||||
0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
|
||||
0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
|
||||
0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e,
|
||||
0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
|
||||
0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce,
|
||||
0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
|
||||
0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
|
||||
0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
|
||||
0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b,
|
||||
0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
|
||||
0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
|
||||
0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
|
||||
0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
|
||||
0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
|
||||
0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a,
|
||||
0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
|
||||
0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263,
|
||||
0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
|
||||
0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
|
||||
0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
|
||||
0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
|
||||
0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
|
||||
0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f,
|
||||
0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
|
||||
0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
|
||||
0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
|
||||
0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e,
|
||||
0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
|
||||
0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6,
|
||||
0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
|
||||
0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
|
||||
0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
|
||||
0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25,
|
||||
0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
|
||||
0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72,
|
||||
0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
|
||||
0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
|
||||
0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
|
||||
0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa,
|
||||
0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
|
||||
0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
|
||||
0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
|
||||
0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
|
||||
0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
|
||||
0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920,
|
||||
0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
|
||||
0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17,
|
||||
0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
|
||||
0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
|
||||
0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a,
|
||||
}, {
|
||||
0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b,
|
||||
0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
|
||||
0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
|
||||
0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
|
||||
0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
|
||||
0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
|
||||
0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf,
|
||||
0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
|
||||
0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
|
||||
0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
|
||||
0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1,
|
||||
0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
|
||||
0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3,
|
||||
0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
|
||||
0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
|
||||
0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
|
||||
0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a,
|
||||
0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
|
||||
0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3,
|
||||
0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
|
||||
0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
|
||||
0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
|
||||
0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39,
|
||||
0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
|
||||
0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
|
||||
0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
|
||||
0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
|
||||
0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
|
||||
0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f,
|
||||
0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
|
||||
0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321,
|
||||
0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
|
||||
0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
|
||||
0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
|
||||
0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
|
||||
0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
|
||||
0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc,
|
||||
0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
|
||||
0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
|
||||
0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
|
||||
0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a,
|
||||
0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
|
||||
0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662,
|
||||
0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
|
||||
0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
|
||||
0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
|
||||
0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea,
|
||||
0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
|
||||
0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e,
|
||||
0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
|
||||
0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
|
||||
0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
|
||||
0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66,
|
||||
0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
|
||||
0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
|
||||
0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
|
||||
0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
|
||||
0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
|
||||
0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9,
|
||||
0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
|
||||
0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d,
|
||||
0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
|
||||
0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
|
||||
0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16,
|
||||
}, {
|
||||
0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b,
|
||||
0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
|
||||
0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
|
||||
0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
|
||||
0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
|
||||
0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
|
||||
0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf,
|
||||
0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
|
||||
0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
|
||||
0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
|
||||
0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1,
|
||||
0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
|
||||
0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3,
|
||||
0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
|
||||
0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
|
||||
0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
|
||||
0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a,
|
||||
0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
|
||||
0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3,
|
||||
0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
|
||||
0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
|
||||
0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
|
||||
0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939,
|
||||
0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
|
||||
0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
|
||||
0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
|
||||
0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
|
||||
0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
|
||||
0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f,
|
||||
0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
|
||||
0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121,
|
||||
0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
|
||||
0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
|
||||
0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
|
||||
0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
|
||||
0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
|
||||
0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc,
|
||||
0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
|
||||
0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
|
||||
0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
|
||||
0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a,
|
||||
0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
|
||||
0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262,
|
||||
0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
|
||||
0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
|
||||
0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
|
||||
0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea,
|
||||
0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
|
||||
0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e,
|
||||
0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
|
||||
0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
|
||||
0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
|
||||
0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666,
|
||||
0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
|
||||
0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
|
||||
0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
|
||||
0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
|
||||
0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
|
||||
0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9,
|
||||
0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
|
||||
0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d,
|
||||
0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
|
||||
0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
|
||||
0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616,
|
||||
}
|
||||
};
|
||||
|
||||
static const uint32_t crypto_fl_tab[4][256] = {
|
||||
{
|
||||
0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
|
||||
0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
|
||||
0x00000030, 0x00000001, 0x00000067, 0x0000002b,
|
||||
0x000000fe, 0x000000d7, 0x000000ab, 0x00000076,
|
||||
0x000000ca, 0x00000082, 0x000000c9, 0x0000007d,
|
||||
0x000000fa, 0x00000059, 0x00000047, 0x000000f0,
|
||||
0x000000ad, 0x000000d4, 0x000000a2, 0x000000af,
|
||||
0x0000009c, 0x000000a4, 0x00000072, 0x000000c0,
|
||||
0x000000b7, 0x000000fd, 0x00000093, 0x00000026,
|
||||
0x00000036, 0x0000003f, 0x000000f7, 0x000000cc,
|
||||
0x00000034, 0x000000a5, 0x000000e5, 0x000000f1,
|
||||
0x00000071, 0x000000d8, 0x00000031, 0x00000015,
|
||||
0x00000004, 0x000000c7, 0x00000023, 0x000000c3,
|
||||
0x00000018, 0x00000096, 0x00000005, 0x0000009a,
|
||||
0x00000007, 0x00000012, 0x00000080, 0x000000e2,
|
||||
0x000000eb, 0x00000027, 0x000000b2, 0x00000075,
|
||||
0x00000009, 0x00000083, 0x0000002c, 0x0000001a,
|
||||
0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0,
|
||||
0x00000052, 0x0000003b, 0x000000d6, 0x000000b3,
|
||||
0x00000029, 0x000000e3, 0x0000002f, 0x00000084,
|
||||
0x00000053, 0x000000d1, 0x00000000, 0x000000ed,
|
||||
0x00000020, 0x000000fc, 0x000000b1, 0x0000005b,
|
||||
0x0000006a, 0x000000cb, 0x000000be, 0x00000039,
|
||||
0x0000004a, 0x0000004c, 0x00000058, 0x000000cf,
|
||||
0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb,
|
||||
0x00000043, 0x0000004d, 0x00000033, 0x00000085,
|
||||
0x00000045, 0x000000f9, 0x00000002, 0x0000007f,
|
||||
0x00000050, 0x0000003c, 0x0000009f, 0x000000a8,
|
||||
0x00000051, 0x000000a3, 0x00000040, 0x0000008f,
|
||||
0x00000092, 0x0000009d, 0x00000038, 0x000000f5,
|
||||
0x000000bc, 0x000000b6, 0x000000da, 0x00000021,
|
||||
0x00000010, 0x000000ff, 0x000000f3, 0x000000d2,
|
||||
0x000000cd, 0x0000000c, 0x00000013, 0x000000ec,
|
||||
0x0000005f, 0x00000097, 0x00000044, 0x00000017,
|
||||
0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d,
|
||||
0x00000064, 0x0000005d, 0x00000019, 0x00000073,
|
||||
0x00000060, 0x00000081, 0x0000004f, 0x000000dc,
|
||||
0x00000022, 0x0000002a, 0x00000090, 0x00000088,
|
||||
0x00000046, 0x000000ee, 0x000000b8, 0x00000014,
|
||||
0x000000de, 0x0000005e, 0x0000000b, 0x000000db,
|
||||
0x000000e0, 0x00000032, 0x0000003a, 0x0000000a,
|
||||
0x00000049, 0x00000006, 0x00000024, 0x0000005c,
|
||||
0x000000c2, 0x000000d3, 0x000000ac, 0x00000062,
|
||||
0x00000091, 0x00000095, 0x000000e4, 0x00000079,
|
||||
0x000000e7, 0x000000c8, 0x00000037, 0x0000006d,
|
||||
0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9,
|
||||
0x0000006c, 0x00000056, 0x000000f4, 0x000000ea,
|
||||
0x00000065, 0x0000007a, 0x000000ae, 0x00000008,
|
||||
0x000000ba, 0x00000078, 0x00000025, 0x0000002e,
|
||||
0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6,
|
||||
0x000000e8, 0x000000dd, 0x00000074, 0x0000001f,
|
||||
0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a,
|
||||
0x00000070, 0x0000003e, 0x000000b5, 0x00000066,
|
||||
0x00000048, 0x00000003, 0x000000f6, 0x0000000e,
|
||||
0x00000061, 0x00000035, 0x00000057, 0x000000b9,
|
||||
0x00000086, 0x000000c1, 0x0000001d, 0x0000009e,
|
||||
0x000000e1, 0x000000f8, 0x00000098, 0x00000011,
|
||||
0x00000069, 0x000000d9, 0x0000008e, 0x00000094,
|
||||
0x0000009b, 0x0000001e, 0x00000087, 0x000000e9,
|
||||
0x000000ce, 0x00000055, 0x00000028, 0x000000df,
|
||||
0x0000008c, 0x000000a1, 0x00000089, 0x0000000d,
|
||||
0x000000bf, 0x000000e6, 0x00000042, 0x00000068,
|
||||
0x00000041, 0x00000099, 0x0000002d, 0x0000000f,
|
||||
0x000000b0, 0x00000054, 0x000000bb, 0x00000016,
|
||||
}, {
|
||||
0x00006300, 0x00007c00, 0x00007700, 0x00007b00,
|
||||
0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500,
|
||||
0x00003000, 0x00000100, 0x00006700, 0x00002b00,
|
||||
0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600,
|
||||
0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00,
|
||||
0x0000fa00, 0x00005900, 0x00004700, 0x0000f000,
|
||||
0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00,
|
||||
0x00009c00, 0x0000a400, 0x00007200, 0x0000c000,
|
||||
0x0000b700, 0x0000fd00, 0x00009300, 0x00002600,
|
||||
0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00,
|
||||
0x00003400, 0x0000a500, 0x0000e500, 0x0000f100,
|
||||
0x00007100, 0x0000d800, 0x00003100, 0x00001500,
|
||||
0x00000400, 0x0000c700, 0x00002300, 0x0000c300,
|
||||
0x00001800, 0x00009600, 0x00000500, 0x00009a00,
|
||||
0x00000700, 0x00001200, 0x00008000, 0x0000e200,
|
||||
0x0000eb00, 0x00002700, 0x0000b200, 0x00007500,
|
||||
0x00000900, 0x00008300, 0x00002c00, 0x00001a00,
|
||||
0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000,
|
||||
0x00005200, 0x00003b00, 0x0000d600, 0x0000b300,
|
||||
0x00002900, 0x0000e300, 0x00002f00, 0x00008400,
|
||||
0x00005300, 0x0000d100, 0x00000000, 0x0000ed00,
|
||||
0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00,
|
||||
0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900,
|
||||
0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00,
|
||||
0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00,
|
||||
0x00004300, 0x00004d00, 0x00003300, 0x00008500,
|
||||
0x00004500, 0x0000f900, 0x00000200, 0x00007f00,
|
||||
0x00005000, 0x00003c00, 0x00009f00, 0x0000a800,
|
||||
0x00005100, 0x0000a300, 0x00004000, 0x00008f00,
|
||||
0x00009200, 0x00009d00, 0x00003800, 0x0000f500,
|
||||
0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100,
|
||||
0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200,
|
||||
0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00,
|
||||
0x00005f00, 0x00009700, 0x00004400, 0x00001700,
|
||||
0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00,
|
||||
0x00006400, 0x00005d00, 0x00001900, 0x00007300,
|
||||
0x00006000, 0x00008100, 0x00004f00, 0x0000dc00,
|
||||
0x00002200, 0x00002a00, 0x00009000, 0x00008800,
|
||||
0x00004600, 0x0000ee00, 0x0000b800, 0x00001400,
|
||||
0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00,
|
||||
0x0000e000, 0x00003200, 0x00003a00, 0x00000a00,
|
||||
0x00004900, 0x00000600, 0x00002400, 0x00005c00,
|
||||
0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200,
|
||||
0x00009100, 0x00009500, 0x0000e400, 0x00007900,
|
||||
0x0000e700, 0x0000c800, 0x00003700, 0x00006d00,
|
||||
0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900,
|
||||
0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00,
|
||||
0x00006500, 0x00007a00, 0x0000ae00, 0x00000800,
|
||||
0x0000ba00, 0x00007800, 0x00002500, 0x00002e00,
|
||||
0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600,
|
||||
0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00,
|
||||
0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00,
|
||||
0x00007000, 0x00003e00, 0x0000b500, 0x00006600,
|
||||
0x00004800, 0x00000300, 0x0000f600, 0x00000e00,
|
||||
0x00006100, 0x00003500, 0x00005700, 0x0000b900,
|
||||
0x00008600, 0x0000c100, 0x00001d00, 0x00009e00,
|
||||
0x0000e100, 0x0000f800, 0x00009800, 0x00001100,
|
||||
0x00006900, 0x0000d900, 0x00008e00, 0x00009400,
|
||||
0x00009b00, 0x00001e00, 0x00008700, 0x0000e900,
|
||||
0x0000ce00, 0x00005500, 0x00002800, 0x0000df00,
|
||||
0x00008c00, 0x0000a100, 0x00008900, 0x00000d00,
|
||||
0x0000bf00, 0x0000e600, 0x00004200, 0x00006800,
|
||||
0x00004100, 0x00009900, 0x00002d00, 0x00000f00,
|
||||
0x0000b000, 0x00005400, 0x0000bb00, 0x00001600,
|
||||
}, {
|
||||
0x00630000, 0x007c0000, 0x00770000, 0x007b0000,
|
||||
0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000,
|
||||
0x00300000, 0x00010000, 0x00670000, 0x002b0000,
|
||||
0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000,
|
||||
0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000,
|
||||
0x00fa0000, 0x00590000, 0x00470000, 0x00f00000,
|
||||
0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000,
|
||||
0x009c0000, 0x00a40000, 0x00720000, 0x00c00000,
|
||||
0x00b70000, 0x00fd0000, 0x00930000, 0x00260000,
|
||||
0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000,
|
||||
0x00340000, 0x00a50000, 0x00e50000, 0x00f10000,
|
||||
0x00710000, 0x00d80000, 0x00310000, 0x00150000,
|
||||
0x00040000, 0x00c70000, 0x00230000, 0x00c30000,
|
||||
0x00180000, 0x00960000, 0x00050000, 0x009a0000,
|
||||
0x00070000, 0x00120000, 0x00800000, 0x00e20000,
|
||||
0x00eb0000, 0x00270000, 0x00b20000, 0x00750000,
|
||||
0x00090000, 0x00830000, 0x002c0000, 0x001a0000,
|
||||
0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000,
|
||||
0x00520000, 0x003b0000, 0x00d60000, 0x00b30000,
|
||||
0x00290000, 0x00e30000, 0x002f0000, 0x00840000,
|
||||
0x00530000, 0x00d10000, 0x00000000, 0x00ed0000,
|
||||
0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000,
|
||||
0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000,
|
||||
0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000,
|
||||
0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000,
|
||||
0x00430000, 0x004d0000, 0x00330000, 0x00850000,
|
||||
0x00450000, 0x00f90000, 0x00020000, 0x007f0000,
|
||||
0x00500000, 0x003c0000, 0x009f0000, 0x00a80000,
|
||||
0x00510000, 0x00a30000, 0x00400000, 0x008f0000,
|
||||
0x00920000, 0x009d0000, 0x00380000, 0x00f50000,
|
||||
0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000,
|
||||
0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000,
|
||||
0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000,
|
||||
0x005f0000, 0x00970000, 0x00440000, 0x00170000,
|
||||
0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000,
|
||||
0x00640000, 0x005d0000, 0x00190000, 0x00730000,
|
||||
0x00600000, 0x00810000, 0x004f0000, 0x00dc0000,
|
||||
0x00220000, 0x002a0000, 0x00900000, 0x00880000,
|
||||
0x00460000, 0x00ee0000, 0x00b80000, 0x00140000,
|
||||
0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000,
|
||||
0x00e00000, 0x00320000, 0x003a0000, 0x000a0000,
|
||||
0x00490000, 0x00060000, 0x00240000, 0x005c0000,
|
||||
0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000,
|
||||
0x00910000, 0x00950000, 0x00e40000, 0x00790000,
|
||||
0x00e70000, 0x00c80000, 0x00370000, 0x006d0000,
|
||||
0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000,
|
||||
0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000,
|
||||
0x00650000, 0x007a0000, 0x00ae0000, 0x00080000,
|
||||
0x00ba0000, 0x00780000, 0x00250000, 0x002e0000,
|
||||
0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000,
|
||||
0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000,
|
||||
0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000,
|
||||
0x00700000, 0x003e0000, 0x00b50000, 0x00660000,
|
||||
0x00480000, 0x00030000, 0x00f60000, 0x000e0000,
|
||||
0x00610000, 0x00350000, 0x00570000, 0x00b90000,
|
||||
0x00860000, 0x00c10000, 0x001d0000, 0x009e0000,
|
||||
0x00e10000, 0x00f80000, 0x00980000, 0x00110000,
|
||||
0x00690000, 0x00d90000, 0x008e0000, 0x00940000,
|
||||
0x009b0000, 0x001e0000, 0x00870000, 0x00e90000,
|
||||
0x00ce0000, 0x00550000, 0x00280000, 0x00df0000,
|
||||
0x008c0000, 0x00a10000, 0x00890000, 0x000d0000,
|
||||
0x00bf0000, 0x00e60000, 0x00420000, 0x00680000,
|
||||
0x00410000, 0x00990000, 0x002d0000, 0x000f0000,
|
||||
0x00b00000, 0x00540000, 0x00bb0000, 0x00160000,
|
||||
}, {
|
||||
0x63000000, 0x7c000000, 0x77000000, 0x7b000000,
|
||||
0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000,
|
||||
0x30000000, 0x01000000, 0x67000000, 0x2b000000,
|
||||
0xfe000000, 0xd7000000, 0xab000000, 0x76000000,
|
||||
0xca000000, 0x82000000, 0xc9000000, 0x7d000000,
|
||||
0xfa000000, 0x59000000, 0x47000000, 0xf0000000,
|
||||
0xad000000, 0xd4000000, 0xa2000000, 0xaf000000,
|
||||
0x9c000000, 0xa4000000, 0x72000000, 0xc0000000,
|
||||
0xb7000000, 0xfd000000, 0x93000000, 0x26000000,
|
||||
0x36000000, 0x3f000000, 0xf7000000, 0xcc000000,
|
||||
0x34000000, 0xa5000000, 0xe5000000, 0xf1000000,
|
||||
0x71000000, 0xd8000000, 0x31000000, 0x15000000,
|
||||
0x04000000, 0xc7000000, 0x23000000, 0xc3000000,
|
||||
0x18000000, 0x96000000, 0x05000000, 0x9a000000,
|
||||
0x07000000, 0x12000000, 0x80000000, 0xe2000000,
|
||||
0xeb000000, 0x27000000, 0xb2000000, 0x75000000,
|
||||
0x09000000, 0x83000000, 0x2c000000, 0x1a000000,
|
||||
0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000,
|
||||
0x52000000, 0x3b000000, 0xd6000000, 0xb3000000,
|
||||
0x29000000, 0xe3000000, 0x2f000000, 0x84000000,
|
||||
0x53000000, 0xd1000000, 0x00000000, 0xed000000,
|
||||
0x20000000, 0xfc000000, 0xb1000000, 0x5b000000,
|
||||
0x6a000000, 0xcb000000, 0xbe000000, 0x39000000,
|
||||
0x4a000000, 0x4c000000, 0x58000000, 0xcf000000,
|
||||
0xd0000000, 0xef000000, 0xaa000000, 0xfb000000,
|
||||
0x43000000, 0x4d000000, 0x33000000, 0x85000000,
|
||||
0x45000000, 0xf9000000, 0x02000000, 0x7f000000,
|
||||
0x50000000, 0x3c000000, 0x9f000000, 0xa8000000,
|
||||
0x51000000, 0xa3000000, 0x40000000, 0x8f000000,
|
||||
0x92000000, 0x9d000000, 0x38000000, 0xf5000000,
|
||||
0xbc000000, 0xb6000000, 0xda000000, 0x21000000,
|
||||
0x10000000, 0xff000000, 0xf3000000, 0xd2000000,
|
||||
0xcd000000, 0x0c000000, 0x13000000, 0xec000000,
|
||||
0x5f000000, 0x97000000, 0x44000000, 0x17000000,
|
||||
0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000,
|
||||
0x64000000, 0x5d000000, 0x19000000, 0x73000000,
|
||||
0x60000000, 0x81000000, 0x4f000000, 0xdc000000,
|
||||
0x22000000, 0x2a000000, 0x90000000, 0x88000000,
|
||||
0x46000000, 0xee000000, 0xb8000000, 0x14000000,
|
||||
0xde000000, 0x5e000000, 0x0b000000, 0xdb000000,
|
||||
0xe0000000, 0x32000000, 0x3a000000, 0x0a000000,
|
||||
0x49000000, 0x06000000, 0x24000000, 0x5c000000,
|
||||
0xc2000000, 0xd3000000, 0xac000000, 0x62000000,
|
||||
0x91000000, 0x95000000, 0xe4000000, 0x79000000,
|
||||
0xe7000000, 0xc8000000, 0x37000000, 0x6d000000,
|
||||
0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000,
|
||||
0x6c000000, 0x56000000, 0xf4000000, 0xea000000,
|
||||
0x65000000, 0x7a000000, 0xae000000, 0x08000000,
|
||||
0xba000000, 0x78000000, 0x25000000, 0x2e000000,
|
||||
0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000,
|
||||
0xe8000000, 0xdd000000, 0x74000000, 0x1f000000,
|
||||
0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000,
|
||||
0x70000000, 0x3e000000, 0xb5000000, 0x66000000,
|
||||
0x48000000, 0x03000000, 0xf6000000, 0x0e000000,
|
||||
0x61000000, 0x35000000, 0x57000000, 0xb9000000,
|
||||
0x86000000, 0xc1000000, 0x1d000000, 0x9e000000,
|
||||
0xe1000000, 0xf8000000, 0x98000000, 0x11000000,
|
||||
0x69000000, 0xd9000000, 0x8e000000, 0x94000000,
|
||||
0x9b000000, 0x1e000000, 0x87000000, 0xe9000000,
|
||||
0xce000000, 0x55000000, 0x28000000, 0xdf000000,
|
||||
0x8c000000, 0xa1000000, 0x89000000, 0x0d000000,
|
||||
0xbf000000, 0xe6000000, 0x42000000, 0x68000000,
|
||||
0x41000000, 0x99000000, 0x2d000000, 0x0f000000,
|
||||
0xb0000000, 0x54000000, 0xbb000000, 0x16000000,
|
||||
}
|
||||
};
|
||||
|
||||
/* initialise the key schedule from the user supplied key */
|
||||
|
||||
static uint32_t aes_ror32(uint32_t word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (32 - shift));
|
||||
}
|
||||
|
||||
#define cpu_to_le32(x) SDL_SwapLE32(x)
|
||||
#define le32_to_cpu(x) SDL_SwapLE32(x)
|
||||
|
||||
#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
|
||||
|
||||
#define imix_col(y, x) do { \
|
||||
u = star_x(x); \
|
||||
v = star_x(u); \
|
||||
w = star_x(v); \
|
||||
t = w ^ (x); \
|
||||
(y) = u ^ v ^ w; \
|
||||
(y) ^= aes_ror32(u ^ t, 8) ^ \
|
||||
aes_ror32(v ^ t, 16) ^ \
|
||||
aes_ror32(t, 24); \
|
||||
} while (0)
|
||||
|
||||
#define ls_box(x) \
|
||||
crypto_fl_tab[0][get_byte(x, 0)] ^ \
|
||||
crypto_fl_tab[1][get_byte(x, 1)] ^ \
|
||||
crypto_fl_tab[2][get_byte(x, 2)] ^ \
|
||||
crypto_fl_tab[3][get_byte(x, 3)]
|
||||
|
||||
#define loop4(i) do { \
|
||||
t = aes_ror32(t, 8); \
|
||||
t = ls_box(t) ^ rco_tab[i]; \
|
||||
t ^= ctx->key_enc[4 * i]; \
|
||||
ctx->key_enc[4 * i + 4] = t; \
|
||||
t ^= ctx->key_enc[4 * i + 1]; \
|
||||
ctx->key_enc[4 * i + 5] = t; \
|
||||
t ^= ctx->key_enc[4 * i + 2]; \
|
||||
ctx->key_enc[4 * i + 6] = t; \
|
||||
t ^= ctx->key_enc[4 * i + 3]; \
|
||||
ctx->key_enc[4 * i + 7] = t; \
|
||||
} while (0)
|
||||
|
||||
#define loop6(i) do { \
|
||||
t = aes_ror32(t, 8); \
|
||||
t = ls_box(t) ^ rco_tab[i]; \
|
||||
t ^= ctx->key_enc[6 * i]; \
|
||||
ctx->key_enc[6 * i + 6] = t; \
|
||||
t ^= ctx->key_enc[6 * i + 1]; \
|
||||
ctx->key_enc[6 * i + 7] = t; \
|
||||
t ^= ctx->key_enc[6 * i + 2]; \
|
||||
ctx->key_enc[6 * i + 8] = t; \
|
||||
t ^= ctx->key_enc[6 * i + 3]; \
|
||||
ctx->key_enc[6 * i + 9] = t; \
|
||||
t ^= ctx->key_enc[6 * i + 4]; \
|
||||
ctx->key_enc[6 * i + 10] = t; \
|
||||
t ^= ctx->key_enc[6 * i + 5]; \
|
||||
ctx->key_enc[6 * i + 11] = t; \
|
||||
} while (0)
|
||||
|
||||
#define loop8tophalf(i) do { \
|
||||
t = aes_ror32(t, 8); \
|
||||
t = ls_box(t) ^ rco_tab[i]; \
|
||||
t ^= ctx->key_enc[8 * i]; \
|
||||
ctx->key_enc[8 * i + 8] = t; \
|
||||
t ^= ctx->key_enc[8 * i + 1]; \
|
||||
ctx->key_enc[8 * i + 9] = t; \
|
||||
t ^= ctx->key_enc[8 * i + 2]; \
|
||||
ctx->key_enc[8 * i + 10] = t; \
|
||||
t ^= ctx->key_enc[8 * i + 3]; \
|
||||
ctx->key_enc[8 * i + 11] = t; \
|
||||
} while (0)
|
||||
|
||||
#define loop8(i) do { \
|
||||
loop8tophalf(i); \
|
||||
t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \
|
||||
ctx->key_enc[8 * i + 12] = t; \
|
||||
t ^= ctx->key_enc[8 * i + 5]; \
|
||||
ctx->key_enc[8 * i + 13] = t; \
|
||||
t ^= ctx->key_enc[8 * i + 6]; \
|
||||
ctx->key_enc[8 * i + 14] = t; \
|
||||
t ^= ctx->key_enc[8 * i + 7]; \
|
||||
ctx->key_enc[8 * i + 15] = t; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* AES_ExpandKey - Expands the AES key as described in FIPS-197
|
||||
* @ctx: The location where the computed key will be stored.
|
||||
* @in_key: The supplied key.
|
||||
* @key_len: The length of the supplied key.
|
||||
*
|
||||
* Returns 0 on success. The function fails only if an invalid key size (or
|
||||
* pointer) is supplied.
|
||||
* The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes
|
||||
* key schedule plus a 16 bytes key which is used before the first round).
|
||||
* The decryption key is prepared for the "Equivalent Inverse Cipher" as
|
||||
* described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is
|
||||
* for the initial combination, the second slot for the first round and so on.
|
||||
*/
|
||||
static int AES_ExpandKey(aes_context_t *ctx, const uint8_t *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
const uint32_t *key = (const uint32_t *)in_key;
|
||||
uint32_t i, t, u, v, w, j;
|
||||
|
||||
if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
|
||||
key_len != AES_KEYSIZE_256)
|
||||
return -1;
|
||||
|
||||
ctx->key_length = key_len;
|
||||
|
||||
ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]);
|
||||
ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]);
|
||||
ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]);
|
||||
ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]);
|
||||
|
||||
switch (key_len) {
|
||||
case AES_KEYSIZE_128:
|
||||
t = ctx->key_enc[3];
|
||||
for (i = 0; i < 10; ++i)
|
||||
loop4(i);
|
||||
break;
|
||||
|
||||
case AES_KEYSIZE_192:
|
||||
ctx->key_enc[4] = le32_to_cpu(key[4]);
|
||||
t = ctx->key_enc[5] = le32_to_cpu(key[5]);
|
||||
for (i = 0; i < 8; ++i)
|
||||
loop6(i);
|
||||
break;
|
||||
|
||||
case AES_KEYSIZE_256:
|
||||
ctx->key_enc[4] = le32_to_cpu(key[4]);
|
||||
ctx->key_enc[5] = le32_to_cpu(key[5]);
|
||||
ctx->key_enc[6] = le32_to_cpu(key[6]);
|
||||
t = ctx->key_enc[7] = le32_to_cpu(key[7]);
|
||||
for (i = 0; i < 6; ++i)
|
||||
loop8(i);
|
||||
loop8tophalf(i);
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->key_dec[0] = ctx->key_enc[key_len + 24];
|
||||
ctx->key_dec[1] = ctx->key_enc[key_len + 25];
|
||||
ctx->key_dec[2] = ctx->key_enc[key_len + 26];
|
||||
ctx->key_dec[3] = ctx->key_enc[key_len + 27];
|
||||
|
||||
for (i = 4; i < key_len + 24; ++i) {
|
||||
j = key_len + 24 - (i & ~3) + (i & 3);
|
||||
imix_col(ctx->key_dec[j], ctx->key_enc[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* AES_SetKey - Set the AES key.
|
||||
* @ctx: AES context struct.
|
||||
* @in_key: The input key.
|
||||
* @key_len: The size of the key.
|
||||
*
|
||||
* Returns 0 on success, on failure -1 is returned.
|
||||
* The function uses AES_ExpandKey() to expand the key.
|
||||
*/
|
||||
static int AES_SetKey(aes_context_t *ctx, const uint8_t *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = AES_ExpandKey(ctx, in_key, key_len);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* encrypt a block of text */
|
||||
|
||||
#define f_rn(bo, bi, n, k) do { \
|
||||
bo[n] = crypto_ft_tab[0][get_byte(bi[n], 0)] ^ \
|
||||
crypto_ft_tab[1][get_byte(bi[(n + 1) & 3], 1)] ^ \
|
||||
crypto_ft_tab[2][get_byte(bi[(n + 2) & 3], 2)] ^ \
|
||||
crypto_ft_tab[3][get_byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \
|
||||
} while (0)
|
||||
|
||||
#define f_nround(bo, bi, k) do {\
|
||||
f_rn(bo, bi, 0, k); \
|
||||
f_rn(bo, bi, 1, k); \
|
||||
f_rn(bo, bi, 2, k); \
|
||||
f_rn(bo, bi, 3, k); \
|
||||
k += 4; \
|
||||
} while (0)
|
||||
|
||||
#define f_rl(bo, bi, n, k) do { \
|
||||
bo[n] = crypto_fl_tab[0][get_byte(bi[n], 0)] ^ \
|
||||
crypto_fl_tab[1][get_byte(bi[(n + 1) & 3], 1)] ^ \
|
||||
crypto_fl_tab[2][get_byte(bi[(n + 2) & 3], 2)] ^ \
|
||||
crypto_fl_tab[3][get_byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \
|
||||
} while (0)
|
||||
|
||||
#define f_lround(bo, bi, k) do {\
|
||||
f_rl(bo, bi, 0, k); \
|
||||
f_rl(bo, bi, 1, k); \
|
||||
f_rl(bo, bi, 2, k); \
|
||||
f_rl(bo, bi, 3, k); \
|
||||
} while (0)
|
||||
|
||||
static void AES_Encrypt(aes_context_t *ctx, uint8_t *out,
|
||||
const uint8_t *in)
|
||||
{
|
||||
const uint32_t *src = (const uint32_t *)in;
|
||||
uint32_t *dst = (uint32_t *)out;
|
||||
uint32_t b0[4], b1[4];
|
||||
const uint32_t *kp = ctx->key_enc + 4;
|
||||
const int key_len = ctx->key_length;
|
||||
|
||||
b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0];
|
||||
b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1];
|
||||
b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2];
|
||||
b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3];
|
||||
|
||||
if (key_len > 24) {
|
||||
f_nround(b1, b0, kp);
|
||||
f_nround(b0, b1, kp);
|
||||
}
|
||||
|
||||
if (key_len > 16) {
|
||||
f_nround(b1, b0, kp);
|
||||
f_nround(b0, b1, kp);
|
||||
}
|
||||
|
||||
f_nround(b1, b0, kp);
|
||||
f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp);
|
||||
f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp);
|
||||
f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp);
|
||||
f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp);
|
||||
f_lround(b0, b1, kp);
|
||||
|
||||
dst[0] = cpu_to_le32(b0[0]);
|
||||
dst[1] = cpu_to_le32(b0[1]);
|
||||
dst[2] = cpu_to_le32(b0[2]);
|
||||
dst[3] = cpu_to_le32(b0[3]);
|
||||
}
|
||||
|
||||
static boolean prng_enabled = false;
|
||||
static aes_context_t prng_context;
|
||||
static uint32_t prng_input_counter;
|
||||
static uint32_t prng_values[4];
|
||||
static unsigned int prng_value_index = 0;
|
||||
|
||||
// Initialize Pseudo-RNG using the specified 128-bit key.
|
||||
|
||||
void PRNG_Start(prng_seed_t key)
|
||||
{
|
||||
AES_SetKey(&prng_context, key, sizeof(prng_seed_t));
|
||||
prng_value_index = 4;
|
||||
prng_input_counter = 0;
|
||||
prng_enabled = true;
|
||||
}
|
||||
|
||||
void PRNG_Stop(void)
|
||||
{
|
||||
prng_enabled = false;
|
||||
}
|
||||
|
||||
// Generate a set of new PRNG values by encrypting a new block.
|
||||
|
||||
static void PRNG_Generate(void)
|
||||
{
|
||||
byte input[16], output[16];
|
||||
unsigned int i;
|
||||
|
||||
// Input for the cipher is a consecutively increasing 32-bit counter.
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
input[4*i] = prng_input_counter & 0xff;
|
||||
input[4*i + 1] = (prng_input_counter >> 8) & 0xff;
|
||||
input[4*i + 2] = (prng_input_counter >> 16) & 0xff;
|
||||
input[4*i + 3] = (prng_input_counter >> 24) & 0xff;
|
||||
++prng_input_counter;
|
||||
}
|
||||
|
||||
AES_Encrypt(&prng_context, output, input);
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
prng_values[i] = output[4*i]
|
||||
| (output[4*i + 1] << 8)
|
||||
| (output[4*i + 2] << 16)
|
||||
| (output[4*i + 3] << 24);
|
||||
}
|
||||
|
||||
prng_value_index = 0;
|
||||
}
|
||||
|
||||
// Read a random 32-bit integer from the PRNG.
|
||||
|
||||
unsigned int PRNG_Random(void)
|
||||
{
|
||||
unsigned int result;
|
||||
|
||||
if (!prng_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (prng_value_index >= 4)
|
||||
{
|
||||
PRNG_Generate();
|
||||
}
|
||||
|
||||
result = prng_values[prng_value_index];
|
||||
++prng_value_index;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
32
src/aes_prng.h
Normal file
32
src/aes_prng.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Pseudo-random number generator for secure demos.
|
||||
//
|
||||
|
||||
#ifndef __AES_PRNG_H__
|
||||
#define __AES_PRNG_H__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
// Nonce value used as random seed for secure demos.
|
||||
|
||||
typedef byte prng_seed_t[16];
|
||||
|
||||
void PRNG_Start(prng_seed_t seed);
|
||||
void PRNG_Stop(void);
|
||||
unsigned int PRNG_Random(void);
|
||||
|
||||
#endif /* #ifndef __AES_PRNG_H__ */
|
||||
|
||||
1174
src/am_map.c
Normal file
1174
src/am_map.c
Normal file
File diff suppressed because it is too large
Load Diff
47
src/am_map.h
Normal file
47
src/am_map.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// AutoMap module.
|
||||
//
|
||||
|
||||
#ifndef __AMMAP_H__
|
||||
#define __AMMAP_H__
|
||||
|
||||
#include "d_event.h"
|
||||
#include "doomtype.h"
|
||||
#include "m_cheat.h"
|
||||
|
||||
// Used by ST StatusBar stuff.
|
||||
#define AM_MSGHEADER (('a' << 24) + ('m' << 16))
|
||||
#define AM_MSGENTERED (AM_MSGHEADER | ('e' << 8))
|
||||
#define AM_MSGEXITED (AM_MSGHEADER | ('x' << 8))
|
||||
|
||||
// Called by main loop.
|
||||
boolean AM_Responder(event_t *ev);
|
||||
|
||||
// Called by main loop.
|
||||
void AM_Ticker(void);
|
||||
|
||||
// Called by main loop,
|
||||
// called instead of view drawer if automap active.
|
||||
void AM_Drawer(void);
|
||||
|
||||
// Called to force the automap to quit
|
||||
// if the level is completed while it is up.
|
||||
void AM_Stop(void);
|
||||
|
||||
extern cheatseq_t cheat_amap;
|
||||
|
||||
#endif
|
||||
631
src/d_englsh.h
Normal file
631
src/d_englsh.h
Normal file
@@ -0,0 +1,631 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Printed strings for translation.
|
||||
// English language support (default).
|
||||
//
|
||||
|
||||
#ifndef __D_ENGLSH__
|
||||
#define __D_ENGLSH__
|
||||
|
||||
//
|
||||
// Printed strings for translation
|
||||
//
|
||||
|
||||
//
|
||||
// D_Main.C
|
||||
//
|
||||
#define D_DEVSTR "Development mode ON.\n"
|
||||
|
||||
//
|
||||
// M_Menu.C
|
||||
//
|
||||
#define PRESSKEY "press a key."
|
||||
#define PRESSYN "press y or n."
|
||||
#define QUITMSG "are you sure you want to\nquit this great game?"
|
||||
#define LOADNET "you can't do load while in a net game!\n\n" PRESSKEY
|
||||
#define QLOADNET "you can't quickload during a netgame!\n\n" PRESSKEY
|
||||
#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n" PRESSKEY
|
||||
#define SAVEDEAD "you can't save if you aren't playing!\n\n" PRESSKEY
|
||||
#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n" PRESSYN
|
||||
#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n" PRESSYN
|
||||
|
||||
#define NEWGAME \
|
||||
"you can't start a new game\n" \
|
||||
"while in a network game.\n\n" PRESSKEY
|
||||
|
||||
#define NIGHTMARE \
|
||||
"are you sure? this skill level\n" \
|
||||
"isn't even remotely fair.\n\n" PRESSYN
|
||||
|
||||
#define SWSTRING \
|
||||
"this is the shareware version of doom.\n\n" \
|
||||
"you need to order the entire trilogy.\n\n" PRESSKEY
|
||||
|
||||
#define MSGOFF "Messages OFF"
|
||||
#define MSGON "Messages ON"
|
||||
#define NETEND "you can't end a netgame!\n\n" PRESSKEY
|
||||
#define ENDGAME "are you sure you want to end the game?\n\n" PRESSYN
|
||||
|
||||
#define DOSY "(press y to quit to dos.)"
|
||||
|
||||
#define DETAILHI "High detail"
|
||||
#define DETAILLO "Low detail"
|
||||
#define GAMMALVL0 "Gamma correction OFF"
|
||||
#define GAMMALVL1 "Gamma correction level 1"
|
||||
#define GAMMALVL2 "Gamma correction level 2"
|
||||
#define GAMMALVL3 "Gamma correction level 3"
|
||||
#define GAMMALVL4 "Gamma correction level 4"
|
||||
#define EMPTYSTRING "empty slot"
|
||||
|
||||
//
|
||||
// P_inter.C
|
||||
//
|
||||
#define GOTARMOR "Picked up the armor."
|
||||
#define GOTMEGA "Picked up the MegaArmor!"
|
||||
#define GOTHTHBONUS "Picked up a health bonus."
|
||||
#define GOTARMBONUS "Picked up an armor bonus."
|
||||
#define GOTSTIM "Picked up a stimpack."
|
||||
#define GOTMEDINEED "Picked up a medikit that you REALLY need!"
|
||||
#define GOTMEDIKIT "Picked up a medikit."
|
||||
#define GOTSUPER "Supercharge!"
|
||||
|
||||
#define GOTBLUECARD "Picked up a blue keycard."
|
||||
#define GOTYELWCARD "Picked up a yellow keycard."
|
||||
#define GOTREDCARD "Picked up a red keycard."
|
||||
#define GOTBLUESKUL "Picked up a blue skull key."
|
||||
#define GOTYELWSKUL "Picked up a yellow skull key."
|
||||
#define GOTREDSKULL "Picked up a red skull key."
|
||||
|
||||
#define GOTINVUL "Invulnerability!"
|
||||
#define GOTBERSERK "Berserk!"
|
||||
#define GOTINVIS "Partial Invisibility"
|
||||
#define GOTSUIT "Radiation Shielding Suit"
|
||||
#define GOTMAP "Computer Area Map"
|
||||
#define GOTVISOR "Light Amplification Visor"
|
||||
#define GOTMSPHERE "MegaSphere!"
|
||||
|
||||
#define GOTCLIP "Picked up a clip."
|
||||
#define GOTCLIPBOX "Picked up a box of bullets."
|
||||
#define GOTROCKET "Picked up a rocket."
|
||||
#define GOTROCKBOX "Picked up a box of rockets."
|
||||
#define GOTCELL "Picked up an energy cell."
|
||||
#define GOTCELLBOX "Picked up an energy cell pack."
|
||||
#define GOTSHELLS "Picked up 4 shotgun shells."
|
||||
#define GOTSHELLBOX "Picked up a box of shotgun shells."
|
||||
#define GOTBACKPACK "Picked up a backpack full of ammo!"
|
||||
|
||||
#define GOTBFG9000 "You got the BFG9000! Oh, yes."
|
||||
#define GOTCHAINGUN "You got the chaingun!"
|
||||
#define GOTCHAINSAW "A chainsaw! Find some meat!"
|
||||
#define GOTLAUNCHER "You got the rocket launcher!"
|
||||
#define GOTPLASMA "You got the plasma gun!"
|
||||
#define GOTSHOTGUN "You got the shotgun!"
|
||||
#define GOTSHOTGUN2 "You got the super shotgun!"
|
||||
|
||||
//
|
||||
// P_Doors.C
|
||||
//
|
||||
#define PD_BLUEO "You need a blue key to activate this object"
|
||||
#define PD_REDO "You need a red key to activate this object"
|
||||
#define PD_YELLOWO "You need a yellow key to activate this object"
|
||||
#define PD_BLUEK "You need a blue key to open this door"
|
||||
#define PD_REDK "You need a red key to open this door"
|
||||
#define PD_YELLOWK "You need a yellow key to open this door"
|
||||
|
||||
//
|
||||
// G_game.C
|
||||
//
|
||||
#define GGSAVED "game saved."
|
||||
|
||||
//
|
||||
// HU_stuff.C
|
||||
//
|
||||
#define HUSTR_MSGU "[Message unsent]"
|
||||
|
||||
#define HUSTR_E1M1 "E1M1: Hangar"
|
||||
#define HUSTR_E1M2 "E1M2: Nuclear Plant"
|
||||
#define HUSTR_E1M3 "E1M3: Toxin Refinery"
|
||||
#define HUSTR_E1M4 "E1M4: Command Control"
|
||||
#define HUSTR_E1M5 "E1M5: Phobos Lab"
|
||||
#define HUSTR_E1M6 "E1M6: Central Processing"
|
||||
#define HUSTR_E1M7 "E1M7: Computer Station"
|
||||
#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
|
||||
#define HUSTR_E1M9 "E1M9: Military Base"
|
||||
|
||||
#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
|
||||
#define HUSTR_E2M2 "E2M2: Containment Area"
|
||||
#define HUSTR_E2M3 "E2M3: Refinery"
|
||||
#define HUSTR_E2M4 "E2M4: Deimos Lab"
|
||||
#define HUSTR_E2M5 "E2M5: Command Center"
|
||||
#define HUSTR_E2M6 "E2M6: Halls of the Damned"
|
||||
#define HUSTR_E2M7 "E2M7: Spawning Vats"
|
||||
#define HUSTR_E2M8 "E2M8: Tower of Babel"
|
||||
#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
|
||||
|
||||
#define HUSTR_E3M1 "E3M1: Hell Keep"
|
||||
#define HUSTR_E3M2 "E3M2: Slough of Despair"
|
||||
#define HUSTR_E3M3 "E3M3: Pandemonium"
|
||||
#define HUSTR_E3M4 "E3M4: House of Pain"
|
||||
#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
|
||||
#define HUSTR_E3M6 "E3M6: Mt. Erebus"
|
||||
#define HUSTR_E3M7 "E3M7: Limbo"
|
||||
#define HUSTR_E3M8 "E3M8: Dis"
|
||||
#define HUSTR_E3M9 "E3M9: Warrens"
|
||||
|
||||
#define HUSTR_E4M1 "E4M1: Hell Beneath"
|
||||
#define HUSTR_E4M2 "E4M2: Perfect Hatred"
|
||||
#define HUSTR_E4M3 "E4M3: Sever The Wicked"
|
||||
#define HUSTR_E4M4 "E4M4: Unruly Evil"
|
||||
#define HUSTR_E4M5 "E4M5: They Will Repent"
|
||||
#define HUSTR_E4M6 "E4M6: Against Thee Wickedly"
|
||||
#define HUSTR_E4M7 "E4M7: And Hell Followed"
|
||||
#define HUSTR_E4M8 "E4M8: Unto The Cruel"
|
||||
#define HUSTR_E4M9 "E4M9: Fear"
|
||||
|
||||
#define HUSTR_1 "level 1: entryway"
|
||||
#define HUSTR_2 "level 2: underhalls"
|
||||
#define HUSTR_3 "level 3: the gantlet"
|
||||
#define HUSTR_4 "level 4: the focus"
|
||||
#define HUSTR_5 "level 5: the waste tunnels"
|
||||
#define HUSTR_6 "level 6: the crusher"
|
||||
#define HUSTR_7 "level 7: dead simple"
|
||||
#define HUSTR_8 "level 8: tricks and traps"
|
||||
#define HUSTR_9 "level 9: the pit"
|
||||
#define HUSTR_10 "level 10: refueling base"
|
||||
#define HUSTR_11 "level 11: 'o' of destruction!"
|
||||
|
||||
#define HUSTR_12 "level 12: the factory"
|
||||
#define HUSTR_13 "level 13: downtown"
|
||||
#define HUSTR_14 "level 14: the inmost dens"
|
||||
#define HUSTR_15 "level 15: industrial zone"
|
||||
#define HUSTR_16 "level 16: suburbs"
|
||||
#define HUSTR_17 "level 17: tenements"
|
||||
#define HUSTR_18 "level 18: the courtyard"
|
||||
#define HUSTR_19 "level 19: the citadel"
|
||||
#define HUSTR_20 "level 20: gotcha!"
|
||||
|
||||
#define HUSTR_21 "level 21: nirvana"
|
||||
#define HUSTR_22 "level 22: the catacombs"
|
||||
#define HUSTR_23 "level 23: barrels o' fun"
|
||||
#define HUSTR_24 "level 24: the chasm"
|
||||
#define HUSTR_25 "level 25: bloodfalls"
|
||||
#define HUSTR_26 "level 26: the abandoned mines"
|
||||
#define HUSTR_27 "level 27: monster condo"
|
||||
#define HUSTR_28 "level 28: the spirit world"
|
||||
#define HUSTR_29 "level 29: the living end"
|
||||
#define HUSTR_30 "level 30: icon of sin"
|
||||
|
||||
#define HUSTR_31 "level 31: wolfenstein"
|
||||
#define HUSTR_32 "level 32: grosse"
|
||||
|
||||
#define PHUSTR_1 "level 1: congo"
|
||||
#define PHUSTR_2 "level 2: well of souls"
|
||||
#define PHUSTR_3 "level 3: aztec"
|
||||
#define PHUSTR_4 "level 4: caged"
|
||||
#define PHUSTR_5 "level 5: ghost town"
|
||||
#define PHUSTR_6 "level 6: baron's lair"
|
||||
#define PHUSTR_7 "level 7: caughtyard"
|
||||
#define PHUSTR_8 "level 8: realm"
|
||||
#define PHUSTR_9 "level 9: abattoire"
|
||||
#define PHUSTR_10 "level 10: onslaught"
|
||||
#define PHUSTR_11 "level 11: hunted"
|
||||
|
||||
#define PHUSTR_12 "level 12: speed"
|
||||
#define PHUSTR_13 "level 13: the crypt"
|
||||
#define PHUSTR_14 "level 14: genesis"
|
||||
#define PHUSTR_15 "level 15: the twilight"
|
||||
#define PHUSTR_16 "level 16: the omen"
|
||||
#define PHUSTR_17 "level 17: compound"
|
||||
#define PHUSTR_18 "level 18: neurosphere"
|
||||
#define PHUSTR_19 "level 19: nme"
|
||||
#define PHUSTR_20 "level 20: the death domain"
|
||||
|
||||
#define PHUSTR_21 "level 21: slayer"
|
||||
#define PHUSTR_22 "level 22: impossible mission"
|
||||
#define PHUSTR_23 "level 23: tombstone"
|
||||
#define PHUSTR_24 "level 24: the final frontier"
|
||||
#define PHUSTR_25 "level 25: the temple of darkness"
|
||||
#define PHUSTR_26 "level 26: bunker"
|
||||
#define PHUSTR_27 "level 27: anti-christ"
|
||||
#define PHUSTR_28 "level 28: the sewers"
|
||||
#define PHUSTR_29 "level 29: odyssey of noises"
|
||||
#define PHUSTR_30 "level 30: the gateway of hell"
|
||||
|
||||
#define PHUSTR_31 "level 31: cyberden"
|
||||
#define PHUSTR_32 "level 32: go 2 it"
|
||||
|
||||
#define THUSTR_1 "level 1: system control"
|
||||
#define THUSTR_2 "level 2: human bbq"
|
||||
#define THUSTR_3 "level 3: power control"
|
||||
#define THUSTR_4 "level 4: wormhole"
|
||||
#define THUSTR_5 "level 5: hanger"
|
||||
#define THUSTR_6 "level 6: open season"
|
||||
#define THUSTR_7 "level 7: prison"
|
||||
#define THUSTR_8 "level 8: metal"
|
||||
#define THUSTR_9 "level 9: stronghold"
|
||||
#define THUSTR_10 "level 10: redemption"
|
||||
#define THUSTR_11 "level 11: storage facility"
|
||||
|
||||
#define THUSTR_12 "level 12: crater"
|
||||
#define THUSTR_13 "level 13: nukage processing"
|
||||
#define THUSTR_14 "level 14: steel works"
|
||||
#define THUSTR_15 "level 15: dead zone"
|
||||
#define THUSTR_16 "level 16: deepest reaches"
|
||||
#define THUSTR_17 "level 17: processing area"
|
||||
#define THUSTR_18 "level 18: mill"
|
||||
#define THUSTR_19 "level 19: shipping/respawning"
|
||||
#define THUSTR_20 "level 20: central processing"
|
||||
|
||||
#define THUSTR_21 "level 21: administration center"
|
||||
#define THUSTR_22 "level 22: habitat"
|
||||
#define THUSTR_23 "level 23: lunar mining project"
|
||||
#define THUSTR_24 "level 24: quarry"
|
||||
#define THUSTR_25 "level 25: baron's den"
|
||||
#define THUSTR_26 "level 26: ballistyx"
|
||||
#define THUSTR_27 "level 27: mount pain"
|
||||
#define THUSTR_28 "level 28: heck"
|
||||
#define THUSTR_29 "level 29: river styx"
|
||||
#define THUSTR_30 "level 30: last call"
|
||||
|
||||
#define THUSTR_31 "level 31: pharaoh"
|
||||
#define THUSTR_32 "level 32: caribbean"
|
||||
|
||||
#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
|
||||
#define HUSTR_CHATMACRO2 "I'm OK."
|
||||
#define HUSTR_CHATMACRO3 "I'm not looking too good!"
|
||||
#define HUSTR_CHATMACRO4 "Help!"
|
||||
#define HUSTR_CHATMACRO5 "You suck!"
|
||||
#define HUSTR_CHATMACRO6 "Next time, scumbag..."
|
||||
#define HUSTR_CHATMACRO7 "Come here!"
|
||||
#define HUSTR_CHATMACRO8 "I'll take care of it."
|
||||
#define HUSTR_CHATMACRO9 "Yes"
|
||||
#define HUSTR_CHATMACRO0 "No"
|
||||
|
||||
#define HUSTR_TALKTOSELF1 "You mumble to yourself"
|
||||
#define HUSTR_TALKTOSELF2 "Who's there?"
|
||||
#define HUSTR_TALKTOSELF3 "You scare yourself"
|
||||
#define HUSTR_TALKTOSELF4 "You start to rave"
|
||||
#define HUSTR_TALKTOSELF5 "You've lost it..."
|
||||
|
||||
#define HUSTR_MESSAGESENT "[Message Sent]"
|
||||
|
||||
// The following should NOT be changed unless it seems
|
||||
// just AWFULLY necessary
|
||||
|
||||
#define HUSTR_PLRGREEN "Green: "
|
||||
#define HUSTR_PLRINDIGO "Indigo: "
|
||||
#define HUSTR_PLRBROWN "Brown: "
|
||||
#define HUSTR_PLRRED "Red: "
|
||||
|
||||
#define HUSTR_KEYGREEN 'g'
|
||||
#define HUSTR_KEYINDIGO 'i'
|
||||
#define HUSTR_KEYBROWN 'b'
|
||||
#define HUSTR_KEYRED 'r'
|
||||
|
||||
//
|
||||
// AM_map.C
|
||||
//
|
||||
|
||||
#define AMSTR_FOLLOWON "Follow Mode ON"
|
||||
#define AMSTR_FOLLOWOFF "Follow Mode OFF"
|
||||
|
||||
#define AMSTR_GRIDON "Grid ON"
|
||||
#define AMSTR_GRIDOFF "Grid OFF"
|
||||
|
||||
#define AMSTR_MARKEDSPOT "Marked Spot"
|
||||
#define AMSTR_MARKSCLEARED "All Marks Cleared"
|
||||
|
||||
//
|
||||
// ST_stuff.C
|
||||
//
|
||||
|
||||
#define STSTR_MUS "Music Change"
|
||||
#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
|
||||
#define STSTR_DQDON "Degreelessness Mode On"
|
||||
#define STSTR_DQDOFF "Degreelessness Mode Off"
|
||||
|
||||
#define STSTR_KFAADDED "Very Happy Ammo Added"
|
||||
#define STSTR_FAADDED "Ammo (no keys) Added"
|
||||
|
||||
#define STSTR_NCON "No Clipping Mode ON"
|
||||
#define STSTR_NCOFF "No Clipping Mode OFF"
|
||||
|
||||
#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
|
||||
#define STSTR_BEHOLDX "Power-up Toggled"
|
||||
|
||||
#define STSTR_CHOPPERS "... doesn't suck - GM"
|
||||
#define STSTR_CLEV "Changing Level..."
|
||||
|
||||
#define E2TEXT \
|
||||
"You've done it! The hideous cyber-\n" \
|
||||
"demon lord that ruled the lost Deimos\n" \
|
||||
"moon base has been slain and you\n" \
|
||||
"are triumphant! But ... where are\n" \
|
||||
"you? You clamber to the edge of the\n" \
|
||||
"moon and look down to see the awful\n" \
|
||||
"truth.\n" \
|
||||
"\n" \
|
||||
"Deimos floats above Hell itself!\n" \
|
||||
"You've never heard of anyone escaping\n" \
|
||||
"from Hell, but you'll make the bastards\n" \
|
||||
"sorry they ever heard of you! Quickly,\n" \
|
||||
"you rappel down to the surface of\n" \
|
||||
"Hell.\n" \
|
||||
"\n" \
|
||||
"Now, it's on to the final chapter of\n" \
|
||||
"DOOM! -- Inferno."
|
||||
|
||||
#define E3TEXT \
|
||||
"The loathsome spiderdemon that\n" \
|
||||
"masterminded the invasion of the moon\n" \
|
||||
"bases and caused so much death has had\n" \
|
||||
"its ass kicked for all time.\n" \
|
||||
"\n" \
|
||||
"A hidden doorway opens and you enter.\n" \
|
||||
"You've proven too tough for Hell to\n" \
|
||||
"contain, and now Hell at last plays\n" \
|
||||
"fair -- for you emerge from the door\n" \
|
||||
"to see the green fields of Earth!\n" \
|
||||
"Home at last.\n" \
|
||||
"\n" \
|
||||
"You wonder what's been happening on\n" \
|
||||
"Earth while you were battling evil\n" \
|
||||
"unleashed. It's good that no Hell-\n" \
|
||||
"spawn could have come through that\n" \
|
||||
"door with you ..."
|
||||
|
||||
#define E4TEXT \
|
||||
"the spider mastermind must have sent forth\n" \
|
||||
"its legions of hellspawn before your\n" \
|
||||
"final confrontation with that terrible\n" \
|
||||
"beast from hell. but you stepped forward\n" \
|
||||
"and brought forth eternal damnation and\n" \
|
||||
"suffering upon the horde as a true hero\n" \
|
||||
"would in the face of something so evil.\n" \
|
||||
"\n" \
|
||||
"besides, someone was gonna pay for what\n" \
|
||||
"happened to daisy, your pet rabbit.\n" \
|
||||
"\n" \
|
||||
"but now, you see spread before you more\n" \
|
||||
"potential pain and gibbitude as a nation\n" \
|
||||
"of demons run amok among our cities.\n" \
|
||||
"\n" \
|
||||
"next stop, hell on earth!"
|
||||
|
||||
// after level 6, put this:
|
||||
|
||||
#define C1TEXT \
|
||||
"YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \
|
||||
"STARPORT. BUT SOMETHING IS WRONG. THE\n" \
|
||||
"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \
|
||||
"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \
|
||||
"IS BEING SUBVERTED BY THEIR PRESENCE.\n" \
|
||||
"\n" \
|
||||
"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \
|
||||
"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \
|
||||
"YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \
|
||||
"OF THE STARBASE AND FIND THE CONTROLLING\n" \
|
||||
"SWITCH WHICH HOLDS EARTH'S POPULATION\n" \
|
||||
"HOSTAGE."
|
||||
|
||||
// After level 11, put this:
|
||||
|
||||
#define C2TEXT \
|
||||
"YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \
|
||||
"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n" \
|
||||
"THE NIGHTMARE. NOW YOU ARE THE ONLY\n" \
|
||||
"HUMAN LEFT ON THE FACE OF THE PLANET.\n" \
|
||||
"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n" \
|
||||
"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n" \
|
||||
"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n" \
|
||||
"THAT YOU HAVE SAVED YOUR SPECIES.\n" \
|
||||
"\n" \
|
||||
"BUT THEN, EARTH CONTROL BEAMS DOWN A\n" \
|
||||
"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n" \
|
||||
"THE SOURCE OF THE ALIEN INVASION. IF YOU\n" \
|
||||
"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n" \
|
||||
"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n" \
|
||||
"YOUR OWN HOME CITY, NOT FAR FROM THE\n" \
|
||||
"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n" \
|
||||
"UP AND RETURN TO THE FRAY."
|
||||
|
||||
// After level 20, put this:
|
||||
|
||||
#define C3TEXT \
|
||||
"YOU ARE AT THE CORRUPT HEART OF THE CITY,\n" \
|
||||
"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n" \
|
||||
"YOU SEE NO WAY TO DESTROY THE CREATURES'\n" \
|
||||
"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n" \
|
||||
"TEETH AND PLUNGE THROUGH IT.\n" \
|
||||
"\n" \
|
||||
"THERE MUST BE A WAY TO CLOSE IT ON THE\n" \
|
||||
"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n" \
|
||||
"GOT TO GO THROUGH HELL TO GET TO IT?"
|
||||
|
||||
// After level 29, put this:
|
||||
|
||||
#define C4TEXT \
|
||||
"THE HORRENDOUS VISAGE OF THE BIGGEST\n" \
|
||||
"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n" \
|
||||
"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n" \
|
||||
"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n" \
|
||||
"UP AND DIES, ITS THRASHING LIMBS\n" \
|
||||
"DEVASTATING UNTOLD MILES OF HELL'S\n" \
|
||||
"SURFACE.\n" \
|
||||
"\n" \
|
||||
"YOU'VE DONE IT. THE INVASION IS OVER.\n" \
|
||||
"EARTH IS SAVED. HELL IS A WRECK. YOU\n" \
|
||||
"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n" \
|
||||
"DIE, NOW. WIPING THE SWEAT FROM YOUR\n" \
|
||||
"FOREHEAD YOU BEGIN THE LONG TREK BACK\n" \
|
||||
"HOME. REBUILDING EARTH OUGHT TO BE A\n" \
|
||||
"LOT MORE FUN THAN RUINING IT WAS.\n"
|
||||
|
||||
// Before level 31, put this:
|
||||
|
||||
#define C5TEXT \
|
||||
"CONGRATULATIONS, YOU'VE FOUND THE SECRET\n" \
|
||||
"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n" \
|
||||
"HUMANS, RATHER THAN DEMONS. YOU WONDER\n" \
|
||||
"WHO THE INMATES OF THIS CORNER OF HELL\n" \
|
||||
"WILL BE."
|
||||
|
||||
// Before level 32, put this:
|
||||
|
||||
#define C6TEXT \
|
||||
"CONGRATULATIONS, YOU'VE FOUND THE\n" \
|
||||
"SUPER SECRET LEVEL! YOU'D BETTER\n" \
|
||||
"BLAZE THROUGH THIS ONE!\n"
|
||||
|
||||
// after map 06
|
||||
|
||||
#define P1TEXT \
|
||||
"You gloat over the steaming carcass of the\n" \
|
||||
"Guardian. With its death, you've wrested\n" \
|
||||
"the Accelerator from the stinking claws\n" \
|
||||
"of Hell. You relax and glance around the\n" \
|
||||
"room. Damn! There was supposed to be at\n" \
|
||||
"least one working prototype, but you can't\n" \
|
||||
"see it. The demons must have taken it.\n" \
|
||||
"\n" \
|
||||
"You must find the prototype, or all your\n" \
|
||||
"struggles will have been wasted. Keep\n" \
|
||||
"moving, keep fighting, keep killing.\n" \
|
||||
"Oh yes, keep living, too."
|
||||
|
||||
// after map 11
|
||||
|
||||
#define P2TEXT \
|
||||
"Even the deadly Arch-Vile labyrinth could\n" \
|
||||
"not stop you, and you've gotten to the\n" \
|
||||
"prototype Accelerator which is soon\n" \
|
||||
"efficiently and permanently deactivated.\n" \
|
||||
"\n" \
|
||||
"You're good at that kind of thing."
|
||||
|
||||
// after map 20
|
||||
|
||||
#define P3TEXT \
|
||||
"You've bashed and battered your way into\n" \
|
||||
"the heart of the devil-hive. Time for a\n" \
|
||||
"Search-and-Destroy mission, aimed at the\n" \
|
||||
"Gatekeeper, whose foul offspring is\n" \
|
||||
"cascading to Earth. Yeah, he's bad. But\n" \
|
||||
"you know who's worse!\n" \
|
||||
"\n" \
|
||||
"Grinning evilly, you check your gear, and\n" \
|
||||
"get ready to give the bastard a little Hell\n" \
|
||||
"of your own making!"
|
||||
|
||||
// after map 30
|
||||
|
||||
#define P4TEXT \
|
||||
"The Gatekeeper's evil face is splattered\n" \
|
||||
"all over the place. As its tattered corpse\n" \
|
||||
"collapses, an inverted Gate forms and\n" \
|
||||
"sucks down the shards of the last\n" \
|
||||
"prototype Accelerator, not to mention the\n" \
|
||||
"few remaining demons. You're done. Hell\n" \
|
||||
"has gone back to pounding bad dead folks \n" \
|
||||
"instead of good live ones. Remember to\n" \
|
||||
"tell your grandkids to put a rocket\n" \
|
||||
"launcher in your coffin. If you go to Hell\n" \
|
||||
"when you die, you'll need it for some\n" \
|
||||
"final cleaning-up ..."
|
||||
|
||||
// before map 31
|
||||
|
||||
#define P5TEXT \
|
||||
"You've found the second-hardest level we\n" \
|
||||
"got. Hope you have a saved game a level or\n" \
|
||||
"two previous. If not, be prepared to die\n" \
|
||||
"aplenty. For master marines only."
|
||||
|
||||
// before map 32
|
||||
|
||||
#define P6TEXT \
|
||||
"Betcha wondered just what WAS the hardest\n" \
|
||||
"level we had ready for ya? Now you know.\n" \
|
||||
"No one gets out alive."
|
||||
|
||||
#define T1TEXT \
|
||||
"You've fought your way out of the infested\n" \
|
||||
"experimental labs. It seems that UAC has\n" \
|
||||
"once again gulped it down. With their\n" \
|
||||
"high turnover, it must be hard for poor\n" \
|
||||
"old UAC to buy corporate health insurance\n" \
|
||||
"nowadays..\n" \
|
||||
"\n" \
|
||||
"Ahead lies the military complex, now\n" \
|
||||
"swarming with diseased horrors hot to get\n" \
|
||||
"their teeth into you. With luck, the\n" \
|
||||
"complex still has some warlike ordnance\n" \
|
||||
"laying around."
|
||||
|
||||
#define T2TEXT \
|
||||
"You hear the grinding of heavy machinery\n" \
|
||||
"ahead. You sure hope they're not stamping\n" \
|
||||
"out new hellspawn, but you're ready to\n" \
|
||||
"ream out a whole herd if you have to.\n" \
|
||||
"They might be planning a blood feast, but\n" \
|
||||
"you feel about as mean as two thousand\n" \
|
||||
"maniacs packed into one mad killer.\n" \
|
||||
"\n" \
|
||||
"You don't plan to go down easy."
|
||||
|
||||
#define T3TEXT \
|
||||
"The vista opening ahead looks real damn\n" \
|
||||
"familiar. Smells familiar, too -- like\n" \
|
||||
"fried excrement. You didn't like this\n" \
|
||||
"place before, and you sure as hell ain't\n" \
|
||||
"planning to like it now. The more you\n" \
|
||||
"brood on it, the madder you get.\n" \
|
||||
"Hefting your gun, an evil grin trickles\n" \
|
||||
"onto your face. Time to take some names."
|
||||
|
||||
#define T4TEXT \
|
||||
"Suddenly, all is silent, from one horizon\n" \
|
||||
"to the other. The agonizing echo of Hell\n" \
|
||||
"fades away, the nightmare sky turns to\n" \
|
||||
"blue, the heaps of monster corpses start \n" \
|
||||
"to evaporate along with the evil stench \n" \
|
||||
"that filled the air. Jeeze, maybe you've\n" \
|
||||
"done it. Have you really won?\n" \
|
||||
"\n" \
|
||||
"Something rumbles in the distance.\n" \
|
||||
"A blue light begins to glow inside the\n" \
|
||||
"ruined skull of the demon-spitter."
|
||||
|
||||
#define T5TEXT \
|
||||
"What now? Looks totally different. Kind\n" \
|
||||
"of like King Tut's condo. Well,\n" \
|
||||
"whatever's here can't be any worse\n" \
|
||||
"than usual. Can it? Or maybe it's best\n" \
|
||||
"to let sleeping gods lie.."
|
||||
|
||||
#define T6TEXT \
|
||||
"Time for a vacation. You've burst the\n" \
|
||||
"bowels of hell and by golly you're ready\n" \
|
||||
"for a break. You mutter to yourself,\n" \
|
||||
"Maybe someone else can kick Hell's ass\n" \
|
||||
"next time around. Ahead lies a quiet town,\n" \
|
||||
"with peaceful flowing water, quaint\n" \
|
||||
"buildings, and presumably no Hellspawn.\n" \
|
||||
"\n" \
|
||||
"As you step off the transport, you hear\n" \
|
||||
"the stomp of a cyberdemon's iron shoe."
|
||||
|
||||
#endif
|
||||
63
src/d_event.c
Normal file
63
src/d_event.c
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// DESCRIPTION: Event handling.
|
||||
//
|
||||
// Events are asynchronous inputs generally generated by the game user.
|
||||
// Events can be discarded if no responder claims them
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "d_event.h"
|
||||
|
||||
#define MAXEVENTS 64
|
||||
|
||||
static event_t events[MAXEVENTS];
|
||||
static int eventhead;
|
||||
static int eventtail;
|
||||
|
||||
//
|
||||
// D_PostEvent
|
||||
// Called by the I/O functions when input is detected
|
||||
//
|
||||
void D_PostEvent (event_t* ev)
|
||||
{
|
||||
events[eventhead] = *ev;
|
||||
eventhead = (eventhead + 1) % MAXEVENTS;
|
||||
}
|
||||
|
||||
// Read an event from the queue.
|
||||
|
||||
event_t *D_PopEvent(void)
|
||||
{
|
||||
event_t *result;
|
||||
|
||||
// No more events waiting.
|
||||
|
||||
if (eventtail == eventhead)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = &events[eventtail];
|
||||
|
||||
// Advance to the next event in the queue.
|
||||
|
||||
eventtail = (eventtail + 1) % MAXEVENTS;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
140
src/d_event.h
Normal file
140
src/d_event.h
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
#ifndef __D_EVENT__
|
||||
#define __D_EVENT__
|
||||
//
|
||||
// Event handling.
|
||||
//
|
||||
|
||||
// Input event types.
|
||||
typedef enum
|
||||
{
|
||||
// Key press/release events.
|
||||
// data1: Key code (from doomkeys.h) of the key that was
|
||||
// pressed or released. This is the key as it appears
|
||||
// on a US keyboard layout, and does not change with
|
||||
// layout.
|
||||
// For ev_keydown only:
|
||||
// data2: ASCII representation of the key that was pressed that
|
||||
// changes with the keyboard layout; eg. if 'Z' is
|
||||
// pressed on a German keyboard, data1='y',data2='z'.
|
||||
// Not affected by modifier keys.
|
||||
// data3: ASCII input, fully modified according to keyboard
|
||||
// layout and any modifier keys that are held down.
|
||||
// Only set if I_StartTextInput() has been called.
|
||||
ev_keydown,
|
||||
ev_keyup,
|
||||
|
||||
// Mouse movement event.
|
||||
// data1: Bitfield of buttons currently held down.
|
||||
// (bit 0 = left; bit 1 = right; bit 2 = middle).
|
||||
// data2: X axis mouse movement (turn).
|
||||
// data3: Y axis mouse movement (forward/backward).
|
||||
ev_mouse,
|
||||
|
||||
// Joystick state.
|
||||
// data1: Bitfield of buttons currently pressed.
|
||||
// data2: X axis mouse movement (turn).
|
||||
// data3: Y axis mouse movement (forward/backward).
|
||||
// data4: Third axis mouse movement (strafe).
|
||||
ev_joystick,
|
||||
|
||||
// Quit event. Triggered when the user clicks the "close" button
|
||||
// to terminate the application.
|
||||
ev_quit
|
||||
} evtype_t;
|
||||
|
||||
// Event structure.
|
||||
typedef struct
|
||||
{
|
||||
evtype_t type;
|
||||
|
||||
// Event-specific data; see the descriptions given above.
|
||||
int data1, data2, data3, data4;
|
||||
} event_t;
|
||||
|
||||
|
||||
//
|
||||
// Button/action code definitions.
|
||||
//
|
||||
typedef enum
|
||||
{
|
||||
// Press "Fire".
|
||||
BT_ATTACK = 1,
|
||||
// Use button, to open doors, activate switches.
|
||||
BT_USE = 2,
|
||||
|
||||
// Flag: game events, not really buttons.
|
||||
BT_SPECIAL = 128,
|
||||
BT_SPECIALMASK = 3,
|
||||
|
||||
// Flag, weapon change pending.
|
||||
// If true, the next 3 bits hold weapon num.
|
||||
BT_CHANGE = 4,
|
||||
// The 3bit weapon mask and shift, convenience.
|
||||
BT_WEAPONMASK = (8+16+32),
|
||||
BT_WEAPONSHIFT = 3,
|
||||
|
||||
// Pause the game.
|
||||
BTS_PAUSE = 1,
|
||||
// Save the game at each console.
|
||||
BTS_SAVEGAME = 2,
|
||||
|
||||
// Savegame slot numbers
|
||||
// occupy the second byte of buttons.
|
||||
BTS_SAVEMASK = (4+8+16),
|
||||
BTS_SAVESHIFT = 2,
|
||||
|
||||
} buttoncode_t;
|
||||
|
||||
// villsa [STRIFE] Strife specific buttons
|
||||
// TODO - not finished
|
||||
typedef enum
|
||||
{
|
||||
// Player view look up
|
||||
BT2_LOOKUP = 1,
|
||||
// Player view look down
|
||||
BT2_LOOKDOWN = 2,
|
||||
// Center player's view
|
||||
BT2_CENTERVIEW = 4,
|
||||
// Use inventory item
|
||||
BT2_INVUSE = 8,
|
||||
// Drop inventory item
|
||||
BT2_INVDROP = 16,
|
||||
// Jump up and down
|
||||
BT2_JUMP = 32,
|
||||
// Use medkit
|
||||
BT2_HEALTH = 128,
|
||||
|
||||
} buttoncode2_t;
|
||||
|
||||
|
||||
|
||||
|
||||
// Called by IO functions when input is detected.
|
||||
void D_PostEvent (event_t *ev);
|
||||
|
||||
// Read an event from the event queue
|
||||
|
||||
event_t *D_PopEvent(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
55
src/d_items.c
Normal file
55
src/d_items.c
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
|
||||
// We are referring to sprite numbers.
|
||||
#include "info.h"
|
||||
|
||||
#include "d_items.h"
|
||||
|
||||
//
|
||||
// PSPRITE ACTIONS for waepons.
|
||||
// This struct controls the weapon animations.
|
||||
//
|
||||
// Each entry is:
|
||||
// ammo/amunition type
|
||||
// upstate
|
||||
// downstate
|
||||
// readystate
|
||||
// atkstate, i.e. attack/fire/hit frame
|
||||
// flashstate, muzzle flash
|
||||
//
|
||||
weaponinfo_t weaponinfo[NUMWEAPONS] = {
|
||||
{// fist
|
||||
am_noammo, S_PUNCHUP, S_PUNCHDOWN, S_PUNCH, S_PUNCH1, S_NULL},
|
||||
{// pistol
|
||||
am_clip, S_PISTOLUP, S_PISTOLDOWN, S_PISTOL, S_PISTOL1, S_PISTOLFLASH},
|
||||
{// shotgun
|
||||
am_shell, S_SGUNUP, S_SGUNDOWN, S_SGUN, S_SGUN1, S_SGUNFLASH1},
|
||||
{// chaingun
|
||||
am_clip, S_CHAINUP, S_CHAINDOWN, S_CHAIN, S_CHAIN1, S_CHAINFLASH1},
|
||||
{// missile launcher
|
||||
am_misl, S_MISSILEUP, S_MISSILEDOWN, S_MISSILE, S_MISSILE1,
|
||||
S_MISSILEFLASH1},
|
||||
{// plasma rifle
|
||||
am_cell, S_PLASMAUP, S_PLASMADOWN, S_PLASMA, S_PLASMA1, S_PLASMAFLASH1},
|
||||
{// bfg 9000
|
||||
am_cell, S_BFGUP, S_BFGDOWN, S_BFG, S_BFG1, S_BFGFLASH1},
|
||||
{// chainsaw
|
||||
am_noammo, S_SAWUP, S_SAWDOWN, S_SAW, S_SAW1, S_NULL},
|
||||
{// super shotgun
|
||||
am_shell, S_DSGUNUP, S_DSGUNDOWN, S_DSGUN, S_DSGUN1, S_DSGUNFLASH1},
|
||||
};
|
||||
37
src/d_items.h
Normal file
37
src/d_items.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Items: key cards, artifacts, weapon, ammunition.
|
||||
//
|
||||
|
||||
#ifndef __D_ITEMS__
|
||||
#define __D_ITEMS__
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
// Weapon info: sprite frames, ammunition use.
|
||||
typedef struct {
|
||||
ammotype_t ammo;
|
||||
int upstate;
|
||||
int downstate;
|
||||
int readystate;
|
||||
int atkstate;
|
||||
int flashstate;
|
||||
|
||||
} weaponinfo_t;
|
||||
|
||||
extern weaponinfo_t weaponinfo[NUMWEAPONS];
|
||||
|
||||
#endif
|
||||
489
src/d_iwad.c
Normal file
489
src/d_iwad.c
Normal file
@@ -0,0 +1,489 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Search for and locate an IWAD file, and initialize according
|
||||
// to the IWAD type.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "d_iwad.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
static const iwad_t iwads[] =
|
||||
{
|
||||
{ "doom2.wad", doom2, commercial, "Doom II" },
|
||||
{ "plutonia.wad", pack_plut, commercial, "Final Doom: Plutonia Experiment" },
|
||||
{ "tnt.wad", pack_tnt, commercial, "Final Doom: TNT: Evilution" },
|
||||
{ "doom.wad", doom, retail, "Doom" },
|
||||
{ "doom1.wad", doom, shareware, "Doom Shareware" },
|
||||
{ "chex.wad", pack_chex, retail, "Chex Quest" },
|
||||
{ "hacx.wad", pack_hacx, commercial, "Hacx" },
|
||||
{ "freedm.wad", doom2, commercial, "FreeDM" },
|
||||
{ "freedoom2.wad", doom2, commercial, "Freedoom: Phase 2" },
|
||||
{ "freedoom1.wad", doom, retail, "Freedoom: Phase 1" },
|
||||
{ "heretic.wad", heretic, retail, "Heretic" },
|
||||
{ "heretic1.wad", heretic, shareware, "Heretic Shareware" },
|
||||
{ "hexen.wad", hexen, commercial, "Hexen" },
|
||||
//{ "strife0.wad", strife, commercial, "Strife" }, // haleyjd: STRIFE-FIXME
|
||||
{ "strife1.wad", strife, commercial, "Strife" },
|
||||
};
|
||||
|
||||
// Array of locations to search for IWAD files
|
||||
//
|
||||
// "128 IWAD search directories should be enough for anybody".
|
||||
|
||||
#define MAX_IWAD_DIRS 128
|
||||
|
||||
static boolean iwad_dirs_built = false;
|
||||
static char *iwad_dirs[MAX_IWAD_DIRS];
|
||||
static int num_iwad_dirs = 0;
|
||||
|
||||
static void AddIWADDir(char *dir)
|
||||
{
|
||||
if (num_iwad_dirs < MAX_IWAD_DIRS)
|
||||
{
|
||||
iwad_dirs[num_iwad_dirs] = dir;
|
||||
++num_iwad_dirs;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the specified path is a path to a file
|
||||
// of the specified name.
|
||||
|
||||
static boolean DirIsFile(char *path, char *filename)
|
||||
{
|
||||
size_t path_len;
|
||||
size_t filename_len;
|
||||
|
||||
path_len = strlen(path);
|
||||
filename_len = strlen(filename);
|
||||
|
||||
return path_len >= filename_len + 1
|
||||
&& path[path_len - filename_len - 1] == DIR_SEPARATOR
|
||||
&& !strcasecmp(&path[path_len - filename_len], filename);
|
||||
}
|
||||
|
||||
// Check if the specified directory contains the specified IWAD
|
||||
// file, returning the full path to the IWAD if found, or NULL
|
||||
// if not found.
|
||||
|
||||
static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
|
||||
{
|
||||
char *filename;
|
||||
char *probe;
|
||||
|
||||
// As a special case, the "directory" may refer directly to an
|
||||
// IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.
|
||||
|
||||
probe = M_FileCaseExists(dir);
|
||||
if (DirIsFile(dir, iwadname) && probe != NULL)
|
||||
{
|
||||
return probe;
|
||||
}
|
||||
|
||||
// Construct the full path to the IWAD if it is located in
|
||||
// this directory, and check if it exists.
|
||||
|
||||
if (!strcmp(dir, "."))
|
||||
{
|
||||
filename = M_StringDuplicate(iwadname);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = M_StringJoin(dir, DIR_SEPARATOR_S, iwadname, NULL);
|
||||
}
|
||||
|
||||
probe = M_FileCaseExists(filename);
|
||||
if (probe != NULL)
|
||||
{
|
||||
return probe;
|
||||
}
|
||||
|
||||
free(filename);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Search a directory to try to find an IWAD
|
||||
// Returns the location of the IWAD if found, otherwise NULL.
|
||||
|
||||
static char *SearchDirectoryForIWAD(char *dir, int mask, GameMission_t *mission)
|
||||
{
|
||||
char *filename;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<arrlen(iwads); ++i)
|
||||
{
|
||||
if (((1 << iwads[i].mission) & mask) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
filename = CheckDirectoryHasIWAD(dir, iwads[i].name);
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
*mission = iwads[i].mission;
|
||||
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// When given an IWAD with the '-iwad' parameter,
|
||||
// attempt to identify it by its name.
|
||||
|
||||
static GameMission_t IdentifyIWADByName(char *name, int mask)
|
||||
{
|
||||
size_t i;
|
||||
GameMission_t mission;
|
||||
char *p;
|
||||
|
||||
p = strrchr(name, DIR_SEPARATOR);
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
name = p + 1;
|
||||
}
|
||||
|
||||
mission = none;
|
||||
|
||||
for (i=0; i<arrlen(iwads); ++i)
|
||||
{
|
||||
// Check if the filename is this IWAD name.
|
||||
|
||||
// Only use supported missions:
|
||||
|
||||
if (((1 << iwads[i].mission) & mask) == 0)
|
||||
continue;
|
||||
|
||||
// Check if it ends in this IWAD name.
|
||||
|
||||
if (!strcasecmp(name, iwads[i].name))
|
||||
{
|
||||
mission = iwads[i].mission;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mission;
|
||||
}
|
||||
|
||||
// Add IWAD directories parsed from splitting a path string containing
|
||||
// paths separated by PATH_SEPARATOR. 'suffix' is a string to concatenate
|
||||
// to the end of the paths before adding them.
|
||||
static void AddIWADPath(char *path, char *suffix)
|
||||
{
|
||||
char *left, *p;
|
||||
|
||||
path = M_StringDuplicate(path);
|
||||
|
||||
// Split into individual dirs within the list.
|
||||
left = path;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
p = strchr(left, PATH_SEPARATOR);
|
||||
if (p != NULL)
|
||||
{
|
||||
// Break at the separator and use the left hand side
|
||||
// as another iwad dir
|
||||
*p = '\0';
|
||||
|
||||
AddIWADDir(M_StringJoin(left, suffix, NULL));
|
||||
left = p + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AddIWADDir(M_StringJoin(left, suffix, NULL));
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
//
|
||||
// Build a list of IWAD files
|
||||
//
|
||||
|
||||
static void BuildIWADDirList(void)
|
||||
{
|
||||
char *env;
|
||||
|
||||
if (iwad_dirs_built)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Look in the current directory. Doom always does this.
|
||||
AddIWADDir(".");
|
||||
|
||||
// Add DOOMWADDIR if it is in the environment
|
||||
env = getenv("DOOMWADDIR");
|
||||
if (env != NULL)
|
||||
{
|
||||
AddIWADDir(env);
|
||||
}
|
||||
|
||||
// Add dirs from DOOMWADPATH:
|
||||
env = getenv("DOOMWADPATH");
|
||||
if (env != NULL)
|
||||
{
|
||||
AddIWADPath(env, "");
|
||||
}
|
||||
|
||||
|
||||
// Don't run this function again.
|
||||
|
||||
iwad_dirs_built = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Searches WAD search paths for an WAD with a specific filename.
|
||||
//
|
||||
|
||||
char *D_FindWADByName(char *name)
|
||||
{
|
||||
char *path;
|
||||
char *probe;
|
||||
int i;
|
||||
|
||||
// Absolute path?
|
||||
|
||||
probe = M_FileCaseExists(name);
|
||||
if (probe != NULL)
|
||||
{
|
||||
return probe;
|
||||
}
|
||||
|
||||
BuildIWADDirList();
|
||||
|
||||
// Search through all IWAD paths for a file with the given name.
|
||||
|
||||
for (i=0; i<num_iwad_dirs; ++i)
|
||||
{
|
||||
// As a special case, if this is in DOOMWADDIR or DOOMWADPATH,
|
||||
// the "directory" may actually refer directly to an IWAD
|
||||
// file.
|
||||
|
||||
probe = M_FileCaseExists(iwad_dirs[i]);
|
||||
if (DirIsFile(iwad_dirs[i], name) && probe != NULL)
|
||||
{
|
||||
return probe;
|
||||
}
|
||||
|
||||
// Construct a string for the full path
|
||||
|
||||
path = M_StringJoin(iwad_dirs[i], DIR_SEPARATOR_S, name, NULL);
|
||||
|
||||
probe = M_FileCaseExists(path);
|
||||
if (probe != NULL)
|
||||
{
|
||||
return probe;
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
// File not found
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// D_TryWADByName
|
||||
//
|
||||
// Searches for a WAD by its filename, or passes through the filename
|
||||
// if not found.
|
||||
//
|
||||
|
||||
char *D_TryFindWADByName(char *filename)
|
||||
{
|
||||
char *result;
|
||||
|
||||
result = D_FindWADByName(filename);
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FindIWAD
|
||||
// Checks availability of IWAD files by name,
|
||||
// to determine whether registered/commercial features
|
||||
// should be executed (notably loading PWADs).
|
||||
//
|
||||
|
||||
char *D_FindIWAD(int mask, GameMission_t *mission)
|
||||
{
|
||||
char *result;
|
||||
char *iwadfile;
|
||||
int iwadparm;
|
||||
int i;
|
||||
|
||||
// Check for the -iwad parameter
|
||||
|
||||
//!
|
||||
// Specify an IWAD file to use.
|
||||
//
|
||||
// @arg <file>
|
||||
//
|
||||
|
||||
iwadparm = M_CheckParmWithArgs("-iwad", 1);
|
||||
|
||||
if (iwadparm)
|
||||
{
|
||||
// Search through IWAD dirs for an IWAD with the given name.
|
||||
|
||||
iwadfile = myargv[iwadparm + 1];
|
||||
|
||||
result = D_FindWADByName(iwadfile);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
I_Error("IWAD file '%s' not found!", iwadfile);
|
||||
}
|
||||
|
||||
*mission = IdentifyIWADByName(result, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search through the list and look for an IWAD
|
||||
|
||||
result = NULL;
|
||||
|
||||
BuildIWADDirList();
|
||||
|
||||
for (i=0; result == NULL && i<num_iwad_dirs; ++i)
|
||||
{
|
||||
result = SearchDirectoryForIWAD(iwad_dirs[i], mask, mission);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find all IWADs in the IWAD search path matching the given mask.
|
||||
|
||||
const iwad_t **D_FindAllIWADs(int mask)
|
||||
{
|
||||
const iwad_t **result;
|
||||
int result_len;
|
||||
char *filename;
|
||||
int i;
|
||||
|
||||
result = malloc(sizeof(iwad_t *) * (arrlen(iwads) + 1));
|
||||
result_len = 0;
|
||||
|
||||
// Try to find all IWADs
|
||||
|
||||
for (i=0; i<arrlen(iwads); ++i)
|
||||
{
|
||||
if (((1 << iwads[i].mission) & mask) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
filename = D_FindWADByName(iwads[i].name);
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
result[result_len] = &iwads[i];
|
||||
++result_len;
|
||||
}
|
||||
}
|
||||
|
||||
// End of list
|
||||
|
||||
result[result_len] = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the IWAD name used for savegames.
|
||||
//
|
||||
|
||||
char *D_SaveGameIWADName(GameMission_t gamemission)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
// Determine the IWAD name to use for savegames.
|
||||
// This determines the directory the savegame files get put into.
|
||||
//
|
||||
// Note that we match on gamemission rather than on IWAD name.
|
||||
// This ensures that doom1.wad and doom.wad saves are stored
|
||||
// in the same place.
|
||||
|
||||
for (i=0; i<arrlen(iwads); ++i)
|
||||
{
|
||||
if (gamemission == iwads[i].mission)
|
||||
{
|
||||
return iwads[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
// Default fallback:
|
||||
|
||||
return "unknown.wad";
|
||||
}
|
||||
|
||||
char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < arrlen(iwads); ++i)
|
||||
{
|
||||
if (iwads[i].mission == mission && iwads[i].mode == mode)
|
||||
{
|
||||
return iwads[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown.wad";
|
||||
}
|
||||
|
||||
char *D_SuggestGameName(GameMission_t mission, GameMode_t mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < arrlen(iwads); ++i)
|
||||
{
|
||||
if (iwads[i].mission == mission
|
||||
&& (mode == indetermined || iwads[i].mode == mode))
|
||||
{
|
||||
return iwads[i].description;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown game?";
|
||||
}
|
||||
|
||||
52
src/d_iwad.h
Normal file
52
src/d_iwad.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Find IWAD and initialize according to IWAD type.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __D_IWAD__
|
||||
#define __D_IWAD__
|
||||
|
||||
#include "d_mode.h"
|
||||
|
||||
#define IWAD_MASK_DOOM ((1 << doom) \
|
||||
| (1 << doom2) \
|
||||
| (1 << pack_tnt) \
|
||||
| (1 << pack_plut) \
|
||||
| (1 << pack_chex) \
|
||||
| (1 << pack_hacx))
|
||||
#define IWAD_MASK_HERETIC (1 << heretic)
|
||||
#define IWAD_MASK_HEXEN (1 << hexen)
|
||||
#define IWAD_MASK_STRIFE (1 << strife)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
GameMission_t mission;
|
||||
GameMode_t mode;
|
||||
char *description;
|
||||
} iwad_t;
|
||||
|
||||
char *D_FindWADByName(char *filename);
|
||||
char *D_TryFindWADByName(char *filename);
|
||||
char *D_FindIWAD(int mask, GameMission_t *mission);
|
||||
const iwad_t **D_FindAllIWADs(int mask);
|
||||
char *D_SaveGameIWADName(GameMission_t gamemission);
|
||||
char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode);
|
||||
char *D_SuggestGameName(GameMission_t mission, GameMode_t mode);
|
||||
void D_CheckCorrectIWAD(GameMission_t mission);
|
||||
|
||||
#endif
|
||||
|
||||
882
src/d_loop.c
Normal file
882
src/d_loop.c
Normal file
@@ -0,0 +1,882 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Main loop code.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "d_event.h"
|
||||
#include "d_loop.h"
|
||||
#include "d_ticcmd.h"
|
||||
#include "i_system.h"
|
||||
#include "i_timer.h"
|
||||
#include "i_video.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_fixed.h"
|
||||
#include "net_client.h"
|
||||
#include "net_io.h"
|
||||
#include "net_loop.h"
|
||||
#include "net_query.h"
|
||||
#include "net_sdl.h"
|
||||
#include "net_server.h"
|
||||
#include "w_file.h"
|
||||
|
||||
// The complete set of data for a particular tic.
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ticcmd_t cmds[NET_MAXPLAYERS];
|
||||
boolean ingame[NET_MAXPLAYERS];
|
||||
} ticcmd_set_t;
|
||||
|
||||
// Maximum time that we wait in TryRunTics() for netgame data to be
|
||||
// received before we bail out and render a frame anyway.
|
||||
// Vanilla Doom used 20 for this value, but we use a smaller value
|
||||
// instead for better responsiveness of the menu when we're stuck.
|
||||
#define MAX_NETGAME_STALL_TICS 5
|
||||
|
||||
//
|
||||
// gametic is the tic about to (or currently being) run
|
||||
// maketic is the tic that hasn't had control made for it yet
|
||||
// recvtic is the latest tic received from the server.
|
||||
//
|
||||
// a gametic cannot be run until ticcmds are received for it
|
||||
// from all players.
|
||||
//
|
||||
|
||||
static ticcmd_set_t ticdata[BACKUPTICS];
|
||||
|
||||
// The index of the next tic to be made (with a call to BuildTiccmd).
|
||||
|
||||
static int maketic;
|
||||
|
||||
// The number of complete tics received from the server so far.
|
||||
|
||||
static int recvtic;
|
||||
|
||||
// The number of tics that have been run (using RunTic) so far.
|
||||
|
||||
int gametic;
|
||||
|
||||
// When set to true, a single tic is run each time TryRunTics() is called.
|
||||
// This is used for -timedemo mode.
|
||||
|
||||
boolean singletics = false;
|
||||
|
||||
// Index of the local player.
|
||||
|
||||
static int localplayer;
|
||||
|
||||
// Used for original sync code.
|
||||
|
||||
static int skiptics = 0;
|
||||
|
||||
// Reduce the bandwidth needed by sampling game input less and transmitting
|
||||
// less. If ticdup is 2, sample half normal, 3 = one third normal, etc.
|
||||
|
||||
int ticdup;
|
||||
|
||||
// Amount to offset the timer for game sync.
|
||||
|
||||
fixed_t offsetms;
|
||||
|
||||
// Use new client syncronisation code
|
||||
|
||||
static boolean new_sync = true;
|
||||
|
||||
// Callback functions for loop code.
|
||||
|
||||
static loop_interface_t *loop_interface = NULL;
|
||||
|
||||
// Current players in the multiplayer game.
|
||||
// This is distinct from playeringame[] used by the game code, which may
|
||||
// modify playeringame[] when playing back multiplayer demos.
|
||||
|
||||
static boolean local_playeringame[NET_MAXPLAYERS];
|
||||
|
||||
// Requested player class "sent" to the server on connect.
|
||||
// If we are only doing a single player game then this needs to be remembered
|
||||
// and saved in the game settings.
|
||||
|
||||
static int player_class;
|
||||
|
||||
|
||||
// 35 fps clock adjusted by offsetms milliseconds
|
||||
|
||||
static int GetAdjustedTime(void)
|
||||
{
|
||||
int time_ms;
|
||||
|
||||
time_ms = I_GetTimeMS();
|
||||
|
||||
if (new_sync)
|
||||
{
|
||||
// Use the adjustments from net_client.c only if we are
|
||||
// using the new sync mode.
|
||||
|
||||
time_ms += (offsetms / FRACUNIT);
|
||||
}
|
||||
|
||||
return (time_ms * TICRATE) / 1000;
|
||||
}
|
||||
|
||||
static boolean BuildNewTic(void)
|
||||
{
|
||||
int gameticdiv;
|
||||
ticcmd_t cmd;
|
||||
|
||||
gameticdiv = gametic/ticdup;
|
||||
|
||||
I_StartTic ();
|
||||
loop_interface->ProcessEvents();
|
||||
|
||||
// Always run the menu
|
||||
|
||||
loop_interface->RunMenu();
|
||||
|
||||
if (drone)
|
||||
{
|
||||
// In drone mode, do not generate any ticcmds.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_sync)
|
||||
{
|
||||
// If playing single player, do not allow tics to buffer
|
||||
// up very far
|
||||
|
||||
if (!net_client_connected && maketic - gameticdiv > 2)
|
||||
return false;
|
||||
|
||||
// Never go more than ~200ms ahead
|
||||
|
||||
if (maketic - gameticdiv > 8)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maketic - gameticdiv >= 5)
|
||||
return false;
|
||||
}
|
||||
|
||||
//printf ("mk:%i ",maketic);
|
||||
memset(&cmd, 0, sizeof(ticcmd_t));
|
||||
loop_interface->BuildTiccmd(&cmd, maketic);
|
||||
|
||||
if (net_client_connected)
|
||||
{
|
||||
NET_CL_SendTiccmd(&cmd, maketic);
|
||||
}
|
||||
|
||||
ticdata[maketic % BACKUPTICS].cmds[localplayer] = cmd;
|
||||
ticdata[maketic % BACKUPTICS].ingame[localplayer] = true;
|
||||
|
||||
++maketic;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// NetUpdate
|
||||
// Builds ticcmds for console player,
|
||||
// sends out a packet
|
||||
//
|
||||
int lasttime;
|
||||
|
||||
void NetUpdate (void)
|
||||
{
|
||||
int nowtime;
|
||||
int newtics;
|
||||
int i;
|
||||
|
||||
// If we are running with singletics (timing a demo), this
|
||||
// is all done separately.
|
||||
|
||||
if (singletics)
|
||||
return;
|
||||
|
||||
// Run network subsystems
|
||||
|
||||
NET_CL_Run();
|
||||
NET_SV_Run();
|
||||
|
||||
// check time
|
||||
nowtime = GetAdjustedTime() / ticdup;
|
||||
newtics = nowtime - lasttime;
|
||||
|
||||
lasttime = nowtime;
|
||||
|
||||
if (skiptics <= newtics)
|
||||
{
|
||||
newtics -= skiptics;
|
||||
skiptics = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
skiptics -= newtics;
|
||||
newtics = 0;
|
||||
}
|
||||
|
||||
// build new ticcmds for console player
|
||||
|
||||
for (i=0 ; i<newtics ; i++)
|
||||
{
|
||||
if (!BuildNewTic())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void D_Disconnected(void)
|
||||
{
|
||||
// In drone mode, the game cannot continue once disconnected.
|
||||
|
||||
if (drone)
|
||||
{
|
||||
I_Error("Disconnected from server in drone mode.");
|
||||
}
|
||||
|
||||
// disconnected from server
|
||||
|
||||
printf("Disconnected from server.\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Invoked by the network engine when a complete set of ticcmds is
|
||||
// available.
|
||||
//
|
||||
|
||||
void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Disconnected from server?
|
||||
|
||||
if (ticcmds == NULL && players_mask == NULL)
|
||||
{
|
||||
D_Disconnected();
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < NET_MAXPLAYERS; ++i)
|
||||
{
|
||||
if (!drone && i == localplayer)
|
||||
{
|
||||
// This is us. Don't overwrite it.
|
||||
}
|
||||
else
|
||||
{
|
||||
ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
|
||||
ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
++recvtic;
|
||||
}
|
||||
|
||||
//
|
||||
// Start game loop
|
||||
//
|
||||
// Called after the screen is set but before the game starts running.
|
||||
//
|
||||
|
||||
void D_StartGameLoop(void)
|
||||
{
|
||||
lasttime = GetAdjustedTime() / ticdup;
|
||||
}
|
||||
|
||||
//
|
||||
// Block until the game start message is received from the server.
|
||||
//
|
||||
|
||||
static void BlockUntilStart(net_gamesettings_t *settings,
|
||||
netgame_startup_callback_t callback)
|
||||
{
|
||||
while (!NET_CL_GetSettings(settings))
|
||||
{
|
||||
NET_CL_Run();
|
||||
NET_SV_Run();
|
||||
|
||||
if (!net_client_connected)
|
||||
{
|
||||
I_Error("Lost connection to server");
|
||||
}
|
||||
|
||||
if (callback != NULL && !callback(net_client_wait_data.ready_players,
|
||||
net_client_wait_data.num_players))
|
||||
{
|
||||
I_Error("Netgame startup aborted.");
|
||||
}
|
||||
|
||||
I_Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
void D_StartNetGame(net_gamesettings_t *settings,
|
||||
netgame_startup_callback_t callback)
|
||||
{
|
||||
int i;
|
||||
|
||||
offsetms = 0;
|
||||
recvtic = 0;
|
||||
|
||||
settings->consoleplayer = 0;
|
||||
settings->num_players = 1;
|
||||
settings->player_classes[0] = player_class;
|
||||
|
||||
//!
|
||||
// @category net
|
||||
//
|
||||
// Use new network client sync code rather than the classic
|
||||
// sync code. This is currently disabled by default because it
|
||||
// has some bugs.
|
||||
//
|
||||
if (M_CheckParm("-newsync") > 0)
|
||||
settings->new_sync = 1;
|
||||
else
|
||||
settings->new_sync = 0;
|
||||
|
||||
// TODO: New sync code is not enabled by default because it's
|
||||
// currently broken.
|
||||
//if (M_CheckParm("-oldsync") > 0)
|
||||
// settings->new_sync = 0;
|
||||
//else
|
||||
// settings->new_sync = 1;
|
||||
|
||||
//!
|
||||
// @category net
|
||||
// @arg <n>
|
||||
//
|
||||
// Send n extra tics in every packet as insurance against dropped
|
||||
// packets.
|
||||
//
|
||||
|
||||
i = M_CheckParmWithArgs("-extratics", 1);
|
||||
|
||||
if (i > 0)
|
||||
settings->extratics = atoi(myargv[i+1]);
|
||||
else
|
||||
settings->extratics = 1;
|
||||
|
||||
//!
|
||||
// @category net
|
||||
// @arg <n>
|
||||
//
|
||||
// Reduce the resolution of the game by a factor of n, reducing
|
||||
// the amount of network bandwidth needed.
|
||||
//
|
||||
|
||||
i = M_CheckParmWithArgs("-dup", 1);
|
||||
|
||||
if (i > 0)
|
||||
settings->ticdup = atoi(myargv[i+1]);
|
||||
else
|
||||
settings->ticdup = 1;
|
||||
|
||||
if (net_client_connected)
|
||||
{
|
||||
// Send our game settings and block until game start is received
|
||||
// from the server.
|
||||
|
||||
NET_CL_StartGame(settings);
|
||||
BlockUntilStart(settings, callback);
|
||||
|
||||
// Read the game settings that were received.
|
||||
|
||||
NET_CL_GetSettings(settings);
|
||||
}
|
||||
|
||||
if (drone)
|
||||
{
|
||||
settings->consoleplayer = 0;
|
||||
}
|
||||
|
||||
// Set the local player and playeringame[] values.
|
||||
|
||||
localplayer = settings->consoleplayer;
|
||||
|
||||
for (i = 0; i < NET_MAXPLAYERS; ++i)
|
||||
{
|
||||
local_playeringame[i] = i < settings->num_players;
|
||||
}
|
||||
|
||||
// Copy settings to global variables.
|
||||
|
||||
ticdup = settings->ticdup;
|
||||
new_sync = settings->new_sync;
|
||||
|
||||
// TODO: Message disabled until we fix new_sync.
|
||||
//if (!new_sync)
|
||||
//{
|
||||
// printf("Syncing netgames like Vanilla Doom.\n");
|
||||
//}
|
||||
}
|
||||
|
||||
boolean D_InitNetGame(net_connect_data_t *connect_data)
|
||||
{
|
||||
boolean result = false;
|
||||
net_addr_t *addr = NULL;
|
||||
int i;
|
||||
|
||||
// Call D_QuitNetGame on exit:
|
||||
|
||||
I_AtExit(D_QuitNetGame, true);
|
||||
|
||||
player_class = connect_data->player_class;
|
||||
|
||||
//!
|
||||
// @category net
|
||||
//
|
||||
// Start a multiplayer server, listening for connections.
|
||||
//
|
||||
|
||||
if (M_CheckParm("-server") > 0
|
||||
|| M_CheckParm("-privateserver") > 0)
|
||||
{
|
||||
NET_SV_Init();
|
||||
NET_SV_AddModule(&net_loop_server_module);
|
||||
NET_SV_AddModule(&net_sdl_module);
|
||||
NET_SV_RegisterWithMaster();
|
||||
|
||||
net_loop_client_module.InitClient();
|
||||
addr = net_loop_client_module.ResolveAddress(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
//!
|
||||
// @category net
|
||||
//
|
||||
// Automatically search the local LAN for a multiplayer
|
||||
// server and join it.
|
||||
//
|
||||
|
||||
i = M_CheckParm("-autojoin");
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
addr = NET_FindLANServer();
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
I_Error("No server found on local LAN");
|
||||
}
|
||||
}
|
||||
|
||||
//!
|
||||
// @arg <address>
|
||||
// @category net
|
||||
//
|
||||
// Connect to a multiplayer server running on the given
|
||||
// address.
|
||||
//
|
||||
|
||||
i = M_CheckParmWithArgs("-connect", 1);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
net_sdl_module.InitClient();
|
||||
addr = net_sdl_module.ResolveAddress(myargv[i+1]);
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
I_Error("Unable to resolve '%s'\n", myargv[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addr != NULL)
|
||||
{
|
||||
if (M_CheckParm("-drone") > 0)
|
||||
{
|
||||
connect_data->drone = true;
|
||||
}
|
||||
|
||||
if (!NET_CL_Connect(addr, connect_data))
|
||||
{
|
||||
I_Error("D_InitNetGame: Failed to connect to %s\n",
|
||||
NET_AddrToString(addr));
|
||||
}
|
||||
|
||||
printf("D_InitNetGame: Connected to %s\n", NET_AddrToString(addr));
|
||||
|
||||
// Wait for launch message received from server.
|
||||
|
||||
/*NET_WaitForLaunch();*/
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// D_QuitNetGame
|
||||
// Called before quitting to leave a net game
|
||||
// without hanging the other players
|
||||
//
|
||||
void D_QuitNetGame (void)
|
||||
{
|
||||
NET_SV_Shutdown();
|
||||
NET_CL_Disconnect();
|
||||
}
|
||||
|
||||
static int GetLowTic(void)
|
||||
{
|
||||
int lowtic;
|
||||
|
||||
lowtic = maketic;
|
||||
|
||||
if (net_client_connected)
|
||||
{
|
||||
if (drone || recvtic < lowtic)
|
||||
{
|
||||
lowtic = recvtic;
|
||||
}
|
||||
}
|
||||
|
||||
return lowtic;
|
||||
}
|
||||
|
||||
static int frameon;
|
||||
static int frameskip[4];
|
||||
static int oldnettics;
|
||||
|
||||
static void OldNetSync(void)
|
||||
{
|
||||
unsigned int i;
|
||||
int keyplayer = -1;
|
||||
|
||||
frameon++;
|
||||
|
||||
// ideally maketic should be 1 - 3 tics above lowtic
|
||||
// if we are consistantly slower, speed up time
|
||||
|
||||
for (i=0 ; i<NET_MAXPLAYERS ; i++)
|
||||
{
|
||||
if (local_playeringame[i])
|
||||
{
|
||||
keyplayer = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyplayer < 0)
|
||||
{
|
||||
// If there are no players, we can never advance anyway
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (localplayer == keyplayer)
|
||||
{
|
||||
// the key player does not adapt
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maketic <= recvtic)
|
||||
{
|
||||
lasttime--;
|
||||
// printf ("-");
|
||||
}
|
||||
|
||||
frameskip[frameon & 3] = oldnettics > recvtic;
|
||||
oldnettics = maketic;
|
||||
|
||||
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
|
||||
{
|
||||
skiptics = 1;
|
||||
// printf ("+");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if there are players in the game:
|
||||
|
||||
static boolean PlayersInGame(void)
|
||||
{
|
||||
boolean result = false;
|
||||
unsigned int i;
|
||||
|
||||
// If we are connected to a server, check if there are any players
|
||||
// in the game.
|
||||
|
||||
if (net_client_connected)
|
||||
{
|
||||
for (i = 0; i < NET_MAXPLAYERS; ++i)
|
||||
{
|
||||
result = result || local_playeringame[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Whether single or multi-player, unless we are running as a drone,
|
||||
// we are in the game.
|
||||
|
||||
if (!drone)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// When using ticdup, certain values must be cleared out when running
|
||||
// the duplicate ticcmds.
|
||||
|
||||
static void TicdupSquash(ticcmd_set_t *set)
|
||||
{
|
||||
ticcmd_t *cmd;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NET_MAXPLAYERS ; ++i)
|
||||
{
|
||||
cmd = &set->cmds[i];
|
||||
cmd->chatchar = 0;
|
||||
if (cmd->buttons & BT_SPECIAL)
|
||||
cmd->buttons = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// When running in single player mode, clear all the ingame[] array
|
||||
// except the local player.
|
||||
|
||||
static void SinglePlayerClear(ticcmd_set_t *set)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NET_MAXPLAYERS; ++i)
|
||||
{
|
||||
if (i != localplayer)
|
||||
{
|
||||
set->ingame[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TryRunTics
|
||||
//
|
||||
|
||||
void TryRunTics (void)
|
||||
{
|
||||
int i;
|
||||
int lowtic;
|
||||
int entertic;
|
||||
static int oldentertics;
|
||||
int realtics;
|
||||
int availabletics;
|
||||
int counts;
|
||||
|
||||
// get real tics
|
||||
entertic = I_GetTime() / ticdup;
|
||||
realtics = entertic - oldentertics;
|
||||
oldentertics = entertic;
|
||||
|
||||
// in singletics mode, run a single tic every time this function
|
||||
// is called.
|
||||
|
||||
if (singletics)
|
||||
{
|
||||
BuildNewTic();
|
||||
}
|
||||
else
|
||||
{
|
||||
NetUpdate ();
|
||||
}
|
||||
|
||||
lowtic = GetLowTic();
|
||||
|
||||
availabletics = lowtic - gametic/ticdup;
|
||||
|
||||
// decide how many tics to run
|
||||
|
||||
if (new_sync)
|
||||
{
|
||||
counts = availabletics;
|
||||
}
|
||||
else
|
||||
{
|
||||
// decide how many tics to run
|
||||
if (realtics < availabletics-1)
|
||||
counts = realtics+1;
|
||||
else if (realtics < availabletics)
|
||||
counts = realtics;
|
||||
else
|
||||
counts = availabletics;
|
||||
|
||||
if (counts < 1)
|
||||
counts = 1;
|
||||
|
||||
if (net_client_connected)
|
||||
{
|
||||
OldNetSync();
|
||||
}
|
||||
}
|
||||
|
||||
if (counts < 1)
|
||||
counts = 1;
|
||||
|
||||
// wait for new tics if needed
|
||||
while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
|
||||
{
|
||||
NetUpdate ();
|
||||
|
||||
lowtic = GetLowTic();
|
||||
|
||||
if (lowtic < gametic/ticdup)
|
||||
I_Error ("TryRunTics: lowtic < gametic");
|
||||
|
||||
// Still no tics to run? Sleep until some are available.
|
||||
if (lowtic < gametic/ticdup + counts)
|
||||
{
|
||||
// If we're in a netgame, we might spin forever waiting for
|
||||
// new network data to be received. So don't stay in here
|
||||
// forever - give the menu a chance to work.
|
||||
if (I_GetTime() / ticdup - entertic >= MAX_NETGAME_STALL_TICS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
I_Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
// run the count * ticdup dics
|
||||
while (counts--)
|
||||
{
|
||||
ticcmd_set_t *set;
|
||||
|
||||
if (!PlayersInGame())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
set = &ticdata[(gametic / ticdup) % BACKUPTICS];
|
||||
|
||||
if (!net_client_connected)
|
||||
{
|
||||
SinglePlayerClear(set);
|
||||
}
|
||||
|
||||
for (i=0 ; i<ticdup ; i++)
|
||||
{
|
||||
if (gametic/ticdup > lowtic)
|
||||
I_Error ("gametic>lowtic");
|
||||
|
||||
memcpy(local_playeringame, set->ingame, sizeof(local_playeringame));
|
||||
|
||||
loop_interface->RunTic(set->cmds, set->ingame);
|
||||
gametic++;
|
||||
|
||||
// modify command for duplicated tics
|
||||
|
||||
TicdupSquash(set);
|
||||
}
|
||||
|
||||
NetUpdate (); // check for new console commands
|
||||
}
|
||||
}
|
||||
|
||||
void D_RegisterLoopCallbacks(loop_interface_t *i)
|
||||
{
|
||||
loop_interface = i;
|
||||
}
|
||||
|
||||
// TODO: Move nonvanilla demo functions into a dedicated file.
|
||||
#include "m_misc.h"
|
||||
#include "w_wad.h"
|
||||
|
||||
static boolean StrictDemos(void)
|
||||
{
|
||||
//!
|
||||
// @category demo
|
||||
//
|
||||
// When recording or playing back demos, disable any extensions
|
||||
// of the vanilla demo format - record demos as vanilla would do,
|
||||
// and play back demos as vanilla would do.
|
||||
//
|
||||
return M_ParmExists("-strictdemos");
|
||||
}
|
||||
|
||||
// If the provided conditional value is true, we're trying to record
|
||||
// a demo file that will include a non-vanilla extension. The function
|
||||
// will return true if the conditional is true and it's allowed to use
|
||||
// this extension (no extensions are allowed if -strictdemos is given
|
||||
// on the command line). A warning is shown on the console using the
|
||||
// provided string describing the non-vanilla expansion.
|
||||
boolean D_NonVanillaRecord(boolean conditional, char *feature)
|
||||
{
|
||||
if (!conditional || StrictDemos())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Warning: Recording a demo file with a non-vanilla extension "
|
||||
"(%s). Use -strictdemos to disable this extension.\n",
|
||||
feature);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the given lump number corresponds to data from a .lmp
|
||||
// file, as opposed to a WAD.
|
||||
static boolean IsDemoFile(int lumpnum)
|
||||
{
|
||||
char *lower;
|
||||
boolean result;
|
||||
|
||||
lower = M_StringDuplicate(lumpinfo[lumpnum]->wad_file->path);
|
||||
M_ForceLowercase(lower);
|
||||
result = M_StringEndsWith(lower, ".lmp");
|
||||
free(lower);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// If the provided conditional value is true, we're trying to play back
|
||||
// a demo that includes a non-vanilla extension. We return true if the
|
||||
// conditional is true and it's allowed to use this extension, checking
|
||||
// that:
|
||||
// - The -strictdemos command line argument is not provided.
|
||||
// - The given lumpnum identifying the demo to play back identifies a
|
||||
// demo that comes from a .lmp file, not a .wad file.
|
||||
// - Before proceeding, a warning is shown to the user on the console.
|
||||
boolean D_NonVanillaPlayback(boolean conditional, int lumpnum,
|
||||
char *feature)
|
||||
{
|
||||
if (!conditional || StrictDemos())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDemoFile(lumpnum))
|
||||
{
|
||||
printf("Warning: WAD contains demo with a non-vanilla extension "
|
||||
"(%s)\n", feature);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Warning: Playing back a demo file with a non-vanilla extension "
|
||||
"(%s). Use -strictdemos to disable this extension.\n",
|
||||
feature);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
90
src/d_loop.h
Normal file
90
src/d_loop.h
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Main loop stuff.
|
||||
//
|
||||
|
||||
#ifndef __D_LOOP__
|
||||
#define __D_LOOP__
|
||||
|
||||
#include "d_ticcmd.h"
|
||||
#include "doomtype.h"
|
||||
#include "net_defs.h"
|
||||
|
||||
// Callback function invoked while waiting for the netgame to start.
|
||||
// The callback is invoked when new players are ready. The callback
|
||||
// should return true, or return false to abort startup.
|
||||
|
||||
typedef boolean (*netgame_startup_callback_t)(int ready_players,
|
||||
int num_players);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Read events from the event queue, and process them.
|
||||
|
||||
void (*ProcessEvents)();
|
||||
|
||||
// Given the current input state, fill in the fields of the specified
|
||||
// ticcmd_t structure with data for a new tic.
|
||||
|
||||
void (*BuildTiccmd)(ticcmd_t *cmd, int maketic);
|
||||
|
||||
// Advance the game forward one tic, using the specified player input.
|
||||
|
||||
void (*RunTic)(ticcmd_t *cmds, boolean *ingame);
|
||||
|
||||
// Run the menu (runs independently of the game).
|
||||
|
||||
void (*RunMenu)();
|
||||
} loop_interface_t;
|
||||
|
||||
// Register callback functions for the main loop code to use.
|
||||
void D_RegisterLoopCallbacks(loop_interface_t *i);
|
||||
|
||||
// Create any new ticcmds and broadcast to other players.
|
||||
void NetUpdate (void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame (void);
|
||||
|
||||
//? how many ticks to run?
|
||||
void TryRunTics (void);
|
||||
|
||||
// Called at start of game loop to initialize timers
|
||||
void D_StartGameLoop(void);
|
||||
|
||||
// Initialize networking code and connect to server.
|
||||
|
||||
boolean D_InitNetGame(net_connect_data_t *connect_data);
|
||||
|
||||
// Start game with specified settings. The structure will be updated
|
||||
// with the actual settings for the game.
|
||||
|
||||
void D_StartNetGame(net_gamesettings_t *settings,
|
||||
netgame_startup_callback_t callback);
|
||||
|
||||
extern boolean singletics;
|
||||
extern int gametic, ticdup;
|
||||
|
||||
// Check if it is permitted to record a demo with a non-vanilla feature.
|
||||
boolean D_NonVanillaRecord(boolean conditional, char *feature);
|
||||
|
||||
// Check if it is permitted to play back a demo with a non-vanilla feature.
|
||||
boolean D_NonVanillaPlayback(boolean conditional, int lumpnum,
|
||||
char *feature);
|
||||
|
||||
#endif
|
||||
|
||||
1295
src/d_main.c
Normal file
1295
src/d_main.c
Normal file
File diff suppressed because it is too large
Load Diff
45
src/d_main.h
Normal file
45
src/d_main.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System specific interface stuff.
|
||||
//
|
||||
|
||||
#ifndef __D_MAIN__
|
||||
#define __D_MAIN__
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
// Read events from all input devices
|
||||
|
||||
void D_ProcessEvents(void);
|
||||
|
||||
//
|
||||
// BASE LEVEL
|
||||
//
|
||||
void D_PageTicker(void);
|
||||
void D_PageDrawer(void);
|
||||
void D_AdvanceDemo(void);
|
||||
void D_DoAdvanceDemo(void);
|
||||
void D_StartTitle(void);
|
||||
|
||||
extern void D_DoomMain(void);
|
||||
|
||||
//
|
||||
// GLOBAL VARIABLES
|
||||
//
|
||||
|
||||
extern gameaction_t gameaction;
|
||||
|
||||
#endif
|
||||
212
src/d_mode.c
Normal file
212
src/d_mode.c
Normal file
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Functions and definitions relating to the game type and operational
|
||||
// mode.
|
||||
//
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "d_mode.h"
|
||||
|
||||
// Valid game mode/mission combinations, with the number of
|
||||
// episodes/maps for each.
|
||||
|
||||
static struct
|
||||
{
|
||||
GameMission_t mission;
|
||||
GameMode_t mode;
|
||||
int episode;
|
||||
int map;
|
||||
} valid_modes[] = {
|
||||
{ pack_chex, retail, 1, 5 },
|
||||
{ doom, shareware, 1, 9 },
|
||||
{ doom, registered, 3, 9 },
|
||||
{ doom, retail, 4, 9 },
|
||||
{ doom2, commercial, 1, 32 },
|
||||
{ pack_tnt, commercial, 1, 32 },
|
||||
{ pack_plut, commercial, 1, 32 },
|
||||
{ pack_hacx, commercial, 1, 32 },
|
||||
{ heretic, shareware, 1, 9 },
|
||||
{ heretic, registered, 3, 9 },
|
||||
{ heretic, retail, 5, 9 },
|
||||
{ hexen, commercial, 1, 60 },
|
||||
{ strife, commercial, 1, 34 },
|
||||
};
|
||||
|
||||
// Check that a gamemode+gamemission received over the network is valid.
|
||||
|
||||
boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<arrlen(valid_modes); ++i)
|
||||
{
|
||||
if (valid_modes[i].mode == mode && valid_modes[i].mission == mission)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
|
||||
int episode, int map)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Hacks for Heretic secret episodes
|
||||
|
||||
if (mission == heretic)
|
||||
{
|
||||
if (mode == retail && episode == 6)
|
||||
{
|
||||
return map >= 1 && map <= 3;
|
||||
}
|
||||
else if (mode == registered && episode == 4)
|
||||
{
|
||||
return map == 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the table entry for this mission/mode combination.
|
||||
|
||||
for (i=0; i<arrlen(valid_modes); ++i)
|
||||
{
|
||||
if (mission == valid_modes[i].mission
|
||||
&& mode == valid_modes[i].mode)
|
||||
{
|
||||
return episode >= 1 && episode <= valid_modes[i].episode
|
||||
&& map >= 1 && map <= valid_modes[i].map;
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown mode/mission combination
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the number of valid episodes for the specified mission/mode.
|
||||
|
||||
int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode)
|
||||
{
|
||||
int episode;
|
||||
|
||||
episode = 1;
|
||||
|
||||
while (D_ValidEpisodeMap(mission, mode, episode, 1))
|
||||
{
|
||||
++episode;
|
||||
}
|
||||
|
||||
return episode - 1;
|
||||
}
|
||||
|
||||
// Table of valid versions
|
||||
|
||||
static struct {
|
||||
GameMission_t mission;
|
||||
GameVersion_t version;
|
||||
} valid_versions[] = {
|
||||
{ doom, exe_doom_1_666 },
|
||||
{ doom, exe_doom_1_7 },
|
||||
{ doom, exe_doom_1_8 },
|
||||
{ doom, exe_doom_1_9 },
|
||||
{ doom, exe_hacx },
|
||||
{ doom, exe_ultimate },
|
||||
{ doom, exe_final },
|
||||
{ doom, exe_final2 },
|
||||
{ doom, exe_chex },
|
||||
{ heretic, exe_heretic_1_3 },
|
||||
{ hexen, exe_hexen_1_1 },
|
||||
{ strife, exe_strife_1_2 },
|
||||
{ strife, exe_strife_1_31 },
|
||||
};
|
||||
|
||||
boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version)
|
||||
{
|
||||
int i;
|
||||
|
||||
// All Doom variants can use the Doom versions.
|
||||
|
||||
if (mission == doom2 || mission == pack_plut || mission == pack_tnt
|
||||
|| mission == pack_hacx || mission == pack_chex)
|
||||
{
|
||||
mission = doom;
|
||||
}
|
||||
|
||||
for (i=0; i<arrlen(valid_versions); ++i)
|
||||
{
|
||||
if (valid_versions[i].mission == mission
|
||||
&& valid_versions[i].version == version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Does this mission type use ExMy form, rather than MAPxy form?
|
||||
|
||||
boolean D_IsEpisodeMap(GameMission_t mission)
|
||||
{
|
||||
switch (mission)
|
||||
{
|
||||
case doom:
|
||||
case heretic:
|
||||
case pack_chex:
|
||||
return true;
|
||||
|
||||
case none:
|
||||
case hexen:
|
||||
case doom2:
|
||||
case pack_hacx:
|
||||
case pack_tnt:
|
||||
case pack_plut:
|
||||
case strife:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char *D_GameMissionString(GameMission_t mission)
|
||||
{
|
||||
switch (mission)
|
||||
{
|
||||
case none:
|
||||
default:
|
||||
return "none";
|
||||
case doom:
|
||||
return "doom";
|
||||
case doom2:
|
||||
return "doom2";
|
||||
case pack_tnt:
|
||||
return "tnt";
|
||||
case pack_plut:
|
||||
return "plutonia";
|
||||
case pack_hacx:
|
||||
return "hacx";
|
||||
case pack_chex:
|
||||
return "chex";
|
||||
case heretic:
|
||||
return "heretic";
|
||||
case hexen:
|
||||
return "hexen";
|
||||
case strife:
|
||||
return "strife";
|
||||
}
|
||||
}
|
||||
|
||||
108
src/d_mode.h
Normal file
108
src/d_mode.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Functions and definitions relating to the game type and operational
|
||||
// mode.
|
||||
//
|
||||
|
||||
#ifndef __D_MODE__
|
||||
#define __D_MODE__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
// The "mission" controls what game we are playing.
|
||||
|
||||
typedef enum
|
||||
{
|
||||
doom, // Doom 1
|
||||
doom2, // Doom 2
|
||||
pack_tnt, // Final Doom: TNT: Evilution
|
||||
pack_plut, // Final Doom: The Plutonia Experiment
|
||||
pack_chex, // Chex Quest (modded doom)
|
||||
pack_hacx, // Hacx (modded doom2)
|
||||
heretic, // Heretic
|
||||
hexen, // Hexen
|
||||
strife, // Strife
|
||||
|
||||
none
|
||||
} GameMission_t;
|
||||
|
||||
// The "mode" allows more accurate specification of the game mode we are
|
||||
// in: eg. shareware vs. registered. So doom1.wad and doom.wad are the
|
||||
// same mission, but a different mode.
|
||||
|
||||
typedef enum
|
||||
{
|
||||
shareware, // Doom/Heretic shareware
|
||||
registered, // Doom/Heretic registered
|
||||
commercial, // Doom II/Hexen
|
||||
retail, // Ultimate Doom
|
||||
indetermined // Unknown.
|
||||
} GameMode_t;
|
||||
|
||||
// What version are we emulating?
|
||||
|
||||
typedef enum
|
||||
{
|
||||
exe_doom_1_2, // Doom 1.2: shareware and registered
|
||||
exe_doom_1_666, // Doom 1.666: for shareware, registered and commercial
|
||||
exe_doom_1_7, // Doom 1.7/1.7a: "
|
||||
exe_doom_1_8, // Doom 1.8: "
|
||||
exe_doom_1_9, // Doom 1.9: "
|
||||
exe_hacx, // Hacx
|
||||
exe_ultimate, // Ultimate Doom (retail)
|
||||
exe_final, // Final Doom
|
||||
exe_final2, // Final Doom (alternate exe)
|
||||
exe_chex, // Chex Quest executable (based on Final Doom)
|
||||
|
||||
exe_heretic_1_3, // Heretic 1.3
|
||||
|
||||
exe_hexen_1_1, // Hexen 1.1
|
||||
exe_strife_1_2, // Strife v1.2
|
||||
exe_strife_1_31 // Strife v1.31
|
||||
} GameVersion_t;
|
||||
|
||||
// What IWAD variant are we using?
|
||||
|
||||
typedef enum
|
||||
{
|
||||
vanilla, // Vanilla Doom
|
||||
freedoom, // FreeDoom: Phase 1 + 2
|
||||
freedm, // FreeDM
|
||||
bfgedition, // Doom Classic (Doom 3: BFG Edition)
|
||||
} GameVariant_t;
|
||||
|
||||
// Skill level.
|
||||
|
||||
typedef enum
|
||||
{
|
||||
sk_noitems = -1, // the "-skill 0" hack
|
||||
sk_baby = 0,
|
||||
sk_easy,
|
||||
sk_medium,
|
||||
sk_hard,
|
||||
sk_nightmare
|
||||
} skill_t;
|
||||
|
||||
boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode);
|
||||
boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version);
|
||||
boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
|
||||
int episode, int map);
|
||||
int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode);
|
||||
boolean D_IsEpisodeMap(GameMission_t mission);
|
||||
char *D_GameMissionString(GameMission_t mission);
|
||||
|
||||
#endif /* #ifndef __D_MODE__ */
|
||||
|
||||
247
src/d_net.c
Normal file
247
src/d_net.c
Normal file
@@ -0,0 +1,247 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// DOOM Network game communication and protocol,
|
||||
// all OS independend parts.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "d_loop.h"
|
||||
#include "d_main.h"
|
||||
#include "d_player.h"
|
||||
#include "d_ticcmd.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "doomtype.h"
|
||||
#include "g_game.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_menu.h"
|
||||
#include "m_misc.h"
|
||||
#include "net_defs.h"
|
||||
#include "tables.h"
|
||||
#include "w_checksum.h"
|
||||
#include "w_wad.h"
|
||||
|
||||
ticcmd_t *netcmds;
|
||||
|
||||
// Called when a player leaves the game
|
||||
|
||||
static void PlayerQuitGame(player_t *player) {
|
||||
static char exitmsg[80];
|
||||
unsigned int player_num;
|
||||
|
||||
player_num = player - players;
|
||||
|
||||
// Do this the same way as Vanilla Doom does, to allow dehacked
|
||||
// replacements of this message
|
||||
|
||||
M_StringCopy(exitmsg, "Player 1 left the game", sizeof(exitmsg));
|
||||
|
||||
exitmsg[7] += player_num;
|
||||
|
||||
playeringame[player_num] = false;
|
||||
players[consoleplayer].message = exitmsg;
|
||||
|
||||
// TODO: check if it is sensible to do this:
|
||||
|
||||
if (demorecording) {
|
||||
G_CheckDemoStatus();
|
||||
}
|
||||
}
|
||||
|
||||
static void RunTic(ticcmd_t *cmds, boolean *ingame) {
|
||||
extern boolean advancedemo;
|
||||
unsigned int i;
|
||||
|
||||
// Check for player quits.
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; ++i) {
|
||||
if (!demoplayback && playeringame[i] && !ingame[i]) {
|
||||
PlayerQuitGame(&players[i]);
|
||||
}
|
||||
}
|
||||
|
||||
netcmds = cmds;
|
||||
|
||||
// check that there are players in the game. if not, we cannot
|
||||
// run a tic.
|
||||
|
||||
if (advancedemo)
|
||||
D_DoAdvanceDemo();
|
||||
|
||||
G_Ticker();
|
||||
}
|
||||
|
||||
static loop_interface_t doom_loop_interface = {D_ProcessEvents, G_BuildTiccmd,
|
||||
RunTic, M_Ticker};
|
||||
|
||||
// Load game settings from the specified structure and
|
||||
// set global variables.
|
||||
|
||||
static void LoadGameSettings(net_gamesettings_t *settings) {
|
||||
unsigned int i;
|
||||
|
||||
deathmatch = settings->deathmatch;
|
||||
startepisode = settings->episode;
|
||||
startmap = settings->map;
|
||||
startskill = settings->skill;
|
||||
startloadgame = settings->loadgame;
|
||||
lowres_turn = settings->lowres_turn;
|
||||
nomonsters = settings->nomonsters;
|
||||
fastparm = settings->fast_monsters;
|
||||
respawnparm = settings->respawn_monsters;
|
||||
timelimit = settings->timelimit;
|
||||
consoleplayer = settings->consoleplayer;
|
||||
|
||||
if (lowres_turn) {
|
||||
printf("NOTE: Turning resolution is reduced; this is probably "
|
||||
"because there is a client recording a Vanilla demo.\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; ++i) {
|
||||
playeringame[i] = i < settings->num_players;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the game settings from global variables to the specified
|
||||
// game settings structure.
|
||||
|
||||
static void SaveGameSettings(net_gamesettings_t *settings) {
|
||||
// Fill in game settings structure with appropriate parameters
|
||||
// for the new game
|
||||
|
||||
settings->deathmatch = deathmatch;
|
||||
settings->episode = startepisode;
|
||||
settings->map = startmap;
|
||||
settings->skill = startskill;
|
||||
settings->loadgame = startloadgame;
|
||||
settings->gameversion = gameversion;
|
||||
settings->nomonsters = nomonsters;
|
||||
settings->fast_monsters = fastparm;
|
||||
settings->respawn_monsters = respawnparm;
|
||||
settings->timelimit = timelimit;
|
||||
|
||||
settings->lowres_turn =
|
||||
M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0;
|
||||
}
|
||||
|
||||
static void InitConnectData(net_connect_data_t *connect_data) {
|
||||
connect_data->max_players = MAXPLAYERS;
|
||||
connect_data->drone = false;
|
||||
|
||||
//!
|
||||
// @category net
|
||||
//
|
||||
// Run as the left screen in three screen mode.
|
||||
//
|
||||
|
||||
if (M_CheckParm("-left") > 0) {
|
||||
viewangleoffset = ANG90;
|
||||
connect_data->drone = true;
|
||||
}
|
||||
|
||||
//!
|
||||
// @category net
|
||||
//
|
||||
// Run as the right screen in three screen mode.
|
||||
//
|
||||
|
||||
if (M_CheckParm("-right") > 0) {
|
||||
viewangleoffset = ANG270;
|
||||
connect_data->drone = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Connect data
|
||||
//
|
||||
|
||||
// Game type fields:
|
||||
|
||||
connect_data->gamemode = gamemode;
|
||||
connect_data->gamemission = gamemission;
|
||||
|
||||
// Are we recording a demo? Possibly set lowres turn mode
|
||||
|
||||
connect_data->lowres_turn =
|
||||
M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0;
|
||||
|
||||
// Read checksums of our WAD directory
|
||||
|
||||
W_Checksum(connect_data->wad_sha1sum);
|
||||
|
||||
// Are we playing with the Freedoom IWAD?
|
||||
|
||||
connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0;
|
||||
}
|
||||
|
||||
void D_ConnectNetGame(void) {
|
||||
net_connect_data_t connect_data;
|
||||
|
||||
InitConnectData(&connect_data);
|
||||
netgame = D_InitNetGame(&connect_data);
|
||||
|
||||
//!
|
||||
// @category net
|
||||
//
|
||||
// Start the game playing as though in a netgame with a single
|
||||
// player. This can also be used to play back single player netgame
|
||||
// demos.
|
||||
//
|
||||
|
||||
if (M_CheckParm("-solo-net") > 0) {
|
||||
netgame = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// D_CheckNetGame
|
||||
// Works out player numbers among the net participants
|
||||
//
|
||||
void D_CheckNetGame(void) {
|
||||
net_gamesettings_t settings;
|
||||
|
||||
if (netgame) {
|
||||
autostart = true;
|
||||
}
|
||||
|
||||
D_RegisterLoopCallbacks(&doom_loop_interface);
|
||||
|
||||
SaveGameSettings(&settings);
|
||||
D_StartNetGame(&settings, NULL);
|
||||
LoadGameSettings(&settings);
|
||||
|
||||
printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
|
||||
startskill, deathmatch, startmap, startepisode);
|
||||
|
||||
printf("player %i of %i (%i nodes)\n", consoleplayer + 1,
|
||||
settings.num_players, settings.num_players);
|
||||
|
||||
// Show players here; the server might have specified a time limit
|
||||
|
||||
if (timelimit > 0 && deathmatch) {
|
||||
// Gross hack to work like Vanilla:
|
||||
|
||||
if (timelimit == 20 && M_CheckParm("-avg")) {
|
||||
printf("Austin Virtual Gaming: Levels will end "
|
||||
"after 20 minutes\n");
|
||||
} else {
|
||||
printf("Levels will end after %d minute", timelimit);
|
||||
if (timelimit > 1)
|
||||
printf("s");
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
195
src/d_player.h
Normal file
195
src/d_player.h
Normal file
@@ -0,0 +1,195 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __D_PLAYER__
|
||||
#define __D_PLAYER__
|
||||
|
||||
// The player data structure depends on a number
|
||||
// of other structs: items (internal inventory),
|
||||
// animation states (closely tied to the sprites
|
||||
// used to represent them, unfortunately).
|
||||
#include "d_items.h"
|
||||
#include "p_pspr.h"
|
||||
|
||||
// In addition, the player is just a special
|
||||
// case of the generic moving object/actor.
|
||||
#include "p_mobj.h"
|
||||
|
||||
// Finally, for odd reasons, the player input
|
||||
// is buffered within the player data struct,
|
||||
// as commands per game tick.
|
||||
#include "d_ticcmd.h"
|
||||
|
||||
#include "net_defs.h"
|
||||
|
||||
//
|
||||
// Player states.
|
||||
//
|
||||
typedef enum {
|
||||
// Playing or camping.
|
||||
PST_LIVE,
|
||||
// Dead on the ground, view follows killer.
|
||||
PST_DEAD,
|
||||
// Ready to restart/respawn???
|
||||
PST_REBORN
|
||||
|
||||
} playerstate_t;
|
||||
|
||||
//
|
||||
// Player internal flags, for cheats and debug.
|
||||
//
|
||||
typedef enum {
|
||||
// No clipping, walk through barriers.
|
||||
CF_NOCLIP = 1,
|
||||
// No damage, no health loss.
|
||||
CF_GODMODE = 2,
|
||||
// Not really a cheat, just a debug aid.
|
||||
CF_NOMOMENTUM = 4
|
||||
|
||||
} cheat_t;
|
||||
|
||||
//
|
||||
// Extended player object info: player_t
|
||||
//
|
||||
typedef struct player_s {
|
||||
mobj_t *mo;
|
||||
playerstate_t playerstate;
|
||||
ticcmd_t cmd;
|
||||
|
||||
// Determine POV,
|
||||
// including viewpoint bobbing during movement.
|
||||
// Focal origin above r.z
|
||||
fixed_t viewz;
|
||||
// Base height above floor for viewz.
|
||||
fixed_t viewheight;
|
||||
// Bob/squat speed.
|
||||
fixed_t deltaviewheight;
|
||||
// bounded/scaled total momentum.
|
||||
fixed_t bob;
|
||||
|
||||
// This is only used between levels,
|
||||
// mo->health is used during levels.
|
||||
int health;
|
||||
int armorpoints;
|
||||
// Armor type is 0-2.
|
||||
int armortype;
|
||||
|
||||
// Power ups. invinc and invis are tic counters.
|
||||
int powers[NUMPOWERS];
|
||||
boolean cards[NUMCARDS];
|
||||
boolean backpack;
|
||||
|
||||
// Frags, kills of other players.
|
||||
int frags[MAXPLAYERS];
|
||||
weapontype_t readyweapon;
|
||||
|
||||
// Is wp_nochange if not changing.
|
||||
weapontype_t pendingweapon;
|
||||
|
||||
int weaponowned[NUMWEAPONS];
|
||||
int ammo[NUMAMMO];
|
||||
int maxammo[NUMAMMO];
|
||||
|
||||
// True if button down last tic.
|
||||
int attackdown;
|
||||
int usedown;
|
||||
|
||||
// Bit flags, for cheats and debug.
|
||||
// See cheat_t, above.
|
||||
int cheats;
|
||||
|
||||
// Refired shots are less accurate.
|
||||
int refire;
|
||||
|
||||
// For intermission stats.
|
||||
int killcount;
|
||||
int itemcount;
|
||||
int secretcount;
|
||||
|
||||
// Hint messages.
|
||||
char *message;
|
||||
|
||||
// For screen flashing (red or bright).
|
||||
int damagecount;
|
||||
int bonuscount;
|
||||
|
||||
// Who did damage (NULL for floors/ceilings).
|
||||
mobj_t *attacker;
|
||||
|
||||
// So gun flashes light up areas.
|
||||
int extralight;
|
||||
|
||||
// Current PLAYPAL, ???
|
||||
// can be set to REDCOLORMAP for pain, etc.
|
||||
int fixedcolormap;
|
||||
|
||||
// Player skin colorshift,
|
||||
// 0-3 for which color to draw player.
|
||||
int colormap;
|
||||
|
||||
// Overlay view sprites (gun, etc).
|
||||
pspdef_t psprites[NUMPSPRITES];
|
||||
|
||||
// True if secret level has been done.
|
||||
boolean didsecret;
|
||||
|
||||
} player_t;
|
||||
|
||||
//
|
||||
// INTERMISSION
|
||||
// Structure passed e.g. to WI_Start(wb)
|
||||
//
|
||||
typedef struct {
|
||||
boolean in; // whether the player is in game
|
||||
|
||||
// Player stats, kills, collected items etc.
|
||||
int skills;
|
||||
int sitems;
|
||||
int ssecret;
|
||||
int stime;
|
||||
int frags[4];
|
||||
int score; // current score on entry, modified on return
|
||||
|
||||
} wbplayerstruct_t;
|
||||
|
||||
typedef struct {
|
||||
int epsd; // episode # (0-2)
|
||||
|
||||
// if true, splash the secret level
|
||||
boolean didsecret;
|
||||
|
||||
// previous and next levels, origin 0
|
||||
int last;
|
||||
int next;
|
||||
|
||||
int maxkills;
|
||||
int maxitems;
|
||||
int maxsecret;
|
||||
int maxfrags;
|
||||
|
||||
// the par time
|
||||
int partime;
|
||||
|
||||
// index of this player in game
|
||||
int pnum;
|
||||
|
||||
wbplayerstruct_t plyr[MAXPLAYERS];
|
||||
|
||||
} wbstartstruct_t;
|
||||
|
||||
#endif
|
||||
35
src/d_textur.h
Normal file
35
src/d_textur.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Typedefs related to to textures etc.,
|
||||
// isolated here to make it easier separating modules.
|
||||
//
|
||||
|
||||
#ifndef __D_TEXTUR__
|
||||
#define __D_TEXTUR__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
//
|
||||
// Flats?
|
||||
//
|
||||
// a pic is an unmasked block of pixels
|
||||
typedef struct {
|
||||
byte width;
|
||||
byte height;
|
||||
byte data;
|
||||
} pic_t;
|
||||
|
||||
#endif
|
||||
54
src/d_think.h
Normal file
54
src/d_think.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// MapObj data. Map Objects or mobjs are actors, entities,
|
||||
// thinker, take-your-pick... anything that moves, acts, or
|
||||
// suffers state changes of more or less violent nature.
|
||||
//
|
||||
|
||||
#ifndef __D_THINK__
|
||||
#define __D_THINK__
|
||||
|
||||
//
|
||||
// Experimental stuff.
|
||||
// To compile this as "ANSI C with classes"
|
||||
// we will need to handle the various
|
||||
// action functions cleanly.
|
||||
//
|
||||
typedef void (*actionf_v)();
|
||||
typedef void (*actionf_p1)(void *);
|
||||
typedef void (*actionf_p2)(void *, void *);
|
||||
|
||||
typedef union {
|
||||
actionf_v acv;
|
||||
actionf_p1 acp1;
|
||||
actionf_p2 acp2;
|
||||
|
||||
} actionf_t;
|
||||
|
||||
// Historically, "think_t" is yet another
|
||||
// function pointer to a routine to handle
|
||||
// an actor.
|
||||
typedef actionf_t think_t;
|
||||
|
||||
// Doubly linked list of actors.
|
||||
typedef struct thinker_s {
|
||||
struct thinker_s *prev;
|
||||
struct thinker_s *next;
|
||||
think_t function;
|
||||
|
||||
} thinker_t;
|
||||
|
||||
#endif
|
||||
56
src/d_ticcmd.h
Normal file
56
src/d_ticcmd.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 1993-2008 Raven Software
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System specific interface stuff.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __D_TICCMD__
|
||||
#define __D_TICCMD__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
|
||||
// The data sampled per tick (single player)
|
||||
// and transmitted to other peers (multiplayer).
|
||||
// Mainly movements/button commands per game tick,
|
||||
// plus a checksum for internal state consistency.
|
||||
|
||||
typedef struct
|
||||
{
|
||||
signed char forwardmove; // *2048 for move
|
||||
signed char sidemove; // *2048 for move
|
||||
short angleturn; // <<16 for angle delta
|
||||
byte chatchar;
|
||||
byte buttons;
|
||||
// villsa [STRIFE] according to the asm,
|
||||
// consistancy is a short, not a byte
|
||||
byte consistancy; // checks for net game
|
||||
|
||||
// villsa - Strife specific:
|
||||
|
||||
byte buttons2;
|
||||
int inventory;
|
||||
|
||||
// Heretic/Hexen specific:
|
||||
|
||||
byte lookfly; // look/fly up/down/centering
|
||||
byte arti; // artitype_t to use
|
||||
} ticcmd_t;
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
184
src/doomdata.h
Normal file
184
src/doomdata.h
Normal file
@@ -0,0 +1,184 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// all external data is defined here
|
||||
// most of the data is loaded into different structures at run time
|
||||
// some internal structures shared by many modules are here
|
||||
//
|
||||
|
||||
#ifndef __DOOMDATA__
|
||||
#define __DOOMDATA__
|
||||
|
||||
// The most basic types we use, portability.
|
||||
#include "doomtype.h"
|
||||
|
||||
// Some global defines, that configure the game.
|
||||
#include "doomdef.h"
|
||||
|
||||
//
|
||||
// Map level types.
|
||||
// The following data structures define the persistent format
|
||||
// used in the lumps of the WAD files.
|
||||
//
|
||||
|
||||
// Lump order in a map WAD: each map needs a couple of lumps
|
||||
// to provide a complete scene geometry description.
|
||||
enum {
|
||||
ML_LABEL, // A separator, name, ExMx or MAPxx
|
||||
ML_THINGS, // Monsters, items..
|
||||
ML_LINEDEFS, // LineDefs, from editing
|
||||
ML_SIDEDEFS, // SideDefs, from editing
|
||||
ML_VERTEXES, // Vertices, edited and BSP splits generated
|
||||
ML_SEGS, // LineSegs, from LineDefs split by BSP
|
||||
ML_SSECTORS, // SubSectors, list of LineSegs
|
||||
ML_NODES, // BSP nodes
|
||||
ML_SECTORS, // Sectors, from editing
|
||||
ML_REJECT, // LUT, sector-sector visibility
|
||||
ML_BLOCKMAP // LUT, motion clipping, walls/grid element
|
||||
};
|
||||
|
||||
// A single Vertex.
|
||||
typedef PACKED_STRUCT({
|
||||
short x;
|
||||
short y;
|
||||
}) mapvertex_t;
|
||||
|
||||
// A SideDef, defining the visual appearance of a wall,
|
||||
// by setting textures and offsets.
|
||||
typedef PACKED_STRUCT({
|
||||
short textureoffset;
|
||||
short rowoffset;
|
||||
char toptexture[8];
|
||||
char bottomtexture[8];
|
||||
char midtexture[8];
|
||||
// Front sector, towards viewer.
|
||||
short sector;
|
||||
}) mapsidedef_t;
|
||||
|
||||
// A LineDef, as used for editing, and as input
|
||||
// to the BSP builder.
|
||||
typedef PACKED_STRUCT({
|
||||
short v1;
|
||||
short v2;
|
||||
short flags;
|
||||
short special;
|
||||
short tag;
|
||||
// sidenum[1] will be -1 if one sided
|
||||
short sidenum[2];
|
||||
}) maplinedef_t;
|
||||
|
||||
//
|
||||
// LineDef attributes.
|
||||
//
|
||||
|
||||
// Solid, is an obstacle.
|
||||
#define ML_BLOCKING 1
|
||||
|
||||
// Blocks monsters only.
|
||||
#define ML_BLOCKMONSTERS 2
|
||||
|
||||
// Backside will not be present at all
|
||||
// if not two sided.
|
||||
#define ML_TWOSIDED 4
|
||||
|
||||
// If a texture is pegged, the texture will have
|
||||
// the end exposed to air held constant at the
|
||||
// top or bottom of the texture (stairs or pulled
|
||||
// down things) and will move with a height change
|
||||
// of one of the neighbor sectors.
|
||||
// Unpegged textures allways have the first row of
|
||||
// the texture at the top pixel of the line for both
|
||||
// top and bottom textures (use next to windows).
|
||||
|
||||
// upper texture unpegged
|
||||
#define ML_DONTPEGTOP 8
|
||||
|
||||
// lower texture unpegged
|
||||
#define ML_DONTPEGBOTTOM 16
|
||||
|
||||
// In AutoMap: don't map as two sided: IT'S A SECRET!
|
||||
#define ML_SECRET 32
|
||||
|
||||
// Sound rendering: don't let sound cross two of these.
|
||||
#define ML_SOUNDBLOCK 64
|
||||
|
||||
// Don't draw on the automap at all.
|
||||
#define ML_DONTDRAW 128
|
||||
|
||||
// Set if already seen, thus drawn in automap.
|
||||
#define ML_MAPPED 256
|
||||
|
||||
// Sector definition, from editing.
|
||||
typedef PACKED_STRUCT({
|
||||
short floorheight;
|
||||
short ceilingheight;
|
||||
char floorpic[8];
|
||||
char ceilingpic[8];
|
||||
short lightlevel;
|
||||
short special;
|
||||
short tag;
|
||||
}) mapsector_t;
|
||||
|
||||
// SubSector, as generated by BSP.
|
||||
typedef PACKED_STRUCT({
|
||||
short numsegs;
|
||||
// Index of first one, segs are stored sequentially.
|
||||
short firstseg;
|
||||
}) mapsubsector_t;
|
||||
|
||||
// LineSeg, generated by splitting LineDefs
|
||||
// using partition lines selected by BSP builder.
|
||||
typedef PACKED_STRUCT({
|
||||
short v1;
|
||||
short v2;
|
||||
short angle;
|
||||
short linedef;
|
||||
short side;
|
||||
short offset;
|
||||
}) mapseg_t;
|
||||
|
||||
// BSP node structure.
|
||||
|
||||
// Indicate a leaf.
|
||||
#define NF_SUBSECTOR 0x8000
|
||||
|
||||
typedef PACKED_STRUCT({
|
||||
// Partition line from (x,y) to x+dx,y+dy)
|
||||
short x;
|
||||
short y;
|
||||
short dx;
|
||||
short dy;
|
||||
|
||||
// Bounding box for each child,
|
||||
// clip against view frustum.
|
||||
short bbox[2][4];
|
||||
|
||||
// If NF_SUBSECTOR its a subsector,
|
||||
// else it's a node of another subtree.
|
||||
unsigned short children[2];
|
||||
|
||||
}) mapnode_t;
|
||||
|
||||
// Thing definition, position, orientation and type,
|
||||
// plus skill/visibility flags and attributes.
|
||||
typedef PACKED_STRUCT({
|
||||
short x;
|
||||
short y;
|
||||
short angle;
|
||||
short type;
|
||||
short options;
|
||||
}) mapthing_t;
|
||||
|
||||
#endif // __DOOMDATA__
|
||||
24
src/doomdef.c
Normal file
24
src/doomdef.c
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// DoomDef - basic defines for DOOM, e.g. Version, game mode
|
||||
// and skill level, and display parameters.
|
||||
//
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
// Location for any defines turned variables.
|
||||
|
||||
// None.
|
||||
143
src/doomdef.h
Normal file
143
src/doomdef.h
Normal file
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Internally used data structures for virtually everything,
|
||||
// lots of other stuff.
|
||||
//
|
||||
|
||||
#ifndef __DOOMDEF__
|
||||
#define __DOOMDEF__
|
||||
|
||||
#include "i_timer.h"
|
||||
|
||||
//
|
||||
// Global parameters/defines.
|
||||
//
|
||||
// DOOM version
|
||||
#define DOOM_VERSION 109
|
||||
|
||||
// Version code for cph's longtics hack ("v1.91")
|
||||
#define DOOM_191_VERSION 111
|
||||
|
||||
// The maximum number of players, multiplayer/networking.
|
||||
#define MAXPLAYERS 4
|
||||
|
||||
// The current state of the game: whether we are
|
||||
// playing, gazing at the intermission screen,
|
||||
// the game final animation, or a demo.
|
||||
typedef enum {
|
||||
GS_LEVEL,
|
||||
GS_INTERMISSION,
|
||||
GS_DEMOSCREEN,
|
||||
} gamestate_t;
|
||||
|
||||
typedef enum {
|
||||
ga_nothing,
|
||||
ga_loadlevel,
|
||||
ga_newgame,
|
||||
ga_loadgame,
|
||||
ga_savegame,
|
||||
ga_playdemo,
|
||||
ga_completed,
|
||||
ga_victory,
|
||||
ga_worlddone,
|
||||
ga_screenshot
|
||||
} gameaction_t;
|
||||
|
||||
//
|
||||
// Difficulty/skill settings/filters.
|
||||
//
|
||||
|
||||
// Skill flags.
|
||||
#define MTF_EASY 1
|
||||
#define MTF_NORMAL 2
|
||||
#define MTF_HARD 4
|
||||
|
||||
// Deaf monsters/do not react to sound.
|
||||
#define MTF_AMBUSH 8
|
||||
|
||||
//
|
||||
// Key cards.
|
||||
//
|
||||
typedef enum {
|
||||
it_bluecard,
|
||||
it_yellowcard,
|
||||
it_redcard,
|
||||
it_blueskull,
|
||||
it_yellowskull,
|
||||
it_redskull,
|
||||
|
||||
NUMCARDS
|
||||
|
||||
} card_t;
|
||||
|
||||
// The defined weapons,
|
||||
// including a marker indicating
|
||||
// user has not changed weapon.
|
||||
typedef enum {
|
||||
wp_fist,
|
||||
wp_pistol,
|
||||
wp_shotgun,
|
||||
wp_chaingun,
|
||||
wp_missile,
|
||||
wp_plasma,
|
||||
wp_bfg,
|
||||
wp_chainsaw,
|
||||
wp_supershotgun,
|
||||
|
||||
NUMWEAPONS,
|
||||
|
||||
// No pending weapon change.
|
||||
wp_nochange
|
||||
|
||||
} weapontype_t;
|
||||
|
||||
// Ammunition types defined.
|
||||
typedef enum {
|
||||
am_clip, // Pistol / chaingun ammo.
|
||||
am_shell, // Shotgun / double barreled shotgun.
|
||||
am_cell, // Plasma rifle, BFG.
|
||||
am_misl, // Missile launcher.
|
||||
NUMAMMO,
|
||||
am_noammo // Unlimited for chainsaw / fist.
|
||||
|
||||
} ammotype_t;
|
||||
|
||||
// Power up artifacts.
|
||||
typedef enum {
|
||||
pw_invulnerability,
|
||||
pw_strength,
|
||||
pw_invisibility,
|
||||
pw_ironfeet,
|
||||
pw_allmap,
|
||||
pw_infrared,
|
||||
NUMPOWERS
|
||||
|
||||
} powertype_t;
|
||||
|
||||
//
|
||||
// Power up durations,
|
||||
// how many seconds till expiration,
|
||||
// assuming TICRATE is 35 ticks/second.
|
||||
//
|
||||
typedef enum {
|
||||
INVULNTICS = (30 * TICRATE),
|
||||
INVISTICS = (60 * TICRATE),
|
||||
INFRATICS = (120 * TICRATE),
|
||||
IRONTICS = (60 * TICRATE)
|
||||
|
||||
} powerduration_t;
|
||||
|
||||
#endif // __DOOMDEF__
|
||||
153
src/doomkeys.h
Normal file
153
src/doomkeys.h
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Key definitions
|
||||
//
|
||||
|
||||
#ifndef __DOOMKEYS__
|
||||
#define __DOOMKEYS__
|
||||
|
||||
//
|
||||
// DOOM keyboard definition.
|
||||
// This is the stuff configured by Setup.Exe.
|
||||
// Most key data are simple ascii (uppercased).
|
||||
//
|
||||
#define KEY_RIGHTARROW 0xae
|
||||
#define KEY_LEFTARROW 0xac
|
||||
#define KEY_UPARROW 0xad
|
||||
#define KEY_DOWNARROW 0xaf
|
||||
#define KEY_ESCAPE 27
|
||||
#define KEY_ENTER 13
|
||||
#define KEY_TAB 9
|
||||
#define KEY_F1 (0x80+0x3b)
|
||||
#define KEY_F2 (0x80+0x3c)
|
||||
#define KEY_F3 (0x80+0x3d)
|
||||
#define KEY_F4 (0x80+0x3e)
|
||||
#define KEY_F5 (0x80+0x3f)
|
||||
#define KEY_F6 (0x80+0x40)
|
||||
#define KEY_F7 (0x80+0x41)
|
||||
#define KEY_F8 (0x80+0x42)
|
||||
#define KEY_F9 (0x80+0x43)
|
||||
#define KEY_F10 (0x80+0x44)
|
||||
#define KEY_F11 (0x80+0x57)
|
||||
#define KEY_F12 (0x80+0x58)
|
||||
|
||||
#define KEY_BACKSPACE 0x7f
|
||||
#define KEY_PAUSE 0xff
|
||||
|
||||
#define KEY_EQUALS 0x3d
|
||||
#define KEY_MINUS 0x2d
|
||||
|
||||
#define KEY_RSHIFT (0x80+0x36)
|
||||
#define KEY_RCTRL (0x80+0x1d)
|
||||
#define KEY_RALT (0x80+0x38)
|
||||
|
||||
#define KEY_LALT KEY_RALT
|
||||
|
||||
// new keys:
|
||||
|
||||
#define KEY_CAPSLOCK (0x80+0x3a)
|
||||
#define KEY_NUMLOCK (0x80+0x45)
|
||||
#define KEY_SCRLCK (0x80+0x46)
|
||||
#define KEY_PRTSCR (0x80+0x59)
|
||||
|
||||
#define KEY_HOME (0x80+0x47)
|
||||
#define KEY_END (0x80+0x4f)
|
||||
#define KEY_PGUP (0x80+0x49)
|
||||
#define KEY_PGDN (0x80+0x51)
|
||||
#define KEY_INS (0x80+0x52)
|
||||
#define KEY_DEL (0x80+0x53)
|
||||
|
||||
#define KEYP_0 0
|
||||
#define KEYP_1 KEY_END
|
||||
#define KEYP_2 KEY_DOWNARROW
|
||||
#define KEYP_3 KEY_PGDN
|
||||
#define KEYP_4 KEY_LEFTARROW
|
||||
#define KEYP_5 '5'
|
||||
#define KEYP_6 KEY_RIGHTARROW
|
||||
#define KEYP_7 KEY_HOME
|
||||
#define KEYP_8 KEY_UPARROW
|
||||
#define KEYP_9 KEY_PGUP
|
||||
|
||||
#define KEYP_DIVIDE '/'
|
||||
#define KEYP_PLUS '+'
|
||||
#define KEYP_MINUS '-'
|
||||
#define KEYP_MULTIPLY '*'
|
||||
#define KEYP_PERIOD 0
|
||||
#define KEYP_EQUALS KEY_EQUALS
|
||||
#define KEYP_ENTER KEY_ENTER
|
||||
|
||||
#define SCANCODE_TO_KEYS_ARRAY { \
|
||||
0, 0, 0, 0, 'a', /* 0-9 */ \
|
||||
'b', 'c', 'd', 'e', 'f', \
|
||||
'g', 'h', 'i', 'j', 'k', /* 10-19 */ \
|
||||
'l', 'm', 'n', 'o', 'p', \
|
||||
'q', 'r', 's', 't', 'u', /* 20-29 */ \
|
||||
'v', 'w', 'x', 'y', 'z', \
|
||||
'1', '2', '3', '4', '5', /* 30-39 */ \
|
||||
'6', '7', '8', '9', '0', \
|
||||
KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE, KEY_TAB, ' ', /* 40-49 */ \
|
||||
KEY_MINUS, KEY_EQUALS, '[', ']', '\\', \
|
||||
0, ';', '\'', '`', ',', /* 50-59 */ \
|
||||
'.', '/', KEY_CAPSLOCK, KEY_F1, KEY_F2, \
|
||||
KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* 60-69 */ \
|
||||
KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, \
|
||||
KEY_PRTSCR, KEY_SCRLCK, KEY_PAUSE, KEY_INS, KEY_HOME, /* 70-79 */ \
|
||||
KEY_PGUP, KEY_DEL, KEY_END, KEY_PGDN, KEY_RIGHTARROW, \
|
||||
KEY_LEFTARROW, KEY_DOWNARROW, KEY_UPARROW, /* 80-89 */ \
|
||||
KEY_NUMLOCK, KEYP_DIVIDE, \
|
||||
KEYP_MULTIPLY, KEYP_MINUS, KEYP_PLUS, KEYP_ENTER, KEYP_1, \
|
||||
KEYP_2, KEYP_3, KEYP_4, KEYP_5, KEYP_6, /* 90-99 */ \
|
||||
KEYP_7, KEYP_8, KEYP_9, KEYP_0, KEYP_PERIOD, \
|
||||
0, 0, 0, KEYP_EQUALS, /* 100-103 */ \
|
||||
}
|
||||
|
||||
// Default names for keys, to use in English or as fallback.
|
||||
#define KEY_NAMES_ARRAY { \
|
||||
{ KEY_BACKSPACE, "BACKSP" }, { KEY_TAB, "TAB" }, \
|
||||
{ KEY_INS, "INS" }, { KEY_DEL, "DEL" }, \
|
||||
{ KEY_PGUP, "PGUP" }, { KEY_PGDN, "PGDN" }, \
|
||||
{ KEY_ENTER, "ENTER" }, { KEY_ESCAPE, "ESC" }, \
|
||||
{ KEY_F1, "F1" }, { KEY_F2, "F2" }, \
|
||||
{ KEY_F3, "F3" }, { KEY_F4, "F4" }, \
|
||||
{ KEY_F5, "F5" }, { KEY_F6, "F6" }, \
|
||||
{ KEY_F7, "F7" }, { KEY_F8, "F8" }, \
|
||||
{ KEY_F9, "F9" }, { KEY_F10, "F10" }, \
|
||||
{ KEY_F11, "F11" }, { KEY_F12, "F12" }, \
|
||||
{ KEY_HOME, "HOME" }, { KEY_END, "END" }, \
|
||||
{ KEY_MINUS, "-" }, { KEY_EQUALS, "=" }, \
|
||||
{ KEY_NUMLOCK, "NUMLCK" }, { KEY_SCRLCK, "SCRLCK" }, \
|
||||
{ KEY_PAUSE, "PAUSE" }, { KEY_PRTSCR, "PRTSC" }, \
|
||||
{ KEY_UPARROW, "UP" }, { KEY_DOWNARROW, "DOWN" }, \
|
||||
{ KEY_LEFTARROW, "LEFT" }, { KEY_RIGHTARROW, "RIGHT" }, \
|
||||
{ KEY_RALT, "ALT" }, { KEY_LALT, "ALT" }, \
|
||||
{ KEY_RSHIFT, "SHIFT" }, { KEY_CAPSLOCK, "CAPS" }, \
|
||||
{ KEY_RCTRL, "CTRL" }, { ' ', "SPACE" }, \
|
||||
{ 'a', "A" }, { 'b', "B" }, { 'c', "C" }, { 'd', "D" }, \
|
||||
{ 'e', "E" }, { 'f', "F" }, { 'g', "G" }, { 'h', "H" }, \
|
||||
{ 'i', "I" }, { 'j', "J" }, { 'k', "K" }, { 'l', "L" }, \
|
||||
{ 'm', "M" }, { 'n', "N" }, { 'o', "O" }, { 'p', "P" }, \
|
||||
{ 'q', "Q" }, { 'r', "R" }, { 's', "S" }, { 't', "T" }, \
|
||||
{ 'u', "U" }, { 'v', "V" }, { 'w', "W" }, { 'x', "X" }, \
|
||||
{ 'y', "Y" }, { 'z', "Z" }, { '0', "0" }, { '1', "1" }, \
|
||||
{ '2', "2" }, { '3', "3" }, { '4', "4" }, { '5', "5" }, \
|
||||
{ '6', "6" }, { '7', "7" }, { '8', "8" }, { '9', "9" }, \
|
||||
{ '[', "[" }, { ']', "]" }, { ';', ";" }, { '`', "`" }, \
|
||||
{ ',', "," }, { '.', "." }, { '/', "/" }, { '\\', "\\" }, \
|
||||
{ '\'', "\'" }, \
|
||||
}
|
||||
|
||||
#endif // __DOOMKEYS__
|
||||
|
||||
29
src/doomstat.c
Normal file
29
src/doomstat.c
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Put all global tate variables here.
|
||||
//
|
||||
|
||||
#include "doomstat.h"
|
||||
|
||||
// Game Mode - identify IWAD as shareware, retail etc.
|
||||
GameMode_t gamemode = indetermined;
|
||||
GameMission_t gamemission = doom;
|
||||
GameVersion_t gameversion = exe_final2;
|
||||
GameVariant_t gamevariant = vanilla;
|
||||
char *gamedescription;
|
||||
|
||||
// Set if homebrew PWAD stuff has been added.
|
||||
boolean modifiedgame;
|
||||
239
src/doomstat.h
Normal file
239
src/doomstat.h
Normal file
@@ -0,0 +1,239 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// All the global variables that store the internal state.
|
||||
// Theoretically speaking, the internal state of the engine
|
||||
// should be found by looking at the variables collected
|
||||
// here, and every relevant module will have to include
|
||||
// this header file.
|
||||
// In practice, things are a bit messy.
|
||||
//
|
||||
|
||||
#ifndef __D_STATE__
|
||||
#define __D_STATE__
|
||||
|
||||
// Game mode/mission
|
||||
#include "d_mode.h"
|
||||
// We need the playr data structure as well.
|
||||
#include "d_player.h"
|
||||
#include "d_ticcmd.h"
|
||||
// We need globally shared data structures,
|
||||
// for defining the global state variables.
|
||||
#include "doomdata.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
// ------------------------
|
||||
// Command line parameters.
|
||||
//
|
||||
extern boolean nomonsters; // checkparm of -nomonsters
|
||||
extern boolean respawnparm; // checkparm of -respawn
|
||||
extern boolean fastparm; // checkparm of -fast
|
||||
|
||||
extern boolean devparm; // DEBUG: launched with -devparm
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Game Mode - identify IWAD as shareware, retail etc.
|
||||
//
|
||||
extern GameMode_t gamemode;
|
||||
extern GameMission_t gamemission;
|
||||
extern GameVersion_t gameversion;
|
||||
extern GameVariant_t gamevariant;
|
||||
extern char *gamedescription;
|
||||
|
||||
// Convenience macro.
|
||||
// 'gamemission' can be equal to pack_chex or pack_hacx, but these are
|
||||
// just modified versions of doom and doom2, and should be interpreted
|
||||
// as the same most of the time.
|
||||
|
||||
#define logical_gamemission \
|
||||
(gamemission == pack_chex ? doom \
|
||||
: gamemission == pack_hacx ? doom2 : gamemission)
|
||||
|
||||
// Set if homebrew PWAD stuff has been added.
|
||||
extern boolean modifiedgame;
|
||||
|
||||
// -------------------------------------------
|
||||
// Selected skill type, map etc.
|
||||
//
|
||||
|
||||
// Defaults for menu, methinks.
|
||||
extern skill_t startskill;
|
||||
extern int startepisode;
|
||||
extern int startmap;
|
||||
|
||||
// Savegame slot to load on startup. This is the value provided to
|
||||
// the -loadgame option. If this has not been provided, this is -1.
|
||||
|
||||
extern int startloadgame;
|
||||
|
||||
extern boolean autostart;
|
||||
|
||||
// Selected by user.
|
||||
extern skill_t gameskill;
|
||||
extern int gameepisode;
|
||||
extern int gamemap;
|
||||
|
||||
// If non-zero, exit the level after this number of minutes
|
||||
extern int timelimit;
|
||||
|
||||
// Nightmare mode flag, single player.
|
||||
extern boolean respawnmonsters;
|
||||
|
||||
// Netgame? Only true if >1 player.
|
||||
extern boolean netgame;
|
||||
|
||||
// 0=Cooperative; 1=Deathmatch; 2=Altdeath
|
||||
extern int deathmatch;
|
||||
|
||||
// -------------------------
|
||||
// Internal parameters for sound rendering.
|
||||
// These have been taken from the DOS version,
|
||||
// but are not (yet) supported with Linux
|
||||
// (e.g. no sound volume adjustment with menu.
|
||||
|
||||
// From m_menu.c:
|
||||
// Sound FX volume has default, 0 - 15
|
||||
// Music volume has default, 0 - 15
|
||||
// These are multiplied by 8.
|
||||
extern int sfxVolume;
|
||||
extern int musicVolume;
|
||||
|
||||
// Current music/sfx card - index useless
|
||||
// w/o a reference LUT in a sound module.
|
||||
// Ideally, this would use indices found
|
||||
// in: /usr/include/linux/soundcard.h
|
||||
extern int snd_MusicDevice;
|
||||
extern int snd_SfxDevice;
|
||||
// Config file? Same disclaimer as above.
|
||||
extern int snd_DesiredMusicDevice;
|
||||
extern int snd_DesiredSfxDevice;
|
||||
|
||||
// -------------------------
|
||||
// Status flags for refresh.
|
||||
//
|
||||
|
||||
// Depending on view size - no status bar?
|
||||
// Note that there is no way to disable the
|
||||
// status bar explicitely.
|
||||
extern boolean statusbaractive;
|
||||
|
||||
extern boolean automapactive; // In AutoMap mode?
|
||||
extern boolean menuactive; // Menu overlayed?
|
||||
extern boolean paused; // Game Pause?
|
||||
|
||||
extern boolean viewactive;
|
||||
|
||||
extern boolean nodrawers;
|
||||
|
||||
extern boolean testcontrols;
|
||||
extern int testcontrols_mousespeed;
|
||||
|
||||
// This one is related to the 3-screen display mode.
|
||||
// ANG90 = left side, ANG270 = right
|
||||
extern int viewangleoffset;
|
||||
|
||||
// Player taking events, and displaying.
|
||||
extern int consoleplayer;
|
||||
extern int displayplayer;
|
||||
|
||||
// -------------------------------------
|
||||
// Scores, rating.
|
||||
// Statistics on a given map, for intermission.
|
||||
//
|
||||
extern int totalkills;
|
||||
extern int totalitems;
|
||||
extern int totalsecret;
|
||||
|
||||
// Timer, for scores.
|
||||
extern int levelstarttic; // gametic at level start
|
||||
extern int leveltime; // tics in game play for par
|
||||
|
||||
// --------------------------------------
|
||||
// DEMO playback/recording related stuff.
|
||||
// No demo, there is a human player in charge?
|
||||
// Disable save/end game?
|
||||
extern boolean usergame;
|
||||
|
||||
//?
|
||||
extern boolean demoplayback;
|
||||
extern boolean demorecording;
|
||||
|
||||
// Round angleturn in ticcmds to the nearest 256. This is used when
|
||||
// recording Vanilla demos in netgames.
|
||||
|
||||
extern boolean lowres_turn;
|
||||
|
||||
// Quit after playing a demo from cmdline.
|
||||
extern boolean singledemo;
|
||||
|
||||
//?
|
||||
extern gamestate_t gamestate;
|
||||
|
||||
//-----------------------------
|
||||
// Internal parameters, fixed.
|
||||
// These are set by the engine, and not changed
|
||||
// according to user inputs. Partly load from
|
||||
// WAD, partly set at startup time.
|
||||
|
||||
// Bookkeeping on players - state.
|
||||
extern player_t players[MAXPLAYERS];
|
||||
|
||||
// Alive? Disconnected?
|
||||
extern boolean playeringame[MAXPLAYERS];
|
||||
|
||||
// Player spawn spots for deathmatch.
|
||||
#define MAX_DM_STARTS 10
|
||||
extern mapthing_t deathmatchstarts[MAX_DM_STARTS];
|
||||
extern mapthing_t *deathmatch_p;
|
||||
|
||||
// Player spawn spots.
|
||||
extern mapthing_t playerstarts[MAXPLAYERS];
|
||||
|
||||
// Intermission stats.
|
||||
// Parameters for world map / intermission.
|
||||
extern wbstartstruct_t wminfo;
|
||||
|
||||
//-----------------------------------------
|
||||
// Internal parameters, used for engine.
|
||||
//
|
||||
|
||||
// File handling stuff.
|
||||
extern char *savegamedir;
|
||||
extern char basedefault[1024];
|
||||
|
||||
// if true, load all graphics at level load
|
||||
extern boolean precache;
|
||||
|
||||
// wipegamestate can be set to -1
|
||||
// to force a wipe on the next draw
|
||||
extern gamestate_t wipegamestate;
|
||||
|
||||
extern int mouseSensitivity;
|
||||
|
||||
extern int bodyqueslot;
|
||||
|
||||
// Needed to store the number of the dummy sky flat.
|
||||
// Used for rendering,
|
||||
// as well as tracking projectiles etc.
|
||||
extern int skyflatnum;
|
||||
|
||||
// Netgame stuff (buffers and pointers, i.e. indices).
|
||||
|
||||
extern int rndindex;
|
||||
|
||||
extern ticcmd_t *netcmds;
|
||||
|
||||
#endif
|
||||
80
src/doomtype.h
Normal file
80
src/doomtype.h
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Simple basic typedefs, isolated here to make it easier
|
||||
// separating modules.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __DOOMTYPE__
|
||||
#define __DOOMTYPE__
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The packed attribute forces structures to be packed into the minimum
|
||||
// space necessary. If this is not done, the compiler may align structure
|
||||
// fields differently to optimize memory access, inflating the overall
|
||||
// structure size. It is important to use the packed attribute on certain
|
||||
// structures where alignment is important, particularly data read/written
|
||||
// to disk.
|
||||
//
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define PACKEDATTR __attribute__((packed))
|
||||
|
||||
#else
|
||||
#define PACKEDATTR
|
||||
#endif
|
||||
|
||||
#define PACKEDPREFIX
|
||||
|
||||
#define PACKED_STRUCT(...) PACKEDPREFIX struct __VA_ARGS__ PACKEDATTR
|
||||
|
||||
// C99 integer types; with gcc we just use this. Other compilers
|
||||
// should add conditional statements that define the C99 types.
|
||||
|
||||
// What is really wanted here is stdint.h; however, some old versions
|
||||
// of Solaris don't have stdint.h and only have inttypes.h (the
|
||||
// pre-standardisation version). inttypes.h is also in the C99
|
||||
// standard and defined to include stdint.h, so include this.
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
false,
|
||||
true
|
||||
} boolean;
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef uint8_t pixel_t;
|
||||
typedef int16_t dpixel_t;
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#define DIR_SEPARATOR '/'
|
||||
#define DIR_SEPARATOR_S "/"
|
||||
#define PATH_SEPARATOR ':'
|
||||
|
||||
|
||||
#define arrlen(array) (sizeof(array) / sizeof(*array))
|
||||
|
||||
#endif
|
||||
|
||||
66
src/dstrings.c
Normal file
66
src/dstrings.c
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Globally defined strings.
|
||||
//
|
||||
|
||||
#include "dstrings.h"
|
||||
|
||||
char *doom1_endmsg[] = {
|
||||
"are you sure you want to\nquit this great game?",
|
||||
"please don't leave, there's more\ndemons to toast!",
|
||||
"let's beat it -- this is turning\ninto a bloodbath!",
|
||||
"i wouldn't leave if i were you.\ndos is much worse.",
|
||||
"you're trying to say you like dos\nbetter than me, right?",
|
||||
"don't leave yet -- there's a\ndemon around that corner!",
|
||||
"ya know, next time you come in here\ni'm gonna toast ya.",
|
||||
"go ahead and leave. see if i care.",
|
||||
};
|
||||
|
||||
char *doom2_endmsg[] = {
|
||||
// QuitDOOM II messages
|
||||
"are you sure you want to\nquit this great game?",
|
||||
"you want to quit?\nthen, thou hast lost an eighth!",
|
||||
"don't go now, there's a \ndimensional shambler waiting\nat the dos "
|
||||
"prompt!",
|
||||
"get outta here and go back\nto your boring programs.",
|
||||
"if i were your boss, i'd \n deathmatch ya in a minute!",
|
||||
"look, bud. you leave now\nand you forfeit your body count!",
|
||||
"just leave. when you come\nback, i'll be waiting with a bat.",
|
||||
"you're lucky i don't smack\nyou for thinking about leaving.",
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
// UNUSED messages included in the source release
|
||||
|
||||
char* endmsg[] =
|
||||
{
|
||||
// DOOM1
|
||||
QUITMSG,
|
||||
// FinalDOOM?
|
||||
"fuck you, pussy!\nget the fuck out!",
|
||||
"you quit and i'll jizz\nin your cystholes!",
|
||||
"if you leave, i'll make\nthe lord drink my jizz.",
|
||||
"hey, ron! can we say\n'fuck' in the game?",
|
||||
"i'd leave: this is just\nmore monsters and levels.\nwhat a load.",
|
||||
"suck it down, asshole!\nyou're a fucking wimp!",
|
||||
"don't quit now! we're \nstill spending your money!",
|
||||
|
||||
// Internal debug. Different style, too.
|
||||
"THIS IS NO MESSAGE!\nPage intentionally left blank."
|
||||
};
|
||||
|
||||
#endif
|
||||
33
src/dstrings.h
Normal file
33
src/dstrings.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// DOOM strings, by language.
|
||||
//
|
||||
|
||||
#ifndef __DSTRINGS__
|
||||
#define __DSTRINGS__
|
||||
|
||||
// Misc. other strings.
|
||||
#define SAVEGAMENAME "doomsav"
|
||||
|
||||
// QuitDOOM messages
|
||||
// 8 per each game type
|
||||
#define NUM_QUITMESSAGES 8
|
||||
|
||||
extern char *doom1_endmsg[];
|
||||
extern char *doom2_endmsg[];
|
||||
|
||||
#endif
|
||||
221
src/f_wipe.c
Normal file
221
src/f_wipe.c
Normal file
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Mission begin melt/wipe screen special effect.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "i_video.h"
|
||||
#include "m_random.h"
|
||||
#include "v_video.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
#include "f_wipe.h"
|
||||
|
||||
//
|
||||
// SCREEN WIPE PACKAGE
|
||||
//
|
||||
|
||||
// when zero, stop the wipe
|
||||
static boolean go = 0;
|
||||
|
||||
static pixel_t *wipe_scr_start;
|
||||
static pixel_t *wipe_scr_end;
|
||||
static pixel_t *wipe_scr;
|
||||
|
||||
void wipe_shittyColMajorXform(dpixel_t *array, int width, int height) {
|
||||
int x;
|
||||
int y;
|
||||
dpixel_t *dest;
|
||||
|
||||
dest = (dpixel_t *)Z_Malloc(width * height * sizeof(*dest), PU_STATIC, 0);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
dest[x * height + y] = array[y * width + x];
|
||||
|
||||
memcpy(array, dest, width * height * sizeof(*dest));
|
||||
|
||||
Z_Free(dest);
|
||||
}
|
||||
|
||||
int wipe_initColorXForm(int width, int height, int ticks) {
|
||||
memcpy(wipe_scr, wipe_scr_start, width * height * sizeof(*wipe_scr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wipe_doColorXForm(int width, int height, int ticks) {
|
||||
boolean changed;
|
||||
pixel_t *w;
|
||||
pixel_t *e;
|
||||
int newval;
|
||||
|
||||
changed = false;
|
||||
w = wipe_scr;
|
||||
e = wipe_scr_end;
|
||||
|
||||
while (w != wipe_scr + width * height) {
|
||||
if (*w != *e) {
|
||||
if (*w > *e) {
|
||||
newval = *w - ticks;
|
||||
if (newval < *e)
|
||||
*w = *e;
|
||||
else
|
||||
*w = newval;
|
||||
changed = true;
|
||||
} else if (*w < *e) {
|
||||
newval = *w + ticks;
|
||||
if (newval > *e)
|
||||
*w = *e;
|
||||
else
|
||||
*w = newval;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
w++;
|
||||
e++;
|
||||
}
|
||||
|
||||
return !changed;
|
||||
}
|
||||
|
||||
int wipe_exitColorXForm(int width, int height, int ticks) { return 0; }
|
||||
|
||||
static int *y;
|
||||
|
||||
int wipe_initMelt(int width, int height, int ticks) {
|
||||
int i, r;
|
||||
|
||||
// copy start screen to main screen
|
||||
memcpy(wipe_scr, wipe_scr_start, width * height * sizeof(*wipe_scr));
|
||||
|
||||
// makes this wipe faster (in theory)
|
||||
// to have stuff in column-major format
|
||||
wipe_shittyColMajorXform((dpixel_t *)wipe_scr_start, width / 2, height);
|
||||
wipe_shittyColMajorXform((dpixel_t *)wipe_scr_end, width / 2, height);
|
||||
|
||||
// setup initial column positions
|
||||
// (y<0 => not ready to scroll yet)
|
||||
y = (int *)Z_Malloc(width * sizeof(int), PU_STATIC, 0);
|
||||
y[0] = -(M_Random() % 16);
|
||||
for (i = 1; i < width; i++) {
|
||||
r = (M_Random() % 3) - 1;
|
||||
y[i] = y[i - 1] + r;
|
||||
if (y[i] > 0)
|
||||
y[i] = 0;
|
||||
else if (y[i] == -16)
|
||||
y[i] = -15;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wipe_doMelt(int width, int height, int ticks) {
|
||||
int i;
|
||||
int j;
|
||||
int dy;
|
||||
int idx;
|
||||
|
||||
dpixel_t *s;
|
||||
dpixel_t *d;
|
||||
boolean done = true;
|
||||
|
||||
width /= 2;
|
||||
|
||||
while (ticks--) {
|
||||
for (i = 0; i < width; i++) {
|
||||
if (y[i] < 0) {
|
||||
y[i]++;
|
||||
done = false;
|
||||
} else if (y[i] < height) {
|
||||
dy = (y[i] < 16) ? y[i] + 1 : 8;
|
||||
if (y[i] + dy >= height)
|
||||
dy = height - y[i];
|
||||
s = &((dpixel_t *)wipe_scr_end)[i * height + y[i]];
|
||||
d = &((dpixel_t *)wipe_scr)[y[i] * width + i];
|
||||
idx = 0;
|
||||
for (j = dy; j; j--) {
|
||||
d[idx] = *(s++);
|
||||
idx += width;
|
||||
}
|
||||
y[i] += dy;
|
||||
s = &((dpixel_t *)wipe_scr_start)[i * height];
|
||||
d = &((dpixel_t *)wipe_scr)[y[i] * width + i];
|
||||
idx = 0;
|
||||
for (j = height - y[i]; j; j--) {
|
||||
d[idx] = *(s++);
|
||||
idx += width;
|
||||
}
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int wipe_exitMelt(int width, int height, int ticks) {
|
||||
Z_Free(y);
|
||||
Z_Free(wipe_scr_start);
|
||||
Z_Free(wipe_scr_end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wipe_StartScreen(int x, int y, int width, int height) {
|
||||
wipe_scr_start = Z_Malloc(
|
||||
SCREENWIDTH * SCREENHEIGHT * sizeof(*wipe_scr_start), PU_STATIC, NULL);
|
||||
I_ReadScreen(wipe_scr_start);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wipe_EndScreen(int x, int y, int width, int height) {
|
||||
wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT * sizeof(*wipe_scr_end),
|
||||
PU_STATIC, NULL);
|
||||
I_ReadScreen(wipe_scr_end);
|
||||
V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wipe_ScreenWipe(int wipeno, int x, int y, int width, int height,
|
||||
int ticks) {
|
||||
int rc;
|
||||
static int (*wipes[])(int, int, int) = {
|
||||
wipe_initColorXForm, wipe_doColorXForm, wipe_exitColorXForm,
|
||||
wipe_initMelt, wipe_doMelt, wipe_exitMelt};
|
||||
|
||||
// initial stuff
|
||||
if (!go) {
|
||||
go = 1;
|
||||
// wipe_scr = (pixel_t *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG
|
||||
wipe_scr = I_VideoBuffer;
|
||||
(*wipes[wipeno * 3])(width, height, ticks);
|
||||
}
|
||||
|
||||
// do a piece of wipe-in
|
||||
V_MarkRect(0, 0, width, height);
|
||||
rc = (*wipes[wipeno * 3 + 1])(width, height, ticks);
|
||||
// V_DrawBlock(x, y, 0, width, height, wipe_scr); // DEBUG
|
||||
|
||||
// final stuff
|
||||
if (rc) {
|
||||
go = 0;
|
||||
(*wipes[wipeno * 3 + 2])(width, height, ticks);
|
||||
}
|
||||
|
||||
return !go;
|
||||
}
|
||||
42
src/f_wipe.h
Normal file
42
src/f_wipe.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Mission start screen wipe/melt, special effects.
|
||||
//
|
||||
|
||||
#ifndef __F_WIPE_H__
|
||||
#define __F_WIPE_H__
|
||||
|
||||
//
|
||||
// SCREEN WIPE PACKAGE
|
||||
//
|
||||
|
||||
enum {
|
||||
// simple gradual pixel change for 8-bit only
|
||||
wipe_ColorXForm,
|
||||
|
||||
// weird screen melt
|
||||
wipe_Melt,
|
||||
|
||||
wipe_NUMWIPES
|
||||
};
|
||||
|
||||
int wipe_StartScreen(int x, int y, int width, int height);
|
||||
|
||||
int wipe_EndScreen(int x, int y, int width, int height);
|
||||
|
||||
int wipe_ScreenWipe(int wipeno, int x, int y, int width, int height, int ticks);
|
||||
|
||||
#endif
|
||||
1989
src/g_game.c
Normal file
1989
src/g_game.c
Normal file
File diff suppressed because it is too large
Load Diff
78
src/g_game.h
Normal file
78
src/g_game.h
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Duh.
|
||||
//
|
||||
|
||||
#ifndef __G_GAME__
|
||||
#define __G_GAME__
|
||||
|
||||
#include "d_event.h"
|
||||
#include "d_mode.h"
|
||||
#include "d_ticcmd.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
//
|
||||
// GAME
|
||||
//
|
||||
void G_DeathMatchSpawnPlayer(int playernum);
|
||||
|
||||
void G_InitNew(skill_t skill, int episode, int map);
|
||||
|
||||
// Can be called by the startup code or M_Responder.
|
||||
// A normal game starts at map 1,
|
||||
// but a warp test can start elsewhere
|
||||
void G_DeferedInitNew(skill_t skill, int episode, int map);
|
||||
|
||||
void G_DeferedPlayDemo(char *demo);
|
||||
|
||||
// Can be called by the startup code or M_Responder,
|
||||
// calls P_SetupLevel or W_EnterWorld.
|
||||
void G_LoadGame(char *name);
|
||||
|
||||
void G_DoLoadGame(void);
|
||||
|
||||
// Called by M_Responder.
|
||||
void G_SaveGame(int slot, char *description);
|
||||
|
||||
// Only called by startup code.
|
||||
void G_RecordDemo(char *name);
|
||||
|
||||
void G_BeginRecording(void);
|
||||
|
||||
void G_PlayDemo(char *name);
|
||||
void G_TimeDemo(char *name);
|
||||
boolean G_CheckDemoStatus(void);
|
||||
|
||||
void G_ExitLevel(void);
|
||||
void G_SecretExitLevel(void);
|
||||
|
||||
void G_WorldDone(void);
|
||||
|
||||
// Read current data from inputs and build a player movement command.
|
||||
|
||||
void G_BuildTiccmd(ticcmd_t *cmd, int maketic);
|
||||
|
||||
void G_Ticker(void);
|
||||
boolean G_Responder(event_t *ev);
|
||||
|
||||
void G_ScreenShot(void);
|
||||
|
||||
void G_DrawMouseSpeedBox(void);
|
||||
int G_VanillaVersionCode(void);
|
||||
|
||||
extern int vanilla_savegame_limit;
|
||||
extern int vanilla_demo_limit;
|
||||
#endif
|
||||
302
src/gusconf.c
Normal file
302
src/gusconf.c
Normal file
@@ -0,0 +1,302 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// GUS emulation code.
|
||||
//
|
||||
// Actually emulating a GUS is far too much work; fortunately
|
||||
// GUS "emulation" already exists in the form of Timidity, which
|
||||
// supports GUS patch files. This code therefore converts Doom's
|
||||
// DMXGUS lump into an equivalent Timidity configuration file.
|
||||
//
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "m_misc.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
#define MAX_INSTRUMENTS 256
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *patch_names[MAX_INSTRUMENTS];
|
||||
int used[MAX_INSTRUMENTS];
|
||||
int mapping[MAX_INSTRUMENTS];
|
||||
unsigned int count;
|
||||
} gus_config_t;
|
||||
|
||||
char *gus_patch_path = "";
|
||||
int gus_ram_kb = 1024;
|
||||
|
||||
static unsigned int MappingIndex(void)
|
||||
{
|
||||
unsigned int result = gus_ram_kb / 256;
|
||||
|
||||
if (result < 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (result > 4)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static int SplitLine(char *line, char **fields, unsigned int max_fields)
|
||||
{
|
||||
unsigned int num_fields;
|
||||
char *p;
|
||||
|
||||
fields[0] = line;
|
||||
num_fields = 1;
|
||||
|
||||
for (p = line; *p != '\0'; ++p)
|
||||
{
|
||||
if (*p == ',')
|
||||
{
|
||||
*p = '\0';
|
||||
|
||||
// Skip spaces following the comma.
|
||||
do
|
||||
{
|
||||
++p;
|
||||
} while (*p != '\0' && isspace(*p));
|
||||
|
||||
fields[num_fields] = p;
|
||||
++num_fields;
|
||||
--p;
|
||||
|
||||
if (num_fields >= max_fields)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*p == '#')
|
||||
{
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip off trailing whitespace from the end of the line.
|
||||
p = fields[num_fields - 1] + strlen(fields[num_fields - 1]);
|
||||
while (p > fields[num_fields - 1] && isspace(*(p - 1)))
|
||||
{
|
||||
--p;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return num_fields;
|
||||
}
|
||||
|
||||
static void ParseLine(gus_config_t *config, char *line)
|
||||
{
|
||||
char *fields[6];
|
||||
unsigned int i;
|
||||
unsigned int num_fields;
|
||||
unsigned int instr_id, mapped_id;
|
||||
|
||||
num_fields = SplitLine(line, fields, 6);
|
||||
|
||||
if (num_fields < 6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
instr_id = atoi(fields[0]);
|
||||
|
||||
// Skip non GM percussions.
|
||||
if ((instr_id >= 128 && instr_id < 128 + 35) || instr_id > 128 + 81)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mapped_id = atoi(fields[MappingIndex()]);
|
||||
|
||||
for (i = 0; i < config->count; i++)
|
||||
{
|
||||
if (config->used[i] == mapped_id)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == config->count)
|
||||
{
|
||||
// DMX uses wrong patch name (we should use name of 'mapped_id'
|
||||
// instrument, but DMX uses name of 'instr_id' instead).
|
||||
free(config->patch_names[i]);
|
||||
config->patch_names[i] = M_StringDuplicate(fields[5]);
|
||||
config->used[i] = mapped_id;
|
||||
config->count++;
|
||||
}
|
||||
config->mapping[instr_id] = i;
|
||||
}
|
||||
|
||||
static void ParseDMXConfig(char *dmxconf, gus_config_t *config)
|
||||
{
|
||||
char *p, *newline;
|
||||
unsigned int i;
|
||||
|
||||
memset(config, 0, sizeof(gus_config_t));
|
||||
|
||||
for (i = 0; i < MAX_INSTRUMENTS; ++i)
|
||||
{
|
||||
config->mapping[i] = -1;
|
||||
config->used[i] = -1;
|
||||
}
|
||||
|
||||
config->count = 0;
|
||||
|
||||
p = dmxconf;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
newline = strchr(p, '\n');
|
||||
|
||||
if (newline != NULL)
|
||||
{
|
||||
*newline = '\0';
|
||||
}
|
||||
|
||||
ParseLine(config, p);
|
||||
|
||||
if (newline == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = newline + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeDMXConfig(gus_config_t *config)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < MAX_INSTRUMENTS; ++i)
|
||||
{
|
||||
free(config->patch_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static char *ReadDMXConfig(void)
|
||||
{
|
||||
int lumpnum;
|
||||
unsigned int len;
|
||||
char *data;
|
||||
|
||||
// TODO: This should be chosen based on gamemode == commercial:
|
||||
|
||||
lumpnum = W_CheckNumForName("DMXGUS");
|
||||
|
||||
if (lumpnum < 0)
|
||||
{
|
||||
lumpnum = W_GetNumForName("DMXGUSC");
|
||||
}
|
||||
|
||||
len = W_LumpLength(lumpnum);
|
||||
data = Z_Malloc(len + 1, PU_STATIC, NULL);
|
||||
W_ReadLump(lumpnum, data);
|
||||
|
||||
data[len] = '\0';
|
||||
return data;
|
||||
}
|
||||
|
||||
static boolean WriteTimidityConfig(char *path, gus_config_t *config)
|
||||
{
|
||||
FILE *fstream;
|
||||
unsigned int i;
|
||||
|
||||
fstream = fopen(path, "w");
|
||||
|
||||
if (fstream == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(fstream, "# Autogenerated Timidity config.\n\n");
|
||||
|
||||
fprintf(fstream, "dir %s\n", gus_patch_path);
|
||||
|
||||
fprintf(fstream, "\nbank 0\n\n");
|
||||
|
||||
for (i = 0; i < 128; ++i)
|
||||
{
|
||||
if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
|
||||
&& config->patch_names[config->mapping[i]] != NULL)
|
||||
{
|
||||
fprintf(fstream, "%i %s\n",
|
||||
i, config->patch_names[config->mapping[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fstream, "\ndrumset 0\n\n");
|
||||
|
||||
for (i = 128 + 35; i <= 128 + 81; ++i)
|
||||
{
|
||||
if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
|
||||
&& config->patch_names[config->mapping[i]] != NULL)
|
||||
{
|
||||
fprintf(fstream, "%i %s\n",
|
||||
i - 128, config->patch_names[config->mapping[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fstream, "\n");
|
||||
|
||||
fclose(fstream);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean GUS_WriteConfig(char *path)
|
||||
{
|
||||
boolean result;
|
||||
char *dmxconf;
|
||||
gus_config_t config;
|
||||
|
||||
if (!strcmp(gus_patch_path, ""))
|
||||
{
|
||||
printf("You haven't configured gus_patch_path.\n");
|
||||
printf("gus_patch_path needs to point to the location of "
|
||||
"your GUS patch set.\n"
|
||||
"To get a copy of the \"standard\" GUS patches, "
|
||||
"download a copy of dgguspat.zip.\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
dmxconf = ReadDMXConfig();
|
||||
ParseDMXConfig(dmxconf, &config);
|
||||
|
||||
result = WriteTimidityConfig(path, &config);
|
||||
|
||||
FreeDMXConfig(&config);
|
||||
Z_Free(dmxconf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
29
src/gusconf.h
Normal file
29
src/gusconf.h
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// GUS emulation code.
|
||||
//
|
||||
|
||||
#ifndef __GUSCONF_H__
|
||||
#define __GUSCONF_H__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
extern char *gus_patch_path;
|
||||
extern int gus_ram_kb;
|
||||
|
||||
boolean GUS_WriteConfig(char *path);
|
||||
|
||||
#endif /* #ifndef __GUSCONF_H__ */
|
||||
|
||||
261
src/hu_lib.c
Normal file
261
src/hu_lib.c
Normal file
@@ -0,0 +1,261 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION: heads-up text and input code
|
||||
//
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "doomkeys.h"
|
||||
#include "hu_lib.h"
|
||||
#include "i_swap.h"
|
||||
#include "i_video.h"
|
||||
#include "r_draw.h"
|
||||
#include "r_main.h"
|
||||
#include "r_state.h"
|
||||
#include "v_video.h"
|
||||
|
||||
// boolean : whether the screen is always erased
|
||||
#define noterased viewwindowx
|
||||
|
||||
extern boolean automapactive; // in AM_map.c
|
||||
|
||||
void HUlib_init(void) {}
|
||||
|
||||
void HUlib_clearTextLine(hu_textline_t *t) {
|
||||
t->len = 0;
|
||||
t->l[0] = 0;
|
||||
t->needsupdate = true;
|
||||
}
|
||||
|
||||
void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t **f, int sc) {
|
||||
t->x = x;
|
||||
t->y = y;
|
||||
t->f = f;
|
||||
t->sc = sc;
|
||||
HUlib_clearTextLine(t);
|
||||
}
|
||||
|
||||
boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch) {
|
||||
|
||||
if (t->len == HU_MAXLINELENGTH)
|
||||
return false;
|
||||
else {
|
||||
t->l[t->len++] = ch;
|
||||
t->l[t->len] = 0;
|
||||
t->needsupdate = 4;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean HUlib_delCharFromTextLine(hu_textline_t *t) {
|
||||
|
||||
if (!t->len)
|
||||
return false;
|
||||
else {
|
||||
t->l[--t->len] = 0;
|
||||
t->needsupdate = 4;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor) {
|
||||
|
||||
int i;
|
||||
int w;
|
||||
int x;
|
||||
unsigned char c;
|
||||
|
||||
// draw the new stuff
|
||||
x = l->x;
|
||||
for (i = 0; i < l->len; i++) {
|
||||
c = toupper(l->l[i]);
|
||||
if (c != ' ' && c >= l->sc && c <= '_') {
|
||||
w = SHORT(l->f[c - l->sc]->width);
|
||||
if (x + w > SCREENWIDTH)
|
||||
break;
|
||||
V_DrawPatchDirect(x, l->y, l->f[c - l->sc]);
|
||||
x += w;
|
||||
} else {
|
||||
x += 4;
|
||||
if (x >= SCREENWIDTH)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// draw the cursor if requested
|
||||
if (drawcursor && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH) {
|
||||
V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]);
|
||||
}
|
||||
}
|
||||
|
||||
// sorta called by HU_Erase and just better darn get things straight
|
||||
void HUlib_eraseTextLine(hu_textline_t *l) {
|
||||
int lh;
|
||||
int y;
|
||||
int yoffset;
|
||||
|
||||
// Only erases when NOT in automap and the screen is reduced,
|
||||
// and the text must either need updating or refreshing
|
||||
// (because of a recent change back from the automap)
|
||||
|
||||
if (!automapactive && viewwindowx && l->needsupdate) {
|
||||
lh = SHORT(l->f[0]->height) + 1;
|
||||
for (y = l->y, yoffset = y * SCREENWIDTH; y < l->y + lh;
|
||||
y++, yoffset += SCREENWIDTH) {
|
||||
if (y < viewwindowy || y >= viewwindowy + viewheight)
|
||||
R_VideoErase(yoffset, SCREENWIDTH); // erase entire line
|
||||
else {
|
||||
R_VideoErase(yoffset, viewwindowx); // erase left border
|
||||
R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
|
||||
// erase right border
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l->needsupdate)
|
||||
l->needsupdate--;
|
||||
}
|
||||
|
||||
void HUlib_initSText(hu_stext_t *s, int x, int y, int h, patch_t **font,
|
||||
int startchar, boolean *on) {
|
||||
|
||||
int i;
|
||||
|
||||
s->h = h;
|
||||
s->on = on;
|
||||
s->laston = true;
|
||||
s->cl = 0;
|
||||
for (i = 0; i < h; i++)
|
||||
HUlib_initTextLine(&s->l[i], x, y - i * (SHORT(font[0]->height) + 1), font,
|
||||
startchar);
|
||||
}
|
||||
|
||||
void HUlib_addLineToSText(hu_stext_t *s) {
|
||||
|
||||
int i;
|
||||
|
||||
// add a clear line
|
||||
if (++s->cl == s->h)
|
||||
s->cl = 0;
|
||||
HUlib_clearTextLine(&s->l[s->cl]);
|
||||
|
||||
// everything needs updating
|
||||
for (i = 0; i < s->h; i++)
|
||||
s->l[i].needsupdate = 4;
|
||||
}
|
||||
|
||||
void HUlib_addMessageToSText(hu_stext_t *s, char *prefix, char *msg) {
|
||||
HUlib_addLineToSText(s);
|
||||
if (prefix)
|
||||
while (*prefix)
|
||||
HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++));
|
||||
|
||||
while (*msg)
|
||||
HUlib_addCharToTextLine(&s->l[s->cl], *(msg++));
|
||||
}
|
||||
|
||||
void HUlib_drawSText(hu_stext_t *s) {
|
||||
int i, idx;
|
||||
hu_textline_t *l;
|
||||
|
||||
if (!*s->on)
|
||||
return; // if not on, don't draw
|
||||
|
||||
// draw everything
|
||||
for (i = 0; i < s->h; i++) {
|
||||
idx = s->cl - i;
|
||||
if (idx < 0)
|
||||
idx += s->h; // handle queue of lines
|
||||
|
||||
l = &s->l[idx];
|
||||
|
||||
// need a decision made here on whether to skip the draw
|
||||
HUlib_drawTextLine(l, false); // no cursor, please
|
||||
}
|
||||
}
|
||||
|
||||
void HUlib_eraseSText(hu_stext_t *s) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->h; i++) {
|
||||
if (s->laston && !*s->on)
|
||||
s->l[i].needsupdate = 4;
|
||||
HUlib_eraseTextLine(&s->l[i]);
|
||||
}
|
||||
s->laston = *s->on;
|
||||
}
|
||||
|
||||
void HUlib_initIText(hu_itext_t *it, int x, int y, patch_t **font,
|
||||
int startchar, boolean *on) {
|
||||
it->lm = 0; // default left margin is start of text
|
||||
it->on = on;
|
||||
it->laston = true;
|
||||
HUlib_initTextLine(&it->l, x, y, font, startchar);
|
||||
}
|
||||
|
||||
// The following deletion routines adhere to the left margin restriction
|
||||
void HUlib_delCharFromIText(hu_itext_t *it) {
|
||||
if (it->l.len != it->lm)
|
||||
HUlib_delCharFromTextLine(&it->l);
|
||||
}
|
||||
|
||||
void HUlib_eraseLineFromIText(hu_itext_t *it) {
|
||||
while (it->lm != it->l.len)
|
||||
HUlib_delCharFromTextLine(&it->l);
|
||||
}
|
||||
|
||||
// Resets left margin as well
|
||||
void HUlib_resetIText(hu_itext_t *it) {
|
||||
it->lm = 0;
|
||||
HUlib_clearTextLine(&it->l);
|
||||
}
|
||||
|
||||
void HUlib_addPrefixToIText(hu_itext_t *it, char *str) {
|
||||
while (*str)
|
||||
HUlib_addCharToTextLine(&it->l, *(str++));
|
||||
it->lm = it->l.len;
|
||||
}
|
||||
|
||||
// wrapper function for handling general keyed input.
|
||||
// returns true if it ate the key
|
||||
boolean HUlib_keyInIText(hu_itext_t *it, unsigned char ch) {
|
||||
ch = toupper(ch);
|
||||
|
||||
if (ch >= ' ' && ch <= '_')
|
||||
HUlib_addCharToTextLine(&it->l, (char)ch);
|
||||
else if (ch == KEY_BACKSPACE)
|
||||
HUlib_delCharFromIText(it);
|
||||
else if (ch != KEY_ENTER)
|
||||
return false; // did not eat key
|
||||
|
||||
return true; // ate the key
|
||||
}
|
||||
|
||||
void HUlib_drawIText(hu_itext_t *it) {
|
||||
|
||||
hu_textline_t *l = &it->l;
|
||||
|
||||
if (!*it->on)
|
||||
return;
|
||||
HUlib_drawTextLine(l, true); // draw the line w/ cursor
|
||||
}
|
||||
|
||||
void HUlib_eraseIText(hu_itext_t *it) {
|
||||
if (it->laston && !*it->on)
|
||||
it->l.needsupdate = 4;
|
||||
HUlib_eraseTextLine(&it->l);
|
||||
it->laston = *it->on;
|
||||
}
|
||||
152
src/hu_lib.h
Normal file
152
src/hu_lib.h
Normal file
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION: none
|
||||
//
|
||||
|
||||
#ifndef __HULIB__
|
||||
#define __HULIB__
|
||||
|
||||
#include "doomkeys.h"
|
||||
#include "doomtype.h"
|
||||
// We are referring to patches.
|
||||
#include "v_patch.h"
|
||||
|
||||
// font stuff
|
||||
#define HU_CHARERASE KEY_BACKSPACE
|
||||
|
||||
#define HU_MAXLINES 4
|
||||
#define HU_MAXLINELENGTH 80
|
||||
|
||||
//
|
||||
// Typedefs of widgets
|
||||
//
|
||||
|
||||
// Text Line widget
|
||||
// (parent of Scrolling Text and Input Text widgets)
|
||||
typedef struct {
|
||||
// left-justified position of scrolling text window
|
||||
int x;
|
||||
int y;
|
||||
|
||||
patch_t **f; // font
|
||||
int sc; // start character
|
||||
char l[HU_MAXLINELENGTH + 1]; // line of text
|
||||
int len; // current line length
|
||||
|
||||
// whether this line needs to be udpated
|
||||
int needsupdate;
|
||||
|
||||
} hu_textline_t;
|
||||
|
||||
// Scrolling Text window widget
|
||||
// (child of Text Line widget)
|
||||
typedef struct {
|
||||
hu_textline_t l[HU_MAXLINES]; // text lines to draw
|
||||
int h; // height in lines
|
||||
int cl; // current line number
|
||||
|
||||
// pointer to boolean stating whether to update window
|
||||
boolean *on;
|
||||
boolean laston; // last value of *->on.
|
||||
|
||||
} hu_stext_t;
|
||||
|
||||
// Input Text Line widget
|
||||
// (child of Text Line widget)
|
||||
typedef struct {
|
||||
hu_textline_t l; // text line to input on
|
||||
|
||||
// left margin past which I am not to delete characters
|
||||
int lm;
|
||||
|
||||
// pointer to boolean stating whether to update window
|
||||
boolean *on;
|
||||
boolean laston; // last value of *->on;
|
||||
|
||||
} hu_itext_t;
|
||||
|
||||
//
|
||||
// Widget creation, access, and update routines
|
||||
//
|
||||
|
||||
// initializes heads-up widget library
|
||||
void HUlib_init(void);
|
||||
|
||||
//
|
||||
// textline code
|
||||
//
|
||||
|
||||
// clear a line of text
|
||||
void HUlib_clearTextLine(hu_textline_t *t);
|
||||
|
||||
void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t **f, int sc);
|
||||
|
||||
// returns success
|
||||
boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch);
|
||||
|
||||
// returns success
|
||||
boolean HUlib_delCharFromTextLine(hu_textline_t *t);
|
||||
|
||||
// draws tline
|
||||
void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor);
|
||||
|
||||
// erases text line
|
||||
void HUlib_eraseTextLine(hu_textline_t *l);
|
||||
|
||||
//
|
||||
// Scrolling Text window widget routines
|
||||
//
|
||||
|
||||
// ?
|
||||
void HUlib_initSText(hu_stext_t *s, int x, int y, int h, patch_t **font,
|
||||
int startchar, boolean *on);
|
||||
|
||||
// add a new line
|
||||
void HUlib_addLineToSText(hu_stext_t *s);
|
||||
|
||||
// ?
|
||||
void HUlib_addMessageToSText(hu_stext_t *s, char *prefix, char *msg);
|
||||
|
||||
// draws stext
|
||||
void HUlib_drawSText(hu_stext_t *s);
|
||||
|
||||
// erases all stext lines
|
||||
void HUlib_eraseSText(hu_stext_t *s);
|
||||
|
||||
// Input Text Line widget routines
|
||||
void HUlib_initIText(hu_itext_t *it, int x, int y, patch_t **font,
|
||||
int startchar, boolean *on);
|
||||
|
||||
// enforces left margin
|
||||
void HUlib_delCharFromIText(hu_itext_t *it);
|
||||
|
||||
// enforces left margin
|
||||
void HUlib_eraseLineFromIText(hu_itext_t *it);
|
||||
|
||||
// resets line and left margin
|
||||
void HUlib_resetIText(hu_itext_t *it);
|
||||
|
||||
// left of left-margin
|
||||
void HUlib_addPrefixToIText(hu_itext_t *it, char *str);
|
||||
|
||||
// whether eaten
|
||||
boolean HUlib_keyInIText(hu_itext_t *it, unsigned char ch);
|
||||
|
||||
void HUlib_drawIText(hu_itext_t *it);
|
||||
|
||||
// erases all itext lines
|
||||
void HUlib_eraseIText(hu_itext_t *it);
|
||||
|
||||
#endif
|
||||
457
src/hu_stuff.c
Normal file
457
src/hu_stuff.c
Normal file
@@ -0,0 +1,457 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION: Heads-up displays
|
||||
//
|
||||
|
||||
#include "hu_stuff.h"
|
||||
#include "d_englsh.h"
|
||||
#include "d_mode.h"
|
||||
#include "d_player.h"
|
||||
#include "d_ticcmd.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomkeys.h"
|
||||
#include "doomstat.h"
|
||||
#include "hu_lib.h"
|
||||
#include "i_input.h"
|
||||
#include "i_swap.h"
|
||||
#include "i_video.h"
|
||||
#include "m_controls.h"
|
||||
#include "m_misc.h"
|
||||
#include "s_sound.h"
|
||||
#include "sounds.h"
|
||||
#include "v_patch.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
//
|
||||
// Locally used constants, shortcuts.
|
||||
//
|
||||
#define HU_TITLE (mapnames[(gameepisode - 1) * 9 + gamemap - 1])
|
||||
#define HU_TITLE2 (mapnames_commercial[gamemap - 1])
|
||||
#define HU_TITLEP (mapnames_commercial[gamemap - 1 + 32])
|
||||
#define HU_TITLET (mapnames_commercial[gamemap - 1 + 64])
|
||||
#define HU_TITLE_CHEX (mapnames_chex[(gameepisode - 1) * 9 + gamemap - 1])
|
||||
#define HU_TITLEHEIGHT 1
|
||||
#define HU_TITLEX 0
|
||||
#define HU_TITLEY (167 - SHORT(hu_font[0]->height))
|
||||
|
||||
#define HU_INPUTTOGGLE 't'
|
||||
#define HU_INPUTX HU_MSGX
|
||||
#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT * (SHORT(hu_font[0]->height) + 1))
|
||||
#define HU_INPUTWIDTH 64
|
||||
#define HU_INPUTHEIGHT 1
|
||||
|
||||
char *chat_macros[10] = {HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2,
|
||||
HUSTR_CHATMACRO3, HUSTR_CHATMACRO4, HUSTR_CHATMACRO5,
|
||||
HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, HUSTR_CHATMACRO8,
|
||||
HUSTR_CHATMACRO9};
|
||||
|
||||
char *player_names[] = {HUSTR_PLRGREEN, HUSTR_PLRINDIGO, HUSTR_PLRBROWN,
|
||||
HUSTR_PLRRED};
|
||||
|
||||
char chat_char; // remove later.
|
||||
static player_t *plr;
|
||||
patch_t *hu_font[HU_FONTSIZE];
|
||||
static hu_textline_t w_title;
|
||||
boolean chat_on;
|
||||
static hu_itext_t w_chat;
|
||||
static boolean always_off = false;
|
||||
static char chat_dest[MAXPLAYERS];
|
||||
static hu_itext_t w_inputbuffer[MAXPLAYERS];
|
||||
|
||||
static boolean message_on;
|
||||
boolean message_dontfuckwithme;
|
||||
static boolean message_nottobefuckedwith;
|
||||
|
||||
static hu_stext_t w_message;
|
||||
static int message_counter;
|
||||
|
||||
extern int showMessages;
|
||||
|
||||
static boolean headsupactive = false;
|
||||
|
||||
//
|
||||
// Builtin map names.
|
||||
// The actual names can be found in DStrings.h.
|
||||
//
|
||||
|
||||
char *mapnames[] = // DOOM shareware/registered/retail (Ultimate) names.
|
||||
{
|
||||
|
||||
HUSTR_E1M1, HUSTR_E1M2, HUSTR_E1M3, HUSTR_E1M4, HUSTR_E1M5,
|
||||
HUSTR_E1M6, HUSTR_E1M7, HUSTR_E1M8, HUSTR_E1M9,
|
||||
|
||||
HUSTR_E2M1, HUSTR_E2M2, HUSTR_E2M3, HUSTR_E2M4, HUSTR_E2M5,
|
||||
HUSTR_E2M6, HUSTR_E2M7, HUSTR_E2M8, HUSTR_E2M9,
|
||||
|
||||
HUSTR_E3M1, HUSTR_E3M2, HUSTR_E3M3, HUSTR_E3M4, HUSTR_E3M5,
|
||||
HUSTR_E3M6, HUSTR_E3M7, HUSTR_E3M8, HUSTR_E3M9,
|
||||
|
||||
HUSTR_E4M1, HUSTR_E4M2, HUSTR_E4M3, HUSTR_E4M4, HUSTR_E4M5,
|
||||
HUSTR_E4M6, HUSTR_E4M7, HUSTR_E4M8, HUSTR_E4M9,
|
||||
|
||||
"NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL",
|
||||
"NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL"};
|
||||
|
||||
char *mapnames_chex[] = // Chex Quest names.
|
||||
{
|
||||
|
||||
HUSTR_E1M1, HUSTR_E1M2, HUSTR_E1M3, HUSTR_E1M4, HUSTR_E1M5,
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5, HUSTR_E1M5,
|
||||
|
||||
"NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL",
|
||||
"NEWLEVEL", "NEWLEVEL", "NEWLEVEL", "NEWLEVEL"};
|
||||
|
||||
// List of names for levels in commercial IWADs
|
||||
// (doom2.wad, plutonia.wad, tnt.wad). These are stored in a
|
||||
// single large array; WADs like pl2.wad have a MAP33, and rely on
|
||||
// the layout in the Vanilla executable, where it is possible to
|
||||
// overflow the end of one array into the next.
|
||||
|
||||
char *mapnames_commercial[] = {
|
||||
// DOOM 2 map names.
|
||||
|
||||
HUSTR_1, HUSTR_2, HUSTR_3, HUSTR_4, HUSTR_5, HUSTR_6, HUSTR_7, HUSTR_8,
|
||||
HUSTR_9, HUSTR_10, HUSTR_11,
|
||||
|
||||
HUSTR_12, HUSTR_13, HUSTR_14, HUSTR_15, HUSTR_16, HUSTR_17, HUSTR_18,
|
||||
HUSTR_19, HUSTR_20,
|
||||
|
||||
HUSTR_21, HUSTR_22, HUSTR_23, HUSTR_24, HUSTR_25, HUSTR_26, HUSTR_27,
|
||||
HUSTR_28, HUSTR_29, HUSTR_30, HUSTR_31, HUSTR_32,
|
||||
|
||||
// Plutonia WAD map names.
|
||||
|
||||
PHUSTR_1, PHUSTR_2, PHUSTR_3, PHUSTR_4, PHUSTR_5, PHUSTR_6, PHUSTR_7,
|
||||
PHUSTR_8, PHUSTR_9, PHUSTR_10, PHUSTR_11,
|
||||
|
||||
PHUSTR_12, PHUSTR_13, PHUSTR_14, PHUSTR_15, PHUSTR_16, PHUSTR_17, PHUSTR_18,
|
||||
PHUSTR_19, PHUSTR_20,
|
||||
|
||||
PHUSTR_21, PHUSTR_22, PHUSTR_23, PHUSTR_24, PHUSTR_25, PHUSTR_26, PHUSTR_27,
|
||||
PHUSTR_28, PHUSTR_29, PHUSTR_30, PHUSTR_31, PHUSTR_32,
|
||||
|
||||
// TNT WAD map names.
|
||||
|
||||
THUSTR_1, THUSTR_2, THUSTR_3, THUSTR_4, THUSTR_5, THUSTR_6, THUSTR_7,
|
||||
THUSTR_8, THUSTR_9, THUSTR_10, THUSTR_11,
|
||||
|
||||
THUSTR_12, THUSTR_13, THUSTR_14, THUSTR_15, THUSTR_16, THUSTR_17, THUSTR_18,
|
||||
THUSTR_19, THUSTR_20,
|
||||
|
||||
THUSTR_21, THUSTR_22, THUSTR_23, THUSTR_24, THUSTR_25, THUSTR_26, THUSTR_27,
|
||||
THUSTR_28, THUSTR_29, THUSTR_30, THUSTR_31, THUSTR_32};
|
||||
|
||||
void HU_Init(void) {
|
||||
|
||||
int i;
|
||||
int j;
|
||||
char buffer[9];
|
||||
|
||||
// load the heads-up font
|
||||
j = HU_FONTSTART;
|
||||
for (i = 0; i < HU_FONTSIZE; i++) {
|
||||
M_snprintf(buffer, 9, "STCFN%.3d", j++);
|
||||
hu_font[i] = (patch_t *)W_CacheLumpName(buffer, PU_STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
void HU_Stop(void) { headsupactive = false; }
|
||||
|
||||
void HU_Start(void) {
|
||||
|
||||
int i;
|
||||
char *s;
|
||||
|
||||
if (headsupactive)
|
||||
HU_Stop();
|
||||
|
||||
plr = &players[consoleplayer];
|
||||
message_on = false;
|
||||
message_dontfuckwithme = false;
|
||||
message_nottobefuckedwith = false;
|
||||
chat_on = false;
|
||||
|
||||
// create the message widget
|
||||
HUlib_initSText(&w_message, HU_MSGX, HU_MSGY, HU_MSGHEIGHT, hu_font,
|
||||
HU_FONTSTART, &message_on);
|
||||
|
||||
// create the map title widget
|
||||
HUlib_initTextLine(&w_title, HU_TITLEX, HU_TITLEY, hu_font, HU_FONTSTART);
|
||||
|
||||
switch (logical_gamemission) {
|
||||
case doom:
|
||||
s = HU_TITLE;
|
||||
break;
|
||||
case doom2:
|
||||
s = HU_TITLE2;
|
||||
break;
|
||||
case pack_plut:
|
||||
s = HU_TITLEP;
|
||||
break;
|
||||
case pack_tnt:
|
||||
s = HU_TITLET;
|
||||
break;
|
||||
default:
|
||||
s = "Unknown level";
|
||||
break;
|
||||
}
|
||||
|
||||
if (logical_gamemission == doom && gameversion == exe_chex) {
|
||||
s = HU_TITLE_CHEX;
|
||||
}
|
||||
|
||||
while (*s)
|
||||
HUlib_addCharToTextLine(&w_title, *(s++));
|
||||
|
||||
// create the chat widget
|
||||
HUlib_initIText(&w_chat, HU_INPUTX, HU_INPUTY, hu_font, HU_FONTSTART,
|
||||
&chat_on);
|
||||
|
||||
// create the inputbuffer widgets
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
HUlib_initIText(&w_inputbuffer[i], 0, 0, 0, 0, &always_off);
|
||||
|
||||
headsupactive = true;
|
||||
}
|
||||
|
||||
void HU_Drawer(void) {
|
||||
|
||||
HUlib_drawSText(&w_message);
|
||||
HUlib_drawIText(&w_chat);
|
||||
if (automapactive)
|
||||
HUlib_drawTextLine(&w_title, false);
|
||||
}
|
||||
|
||||
void HU_Erase(void) {
|
||||
|
||||
HUlib_eraseSText(&w_message);
|
||||
HUlib_eraseIText(&w_chat);
|
||||
HUlib_eraseTextLine(&w_title);
|
||||
}
|
||||
|
||||
void HU_Ticker(void) {
|
||||
|
||||
int i, rc;
|
||||
char c;
|
||||
|
||||
// tick down message counter if message is up
|
||||
if (message_counter && !--message_counter) {
|
||||
message_on = false;
|
||||
message_nottobefuckedwith = false;
|
||||
}
|
||||
|
||||
if (showMessages || message_dontfuckwithme) {
|
||||
|
||||
// display message if necessary
|
||||
if ((plr->message && !message_nottobefuckedwith) ||
|
||||
(plr->message && message_dontfuckwithme)) {
|
||||
HUlib_addMessageToSText(&w_message, 0, plr->message);
|
||||
plr->message = 0;
|
||||
message_on = true;
|
||||
message_counter = HU_MSGTIMEOUT;
|
||||
message_nottobefuckedwith = message_dontfuckwithme;
|
||||
message_dontfuckwithme = 0;
|
||||
}
|
||||
|
||||
} // else message_on = false;
|
||||
|
||||
// check for incoming chat characters
|
||||
if (netgame) {
|
||||
for (i = 0; i < MAXPLAYERS; i++) {
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (i != consoleplayer && (c = players[i].cmd.chatchar)) {
|
||||
if (c <= HU_BROADCAST)
|
||||
chat_dest[i] = c;
|
||||
else {
|
||||
rc = HUlib_keyInIText(&w_inputbuffer[i], c);
|
||||
if (rc && c == KEY_ENTER) {
|
||||
if (w_inputbuffer[i].l.len && (chat_dest[i] == consoleplayer + 1 ||
|
||||
chat_dest[i] == HU_BROADCAST)) {
|
||||
HUlib_addMessageToSText(&w_message, (player_names[i]),
|
||||
w_inputbuffer[i].l.l);
|
||||
|
||||
message_nottobefuckedwith = true;
|
||||
message_on = true;
|
||||
message_counter = HU_MSGTIMEOUT;
|
||||
if (gamemode == commercial)
|
||||
S_StartSound(0, sfx_radio);
|
||||
else
|
||||
S_StartSound(0, sfx_tink);
|
||||
}
|
||||
HUlib_resetIText(&w_inputbuffer[i]);
|
||||
}
|
||||
}
|
||||
players[i].cmd.chatchar = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define QUEUESIZE 128
|
||||
|
||||
static char chatchars[QUEUESIZE];
|
||||
static int head = 0;
|
||||
static int tail = 0;
|
||||
|
||||
void HU_queueChatChar(char c) {
|
||||
if (((head + 1) & (QUEUESIZE - 1)) == tail) {
|
||||
plr->message = (HUSTR_MSGU);
|
||||
} else {
|
||||
chatchars[head] = c;
|
||||
head = (head + 1) & (QUEUESIZE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
char HU_dequeueChatChar(void) {
|
||||
char c;
|
||||
|
||||
if (head != tail) {
|
||||
c = chatchars[tail];
|
||||
tail = (tail + 1) & (QUEUESIZE - 1);
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void StartChatInput(int dest) {
|
||||
chat_on = true;
|
||||
HUlib_resetIText(&w_chat);
|
||||
HU_queueChatChar(HU_BROADCAST);
|
||||
|
||||
I_StartTextInput(0, 8, SCREENWIDTH, 16);
|
||||
}
|
||||
|
||||
static void StopChatInput(void) {
|
||||
chat_on = false;
|
||||
I_StopTextInput();
|
||||
}
|
||||
|
||||
boolean HU_Responder(event_t *ev) {
|
||||
|
||||
static char lastmessage[HU_MAXLINELENGTH + 1];
|
||||
char *macromessage;
|
||||
boolean eatkey = false;
|
||||
static boolean altdown = false;
|
||||
unsigned char c;
|
||||
int i;
|
||||
int numplayers;
|
||||
|
||||
static int num_nobrainers = 0;
|
||||
|
||||
numplayers = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
numplayers += playeringame[i];
|
||||
|
||||
if (ev->data1 == KEY_RSHIFT) {
|
||||
return false;
|
||||
} else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT) {
|
||||
altdown = ev->type == ev_keydown;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ev->type != ev_keydown)
|
||||
return false;
|
||||
|
||||
if (!chat_on) {
|
||||
if (ev->data1 == key_message_refresh) {
|
||||
message_on = true;
|
||||
message_counter = HU_MSGTIMEOUT;
|
||||
eatkey = true;
|
||||
} else if (netgame && ev->data2 == key_multi_msg) {
|
||||
eatkey = true;
|
||||
StartChatInput(HU_BROADCAST);
|
||||
} else if (netgame && numplayers > 2) {
|
||||
for (i = 0; i < MAXPLAYERS; i++) {
|
||||
if (ev->data2 == key_multi_msgplayer[i]) {
|
||||
if (playeringame[i] && i != consoleplayer) {
|
||||
eatkey = true;
|
||||
StartChatInput(i + 1);
|
||||
break;
|
||||
} else if (i == consoleplayer) {
|
||||
num_nobrainers++;
|
||||
if (num_nobrainers < 3)
|
||||
plr->message = (HUSTR_TALKTOSELF1);
|
||||
else if (num_nobrainers < 6)
|
||||
plr->message = (HUSTR_TALKTOSELF2);
|
||||
else if (num_nobrainers < 9)
|
||||
plr->message = (HUSTR_TALKTOSELF3);
|
||||
else if (num_nobrainers < 32)
|
||||
plr->message = (HUSTR_TALKTOSELF4);
|
||||
else
|
||||
plr->message = (HUSTR_TALKTOSELF5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// send a macro
|
||||
if (altdown) {
|
||||
c = ev->data1 - '0';
|
||||
if (c > 9)
|
||||
return false;
|
||||
// fprintf(stderr, "got here\n");
|
||||
macromessage = chat_macros[c];
|
||||
|
||||
// kill last message with a '\n'
|
||||
HU_queueChatChar(KEY_ENTER); // DEBUG!!!
|
||||
|
||||
// send the macro message
|
||||
while (*macromessage)
|
||||
HU_queueChatChar(*macromessage++);
|
||||
HU_queueChatChar(KEY_ENTER);
|
||||
|
||||
// leave chat mode and notify that it was sent
|
||||
StopChatInput();
|
||||
M_StringCopy(lastmessage, chat_macros[c], sizeof(lastmessage));
|
||||
plr->message = lastmessage;
|
||||
eatkey = true;
|
||||
} else {
|
||||
c = ev->data3;
|
||||
|
||||
eatkey = HUlib_keyInIText(&w_chat, c);
|
||||
if (eatkey) {
|
||||
// static unsigned char buf[20]; // DEBUG
|
||||
HU_queueChatChar(c);
|
||||
|
||||
// M_snprintf(buf, sizeof(buf), "KEY: %d => %d", ev->data1, c);
|
||||
// plr->message = buf;
|
||||
}
|
||||
if (c == KEY_ENTER) {
|
||||
StopChatInput();
|
||||
if (w_chat.l.len) {
|
||||
M_StringCopy(lastmessage, w_chat.l.l, sizeof(lastmessage));
|
||||
plr->message = lastmessage;
|
||||
}
|
||||
} else if (c == KEY_ESCAPE) {
|
||||
StopChatInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return eatkey;
|
||||
}
|
||||
59
src/hu_stuff.h
Normal file
59
src/hu_stuff.h
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION: Head up display
|
||||
//
|
||||
|
||||
#ifndef __HU_STUFF_H__
|
||||
#define __HU_STUFF_H__
|
||||
|
||||
#include "d_event.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_timer.h"
|
||||
|
||||
//
|
||||
// Globally visible constants.
|
||||
//
|
||||
#define HU_FONTSTART '!' // the first font characters
|
||||
#define HU_FONTEND '_' // the last font characters
|
||||
|
||||
// Calculate # of glyphs in font.
|
||||
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
|
||||
|
||||
#define HU_BROADCAST 5
|
||||
|
||||
#define HU_MSGX 0
|
||||
#define HU_MSGY 0
|
||||
#define HU_MSGWIDTH 64 // in characters
|
||||
#define HU_MSGHEIGHT 1 // in lines
|
||||
|
||||
#define HU_MSGTIMEOUT (4 * TICRATE)
|
||||
|
||||
//
|
||||
// HEADS UP TEXT
|
||||
//
|
||||
|
||||
void HU_Init(void);
|
||||
void HU_Start(void);
|
||||
|
||||
boolean HU_Responder(event_t *ev);
|
||||
|
||||
void HU_Ticker(void);
|
||||
void HU_Drawer(void);
|
||||
char HU_dequeueChatChar(void);
|
||||
void HU_Erase(void);
|
||||
|
||||
extern char *chat_macros[10];
|
||||
|
||||
#endif
|
||||
69
src/i_cdmus.c
Normal file
69
src/i_cdmus.c
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 1993-2008 Raven Software
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// Hexen CD interface.
|
||||
//
|
||||
|
||||
#include "i_cdmus.h"
|
||||
|
||||
int cd_Error;
|
||||
|
||||
int I_CDMusInit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We cannot print status messages inline during startup, they must
|
||||
// be deferred until after I_CDMusInit has returned.
|
||||
|
||||
void I_CDMusPrintStartup(void)
|
||||
{
|
||||
}
|
||||
|
||||
int I_CDMusPlay(int track)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_CDMusStop(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_CDMusResume(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_CDMusSetVolume(int volume)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_CDMusFirstTrack(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_CDMusLastTrack(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_CDMusTrackLength(int track_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
41
src/i_cdmus.h
Normal file
41
src/i_cdmus.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 1993-2008 Raven Software
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
// i_cdmus.h
|
||||
|
||||
#ifndef __ICDMUS__
|
||||
#define __ICDMUS__
|
||||
|
||||
#define CDERR_NOTINSTALLED 10 // MSCDEX not installed
|
||||
#define CDERR_NOAUDIOSUPPORT 11 // CD-ROM Doesn't support audio
|
||||
#define CDERR_NOAUDIOTRACKS 12 // Current CD has no audio tracks
|
||||
#define CDERR_BADDRIVE 20 // Bad drive number
|
||||
#define CDERR_BADTRACK 21 // Bad track number
|
||||
#define CDERR_IOCTLBUFFMEM 22 // Not enough low memory for IOCTL
|
||||
#define CDERR_DEVREQBASE 100 // DevReq errors
|
||||
|
||||
extern int cd_Error;
|
||||
|
||||
int I_CDMusInit(void);
|
||||
void I_CDMusPrintStartup(void);
|
||||
int I_CDMusPlay(int track);
|
||||
int I_CDMusStop(void);
|
||||
int I_CDMusResume(void);
|
||||
int I_CDMusSetVolume(int volume);
|
||||
int I_CDMusFirstTrack(void);
|
||||
int I_CDMusLastTrack(void);
|
||||
int I_CDMusTrackLength(int track);
|
||||
|
||||
#endif
|
||||
471
src/i_input.c
Normal file
471
src/i_input.c
Normal file
@@ -0,0 +1,471 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// SDL implementation of system-specific input interface.
|
||||
//
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL2/SDL_events.h"
|
||||
#include "SDL2/SDL_keyboard.h"
|
||||
#include "SDL2/SDL_keycode.h"
|
||||
#include "SDL2/SDL_mouse.h"
|
||||
#include "SDL2/SDL_scancode.h"
|
||||
#include "d_event.h"
|
||||
#include "doomkeys.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_input.h"
|
||||
#include "m_config.h"
|
||||
|
||||
static const int scancode_translate_table[] = SCANCODE_TO_KEYS_ARRAY;
|
||||
|
||||
// Lookup table for mapping ASCII characters to their equivalent when
|
||||
// shift is pressed on a US layout keyboard. This is the original table
|
||||
// as found in the Doom sources, comments and all.
|
||||
static const char shiftxform[] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
31, ' ', '!', '"', '#', '$', '%', '&',
|
||||
'"', // shift-'
|
||||
'(', ')', '*', '+',
|
||||
'<', // shift-,
|
||||
'_', // shift--
|
||||
'>', // shift-.
|
||||
'?', // shift-/
|
||||
')', // shift-0
|
||||
'!', // shift-1
|
||||
'@', // shift-2
|
||||
'#', // shift-3
|
||||
'$', // shift-4
|
||||
'%', // shift-5
|
||||
'^', // shift-6
|
||||
'&', // shift-7
|
||||
'*', // shift-8
|
||||
'(', // shift-9
|
||||
':',
|
||||
':', // shift-;
|
||||
'<',
|
||||
'+', // shift-=
|
||||
'>', '?', '@',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'[', // shift-[
|
||||
'!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
|
||||
']', // shift-]
|
||||
'"', '_',
|
||||
'\'', // shift-`
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'{', '|', '}', '~', 127
|
||||
};
|
||||
|
||||
// If true, I_StartTextInput() has been called, and we are populating
|
||||
// the data3 field of ev_keydown events.
|
||||
static boolean text_input_enabled = true;
|
||||
|
||||
// Bit mask of mouse button state.
|
||||
static unsigned int mouse_button_state = 0;
|
||||
|
||||
// Disallow mouse and joystick movement to cause forward/backward
|
||||
// motion. Specified with the '-novert' command line parameter.
|
||||
// This is an int to allow saving to config file
|
||||
int novert = 0;
|
||||
|
||||
// If true, keyboard mapping is ignored, like in Vanilla Doom.
|
||||
// The sensible thing to do is to disable this if you have a non-US
|
||||
// keyboard.
|
||||
|
||||
int vanilla_keyboard_mapping = true;
|
||||
|
||||
// Mouse acceleration
|
||||
//
|
||||
// This emulates some of the behavior of DOS mouse drivers by increasing
|
||||
// the speed when the mouse is moved fast.
|
||||
//
|
||||
// The mouse input values are input directly to the game, but when
|
||||
// the values exceed the value of mouse_threshold, they are multiplied
|
||||
// by mouse_acceleration to increase the speed.
|
||||
float mouse_acceleration = 2.0;
|
||||
int mouse_threshold = 10;
|
||||
|
||||
// Translates the SDL key to a value of the type found in doomkeys.h
|
||||
static int TranslateKey(SDL_Keysym *sym)
|
||||
{
|
||||
int scancode = sym->scancode;
|
||||
|
||||
switch (scancode)
|
||||
{
|
||||
case SDL_SCANCODE_LCTRL:
|
||||
case SDL_SCANCODE_RCTRL:
|
||||
return KEY_RCTRL;
|
||||
|
||||
case SDL_SCANCODE_LSHIFT:
|
||||
case SDL_SCANCODE_RSHIFT:
|
||||
return KEY_RSHIFT;
|
||||
|
||||
case SDL_SCANCODE_LALT:
|
||||
return KEY_LALT;
|
||||
|
||||
case SDL_SCANCODE_RALT:
|
||||
return KEY_RALT;
|
||||
|
||||
default:
|
||||
if (scancode >= 0 && scancode < arrlen(scancode_translate_table))
|
||||
{
|
||||
return scancode_translate_table[scancode];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the localized version of the key press. This takes into account the
|
||||
// keyboard layout, but does not apply any changes due to modifiers, (eg.
|
||||
// shift-, alt-, etc.)
|
||||
static int GetLocalizedKey(SDL_Keysym *sym)
|
||||
{
|
||||
// When using Vanilla mapping, we just base everything off the scancode
|
||||
// and always pretend the user is using a US layout keyboard.
|
||||
if (vanilla_keyboard_mapping)
|
||||
{
|
||||
return TranslateKey(sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
int result = sym->sym;
|
||||
|
||||
if (result < 0 || result >= 128)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the equivalent ASCII (Unicode?) character for a keypress.
|
||||
static int GetTypedChar(SDL_Keysym *sym)
|
||||
{
|
||||
// We only return typed characters when entering text, after
|
||||
// I_StartTextInput() has been called. Otherwise we return nothing.
|
||||
if (!text_input_enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If we're strictly emulating Vanilla, we should always act like
|
||||
// we're using a US layout keyboard (in ev_keydown, data1=data2).
|
||||
// Otherwise we should use the native key mapping.
|
||||
if (vanilla_keyboard_mapping)
|
||||
{
|
||||
int result = TranslateKey(sym);
|
||||
|
||||
// If shift is held down, apply the original uppercase
|
||||
// translation table used under DOS.
|
||||
if ((SDL_GetModState() & KMOD_SHIFT) != 0
|
||||
&& result >= 0 && result < arrlen(shiftxform))
|
||||
{
|
||||
result = shiftxform[result];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_Event next_event;
|
||||
|
||||
// Special cases, where we always return a fixed value.
|
||||
switch (sym->sym)
|
||||
{
|
||||
case SDLK_BACKSPACE: return KEY_BACKSPACE;
|
||||
case SDLK_RETURN: return KEY_ENTER;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// The following is a gross hack, but I don't see an easier way
|
||||
// of doing this within the SDL2 API (in SDL1 it was easier).
|
||||
// We want to get the fully transformed input character associated
|
||||
// with this keypress - correct keyboard layout, appropriately
|
||||
// transformed by any modifier keys, etc. So peek ahead in the SDL
|
||||
// event queue and see if the key press is immediately followed by
|
||||
// an SDL_TEXTINPUT event. If it is, it's reasonable to assume the
|
||||
// key press and the text input are connected. Technically the SDL
|
||||
// API does not guarantee anything of the sort, but in practice this
|
||||
// is what happens and I've verified it through manual inspect of
|
||||
// the SDL source code.
|
||||
//
|
||||
// In an ideal world we'd split out ev_keydown into a separate
|
||||
// ev_textinput event, as SDL2 has done. But this doesn't work
|
||||
// (I experimented with the idea), because lots of Doom's code is
|
||||
// based around different responders "eating" events to stop them
|
||||
// being passed on to another responder. If code is listening for
|
||||
// a text input, it cannot block the corresponding keydown events
|
||||
// which can affect other responders.
|
||||
//
|
||||
// So we're stuck with this as a rather fragile alternative.
|
||||
|
||||
if (SDL_PeepEvents(&next_event, 1, SDL_PEEKEVENT,
|
||||
SDL_FIRSTEVENT, SDL_LASTEVENT) == 1
|
||||
&& next_event.type == SDL_TEXTINPUT)
|
||||
{
|
||||
// If an SDL_TEXTINPUT event is found, we always assume it
|
||||
// matches the key press. The input text must be a single
|
||||
// ASCII character - if it isn't, it's possible the input
|
||||
// char is a Unicode value instead; better to send a null
|
||||
// character than the unshifted key.
|
||||
if (strlen(next_event.text.text) == 1
|
||||
&& (next_event.text.text[0] & 0x80) == 0)
|
||||
{
|
||||
return next_event.text.text[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to find anything :/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void I_HandleKeyboardEvent(SDL_Event *sdlevent)
|
||||
{
|
||||
// XXX: passing pointers to event for access after this function
|
||||
// has terminated is undefined behaviour
|
||||
event_t event;
|
||||
|
||||
switch (sdlevent->type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
event.type = ev_keydown;
|
||||
event.data1 = TranslateKey(&sdlevent->key.keysym);
|
||||
event.data2 = GetLocalizedKey(&sdlevent->key.keysym);
|
||||
event.data3 = GetTypedChar(&sdlevent->key.keysym);
|
||||
|
||||
if (event.data1 != 0)
|
||||
{
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
event.type = ev_keyup;
|
||||
event.data1 = TranslateKey(&sdlevent->key.keysym);
|
||||
|
||||
// data2/data3 are initialized to zero for ev_keyup.
|
||||
// For ev_keydown it's the shifted Unicode character
|
||||
// that was typed, but if something wants to detect
|
||||
// key releases it should do so based on data1
|
||||
// (key ID), not the printable char.
|
||||
|
||||
event.data2 = 0;
|
||||
event.data3 = 0;
|
||||
|
||||
if (event.data1 != 0)
|
||||
{
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void I_StartTextInput(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
text_input_enabled = true;
|
||||
|
||||
if (!vanilla_keyboard_mapping)
|
||||
{
|
||||
// SDL2-TODO: SDL_SetTextInputRect(...);
|
||||
SDL_StartTextInput();
|
||||
}
|
||||
}
|
||||
|
||||
void I_StopTextInput(void)
|
||||
{
|
||||
text_input_enabled = false;
|
||||
|
||||
if (!vanilla_keyboard_mapping)
|
||||
{
|
||||
SDL_StopTextInput();
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateMouseButtonState(unsigned int button, boolean on)
|
||||
{
|
||||
static event_t event;
|
||||
|
||||
if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: button "0" is left, button "1" is right,
|
||||
// button "2" is middle for Doom. This is different
|
||||
// to how SDL sees things.
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
button = 0;
|
||||
break;
|
||||
|
||||
case SDL_BUTTON_RIGHT:
|
||||
button = 1;
|
||||
break;
|
||||
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
button = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
// SDL buttons are indexed from 1.
|
||||
--button;
|
||||
break;
|
||||
}
|
||||
|
||||
// Turn bit representing this button on or off.
|
||||
|
||||
if (on)
|
||||
{
|
||||
mouse_button_state |= (1 << button);
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse_button_state &= ~(1 << button);
|
||||
}
|
||||
|
||||
// Post an event with the new button state.
|
||||
|
||||
event.type = ev_mouse;
|
||||
event.data1 = mouse_button_state;
|
||||
event.data2 = event.data3 = 0;
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
static void MapMouseWheelToButtons(SDL_MouseWheelEvent *wheel)
|
||||
{
|
||||
// SDL2 distinguishes button events from mouse wheel events.
|
||||
// We want to treat the mouse wheel as two buttons, as per
|
||||
// SDL1
|
||||
static event_t up, down;
|
||||
int button;
|
||||
|
||||
if (wheel->y <= 0)
|
||||
{ // scroll down
|
||||
button = 4;
|
||||
}
|
||||
else
|
||||
{ // scroll up
|
||||
button = 3;
|
||||
}
|
||||
|
||||
// post a button down event
|
||||
mouse_button_state |= (1 << button);
|
||||
down.type = ev_mouse;
|
||||
down.data1 = mouse_button_state;
|
||||
down.data2 = down.data3 = 0;
|
||||
D_PostEvent(&down);
|
||||
|
||||
// post a button up event
|
||||
mouse_button_state &= ~(1 << button);
|
||||
up.type = ev_mouse;
|
||||
up.data1 = mouse_button_state;
|
||||
up.data2 = up.data3 = 0;
|
||||
D_PostEvent(&up);
|
||||
}
|
||||
|
||||
void I_HandleMouseEvent(SDL_Event *sdlevent)
|
||||
{
|
||||
switch (sdlevent->type)
|
||||
{
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
UpdateMouseButtonState(sdlevent->button.button, true);
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
UpdateMouseButtonState(sdlevent->button.button, false);
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
MapMouseWheelToButtons(&(sdlevent->wheel));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int AccelerateMouse(int val)
|
||||
{
|
||||
if (val < 0)
|
||||
return -AccelerateMouse(-val);
|
||||
|
||||
if (val > mouse_threshold)
|
||||
{
|
||||
return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read the change in mouse state to generate mouse motion events
|
||||
//
|
||||
// This is to combine all mouse movement for a tic into one mouse
|
||||
// motion event.
|
||||
void I_ReadMouse(void)
|
||||
{
|
||||
int x, y;
|
||||
event_t ev;
|
||||
|
||||
SDL_GetRelativeMouseState(&x, &y);
|
||||
|
||||
if (x != 0 || y != 0)
|
||||
{
|
||||
ev.type = ev_mouse;
|
||||
ev.data1 = mouse_button_state;
|
||||
ev.data2 = AccelerateMouse(x);
|
||||
|
||||
if (!novert)
|
||||
{
|
||||
ev.data3 = -AccelerateMouse(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ev.data3 = 0;
|
||||
}
|
||||
|
||||
// XXX: undefined behaviour since event is scoped to
|
||||
// this function
|
||||
D_PostEvent(&ev);
|
||||
}
|
||||
}
|
||||
|
||||
// Bind all variables controlling input options.
|
||||
void I_BindInputVariables(void)
|
||||
{
|
||||
M_BindFloatVariable("mouse_acceleration", &mouse_acceleration);
|
||||
M_BindIntVariable("mouse_threshold", &mouse_threshold);
|
||||
M_BindIntVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping);
|
||||
M_BindIntVariable("novert", &novert);
|
||||
}
|
||||
40
src/i_input.h
Normal file
40
src/i_input.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System-specific keyboard/mouse input.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_INPUT__
|
||||
#define __I_INPUT__
|
||||
|
||||
#define MAX_MOUSE_BUTTONS 8
|
||||
|
||||
extern float mouse_acceleration;
|
||||
extern int mouse_threshold;
|
||||
|
||||
void I_BindInputVariables(void);
|
||||
void I_ReadMouse(void);
|
||||
|
||||
// I_StartTextInput begins text input, activating the on-screen keyboard
|
||||
// (if one is used). The caller indicates that any entered text will be
|
||||
// displayed in the rectangle given by the provided set of coordinates.
|
||||
void I_StartTextInput(int x1, int y1, int x2, int y2);
|
||||
|
||||
// I_StopTextInput finishes text input, deactivating the on-screen keyboard
|
||||
// (if one is used).
|
||||
void I_StopTextInput(void);
|
||||
|
||||
#endif
|
||||
384
src/i_joystick.c
Normal file
384
src/i_joystick.c
Normal file
@@ -0,0 +1,384 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// SDL Joystick code.
|
||||
//
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_events.h"
|
||||
#include "SDL2/SDL_joystick.h"
|
||||
#include "d_event.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_joystick.h"
|
||||
#include "i_system.h"
|
||||
#include "m_config.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
// When an axis is within the dead zone, it is set to zero.
|
||||
// This is 5% of the full range:
|
||||
|
||||
#define DEAD_ZONE (32768 / 3)
|
||||
|
||||
static SDL_Joystick *joystick = NULL;
|
||||
|
||||
// Configuration variables:
|
||||
|
||||
// Standard default.cfg Joystick enable/disable
|
||||
|
||||
static int usejoystick = 0;
|
||||
|
||||
// SDL GUID and index of the joystick to use.
|
||||
static char *joystick_guid = "";
|
||||
static int joystick_index = -1;
|
||||
|
||||
// Which joystick axis to use for horizontal movement, and whether to
|
||||
// invert the direction:
|
||||
|
||||
static int joystick_x_axis = 0;
|
||||
static int joystick_x_invert = 0;
|
||||
|
||||
// Which joystick axis to use for vertical movement, and whether to
|
||||
// invert the direction:
|
||||
|
||||
static int joystick_y_axis = 1;
|
||||
static int joystick_y_invert = 0;
|
||||
|
||||
// Which joystick axis to use for strafing?
|
||||
|
||||
static int joystick_strafe_axis = -1;
|
||||
static int joystick_strafe_invert = 0;
|
||||
|
||||
// Virtual to physical button joystick button mapping. By default this
|
||||
// is a straight mapping.
|
||||
static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
};
|
||||
|
||||
void I_ShutdownJoystick(void)
|
||||
{
|
||||
if (joystick != NULL)
|
||||
{
|
||||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean IsValidAxis(int axis)
|
||||
{
|
||||
int num_axes;
|
||||
|
||||
if (axis < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IS_BUTTON_AXIS(axis))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IS_HAT_AXIS(axis))
|
||||
{
|
||||
return HAT_AXIS_HAT(axis) < SDL_JoystickNumHats(joystick);
|
||||
}
|
||||
|
||||
num_axes = SDL_JoystickNumAxes(joystick);
|
||||
|
||||
return axis < num_axes;
|
||||
}
|
||||
|
||||
static int DeviceIndex(void)
|
||||
{
|
||||
SDL_JoystickGUID guid, dev_guid;
|
||||
int i;
|
||||
|
||||
guid = SDL_JoystickGetGUIDFromString(joystick_guid);
|
||||
|
||||
// GUID identifies a class of device rather than a specific device.
|
||||
// Check if joystick_index has the expected GUID, as this can act
|
||||
// as a tie-breaker in case there are multiple identical devices.
|
||||
if (joystick_index >= 0 && joystick_index < SDL_NumJoysticks())
|
||||
{
|
||||
dev_guid = SDL_JoystickGetDeviceGUID(joystick_index);
|
||||
if (!memcmp(&guid, &dev_guid, sizeof(SDL_JoystickGUID)))
|
||||
{
|
||||
return joystick_index;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all devices to look for one with the expected GUID.
|
||||
for (i = 0; i < SDL_NumJoysticks(); ++i)
|
||||
{
|
||||
dev_guid = SDL_JoystickGetDeviceGUID(i);
|
||||
if (!memcmp(&guid, &dev_guid, sizeof(SDL_JoystickGUID)))
|
||||
{
|
||||
printf("I_InitJoystick: Joystick moved to index %d.\n", i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// No joystick found with the expected GUID.
|
||||
return -1;
|
||||
}
|
||||
|
||||
void I_InitJoystick(void)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!usejoystick || !strcmp(joystick_guid, ""))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
index = DeviceIndex();
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
printf("I_InitJoystick: Couldn't find joystick with GUID \"%s\": "
|
||||
"device not found or not connected?\n",
|
||||
joystick_guid);
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the joystick
|
||||
|
||||
joystick = SDL_JoystickOpen(index);
|
||||
|
||||
if (joystick == NULL)
|
||||
{
|
||||
printf("I_InitJoystick: Failed to open joystick #%i\n", index);
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsValidAxis(joystick_x_axis)
|
||||
|| !IsValidAxis(joystick_y_axis)
|
||||
|| !IsValidAxis(joystick_strafe_axis))
|
||||
{
|
||||
printf("I_InitJoystick: Invalid joystick axis for configured joystick "
|
||||
"(run joystick setup again)\n");
|
||||
|
||||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
|
||||
SDL_JoystickEventState(SDL_ENABLE);
|
||||
|
||||
// Initialized okay!
|
||||
|
||||
printf("I_InitJoystick: %s\n", SDL_JoystickName(joystick));
|
||||
|
||||
I_AtExit(I_ShutdownJoystick, true);
|
||||
}
|
||||
|
||||
static boolean IsAxisButton(int physbutton)
|
||||
{
|
||||
if (IS_BUTTON_AXIS(joystick_x_axis))
|
||||
{
|
||||
if (physbutton == BUTTON_AXIS_NEG(joystick_x_axis)
|
||||
|| physbutton == BUTTON_AXIS_POS(joystick_x_axis))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (IS_BUTTON_AXIS(joystick_y_axis))
|
||||
{
|
||||
if (physbutton == BUTTON_AXIS_NEG(joystick_y_axis)
|
||||
|| physbutton == BUTTON_AXIS_POS(joystick_y_axis))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (IS_BUTTON_AXIS(joystick_strafe_axis))
|
||||
{
|
||||
if (physbutton == BUTTON_AXIS_NEG(joystick_strafe_axis)
|
||||
|| physbutton == BUTTON_AXIS_POS(joystick_strafe_axis))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the state of the given virtual button.
|
||||
|
||||
static int ReadButtonState(int vbutton)
|
||||
{
|
||||
int physbutton;
|
||||
|
||||
// Map from virtual button to physical (SDL) button.
|
||||
if (vbutton < NUM_VIRTUAL_BUTTONS)
|
||||
{
|
||||
physbutton = joystick_physical_buttons[vbutton];
|
||||
}
|
||||
else
|
||||
{
|
||||
physbutton = vbutton;
|
||||
}
|
||||
|
||||
// Never read axis buttons as buttons.
|
||||
if (IsAxisButton(physbutton))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return SDL_JoystickGetButton(joystick, physbutton);
|
||||
}
|
||||
|
||||
// Get a bitmask of all currently-pressed buttons
|
||||
|
||||
static int GetButtonsState(void)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
|
||||
for (i = 0; i < 20; ++i)
|
||||
{
|
||||
if (ReadButtonState(i))
|
||||
{
|
||||
result |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read the state of an axis, inverting if necessary.
|
||||
|
||||
static int GetAxisState(int axis, int invert)
|
||||
{
|
||||
int result;
|
||||
|
||||
// Axis -1 means disabled.
|
||||
|
||||
if (axis < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Is this a button axis, or a hat axis?
|
||||
// If so, we need to handle it specially.
|
||||
|
||||
result = 0;
|
||||
|
||||
if (IS_BUTTON_AXIS(axis))
|
||||
{
|
||||
if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_NEG(axis)))
|
||||
{
|
||||
result -= 32767;
|
||||
}
|
||||
if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_POS(axis)))
|
||||
{
|
||||
result += 32767;
|
||||
}
|
||||
}
|
||||
else if (IS_HAT_AXIS(axis))
|
||||
{
|
||||
int direction = HAT_AXIS_DIRECTION(axis);
|
||||
int hatval = SDL_JoystickGetHat(joystick, HAT_AXIS_HAT(axis));
|
||||
|
||||
if (direction == HAT_AXIS_HORIZONTAL)
|
||||
{
|
||||
if ((hatval & SDL_HAT_LEFT) != 0)
|
||||
{
|
||||
result -= 32767;
|
||||
}
|
||||
else if ((hatval & SDL_HAT_RIGHT) != 0)
|
||||
{
|
||||
result += 32767;
|
||||
}
|
||||
}
|
||||
else if (direction == HAT_AXIS_VERTICAL)
|
||||
{
|
||||
if ((hatval & SDL_HAT_UP) != 0)
|
||||
{
|
||||
result -= 32767;
|
||||
}
|
||||
else if ((hatval & SDL_HAT_DOWN) != 0)
|
||||
{
|
||||
result += 32767;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SDL_JoystickGetAxis(joystick, axis);
|
||||
|
||||
if (result < DEAD_ZONE && result > -DEAD_ZONE)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (invert)
|
||||
{
|
||||
result = -result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void I_UpdateJoystick(void)
|
||||
{
|
||||
if (joystick != NULL)
|
||||
{
|
||||
event_t ev;
|
||||
|
||||
ev.type = ev_joystick;
|
||||
ev.data1 = GetButtonsState();
|
||||
ev.data2 = GetAxisState(joystick_x_axis, joystick_x_invert);
|
||||
ev.data3 = GetAxisState(joystick_y_axis, joystick_y_invert);
|
||||
ev.data4 = GetAxisState(joystick_strafe_axis, joystick_strafe_invert);
|
||||
|
||||
D_PostEvent(&ev);
|
||||
}
|
||||
}
|
||||
|
||||
void I_BindJoystickVariables(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
M_BindIntVariable("use_joystick", &usejoystick);
|
||||
M_BindStringVariable("joystick_guid", &joystick_guid);
|
||||
M_BindIntVariable("joystick_index", &joystick_index);
|
||||
M_BindIntVariable("joystick_x_axis", &joystick_x_axis);
|
||||
M_BindIntVariable("joystick_y_axis", &joystick_y_axis);
|
||||
M_BindIntVariable("joystick_strafe_axis", &joystick_strafe_axis);
|
||||
M_BindIntVariable("joystick_x_invert", &joystick_x_invert);
|
||||
M_BindIntVariable("joystick_y_invert", &joystick_y_invert);
|
||||
M_BindIntVariable("joystick_strafe_invert",&joystick_strafe_invert);
|
||||
|
||||
for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
|
||||
{
|
||||
char name[32];
|
||||
M_snprintf(name, sizeof(name), "joystick_physical_button%i", i);
|
||||
M_BindIntVariable(name, &joystick_physical_buttons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
70
src/i_joystick.h
Normal file
70
src/i_joystick.h
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System-specific joystick interface.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_JOYSTICK__
|
||||
#define __I_JOYSTICK__
|
||||
|
||||
// Number of "virtual" joystick buttons defined in configuration files.
|
||||
// This needs to be at least as large as the number of different key
|
||||
// bindings supported by the higher-level game code (joyb* variables).
|
||||
#define NUM_VIRTUAL_BUTTONS 11
|
||||
|
||||
// If this bit is set in a configuration file axis value, the axis is
|
||||
// not actually a joystick axis, but instead is a "button axis". This
|
||||
// means that instead of reading an SDL joystick axis, we read the
|
||||
// state of two buttons to get the axis value. This is needed for eg.
|
||||
// the PS3 SIXAXIS controller, where the D-pad buttons register as
|
||||
// buttons, not as two axes.
|
||||
#define BUTTON_AXIS 0x10000
|
||||
|
||||
// Query whether a given axis value describes a button axis.
|
||||
#define IS_BUTTON_AXIS(axis) ((axis) >= 0 && ((axis) & BUTTON_AXIS) != 0)
|
||||
|
||||
// Get the individual buttons from a button axis value.
|
||||
#define BUTTON_AXIS_NEG(axis) ((axis) & 0xff)
|
||||
#define BUTTON_AXIS_POS(axis) (((axis) >> 8) & 0xff)
|
||||
|
||||
// Create a button axis value from two button values.
|
||||
#define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8))
|
||||
|
||||
// If this bit is set in an axis value, the axis is not actually a
|
||||
// joystick axis, but is a "hat" axis. This means that we read (one of)
|
||||
// the hats on the joystick.
|
||||
#define HAT_AXIS 0x20000
|
||||
|
||||
#define IS_HAT_AXIS(axis) ((axis) >= 0 && ((axis) & HAT_AXIS) != 0)
|
||||
|
||||
// Get the hat number from a hat axis value.
|
||||
#define HAT_AXIS_HAT(axis) ((axis) & 0xff)
|
||||
// Which axis of the hat? (horizonal or vertical)
|
||||
#define HAT_AXIS_DIRECTION(axis) (((axis) >> 8) & 0xff)
|
||||
|
||||
#define CREATE_HAT_AXIS(hat, direction) \
|
||||
(HAT_AXIS | (hat) | ((direction) << 8))
|
||||
|
||||
#define HAT_AXIS_HORIZONTAL 1
|
||||
#define HAT_AXIS_VERTICAL 2
|
||||
|
||||
void I_InitJoystick(void);
|
||||
void I_ShutdownJoystick(void);
|
||||
void I_UpdateJoystick(void);
|
||||
|
||||
void I_BindJoystickVariables(void);
|
||||
|
||||
#endif /* #ifndef __I_JOYSTICK__ */
|
||||
|
||||
37
src/i_main.c
Normal file
37
src/i_main.c
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Main program, simply calls D_DoomMain high level loop.
|
||||
//
|
||||
|
||||
#include "d_main.h"
|
||||
#include "m_argv.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// save arguments
|
||||
|
||||
myargc = argc;
|
||||
myargv = argv;
|
||||
|
||||
M_FindResponseFile();
|
||||
|
||||
// start doom
|
||||
|
||||
D_DoomMain ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
1302
src/i_sdlmusic.c
Normal file
1302
src/i_sdlmusic.c
Normal file
File diff suppressed because it is too large
Load Diff
874
src/i_sdlsound.c
Normal file
874
src/i_sdlsound.c
Normal file
@@ -0,0 +1,874 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
// Copyright(C) 2008 David Flater
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System interface for sound.
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_audio.h"
|
||||
#include "SDL2/SDL_mixer.h"
|
||||
#include "SDL2/SDL_stdinc.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_sound.h"
|
||||
#include "i_system.h"
|
||||
#include "m_misc.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
struct allocated_sound_s;
|
||||
|
||||
#define NUM_CHANNELS 16
|
||||
|
||||
typedef struct allocated_sound_s allocated_sound_t;
|
||||
|
||||
struct allocated_sound_s
|
||||
{
|
||||
sfxinfo_t *sfxinfo;
|
||||
Mix_Chunk chunk;
|
||||
int use_count;
|
||||
int pitch;
|
||||
allocated_sound_t *prev, *next;
|
||||
};
|
||||
|
||||
static boolean sound_initialized = false;
|
||||
|
||||
static allocated_sound_t *channels_playing[NUM_CHANNELS];
|
||||
|
||||
static int mixer_freq;
|
||||
static Uint16 mixer_format;
|
||||
static int mixer_channels;
|
||||
static boolean use_sfx_prefix;
|
||||
static boolean (*ExpandSoundData)(sfxinfo_t *sfxinfo,
|
||||
byte *data,
|
||||
int samplerate,
|
||||
int length) = NULL;
|
||||
|
||||
// Doubly-linked list of allocated sounds.
|
||||
// When a sound is played, it is moved to the head, so that the oldest
|
||||
// sounds not used recently are at the tail.
|
||||
|
||||
static allocated_sound_t *allocated_sounds_head = NULL;
|
||||
static allocated_sound_t *allocated_sounds_tail = NULL;
|
||||
static int allocated_sounds_size = 0;
|
||||
|
||||
int use_libsamplerate = 0;
|
||||
|
||||
// Scale factor used when converting libsamplerate floating point numbers
|
||||
// to integers. Too high means the sounds can clip; too low means they
|
||||
// will be too quiet. This is an amount that should avoid clipping most
|
||||
// of the time: with all the Doom IWAD sound effects, at least. If a PWAD
|
||||
// is used, clipping might occur.
|
||||
|
||||
float libsamplerate_scale = 0.65f;
|
||||
|
||||
// Hook a sound into the linked list at the head.
|
||||
|
||||
static void AllocatedSoundLink(allocated_sound_t *snd)
|
||||
{
|
||||
snd->prev = NULL;
|
||||
|
||||
snd->next = allocated_sounds_head;
|
||||
allocated_sounds_head = snd;
|
||||
|
||||
if (allocated_sounds_tail == NULL)
|
||||
{
|
||||
allocated_sounds_tail = snd;
|
||||
}
|
||||
else
|
||||
{
|
||||
snd->next->prev = snd;
|
||||
}
|
||||
}
|
||||
|
||||
// Unlink a sound from the linked list.
|
||||
|
||||
static void AllocatedSoundUnlink(allocated_sound_t *snd)
|
||||
{
|
||||
if (snd->prev == NULL)
|
||||
{
|
||||
allocated_sounds_head = snd->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
snd->prev->next = snd->next;
|
||||
}
|
||||
|
||||
if (snd->next == NULL)
|
||||
{
|
||||
allocated_sounds_tail = snd->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
snd->next->prev = snd->prev;
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeAllocatedSound(allocated_sound_t *snd)
|
||||
{
|
||||
// Unlink from linked list.
|
||||
|
||||
AllocatedSoundUnlink(snd);
|
||||
|
||||
// Keep track of the amount of allocated sound data:
|
||||
|
||||
allocated_sounds_size -= snd->chunk.alen;
|
||||
|
||||
free(snd);
|
||||
}
|
||||
|
||||
// Search from the tail backwards along the allocated sounds list, find
|
||||
// and free a sound that is not in use, to free up memory. Return true
|
||||
// for success.
|
||||
|
||||
static boolean FindAndFreeSound(void)
|
||||
{
|
||||
allocated_sound_t *snd;
|
||||
|
||||
snd = allocated_sounds_tail;
|
||||
|
||||
while (snd != NULL)
|
||||
{
|
||||
if (snd->use_count == 0)
|
||||
{
|
||||
FreeAllocatedSound(snd);
|
||||
return true;
|
||||
}
|
||||
|
||||
snd = snd->prev;
|
||||
}
|
||||
|
||||
// No available sounds to free...
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enforce SFX cache size limit. We are just about to allocate "len"
|
||||
// bytes on the heap for a new sound effect, so free up some space
|
||||
// so that we keep allocated_sounds_size < snd_cachesize
|
||||
|
||||
static void ReserveCacheSpace(size_t len)
|
||||
{
|
||||
if (snd_cachesize <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep freeing sound effects that aren't currently being played,
|
||||
// until there is enough space for the new sound.
|
||||
|
||||
while (allocated_sounds_size + len > snd_cachesize)
|
||||
{
|
||||
// Free a sound. If there is nothing more to free, stop.
|
||||
|
||||
if (!FindAndFreeSound())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a block for a new sound effect.
|
||||
|
||||
static allocated_sound_t *AllocateSound(sfxinfo_t *sfxinfo, size_t len)
|
||||
{
|
||||
allocated_sound_t *snd;
|
||||
|
||||
// Keep allocated sounds within the cache size.
|
||||
|
||||
ReserveCacheSpace(len);
|
||||
|
||||
// Allocate the sound structure and data. The data will immediately
|
||||
// follow the structure, which acts as a header.
|
||||
|
||||
do
|
||||
{
|
||||
snd = malloc(sizeof(allocated_sound_t) + len);
|
||||
|
||||
// Out of memory? Try to free an old sound, then loop round
|
||||
// and try again.
|
||||
|
||||
if (snd == NULL && !FindAndFreeSound())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} while (snd == NULL);
|
||||
|
||||
// Skip past the chunk structure for the audio buffer
|
||||
|
||||
snd->chunk.abuf = (byte *) (snd + 1);
|
||||
snd->chunk.alen = len;
|
||||
snd->chunk.allocated = 1;
|
||||
snd->chunk.volume = MIX_MAX_VOLUME;
|
||||
snd->pitch = NORM_PITCH;
|
||||
|
||||
snd->sfxinfo = sfxinfo;
|
||||
snd->use_count = 0;
|
||||
|
||||
// Keep track of how much memory all these cached sounds are using...
|
||||
|
||||
allocated_sounds_size += len;
|
||||
|
||||
AllocatedSoundLink(snd);
|
||||
|
||||
return snd;
|
||||
}
|
||||
|
||||
// Lock a sound, to indicate that it may not be freed.
|
||||
|
||||
static void LockAllocatedSound(allocated_sound_t *snd)
|
||||
{
|
||||
// Increase use count, to stop the sound being freed.
|
||||
|
||||
++snd->use_count;
|
||||
|
||||
//printf("++ %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count);
|
||||
|
||||
// When we use a sound, re-link it into the list at the head, so
|
||||
// that the oldest sounds fall to the end of the list for freeing.
|
||||
|
||||
AllocatedSoundUnlink(snd);
|
||||
AllocatedSoundLink(snd);
|
||||
}
|
||||
|
||||
// Unlock a sound to indicate that it may now be freed.
|
||||
|
||||
static void UnlockAllocatedSound(allocated_sound_t *snd)
|
||||
{
|
||||
if (snd->use_count <= 0)
|
||||
{
|
||||
I_Error("Sound effect released more times than it was locked...");
|
||||
}
|
||||
|
||||
--snd->use_count;
|
||||
|
||||
//printf("-- %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count);
|
||||
}
|
||||
|
||||
// Search through the list of allocated sounds and return the one that matches
|
||||
// the supplied sfxinfo entry and pitch level.
|
||||
|
||||
static allocated_sound_t * GetAllocatedSoundBySfxInfoAndPitch(sfxinfo_t *sfxinfo, int pitch)
|
||||
{
|
||||
allocated_sound_t * p = allocated_sounds_head;
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
if (p->sfxinfo == sfxinfo && p->pitch == pitch)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate a new sound chunk and pitch-shift an existing sound up-or-down
|
||||
// into it.
|
||||
|
||||
static allocated_sound_t * PitchShift(allocated_sound_t *insnd, int pitch)
|
||||
{
|
||||
allocated_sound_t * outsnd;
|
||||
Sint16 *inp, *outp;
|
||||
Sint16 *srcbuf, *dstbuf;
|
||||
Uint32 srclen, dstlen;
|
||||
|
||||
srcbuf = (Sint16 *)insnd->chunk.abuf;
|
||||
srclen = insnd->chunk.alen;
|
||||
|
||||
// determine ratio pitch:NORM_PITCH and apply to srclen, then invert.
|
||||
// This is an approximation of vanilla behaviour based on measurements
|
||||
dstlen = (int)((1 + (1 - (float)pitch / NORM_PITCH)) * srclen);
|
||||
|
||||
// ensure that the new buffer is an even length
|
||||
if ((dstlen % 2) == 0)
|
||||
{
|
||||
dstlen++;
|
||||
}
|
||||
|
||||
outsnd = AllocateSound(insnd->sfxinfo, dstlen);
|
||||
|
||||
if (!outsnd)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
outsnd->pitch = pitch;
|
||||
dstbuf = (Sint16 *)outsnd->chunk.abuf;
|
||||
|
||||
// loop over output buffer. find corresponding input cell, copy over
|
||||
for (outp = dstbuf; outp < dstbuf + dstlen/2; ++outp)
|
||||
{
|
||||
inp = srcbuf + (int)((float)(outp - dstbuf) / dstlen * srclen);
|
||||
*outp = *inp;
|
||||
}
|
||||
|
||||
return outsnd;
|
||||
}
|
||||
|
||||
// When a sound stops, check if it is still playing. If it is not,
|
||||
// we can mark the sound data as CACHE to be freed back for other
|
||||
// means.
|
||||
|
||||
static void ReleaseSoundOnChannel(int channel)
|
||||
{
|
||||
allocated_sound_t *snd = channels_playing[channel];
|
||||
|
||||
Mix_HaltChannel(channel);
|
||||
|
||||
if (snd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
channels_playing[channel] = NULL;
|
||||
|
||||
UnlockAllocatedSound(snd);
|
||||
|
||||
// if the sound is a pitch-shift and it's not in use, immediately
|
||||
// free it
|
||||
if (snd->pitch != NORM_PITCH && snd->use_count <= 0)
|
||||
{
|
||||
FreeAllocatedSound(snd);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean ConvertibleRatio(int freq1, int freq2)
|
||||
{
|
||||
int ratio;
|
||||
|
||||
if (freq1 > freq2)
|
||||
{
|
||||
return ConvertibleRatio(freq2, freq1);
|
||||
}
|
||||
else if ((freq2 % freq1) != 0)
|
||||
{
|
||||
// Not in a direct ratio
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check the ratio is a power of 2
|
||||
|
||||
ratio = freq2 / freq1;
|
||||
|
||||
while ((ratio & 1) == 0)
|
||||
{
|
||||
ratio = ratio >> 1;
|
||||
}
|
||||
|
||||
return ratio == 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generic sound expansion function for any sample rate.
|
||||
// Returns number of clipped samples (always 0).
|
||||
|
||||
static boolean ExpandSoundData_SDL(sfxinfo_t *sfxinfo,
|
||||
byte *data,
|
||||
int samplerate,
|
||||
int length)
|
||||
{
|
||||
SDL_AudioCVT convertor;
|
||||
allocated_sound_t *snd;
|
||||
Mix_Chunk *chunk;
|
||||
uint32_t expanded_length;
|
||||
|
||||
// Calculate the length of the expanded version of the sample.
|
||||
|
||||
expanded_length = (uint32_t) ((((uint64_t) length) * mixer_freq) / samplerate);
|
||||
|
||||
// Double up twice: 8 -> 16 bit and mono -> stereo
|
||||
|
||||
expanded_length *= 4;
|
||||
|
||||
// Allocate a chunk in which to expand the sound
|
||||
|
||||
snd = AllocateSound(sfxinfo, expanded_length);
|
||||
|
||||
if (snd == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
chunk = &snd->chunk;
|
||||
|
||||
// If we can, use the standard / optimized SDL conversion routines.
|
||||
|
||||
if (samplerate <= mixer_freq
|
||||
&& ConvertibleRatio(samplerate, mixer_freq)
|
||||
&& SDL_BuildAudioCVT(&convertor,
|
||||
AUDIO_U8, 1, samplerate,
|
||||
mixer_format, mixer_channels, mixer_freq))
|
||||
{
|
||||
convertor.buf = chunk->abuf;
|
||||
convertor.len = length;
|
||||
memcpy(convertor.buf, data, length);
|
||||
|
||||
SDL_ConvertAudio(&convertor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Sint16 *expanded = (Sint16 *) chunk->abuf;
|
||||
int expanded_length;
|
||||
int expand_ratio;
|
||||
int i;
|
||||
|
||||
// Generic expansion if conversion does not work:
|
||||
//
|
||||
// SDL's audio conversion only works for rate conversions that are
|
||||
// powers of 2; if the two formats are not in a direct power of 2
|
||||
// ratio, do this naive conversion instead.
|
||||
|
||||
// number of samples in the converted sound
|
||||
|
||||
expanded_length = ((uint64_t) length * mixer_freq) / samplerate;
|
||||
expand_ratio = (length << 8) / expanded_length;
|
||||
|
||||
for (i=0; i<expanded_length; ++i)
|
||||
{
|
||||
Sint16 sample;
|
||||
int src;
|
||||
|
||||
src = (i * expand_ratio) >> 8;
|
||||
|
||||
sample = data[src] | (data[src] << 8);
|
||||
sample -= 32768;
|
||||
|
||||
// expand 8->16 bits, mono->stereo
|
||||
|
||||
expanded[i * 2] = expanded[i * 2 + 1] = sample;
|
||||
}
|
||||
|
||||
// Perform a low-pass filter on the upscaled sound to filter
|
||||
// out high-frequency noise from the conversion process.
|
||||
|
||||
{
|
||||
float rc, dt, alpha;
|
||||
|
||||
// Low-pass filter for cutoff frequency f:
|
||||
//
|
||||
// For sampling rate r, dt = 1 / r
|
||||
// rc = 1 / 2*pi*f
|
||||
// alpha = dt / (rc + dt)
|
||||
|
||||
// Filter to the half sample rate of the original sound effect
|
||||
// (maximum frequency, by nyquist)
|
||||
|
||||
dt = 1.0f / mixer_freq;
|
||||
rc = 1.0f / (3.14f * samplerate);
|
||||
alpha = dt / (rc + dt);
|
||||
|
||||
// Both channels are processed in parallel, hence [i-2]:
|
||||
|
||||
for (i=2; i<expanded_length * 2; ++i)
|
||||
{
|
||||
expanded[i] = (Sint16) (alpha * expanded[i]
|
||||
+ (1 - alpha) * expanded[i-2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load and convert a sound effect
|
||||
// Returns true if successful
|
||||
|
||||
static boolean CacheSFX(sfxinfo_t *sfxinfo)
|
||||
{
|
||||
int lumpnum;
|
||||
unsigned int lumplen;
|
||||
int samplerate;
|
||||
unsigned int length;
|
||||
byte *data;
|
||||
|
||||
// need to load the sound
|
||||
|
||||
lumpnum = sfxinfo->lumpnum;
|
||||
data = W_CacheLumpNum(lumpnum, PU_STATIC);
|
||||
lumplen = W_LumpLength(lumpnum);
|
||||
|
||||
// Check the header, and ensure this is a valid sound
|
||||
|
||||
if (lumplen < 8
|
||||
|| data[0] != 0x03 || data[1] != 0x00)
|
||||
{
|
||||
// Invalid sound
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 16 bit sample rate field, 32 bit length field
|
||||
|
||||
samplerate = (data[3] << 8) | data[2];
|
||||
length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
|
||||
|
||||
// If the header specifies that the length of the sound is greater than
|
||||
// the length of the lump itself, this is an invalid sound lump
|
||||
|
||||
// We also discard sound lumps that are less than 49 samples long,
|
||||
// as this is how DMX behaves - although the actual cut-off length
|
||||
// seems to vary slightly depending on the sample rate. This needs
|
||||
// further investigation to better understand the correct
|
||||
// behavior.
|
||||
|
||||
if (length > lumplen - 8 || length <= 48)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The DMX sound library seems to skip the first 16 and last 16
|
||||
// bytes of the lump - reason unknown.
|
||||
|
||||
data += 16;
|
||||
length -= 32;
|
||||
|
||||
// Sample rate conversion
|
||||
|
||||
if (!ExpandSoundData(sfxinfo, data + 8, samplerate, length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// don't need the original lump any more
|
||||
|
||||
W_ReleaseLumpNum(lumpnum);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len)
|
||||
{
|
||||
// Linked sfx lumps? Get the lump number for the sound linked to.
|
||||
|
||||
if (sfx->link != NULL)
|
||||
{
|
||||
sfx = sfx->link;
|
||||
}
|
||||
|
||||
// Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't
|
||||
// do this.
|
||||
|
||||
if (use_sfx_prefix)
|
||||
{
|
||||
M_snprintf(buf, buf_len, "ds%s", (sfx->name));
|
||||
}
|
||||
else
|
||||
{
|
||||
M_StringCopy(buf, (sfx->name), buf_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
// Load a SFX chunk into memory and ensure that it is locked.
|
||||
|
||||
static boolean LockSound(sfxinfo_t *sfxinfo)
|
||||
{
|
||||
// If the sound isn't loaded, load it now
|
||||
if (GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, NORM_PITCH) == NULL)
|
||||
{
|
||||
if (!CacheSFX(sfxinfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LockAllocatedSound(GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, NORM_PITCH));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve the raw data lump index
|
||||
// for a given SFX name.
|
||||
//
|
||||
|
||||
static int I_SDL_GetSfxLumpNum(sfxinfo_t *sfx)
|
||||
{
|
||||
char namebuf[9];
|
||||
|
||||
GetSfxLumpName(sfx, namebuf, sizeof(namebuf));
|
||||
|
||||
return W_GetNumForName(namebuf);
|
||||
}
|
||||
|
||||
static void I_SDL_UpdateSoundParams(int handle, int vol, int sep)
|
||||
{
|
||||
int left, right;
|
||||
|
||||
if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
left = ((254 - sep) * vol) / 127;
|
||||
right = ((sep) * vol) / 127;
|
||||
|
||||
if (left < 0) left = 0;
|
||||
else if ( left > 255) left = 255;
|
||||
if (right < 0) right = 0;
|
||||
else if (right > 255) right = 255;
|
||||
|
||||
Mix_SetPanning(handle, left, right);
|
||||
}
|
||||
|
||||
//
|
||||
// Starting a sound means adding it
|
||||
// to the current list of active sounds
|
||||
// in the internal channels.
|
||||
// As the SFX info struct contains
|
||||
// e.g. a pointer to the raw data,
|
||||
// it is ignored.
|
||||
// As our sound handling does not handle
|
||||
// priority, it is ignored.
|
||||
// Pitching (that is, increased speed of playback)
|
||||
// is set, but currently not used by mixing.
|
||||
//
|
||||
|
||||
static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep, int pitch)
|
||||
{
|
||||
allocated_sound_t *snd;
|
||||
|
||||
if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Release a sound effect if there is already one playing
|
||||
// on this channel
|
||||
|
||||
ReleaseSoundOnChannel(channel);
|
||||
|
||||
// Get the sound data
|
||||
|
||||
if (!LockSound(sfxinfo))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
snd = GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, pitch);
|
||||
|
||||
if (snd == NULL)
|
||||
{
|
||||
allocated_sound_t *newsnd;
|
||||
// fetch the base sound effect, un-pitch-shifted
|
||||
snd = GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, NORM_PITCH);
|
||||
|
||||
if (snd == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (snd_pitchshift)
|
||||
{
|
||||
newsnd = PitchShift(snd, pitch);
|
||||
|
||||
if (newsnd)
|
||||
{
|
||||
LockAllocatedSound(newsnd);
|
||||
UnlockAllocatedSound(snd);
|
||||
snd = newsnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LockAllocatedSound(snd);
|
||||
}
|
||||
|
||||
// play sound
|
||||
|
||||
Mix_PlayChannel(channel, &snd->chunk, 0);
|
||||
|
||||
channels_playing[channel] = snd;
|
||||
|
||||
// set separation, etc.
|
||||
|
||||
I_SDL_UpdateSoundParams(channel, vol, sep);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
static void I_SDL_StopSound(int handle)
|
||||
{
|
||||
if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Sound data is no longer needed; release the
|
||||
// sound data being used for this channel
|
||||
|
||||
ReleaseSoundOnChannel(handle);
|
||||
}
|
||||
|
||||
|
||||
static boolean I_SDL_SoundIsPlaying(int handle)
|
||||
{
|
||||
if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Mix_Playing(handle);
|
||||
}
|
||||
|
||||
//
|
||||
// Periodically called to update the sound system
|
||||
//
|
||||
|
||||
static void I_SDL_UpdateSound(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Check all channels to see if a sound has finished
|
||||
|
||||
for (i=0; i<NUM_CHANNELS; ++i)
|
||||
{
|
||||
if (channels_playing[i] && !I_SDL_SoundIsPlaying(i))
|
||||
{
|
||||
// Sound has finished playing on this channel,
|
||||
// but sound data has not been released to cache
|
||||
|
||||
ReleaseSoundOnChannel(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void I_SDL_ShutdownSound(void)
|
||||
{
|
||||
if (!sound_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mix_CloseAudio();
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
|
||||
sound_initialized = false;
|
||||
}
|
||||
|
||||
// Calculate slice size, based on snd_maxslicetime_ms.
|
||||
// The result must be a power of two.
|
||||
|
||||
static int GetSliceSize(void)
|
||||
{
|
||||
int limit;
|
||||
int n;
|
||||
|
||||
limit = (snd_samplerate * snd_maxslicetime_ms) / 1000;
|
||||
|
||||
// Try all powers of two, not exceeding the limit.
|
||||
|
||||
for (n=0;; ++n)
|
||||
{
|
||||
// 2^n <= limit < 2^n+1 ?
|
||||
|
||||
if ((1 << (n + 1)) > limit)
|
||||
{
|
||||
return (1 << n);
|
||||
}
|
||||
}
|
||||
|
||||
// Should never happen?
|
||||
|
||||
return 1024;
|
||||
}
|
||||
|
||||
static boolean I_SDL_InitSound(boolean _use_sfx_prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
use_sfx_prefix = _use_sfx_prefix;
|
||||
|
||||
// No sounds yet
|
||||
|
||||
for (i=0; i<NUM_CHANNELS; ++i)
|
||||
{
|
||||
channels_playing[i] = NULL;
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0)
|
||||
{
|
||||
fprintf(stderr, "Unable to set up sound.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, GetSliceSize()) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
ExpandSoundData = ExpandSoundData_SDL;
|
||||
|
||||
Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
|
||||
|
||||
if (use_libsamplerate != 0)
|
||||
{
|
||||
fprintf(stderr, "I_SDL_InitSound: use_libsamplerate=%i, but "
|
||||
"libsamplerate support not compiled in.\n",
|
||||
use_libsamplerate);
|
||||
}
|
||||
|
||||
Mix_AllocateChannels(NUM_CHANNELS);
|
||||
|
||||
SDL_PauseAudio(0);
|
||||
|
||||
sound_initialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static snddevice_t sound_sdl_devices[] =
|
||||
{
|
||||
SNDDEVICE_SB,
|
||||
SNDDEVICE_PAS,
|
||||
SNDDEVICE_GUS,
|
||||
SNDDEVICE_WAVEBLASTER,
|
||||
SNDDEVICE_SOUNDCANVAS,
|
||||
SNDDEVICE_AWE32,
|
||||
};
|
||||
|
||||
sound_module_t sound_sdl_module =
|
||||
{
|
||||
sound_sdl_devices,
|
||||
arrlen(sound_sdl_devices),
|
||||
I_SDL_InitSound,
|
||||
I_SDL_ShutdownSound,
|
||||
I_SDL_GetSfxLumpNum,
|
||||
I_SDL_UpdateSound,
|
||||
I_SDL_UpdateSoundParams,
|
||||
I_SDL_StartSound,
|
||||
I_SDL_StopSound,
|
||||
I_SDL_SoundIsPlaying,
|
||||
I_SDL_PrecacheSounds,
|
||||
};
|
||||
|
||||
435
src/i_sound.c
Normal file
435
src/i_sound.c
Normal file
@@ -0,0 +1,435 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION: none
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "gusconf.h"
|
||||
#include "i_sound.h"
|
||||
#include "i_video.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_config.h"
|
||||
|
||||
// Sound sample rate to use for digital output (Hz)
|
||||
|
||||
int snd_samplerate = 44100;
|
||||
|
||||
// Maximum number of bytes to dedicate to allocated sound effects.
|
||||
// (Default: 64MB)
|
||||
|
||||
int snd_cachesize = 64 * 1024 * 1024;
|
||||
|
||||
// Config variable that controls the sound buffer size.
|
||||
// We default to 28ms (1000 / 35fps = 1 buffer per tic).
|
||||
|
||||
int snd_maxslicetime_ms = 28;
|
||||
|
||||
// External command to invoke to play back music.
|
||||
|
||||
char *snd_musiccmd = "";
|
||||
|
||||
// Whether to vary the pitch of sound effects
|
||||
// Each game will set the default differently
|
||||
|
||||
int snd_pitchshift = -1;
|
||||
|
||||
// Low-level sound and music modules we are using
|
||||
|
||||
static sound_module_t *sound_module;
|
||||
static music_module_t *music_module;
|
||||
|
||||
int snd_musicdevice = SNDDEVICE_SB;
|
||||
int snd_sfxdevice = SNDDEVICE_SB;
|
||||
|
||||
// Sound modules
|
||||
|
||||
extern void I_InitTimidityConfig(void);
|
||||
extern sound_module_t sound_sdl_module;
|
||||
extern music_module_t music_sdl_module;
|
||||
|
||||
// For native music module:
|
||||
|
||||
extern char *music_pack_path;
|
||||
extern char *timidity_cfg_path;
|
||||
|
||||
// Compiled-in sound modules:
|
||||
|
||||
static sound_module_t *sound_modules[] =
|
||||
{
|
||||
&sound_sdl_module,
|
||||
NULL,
|
||||
};
|
||||
|
||||
// Compiled-in music modules:
|
||||
|
||||
static music_module_t *music_modules[] =
|
||||
{
|
||||
&music_sdl_module,
|
||||
NULL,
|
||||
};
|
||||
|
||||
// Check if a sound device is in the given list of devices
|
||||
|
||||
static boolean SndDeviceInList(snddevice_t device, snddevice_t *list,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<len; ++i)
|
||||
{
|
||||
if (device == list[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find and initialize a sound_module_t appropriate for the setting
|
||||
// in snd_sfxdevice.
|
||||
|
||||
static void InitSfxModule(boolean use_sfx_prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
sound_module = NULL;
|
||||
|
||||
for (i=0; sound_modules[i] != NULL; ++i)
|
||||
{
|
||||
// Is the sfx device in the list of devices supported by
|
||||
// this module?
|
||||
|
||||
if (SndDeviceInList(snd_sfxdevice,
|
||||
sound_modules[i]->sound_devices,
|
||||
sound_modules[i]->num_sound_devices))
|
||||
{
|
||||
// Initialize the module
|
||||
|
||||
if (sound_modules[i]->Init(use_sfx_prefix))
|
||||
{
|
||||
sound_module = sound_modules[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize music according to snd_musicdevice.
|
||||
|
||||
static void InitMusicModule(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
music_module = NULL;
|
||||
|
||||
for (i=0; music_modules[i] != NULL; ++i)
|
||||
{
|
||||
// Is the music device in the list of devices supported
|
||||
// by this module?
|
||||
printf("snd_musicdevice\n");
|
||||
printf("%d\n", snd_musicdevice);
|
||||
|
||||
if (SndDeviceInList(snd_musicdevice,
|
||||
music_modules[i]->sound_devices,
|
||||
music_modules[i]->num_sound_devices))
|
||||
{
|
||||
printf("nope!\n");
|
||||
// Initialize the module
|
||||
|
||||
if (music_modules[i]->Init())
|
||||
{
|
||||
music_module = music_modules[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Initializes sound stuff, including volume
|
||||
// Sets channels, SFX and music volume,
|
||||
// allocates channel buffer, sets S_sfx lookup.
|
||||
//
|
||||
|
||||
void I_InitSound(boolean use_sfx_prefix)
|
||||
{
|
||||
boolean nosound, nosfx, nomusic;
|
||||
|
||||
//!
|
||||
// @vanilla
|
||||
//
|
||||
// Disable all sound output.
|
||||
//
|
||||
|
||||
nosound = M_CheckParm("-nosound") > 0;
|
||||
|
||||
//!
|
||||
// @vanilla
|
||||
//
|
||||
// Disable sound effects.
|
||||
//
|
||||
|
||||
nosfx = M_CheckParm("-nosfx") > 0;
|
||||
|
||||
//!
|
||||
// @vanilla
|
||||
//
|
||||
// Disable music.
|
||||
//
|
||||
|
||||
nomusic = M_CheckParm("-nomusic") > 0;
|
||||
|
||||
// Initialize the sound and music subsystems.
|
||||
|
||||
if (!nosound && !screensaver_mode)
|
||||
{
|
||||
// This is kind of a hack. If native MIDI is enabled, set up
|
||||
// the TIMIDITY_CFG environment variable here before SDL_mixer
|
||||
// is opened.
|
||||
|
||||
if (!nomusic
|
||||
&& (snd_musicdevice == SNDDEVICE_GENMIDI
|
||||
|| snd_musicdevice == SNDDEVICE_GUS))
|
||||
{
|
||||
I_InitTimidityConfig();
|
||||
}
|
||||
|
||||
if (!nosfx)
|
||||
{
|
||||
InitSfxModule(use_sfx_prefix);
|
||||
}
|
||||
|
||||
if (!nomusic)
|
||||
{
|
||||
InitMusicModule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I_ShutdownSound(void)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
sound_module->Shutdown();
|
||||
}
|
||||
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
int I_GetSfxLumpNum(sfxinfo_t *sfxinfo)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
return sound_module->GetSfxLumpNum(sfxinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void I_UpdateSound(void)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
sound_module->Update();
|
||||
}
|
||||
|
||||
if (music_module != NULL && music_module->Poll != NULL)
|
||||
{
|
||||
music_module->Poll();
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckVolumeSeparation(int *vol, int *sep)
|
||||
{
|
||||
if (*sep < 0)
|
||||
{
|
||||
*sep = 0;
|
||||
}
|
||||
else if (*sep > 254)
|
||||
{
|
||||
*sep = 254;
|
||||
}
|
||||
|
||||
if (*vol < 0)
|
||||
{
|
||||
*vol = 0;
|
||||
}
|
||||
else if (*vol > 127)
|
||||
{
|
||||
*vol = 127;
|
||||
}
|
||||
}
|
||||
|
||||
void I_UpdateSoundParams(int channel, int vol, int sep)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
CheckVolumeSeparation(&vol, &sep);
|
||||
sound_module->UpdateSoundParams(channel, vol, sep);
|
||||
}
|
||||
}
|
||||
|
||||
int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep, int pitch)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
CheckVolumeSeparation(&vol, &sep);
|
||||
return sound_module->StartSound(sfxinfo, channel, vol, sep, pitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void I_StopSound(int channel)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
sound_module->StopSound(channel);
|
||||
}
|
||||
}
|
||||
|
||||
boolean I_SoundIsPlaying(int channel)
|
||||
{
|
||||
if (sound_module != NULL)
|
||||
{
|
||||
return sound_module->SoundIsPlaying(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
|
||||
{
|
||||
if (sound_module != NULL && sound_module->CacheSounds != NULL)
|
||||
{
|
||||
sound_module->CacheSounds(sounds, num_sounds);
|
||||
}
|
||||
}
|
||||
|
||||
void I_InitMusic(void)
|
||||
{
|
||||
}
|
||||
|
||||
void I_ShutdownMusic(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void I_SetMusicVolume(int volume)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->SetMusicVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
void I_PauseSong(void)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->PauseMusic();
|
||||
}
|
||||
}
|
||||
|
||||
void I_ResumeSong(void)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->ResumeMusic();
|
||||
}
|
||||
}
|
||||
|
||||
void *I_RegisterSong(void *data, int len)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
return music_module->RegisterSong(data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void I_UnRegisterSong(void *handle)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->UnRegisterSong(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void I_PlaySong(void *handle, boolean looping)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->PlaySong(handle, looping);
|
||||
}
|
||||
}
|
||||
|
||||
void I_StopSong(void)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
music_module->StopSong();
|
||||
}
|
||||
}
|
||||
|
||||
boolean I_MusicIsPlaying(void)
|
||||
{
|
||||
if (music_module != NULL)
|
||||
{
|
||||
return music_module->MusicIsPlaying();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void I_BindSoundVariables(void)
|
||||
{
|
||||
extern int use_libsamplerate;
|
||||
extern float libsamplerate_scale;
|
||||
|
||||
M_BindIntVariable("snd_musicdevice", &snd_musicdevice);
|
||||
M_BindIntVariable("snd_sfxdevice", &snd_sfxdevice);
|
||||
M_BindIntVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms);
|
||||
M_BindStringVariable("snd_musiccmd", &snd_musiccmd);
|
||||
M_BindIntVariable("snd_samplerate", &snd_samplerate);
|
||||
M_BindIntVariable("snd_cachesize", &snd_cachesize);
|
||||
M_BindIntVariable("snd_pitchshift", &snd_pitchshift);
|
||||
|
||||
M_BindStringVariable("music_pack_path", &music_pack_path);
|
||||
M_BindStringVariable("timidity_cfg_path", &timidity_cfg_path);
|
||||
M_BindStringVariable("gus_patch_path", &gus_patch_path);
|
||||
M_BindIntVariable("gus_ram_kb", &gus_ram_kb);
|
||||
|
||||
M_BindIntVariable("use_libsamplerate", &use_libsamplerate);
|
||||
M_BindFloatVariable("libsamplerate_scale", &libsamplerate_scale);
|
||||
}
|
||||
|
||||
243
src/i_sound.h
Normal file
243
src/i_sound.h
Normal file
@@ -0,0 +1,243 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// The not so system specific sound interface.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_SOUND__
|
||||
#define __I_SOUND__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
struct sfxinfo_struct;
|
||||
|
||||
// so that the individual game logic and sound driver code agree
|
||||
#define NORM_PITCH 127
|
||||
|
||||
//
|
||||
// SoundFX struct.
|
||||
//
|
||||
typedef struct sfxinfo_struct sfxinfo_t;
|
||||
|
||||
struct sfxinfo_struct
|
||||
{
|
||||
// tag name, used for hexen.
|
||||
char *tagname;
|
||||
|
||||
// lump name. If we are running with use_sfx_prefix=true, a
|
||||
// 'DS' (or 'DP' for PC speaker sounds) is prepended to this.
|
||||
|
||||
char name[9];
|
||||
|
||||
// Sfx priority
|
||||
int priority;
|
||||
|
||||
// referenced sound if a link
|
||||
sfxinfo_t *link;
|
||||
|
||||
// pitch if a link (Doom), whether to pitch-shift (Hexen)
|
||||
int pitch;
|
||||
|
||||
// volume if a link
|
||||
int volume;
|
||||
|
||||
// this is checked every second to see if sound
|
||||
// can be thrown out (if 0, then decrement, if -1,
|
||||
// then throw out, if > 0, then it is in use)
|
||||
int usefulness;
|
||||
|
||||
// lump number of sfx
|
||||
int lumpnum;
|
||||
|
||||
// Maximum number of channels that the sound can be played on
|
||||
// (Heretic)
|
||||
int numchannels;
|
||||
|
||||
// data used by the low level code
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
//
|
||||
// MusicInfo struct.
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
// up to 6-character name
|
||||
char *name;
|
||||
|
||||
// lump number of music
|
||||
int lumpnum;
|
||||
|
||||
// music data
|
||||
void *data;
|
||||
|
||||
// music handle once registered
|
||||
void *handle;
|
||||
|
||||
} musicinfo_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SNDDEVICE_NONE = 0,
|
||||
SNDDEVICE_PCSPEAKER = 1,
|
||||
SNDDEVICE_ADLIB = 2,
|
||||
SNDDEVICE_SB = 3,
|
||||
SNDDEVICE_PAS = 4,
|
||||
SNDDEVICE_GUS = 5,
|
||||
SNDDEVICE_WAVEBLASTER = 6,
|
||||
SNDDEVICE_SOUNDCANVAS = 7,
|
||||
SNDDEVICE_GENMIDI = 8,
|
||||
SNDDEVICE_AWE32 = 9,
|
||||
SNDDEVICE_CD = 10,
|
||||
} snddevice_t;
|
||||
|
||||
// Interface for sound modules
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// List of sound devices that this sound module is used for.
|
||||
|
||||
snddevice_t *sound_devices;
|
||||
int num_sound_devices;
|
||||
|
||||
// Initialise sound module
|
||||
// Returns true if successfully initialised
|
||||
|
||||
boolean (*Init)(boolean use_sfx_prefix);
|
||||
|
||||
// Shutdown sound module
|
||||
|
||||
void (*Shutdown)(void);
|
||||
|
||||
// Returns the lump index of the given sound.
|
||||
|
||||
int (*GetSfxLumpNum)(sfxinfo_t *sfxinfo);
|
||||
|
||||
// Called periodically to update the subsystem.
|
||||
|
||||
void (*Update)(void);
|
||||
|
||||
// Update the sound settings on the given channel.
|
||||
|
||||
void (*UpdateSoundParams)(int channel, int vol, int sep);
|
||||
|
||||
// Start a sound on a given channel. Returns the channel id
|
||||
// or -1 on failure.
|
||||
|
||||
int (*StartSound)(sfxinfo_t *sfxinfo, int channel, int vol, int sep, int pitch);
|
||||
|
||||
// Stop the sound playing on the given channel.
|
||||
|
||||
void (*StopSound)(int channel);
|
||||
|
||||
// Query if a sound is playing on the given channel
|
||||
|
||||
boolean (*SoundIsPlaying)(int channel);
|
||||
|
||||
// Called on startup to precache sound effects (if necessary)
|
||||
|
||||
void (*CacheSounds)(sfxinfo_t *sounds, int num_sounds);
|
||||
|
||||
} sound_module_t;
|
||||
|
||||
void I_InitSound(boolean use_sfx_prefix);
|
||||
void I_ShutdownSound(void);
|
||||
int I_GetSfxLumpNum(sfxinfo_t *sfxinfo);
|
||||
void I_UpdateSound(void);
|
||||
void I_UpdateSoundParams(int channel, int vol, int sep);
|
||||
int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep, int pitch);
|
||||
void I_StopSound(int channel);
|
||||
boolean I_SoundIsPlaying(int channel);
|
||||
void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds);
|
||||
|
||||
// Interface for music modules
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// List of sound devices that this music module is used for.
|
||||
|
||||
snddevice_t *sound_devices;
|
||||
int num_sound_devices;
|
||||
|
||||
// Initialise the music subsystem
|
||||
|
||||
boolean (*Init)(void);
|
||||
|
||||
// Shutdown the music subsystem
|
||||
|
||||
void (*Shutdown)(void);
|
||||
|
||||
// Set music volume - range 0-127
|
||||
|
||||
void (*SetMusicVolume)(int volume);
|
||||
|
||||
// Pause music
|
||||
|
||||
void (*PauseMusic)(void);
|
||||
|
||||
// Un-pause music
|
||||
|
||||
void (*ResumeMusic)(void);
|
||||
|
||||
// Register a song handle from data
|
||||
// Returns a handle that can be used to play the song
|
||||
|
||||
void *(*RegisterSong)(void *data, int len);
|
||||
|
||||
// Un-register (free) song data
|
||||
|
||||
void (*UnRegisterSong)(void *handle);
|
||||
|
||||
// Play the song
|
||||
|
||||
void (*PlaySong)(void *handle, boolean looping);
|
||||
|
||||
// Stop playing the current song.
|
||||
|
||||
void (*StopSong)(void);
|
||||
|
||||
// Query if music is playing.
|
||||
|
||||
boolean (*MusicIsPlaying)(void);
|
||||
|
||||
// Invoked periodically to poll.
|
||||
|
||||
void (*Poll)(void);
|
||||
} music_module_t;
|
||||
|
||||
void I_InitMusic(void);
|
||||
void I_ShutdownMusic(void);
|
||||
void I_SetMusicVolume(int volume);
|
||||
void I_PauseSong(void);
|
||||
void I_ResumeSong(void);
|
||||
void *I_RegisterSong(void *data, int len);
|
||||
void I_UnRegisterSong(void *handle);
|
||||
void I_PlaySong(void *handle, boolean looping);
|
||||
void I_StopSong(void);
|
||||
boolean I_MusicIsPlaying(void);
|
||||
|
||||
extern int snd_sfxdevice;
|
||||
extern int snd_musicdevice;
|
||||
extern int snd_samplerate;
|
||||
extern int snd_cachesize;
|
||||
extern int snd_maxslicetime_ms;
|
||||
extern char *snd_musiccmd;
|
||||
extern int snd_pitchshift;
|
||||
|
||||
void I_BindSoundVariables(void);
|
||||
|
||||
#endif
|
||||
|
||||
43
src/i_swap.h
Normal file
43
src/i_swap.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Endianess handling, swapping 16bit and 32bit.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_SWAP__
|
||||
#define __I_SWAP__
|
||||
|
||||
#include "SDL2/SDL_endian.h"
|
||||
|
||||
// Endianess handling.
|
||||
// WAD files are stored little endian.
|
||||
|
||||
// Just use SDL's endianness swapping functions.
|
||||
|
||||
// These are deliberately cast to signed values; this is the behaviour
|
||||
// of the macros in the original source and some code relies on it.
|
||||
|
||||
#define SHORT(x) ((signed short) SDL_SwapLE16(x))
|
||||
#define LONG(x) ((signed int) SDL_SwapLE32(x))
|
||||
|
||||
// Defines for checking the endianness of the system.
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define SYS_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
409
src/i_system.c
Normal file
409
src/i_system.c
Normal file
@@ -0,0 +1,409 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_messagebox.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
struct atexit_listentry_s;
|
||||
|
||||
#define DEFAULT_RAM 16 /* MiB */
|
||||
#define MIN_RAM 4 /* MiB */
|
||||
|
||||
|
||||
typedef struct atexit_listentry_s atexit_listentry_t;
|
||||
|
||||
struct atexit_listentry_s
|
||||
{
|
||||
atexit_func_t func;
|
||||
boolean run_on_error;
|
||||
atexit_listentry_t *next;
|
||||
};
|
||||
|
||||
static atexit_listentry_t *exit_funcs = NULL;
|
||||
|
||||
void I_AtExit(atexit_func_t func, boolean run_on_error)
|
||||
{
|
||||
atexit_listentry_t *entry;
|
||||
|
||||
entry = malloc(sizeof(*entry));
|
||||
|
||||
entry->func = func;
|
||||
entry->run_on_error = run_on_error;
|
||||
entry->next = exit_funcs;
|
||||
exit_funcs = entry;
|
||||
}
|
||||
|
||||
// Tactile feedback function, probably used for the Logitech Cyberman
|
||||
|
||||
void I_Tactile(int on, int off, int total)
|
||||
{
|
||||
}
|
||||
|
||||
// Zone memory auto-allocation function that allocates the zone size
|
||||
// by trying progressively smaller zone sizes until one is found that
|
||||
// works.
|
||||
|
||||
static byte *AutoAllocMemory(int *size, int default_ram, int min_ram)
|
||||
{
|
||||
byte *zonemem;
|
||||
|
||||
// Allocate the zone memory. This loop tries progressively smaller
|
||||
// zone sizes until a size is found that can be allocated.
|
||||
// If we used the -mb command line parameter, only the parameter
|
||||
// provided is accepted.
|
||||
|
||||
zonemem = NULL;
|
||||
|
||||
while (zonemem == NULL)
|
||||
{
|
||||
// We need a reasonable minimum amount of RAM to start.
|
||||
|
||||
if (default_ram < min_ram)
|
||||
{
|
||||
I_Error("Unable to allocate %i MiB of RAM for zone", default_ram);
|
||||
}
|
||||
|
||||
// Try to allocate the zone memory.
|
||||
|
||||
*size = default_ram * 1024 * 1024;
|
||||
|
||||
zonemem = malloc(*size);
|
||||
|
||||
// Failed to allocate? Reduce zone size until we reach a size
|
||||
// that is acceptable.
|
||||
|
||||
if (zonemem == NULL)
|
||||
{
|
||||
default_ram -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return zonemem;
|
||||
}
|
||||
|
||||
byte *I_ZoneBase (int *size)
|
||||
{
|
||||
byte *zonemem;
|
||||
int min_ram, default_ram;
|
||||
int p;
|
||||
|
||||
//!
|
||||
// @arg <mb>
|
||||
//
|
||||
// Specify the heap size, in MiB (default 16).
|
||||
//
|
||||
|
||||
p = M_CheckParmWithArgs("-mb", 1);
|
||||
|
||||
if (p > 0)
|
||||
{
|
||||
default_ram = atoi(myargv[p+1]);
|
||||
min_ram = default_ram;
|
||||
}
|
||||
else
|
||||
{
|
||||
default_ram = DEFAULT_RAM;
|
||||
min_ram = MIN_RAM;
|
||||
}
|
||||
|
||||
zonemem = AutoAllocMemory(size, default_ram, min_ram);
|
||||
|
||||
printf("zone memory: %p, %x allocated for zone\n",
|
||||
zonemem, *size);
|
||||
|
||||
return zonemem;
|
||||
}
|
||||
|
||||
void I_PrintBanner(char *msg)
|
||||
{
|
||||
int i;
|
||||
int spaces = 35 - (strlen(msg) / 2);
|
||||
|
||||
for (i=0; i<spaces; ++i)
|
||||
putchar(' ');
|
||||
|
||||
puts(msg);
|
||||
}
|
||||
|
||||
void I_PrintDivider(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<75; ++i)
|
||||
{
|
||||
putchar('=');
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void I_PrintStartupBanner(char *gamedescription)
|
||||
{
|
||||
I_PrintDivider();
|
||||
I_PrintBanner(gamedescription);
|
||||
I_PrintDivider();
|
||||
|
||||
printf(
|
||||
" " "Chocolate Doom" " is free software, covered by the GNU General Public\n"
|
||||
" License. There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
|
||||
" FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
|
||||
" copies under certain conditions. See the source for more information.\n");
|
||||
|
||||
I_PrintDivider();
|
||||
}
|
||||
|
||||
//
|
||||
// I_ConsoleStdout
|
||||
//
|
||||
// Returns true if stdout is a real console, false if it is a file
|
||||
//
|
||||
|
||||
boolean I_ConsoleStdout(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// I_Init
|
||||
//
|
||||
/*
|
||||
void I_Init (void)
|
||||
{
|
||||
I_CheckIsScreensaver();
|
||||
I_InitTimer();
|
||||
I_InitJoystick();
|
||||
}
|
||||
void I_BindVariables(void)
|
||||
{
|
||||
I_BindVideoVariables();
|
||||
I_BindJoystickVariables();
|
||||
I_BindSoundVariables();
|
||||
}
|
||||
*/
|
||||
|
||||
//
|
||||
// I_Quit
|
||||
//
|
||||
|
||||
void I_Quit (void)
|
||||
{
|
||||
atexit_listentry_t *entry;
|
||||
|
||||
// Run through all exit functions
|
||||
|
||||
entry = exit_funcs;
|
||||
|
||||
while (entry != NULL)
|
||||
{
|
||||
entry->func();
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// I_Error
|
||||
//
|
||||
|
||||
static boolean already_quitting = false;
|
||||
|
||||
void I_Error (char *error, ...)
|
||||
{
|
||||
char msgbuf[512];
|
||||
va_list argptr;
|
||||
atexit_listentry_t *entry;
|
||||
boolean exit_gui_popup;
|
||||
|
||||
if (already_quitting)
|
||||
{
|
||||
fprintf(stderr, "Warning: recursive call to I_Error detected.\n");
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
already_quitting = true;
|
||||
}
|
||||
|
||||
// Message first.
|
||||
va_start(argptr, error);
|
||||
//fprintf(stderr, "\nError: ");
|
||||
vfprintf(stderr, error, argptr);
|
||||
fprintf(stderr, "\n\n");
|
||||
va_end(argptr);
|
||||
fflush(stderr);
|
||||
|
||||
// Write a copy of the message into buffer.
|
||||
va_start(argptr, error);
|
||||
memset(msgbuf, 0, sizeof(msgbuf));
|
||||
M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
|
||||
entry = exit_funcs;
|
||||
|
||||
while (entry != NULL)
|
||||
{
|
||||
if (entry->run_on_error)
|
||||
{
|
||||
entry->func();
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
exit_gui_popup = !M_ParmExists("-nogui");
|
||||
|
||||
// Pop up a GUI dialog box to show the error message, if the
|
||||
// game was not run from the console (and the user will
|
||||
// therefore be unable to otherwise see the message).
|
||||
if (exit_gui_popup && !I_ConsoleStdout())
|
||||
{
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
|
||||
"Chocolate Doom 3", msgbuf, NULL);
|
||||
}
|
||||
|
||||
// abort();
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//
|
||||
// Read Access Violation emulation.
|
||||
//
|
||||
// From PrBoom+, by entryway.
|
||||
//
|
||||
|
||||
// C:\>debug
|
||||
// -d 0:0
|
||||
//
|
||||
// DOS 6.22:
|
||||
// 0000:0000 (57 92 19 00) F4 06 70 00-(16 00)
|
||||
// DOS 7.1:
|
||||
// 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)
|
||||
// Win98:
|
||||
// 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)
|
||||
// DOSBox under XP:
|
||||
// 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00)
|
||||
|
||||
#define DOS_MEM_DUMP_SIZE 10
|
||||
|
||||
static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {
|
||||
0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};
|
||||
static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {
|
||||
0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};
|
||||
static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {
|
||||
0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};
|
||||
static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];
|
||||
|
||||
static const unsigned char *dos_mem_dump = mem_dump_dos622;
|
||||
|
||||
boolean I_GetMemoryValue(unsigned int offset, void *value, int size)
|
||||
{
|
||||
static boolean firsttime = true;
|
||||
|
||||
if (firsttime)
|
||||
{
|
||||
int p, i, val;
|
||||
|
||||
firsttime = false;
|
||||
i = 0;
|
||||
|
||||
//!
|
||||
// @category compat
|
||||
// @arg <version>
|
||||
//
|
||||
// Specify DOS version to emulate for NULL pointer dereference
|
||||
// emulation. Supported versions are: dos622, dos71, dosbox.
|
||||
// The default is to emulate DOS 7.1 (Windows 98).
|
||||
//
|
||||
|
||||
p = M_CheckParmWithArgs("-setmem", 1);
|
||||
|
||||
if (p > 0)
|
||||
{
|
||||
if (!strcasecmp(myargv[p + 1], "dos622"))
|
||||
{
|
||||
dos_mem_dump = mem_dump_dos622;
|
||||
}
|
||||
if (!strcasecmp(myargv[p + 1], "dos71"))
|
||||
{
|
||||
dos_mem_dump = mem_dump_win98;
|
||||
}
|
||||
else if (!strcasecmp(myargv[p + 1], "dosbox"))
|
||||
{
|
||||
dos_mem_dump = mem_dump_dosbox;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i)
|
||||
{
|
||||
++p;
|
||||
|
||||
if (p >= myargc || myargv[p][0] == '-')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
M_StrToInt(myargv[p], &val);
|
||||
mem_dump_custom[i++] = (unsigned char) val;
|
||||
}
|
||||
|
||||
dos_mem_dump = mem_dump_custom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
*((unsigned char *) value) = dos_mem_dump[offset];
|
||||
return true;
|
||||
case 2:
|
||||
*((unsigned short *) value) = dos_mem_dump[offset]
|
||||
| (dos_mem_dump[offset + 1] << 8);
|
||||
return true;
|
||||
case 4:
|
||||
*((unsigned int *) value) = dos_mem_dump[offset]
|
||||
| (dos_mem_dump[offset + 1] << 8)
|
||||
| (dos_mem_dump[offset + 2] << 16)
|
||||
| (dos_mem_dump[offset + 3] << 24);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
84
src/i_system.h
Normal file
84
src/i_system.h
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System specific interface stuff.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_SYSTEM__
|
||||
#define __I_SYSTEM__
|
||||
|
||||
#include "d_ticcmd.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
|
||||
typedef void (*atexit_func_t)(void);
|
||||
|
||||
// Called by DoomMain.
|
||||
void I_Init (void);
|
||||
|
||||
// Called by startup code
|
||||
// to get the ammount of memory to malloc
|
||||
// for the zone management.
|
||||
byte* I_ZoneBase (int *size);
|
||||
|
||||
boolean I_ConsoleStdout(void);
|
||||
|
||||
|
||||
// Asynchronous interrupt functions should maintain private queues
|
||||
// that are read by the synchronous functions
|
||||
// to be converted into events.
|
||||
|
||||
// Either returns a null ticcmd,
|
||||
// or calls a loadable driver to build it.
|
||||
// This ticcmd will then be modified by the gameloop
|
||||
// for normal input.
|
||||
ticcmd_t* I_BaseTiccmd (void);
|
||||
|
||||
|
||||
// Called by M_Responder when quit is selected.
|
||||
// Clean exit, displays sell blurb.
|
||||
void I_Quit (void);
|
||||
|
||||
void I_Error (char *error, ...);
|
||||
|
||||
void I_Tactile (int on, int off, int total);
|
||||
|
||||
boolean I_GetMemoryValue(unsigned int offset, void *value, int size);
|
||||
|
||||
// Schedule a function to be called when the program exits.
|
||||
// If run_if_error is true, the function is called if the exit
|
||||
// is due to an error (I_Error)
|
||||
|
||||
void I_AtExit(atexit_func_t func, boolean run_if_error);
|
||||
|
||||
// Add all system-specific config file variable bindings.
|
||||
|
||||
void I_BindVariables(void);
|
||||
|
||||
// Print startup banner copyright message.
|
||||
|
||||
void I_PrintStartupBanner(char *gamedescription);
|
||||
|
||||
// Print a centered text banner displaying the given string.
|
||||
|
||||
void I_PrintBanner(char *text);
|
||||
|
||||
// Print a dividing line for startup banners.
|
||||
|
||||
void I_PrintDivider(void);
|
||||
|
||||
#endif
|
||||
|
||||
80
src/i_timer.c
Normal file
80
src/i_timer.c
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Timer functions.
|
||||
//
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_stdinc.h"
|
||||
#include "SDL2/SDL_timer.h"
|
||||
#include "i_timer.h"
|
||||
|
||||
//
|
||||
// I_GetTime
|
||||
// returns time in 1/35th second tics
|
||||
//
|
||||
|
||||
static Uint32 basetime = 0;
|
||||
|
||||
int I_GetTime (void)
|
||||
{
|
||||
Uint32 ticks;
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
if (basetime == 0)
|
||||
basetime = ticks;
|
||||
|
||||
ticks -= basetime;
|
||||
|
||||
return (ticks * TICRATE) / 1000;
|
||||
}
|
||||
|
||||
//
|
||||
// Same as I_GetTime, but returns time in milliseconds
|
||||
//
|
||||
|
||||
int I_GetTimeMS(void)
|
||||
{
|
||||
Uint32 ticks;
|
||||
|
||||
ticks = SDL_GetTicks();
|
||||
|
||||
if (basetime == 0)
|
||||
basetime = ticks;
|
||||
|
||||
return ticks - basetime;
|
||||
}
|
||||
|
||||
// Sleep for a specified number of ms
|
||||
|
||||
void I_Sleep(int ms)
|
||||
{
|
||||
SDL_Delay(ms);
|
||||
}
|
||||
|
||||
void I_WaitVBL(int count)
|
||||
{
|
||||
I_Sleep((count * 1000) / 70);
|
||||
}
|
||||
|
||||
|
||||
void I_InitTimer(void)
|
||||
{
|
||||
// initialize timer
|
||||
|
||||
SDL_Init(SDL_INIT_TIMER);
|
||||
}
|
||||
|
||||
42
src/i_timer.h
Normal file
42
src/i_timer.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System-specific timer interface
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_TIMER__
|
||||
#define __I_TIMER__
|
||||
|
||||
#define TICRATE 35
|
||||
|
||||
// Called by D_DoomLoop,
|
||||
// returns current time in tics.
|
||||
int I_GetTime (void);
|
||||
|
||||
// returns current time in ms
|
||||
int I_GetTimeMS (void);
|
||||
|
||||
// Pause for a specified number of ms
|
||||
void I_Sleep(int ms);
|
||||
|
||||
// Initialize timer
|
||||
void I_InitTimer(void);
|
||||
|
||||
// Wait for vertical retrace or pause a bit.
|
||||
void I_WaitVBL(int count);
|
||||
|
||||
#endif
|
||||
|
||||
1451
src/i_video.c
Normal file
1451
src/i_video.c
Normal file
File diff suppressed because it is too large
Load Diff
103
src/i_video.h
Normal file
103
src/i_video.h
Normal file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// System specific interface stuff.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __I_VIDEO__
|
||||
#define __I_VIDEO__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
// Screen width and height.
|
||||
|
||||
#define SCREENWIDTH 320
|
||||
#define SCREENHEIGHT 200
|
||||
|
||||
// Screen height used when aspect_ratio_correct=true.
|
||||
|
||||
#define SCREENHEIGHT_4_3 240
|
||||
|
||||
typedef boolean (*grabmouse_callback_t)(void);
|
||||
|
||||
// Called by D_DoomMain,
|
||||
// determines the hardware configuration
|
||||
// and sets up the video mode
|
||||
void I_InitGraphics (void);
|
||||
|
||||
void I_GraphicsCheckCommandLine(void);
|
||||
|
||||
void I_ShutdownGraphics(void);
|
||||
|
||||
// Takes full 8 bit values.
|
||||
void I_SetPalette (byte* palette);
|
||||
int I_GetPaletteIndex(int r, int g, int b);
|
||||
|
||||
void I_UpdateNoBlit (void);
|
||||
void I_FinishUpdate (void);
|
||||
|
||||
void I_ReadScreen (pixel_t* scr);
|
||||
|
||||
void I_BeginRead (void);
|
||||
|
||||
void I_SetWindowTitle(char *title);
|
||||
|
||||
void I_CheckIsScreensaver(void);
|
||||
void I_SetGrabMouseCallback(grabmouse_callback_t func);
|
||||
|
||||
void I_DisplayFPSDots(boolean dots_on);
|
||||
void I_BindVideoVariables(void);
|
||||
|
||||
void I_InitWindowTitle(void);
|
||||
void I_InitWindowIcon(void);
|
||||
|
||||
// Called before processing any tics in a frame (just after displaying a frame).
|
||||
// Time consuming syncronous operations are performed here (joystick reading).
|
||||
|
||||
void I_StartFrame (void);
|
||||
|
||||
// Called before processing each tic in a frame.
|
||||
// Quick syncronous operations are performed here.
|
||||
|
||||
void I_StartTic (void);
|
||||
|
||||
// Enable the loading disk image displayed when reading from disk.
|
||||
|
||||
void I_EnableLoadingDisk(int xoffs, int yoffs);
|
||||
|
||||
extern char *video_driver;
|
||||
extern boolean screenvisible;
|
||||
|
||||
extern int vanilla_keyboard_mapping;
|
||||
extern boolean screensaver_mode;
|
||||
extern int usegamma;
|
||||
extern pixel_t *I_VideoBuffer;
|
||||
|
||||
extern int screen_width;
|
||||
extern int screen_height;
|
||||
extern int fullscreen;
|
||||
extern int aspect_ratio_correct;
|
||||
extern int integer_scaling;
|
||||
extern int vga_porch_flash;
|
||||
extern int force_software_renderer;
|
||||
|
||||
extern char *window_position;
|
||||
void I_GetWindowPosition(int *x, int *y, int w, int h);
|
||||
|
||||
// Joystic/gamepad hysteresis
|
||||
extern unsigned int joywait;
|
||||
|
||||
#endif
|
||||
264
src/i_videohr.c
Normal file
264
src/i_videohr.c
Normal file
@@ -0,0 +1,264 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// SDL emulation of VGA 640x480x4 planar video mode,
|
||||
// for Hexen startup loading screen.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_events.h"
|
||||
#include "SDL2/SDL_keyboard.h"
|
||||
#include "SDL2/SDL_keycode.h"
|
||||
#include "SDL2/SDL_pixels.h"
|
||||
#include "SDL2/SDL_rect.h"
|
||||
#include "SDL2/SDL_surface.h"
|
||||
#include "SDL2/SDL_video.h"
|
||||
#include "doomtype.h"
|
||||
#include "i_timer.h"
|
||||
#include "i_video.h"
|
||||
|
||||
// Palette fade-in takes two seconds
|
||||
|
||||
#define FADE_TIME 2000
|
||||
|
||||
#define HR_SCREENWIDTH 640
|
||||
#define HR_SCREENHEIGHT 480
|
||||
|
||||
static SDL_Window *hr_screen = NULL;
|
||||
static SDL_Surface *hr_surface = NULL;
|
||||
static char *window_title = "";
|
||||
|
||||
boolean I_SetVideoModeHR(void)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
I_GetWindowPosition(&x, &y, HR_SCREENWIDTH, HR_SCREENHEIGHT);
|
||||
|
||||
// Create screen surface at the native desktop pixel depth (bpp=0),
|
||||
// as we cannot trust true 8-bit to reliably work nowadays.
|
||||
hr_screen = SDL_CreateWindow(window_title, x, y,
|
||||
HR_SCREENWIDTH, HR_SCREENHEIGHT,
|
||||
0);
|
||||
|
||||
if (hr_screen == NULL)
|
||||
{
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We do all actual drawing into an intermediate surface.
|
||||
hr_surface = SDL_CreateRGBSurface(0, HR_SCREENWIDTH, HR_SCREENHEIGHT,
|
||||
8, 0, 0, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void I_SetWindowTitleHR(char *title)
|
||||
{
|
||||
window_title = title;
|
||||
}
|
||||
|
||||
void I_UnsetVideoModeHR(void)
|
||||
{
|
||||
if (hr_screen != NULL)
|
||||
{
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
hr_screen = NULL;
|
||||
SDL_FreeSurface(hr_surface);
|
||||
hr_surface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void I_ClearScreenHR(void)
|
||||
{
|
||||
SDL_Rect area = { 0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT };
|
||||
|
||||
SDL_FillRect(hr_surface, &area, 0);
|
||||
}
|
||||
|
||||
void I_SlamBlockHR(int x, int y, int w, int h, const byte *src)
|
||||
{
|
||||
SDL_Rect blit_rect;
|
||||
const byte *srcptrs[4];
|
||||
byte srcbits[4];
|
||||
byte *dest;
|
||||
int x1, y1;
|
||||
int i;
|
||||
int bit;
|
||||
|
||||
// Set up source pointers to read from source buffer - each 4-bit
|
||||
// pixel has its bits split into four sub-buffers
|
||||
|
||||
for (i=0; i<4; ++i)
|
||||
{
|
||||
srcptrs[i] = src + (i * w * h / 8);
|
||||
}
|
||||
|
||||
if (SDL_LockSurface(hr_surface) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw each pixel
|
||||
|
||||
bit = 0;
|
||||
|
||||
for (y1=y; y1<y+h; ++y1)
|
||||
{
|
||||
dest = ((byte *) hr_surface->pixels) + y1 * hr_surface->pitch + x;
|
||||
|
||||
for (x1=x; x1<x+w; ++x1)
|
||||
{
|
||||
// Get the bits for this pixel
|
||||
// For each bit, find the byte containing it, shift down
|
||||
// and mask out the specific bit wanted.
|
||||
|
||||
for (i=0; i<4; ++i)
|
||||
{
|
||||
srcbits[i] = (srcptrs[i][bit / 8] >> (7 - (bit % 8))) & 0x1;
|
||||
}
|
||||
|
||||
// Reassemble the pixel value
|
||||
|
||||
*dest = (srcbits[0] << 0)
|
||||
| (srcbits[1] << 1)
|
||||
| (srcbits[2] << 2)
|
||||
| (srcbits[3] << 3);
|
||||
|
||||
// Next pixel!
|
||||
|
||||
++dest;
|
||||
++bit;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(hr_surface);
|
||||
|
||||
// Update the region we drew.
|
||||
blit_rect.x = x;
|
||||
blit_rect.y = y;
|
||||
blit_rect.w = w;
|
||||
blit_rect.h = h;
|
||||
SDL_BlitSurface(hr_surface, &blit_rect,
|
||||
SDL_GetWindowSurface(hr_screen), &blit_rect);
|
||||
SDL_UpdateWindowSurfaceRects(hr_screen, &blit_rect, 1);
|
||||
}
|
||||
|
||||
void I_SlamHR(const byte *buffer)
|
||||
{
|
||||
I_SlamBlockHR(0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT, buffer);
|
||||
}
|
||||
|
||||
void I_InitPaletteHR(void)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
void I_SetPaletteHR(const byte *palette)
|
||||
{
|
||||
SDL_Rect screen_rect = {0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT};
|
||||
SDL_Color sdlpal[16];
|
||||
int i;
|
||||
|
||||
for (i=0; i<16; ++i)
|
||||
{
|
||||
sdlpal[i].r = palette[i * 3 + 0] * 4;
|
||||
sdlpal[i].g = palette[i * 3 + 1] * 4;
|
||||
sdlpal[i].b = palette[i * 3 + 2] * 4;
|
||||
}
|
||||
|
||||
// After setting colors, update the screen.
|
||||
SDL_SetPaletteColors(hr_surface->format->palette, sdlpal, 0, 16);
|
||||
SDL_BlitSurface(hr_surface, &screen_rect,
|
||||
SDL_GetWindowSurface(hr_screen), &screen_rect);
|
||||
SDL_UpdateWindowSurfaceRects(hr_screen, &screen_rect, 1);
|
||||
}
|
||||
|
||||
void I_FadeToPaletteHR(const byte *palette)
|
||||
{
|
||||
byte tmppal[16 * 3];
|
||||
int starttime;
|
||||
int elapsed;
|
||||
int i;
|
||||
|
||||
starttime = I_GetTimeMS();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
elapsed = I_GetTimeMS() - starttime;
|
||||
|
||||
if (elapsed >= FADE_TIME)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate the fake palette
|
||||
|
||||
for (i=0; i<16 * 3; ++i)
|
||||
{
|
||||
tmppal[i] = (palette[i] * elapsed) / FADE_TIME;
|
||||
}
|
||||
|
||||
I_SetPaletteHR(tmppal);
|
||||
SDL_UpdateWindowSurface(hr_screen);
|
||||
|
||||
// Sleep a bit
|
||||
|
||||
I_Sleep(10);
|
||||
}
|
||||
|
||||
// Set the final palette
|
||||
|
||||
I_SetPaletteHR(palette);
|
||||
}
|
||||
|
||||
void I_BlackPaletteHR(void)
|
||||
{
|
||||
byte blackpal[16 * 3];
|
||||
|
||||
memset(blackpal, 0, sizeof(blackpal));
|
||||
|
||||
I_SetPaletteHR(blackpal);
|
||||
}
|
||||
|
||||
// Check if the user has hit the escape key to abort startup.
|
||||
boolean I_CheckAbortHR(void)
|
||||
{
|
||||
SDL_Event ev;
|
||||
boolean result = false;
|
||||
|
||||
// Not initialized?
|
||||
if (hr_surface == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (SDL_PollEvent(&ev))
|
||||
{
|
||||
if (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_ESCAPE)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
35
src/i_videohr.h
Normal file
35
src/i_videohr.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// SDL emulation of VGA 640x480x4 planar video mode,
|
||||
// for Hexen startup loading screen.
|
||||
//
|
||||
|
||||
#ifndef I_VIDEOHR_H
|
||||
#define I_VIDEOHR_H
|
||||
|
||||
boolean I_SetVideoModeHR(void);
|
||||
void I_UnsetVideoModeHR(void);
|
||||
void I_SetWindowTitleHR(char *title);
|
||||
void I_ClearScreenHR(void);
|
||||
void I_SlamBlockHR(int x, int y, int w, int h, const byte *src);
|
||||
void I_SlamHR(const byte *buffer);
|
||||
void I_InitPaletteHR(void);
|
||||
void I_SetPaletteHR(const byte *palette);
|
||||
void I_FadeToPaletteHR(const byte *palette);
|
||||
void I_BlackPaletteHR(void);
|
||||
boolean I_CheckAbortHR(void);
|
||||
|
||||
#endif /* #ifndef I_VIDEOHR_H */
|
||||
|
||||
4797
src/info.c
Normal file
4797
src/info.c
Normal file
File diff suppressed because it is too large
Load Diff
1326
src/info.h
Normal file
1326
src/info.h
Normal file
File diff suppressed because it is too large
Load Diff
10
src/ipu/AM_map.c
Normal file
10
src/ipu/AM_map.c
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
|
||||
typedef unsigned char pixel_t;
|
||||
|
||||
void AM_Drawer(pixel_t* fb) {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
fb[(i + 1) * 320] = 56;
|
||||
}
|
||||
}
|
||||
BIN
src/ipu/AM_map.gp
Normal file
BIN
src/ipu/AM_map.gp
Normal file
Binary file not shown.
16
src/ipu/Makefile
Normal file
16
src/ipu/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
GARPHOBJS = AM_map.gp # m_fixed.gp
|
||||
|
||||
all: ipu_rt.gp
|
||||
|
||||
ipu_rt.gp: $(GARPHOBJS) ipu_vertices.gp
|
||||
popc $(GARPHOBJS) ipu_vertices.gp -o $@
|
||||
|
||||
ipu_vertices.gp: ipu_vertices.cpp
|
||||
popc -Os $^ -o $@
|
||||
|
||||
%.gp: %.c
|
||||
popc -Os $^ -o $@
|
||||
|
||||
clean:
|
||||
rm $(GARPHOBJS) ipu_vertices.gp
|
||||
11
src/ipu/am_map.h
Normal file
11
src/ipu/am_map.h
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
#ifndef __AMMAP_H__
|
||||
#define __AMMAP_H__
|
||||
|
||||
|
||||
typedef uint8_t pixel_t;
|
||||
void AM_Drawer(pixel_t*);
|
||||
|
||||
|
||||
#endif
|
||||
BIN
src/ipu/ipu_rt.gp
Normal file
BIN
src/ipu/ipu_rt.gp
Normal file
Binary file not shown.
31
src/ipu/ipu_vertices.cpp
Normal file
31
src/ipu/ipu_vertices.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
#include <Vertex.hpp>
|
||||
|
||||
// #include "doomtype.h"
|
||||
typedef uint8_t pixel_t;
|
||||
|
||||
|
||||
extern "C" {
|
||||
void AM_LevelInit(void);
|
||||
void AM_Drawer(pixel_t*);
|
||||
};
|
||||
|
||||
|
||||
class AM_LevelInit_Vertex : public poplar::Vertex {
|
||||
public:
|
||||
bool compute() {
|
||||
AM_LevelInit();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class AM_Drawer_Vertex : public poplar::Vertex {
|
||||
public:
|
||||
poplar::InOut<poplar::Vector<unsigned char>> frame;
|
||||
|
||||
bool compute() {
|
||||
AM_Drawer(&frame[0]);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
BIN
src/ipu/ipu_vertices.gp
Normal file
BIN
src/ipu/ipu_vertices.gp
Normal file
Binary file not shown.
262
src/m_argv.c
Normal file
262
src/m_argv.c
Normal file
@@ -0,0 +1,262 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
#include "m_argv.h" // haleyjd 20110212: warning fix
|
||||
#include "m_misc.h"
|
||||
|
||||
int myargc;
|
||||
char** myargv;
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// M_CheckParm
|
||||
// Checks for the given parameter
|
||||
// in the program's command line arguments.
|
||||
// Returns the argument number (1 to argc-1)
|
||||
// or 0 if not present
|
||||
//
|
||||
|
||||
int M_CheckParmWithArgs(char *check, int num_args)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < myargc - num_args; i++)
|
||||
{
|
||||
if (!strcasecmp(check, myargv[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// M_ParmExists
|
||||
//
|
||||
// Returns true if the given parameter exists in the program's command
|
||||
// line arguments, false if not.
|
||||
//
|
||||
|
||||
boolean M_ParmExists(char *check)
|
||||
{
|
||||
return M_CheckParm(check) != 0;
|
||||
}
|
||||
|
||||
int M_CheckParm(char *check)
|
||||
{
|
||||
return M_CheckParmWithArgs(check, 0);
|
||||
}
|
||||
|
||||
#define MAXARGVS 100
|
||||
|
||||
static void LoadResponseFile(int argv_index)
|
||||
{
|
||||
FILE *handle;
|
||||
int size;
|
||||
char *infile;
|
||||
char *file;
|
||||
char *response_filename;
|
||||
char **newargv;
|
||||
int newargc;
|
||||
int i, k;
|
||||
|
||||
response_filename = myargv[argv_index] + 1;
|
||||
|
||||
// Read the response file into memory
|
||||
handle = fopen(response_filename, "rb");
|
||||
|
||||
if (handle == NULL)
|
||||
{
|
||||
printf ("\nNo such response file!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Found response file %s!\n", response_filename);
|
||||
|
||||
size = M_FileLength(handle);
|
||||
|
||||
// Read in the entire file
|
||||
// Allocate one byte extra - this is in case there is an argument
|
||||
// at the end of the response file, in which case a '\0' will be
|
||||
// needed.
|
||||
|
||||
file = malloc(size + 1);
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < size)
|
||||
{
|
||||
k = fread(file + i, 1, size - i, handle);
|
||||
|
||||
if (k < 0)
|
||||
{
|
||||
I_Error("Failed to read full contents of '%s'", response_filename);
|
||||
}
|
||||
|
||||
i += k;
|
||||
}
|
||||
|
||||
fclose(handle);
|
||||
|
||||
// Create new arguments list array
|
||||
|
||||
newargv = malloc(sizeof(char *) * MAXARGVS);
|
||||
newargc = 0;
|
||||
memset(newargv, 0, sizeof(char *) * MAXARGVS);
|
||||
|
||||
// Copy all the arguments in the list up to the response file
|
||||
|
||||
for (i=0; i<argv_index; ++i)
|
||||
{
|
||||
newargv[i] = myargv[i];
|
||||
++newargc;
|
||||
}
|
||||
|
||||
infile = file;
|
||||
k = 0;
|
||||
|
||||
while(k < size)
|
||||
{
|
||||
// Skip past space characters to the next argument
|
||||
|
||||
while(k < size && isspace(infile[k]))
|
||||
{
|
||||
++k;
|
||||
}
|
||||
|
||||
if (k >= size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// If the next argument is enclosed in quote marks, treat
|
||||
// the contents as a single argument. This allows long filenames
|
||||
// to be specified.
|
||||
|
||||
if (infile[k] == '\"')
|
||||
{
|
||||
// Skip the first character(")
|
||||
++k;
|
||||
|
||||
newargv[newargc++] = &infile[k];
|
||||
|
||||
// Read all characters between quotes
|
||||
|
||||
while (k < size && infile[k] != '\"' && infile[k] != '\n')
|
||||
{
|
||||
++k;
|
||||
}
|
||||
|
||||
if (k >= size || infile[k] == '\n')
|
||||
{
|
||||
I_Error("Quotes unclosed in response file '%s'",
|
||||
response_filename);
|
||||
}
|
||||
|
||||
// Cut off the string at the closing quote
|
||||
|
||||
infile[k] = '\0';
|
||||
++k;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read in the next argument until a space is reached
|
||||
|
||||
newargv[newargc++] = &infile[k];
|
||||
|
||||
while(k < size && !isspace(infile[k]))
|
||||
{
|
||||
++k;
|
||||
}
|
||||
|
||||
// Cut off the end of the argument at the first space
|
||||
|
||||
infile[k] = '\0';
|
||||
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
// Add arguments following the response file argument
|
||||
|
||||
for (i=argv_index + 1; i<myargc; ++i)
|
||||
{
|
||||
newargv[newargc] = myargv[i];
|
||||
++newargc;
|
||||
}
|
||||
|
||||
myargv = newargv;
|
||||
myargc = newargc;
|
||||
|
||||
#if 0
|
||||
// Disabled - Vanilla Doom does not do this.
|
||||
// Display arguments
|
||||
|
||||
printf("%d command-line args:\n", myargc);
|
||||
|
||||
for (k=1; k<myargc; k++)
|
||||
{
|
||||
printf("'%s'\n", myargv[k]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Find a Response File
|
||||
//
|
||||
|
||||
void M_FindResponseFile(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < myargc; i++)
|
||||
{
|
||||
if (myargv[i][0] == '@')
|
||||
{
|
||||
LoadResponseFile(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the name of the executable used to start the program:
|
||||
|
||||
char *M_GetExecutableName(void)
|
||||
{
|
||||
char *sep;
|
||||
|
||||
sep = strrchr(myargv[0], DIR_SEPARATOR);
|
||||
|
||||
if (sep == NULL)
|
||||
{
|
||||
return myargv[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return sep + 1;
|
||||
}
|
||||
}
|
||||
|
||||
49
src/m_argv.h
Normal file
49
src/m_argv.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Nil.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __M_ARGV__
|
||||
#define __M_ARGV__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
//
|
||||
// MISC
|
||||
//
|
||||
extern int myargc;
|
||||
extern char** myargv;
|
||||
|
||||
// Returns the position of the given parameter
|
||||
// in the arg list (0 if not found).
|
||||
int M_CheckParm (char* check);
|
||||
|
||||
// Same as M_CheckParm, but checks that num_args arguments are available
|
||||
// following the specified argument.
|
||||
int M_CheckParmWithArgs(char *check, int num_args);
|
||||
|
||||
void M_FindResponseFile(void);
|
||||
|
||||
// Parameter has been specified?
|
||||
|
||||
boolean M_ParmExists(char *check);
|
||||
|
||||
// Get name of executable used to run this program:
|
||||
|
||||
char *M_GetExecutableName(void);
|
||||
|
||||
#endif
|
||||
56
src/m_bbox.c
Normal file
56
src/m_bbox.c
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Main loop menu stuff.
|
||||
// Random number LUT.
|
||||
// Default Config File.
|
||||
// PCX Screenshots.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "m_bbox.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
|
||||
|
||||
void M_ClearBox (fixed_t *box)
|
||||
{
|
||||
box[BOXTOP] = box[BOXRIGHT] = INT_MIN;
|
||||
box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
M_AddToBox
|
||||
( fixed_t* box,
|
||||
fixed_t x,
|
||||
fixed_t y )
|
||||
{
|
||||
if (x<box[BOXLEFT])
|
||||
box[BOXLEFT] = x;
|
||||
else if (x>box[BOXRIGHT])
|
||||
box[BOXRIGHT] = x;
|
||||
if (y<box[BOXBOTTOM])
|
||||
box[BOXBOTTOM] = y;
|
||||
else if (y>box[BOXTOP])
|
||||
box[BOXTOP] = y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
45
src/m_bbox.h
Normal file
45
src/m_bbox.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Nil.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __M_BBOX__
|
||||
#define __M_BBOX__
|
||||
|
||||
#include "m_fixed.h"
|
||||
|
||||
|
||||
// Bounding box coordinate storage.
|
||||
enum
|
||||
{
|
||||
BOXTOP,
|
||||
BOXBOTTOM,
|
||||
BOXLEFT,
|
||||
BOXRIGHT
|
||||
}; // bbox coordinates
|
||||
|
||||
// Bounding box functions.
|
||||
void M_ClearBox (fixed_t* box);
|
||||
|
||||
void
|
||||
M_AddToBox
|
||||
( fixed_t* box,
|
||||
fixed_t x,
|
||||
fixed_t y );
|
||||
|
||||
|
||||
#endif
|
||||
89
src/m_cheat.c
Normal file
89
src/m_cheat.c
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Cheat sequence checking.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "m_cheat.h"
|
||||
|
||||
//
|
||||
// CHEAT SEQUENCE PACKAGE
|
||||
//
|
||||
|
||||
//
|
||||
// Called in st_stuff module, which handles the input.
|
||||
// Returns a 1 if the cheat was successful, 0 if failed.
|
||||
//
|
||||
int
|
||||
cht_CheckCheat
|
||||
( cheatseq_t* cht,
|
||||
char key )
|
||||
{
|
||||
// if we make a short sequence on a cheat with parameters, this
|
||||
// will not work in vanilla doom. behave the same.
|
||||
|
||||
if (cht->parameter_chars > 0 && strlen(cht->sequence) < cht->sequence_len)
|
||||
return false;
|
||||
|
||||
if (cht->chars_read < strlen(cht->sequence))
|
||||
{
|
||||
// still reading characters from the cheat code
|
||||
// and verifying. reset back to the beginning
|
||||
// if a key is wrong
|
||||
|
||||
if (key == cht->sequence[cht->chars_read])
|
||||
++cht->chars_read;
|
||||
else
|
||||
cht->chars_read = 0;
|
||||
|
||||
cht->param_chars_read = 0;
|
||||
}
|
||||
else if (cht->param_chars_read < cht->parameter_chars)
|
||||
{
|
||||
// we have passed the end of the cheat sequence and are
|
||||
// entering parameters now
|
||||
|
||||
cht->parameter_buf[cht->param_chars_read] = key;
|
||||
|
||||
++cht->param_chars_read;
|
||||
}
|
||||
|
||||
if (cht->chars_read >= strlen(cht->sequence)
|
||||
&& cht->param_chars_read >= cht->parameter_chars)
|
||||
{
|
||||
cht->chars_read = cht->param_chars_read = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// cheat not matched yet
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
cht_GetParam
|
||||
( cheatseq_t* cht,
|
||||
char* buffer )
|
||||
{
|
||||
memcpy(buffer, cht->parameter_buf, cht->parameter_chars);
|
||||
}
|
||||
|
||||
|
||||
63
src/m_cheat.h
Normal file
63
src/m_cheat.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Cheat code checking.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __M_CHEAT__
|
||||
#define __M_CHEAT__
|
||||
|
||||
#include <stddef.h>
|
||||
//
|
||||
// CHEAT SEQUENCE PACKAGE
|
||||
//
|
||||
|
||||
// declaring a cheat
|
||||
|
||||
#define CHEAT(value, parameters) \
|
||||
{ value, sizeof(value) - 1, parameters, 0, 0, "" }
|
||||
|
||||
#define MAX_CHEAT_LEN 25
|
||||
#define MAX_CHEAT_PARAMS 5
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// settings for this cheat
|
||||
|
||||
char sequence[MAX_CHEAT_LEN];
|
||||
size_t sequence_len;
|
||||
int parameter_chars;
|
||||
|
||||
// state used during the game
|
||||
|
||||
size_t chars_read;
|
||||
int param_chars_read;
|
||||
char parameter_buf[MAX_CHEAT_PARAMS];
|
||||
} cheatseq_t;
|
||||
|
||||
int
|
||||
cht_CheckCheat
|
||||
( cheatseq_t* cht,
|
||||
char key );
|
||||
|
||||
|
||||
void
|
||||
cht_GetParam
|
||||
( cheatseq_t* cht,
|
||||
char* buffer );
|
||||
|
||||
|
||||
#endif
|
||||
2134
src/m_config.c
Normal file
2134
src/m_config.c
Normal file
File diff suppressed because it is too large
Load Diff
41
src/m_config.h
Normal file
41
src/m_config.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Configuration file interface.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __M_CONFIG__
|
||||
#define __M_CONFIG__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
void M_LoadDefaults(void);
|
||||
void M_SaveDefaults(void);
|
||||
void M_SaveDefaultsAlternate(char *main, char *extra);
|
||||
void M_SetConfigDir(char *dir);
|
||||
void M_BindIntVariable(char *name, int *variable);
|
||||
void M_BindFloatVariable(char *name, float *variable);
|
||||
void M_BindStringVariable(char *name, char **variable);
|
||||
boolean M_SetVariable(char *name, char *value);
|
||||
int M_GetIntVariable(char *name);
|
||||
const char *M_GetStringVariable(char *name);
|
||||
float M_GetFloatVariable(char *name);
|
||||
void M_SetConfigFilenames(char *main_config, char *extra_config);
|
||||
char *M_GetSaveGameDir(char *iwadname);
|
||||
|
||||
extern char *configdir;
|
||||
|
||||
#endif
|
||||
397
src/m_controls.c
Normal file
397
src/m_controls.c
Normal file
@@ -0,0 +1,397 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 1993-2008 Raven Software
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include "doomkeys.h"
|
||||
#include "m_config.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
//
|
||||
// Keyboard controls
|
||||
//
|
||||
|
||||
int key_right = KEY_RIGHTARROW;
|
||||
int key_left = KEY_LEFTARROW;
|
||||
|
||||
int key_up = KEY_UPARROW;
|
||||
int key_down = KEY_DOWNARROW;
|
||||
int key_strafeleft = ',';
|
||||
int key_straferight = '.';
|
||||
int key_fire = KEY_RCTRL;
|
||||
int key_use = ' ';
|
||||
int key_strafe = KEY_RALT;
|
||||
int key_speed = KEY_RSHIFT;
|
||||
|
||||
//
|
||||
// Heretic keyboard controls
|
||||
//
|
||||
|
||||
int key_flyup = KEY_PGUP;
|
||||
int key_flydown = KEY_INS;
|
||||
int key_flycenter = KEY_HOME;
|
||||
|
||||
int key_lookup = KEY_PGDN;
|
||||
int key_lookdown = KEY_DEL;
|
||||
int key_lookcenter = KEY_END;
|
||||
|
||||
int key_invleft = '[';
|
||||
int key_invright = ']';
|
||||
int key_useartifact = KEY_ENTER;
|
||||
|
||||
//
|
||||
// Hexen key controls
|
||||
//
|
||||
|
||||
int key_jump = '/';
|
||||
|
||||
int key_arti_all = KEY_BACKSPACE;
|
||||
int key_arti_health = '\\';
|
||||
int key_arti_poisonbag = '0';
|
||||
int key_arti_blastradius = '9';
|
||||
int key_arti_teleport = '8';
|
||||
int key_arti_teleportother = '7';
|
||||
int key_arti_egg = '6';
|
||||
int key_arti_invulnerability = '5';
|
||||
|
||||
//
|
||||
// Strife key controls
|
||||
//
|
||||
// haleyjd 09/01/10
|
||||
//
|
||||
|
||||
// Note: Strife also uses key_invleft, key_invright, key_jump, key_lookup, and
|
||||
// key_lookdown, but with different default values.
|
||||
|
||||
int key_usehealth = 'h';
|
||||
int key_invquery = 'q';
|
||||
int key_mission = 'w';
|
||||
int key_invpop = 'z';
|
||||
int key_invkey = 'k';
|
||||
int key_invhome = KEY_HOME;
|
||||
int key_invend = KEY_END;
|
||||
int key_invuse = KEY_ENTER;
|
||||
int key_invdrop = KEY_BACKSPACE;
|
||||
|
||||
|
||||
//
|
||||
// Mouse controls
|
||||
//
|
||||
|
||||
int mousebfire = 0;
|
||||
int mousebstrafe = 1;
|
||||
int mousebforward = 2;
|
||||
|
||||
int mousebjump = -1;
|
||||
|
||||
int mousebstrafeleft = -1;
|
||||
int mousebstraferight = -1;
|
||||
int mousebbackward = -1;
|
||||
int mousebuse = -1;
|
||||
|
||||
int mousebprevweapon = -1;
|
||||
int mousebnextweapon = -1;
|
||||
|
||||
|
||||
int key_message_refresh = KEY_ENTER;
|
||||
int key_pause = KEY_PAUSE;
|
||||
int key_demo_quit = 'q';
|
||||
int key_spy = KEY_F12;
|
||||
|
||||
// Multiplayer chat keys:
|
||||
|
||||
int key_multi_msg = 't';
|
||||
int key_multi_msgplayer[8];
|
||||
|
||||
// Weapon selection keys:
|
||||
|
||||
int key_weapon1 = '1';
|
||||
int key_weapon2 = '2';
|
||||
int key_weapon3 = '3';
|
||||
int key_weapon4 = '4';
|
||||
int key_weapon5 = '5';
|
||||
int key_weapon6 = '6';
|
||||
int key_weapon7 = '7';
|
||||
int key_weapon8 = '8';
|
||||
int key_prevweapon = 0;
|
||||
int key_nextweapon = 0;
|
||||
|
||||
// Map control keys:
|
||||
|
||||
int key_map_north = KEY_UPARROW;
|
||||
int key_map_south = KEY_DOWNARROW;
|
||||
int key_map_east = KEY_RIGHTARROW;
|
||||
int key_map_west = KEY_LEFTARROW;
|
||||
int key_map_zoomin = '=';
|
||||
int key_map_zoomout = '-';
|
||||
int key_map_toggle = KEY_TAB;
|
||||
int key_map_maxzoom = '0';
|
||||
int key_map_follow = 'f';
|
||||
int key_map_grid = 'g';
|
||||
int key_map_mark = 'm';
|
||||
int key_map_clearmark = 'c';
|
||||
|
||||
// menu keys:
|
||||
|
||||
int key_menu_activate = KEY_ESCAPE;
|
||||
int key_menu_up = KEY_UPARROW;
|
||||
int key_menu_down = KEY_DOWNARROW;
|
||||
int key_menu_left = KEY_LEFTARROW;
|
||||
int key_menu_right = KEY_RIGHTARROW;
|
||||
int key_menu_back = KEY_BACKSPACE;
|
||||
int key_menu_forward = KEY_ENTER;
|
||||
int key_menu_confirm = 'y';
|
||||
int key_menu_abort = 'n';
|
||||
|
||||
int key_menu_help = KEY_F1;
|
||||
int key_menu_save = KEY_F2;
|
||||
int key_menu_load = KEY_F3;
|
||||
int key_menu_volume = KEY_F4;
|
||||
int key_menu_detail = KEY_F5;
|
||||
int key_menu_qsave = KEY_F6;
|
||||
int key_menu_endgame = KEY_F7;
|
||||
int key_menu_messages = KEY_F8;
|
||||
int key_menu_qload = KEY_F9;
|
||||
int key_menu_quit = KEY_F10;
|
||||
int key_menu_gamma = KEY_F11;
|
||||
|
||||
int key_menu_incscreen = KEY_EQUALS;
|
||||
int key_menu_decscreen = KEY_MINUS;
|
||||
int key_menu_screenshot = 0;
|
||||
|
||||
//
|
||||
// Joystick controls
|
||||
//
|
||||
|
||||
int joybfire = 0;
|
||||
int joybstrafe = 1;
|
||||
int joybuse = 3;
|
||||
int joybspeed = 2;
|
||||
|
||||
int joybstrafeleft = -1;
|
||||
int joybstraferight = -1;
|
||||
|
||||
int joybjump = -1;
|
||||
|
||||
int joybprevweapon = -1;
|
||||
int joybnextweapon = -1;
|
||||
|
||||
int joybmenu = -1;
|
||||
int joybautomap = -1;
|
||||
|
||||
// Control whether if a mouse button is double clicked, it acts like
|
||||
// "use" has been pressed
|
||||
|
||||
int dclick_use = 1;
|
||||
|
||||
//
|
||||
// Bind all of the common controls used by Doom and all other games.
|
||||
//
|
||||
|
||||
void M_BindBaseControls(void)
|
||||
{
|
||||
M_BindIntVariable("key_right", &key_right);
|
||||
M_BindIntVariable("key_left", &key_left);
|
||||
M_BindIntVariable("key_up", &key_up);
|
||||
M_BindIntVariable("key_down", &key_down);
|
||||
M_BindIntVariable("key_strafeleft", &key_strafeleft);
|
||||
M_BindIntVariable("key_straferight", &key_straferight);
|
||||
M_BindIntVariable("key_fire", &key_fire);
|
||||
M_BindIntVariable("key_use", &key_use);
|
||||
M_BindIntVariable("key_strafe", &key_strafe);
|
||||
M_BindIntVariable("key_speed", &key_speed);
|
||||
|
||||
M_BindIntVariable("mouseb_fire", &mousebfire);
|
||||
M_BindIntVariable("mouseb_strafe", &mousebstrafe);
|
||||
M_BindIntVariable("mouseb_forward", &mousebforward);
|
||||
|
||||
M_BindIntVariable("joyb_fire", &joybfire);
|
||||
M_BindIntVariable("joyb_strafe", &joybstrafe);
|
||||
M_BindIntVariable("joyb_use", &joybuse);
|
||||
M_BindIntVariable("joyb_speed", &joybspeed);
|
||||
|
||||
M_BindIntVariable("joyb_menu_activate", &joybmenu);
|
||||
M_BindIntVariable("joyb_toggle_automap", &joybautomap);
|
||||
|
||||
// Extra controls that are not in the Vanilla versions:
|
||||
|
||||
M_BindIntVariable("joyb_strafeleft", &joybstrafeleft);
|
||||
M_BindIntVariable("joyb_straferight", &joybstraferight);
|
||||
M_BindIntVariable("mouseb_strafeleft", &mousebstrafeleft);
|
||||
M_BindIntVariable("mouseb_straferight", &mousebstraferight);
|
||||
M_BindIntVariable("mouseb_use", &mousebuse);
|
||||
M_BindIntVariable("mouseb_backward", &mousebbackward);
|
||||
M_BindIntVariable("dclick_use", &dclick_use);
|
||||
M_BindIntVariable("key_pause", &key_pause);
|
||||
M_BindIntVariable("key_message_refresh", &key_message_refresh);
|
||||
}
|
||||
|
||||
void M_BindHereticControls(void)
|
||||
{
|
||||
M_BindIntVariable("key_flyup", &key_flyup);
|
||||
M_BindIntVariable("key_flydown", &key_flydown);
|
||||
M_BindIntVariable("key_flycenter", &key_flycenter);
|
||||
|
||||
M_BindIntVariable("key_lookup", &key_lookup);
|
||||
M_BindIntVariable("key_lookdown", &key_lookdown);
|
||||
M_BindIntVariable("key_lookcenter", &key_lookcenter);
|
||||
|
||||
M_BindIntVariable("key_invleft", &key_invleft);
|
||||
M_BindIntVariable("key_invright", &key_invright);
|
||||
M_BindIntVariable("key_useartifact", &key_useartifact);
|
||||
}
|
||||
|
||||
void M_BindHexenControls(void)
|
||||
{
|
||||
M_BindIntVariable("key_jump", &key_jump);
|
||||
M_BindIntVariable("mouseb_jump", &mousebjump);
|
||||
M_BindIntVariable("joyb_jump", &joybjump);
|
||||
|
||||
M_BindIntVariable("key_arti_all", &key_arti_all);
|
||||
M_BindIntVariable("key_arti_health", &key_arti_health);
|
||||
M_BindIntVariable("key_arti_poisonbag", &key_arti_poisonbag);
|
||||
M_BindIntVariable("key_arti_blastradius", &key_arti_blastradius);
|
||||
M_BindIntVariable("key_arti_teleport", &key_arti_teleport);
|
||||
M_BindIntVariable("key_arti_teleportother", &key_arti_teleportother);
|
||||
M_BindIntVariable("key_arti_egg", &key_arti_egg);
|
||||
M_BindIntVariable("key_arti_invulnerability", &key_arti_invulnerability);
|
||||
}
|
||||
|
||||
void M_BindStrifeControls(void)
|
||||
{
|
||||
// These are shared with all games, but have different defaults:
|
||||
key_message_refresh = '/';
|
||||
|
||||
// These keys are shared with Heretic/Hexen but have different defaults:
|
||||
key_jump = 'a';
|
||||
key_lookup = KEY_PGUP;
|
||||
key_lookdown = KEY_PGDN;
|
||||
key_invleft = KEY_INS;
|
||||
key_invright = KEY_DEL;
|
||||
|
||||
M_BindIntVariable("key_jump", &key_jump);
|
||||
M_BindIntVariable("key_lookUp", &key_lookup);
|
||||
M_BindIntVariable("key_lookDown", &key_lookdown);
|
||||
M_BindIntVariable("key_invLeft", &key_invleft);
|
||||
M_BindIntVariable("key_invRight", &key_invright);
|
||||
|
||||
// Custom Strife-only Keys:
|
||||
M_BindIntVariable("key_useHealth", &key_usehealth);
|
||||
M_BindIntVariable("key_invquery", &key_invquery);
|
||||
M_BindIntVariable("key_mission", &key_mission);
|
||||
M_BindIntVariable("key_invPop", &key_invpop);
|
||||
M_BindIntVariable("key_invKey", &key_invkey);
|
||||
M_BindIntVariable("key_invHome", &key_invhome);
|
||||
M_BindIntVariable("key_invEnd", &key_invend);
|
||||
M_BindIntVariable("key_invUse", &key_invuse);
|
||||
M_BindIntVariable("key_invDrop", &key_invdrop);
|
||||
|
||||
// Strife also supports jump on mouse and joystick, and in the exact same
|
||||
// manner as Hexen!
|
||||
M_BindIntVariable("mouseb_jump", &mousebjump);
|
||||
M_BindIntVariable("joyb_jump", &joybjump);
|
||||
}
|
||||
|
||||
void M_BindWeaponControls(void)
|
||||
{
|
||||
M_BindIntVariable("key_weapon1", &key_weapon1);
|
||||
M_BindIntVariable("key_weapon2", &key_weapon2);
|
||||
M_BindIntVariable("key_weapon3", &key_weapon3);
|
||||
M_BindIntVariable("key_weapon4", &key_weapon4);
|
||||
M_BindIntVariable("key_weapon5", &key_weapon5);
|
||||
M_BindIntVariable("key_weapon6", &key_weapon6);
|
||||
M_BindIntVariable("key_weapon7", &key_weapon7);
|
||||
M_BindIntVariable("key_weapon8", &key_weapon8);
|
||||
|
||||
M_BindIntVariable("key_prevweapon", &key_prevweapon);
|
||||
M_BindIntVariable("key_nextweapon", &key_nextweapon);
|
||||
|
||||
M_BindIntVariable("joyb_prevweapon", &joybprevweapon);
|
||||
M_BindIntVariable("joyb_nextweapon", &joybnextweapon);
|
||||
|
||||
M_BindIntVariable("mouseb_prevweapon", &mousebprevweapon);
|
||||
M_BindIntVariable("mouseb_nextweapon", &mousebnextweapon);
|
||||
}
|
||||
|
||||
void M_BindMapControls(void)
|
||||
{
|
||||
M_BindIntVariable("key_map_north", &key_map_north);
|
||||
M_BindIntVariable("key_map_south", &key_map_south);
|
||||
M_BindIntVariable("key_map_east", &key_map_east);
|
||||
M_BindIntVariable("key_map_west", &key_map_west);
|
||||
M_BindIntVariable("key_map_zoomin", &key_map_zoomin);
|
||||
M_BindIntVariable("key_map_zoomout", &key_map_zoomout);
|
||||
M_BindIntVariable("key_map_toggle", &key_map_toggle);
|
||||
M_BindIntVariable("key_map_maxzoom", &key_map_maxzoom);
|
||||
M_BindIntVariable("key_map_follow", &key_map_follow);
|
||||
M_BindIntVariable("key_map_grid", &key_map_grid);
|
||||
M_BindIntVariable("key_map_mark", &key_map_mark);
|
||||
M_BindIntVariable("key_map_clearmark", &key_map_clearmark);
|
||||
}
|
||||
|
||||
void M_BindMenuControls(void)
|
||||
{
|
||||
M_BindIntVariable("key_menu_activate", &key_menu_activate);
|
||||
M_BindIntVariable("key_menu_up", &key_menu_up);
|
||||
M_BindIntVariable("key_menu_down", &key_menu_down);
|
||||
M_BindIntVariable("key_menu_left", &key_menu_left);
|
||||
M_BindIntVariable("key_menu_right", &key_menu_right);
|
||||
M_BindIntVariable("key_menu_back", &key_menu_back);
|
||||
M_BindIntVariable("key_menu_forward", &key_menu_forward);
|
||||
M_BindIntVariable("key_menu_confirm", &key_menu_confirm);
|
||||
M_BindIntVariable("key_menu_abort", &key_menu_abort);
|
||||
|
||||
M_BindIntVariable("key_menu_help", &key_menu_help);
|
||||
M_BindIntVariable("key_menu_save", &key_menu_save);
|
||||
M_BindIntVariable("key_menu_load", &key_menu_load);
|
||||
M_BindIntVariable("key_menu_volume", &key_menu_volume);
|
||||
M_BindIntVariable("key_menu_detail", &key_menu_detail);
|
||||
M_BindIntVariable("key_menu_qsave", &key_menu_qsave);
|
||||
M_BindIntVariable("key_menu_endgame", &key_menu_endgame);
|
||||
M_BindIntVariable("key_menu_messages", &key_menu_messages);
|
||||
M_BindIntVariable("key_menu_qload", &key_menu_qload);
|
||||
M_BindIntVariable("key_menu_quit", &key_menu_quit);
|
||||
M_BindIntVariable("key_menu_gamma", &key_menu_gamma);
|
||||
|
||||
M_BindIntVariable("key_menu_incscreen", &key_menu_incscreen);
|
||||
M_BindIntVariable("key_menu_decscreen", &key_menu_decscreen);
|
||||
M_BindIntVariable("key_menu_screenshot",&key_menu_screenshot);
|
||||
M_BindIntVariable("key_demo_quit", &key_demo_quit);
|
||||
M_BindIntVariable("key_spy", &key_spy);
|
||||
}
|
||||
|
||||
void M_BindChatControls(unsigned int num_players)
|
||||
{
|
||||
char name[32]; // haleyjd: 20 not large enough - Thank you, come again!
|
||||
unsigned int i; // haleyjd: signedness conflict
|
||||
|
||||
M_BindIntVariable("key_multi_msg", &key_multi_msg);
|
||||
|
||||
for (i=0; i<num_players; ++i)
|
||||
{
|
||||
M_snprintf(name, sizeof(name), "key_multi_msgplayer%i", i + 1);
|
||||
M_BindIntVariable(name, &key_multi_msgplayer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Apply custom patches to the default values depending on the
|
||||
// platform we are running on.
|
||||
//
|
||||
|
||||
void M_ApplyPlatformDefaults(void)
|
||||
{
|
||||
// no-op. Add your platform-specific patches here.
|
||||
}
|
||||
|
||||
169
src/m_controls.h
Normal file
169
src/m_controls.h
Normal file
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 1993-2008 Raven Software
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef __M_CONTROLS_H__
|
||||
#define __M_CONTROLS_H__
|
||||
|
||||
extern int key_right;
|
||||
extern int key_left;
|
||||
|
||||
extern int key_up;
|
||||
extern int key_down;
|
||||
extern int key_strafeleft;
|
||||
extern int key_straferight;
|
||||
extern int key_fire;
|
||||
extern int key_use;
|
||||
extern int key_strafe;
|
||||
extern int key_speed;
|
||||
|
||||
extern int key_jump;
|
||||
|
||||
extern int key_flyup;
|
||||
extern int key_flydown;
|
||||
extern int key_flycenter;
|
||||
extern int key_lookup;
|
||||
extern int key_lookdown;
|
||||
extern int key_lookcenter;
|
||||
extern int key_invleft;
|
||||
extern int key_invright;
|
||||
extern int key_useartifact;
|
||||
|
||||
// villsa [STRIFE] strife keys
|
||||
extern int key_usehealth;
|
||||
extern int key_invquery;
|
||||
extern int key_mission;
|
||||
extern int key_invpop;
|
||||
extern int key_invkey;
|
||||
extern int key_invhome;
|
||||
extern int key_invend;
|
||||
extern int key_invuse;
|
||||
extern int key_invdrop;
|
||||
|
||||
extern int key_message_refresh;
|
||||
extern int key_pause;
|
||||
|
||||
extern int key_multi_msg;
|
||||
extern int key_multi_msgplayer[8];
|
||||
|
||||
extern int key_weapon1;
|
||||
extern int key_weapon2;
|
||||
extern int key_weapon3;
|
||||
extern int key_weapon4;
|
||||
extern int key_weapon5;
|
||||
extern int key_weapon6;
|
||||
extern int key_weapon7;
|
||||
extern int key_weapon8;
|
||||
|
||||
extern int key_arti_all;
|
||||
extern int key_arti_health;
|
||||
extern int key_arti_poisonbag;
|
||||
extern int key_arti_blastradius;
|
||||
extern int key_arti_teleport;
|
||||
extern int key_arti_teleportother;
|
||||
extern int key_arti_egg;
|
||||
extern int key_arti_invulnerability;
|
||||
|
||||
extern int key_demo_quit;
|
||||
extern int key_spy;
|
||||
extern int key_prevweapon;
|
||||
extern int key_nextweapon;
|
||||
|
||||
extern int key_map_north;
|
||||
extern int key_map_south;
|
||||
extern int key_map_east;
|
||||
extern int key_map_west;
|
||||
extern int key_map_zoomin;
|
||||
extern int key_map_zoomout;
|
||||
extern int key_map_toggle;
|
||||
extern int key_map_maxzoom;
|
||||
extern int key_map_follow;
|
||||
extern int key_map_grid;
|
||||
extern int key_map_mark;
|
||||
extern int key_map_clearmark;
|
||||
|
||||
// menu keys:
|
||||
|
||||
extern int key_menu_activate;
|
||||
extern int key_menu_up;
|
||||
extern int key_menu_down;
|
||||
extern int key_menu_left;
|
||||
extern int key_menu_right;
|
||||
extern int key_menu_back;
|
||||
extern int key_menu_forward;
|
||||
extern int key_menu_confirm;
|
||||
extern int key_menu_abort;
|
||||
|
||||
extern int key_menu_help;
|
||||
extern int key_menu_save;
|
||||
extern int key_menu_load;
|
||||
extern int key_menu_volume;
|
||||
extern int key_menu_detail;
|
||||
extern int key_menu_qsave;
|
||||
extern int key_menu_endgame;
|
||||
extern int key_menu_messages;
|
||||
extern int key_menu_qload;
|
||||
extern int key_menu_quit;
|
||||
extern int key_menu_gamma;
|
||||
|
||||
extern int key_menu_incscreen;
|
||||
extern int key_menu_decscreen;
|
||||
extern int key_menu_screenshot;
|
||||
|
||||
extern int mousebfire;
|
||||
extern int mousebstrafe;
|
||||
extern int mousebforward;
|
||||
|
||||
extern int mousebjump;
|
||||
|
||||
extern int mousebstrafeleft;
|
||||
extern int mousebstraferight;
|
||||
extern int mousebbackward;
|
||||
extern int mousebuse;
|
||||
|
||||
extern int mousebprevweapon;
|
||||
extern int mousebnextweapon;
|
||||
|
||||
extern int joybfire;
|
||||
extern int joybstrafe;
|
||||
extern int joybuse;
|
||||
extern int joybspeed;
|
||||
|
||||
extern int joybjump;
|
||||
|
||||
extern int joybstrafeleft;
|
||||
extern int joybstraferight;
|
||||
|
||||
extern int joybprevweapon;
|
||||
extern int joybnextweapon;
|
||||
|
||||
extern int joybmenu;
|
||||
extern int joybautomap;
|
||||
|
||||
extern int dclick_use;
|
||||
|
||||
void M_BindBaseControls(void);
|
||||
void M_BindHereticControls(void);
|
||||
void M_BindHexenControls(void);
|
||||
void M_BindStrifeControls(void);
|
||||
void M_BindWeaponControls(void);
|
||||
void M_BindMapControls(void);
|
||||
void M_BindMenuControls(void);
|
||||
void M_BindChatControls(unsigned int num_players);
|
||||
|
||||
void M_ApplyPlatformDefaults(void);
|
||||
|
||||
#endif /* #ifndef __M_CONTROLS_H__ */
|
||||
|
||||
61
src/m_fixed.c
Normal file
61
src/m_fixed.c
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Fixed point implementation.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "m_fixed.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// Fixme. __USE_C_FIXED__ or something.
|
||||
|
||||
fixed_t
|
||||
FixedMul
|
||||
( fixed_t a,
|
||||
fixed_t b )
|
||||
{
|
||||
return ((int64_t) a * (int64_t) b) >> FRACBITS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FixedDiv, C version.
|
||||
//
|
||||
|
||||
fixed_t FixedDiv(fixed_t a, fixed_t b)
|
||||
{
|
||||
if ((abs(a) >> 14) >= abs(b))
|
||||
{
|
||||
return (a^b) < 0 ? INT_MIN : INT_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t result;
|
||||
|
||||
result = ((int64_t) a << FRACBITS) / b;
|
||||
|
||||
return (fixed_t) result;
|
||||
}
|
||||
}
|
||||
|
||||
39
src/m_fixed.h
Normal file
39
src/m_fixed.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Fixed point arithemtics, implementation.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __M_FIXED__
|
||||
#define __M_FIXED__
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Fixed point, 32bit as 16.16.
|
||||
//
|
||||
#define FRACBITS 16
|
||||
#define FRACUNIT (1<<FRACBITS)
|
||||
|
||||
typedef int fixed_t;
|
||||
|
||||
fixed_t FixedMul (fixed_t a, fixed_t b);
|
||||
fixed_t FixedDiv (fixed_t a, fixed_t b);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
1608
src/m_menu.c
Normal file
1608
src/m_menu.c
Normal file
File diff suppressed because it is too large
Load Diff
54
src/m_menu.h
Normal file
54
src/m_menu.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Menu widget stuff, episode selection and such.
|
||||
//
|
||||
|
||||
#ifndef __M_MENU__
|
||||
#define __M_MENU__
|
||||
|
||||
#include "d_event.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
//
|
||||
// MENUS
|
||||
//
|
||||
// Called by main loop,
|
||||
// saves config file and calls I_Quit when user exits.
|
||||
// Even when the menu is not displayed,
|
||||
// this can resize the view and change game parameters.
|
||||
// Does all the real work of the menu interaction.
|
||||
boolean M_Responder(event_t *ev);
|
||||
|
||||
// Called by main loop,
|
||||
// only used for menu (skull cursor) animation.
|
||||
void M_Ticker(void);
|
||||
|
||||
// Called by main loop,
|
||||
// draws the menus directly into the screen buffer.
|
||||
void M_Drawer(void);
|
||||
|
||||
// Called by D_DoomMain,
|
||||
// loads the config file.
|
||||
void M_Init(void);
|
||||
|
||||
// Called by intro code to force menu up upon a keypress,
|
||||
// does nothing if menu is already up.
|
||||
void M_StartControlPanel(void);
|
||||
|
||||
extern int detailLevel;
|
||||
extern int screenblocks;
|
||||
|
||||
#endif
|
||||
562
src/m_misc.c
Normal file
562
src/m_misc.c
Normal file
@@ -0,0 +1,562 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 1993-2008 Raven Software
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Miscellaneous.
|
||||
//
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
#include "m_misc.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
//
|
||||
// Create a directory
|
||||
//
|
||||
|
||||
void M_MakeDirectory(char *path)
|
||||
{
|
||||
mkdir(path, 0755);
|
||||
}
|
||||
|
||||
// Check if a file exists
|
||||
|
||||
boolean M_FileExists(char *filename)
|
||||
{
|
||||
FILE *fstream;
|
||||
|
||||
fstream = fopen(filename, "r");
|
||||
|
||||
if (fstream != NULL)
|
||||
{
|
||||
fclose(fstream);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can't open because the file is a directory, the
|
||||
// "file" exists at least!
|
||||
|
||||
return errno == EISDIR;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a file exists by probing for common case variation of its filename.
|
||||
// Returns a newly allocated string that the caller is responsible for freeing.
|
||||
|
||||
char *M_FileCaseExists(char *path)
|
||||
{
|
||||
char *path_dup, *filename, *ext;
|
||||
|
||||
path_dup = M_StringDuplicate(path);
|
||||
|
||||
// 0: actual path
|
||||
if (M_FileExists(path_dup))
|
||||
{
|
||||
return path_dup;
|
||||
}
|
||||
|
||||
filename = strrchr(path_dup, DIR_SEPARATOR);
|
||||
if (filename != NULL)
|
||||
{
|
||||
filename++;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = path_dup;
|
||||
}
|
||||
|
||||
// 1: lowercase filename, e.g. doom2.wad
|
||||
M_ForceLowercase(filename);
|
||||
|
||||
if (M_FileExists(path_dup))
|
||||
{
|
||||
return path_dup;
|
||||
}
|
||||
|
||||
// 2: uppercase filename, e.g. DOOM2.WAD
|
||||
M_ForceUppercase(filename);
|
||||
|
||||
if (M_FileExists(path_dup))
|
||||
{
|
||||
return path_dup;
|
||||
}
|
||||
|
||||
// 3. uppercase basename with lowercase extension, e.g. DOOM2.wad
|
||||
ext = strrchr(path_dup, '.');
|
||||
if (ext != NULL && ext > filename)
|
||||
{
|
||||
M_ForceLowercase(ext + 1);
|
||||
|
||||
if (M_FileExists(path_dup))
|
||||
{
|
||||
return path_dup;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. lowercase filename with uppercase first letter, e.g. Doom2.wad
|
||||
if (strlen(filename) > 1)
|
||||
{
|
||||
M_ForceLowercase(filename + 1);
|
||||
|
||||
if (M_FileExists(path_dup))
|
||||
{
|
||||
return path_dup;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. no luck
|
||||
free(path_dup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the length of an open file.
|
||||
//
|
||||
|
||||
long M_FileLength(FILE *handle)
|
||||
{
|
||||
long savedpos;
|
||||
long length;
|
||||
|
||||
// save the current position in the file
|
||||
savedpos = ftell(handle);
|
||||
|
||||
// jump to the end and find the length
|
||||
fseek(handle, 0, SEEK_END);
|
||||
length = ftell(handle);
|
||||
|
||||
// go back to the old location
|
||||
fseek(handle, savedpos, SEEK_SET);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
//
|
||||
// M_WriteFile
|
||||
//
|
||||
|
||||
boolean M_WriteFile(char *name, void *source, int length)
|
||||
{
|
||||
FILE *handle;
|
||||
int count;
|
||||
|
||||
handle = fopen(name, "wb");
|
||||
|
||||
if (handle == NULL)
|
||||
return false;
|
||||
|
||||
count = fwrite(source, 1, length, handle);
|
||||
fclose(handle);
|
||||
|
||||
if (count < length)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// M_ReadFile
|
||||
//
|
||||
|
||||
int M_ReadFile(char *name, byte **buffer)
|
||||
{
|
||||
FILE *handle;
|
||||
int count, length;
|
||||
byte *buf;
|
||||
|
||||
handle = fopen(name, "rb");
|
||||
if (handle == NULL)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
|
||||
// find the size of the file by seeking to the end and
|
||||
// reading the current position
|
||||
|
||||
length = M_FileLength(handle);
|
||||
|
||||
buf = Z_Malloc (length, PU_STATIC, NULL);
|
||||
count = fread(buf, 1, length, handle);
|
||||
fclose (handle);
|
||||
|
||||
if (count < length)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
|
||||
*buffer = buf;
|
||||
return length;
|
||||
}
|
||||
|
||||
// Returns the path to a temporary file of the given name, stored
|
||||
// inside the system temporary directory.
|
||||
//
|
||||
// The returned value must be freed with Z_Free after use.
|
||||
|
||||
char *M_TempFile(char *s)
|
||||
{
|
||||
char *tempdir;
|
||||
|
||||
tempdir = "/tmp";
|
||||
|
||||
return M_StringJoin(tempdir, DIR_SEPARATOR_S, s, NULL);
|
||||
}
|
||||
|
||||
boolean M_StrToInt(const char *str, int *result)
|
||||
{
|
||||
return sscanf(str, " 0x%x", result) == 1
|
||||
|| sscanf(str, " 0X%x", result) == 1
|
||||
|| sscanf(str, " 0%o", result) == 1
|
||||
|| sscanf(str, " %d", result) == 1;
|
||||
}
|
||||
|
||||
void M_ExtractFileBase(char *path, char *dest)
|
||||
{
|
||||
char *src;
|
||||
char *filename;
|
||||
int length;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
// back up until a \ or the start
|
||||
while (src != path && *(src - 1) != DIR_SEPARATOR)
|
||||
{
|
||||
src--;
|
||||
}
|
||||
|
||||
filename = src;
|
||||
|
||||
// Copy up to eight characters
|
||||
// Note: Vanilla Doom exits with an error if a filename is specified
|
||||
// with a base of more than eight characters. To remove the 8.3
|
||||
// filename limit, instead we simply truncate the name.
|
||||
|
||||
length = 0;
|
||||
memset(dest, 0, 8);
|
||||
|
||||
while (*src != '\0' && *src != '.')
|
||||
{
|
||||
if (length >= 8)
|
||||
{
|
||||
printf("Warning: Truncated '%s' lump name to '%.8s'.\n",
|
||||
filename, dest);
|
||||
break;
|
||||
}
|
||||
|
||||
dest[length++] = toupper((int)*src++);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC M_ForceUppercase
|
||||
//
|
||||
// Change string to uppercase.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void M_ForceUppercase(char *text)
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = text; *p != '\0'; ++p)
|
||||
{
|
||||
*p = toupper(*p);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC M_ForceLowercase
|
||||
//
|
||||
// Change string to lowercase.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void M_ForceLowercase(char *text)
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = text; *p != '\0'; ++p)
|
||||
{
|
||||
*p = tolower(*p);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// M_StrCaseStr
|
||||
//
|
||||
// Case-insensitive version of strstr()
|
||||
//
|
||||
|
||||
char *M_StrCaseStr(char *haystack, char *needle)
|
||||
{
|
||||
unsigned int haystack_len;
|
||||
unsigned int needle_len;
|
||||
unsigned int len;
|
||||
unsigned int i;
|
||||
|
||||
haystack_len = strlen(haystack);
|
||||
needle_len = strlen(needle);
|
||||
|
||||
if (haystack_len < needle_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = haystack_len - needle_len;
|
||||
|
||||
for (i = 0; i <= len; ++i)
|
||||
{
|
||||
if (!strncasecmp(haystack + i, needle, needle_len))
|
||||
{
|
||||
return haystack + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Safe version of strdup() that checks the string was successfully
|
||||
// allocated.
|
||||
//
|
||||
|
||||
char *M_StringDuplicate(const char *orig)
|
||||
{
|
||||
char *result;
|
||||
|
||||
result = strdup(orig);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
I_Error("Failed to duplicate string (length %i)\n",
|
||||
strlen(orig));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// String replace function.
|
||||
//
|
||||
|
||||
char *M_StringReplace(const char *haystack, const char *needle,
|
||||
const char *replacement)
|
||||
{
|
||||
char *result, *dst;
|
||||
const char *p;
|
||||
size_t needle_len = strlen(needle);
|
||||
size_t result_len, dst_len;
|
||||
|
||||
// Iterate through occurrences of 'needle' and calculate the size of
|
||||
// the new string.
|
||||
result_len = strlen(haystack) + 1;
|
||||
p = haystack;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
p = strstr(p, needle);
|
||||
if (p == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p += needle_len;
|
||||
result_len += strlen(replacement) - needle_len;
|
||||
}
|
||||
|
||||
// Construct new string.
|
||||
|
||||
result = malloc(result_len);
|
||||
if (result == NULL)
|
||||
{
|
||||
I_Error("M_StringReplace: Failed to allocate new string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dst = result; dst_len = result_len;
|
||||
p = haystack;
|
||||
|
||||
while (*p != '\0')
|
||||
{
|
||||
if (!strncmp(p, needle, needle_len))
|
||||
{
|
||||
M_StringCopy(dst, replacement, dst_len);
|
||||
p += needle_len;
|
||||
dst += strlen(replacement);
|
||||
dst_len -= strlen(replacement);
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst = *p;
|
||||
++dst; --dst_len;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Safe string copy function that works like OpenBSD's strlcpy().
|
||||
// Returns true if the string was not truncated.
|
||||
|
||||
boolean M_StringCopy(char *dest, const char *src, size_t dest_size)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (dest_size >= 1)
|
||||
{
|
||||
dest[dest_size - 1] = '\0';
|
||||
strncpy(dest, src, dest_size - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
len = strlen(dest);
|
||||
return src[len] == '\0';
|
||||
}
|
||||
|
||||
// Safe string concat function that works like OpenBSD's strlcat().
|
||||
// Returns true if string not truncated.
|
||||
|
||||
boolean M_StringConcat(char *dest, const char *src, size_t dest_size)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
offset = strlen(dest);
|
||||
if (offset > dest_size)
|
||||
{
|
||||
offset = dest_size;
|
||||
}
|
||||
|
||||
return M_StringCopy(dest + offset, src, dest_size - offset);
|
||||
}
|
||||
|
||||
// Returns true if 's' begins with the specified prefix.
|
||||
|
||||
boolean M_StringStartsWith(const char *s, const char *prefix)
|
||||
{
|
||||
return strlen(s) > strlen(prefix)
|
||||
&& strncmp(s, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
// Returns true if 's' ends with the specified suffix.
|
||||
|
||||
boolean M_StringEndsWith(const char *s, const char *suffix)
|
||||
{
|
||||
return strlen(s) >= strlen(suffix)
|
||||
&& strcmp(s + strlen(s) - strlen(suffix), suffix) == 0;
|
||||
}
|
||||
|
||||
// Return a newly-malloced string with all the strings given as arguments
|
||||
// concatenated together.
|
||||
|
||||
char *M_StringJoin(const char *s, ...)
|
||||
{
|
||||
char *result;
|
||||
const char *v;
|
||||
va_list args;
|
||||
size_t result_len;
|
||||
|
||||
result_len = strlen(s) + 1;
|
||||
|
||||
va_start(args, s);
|
||||
for (;;)
|
||||
{
|
||||
v = va_arg(args, const char *);
|
||||
if (v == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result_len += strlen(v);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
result = malloc(result_len);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
I_Error("M_StringJoin: Failed to allocate new string.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
M_StringCopy(result, s, result_len);
|
||||
|
||||
va_start(args, s);
|
||||
for (;;)
|
||||
{
|
||||
v = va_arg(args, const char *);
|
||||
if (v == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
M_StringConcat(result, v, result_len);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Safe, portable vsnprintf().
|
||||
int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (buf_len < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Windows (and other OSes?) has a vsnprintf() that doesn't always
|
||||
// append a trailing \0. So we must do it, and write into a buffer
|
||||
// that is one byte shorter; otherwise this function is unsafe.
|
||||
result = vsnprintf(buf, buf_len, s, args);
|
||||
|
||||
// If truncated, change the final char in the buffer to a \0.
|
||||
// A negative result indicates a truncated buffer on Windows.
|
||||
if (result < 0 || result >= buf_len)
|
||||
{
|
||||
buf[buf_len - 1] = '\0';
|
||||
result = buf_len - 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Safe, portable snprintf().
|
||||
int M_snprintf(char *buf, size_t buf_len, const char *s, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
va_start(args, s);
|
||||
result = M_vsnprintf(buf, buf_len, s, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
52
src/m_misc.h
Normal file
52
src/m_misc.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Miscellaneous.
|
||||
//
|
||||
|
||||
|
||||
#ifndef __M_MISC__
|
||||
#define __M_MISC__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
boolean M_WriteFile(char *name, void *source, int length);
|
||||
int M_ReadFile(char *name, byte **buffer);
|
||||
void M_MakeDirectory(char *dir);
|
||||
char *M_TempFile(char *s);
|
||||
boolean M_FileExists(char *file);
|
||||
char *M_FileCaseExists(char *file);
|
||||
long M_FileLength(FILE *handle);
|
||||
boolean M_StrToInt(const char *str, int *result);
|
||||
void M_ExtractFileBase(char *path, char *dest);
|
||||
void M_ForceUppercase(char *text);
|
||||
void M_ForceLowercase(char *text);
|
||||
char *M_StrCaseStr(char *haystack, char *needle);
|
||||
char *M_StringDuplicate(const char *orig);
|
||||
boolean M_StringCopy(char *dest, const char *src, size_t dest_size);
|
||||
boolean M_StringConcat(char *dest, const char *src, size_t dest_size);
|
||||
char *M_StringReplace(const char *haystack, const char *needle,
|
||||
const char *replacement);
|
||||
char *M_StringJoin(const char *s, ...);
|
||||
boolean M_StringStartsWith(const char *s, const char *prefix);
|
||||
boolean M_StringEndsWith(const char *s, const char *suffix);
|
||||
int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args);
|
||||
int M_snprintf(char *buf, size_t buf_len, const char *s, ...);
|
||||
|
||||
#endif
|
||||
|
||||
64
src/m_random.c
Normal file
64
src/m_random.c
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Random number LUT.
|
||||
//
|
||||
|
||||
//
|
||||
// M_Random
|
||||
// Returns a 0-255 number
|
||||
//
|
||||
|
||||
static const unsigned char rndtable[256] = {
|
||||
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74,
|
||||
21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, 95, 110,
|
||||
85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, 52, 140, 202,
|
||||
120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, 149, 104, 25, 178,
|
||||
252, 182, 202, 182, 141, 197, 4, 81, 181, 242, 145, 42, 39, 227, 156,
|
||||
198, 225, 193, 219, 93, 122, 175, 249, 0, 175, 143, 70, 239, 46, 246,
|
||||
163, 53, 163, 109, 168, 135, 2, 235, 25, 92, 20, 145, 138, 77, 69,
|
||||
166, 78, 176, 173, 212, 166, 113, 94, 161, 41, 50, 239, 49, 111, 164,
|
||||
70, 60, 2, 37, 171, 75, 136, 156, 11, 56, 42, 146, 138, 229, 73,
|
||||
146, 77, 61, 98, 196, 135, 106, 63, 197, 195, 86, 96, 203, 113, 101,
|
||||
170, 247, 181, 113, 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112,
|
||||
166, 103, 241, 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66,
|
||||
143, 224, 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159,
|
||||
95, 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226,
|
||||
71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, 17,
|
||||
46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 197, 242,
|
||||
98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136, 120, 163, 236,
|
||||
249};
|
||||
|
||||
int rndindex = 0;
|
||||
int prndindex = 0;
|
||||
|
||||
// Which one is deterministic?
|
||||
int P_Random(void) {
|
||||
prndindex = (prndindex + 1) & 0xff;
|
||||
return rndtable[prndindex];
|
||||
}
|
||||
|
||||
int M_Random(void) {
|
||||
rndindex = (rndindex + 1) & 0xff;
|
||||
return rndtable[rndindex];
|
||||
}
|
||||
|
||||
void M_ClearRandom(void) { rndindex = prndindex = 0; }
|
||||
|
||||
// inspired by the same routine in Eternity, thanks haleyjd
|
||||
int P_SubRandom(void) {
|
||||
int r = P_Random();
|
||||
return r - P_Random();
|
||||
}
|
||||
37
src/m_random.h
Normal file
37
src/m_random.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __M_RANDOM__
|
||||
#define __M_RANDOM__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
// Returns a number from 0 to 255,
|
||||
// from a lookup table.
|
||||
int M_Random(void);
|
||||
|
||||
// As M_Random, but used only by the play simulation.
|
||||
int P_Random(void);
|
||||
|
||||
// Fix randoms for demos.
|
||||
void M_ClearRandom(void);
|
||||
|
||||
// Defined version of P_Random() - P_Random()
|
||||
int P_SubRandom(void);
|
||||
|
||||
#endif
|
||||
195
src/memio.c
Normal file
195
src/memio.c
Normal file
@@ -0,0 +1,195 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Emulates the IO functions in C stdio.h reading and writing to
|
||||
// memory.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "memio.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
typedef enum {
|
||||
MODE_READ,
|
||||
MODE_WRITE,
|
||||
} memfile_mode_t;
|
||||
|
||||
struct _MEMFILE {
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
size_t alloced;
|
||||
unsigned int position;
|
||||
memfile_mode_t mode;
|
||||
};
|
||||
|
||||
// Open a memory area for reading
|
||||
|
||||
MEMFILE *mem_fopen_read(void *buf, size_t buflen)
|
||||
{
|
||||
MEMFILE *file;
|
||||
|
||||
file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
|
||||
|
||||
file->buf = (unsigned char *) buf;
|
||||
file->buflen = buflen;
|
||||
file->position = 0;
|
||||
file->mode = MODE_READ;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
// Read bytes
|
||||
|
||||
size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream)
|
||||
{
|
||||
size_t items;
|
||||
|
||||
if (stream->mode != MODE_READ)
|
||||
{
|
||||
printf("not a read stream\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Trying to read more bytes than we have left?
|
||||
|
||||
items = nmemb;
|
||||
|
||||
if (items * size > stream->buflen - stream->position)
|
||||
{
|
||||
items = (stream->buflen - stream->position) / size;
|
||||
}
|
||||
|
||||
// Copy bytes to buffer
|
||||
|
||||
memcpy(buf, stream->buf + stream->position, items * size);
|
||||
|
||||
// Update position
|
||||
|
||||
stream->position += items * size;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
// Open a memory area for writing
|
||||
|
||||
MEMFILE *mem_fopen_write(void)
|
||||
{
|
||||
MEMFILE *file;
|
||||
|
||||
file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
|
||||
|
||||
file->alloced = 1024;
|
||||
file->buf = Z_Malloc(file->alloced, PU_STATIC, 0);
|
||||
file->buflen = 0;
|
||||
file->position = 0;
|
||||
file->mode = MODE_WRITE;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
// Write bytes to stream
|
||||
|
||||
size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (stream->mode != MODE_WRITE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// More bytes than can fit in the buffer?
|
||||
// If so, reallocate bigger.
|
||||
|
||||
bytes = size * nmemb;
|
||||
|
||||
while (bytes > stream->alloced - stream->position)
|
||||
{
|
||||
unsigned char *newbuf;
|
||||
|
||||
newbuf = Z_Malloc(stream->alloced * 2, PU_STATIC, 0);
|
||||
memcpy(newbuf, stream->buf, stream->alloced);
|
||||
Z_Free(stream->buf);
|
||||
stream->buf = newbuf;
|
||||
stream->alloced *= 2;
|
||||
}
|
||||
|
||||
// Copy into buffer
|
||||
|
||||
memcpy(stream->buf + stream->position, ptr, bytes);
|
||||
stream->position += bytes;
|
||||
|
||||
if (stream->position > stream->buflen)
|
||||
stream->buflen = stream->position;
|
||||
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen)
|
||||
{
|
||||
*buf = stream->buf;
|
||||
*buflen = stream->buflen;
|
||||
}
|
||||
|
||||
void mem_fclose(MEMFILE *stream)
|
||||
{
|
||||
if (stream->mode == MODE_WRITE)
|
||||
{
|
||||
Z_Free(stream->buf);
|
||||
}
|
||||
|
||||
Z_Free(stream);
|
||||
}
|
||||
|
||||
long mem_ftell(MEMFILE *stream)
|
||||
{
|
||||
return stream->position;
|
||||
}
|
||||
|
||||
int mem_fseek(MEMFILE *stream, signed long position, mem_rel_t whence)
|
||||
{
|
||||
unsigned int newpos;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case MEM_SEEK_SET:
|
||||
newpos = (int) position;
|
||||
break;
|
||||
|
||||
case MEM_SEEK_CUR:
|
||||
newpos = (int) (stream->position + position);
|
||||
break;
|
||||
|
||||
case MEM_SEEK_END:
|
||||
newpos = (int) (stream->buflen + position);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (newpos < stream->buflen)
|
||||
{
|
||||
stream->position = newpos;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error seeking to %i\n", newpos);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
src/memio.h
Normal file
40
src/memio.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef MEMIO_H
|
||||
#define MEMIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct _MEMFILE MEMFILE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MEM_SEEK_SET,
|
||||
MEM_SEEK_CUR,
|
||||
MEM_SEEK_END,
|
||||
} mem_rel_t;
|
||||
|
||||
MEMFILE *mem_fopen_read(void *buf, size_t buflen);
|
||||
size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream);
|
||||
MEMFILE *mem_fopen_write(void);
|
||||
size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream);
|
||||
void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen);
|
||||
void mem_fclose(MEMFILE *stream);
|
||||
long mem_ftell(MEMFILE *stream);
|
||||
int mem_fseek(MEMFILE *stream, signed long offset, mem_rel_t whence);
|
||||
|
||||
#endif /* #ifndef MEMIO_H */
|
||||
|
||||
819
src/midifile.c
Normal file
819
src/midifile.c
Normal file
@@ -0,0 +1,819 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Reading of MIDI files.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL2/SDL_endian.h"
|
||||
#include "doomtype.h"
|
||||
#include "midifile.h"
|
||||
|
||||
#define HEADER_CHUNK_ID "MThd"
|
||||
#define TRACK_CHUNK_ID "MTrk"
|
||||
#define MAX_BUFFER_SIZE 0x10000
|
||||
|
||||
typedef PACKED_STRUCT (
|
||||
{
|
||||
byte chunk_id[4];
|
||||
unsigned int chunk_size;
|
||||
}) chunk_header_t;
|
||||
|
||||
typedef PACKED_STRUCT (
|
||||
{
|
||||
chunk_header_t chunk_header;
|
||||
unsigned short format_type;
|
||||
unsigned short num_tracks;
|
||||
unsigned short time_division;
|
||||
}) midi_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Length in bytes:
|
||||
|
||||
unsigned int data_len;
|
||||
|
||||
// Events in this track:
|
||||
|
||||
midi_event_t *events;
|
||||
int num_events;
|
||||
} midi_track_t;
|
||||
|
||||
struct midi_track_iter_s
|
||||
{
|
||||
midi_track_t *track;
|
||||
unsigned int position;
|
||||
};
|
||||
|
||||
struct midi_file_s
|
||||
{
|
||||
midi_header_t header;
|
||||
|
||||
// All tracks in this file:
|
||||
midi_track_t *tracks;
|
||||
unsigned int num_tracks;
|
||||
|
||||
// Data buffer used to store data read for SysEx or meta events:
|
||||
byte *buffer;
|
||||
unsigned int buffer_size;
|
||||
};
|
||||
|
||||
// Check the header of a chunk:
|
||||
|
||||
static boolean CheckChunkHeader(chunk_header_t *chunk,
|
||||
char *expected_id)
|
||||
{
|
||||
boolean result;
|
||||
|
||||
result = (memcmp((char *) chunk->chunk_id, expected_id, 4) == 0);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header, "
|
||||
"got '%c%c%c%c'\n",
|
||||
expected_id,
|
||||
chunk->chunk_id[0], chunk->chunk_id[1],
|
||||
chunk->chunk_id[2], chunk->chunk_id[3]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read a single byte. Returns false on error.
|
||||
|
||||
static boolean ReadByte(byte *result, FILE *stream)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = fgetc(stream);
|
||||
|
||||
if (c == EOF)
|
||||
{
|
||||
fprintf(stderr, "ReadByte: Unexpected end of file\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = (byte) c;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Read a variable-length value.
|
||||
|
||||
static boolean ReadVariableLength(unsigned int *result, FILE *stream)
|
||||
{
|
||||
int i;
|
||||
byte b = 0;
|
||||
|
||||
*result = 0;
|
||||
|
||||
for (i=0; i<4; ++i)
|
||||
{
|
||||
if (!ReadByte(&b, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadVariableLength: Error while reading "
|
||||
"variable-length value\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert the bottom seven bits from this byte.
|
||||
|
||||
*result <<= 7;
|
||||
*result |= b & 0x7f;
|
||||
|
||||
// If the top bit is not set, this is the end.
|
||||
|
||||
if ((b & 0x80) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "ReadVariableLength: Variable-length value too "
|
||||
"long: maximum of four bytes\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read a byte sequence into the data buffer.
|
||||
|
||||
static void *ReadByteSequence(unsigned int num_bytes, FILE *stream)
|
||||
{
|
||||
unsigned int i;
|
||||
byte *result;
|
||||
|
||||
// Allocate a buffer. Allocate one extra byte, as malloc(0) is
|
||||
// non-portable.
|
||||
|
||||
result = malloc(num_bytes + 1);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
fprintf(stderr, "ReadByteSequence: Failed to allocate buffer\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the data:
|
||||
|
||||
for (i=0; i<num_bytes; ++i)
|
||||
{
|
||||
if (!ReadByte(&result[i], stream))
|
||||
{
|
||||
fprintf(stderr, "ReadByteSequence: Error while reading byte %u\n",
|
||||
i);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read a MIDI channel event.
|
||||
// two_param indicates that the event type takes two parameters
|
||||
// (three byte) otherwise it is single parameter (two byte)
|
||||
|
||||
static boolean ReadChannelEvent(midi_event_t *event,
|
||||
byte event_type, boolean two_param,
|
||||
FILE *stream)
|
||||
{
|
||||
byte b = 0;
|
||||
|
||||
// Set basics:
|
||||
|
||||
event->event_type = event_type & 0xf0;
|
||||
event->data.channel.channel = event_type & 0x0f;
|
||||
|
||||
// Read parameters:
|
||||
|
||||
if (!ReadByte(&b, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadChannelEvent: Error while reading channel "
|
||||
"event parameters\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
event->data.channel.param1 = b;
|
||||
|
||||
// Second parameter:
|
||||
|
||||
if (two_param)
|
||||
{
|
||||
if (!ReadByte(&b, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadChannelEvent: Error while reading channel "
|
||||
"event parameters\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
event->data.channel.param2 = b;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read sysex event:
|
||||
|
||||
static boolean ReadSysExEvent(midi_event_t *event, int event_type,
|
||||
FILE *stream)
|
||||
{
|
||||
event->event_type = event_type;
|
||||
|
||||
if (!ReadVariableLength(&event->data.sysex.length, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadSysExEvent: Failed to read length of "
|
||||
"SysEx block\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the byte sequence:
|
||||
|
||||
event->data.sysex.data = ReadByteSequence(event->data.sysex.length, stream);
|
||||
|
||||
if (event->data.sysex.data == NULL)
|
||||
{
|
||||
fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read meta event:
|
||||
|
||||
static boolean ReadMetaEvent(midi_event_t *event, FILE *stream)
|
||||
{
|
||||
byte b = 0;
|
||||
|
||||
event->event_type = MIDI_EVENT_META;
|
||||
|
||||
// Read meta event type:
|
||||
|
||||
if (!ReadByte(&b, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadMetaEvent: Failed to read meta event type\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
event->data.meta.type = b;
|
||||
|
||||
// Read length of meta event data:
|
||||
|
||||
if (!ReadVariableLength(&event->data.meta.length, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadSysExEvent: Failed to read length of "
|
||||
"SysEx block\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the byte sequence:
|
||||
|
||||
event->data.meta.data = ReadByteSequence(event->data.meta.length, stream);
|
||||
|
||||
if (event->data.meta.data == NULL)
|
||||
{
|
||||
fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean ReadEvent(midi_event_t *event, unsigned int *last_event_type,
|
||||
FILE *stream)
|
||||
{
|
||||
byte event_type = 0;
|
||||
|
||||
if (!ReadVariableLength(&event->delta_time, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadEvent: Failed to read event timestamp\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadByte(&event_type, stream))
|
||||
{
|
||||
fprintf(stderr, "ReadEvent: Failed to read event type\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All event types have their top bit set. Therefore, if
|
||||
// the top bit is not set, it is because we are using the "same
|
||||
// as previous event type" shortcut to save a byte. Skip back
|
||||
// a byte so that we read this byte again.
|
||||
|
||||
if ((event_type & 0x80) == 0)
|
||||
{
|
||||
event_type = *last_event_type;
|
||||
|
||||
if (fseek(stream, -1, SEEK_CUR) < 0)
|
||||
{
|
||||
fprintf(stderr, "ReadEvent: Unable to seek in stream\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*last_event_type = event_type;
|
||||
}
|
||||
|
||||
// Check event type:
|
||||
|
||||
switch (event_type & 0xf0)
|
||||
{
|
||||
// Two parameter channel events:
|
||||
|
||||
case MIDI_EVENT_NOTE_OFF:
|
||||
case MIDI_EVENT_NOTE_ON:
|
||||
case MIDI_EVENT_AFTERTOUCH:
|
||||
case MIDI_EVENT_CONTROLLER:
|
||||
case MIDI_EVENT_PITCH_BEND:
|
||||
return ReadChannelEvent(event, event_type, true, stream);
|
||||
|
||||
// Single parameter channel events:
|
||||
|
||||
case MIDI_EVENT_PROGRAM_CHANGE:
|
||||
case MIDI_EVENT_CHAN_AFTERTOUCH:
|
||||
return ReadChannelEvent(event, event_type, false, stream);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Specific value?
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
case MIDI_EVENT_SYSEX:
|
||||
case MIDI_EVENT_SYSEX_SPLIT:
|
||||
return ReadSysExEvent(event, event_type, stream);
|
||||
|
||||
case MIDI_EVENT_META:
|
||||
return ReadMetaEvent(event, stream);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "ReadEvent: Unknown MIDI event type: 0x%x\n", event_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Free an event:
|
||||
|
||||
static void FreeEvent(midi_event_t *event)
|
||||
{
|
||||
// Some event types have dynamically allocated buffers assigned
|
||||
// to them that must be freed.
|
||||
|
||||
switch (event->event_type)
|
||||
{
|
||||
case MIDI_EVENT_SYSEX:
|
||||
case MIDI_EVENT_SYSEX_SPLIT:
|
||||
free(event->data.sysex.data);
|
||||
break;
|
||||
|
||||
case MIDI_EVENT_META:
|
||||
free(event->data.meta.data);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read and check the track chunk header
|
||||
|
||||
static boolean ReadTrackHeader(midi_track_t *track, FILE *stream)
|
||||
{
|
||||
size_t records_read;
|
||||
chunk_header_t chunk_header;
|
||||
|
||||
records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, stream);
|
||||
|
||||
if (records_read < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckChunkHeader(&chunk_header, TRACK_CHUNK_ID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
track->data_len = SDL_SwapBE32(chunk_header.chunk_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean ReadTrack(midi_track_t *track, FILE *stream)
|
||||
{
|
||||
midi_event_t *new_events;
|
||||
midi_event_t *event;
|
||||
unsigned int last_event_type;
|
||||
|
||||
track->num_events = 0;
|
||||
track->events = NULL;
|
||||
|
||||
// Read the header:
|
||||
|
||||
if (!ReadTrackHeader(track, stream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Then the events:
|
||||
|
||||
last_event_type = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// Resize the track slightly larger to hold another event:
|
||||
|
||||
new_events = realloc(track->events,
|
||||
sizeof(midi_event_t) * (track->num_events + 1));
|
||||
|
||||
if (new_events == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
track->events = new_events;
|
||||
|
||||
// Read the next event:
|
||||
|
||||
event = &track->events[track->num_events];
|
||||
if (!ReadEvent(event, &last_event_type, stream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
++track->num_events;
|
||||
|
||||
// End of track?
|
||||
|
||||
if (event->event_type == MIDI_EVENT_META
|
||||
&& event->data.meta.type == MIDI_META_END_OF_TRACK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Free a track:
|
||||
|
||||
static void FreeTrack(midi_track_t *track)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i<track->num_events; ++i)
|
||||
{
|
||||
FreeEvent(&track->events[i]);
|
||||
}
|
||||
|
||||
free(track->events);
|
||||
}
|
||||
|
||||
static boolean ReadAllTracks(midi_file_t *file, FILE *stream)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// Allocate list of tracks and read each track:
|
||||
|
||||
file->tracks = malloc(sizeof(midi_track_t) * file->num_tracks);
|
||||
|
||||
if (file->tracks == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(file->tracks, 0, sizeof(midi_track_t) * file->num_tracks);
|
||||
|
||||
// Read each track:
|
||||
|
||||
for (i=0; i<file->num_tracks; ++i)
|
||||
{
|
||||
if (!ReadTrack(&file->tracks[i], stream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read and check the header chunk.
|
||||
|
||||
static boolean ReadFileHeader(midi_file_t *file, FILE *stream)
|
||||
{
|
||||
size_t records_read;
|
||||
unsigned int format_type;
|
||||
|
||||
records_read = fread(&file->header, sizeof(midi_header_t), 1, stream);
|
||||
|
||||
if (records_read < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID)
|
||||
|| SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6)
|
||||
{
|
||||
fprintf(stderr, "ReadFileHeader: Invalid MIDI chunk header! "
|
||||
"chunk_size=%i\n",
|
||||
SDL_SwapBE32(file->header.chunk_header.chunk_size));
|
||||
return false;
|
||||
}
|
||||
|
||||
format_type = SDL_SwapBE16(file->header.format_type);
|
||||
file->num_tracks = SDL_SwapBE16(file->header.num_tracks);
|
||||
|
||||
if ((format_type != 0 && format_type != 1)
|
||||
|| file->num_tracks < 1)
|
||||
{
|
||||
fprintf(stderr, "ReadFileHeader: Only type 0/1 "
|
||||
"MIDI files supported!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MIDI_FreeFile(midi_file_t *file)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (file->tracks != NULL)
|
||||
{
|
||||
for (i=0; i<file->num_tracks; ++i)
|
||||
{
|
||||
FreeTrack(&file->tracks[i]);
|
||||
}
|
||||
|
||||
free(file->tracks);
|
||||
}
|
||||
|
||||
free(file);
|
||||
}
|
||||
|
||||
midi_file_t *MIDI_LoadFile(char *filename)
|
||||
{
|
||||
midi_file_t *file;
|
||||
FILE *stream;
|
||||
|
||||
file = malloc(sizeof(midi_file_t));
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file->tracks = NULL;
|
||||
file->num_tracks = 0;
|
||||
file->buffer = NULL;
|
||||
file->buffer_size = 0;
|
||||
|
||||
// Open file
|
||||
|
||||
stream = fopen(filename, "rb");
|
||||
|
||||
if (stream == NULL)
|
||||
{
|
||||
fprintf(stderr, "MIDI_LoadFile: Failed to open '%s'\n", filename);
|
||||
MIDI_FreeFile(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read MIDI file header
|
||||
|
||||
if (!ReadFileHeader(file, stream))
|
||||
{
|
||||
fclose(stream);
|
||||
MIDI_FreeFile(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read all tracks:
|
||||
|
||||
if (!ReadAllTracks(file, stream))
|
||||
{
|
||||
fclose(stream);
|
||||
MIDI_FreeFile(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
// Get the number of tracks in a MIDI file.
|
||||
|
||||
unsigned int MIDI_NumTracks(midi_file_t *file)
|
||||
{
|
||||
return file->num_tracks;
|
||||
}
|
||||
|
||||
// Start iterating over the events in a track.
|
||||
|
||||
midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track)
|
||||
{
|
||||
midi_track_iter_t *iter;
|
||||
|
||||
assert(track < file->num_tracks);
|
||||
|
||||
iter = malloc(sizeof(*iter));
|
||||
iter->track = &file->tracks[track];
|
||||
iter->position = 0;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
void MIDI_FreeIterator(midi_track_iter_t *iter)
|
||||
{
|
||||
free(iter);
|
||||
}
|
||||
|
||||
// Get the time until the next MIDI event in a track.
|
||||
|
||||
unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter)
|
||||
{
|
||||
if (iter->position < iter->track->num_events)
|
||||
{
|
||||
midi_event_t *next_event;
|
||||
|
||||
next_event = &iter->track->events[iter->position];
|
||||
|
||||
return next_event->delta_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a pointer to the next MIDI event.
|
||||
|
||||
int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event)
|
||||
{
|
||||
if (iter->position < iter->track->num_events)
|
||||
{
|
||||
*event = &iter->track->events[iter->position];
|
||||
++iter->position;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int MIDI_GetFileTimeDivision(midi_file_t *file)
|
||||
{
|
||||
short result = SDL_SwapBE16(file->header.time_division);
|
||||
|
||||
// Negative time division indicates SMPTE time and must be handled
|
||||
// differently.
|
||||
if (result < 0)
|
||||
{
|
||||
return (signed int)(-(result/256))
|
||||
* (signed int)(result & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void MIDI_RestartIterator(midi_track_iter_t *iter)
|
||||
{
|
||||
iter->position = 0;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
static char *MIDI_EventTypeToString(midi_event_type_t event_type)
|
||||
{
|
||||
switch (event_type)
|
||||
{
|
||||
case MIDI_EVENT_NOTE_OFF:
|
||||
return "MIDI_EVENT_NOTE_OFF";
|
||||
case MIDI_EVENT_NOTE_ON:
|
||||
return "MIDI_EVENT_NOTE_ON";
|
||||
case MIDI_EVENT_AFTERTOUCH:
|
||||
return "MIDI_EVENT_AFTERTOUCH";
|
||||
case MIDI_EVENT_CONTROLLER:
|
||||
return "MIDI_EVENT_CONTROLLER";
|
||||
case MIDI_EVENT_PROGRAM_CHANGE:
|
||||
return "MIDI_EVENT_PROGRAM_CHANGE";
|
||||
case MIDI_EVENT_CHAN_AFTERTOUCH:
|
||||
return "MIDI_EVENT_CHAN_AFTERTOUCH";
|
||||
case MIDI_EVENT_PITCH_BEND:
|
||||
return "MIDI_EVENT_PITCH_BEND";
|
||||
case MIDI_EVENT_SYSEX:
|
||||
return "MIDI_EVENT_SYSEX";
|
||||
case MIDI_EVENT_SYSEX_SPLIT:
|
||||
return "MIDI_EVENT_SYSEX_SPLIT";
|
||||
case MIDI_EVENT_META:
|
||||
return "MIDI_EVENT_META";
|
||||
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintTrack(midi_track_t *track)
|
||||
{
|
||||
midi_event_t *event;
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i<track->num_events; ++i)
|
||||
{
|
||||
event = &track->events[i];
|
||||
|
||||
if (event->delta_time > 0)
|
||||
{
|
||||
printf("Delay: %i ticks\n", event->delta_time);
|
||||
}
|
||||
|
||||
printf("Event type: %s (%i)\n",
|
||||
MIDI_EventTypeToString(event->event_type),
|
||||
event->event_type);
|
||||
|
||||
switch(event->event_type)
|
||||
{
|
||||
case MIDI_EVENT_NOTE_OFF:
|
||||
case MIDI_EVENT_NOTE_ON:
|
||||
case MIDI_EVENT_AFTERTOUCH:
|
||||
case MIDI_EVENT_CONTROLLER:
|
||||
case MIDI_EVENT_PROGRAM_CHANGE:
|
||||
case MIDI_EVENT_CHAN_AFTERTOUCH:
|
||||
case MIDI_EVENT_PITCH_BEND:
|
||||
printf("\tChannel: %i\n", event->data.channel.channel);
|
||||
printf("\tParameter 1: %i\n", event->data.channel.param1);
|
||||
printf("\tParameter 2: %i\n", event->data.channel.param2);
|
||||
break;
|
||||
|
||||
case MIDI_EVENT_SYSEX:
|
||||
case MIDI_EVENT_SYSEX_SPLIT:
|
||||
printf("\tLength: %i\n", event->data.sysex.length);
|
||||
break;
|
||||
|
||||
case MIDI_EVENT_META:
|
||||
printf("\tMeta type: %i\n", event->data.meta.type);
|
||||
printf("\tLength: %i\n", event->data.meta.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
midi_file_t *file;
|
||||
unsigned int i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Usage: %s <filename>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
file = MIDI_LoadFile(argv[1]);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to open %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<file->num_tracks; ++i)
|
||||
{
|
||||
printf("\n== Track %i ==\n\n", i);
|
||||
|
||||
PrintTrack(&file->tracks[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
171
src/midifile.h
Normal file
171
src/midifile.h
Normal file
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// MIDI file parsing.
|
||||
//
|
||||
|
||||
#ifndef MIDIFILE_H
|
||||
#define MIDIFILE_H
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
typedef struct midi_file_s midi_file_t;
|
||||
typedef struct midi_track_iter_s midi_track_iter_t;
|
||||
|
||||
#define MIDI_CHANNELS_PER_TRACK 16
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_EVENT_NOTE_OFF = 0x80,
|
||||
MIDI_EVENT_NOTE_ON = 0x90,
|
||||
MIDI_EVENT_AFTERTOUCH = 0xa0,
|
||||
MIDI_EVENT_CONTROLLER = 0xb0,
|
||||
MIDI_EVENT_PROGRAM_CHANGE = 0xc0,
|
||||
MIDI_EVENT_CHAN_AFTERTOUCH = 0xd0,
|
||||
MIDI_EVENT_PITCH_BEND = 0xe0,
|
||||
|
||||
MIDI_EVENT_SYSEX = 0xf0,
|
||||
MIDI_EVENT_SYSEX_SPLIT = 0xf7,
|
||||
MIDI_EVENT_META = 0xff,
|
||||
} midi_event_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_CONTROLLER_BANK_SELECT = 0x0,
|
||||
MIDI_CONTROLLER_MODULATION = 0x1,
|
||||
MIDI_CONTROLLER_BREATH_CONTROL = 0x2,
|
||||
MIDI_CONTROLLER_FOOT_CONTROL = 0x3,
|
||||
MIDI_CONTROLLER_PORTAMENTO = 0x4,
|
||||
MIDI_CONTROLLER_DATA_ENTRY = 0x5,
|
||||
|
||||
MIDI_CONTROLLER_MAIN_VOLUME = 0x7,
|
||||
MIDI_CONTROLLER_PAN = 0xa,
|
||||
|
||||
MIDI_CONTROLLER_ALL_NOTES_OFF = 0x7b,
|
||||
} midi_controller_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_META_SEQUENCE_NUMBER = 0x0,
|
||||
|
||||
MIDI_META_TEXT = 0x1,
|
||||
MIDI_META_COPYRIGHT = 0x2,
|
||||
MIDI_META_TRACK_NAME = 0x3,
|
||||
MIDI_META_INSTR_NAME = 0x4,
|
||||
MIDI_META_LYRICS = 0x5,
|
||||
MIDI_META_MARKER = 0x6,
|
||||
MIDI_META_CUE_POINT = 0x7,
|
||||
|
||||
MIDI_META_CHANNEL_PREFIX = 0x20,
|
||||
MIDI_META_END_OF_TRACK = 0x2f,
|
||||
|
||||
MIDI_META_SET_TEMPO = 0x51,
|
||||
MIDI_META_SMPTE_OFFSET = 0x54,
|
||||
MIDI_META_TIME_SIGNATURE = 0x58,
|
||||
MIDI_META_KEY_SIGNATURE = 0x59,
|
||||
MIDI_META_SEQUENCER_SPECIFIC = 0x7f,
|
||||
} midi_meta_event_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Meta event type:
|
||||
|
||||
unsigned int type;
|
||||
|
||||
// Length:
|
||||
|
||||
unsigned int length;
|
||||
|
||||
// Meta event data:
|
||||
|
||||
byte *data;
|
||||
} midi_meta_event_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Length:
|
||||
|
||||
unsigned int length;
|
||||
|
||||
// Event data:
|
||||
|
||||
byte *data;
|
||||
} midi_sysex_event_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// The channel number to which this applies:
|
||||
|
||||
unsigned int channel;
|
||||
|
||||
// Extra parameters:
|
||||
|
||||
unsigned int param1;
|
||||
unsigned int param2;
|
||||
} midi_channel_event_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Time between the previous event and this event.
|
||||
unsigned int delta_time;
|
||||
|
||||
// Type of event:
|
||||
midi_event_type_t event_type;
|
||||
|
||||
union
|
||||
{
|
||||
midi_channel_event_data_t channel;
|
||||
midi_meta_event_data_t meta;
|
||||
midi_sysex_event_data_t sysex;
|
||||
} data;
|
||||
} midi_event_t;
|
||||
|
||||
// Load a MIDI file.
|
||||
|
||||
midi_file_t *MIDI_LoadFile(char *filename);
|
||||
|
||||
// Free a MIDI file.
|
||||
|
||||
void MIDI_FreeFile(midi_file_t *file);
|
||||
|
||||
// Get the time division value from the MIDI header.
|
||||
|
||||
unsigned int MIDI_GetFileTimeDivision(midi_file_t *file);
|
||||
|
||||
// Get the number of tracks in a MIDI file.
|
||||
|
||||
unsigned int MIDI_NumTracks(midi_file_t *file);
|
||||
|
||||
// Start iterating over the events in a track.
|
||||
|
||||
midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track_num);
|
||||
|
||||
// Free an iterator.
|
||||
|
||||
void MIDI_FreeIterator(midi_track_iter_t *iter);
|
||||
|
||||
// Get the time until the next MIDI event in a track.
|
||||
|
||||
unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter);
|
||||
|
||||
// Get a pointer to the next MIDI event.
|
||||
|
||||
int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event);
|
||||
|
||||
// Reset an iterator to the beginning of a track.
|
||||
|
||||
void MIDI_RestartIterator(midi_track_iter_t *iter);
|
||||
|
||||
#endif /* #ifndef MIDIFILE_H */
|
||||
|
||||
732
src/mus2mid.c
Normal file
732
src/mus2mid.c
Normal file
@@ -0,0 +1,732 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
// Copyright(C) 2006 Ben Ryves 2006
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// mus2mid.c - Ben Ryves 2006 - http://benryves.com - benryves@benryves.com
|
||||
// Use to convert a MUS file into a single track, type 0 MIDI file.
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_swap.h"
|
||||
#include "memio.h"
|
||||
#include "mus2mid.h"
|
||||
|
||||
#define NUM_CHANNELS 16
|
||||
|
||||
#define MIDI_PERCUSSION_CHAN 9
|
||||
#define MUS_PERCUSSION_CHAN 15
|
||||
|
||||
// MUS event codes
|
||||
typedef enum
|
||||
{
|
||||
mus_releasekey = 0x00,
|
||||
mus_presskey = 0x10,
|
||||
mus_pitchwheel = 0x20,
|
||||
mus_systemevent = 0x30,
|
||||
mus_changecontroller = 0x40,
|
||||
mus_scoreend = 0x60
|
||||
} musevent;
|
||||
|
||||
// MIDI event codes
|
||||
typedef enum
|
||||
{
|
||||
midi_releasekey = 0x80,
|
||||
midi_presskey = 0x90,
|
||||
midi_aftertouchkey = 0xA0,
|
||||
midi_changecontroller = 0xB0,
|
||||
midi_changepatch = 0xC0,
|
||||
midi_aftertouchchannel = 0xD0,
|
||||
midi_pitchwheel = 0xE0
|
||||
} midievent;
|
||||
|
||||
// Structure to hold MUS file header
|
||||
typedef PACKED_STRUCT (
|
||||
{
|
||||
byte id[4];
|
||||
unsigned short scorelength;
|
||||
unsigned short scorestart;
|
||||
unsigned short primarychannels;
|
||||
unsigned short secondarychannels;
|
||||
unsigned short instrumentcount;
|
||||
}) musheader;
|
||||
|
||||
// Standard MIDI type 0 header + track header
|
||||
static const byte midiheader[] =
|
||||
{
|
||||
'M', 'T', 'h', 'd', // Main header
|
||||
0x00, 0x00, 0x00, 0x06, // Header size
|
||||
0x00, 0x00, // MIDI type (0)
|
||||
0x00, 0x01, // Number of tracks
|
||||
0x00, 0x46, // Resolution
|
||||
'M', 'T', 'r', 'k', // Start of track
|
||||
0x00, 0x00, 0x00, 0x00 // Placeholder for track length
|
||||
};
|
||||
|
||||
// Cached channel velocities
|
||||
static byte channelvelocities[] =
|
||||
{
|
||||
127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 127
|
||||
};
|
||||
|
||||
// Timestamps between sequences of MUS events
|
||||
|
||||
static unsigned int queuedtime = 0;
|
||||
|
||||
// Counter for the length of the track
|
||||
|
||||
static unsigned int tracksize;
|
||||
|
||||
static const byte controller_map[] =
|
||||
{
|
||||
0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D,
|
||||
0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79
|
||||
};
|
||||
|
||||
static int channel_map[NUM_CHANNELS];
|
||||
|
||||
// Write timestamp to a MIDI file.
|
||||
|
||||
static boolean WriteTime(unsigned int time, MEMFILE *midioutput)
|
||||
{
|
||||
unsigned int buffer = time & 0x7F;
|
||||
byte writeval;
|
||||
|
||||
while ((time >>= 7) != 0)
|
||||
{
|
||||
buffer <<= 8;
|
||||
buffer |= ((time & 0x7F) | 0x80);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
writeval = (byte)(buffer & 0xFF);
|
||||
|
||||
if (mem_fwrite(&writeval, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
++tracksize;
|
||||
|
||||
if ((buffer & 0x80) != 0)
|
||||
{
|
||||
buffer >>= 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
queuedtime = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the end of track marker
|
||||
static boolean WriteEndTrack(MEMFILE *midioutput)
|
||||
{
|
||||
byte endtrack[] = {0xFF, 0x2F, 0x00};
|
||||
|
||||
if (WriteTime(queuedtime, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fwrite(endtrack, 1, 3, midioutput) != 3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksize += 3;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a key press event
|
||||
static boolean WritePressKey(byte channel, byte key,
|
||||
byte velocity, MEMFILE *midioutput)
|
||||
{
|
||||
byte working = midi_presskey | channel;
|
||||
|
||||
if (WriteTime(queuedtime, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = key & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = velocity & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksize += 3;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a key release event
|
||||
static boolean WriteReleaseKey(byte channel, byte key,
|
||||
MEMFILE *midioutput)
|
||||
{
|
||||
byte working = midi_releasekey | channel;
|
||||
|
||||
if (WriteTime(queuedtime, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = key & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = 0;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksize += 3;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a pitch wheel/bend event
|
||||
static boolean WritePitchWheel(byte channel, short wheel,
|
||||
MEMFILE *midioutput)
|
||||
{
|
||||
byte working = midi_pitchwheel | channel;
|
||||
|
||||
if (WriteTime(queuedtime, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = wheel & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = (wheel >> 7) & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksize += 3;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a patch change event
|
||||
static boolean WriteChangePatch(byte channel, byte patch,
|
||||
MEMFILE *midioutput)
|
||||
{
|
||||
byte working = midi_changepatch | channel;
|
||||
|
||||
if (WriteTime(queuedtime, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = patch & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksize += 2;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a valued controller change event
|
||||
|
||||
static boolean WriteChangeController_Valued(byte channel,
|
||||
byte control,
|
||||
byte value,
|
||||
MEMFILE *midioutput)
|
||||
{
|
||||
byte working = midi_changecontroller | channel;
|
||||
|
||||
if (WriteTime(queuedtime, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
working = control & 0x7F;
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Quirk in vanilla DOOM? MUS controller values should be
|
||||
// 7-bit, not 8-bit.
|
||||
|
||||
working = value;// & 0x7F;
|
||||
|
||||
// Fix on said quirk to stop MIDI players from complaining that
|
||||
// the value is out of range:
|
||||
|
||||
if (working & 0x80)
|
||||
{
|
||||
working = 0x7F;
|
||||
}
|
||||
|
||||
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksize += 3;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a valueless controller change event
|
||||
static boolean WriteChangeController_Valueless(byte channel,
|
||||
byte control,
|
||||
MEMFILE *midioutput)
|
||||
{
|
||||
return WriteChangeController_Valued(channel, control, 0,
|
||||
midioutput);
|
||||
}
|
||||
|
||||
// Allocate a free MIDI channel.
|
||||
|
||||
static int AllocateMIDIChannel(void)
|
||||
{
|
||||
int result;
|
||||
int max;
|
||||
int i;
|
||||
|
||||
// Find the current highest-allocated channel.
|
||||
|
||||
max = -1;
|
||||
|
||||
for (i=0; i<NUM_CHANNELS; ++i)
|
||||
{
|
||||
if (channel_map[i] > max)
|
||||
{
|
||||
max = channel_map[i];
|
||||
}
|
||||
}
|
||||
|
||||
// max is now equal to the highest-allocated MIDI channel. We can
|
||||
// now allocate the next available channel. This also works if
|
||||
// no channels are currently allocated (max=-1)
|
||||
|
||||
result = max + 1;
|
||||
|
||||
// Don't allocate the MIDI percussion channel!
|
||||
|
||||
if (result == MIDI_PERCUSSION_CHAN)
|
||||
{
|
||||
++result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Given a MUS channel number, get the MIDI channel number to use
|
||||
// in the outputted file.
|
||||
|
||||
static int GetMIDIChannel(int mus_channel, MEMFILE *midioutput)
|
||||
{
|
||||
// Find the MIDI channel to use for this MUS channel.
|
||||
// MUS channel 15 is the percusssion channel.
|
||||
|
||||
if (mus_channel == MUS_PERCUSSION_CHAN)
|
||||
{
|
||||
return MIDI_PERCUSSION_CHAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a MIDI channel hasn't been allocated for this MUS channel
|
||||
// yet, allocate the next free MIDI channel.
|
||||
|
||||
if (channel_map[mus_channel] == -1)
|
||||
{
|
||||
channel_map[mus_channel] = AllocateMIDIChannel();
|
||||
|
||||
// First time using the channel, send an "all notes off"
|
||||
// event. This fixes "The D_DDTBLU disease" described here:
|
||||
// https://www.doomworld.com/vb/source-ports/66802-the
|
||||
WriteChangeController_Valueless(channel_map[mus_channel], 0x7b,
|
||||
midioutput);
|
||||
}
|
||||
|
||||
return channel_map[mus_channel];
|
||||
}
|
||||
}
|
||||
|
||||
static boolean ReadMusHeader(MEMFILE *file, musheader *header)
|
||||
{
|
||||
boolean result;
|
||||
|
||||
result = mem_fread(&header->id, sizeof(byte), 4, file) == 4
|
||||
&& mem_fread(&header->scorelength, sizeof(short), 1, file) == 1
|
||||
&& mem_fread(&header->scorestart, sizeof(short), 1, file) == 1
|
||||
&& mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1
|
||||
&& mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1
|
||||
&& mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1;
|
||||
|
||||
if (result)
|
||||
{
|
||||
header->scorelength = SHORT(header->scorelength);
|
||||
header->scorestart = SHORT(header->scorestart);
|
||||
header->primarychannels = SHORT(header->primarychannels);
|
||||
header->secondarychannels = SHORT(header->secondarychannels);
|
||||
header->instrumentcount = SHORT(header->instrumentcount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Read a MUS file from a stream (musinput) and output a MIDI file to
|
||||
// a stream (midioutput).
|
||||
//
|
||||
// Returns 0 on success or 1 on failure.
|
||||
|
||||
boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
|
||||
{
|
||||
// Header for the MUS file
|
||||
musheader musfileheader;
|
||||
|
||||
// Descriptor for the current MUS event
|
||||
byte eventdescriptor;
|
||||
int channel; // Channel number
|
||||
musevent event;
|
||||
|
||||
|
||||
// Bunch of vars read from MUS lump
|
||||
byte key;
|
||||
byte controllernumber;
|
||||
byte controllervalue;
|
||||
|
||||
// Buffer used for MIDI track size record
|
||||
byte tracksizebuffer[4];
|
||||
|
||||
// Flag for when the score end marker is hit.
|
||||
int hitscoreend = 0;
|
||||
|
||||
// Temp working byte
|
||||
byte working;
|
||||
// Used in building up time delays
|
||||
unsigned int timedelay;
|
||||
|
||||
// Initialise channel map to mark all channels as unused.
|
||||
|
||||
for (channel=0; channel<NUM_CHANNELS; ++channel)
|
||||
{
|
||||
channel_map[channel] = -1;
|
||||
}
|
||||
|
||||
// Grab the header
|
||||
|
||||
if (!ReadMusHeader(musinput, &musfileheader))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CHECK_MUS_HEADER
|
||||
// Check MUS header
|
||||
if (musfileheader.id[0] != 'M'
|
||||
|| musfileheader.id[1] != 'U'
|
||||
|| musfileheader.id[2] != 'S'
|
||||
|| musfileheader.id[3] != 0x1A)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Seek to where the data is held
|
||||
if (mem_fseek(musinput, (long)musfileheader.scorestart,
|
||||
MEM_SEEK_SET) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// So, we can assume the MUS file is faintly legit. Let's start
|
||||
// writing MIDI data...
|
||||
|
||||
mem_fwrite(midiheader, 1, sizeof(midiheader), midioutput);
|
||||
tracksize = 0;
|
||||
|
||||
// Now, process the MUS file:
|
||||
while (!hitscoreend)
|
||||
{
|
||||
// Handle a block of events:
|
||||
|
||||
while (!hitscoreend)
|
||||
{
|
||||
// Fetch channel number and event code:
|
||||
|
||||
if (mem_fread(&eventdescriptor, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
channel = GetMIDIChannel(eventdescriptor & 0x0F, midioutput);
|
||||
event = eventdescriptor & 0x70;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case mus_releasekey:
|
||||
if (mem_fread(&key, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WriteReleaseKey(channel, key, midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case mus_presskey:
|
||||
if (mem_fread(&key, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key & 0x80)
|
||||
{
|
||||
if (mem_fread(&channelvelocities[channel], 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
channelvelocities[channel] &= 0x7F;
|
||||
}
|
||||
|
||||
if (WritePressKey(channel, key,
|
||||
channelvelocities[channel], midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case mus_pitchwheel:
|
||||
if (mem_fread(&key, 1, 1, musinput) != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (WritePitchWheel(channel, (short)(key * 64), midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case mus_systemevent:
|
||||
if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (controllernumber < 10 || controllernumber > 14)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WriteChangeController_Valueless(channel,
|
||||
controller_map[controllernumber],
|
||||
midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case mus_changecontroller:
|
||||
if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mem_fread(&controllervalue, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (controllernumber == 0)
|
||||
{
|
||||
if (WriteChangePatch(channel, controllervalue,
|
||||
midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (controllernumber < 1 || controllernumber > 9)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WriteChangeController_Valued(channel,
|
||||
controller_map[controllernumber],
|
||||
controllervalue,
|
||||
midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case mus_scoreend:
|
||||
hitscoreend = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (eventdescriptor & 0x80)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now we need to read the time code:
|
||||
if (!hitscoreend)
|
||||
{
|
||||
timedelay = 0;
|
||||
for (;;)
|
||||
{
|
||||
if (mem_fread(&working, 1, 1, musinput) != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
timedelay = timedelay * 128 + (working & 0x7F);
|
||||
if ((working & 0x80) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
queuedtime += timedelay;
|
||||
}
|
||||
}
|
||||
|
||||
// End of track
|
||||
if (WriteEndTrack(midioutput))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write the track size into the stream
|
||||
if (mem_fseek(midioutput, 18, MEM_SEEK_SET))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tracksizebuffer[0] = (tracksize >> 24) & 0xff;
|
||||
tracksizebuffer[1] = (tracksize >> 16) & 0xff;
|
||||
tracksizebuffer[2] = (tracksize >> 8) & 0xff;
|
||||
tracksizebuffer[3] = tracksize & 0xff;
|
||||
|
||||
if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
#include "m_misc.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
MEMFILE *src, *dst;
|
||||
byte *infile;
|
||||
long infile_len;
|
||||
void *outfile;
|
||||
size_t outfile_len;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
printf("Usage: %s <musfile> <midfile>\n", argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Z_Init();
|
||||
|
||||
infile_len = M_ReadFile(argv[1], &infile);
|
||||
|
||||
src = mem_fopen_read(infile, infile_len);
|
||||
dst = mem_fopen_write();
|
||||
|
||||
if (mus2mid(src, dst))
|
||||
{
|
||||
fprintf(stderr, "mus2mid() failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Write result to output file:
|
||||
|
||||
mem_get_buf(dst, &outfile, &outfile_len);
|
||||
|
||||
M_WriteFile(argv[2], outfile, outfile_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
29
src/mus2mid.h
Normal file
29
src/mus2mid.h
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Copyright(C) 1993-1996 Id Software, Inc.
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
// Copyright(C) 2006 Ben Ryves 2006
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// mus2mid.h - Ben Ryves 2006 - http://benryves.com - benryves@benryves.com
|
||||
// Use to convert a MUS file into a single track, type 0 MIDI file.
|
||||
|
||||
#ifndef MUS2MID_H
|
||||
#define MUS2MID_H
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "memio.h"
|
||||
|
||||
boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput);
|
||||
|
||||
#endif /* #ifndef MUS2MID_H */
|
||||
|
||||
1084
src/net_client.c
Normal file
1084
src/net_client.c
Normal file
File diff suppressed because it is too large
Load Diff
50
src/net_client.h
Normal file
50
src/net_client.h
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Network client code
|
||||
//
|
||||
|
||||
#ifndef NET_CLIENT_H
|
||||
#define NET_CLIENT_H
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "d_ticcmd.h"
|
||||
#include "sha1.h"
|
||||
#include "net_defs.h"
|
||||
|
||||
boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data);
|
||||
void NET_CL_Disconnect(void);
|
||||
void NET_CL_Run(void);
|
||||
void NET_CL_Init(void);
|
||||
void NET_CL_LaunchGame(void);
|
||||
void NET_CL_StartGame(net_gamesettings_t *settings);
|
||||
void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic);
|
||||
boolean NET_CL_GetSettings(net_gamesettings_t *_settings);
|
||||
void NET_Init(void);
|
||||
|
||||
void NET_BindVariables(void);
|
||||
|
||||
extern boolean net_client_connected;
|
||||
extern boolean net_client_received_wait_data;
|
||||
extern net_waitdata_t net_client_wait_data;
|
||||
extern boolean net_waiting_for_launch;
|
||||
extern char *net_player_name;
|
||||
|
||||
extern sha1_digest_t net_server_wad_sha1sum;
|
||||
extern unsigned int net_server_is_freedoom;
|
||||
extern sha1_digest_t net_local_wad_sha1sum;
|
||||
extern unsigned int net_local_is_freedoom;
|
||||
|
||||
extern boolean drone;
|
||||
|
||||
#endif /* #ifndef NET_CLIENT_H */
|
||||
534
src/net_common.c
Normal file
534
src/net_common.c
Normal file
@@ -0,0 +1,534 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Common code shared between the client and server
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "d_mode.h"
|
||||
#include "i_timer.h"
|
||||
|
||||
#include "net_common.h"
|
||||
#include "net_io.h"
|
||||
#include "net_packet.h"
|
||||
#include "net_structrw.h"
|
||||
|
||||
// connections time out after 30 seconds
|
||||
|
||||
#define CONNECTION_TIMEOUT_LEN 30
|
||||
|
||||
// maximum time between sending packets
|
||||
|
||||
#define KEEPALIVE_PERIOD 1
|
||||
|
||||
// reliable packet that is guaranteed to reach its destination
|
||||
|
||||
struct net_reliable_packet_s
|
||||
{
|
||||
net_packet_t *packet;
|
||||
int last_send_time;
|
||||
int seq;
|
||||
net_reliable_packet_t *next;
|
||||
};
|
||||
|
||||
static void NET_Conn_Init(net_connection_t *conn, net_addr_t *addr)
|
||||
{
|
||||
conn->last_send_time = -1;
|
||||
conn->num_retries = 0;
|
||||
conn->addr = addr;
|
||||
conn->reliable_packets = NULL;
|
||||
conn->reliable_send_seq = 0;
|
||||
conn->reliable_recv_seq = 0;
|
||||
}
|
||||
|
||||
// Initialize as a client connection
|
||||
|
||||
void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr)
|
||||
{
|
||||
NET_Conn_Init(conn, addr);
|
||||
conn->state = NET_CONN_STATE_CONNECTING;
|
||||
}
|
||||
|
||||
// Initialize as a server connection
|
||||
|
||||
void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr)
|
||||
{
|
||||
NET_Conn_Init(conn, addr);
|
||||
conn->state = NET_CONN_STATE_WAITING_ACK;
|
||||
}
|
||||
|
||||
// Send a packet to a connection
|
||||
// All packets should be sent through this interface, as it maintains the
|
||||
// keepalive_send_time counter.
|
||||
|
||||
void NET_Conn_SendPacket(net_connection_t *conn, net_packet_t *packet)
|
||||
{
|
||||
conn->keepalive_send_time = I_GetTimeMS();
|
||||
NET_SendPacket(conn->addr, packet);
|
||||
}
|
||||
|
||||
// parse an ACK packet from a client
|
||||
|
||||
static void NET_Conn_ParseACK(net_connection_t *conn, net_packet_t *packet)
|
||||
{
|
||||
net_packet_t *reply;
|
||||
|
||||
if (conn->state == NET_CONN_STATE_CONNECTING)
|
||||
{
|
||||
// We are a client
|
||||
|
||||
// received a response from the server to our SYN
|
||||
|
||||
conn->state = NET_CONN_STATE_CONNECTED;
|
||||
|
||||
// We must send an ACK reply to the server's ACK
|
||||
|
||||
reply = NET_NewPacket(10);
|
||||
NET_WriteInt16(reply, NET_PACKET_TYPE_ACK);
|
||||
NET_Conn_SendPacket(conn, reply);
|
||||
NET_FreePacket(reply);
|
||||
}
|
||||
|
||||
if (conn->state == NET_CONN_STATE_WAITING_ACK)
|
||||
{
|
||||
// We are a server
|
||||
|
||||
// Client is connected
|
||||
|
||||
conn->state = NET_CONN_STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void NET_Conn_ParseDisconnect(net_connection_t *conn, net_packet_t *packet)
|
||||
{
|
||||
net_packet_t *reply;
|
||||
|
||||
// Other end wants to disconnect
|
||||
// Send a DISCONNECT_ACK reply.
|
||||
|
||||
reply = NET_NewPacket(10);
|
||||
NET_WriteInt16(reply, NET_PACKET_TYPE_DISCONNECT_ACK);
|
||||
NET_Conn_SendPacket(conn, reply);
|
||||
NET_FreePacket(reply);
|
||||
|
||||
conn->last_send_time = I_GetTimeMS();
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED_SLEEP;
|
||||
conn->disconnect_reason = NET_DISCONNECT_REMOTE;
|
||||
}
|
||||
|
||||
// Parse a DISCONNECT_ACK packet
|
||||
|
||||
static void NET_Conn_ParseDisconnectACK(net_connection_t *conn,
|
||||
net_packet_t *packet)
|
||||
{
|
||||
|
||||
if (conn->state == NET_CONN_STATE_DISCONNECTING)
|
||||
{
|
||||
// We have received an acknowledgement to our disconnect
|
||||
// request. We have been disconnected successfully.
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED;
|
||||
conn->disconnect_reason = NET_DISCONNECT_LOCAL;
|
||||
conn->last_send_time = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void NET_Conn_ParseReject(net_connection_t *conn, net_packet_t *packet)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = NET_ReadString(packet);
|
||||
|
||||
if (msg == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->state == NET_CONN_STATE_CONNECTING)
|
||||
{
|
||||
// rejected by server
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED;
|
||||
conn->disconnect_reason = NET_DISCONNECT_REMOTE;
|
||||
|
||||
printf("Rejected by server: ");
|
||||
NET_SafePuts(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void NET_Conn_ParseReliableACK(net_connection_t *conn, net_packet_t *packet)
|
||||
{
|
||||
unsigned int seq;
|
||||
|
||||
if (!NET_ReadInt8(packet, &seq))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->reliable_packets == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this an acknowledgement for the first packet in the list?
|
||||
|
||||
if (seq == (unsigned int)((conn->reliable_packets->seq + 1) & 0xff))
|
||||
{
|
||||
net_reliable_packet_t *rp;
|
||||
|
||||
// Discard it, then.
|
||||
// Unlink from the list.
|
||||
|
||||
rp = conn->reliable_packets;
|
||||
conn->reliable_packets = rp->next;
|
||||
|
||||
NET_FreePacket(rp->packet);
|
||||
free(rp);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the header of a reliable packet
|
||||
//
|
||||
// Returns true if the packet should be discarded (incorrect sequence)
|
||||
|
||||
static boolean NET_Conn_ReliablePacket(net_connection_t *conn,
|
||||
net_packet_t *packet)
|
||||
{
|
||||
unsigned int seq;
|
||||
net_packet_t *reply;
|
||||
boolean result;
|
||||
|
||||
// Read the sequence number
|
||||
|
||||
if (!NET_ReadInt8(packet, &seq))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (seq != (unsigned int)(conn->reliable_recv_seq & 0xff))
|
||||
{
|
||||
// This is not the next expected packet in the sequence!
|
||||
//
|
||||
// Discard the packet. If we were smart, we would use a proper
|
||||
// sliding window protocol to do this, but I'm lazy.
|
||||
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now we can receive the next packet in the sequence.
|
||||
|
||||
conn->reliable_recv_seq = (conn->reliable_recv_seq + 1) & 0xff;
|
||||
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Send an acknowledgement
|
||||
|
||||
// Note: this is braindead. It would be much more sensible to
|
||||
// include this in the next packet, rather than the overhead of
|
||||
// sending a complete packet just for one byte of information.
|
||||
|
||||
reply = NET_NewPacket(10);
|
||||
|
||||
NET_WriteInt16(reply, NET_PACKET_TYPE_RELIABLE_ACK);
|
||||
NET_WriteInt8(reply, conn->reliable_recv_seq & 0xff);
|
||||
|
||||
NET_Conn_SendPacket(conn, reply);
|
||||
|
||||
NET_FreePacket(reply);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Process a packet received by the server
|
||||
//
|
||||
// Returns true if eaten by common code
|
||||
|
||||
boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet,
|
||||
unsigned int *packet_type)
|
||||
{
|
||||
conn->keepalive_recv_time = I_GetTimeMS();
|
||||
|
||||
// Is this a reliable packet?
|
||||
|
||||
if (*packet_type & NET_RELIABLE_PACKET)
|
||||
{
|
||||
if (NET_Conn_ReliablePacket(conn, packet))
|
||||
{
|
||||
// Invalid packet: eat it.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove the reliable bit
|
||||
|
||||
*packet_type &= ~NET_RELIABLE_PACKET;
|
||||
}
|
||||
|
||||
switch (*packet_type)
|
||||
{
|
||||
case NET_PACKET_TYPE_ACK:
|
||||
NET_Conn_ParseACK(conn, packet);
|
||||
break;
|
||||
case NET_PACKET_TYPE_DISCONNECT:
|
||||
NET_Conn_ParseDisconnect(conn, packet);
|
||||
break;
|
||||
case NET_PACKET_TYPE_DISCONNECT_ACK:
|
||||
NET_Conn_ParseDisconnectACK(conn, packet);
|
||||
break;
|
||||
case NET_PACKET_TYPE_KEEPALIVE:
|
||||
// No special action needed.
|
||||
break;
|
||||
case NET_PACKET_TYPE_REJECTED:
|
||||
NET_Conn_ParseReject(conn, packet);
|
||||
break;
|
||||
case NET_PACKET_TYPE_RELIABLE_ACK:
|
||||
NET_Conn_ParseReliableACK(conn, packet);
|
||||
break;
|
||||
default:
|
||||
// Not a common packet
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We found a packet that we found interesting, and ate it.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NET_Conn_Disconnect(net_connection_t *conn)
|
||||
{
|
||||
if (conn->state != NET_CONN_STATE_DISCONNECTED
|
||||
&& conn->state != NET_CONN_STATE_DISCONNECTING
|
||||
&& conn->state != NET_CONN_STATE_DISCONNECTED_SLEEP)
|
||||
{
|
||||
conn->state = NET_CONN_STATE_DISCONNECTING;
|
||||
conn->disconnect_reason = NET_DISCONNECT_LOCAL;
|
||||
conn->last_send_time = -1;
|
||||
conn->num_retries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void NET_Conn_Run(net_connection_t *conn)
|
||||
{
|
||||
net_packet_t *packet;
|
||||
unsigned int nowtime;
|
||||
|
||||
nowtime = I_GetTimeMS();
|
||||
|
||||
if (conn->state == NET_CONN_STATE_CONNECTED)
|
||||
{
|
||||
// Check the keepalive counters
|
||||
|
||||
if (nowtime - conn->keepalive_recv_time > CONNECTION_TIMEOUT_LEN * 1000)
|
||||
{
|
||||
// Haven't received any packets from the other end in a long
|
||||
// time. Assume disconnected.
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED;
|
||||
conn->disconnect_reason = NET_DISCONNECT_TIMEOUT;
|
||||
}
|
||||
|
||||
if (nowtime - conn->keepalive_send_time > KEEPALIVE_PERIOD * 1000)
|
||||
{
|
||||
// We have not sent anything in a long time.
|
||||
// Send a keepalive.
|
||||
|
||||
packet = NET_NewPacket(10);
|
||||
NET_WriteInt16(packet, NET_PACKET_TYPE_KEEPALIVE);
|
||||
NET_Conn_SendPacket(conn, packet);
|
||||
NET_FreePacket(packet);
|
||||
}
|
||||
|
||||
// Check the reliable packet list. Has the first packet in the
|
||||
// list timed out?
|
||||
//
|
||||
// NB. This is braindead, we have a fixed time of one second.
|
||||
|
||||
if (conn->reliable_packets != NULL
|
||||
&& (conn->reliable_packets->last_send_time < 0
|
||||
|| nowtime - conn->reliable_packets->last_send_time > 1000))
|
||||
{
|
||||
// Packet timed out, time to resend
|
||||
|
||||
NET_Conn_SendPacket(conn, conn->reliable_packets->packet);
|
||||
conn->reliable_packets->last_send_time = nowtime;
|
||||
}
|
||||
}
|
||||
else if (conn->state == NET_CONN_STATE_WAITING_ACK)
|
||||
{
|
||||
if (conn->last_send_time < 0
|
||||
|| nowtime - conn->last_send_time > 1000)
|
||||
{
|
||||
// it has been a second since the last ACK was sent, and
|
||||
// still no reply.
|
||||
|
||||
if (conn->num_retries < MAX_RETRIES)
|
||||
{
|
||||
// send another ACK
|
||||
|
||||
packet = NET_NewPacket(10);
|
||||
NET_WriteInt16(packet, NET_PACKET_TYPE_ACK);
|
||||
NET_Conn_SendPacket(conn, packet);
|
||||
NET_FreePacket(packet);
|
||||
conn->last_send_time = nowtime;
|
||||
|
||||
++conn->num_retries;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more retries allowed.
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED;
|
||||
conn->disconnect_reason = NET_DISCONNECT_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (conn->state == NET_CONN_STATE_DISCONNECTING)
|
||||
{
|
||||
// Waiting for a reply to our DISCONNECT request.
|
||||
|
||||
if (conn->last_send_time < 0
|
||||
|| nowtime - conn->last_send_time > 1000)
|
||||
{
|
||||
// it has been a second since the last disconnect packet
|
||||
// was sent, and still no reply.
|
||||
|
||||
if (conn->num_retries < MAX_RETRIES)
|
||||
{
|
||||
// send another disconnect
|
||||
|
||||
packet = NET_NewPacket(10);
|
||||
NET_WriteInt16(packet, NET_PACKET_TYPE_DISCONNECT);
|
||||
NET_Conn_SendPacket(conn, packet);
|
||||
NET_FreePacket(packet);
|
||||
conn->last_send_time = nowtime;
|
||||
|
||||
++conn->num_retries;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No more retries allowed.
|
||||
// Force disconnect.
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED;
|
||||
conn->disconnect_reason = NET_DISCONNECT_LOCAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (conn->state == NET_CONN_STATE_DISCONNECTED_SLEEP)
|
||||
{
|
||||
// We are disconnected, waiting in case we need to send
|
||||
// a DISCONNECT_ACK to the server again.
|
||||
|
||||
if (nowtime - conn->last_send_time > 5000)
|
||||
{
|
||||
// Idle for 5 seconds, switch state
|
||||
|
||||
conn->state = NET_CONN_STATE_DISCONNECTED;
|
||||
conn->disconnect_reason = NET_DISCONNECT_REMOTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type)
|
||||
{
|
||||
net_packet_t *packet;
|
||||
net_reliable_packet_t *rp;
|
||||
net_reliable_packet_t **listend;
|
||||
|
||||
// Generate a packet with the right header
|
||||
|
||||
packet = NET_NewPacket(100);
|
||||
|
||||
NET_WriteInt16(packet, packet_type | NET_RELIABLE_PACKET);
|
||||
|
||||
// write the low byte of the send sequence number
|
||||
|
||||
NET_WriteInt8(packet, conn->reliable_send_seq & 0xff);
|
||||
|
||||
// Add to the list of reliable packets
|
||||
|
||||
rp = malloc(sizeof(net_reliable_packet_t));
|
||||
rp->packet = packet;
|
||||
rp->next = NULL;
|
||||
rp->seq = conn->reliable_send_seq;
|
||||
rp->last_send_time = -1;
|
||||
|
||||
for (listend = &conn->reliable_packets;
|
||||
*listend != NULL;
|
||||
listend = &((*listend)->next));
|
||||
|
||||
*listend = rp;
|
||||
|
||||
// Count along the sequence
|
||||
|
||||
conn->reliable_send_seq = (conn->reliable_send_seq + 1) & 0xff;
|
||||
|
||||
// Finished
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
// Used to expand the least significant byte of a tic number into
|
||||
// the full tic number, from the current tic number
|
||||
|
||||
unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b)
|
||||
{
|
||||
unsigned int l, h;
|
||||
unsigned int result;
|
||||
|
||||
h = relative & ~0xff;
|
||||
l = relative & 0xff;
|
||||
|
||||
result = h | b;
|
||||
|
||||
if (l < 0x40 && b > 0xb0)
|
||||
result -= 0x100;
|
||||
if (l > 0xb0 && b < 0x40)
|
||||
result += 0x100;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that game settings are valid
|
||||
|
||||
boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
|
||||
net_gamesettings_t *settings)
|
||||
{
|
||||
if (settings->ticdup <= 0)
|
||||
return false;
|
||||
|
||||
if (settings->extratics < 0)
|
||||
return false;
|
||||
|
||||
if (settings->deathmatch < 0 || settings->deathmatch > 2)
|
||||
return false;
|
||||
|
||||
if (settings->skill < sk_noitems || settings->skill > sk_nightmare)
|
||||
return false;
|
||||
|
||||
if (!D_ValidGameVersion(mission, settings->gameversion))
|
||||
return false;
|
||||
|
||||
if (!D_ValidEpisodeMap(mission, mode, settings->episode, settings->map))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
111
src/net_common.h
Normal file
111
src/net_common.h
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Common code shared between the client and server
|
||||
//
|
||||
|
||||
#ifndef NET_COMMON_H
|
||||
#define NET_COMMON_H
|
||||
|
||||
#include "d_mode.h"
|
||||
#include "doomtype.h"
|
||||
#include "net_defs.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// sending syn packets, waiting for an ACK reply
|
||||
// (client side)
|
||||
|
||||
NET_CONN_STATE_CONNECTING,
|
||||
|
||||
// received a syn, sent an ack, waiting for an ack reply
|
||||
// (server side)
|
||||
|
||||
NET_CONN_STATE_WAITING_ACK,
|
||||
|
||||
// successfully connected
|
||||
|
||||
NET_CONN_STATE_CONNECTED,
|
||||
|
||||
// sent a DISCONNECT packet, waiting for a DISCONNECT_ACK reply
|
||||
|
||||
NET_CONN_STATE_DISCONNECTING,
|
||||
|
||||
// client successfully disconnected
|
||||
|
||||
NET_CONN_STATE_DISCONNECTED,
|
||||
|
||||
// We are disconnected, but in a sleep state, waiting for several
|
||||
// seconds. This is in case the DISCONNECT_ACK we sent failed
|
||||
// to arrive, and we need to send another one. We keep this as
|
||||
// a valid connection for a few seconds until we are sure that
|
||||
// the other end has successfully disconnected as well.
|
||||
|
||||
NET_CONN_STATE_DISCONNECTED_SLEEP,
|
||||
|
||||
} net_connstate_t;
|
||||
|
||||
// Reason a connection was terminated
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// As the result of a local disconnect request
|
||||
|
||||
NET_DISCONNECT_LOCAL,
|
||||
|
||||
// As the result of a remote disconnect request
|
||||
|
||||
NET_DISCONNECT_REMOTE,
|
||||
|
||||
// Timeout (no data received in a long time)
|
||||
|
||||
NET_DISCONNECT_TIMEOUT,
|
||||
|
||||
} net_disconnect_reason_t;
|
||||
|
||||
#define MAX_RETRIES 5
|
||||
|
||||
typedef struct net_reliable_packet_s net_reliable_packet_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
net_connstate_t state;
|
||||
net_disconnect_reason_t disconnect_reason;
|
||||
net_addr_t *addr;
|
||||
int last_send_time;
|
||||
int num_retries;
|
||||
int keepalive_send_time;
|
||||
int keepalive_recv_time;
|
||||
net_reliable_packet_t *reliable_packets;
|
||||
int reliable_send_seq;
|
||||
int reliable_recv_seq;
|
||||
} net_connection_t;
|
||||
|
||||
|
||||
void NET_Conn_SendPacket(net_connection_t *conn, net_packet_t *packet);
|
||||
void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr);
|
||||
void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr);
|
||||
boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet,
|
||||
unsigned int *packet_type);
|
||||
void NET_Conn_Disconnect(net_connection_t *conn);
|
||||
void NET_Conn_Run(net_connection_t *conn);
|
||||
net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type);
|
||||
|
||||
// Other miscellaneous common functions
|
||||
|
||||
unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b);
|
||||
boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
|
||||
net_gamesettings_t *settings);
|
||||
|
||||
#endif /* #ifndef NET_COMMON_H */
|
||||
|
||||
73
src/net_dedicated.c
Normal file
73
src/net_dedicated.c
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright(C) 2005-2014 Simon Howard
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// Dedicated server code.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
#include "i_timer.h"
|
||||
#include "m_argv.h"
|
||||
#include "net_sdl.h"
|
||||
#include "net_server.h"
|
||||
|
||||
//
|
||||
// People can become confused about how dedicated servers work. Game
|
||||
// options are specified to the controlling player who is the first to
|
||||
// join a game. Bomb out with an error message if game options are
|
||||
// specified to a dedicated server.
|
||||
//
|
||||
|
||||
static char *not_dedicated_options[] =
|
||||
{
|
||||
"-iwad", "-gameversion", "-nomonsters", "-respawn",
|
||||
"-fast", "-altdeath", "-deathmatch", "-turbo", "-merge", "-af", "-as",
|
||||
"-aa", "-file", "-wart", "-skill", "-episode", "-timer", "-avg", "-warp",
|
||||
"-loadgame", "-longtics", "-extratics", "-dup", NULL,
|
||||
};
|
||||
|
||||
static void CheckForClientOptions(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; not_dedicated_options[i] != NULL; ++i)
|
||||
{
|
||||
if (M_CheckParm(not_dedicated_options[i]) > 0)
|
||||
{
|
||||
I_Error("The command line parameter '%s' was specified to a "
|
||||
"dedicated server.\nGame parameters should be specified "
|
||||
"to the first player to join a server, \nnot to the "
|
||||
"server itself. ",
|
||||
not_dedicated_options[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NET_DedicatedServer(void)
|
||||
{
|
||||
CheckForClientOptions();
|
||||
|
||||
NET_SV_Init();
|
||||
NET_SV_AddModule(&net_sdl_module);
|
||||
NET_SV_RegisterWithMaster();
|
||||
|
||||
while (true)
|
||||
{
|
||||
NET_SV_Run();
|
||||
I_Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user