Merge branch 'master' of github.com:chocolate-doom/chocolate-doom
This commit is contained in:
commit
580096dd8c
34 changed files with 482 additions and 92 deletions
4
.github/workflows/cpp-linter.yml
vendored
4
.github/workflows/cpp-linter.yml
vendored
|
@ -19,9 +19,9 @@ jobs:
|
|||
compiler: [clang]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get install libfluidsynth-dev libpng-dev libsamplerate0-dev libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-net-dev ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install libfluidsynth-dev libpng-dev libsamplerate0-dev libsdl2-dev libsdl2-mixer-dev libsdl2-net-dev ninja-build
|
||||
- name: Run cmake to generate compilation database
|
||||
run: cmake -S . -B . -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=1
|
||||
- uses: cpp-linter/cpp-linter-action@v2
|
||||
|
|
4
.github/workflows/cppcheck.yml
vendored
4
.github/workflows/cppcheck.yml
vendored
|
@ -9,13 +9,13 @@ on:
|
|||
|
||||
jobs:
|
||||
cppcheck:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get install cppcheck
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run cppcheck
|
||||
env:
|
||||
|
|
53
.github/workflows/main.yml
vendored
53
.github/workflows/main.yml
vendored
|
@ -4,6 +4,8 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- "master"
|
||||
tags:
|
||||
- "*"
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
|
@ -33,6 +35,9 @@ jobs:
|
|||
os: macos-latest
|
||||
compiler: clang
|
||||
shell: bash
|
||||
artifacts: true
|
||||
pkg-path: pkg/osx/*.dmg
|
||||
pkg-dir: pkg/osx
|
||||
|
||||
- name: MSYS2 UCRT64
|
||||
os: windows-latest
|
||||
|
@ -40,6 +45,9 @@ jobs:
|
|||
shell: 'msys2 {0}'
|
||||
msystem: ucrt64
|
||||
msys-env: mingw-w64-ucrt-x86_64
|
||||
artifacts: true
|
||||
pkg-path: pkg/win32/*.zip
|
||||
pkg-dir: pkg/win32
|
||||
|
||||
- name: MSYS2 MINGW32
|
||||
os: windows-latest
|
||||
|
@ -47,6 +55,9 @@ jobs:
|
|||
shell: 'msys2 {0}'
|
||||
msystem: mingw32
|
||||
msys-env: mingw-w64-i686
|
||||
artifacts: true
|
||||
pkg-path: pkg/win32/*.zip
|
||||
pkg-dir: pkg/win32
|
||||
|
||||
steps:
|
||||
- name: Install pandoc
|
||||
|
@ -84,7 +95,7 @@ jobs:
|
|||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.config.msystem }}
|
||||
update: false
|
||||
update: true
|
||||
path-type: inherit
|
||||
install: >-
|
||||
autotools
|
||||
|
@ -115,28 +126,30 @@ jobs:
|
|||
PREFIX=`sed -n '/PROGRAM_PREFIX/p' ${PWD}/config.h | cut -d '"' -f 2`
|
||||
make -j4 -C quickcheck check SOURCE_PORT=$PWD/src/${PREFIX}doom
|
||||
|
||||
- name: Package (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
- name: Package
|
||||
if: ${{ matrix.config.artifacts }}
|
||||
run: |
|
||||
cd pkg/osx
|
||||
cd ${{ matrix.config.pkg-dir }}
|
||||
make
|
||||
|
||||
- name: Package (MSYS2)
|
||||
if: runner.os == 'Windows'
|
||||
- name: Upload artifacts
|
||||
if: ${{ matrix.config.artifacts }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.config.name }}
|
||||
path: ${{ matrix.config.pkg-path }}
|
||||
|
||||
- name: Extract Package String
|
||||
if: ${{ contains(github.ref, 'tags') }}
|
||||
run: |
|
||||
cd pkg/win32
|
||||
make
|
||||
PACKAGE_STRING=`sed -n '/PACKAGE_STRING/p' ${PWD}/config.h | cut -d '"' -f 2`
|
||||
echo "PACKAGE_STRING=${PACKAGE_STRING}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifacts (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v3
|
||||
- name: Release
|
||||
if: ${{ contains(github.ref, 'tags') && matrix.config.artifacts }}
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: macOS
|
||||
path: pkg/osx/*.dmg
|
||||
|
||||
- name: Upload artifacts (MSYS2)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Win-${{ matrix.config.msystem }}
|
||||
path: pkg/win32/*.zip
|
||||
name: ${{ env.PACKAGE_STRING }}
|
||||
bodyFile: RELEASE_NOTES.md
|
||||
allowUpdates: true
|
||||
artifacts: ${{ matrix.config.pkg-path }}
|
||||
|
|
|
@ -15,7 +15,7 @@ set(PACKAGE_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
|
|||
set(PACKAGE_BUGREPORT "https://github.com/fabiangreffrath/crispy-doom/issues")
|
||||
|
||||
string(REGEX REPLACE " Doom$" "" PACKAGE_SHORTNAME "${PACKAGE_NAME}")
|
||||
set(PACKAGE_COPYRIGHT "Copyright (C) 1993-2023")
|
||||
set(PACKAGE_COPYRIGHT "Copyright (C) 1993-2024")
|
||||
set(PACKAGE_LICENSE "GNU General Public License, version 2")
|
||||
|
||||
# Any settings that should apply to all targets in this directory and all
|
||||
|
|
|
@ -26,7 +26,7 @@ of compatibility:
|
|||
|
||||
* DOS Doom 1.9 (although there are actually multiple “1.9”s).
|
||||
* DOS Heretic 1.3.
|
||||
* DOS Hexen 1.1.
|
||||
* DOS Hexen 1.1 (although there are actually two known “1.1”s).
|
||||
* DOS Strife 1.31.
|
||||
* DOS Chex Quest.
|
||||
|
||||
|
|
1
RELEASE_NOTES.md
Normal file
1
RELEASE_NOTES.md
Normal file
|
@ -0,0 +1 @@
|
|||
Test
|
15
configure.ac
15
configure.ac
|
@ -3,7 +3,7 @@ AC_INIT(Crispy Doom, 6.0.0,
|
|||
|
||||
PACKAGE_SHORTNAME=${PACKAGE_NAME% Doom}
|
||||
PACKAGE_SHORTDESC="Limit-removing enhanced-resolution Doom source port"
|
||||
PACKAGE_COPYRIGHT="Copyright (C) 1993-2023"
|
||||
PACKAGE_COPYRIGHT="Copyright (C) 1993-2024"
|
||||
PACKAGE_LICENSE="GNU General Public License, version 2"
|
||||
PACKAGE_MAINTAINER="Fabian Greffrath"
|
||||
PACKAGE_URL="http://fabiangreffrath.github.io/crispy-doom"
|
||||
|
@ -31,6 +31,19 @@ then
|
|||
CFLAGS="-O$OPT_LEVEL -g $WARNINGS $orig_CFLAGS"
|
||||
fi
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
TARGET_OS=""
|
||||
AS_CASE([$target_cpu],
|
||||
[x86_64|aarch64*],
|
||||
[
|
||||
TARGET_OS="64"
|
||||
],
|
||||
[i?86|arm*],
|
||||
[
|
||||
TARGET_OS="32"
|
||||
])
|
||||
AC_SUBST([TARGET_OS])
|
||||
|
||||
PKG_CHECK_MODULES(SDL, [sdl2 >= 2.0.14])
|
||||
# Check for SDL2_mixer
|
||||
AC_ARG_ENABLE([sdl2mixer],
|
||||
|
|
|
@ -27,6 +27,9 @@ _@PROGRAM_SPREFIX@_hexen()
|
|||
esac
|
||||
|
||||
case $prev in
|
||||
-gameversion)
|
||||
COMPREPLY=(1.1 1.1r2)
|
||||
;;
|
||||
-setmem)
|
||||
COMPREPLY=(dos622 dos71 dosbox)
|
||||
;;
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
.TH @PROGRAM_SPREFIX@\-doom.cfg 5
|
||||
.TH @PROGRAM_SPREFIX@\-@GAME@.cfg 5
|
||||
.SH NAME
|
||||
@PROGRAM_SPREFIX@\-doom.cfg \- @PACKAGE_NAME@ configuration file
|
||||
@PROGRAM_SPREFIX@\-@GAME@.cfg \- @PACKAGE_SHORTNAME@ @GAME_UPPER@ configuration file
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fI@PROGRAM_SPREFIX@\-doom.cfg\fR
|
||||
is a configuration file for \fB@PROGRAM_SPREFIX@\-doom\fR(6). This file acts
|
||||
\fI@PROGRAM_SPREFIX@\-@GAME@.cfg\fR
|
||||
is a configuration file for \fB@PROGRAM_SPREFIX@\-@GAME@\fR(6). This file acts
|
||||
as an auxiliary configuration file; the main configuration options
|
||||
are stored in \fBdefault.cfg\fR, which contains the same configuration
|
||||
options as Vanilla Doom (for compatibility). \fI@PROGRAM_SPREFIX@\-doom.cfg\fR
|
||||
contains configuration options that are specific to @PACKAGE_NAME@
|
||||
are stored in \fB@CFGFILE@\fR, which contains the same configuration
|
||||
options as Vanilla @GAME_UPPER@ (for compatibility). \fI@PROGRAM_SPREFIX@\-@GAME@.cfg\fR
|
||||
contains configuration options that are specific to @PACKAGE_SHORTNAME@\-@GAME_UPPER@
|
||||
only.
|
||||
.PP
|
||||
\fI@PROGRAM_SPREFIX@\-doom.cfg\fR is normally stored in the user's home directory,
|
||||
as \fI~/.local/share/@PROGRAM_SPREFIX@\-doom/@PROGRAM_SPREFIX@\-doom.cfg\fR. The path can be
|
||||
\fI@PROGRAM_SPREFIX@\-@GAME@.cfg\fR is normally stored in the user's home directory,
|
||||
as \fI~/.local/share/@PROGRAM_SPREFIX@\-@GAME@/@PROGRAM_SPREFIX@\-@GAME@.cfg\fR. The path can be
|
||||
overridden using the \fBXDG_DATA_HOME\fR environment variable (see the XDG
|
||||
Base Directory Specification).
|
||||
.PP
|
||||
The \fB@PROGRAM_SPREFIX@\-setup\fR(6) tool provides a simple to use front-end
|
||||
for editing \fI@PROGRAM_SPREFIX@\-doom.cfg\fR.
|
||||
The \fB@PROGRAM_SPREFIX@\-@GAME@\-setup\fR(6) tool provides a simple to use front-end
|
||||
for editing \fI@PROGRAM_SPREFIX@\-@GAME@.cfg\fR.
|
||||
.SH FILE FORMAT
|
||||
.PP
|
||||
The file format is the same as that used for \fBdefault.cfg\fR(5).
|
||||
The file format is the same as that used for \fB@CFGFILE@\fR(5).
|
||||
.br
|
||||
|
||||
@content
|
||||
|
||||
.SH SEE ALSO
|
||||
\fB@PROGRAM_SPREFIX@\-doom\fR(6),
|
||||
\fBdefault.cfg\fR(5),
|
||||
\fB@PROGRAM_SPREFIX@\-setup\fR(6)
|
||||
\fB@PROGRAM_SPREFIX@\-@GAME@\fR(6),
|
||||
\fB@CFGFILE@\fR(5),
|
||||
\fB@PROGRAM_SPREFIX@\-@GAME@\-setup\fR(6)
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ PACKAGE_STRING = @PACKAGE_STRING@
|
|||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
TARGET_OS = @TARGET_OS@
|
||||
|
||||
# Documentation files to distribute with packages.
|
||||
|
||||
DOC_FILES = README.md \
|
||||
|
|
|
@ -3,11 +3,10 @@ include ../config.make
|
|||
|
||||
TOPLEVEL=../..
|
||||
|
||||
SYS:=$(shell uname)
|
||||
ifneq (, $(findstring MINGW64, $(SYS)))
|
||||
POSTFIX=win64
|
||||
ifeq ($(TARGET_OS),64)
|
||||
POSTFIX=win64
|
||||
else
|
||||
POSTFIX=win32
|
||||
POSTFIX=win32
|
||||
endif
|
||||
|
||||
DOOM_ZIP=$(PROGRAM_PREFIX)doom-$(PACKAGE_VERSION)-$(POSTFIX).zip
|
||||
|
|
|
@ -134,6 +134,7 @@ static struct {
|
|||
{ doom, exe_chex },
|
||||
{ heretic, exe_heretic_1_3 },
|
||||
{ hexen, exe_hexen_1_1 },
|
||||
{ hexen, exe_hexen_1_1r2 },
|
||||
{ strife, exe_strife_1_2 },
|
||||
{ strife, exe_strife_1_31 },
|
||||
};
|
||||
|
|
|
@ -73,6 +73,7 @@ typedef enum
|
|||
exe_heretic_1_3, // Heretic 1.3
|
||||
|
||||
exe_hexen_1_1, // Hexen 1.1
|
||||
exe_hexen_1_1r2, // Hexen 1.1 (alternate exe)
|
||||
exe_strife_1_2, // Strife v1.2
|
||||
exe_strife_1_31 // Strife v1.31
|
||||
} GameVersion_t;
|
||||
|
|
|
@ -1110,7 +1110,7 @@ void PrintDehackedBanners(void)
|
|||
}
|
||||
}
|
||||
|
||||
static struct
|
||||
static const struct
|
||||
{
|
||||
const char *description;
|
||||
const char *cmdline;
|
||||
|
@ -1140,11 +1140,11 @@ static void InitGameVersion(void)
|
|||
int i;
|
||||
boolean status;
|
||||
|
||||
//!
|
||||
//!
|
||||
// @arg <version>
|
||||
// @category compat
|
||||
//
|
||||
// Emulate a specific version of Doom. Valid values are "1.2",
|
||||
// Emulate a specific version of Doom. Valid values are "1.2",
|
||||
// "1.666", "1.7", "1.8", "1.9", "ultimate", "final", "final2",
|
||||
// "hacx" and "chex".
|
||||
//
|
||||
|
@ -1161,8 +1161,8 @@ static void InitGameVersion(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameversions[i].description == NULL)
|
||||
|
||||
if (gameversions[i].description == NULL)
|
||||
{
|
||||
printf("Supported game versions:\n");
|
||||
|
||||
|
@ -1171,7 +1171,7 @@ static void InitGameVersion(void)
|
|||
printf("\t%s (%s)\n", gameversions[i].cmdline,
|
||||
gameversions[i].description);
|
||||
}
|
||||
|
||||
|
||||
I_Error("Unknown game version '%s'", myargv[p+1]);
|
||||
}
|
||||
}
|
||||
|
@ -1260,7 +1260,7 @@ static void InitGameVersion(void)
|
|||
{
|
||||
deathmatch = 1;
|
||||
}
|
||||
|
||||
|
||||
// The original exe does not support retail - 4th episode not supported
|
||||
|
||||
if (gameversion < exe_ultimate && gamemode == retail)
|
||||
|
|
|
@ -320,6 +320,12 @@ static int G_NextWeapon(int direction)
|
|||
}
|
||||
}
|
||||
|
||||
// The current weapon must be present in weapon_order_table
|
||||
// otherwise something has gone terribly wrong
|
||||
if (i >= arrlen(weapon_order_table)) {
|
||||
I_Error("Internal error: weapon %d not present in weapon_order_table", weapon);
|
||||
}
|
||||
|
||||
// Switch weapon. Don't loop forever.
|
||||
start_i = i;
|
||||
do
|
||||
|
|
|
@ -64,6 +64,9 @@ void G_DoSaveGame(void);
|
|||
void D_PageTicker(void);
|
||||
void D_AdvanceDemo(void);
|
||||
|
||||
static boolean InventoryMoveLeft();
|
||||
static boolean InventoryMoveRight();
|
||||
|
||||
struct
|
||||
{
|
||||
int type; // mobjtype_t
|
||||
|
@ -272,6 +275,12 @@ static int G_NextWeapon(int direction)
|
|||
}
|
||||
}
|
||||
|
||||
// The current weapon must be present in weapon_order_table
|
||||
// otherwise something has gone terribly wrong
|
||||
if (i >= arrlen(weapon_order_table)) {
|
||||
I_Error("Internal error: weapon %d not present in weapon_order_table", weapon);
|
||||
}
|
||||
|
||||
// Switch weapon. Don't loop forever.
|
||||
start_i = i;
|
||||
do
|
||||
|
@ -574,15 +583,15 @@ void G_BuildTiccmd(ticcmd_t *cmd, int maketic)
|
|||
// haleyjd: removed externdriver crap
|
||||
|
||||
// Fly up/down/drop keys
|
||||
if (gamekeydown[key_flyup])
|
||||
if (gamekeydown[key_flyup] || joybuttons[joybflyup])
|
||||
{
|
||||
flyheight = 5; // note that the actual flyheight will be twice this
|
||||
}
|
||||
if (gamekeydown[key_flydown])
|
||||
if (gamekeydown[key_flydown] || joybuttons[joybflydown])
|
||||
{
|
||||
flyheight = -5;
|
||||
}
|
||||
if (gamekeydown[key_flycenter])
|
||||
if (gamekeydown[key_flycenter] || joybuttons[joybflycenter])
|
||||
{
|
||||
flyheight = TOCENTER;
|
||||
// haleyjd: removed externdriver crap
|
||||
|
@ -590,7 +599,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, int maketic)
|
|||
}
|
||||
|
||||
// Use artifact key
|
||||
if (gamekeydown[key_useartifact] || mousebuttons[mousebuseartifact])
|
||||
if (gamekeydown[key_useartifact] || mousebuttons[mousebuseartifact]
|
||||
|| joybuttons[joybuseartifact])
|
||||
{
|
||||
if (gamekeydown[key_speed] && !noartiskip)
|
||||
{
|
||||
|
@ -990,6 +1000,9 @@ void G_DoLoadLevel(void)
|
|||
static void SetJoyButtons(unsigned int buttons_mask)
|
||||
{
|
||||
int i;
|
||||
player_t* plr;
|
||||
|
||||
plr = &players[consoleplayer];
|
||||
|
||||
for (i=0; i<MAX_JOY_BUTTONS; ++i)
|
||||
{
|
||||
|
@ -1009,6 +1022,22 @@ static void SetJoyButtons(unsigned int buttons_mask)
|
|||
{
|
||||
next_weapon = 1;
|
||||
}
|
||||
else if (i == joybinvleft)
|
||||
{
|
||||
InventoryMoveLeft();
|
||||
}
|
||||
else if (i == joybinvright)
|
||||
{
|
||||
InventoryMoveRight();
|
||||
}
|
||||
else if (i == joybuseartifact)
|
||||
{
|
||||
if (!inventory)
|
||||
{
|
||||
plr->readyArtifact = plr->inventory[inv_ptr].type;
|
||||
}
|
||||
usearti = true;
|
||||
}
|
||||
}
|
||||
|
||||
joybuttons[i] = button_on;
|
||||
|
|
|
@ -1222,14 +1222,21 @@ boolean PTR_AimTraverse(intercept_t * in)
|
|||
|
||||
dist = FixedMul(attackrange, in->frac);
|
||||
|
||||
if (li->frontsector->floorheight != li->backsector->floorheight)
|
||||
// Added checks if there is no backsector to prevent crashing.
|
||||
// Crashes didn't happen in the DOS version of Heretic
|
||||
// because reading NULL pointer produces unpredictable but
|
||||
// deterministic values instead of crashing.
|
||||
// See https://github.com/chocolate-doom/chocolate-doom/issues/1665
|
||||
if (li->backsector == NULL
|
||||
|| li->frontsector->floorheight != li->backsector->floorheight)
|
||||
{
|
||||
slope = FixedDiv(openbottom - shootz, dist);
|
||||
if (slope > bottomslope)
|
||||
bottomslope = slope;
|
||||
}
|
||||
|
||||
if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
|
||||
if (li->backsector == NULL
|
||||
|| li->frontsector->ceilingheight != li->backsector->ceilingheight)
|
||||
{
|
||||
slope = FixedDiv(opentop - shootz, dist);
|
||||
if (slope < topslope)
|
||||
|
|
|
@ -1821,7 +1821,7 @@ void A_GauntletAttack(mobj_t *actor, player_t *player, pspdef_t *psp)
|
|||
linetarget->x, linetarget->y);
|
||||
if (angle - player->mo->angle > ANG180)
|
||||
{
|
||||
if (angle - player->mo->angle < -ANG90 / 20)
|
||||
if ((signed int) (angle - player->mo->angle) < -ANG90 / 20)
|
||||
player->mo->angle = angle + ANG90 / 21;
|
||||
else
|
||||
player->mo->angle -= ANG90 / 20;
|
||||
|
|
|
@ -1174,11 +1174,9 @@ void A_SoAExplode(mobj_t *actor, player_t *player, pspdef_t *psp)
|
|||
}
|
||||
if (actor->args[0])
|
||||
{ // Spawn an item
|
||||
#if 0 // Checks are not present in version 1.1
|
||||
if (!nomonsters
|
||||
if ((gameversion != exe_hexen_1_1r2) || !nomonsters
|
||||
|| !(mobjinfo[TranslateThingType[actor->args[0]]].
|
||||
flags & MF_COUNTKILL))
|
||||
#endif
|
||||
{ // Only spawn monsters if not -nomonsters
|
||||
P_SpawnMobj(actor->x, actor->y, actor->z,
|
||||
TranslateThingType[actor->args[0]]);
|
||||
|
|
|
@ -60,6 +60,9 @@ void G_DoSingleReborn(void);
|
|||
void H2_PageTicker(void);
|
||||
void H2_AdvanceDemo(void);
|
||||
|
||||
static boolean InventoryMoveLeft();
|
||||
static boolean InventoryMoveRight();
|
||||
|
||||
|
||||
gameaction_t gameaction;
|
||||
gamestate_t gamestate;
|
||||
|
@ -499,22 +502,23 @@ void G_BuildTiccmd(ticcmd_t *cmd, int maketic)
|
|||
// haleyjd: removed externdriver crap
|
||||
|
||||
// Fly up/down/drop keys
|
||||
if (gamekeydown[key_flyup])
|
||||
if (gamekeydown[key_flyup] || joybuttons[joybflyup])
|
||||
{
|
||||
flyheight = 5; // note that the actual flyheight will be twice this
|
||||
}
|
||||
if (gamekeydown[key_flydown])
|
||||
if (gamekeydown[key_flydown] || joybuttons[joybflydown])
|
||||
{
|
||||
flyheight = -5;
|
||||
}
|
||||
if (gamekeydown[key_flycenter])
|
||||
if (gamekeydown[key_flycenter] || joybuttons[joybflycenter])
|
||||
{
|
||||
flyheight = TOCENTER;
|
||||
// haleyjd: removed externdriver crap
|
||||
look = TOCENTER;
|
||||
}
|
||||
// Use artifact key
|
||||
if (gamekeydown[key_useartifact] || mousebuttons[mousebuseartifact])
|
||||
if (gamekeydown[key_useartifact] || mousebuttons[mousebuseartifact]
|
||||
|| joybuttons[joybuseartifact])
|
||||
{
|
||||
if (gamekeydown[key_speed] && artiskip)
|
||||
{
|
||||
|
@ -522,6 +526,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, int maketic)
|
|||
{ // Skip an artifact
|
||||
gamekeydown[key_useartifact] = false;
|
||||
mousebuttons[mousebuseartifact] = false;
|
||||
joybuttons[joybuseartifact] = false;
|
||||
P_PlayerNextArtifact(&players[consoleplayer]);
|
||||
}
|
||||
}
|
||||
|
@ -920,6 +925,9 @@ void G_DoLoadLevel(void)
|
|||
static void SetJoyButtons(unsigned int buttons_mask)
|
||||
{
|
||||
int i;
|
||||
player_t *plr;
|
||||
|
||||
plr = &players[consoleplayer];
|
||||
|
||||
for (i=0; i<MAX_JOY_BUTTONS; ++i)
|
||||
{
|
||||
|
@ -939,6 +947,22 @@ static void SetJoyButtons(unsigned int buttons_mask)
|
|||
{
|
||||
next_weapon = 1;
|
||||
}
|
||||
else if (i == joybinvleft)
|
||||
{
|
||||
InventoryMoveLeft();
|
||||
}
|
||||
else if (i == joybinvright)
|
||||
{
|
||||
InventoryMoveRight();
|
||||
}
|
||||
else if (i == joybuseartifact)
|
||||
{
|
||||
if (!inventory)
|
||||
{
|
||||
plr->readyArtifact = plr->inventory[inv_ptr].type;
|
||||
}
|
||||
usearti = true;
|
||||
}
|
||||
}
|
||||
|
||||
joybuttons[i] = button_on;
|
||||
|
|
|
@ -93,6 +93,7 @@ static void CrispyDrawStats(void); // [crispy]
|
|||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
GameMode_t gamemode;
|
||||
GameVersion_t gameversion = exe_hexen_1_1;
|
||||
static const char *gamedescription;
|
||||
char *iwadfile;
|
||||
static char demolumpname[9]; // Demo lump to start playing.
|
||||
|
@ -379,6 +380,81 @@ void D_SetGameDescription(void)
|
|||
}
|
||||
}
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *description;
|
||||
const char *cmdline;
|
||||
GameVersion_t version;
|
||||
} gameversions[] = {
|
||||
{"Hexen 1.1", "1.1", exe_hexen_1_1},
|
||||
{"Hexen 1.1 (alt)", "1.1r2", exe_hexen_1_1r2},
|
||||
{ NULL, NULL, 0},
|
||||
};
|
||||
|
||||
// Initialize the game version
|
||||
|
||||
static void InitGameVersion(void)
|
||||
{
|
||||
int p;
|
||||
|
||||
//!
|
||||
// @arg <version>
|
||||
// @category compat
|
||||
//
|
||||
// Emulate a specific version of Hexen.
|
||||
// Valid values are "1.1" and "1.1r2".
|
||||
//
|
||||
|
||||
p = M_CheckParmWithArgs("-gameversion", 1);
|
||||
|
||||
if (p)
|
||||
{
|
||||
int i;
|
||||
for (i=0; gameversions[i].description != NULL; ++i)
|
||||
{
|
||||
if (!strcmp(myargv[p+1], gameversions[i].cmdline))
|
||||
{
|
||||
gameversion = gameversions[i].version;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameversions[i].description == NULL)
|
||||
{
|
||||
printf("Supported game versions:\n");
|
||||
|
||||
for (i=0; gameversions[i].description != NULL; ++i)
|
||||
{
|
||||
printf("\t%s (%s)\n", gameversions[i].cmdline,
|
||||
gameversions[i].description);
|
||||
}
|
||||
|
||||
I_Error("Unknown game version '%s'", myargv[p+1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Determine automatically
|
||||
|
||||
gameversion = exe_hexen_1_1;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintGameVersion(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; gameversions[i].description != NULL; ++i)
|
||||
{
|
||||
if (gameversions[i].version == gameversion)
|
||||
{
|
||||
printf("Emulating the behavior of the "
|
||||
"'%s' executable.\n", gameversions[i].description);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const loadparms[] = {"-file", "-merge", NULL}; // [crispy]
|
||||
|
||||
//==========================================================================
|
||||
|
@ -464,6 +540,7 @@ void D_DoomMain(void)
|
|||
D_AddFile(iwadfile);
|
||||
W_CheckCorrectIWAD(hexen);
|
||||
D_IdentifyVersion();
|
||||
InitGameVersion();
|
||||
D_SetGameDescription();
|
||||
AdjustForMacIWAD();
|
||||
|
||||
|
@ -565,6 +642,8 @@ void D_DoomMain(void)
|
|||
ST_Message("D_CheckNetGame: Checking network game status.\n");
|
||||
D_CheckNetGame();
|
||||
|
||||
PrintGameVersion();
|
||||
|
||||
ST_Message("SB_Init: Loading patches.\n");
|
||||
SB_Init();
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@
|
|||
//#endif
|
||||
#define HEXEN_VERSIONTEXT ((gamemode == shareware) ? \
|
||||
"DEMO 10 16 95" : \
|
||||
(gameversion != exe_hexen_1_1r2) ? \
|
||||
"VERSION 1.1 MAR 12 1996 (CBI)" : \
|
||||
"VERSION 1.1 MAR 22 1996 (BCP)")
|
||||
|
||||
// all exterior data is defined here
|
||||
|
@ -611,7 +613,8 @@ void NET_SendFrags(player_t * player);
|
|||
|
||||
#define TELEFOGHEIGHT (32*FRACUNIT)
|
||||
|
||||
extern GameMode_t gamemode; // Always commercial
|
||||
extern GameMode_t gamemode;
|
||||
extern GameVersion_t gameversion;
|
||||
|
||||
extern gameaction_t gameaction;
|
||||
|
||||
|
|
|
@ -528,6 +528,7 @@ boolean P_LookForPlayers(mobj_t * actor, boolean allaround)
|
|||
player_t *player;
|
||||
angle_t an;
|
||||
fixed_t dist;
|
||||
int consecutive_missing = 0; // for breaking infinite loop
|
||||
|
||||
if (!netgame && players[0].health <= 0)
|
||||
{ // Single player game and player is dead, look for monsters
|
||||
|
@ -535,18 +536,38 @@ boolean P_LookForPlayers(mobj_t * actor, boolean allaround)
|
|||
}
|
||||
c = 0;
|
||||
|
||||
// NOTE: This behavior has been changed from the Vanilla behavior, where
|
||||
// an infinite loop can occur if players 0-3 all quit the game. Although
|
||||
// technically this is not what Vanilla does, fixing this is highly
|
||||
// desirable, and having the game simply lock up is not acceptable.
|
||||
// stop = (actor->lastlook - 1) & 3;
|
||||
// for (;; actor->lastlook = (actor->lastlook + 1) & 3)
|
||||
// The 3 below is probably a mistake (it should be MAXPLAYERS - 1, or 7)
|
||||
// and in vanilla this can potentially cause an infinite loop in
|
||||
// multiplayer. Unfortunately we can't correct the mistake - doing so will
|
||||
// cause desyncs. Upon spawning, each enemy's lastlook is initialized to a
|
||||
// random value between 0 and 7 (i.e MAXPLAYERS - 1). There's a chance
|
||||
// that the first call of this function for that enemy will return early
|
||||
// courtesy of the actor->lastlook == stop condition. In a single-player
|
||||
// game this occurs when (actor->lastlook - 1) & 3 equals 0, or when
|
||||
// lastlook equals 1 or 5.
|
||||
|
||||
stop = (actor->lastlook + maxplayers - 1) % maxplayers;
|
||||
for (;; actor->lastlook = (actor->lastlook + 1) % maxplayers)
|
||||
// If you use MAXPLAYERS - 1, it has the side effect of altering which
|
||||
// enemies are affected by an early actor->lastlook == stop return. Now it
|
||||
// happens when (actor->lastlook - 1) & 7 equals 0, or when lastlook equals
|
||||
// 1, *not* 1 and 5 as above.
|
||||
|
||||
stop = (actor->lastlook - 1) & 3;
|
||||
for (;; actor->lastlook = (actor->lastlook + 1) & 3)
|
||||
{
|
||||
if (!playeringame[actor->lastlook])
|
||||
{
|
||||
// Break the vanilla infinite loop here. It can occur if there are
|
||||
// > 4 players and players 0 - 3 all quit the game. Error out
|
||||
// instead.
|
||||
if (consecutive_missing == 4)
|
||||
{
|
||||
I_Error("P_LookForPlayers: No player 1 - 4.\n");
|
||||
}
|
||||
consecutive_missing++;
|
||||
continue;
|
||||
}
|
||||
|
||||
consecutive_missing = 0;
|
||||
|
||||
if (c++ == 2 || actor->lastlook == stop)
|
||||
return false; // done looking
|
||||
|
|
|
@ -90,7 +90,7 @@ int joystick_look_sensitivity = 10;
|
|||
// 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
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
||||
};
|
||||
|
||||
void I_ShutdownGamepad(void)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
// 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
|
||||
#define NUM_VIRTUAL_BUTTONS 17
|
||||
|
||||
// Max allowed number of virtual mappings. Chosen to be less than joybspeed
|
||||
// autorun value.
|
||||
|
|
|
@ -1529,6 +1529,48 @@ static default_t extra_defaults_list[] =
|
|||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button10),
|
||||
|
||||
//!
|
||||
// The physical joystick button that corresponds to joystick
|
||||
// virtual button #11.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button11),
|
||||
|
||||
//!
|
||||
// The physical joystick button that corresponds to joystick
|
||||
// virtual button #12.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button12),
|
||||
|
||||
//!
|
||||
// The physical joystick button that corresponds to joystick
|
||||
// virtual button #13.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button13),
|
||||
|
||||
//!
|
||||
// The physical joystick button that corresponds to joystick
|
||||
// virtual button #14.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button14),
|
||||
|
||||
//!
|
||||
// The physical joystick button that corresponds to joystick
|
||||
// virtual button #15.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button15),
|
||||
|
||||
//!
|
||||
// The physical joystick button that corresponds to joystick
|
||||
// virtual button #16.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joystick_physical_button16),
|
||||
|
||||
//!
|
||||
// If non-zero, use the SDL_GameController interface instead of the
|
||||
// SDL_Joystick interface.
|
||||
|
@ -1606,6 +1648,48 @@ static default_t extra_defaults_list[] =
|
|||
|
||||
CONFIG_VARIABLE_INT(joyb_nextweapon),
|
||||
|
||||
//!
|
||||
// @game heretic hexen
|
||||
// Joystick virtual button to activate artifact.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joyb_useartifact),
|
||||
|
||||
//!
|
||||
// @game heretic hexen
|
||||
// Joystick virtual button to move left in the inventory.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joyb_invleft),
|
||||
|
||||
//!
|
||||
// @game heretic hexen
|
||||
// Joystick virtual button to move right in the inventory.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joyb_invright),
|
||||
|
||||
//!
|
||||
// @game heretic hexen
|
||||
// Joystick virtual button to fly up.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joyb_flyup),
|
||||
|
||||
//!
|
||||
// @game heretic hexen
|
||||
// Joystick virtual button to fly down.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joyb_flydown),
|
||||
|
||||
//!
|
||||
// @game heretic hexen
|
||||
// Joystick virtual button to center flying.
|
||||
//
|
||||
|
||||
CONFIG_VARIABLE_INT(joyb_flycenter),
|
||||
|
||||
//!
|
||||
// Key to pause or unpause the game.
|
||||
//
|
||||
|
|
|
@ -232,6 +232,14 @@ int joybnextweapon = -1;
|
|||
int joybmenu = -1;
|
||||
int joybautomap = -1;
|
||||
|
||||
int joybuseartifact = -1;
|
||||
int joybinvleft = -1;
|
||||
int joybinvright = -1;
|
||||
|
||||
int joybflyup = -1;
|
||||
int joybflydown = -1;
|
||||
int joybflycenter = -1;
|
||||
|
||||
// Control whether if a mouse button is double clicked, it acts like
|
||||
// "use" has been pressed
|
||||
|
||||
|
@ -317,6 +325,14 @@ void M_BindHereticControls(void)
|
|||
M_BindIntVariable("mouseb_invright", &mousebinvright);
|
||||
M_BindIntVariable("mouseb_useartifact", &mousebuseartifact);
|
||||
|
||||
M_BindIntVariable("joyb_invleft", &joybinvleft);
|
||||
M_BindIntVariable("joyb_invright", &joybinvright);
|
||||
M_BindIntVariable("joyb_useartifact", &joybuseartifact);
|
||||
|
||||
M_BindIntVariable("joyb_flyup", &joybflyup);
|
||||
M_BindIntVariable("joyb_flydown", &joybflydown);
|
||||
M_BindIntVariable("joyb_flycenter", &joybflycenter);
|
||||
|
||||
M_BindIntVariable("key_arti_quartz", &key_arti_quartz);
|
||||
M_BindIntVariable("key_arti_urn", &key_arti_urn);
|
||||
M_BindIntVariable("key_arti_bomb", &key_arti_bomb);
|
||||
|
|
|
@ -191,6 +191,14 @@ extern int joybnextweapon;
|
|||
extern int joybmenu;
|
||||
extern int joybautomap;
|
||||
|
||||
extern int joybuseartifact;
|
||||
extern int joybinvleft;
|
||||
extern int joybinvright;
|
||||
|
||||
extern int joybflyup;
|
||||
extern int joybflydown;
|
||||
extern int joybflycenter;
|
||||
|
||||
extern int dclick_use;
|
||||
|
||||
void M_BindBaseControls(void);
|
||||
|
|
|
@ -323,6 +323,7 @@ static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet,
|
|||
// Create new target.
|
||||
|
||||
target = GetTargetForAddr(addr, true);
|
||||
broadcast_target = GetTargetForAddr(NULL, false);
|
||||
target->state = QUERY_TARGET_QUERIED;
|
||||
target->query_time = broadcast_target->query_time;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ int joystick_look_sensitivity = 10;
|
|||
|
||||
// Virtual to physical mapping.
|
||||
int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
||||
};
|
||||
|
||||
static txt_button_t *joystick_button;
|
||||
|
@ -164,6 +164,12 @@ static const joystick_config_t empty_defaults[] =
|
|||
{"joyb_jump", -1},
|
||||
{"joyb_menu_activate", -1},
|
||||
{"joyb_toggle_automap", -1},
|
||||
{"joyb_useartifact", -1},
|
||||
{"joyb_invleft", -1},
|
||||
{"joyb_invright", -1},
|
||||
{"joyb_flyup", -1},
|
||||
{"joyb_flydown", -1},
|
||||
{"joyb_flycenter", -1},
|
||||
{"joystick_physical_button0", 0},
|
||||
{"joystick_physical_button1", 1},
|
||||
{"joystick_physical_button2", 2},
|
||||
|
@ -174,6 +180,13 @@ static const joystick_config_t empty_defaults[] =
|
|||
{"joystick_physical_button7", 7},
|
||||
{"joystick_physical_button8", 8},
|
||||
{"joystick_physical_button9", 9},
|
||||
{"joystick_physical_button10", 10},
|
||||
{"joystick_physical_button11", 11},
|
||||
{"joystick_physical_button12", 12},
|
||||
{"joystick_physical_button13", 13},
|
||||
{"joystick_physical_button14", 14},
|
||||
{"joystick_physical_button15", 15},
|
||||
{"joystick_physical_button16", 16},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
|
@ -630,6 +643,12 @@ static const joystick_config_t modern_gamepad[] =
|
|||
{"joyb_nextweapon", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||
{"joyb_menu_activate", SDL_CONTROLLER_BUTTON_START},
|
||||
{"joyb_toggle_automap", SDL_CONTROLLER_BUTTON_Y},
|
||||
{"joyb_useartifact", SDL_CONTROLLER_BUTTON_X},
|
||||
{"joyb_invleft", SDL_CONTROLLER_BUTTON_DPAD_LEFT},
|
||||
{"joyb_invright", SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
|
||||
{"joyb_flyup", SDL_CONTROLLER_BUTTON_DPAD_UP},
|
||||
{"joyb_flydown", SDL_CONTROLLER_BUTTON_DPAD_DOWN},
|
||||
{"joyb_flycenter", SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
|
@ -1167,13 +1186,35 @@ static void AdjustAnalog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
|
|||
TXT_SetWidgetAlign(window, TXT_HORIZ_CENTER);
|
||||
}
|
||||
|
||||
static void MoreControls(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
|
||||
{
|
||||
txt_window_t *window;
|
||||
|
||||
window = TXT_NewWindow("Additional Gamepad/Joystick buttons");
|
||||
TXT_SetTableColumns(window, 6);
|
||||
TXT_SetColumnWidths(window, 18, 10, 1, 18, 10, 0);
|
||||
|
||||
AddJoystickControl(window, "Use artifact", &joybuseartifact);
|
||||
AddJoystickControl(window, "Inventory left", &joybinvleft);
|
||||
AddJoystickControl(window, "Inventory right", &joybinvright);
|
||||
AddJoystickControl(window, "Fly up", &joybflyup);
|
||||
AddJoystickControl(window, "Fly down", &joybflydown);
|
||||
AddJoystickControl(window, "Fly center", &joybflycenter);
|
||||
|
||||
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
|
||||
TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
|
||||
TXT_NewWindowEscapeAction(window));
|
||||
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
|
||||
TXT_SetWidgetAlign(window, TXT_HORIZ_CENTER);
|
||||
}
|
||||
|
||||
void ConfigJoystick(TXT_UNCAST_ARG(widget), void *user_data)
|
||||
{
|
||||
txt_window_t *window;
|
||||
|
||||
window = TXT_NewWindow("Gamepad/Joystick configuration");
|
||||
TXT_SetTableColumns(window, 6);
|
||||
TXT_SetColumnWidths(window, 18, 10, 1, 15, 10, 0);
|
||||
TXT_SetColumnWidths(window, 18, 10, 1, 18, 10, 0);
|
||||
TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
|
||||
|
||||
TXT_AddWidgets(window,
|
||||
|
@ -1269,6 +1310,13 @@ void ConfigJoystick(TXT_UNCAST_ARG(widget), void *user_data)
|
|||
|
||||
AddJoystickControl(window, "Toggle Automap", &joybautomap);
|
||||
|
||||
if (gamemission == heretic || gamemission == hexen)
|
||||
{
|
||||
TXT_AddWidget(window,
|
||||
TXT_NewButton2("More controls...", MoreControls, NULL));
|
||||
TXT_AddWidget(window, TXT_TABLE_EOL);
|
||||
}
|
||||
|
||||
TXT_SignalConnect(joystick_button, "pressed", CalibrateJoystick, window);
|
||||
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction());
|
||||
|
||||
|
|
|
@ -58,6 +58,12 @@ static int *all_joystick_buttons[NUM_VIRTUAL_BUTTONS] =
|
|||
&joybjump,
|
||||
&joybmenu,
|
||||
&joybautomap,
|
||||
&joybuseartifact,
|
||||
&joybinvleft,
|
||||
&joybinvright,
|
||||
&joybflyup,
|
||||
&joybflydown,
|
||||
&joybflycenter,
|
||||
};
|
||||
|
||||
// For indirection so that we're not dependent on item ordering in the
|
||||
|
|
|
@ -1095,7 +1095,7 @@ void PrintDehackedBanners(void)
|
|||
}
|
||||
}
|
||||
|
||||
static struct
|
||||
static const struct
|
||||
{
|
||||
const char *description;
|
||||
const char *cmdline;
|
||||
|
@ -1111,9 +1111,8 @@ static struct
|
|||
static void InitGameVersion(void)
|
||||
{
|
||||
int p;
|
||||
int i;
|
||||
|
||||
// haleyjd: we support emulating either the 1.2 or the 1.31 versions of
|
||||
// haleyjd: we support emulating either the 1.2 or the 1.31 versions of
|
||||
// Strife, which are the most significant. 1.2 is the most mature version
|
||||
// that still has the single saveslot restriction, whereas 1.31 is the
|
||||
// final revision. The differences between the two are barely worth
|
||||
|
@ -1130,6 +1129,7 @@ static void InitGameVersion(void)
|
|||
|
||||
if (p)
|
||||
{
|
||||
int i;
|
||||
for (i=0; gameversions[i].description != NULL; ++i)
|
||||
{
|
||||
if (!strcmp(myargv[p+1], gameversions[i].cmdline))
|
||||
|
@ -1139,7 +1139,7 @@ static void InitGameVersion(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (gameversions[i].description == NULL)
|
||||
if (gameversions[i].description == NULL)
|
||||
{
|
||||
printf("Supported game versions:\n");
|
||||
|
||||
|
|
|
@ -313,6 +313,12 @@ static int G_NextWeapon(int direction)
|
|||
}
|
||||
}
|
||||
|
||||
// The current weapon must be present in weapon_order_table
|
||||
// otherwise something has gone terribly wrong
|
||||
if (i >= arrlen(weapon_order_table)) {
|
||||
I_Error("Internal error: weapon %d not present in weapon_order_table", weapon);
|
||||
}
|
||||
|
||||
// Switch weapon.
|
||||
start_i = i;
|
||||
do
|
||||
|
|
|
@ -737,6 +737,7 @@ P_LookForPlayers
|
|||
angle_t an;
|
||||
fixed_t dist;
|
||||
mobj_t * master = players[actor->miscdata].mo;
|
||||
int consecutive_missing = 0; // for breaking infinite loop
|
||||
|
||||
// haleyjd 09/05/10: handle Allies
|
||||
if(actor->flags & MF_ALLY)
|
||||
|
@ -794,19 +795,39 @@ P_LookForPlayers
|
|||
|
||||
c = 0;
|
||||
|
||||
// NOTE: This behavior has been changed from the Vanilla behavior, where
|
||||
// an infinite loop can occur if players 0-3 all quit the game. Although
|
||||
// technically this is not what Vanilla does, fixing this is highly
|
||||
// desirable, and having the game simply lock up is not acceptable.
|
||||
// stop = (actor->lastlook - 1) & 3;
|
||||
// for (;; actor->lastlook = (actor->lastlook + 1) & 3)
|
||||
// The 3 below is probably a mistake (it should be MAXPLAYERS - 1, or 7)
|
||||
// and in vanilla this can potentially cause an infinite loop in
|
||||
// multiplayer. Unfortunately we can't correct the mistake - doing so will
|
||||
// cause desyncs. Upon spawning, each enemy's lastlook is initialized to a
|
||||
// random value between 0 and 7 (i.e MAXPLAYERS - 1). There's a chance
|
||||
// that the first call of this function for that enemy will return early
|
||||
// courtesy of the actor->lastlook == stop condition. In a single-player
|
||||
// game this occurs when (actor->lastlook - 1) & 3 equals 0, or when
|
||||
// lastlook equals 1 or 5.
|
||||
|
||||
stop = (actor->lastlook + MAXPLAYERS - 1) % MAXPLAYERS;
|
||||
// If you use MAXPLAYERS - 1, it has the side effect of altering which
|
||||
// enemies are affected by an early actor->lastlook == stop return. Now it
|
||||
// happens when (actor->lastlook - 1) & 7 equals 0, or when lastlook equals
|
||||
// 1, *not* 1 and 5 as above.
|
||||
|
||||
for ( ; ; actor->lastlook = (actor->lastlook + 1) % MAXPLAYERS)
|
||||
stop = (actor->lastlook-1)&3;
|
||||
|
||||
for ( ; ; actor->lastlook = (actor->lastlook+1)&3 )
|
||||
{
|
||||
if (!playeringame[actor->lastlook])
|
||||
{
|
||||
// Break the vanilla infinite loop here. It can occur if there are
|
||||
// > 4 players and players 0 - 3 all quit the game. Error out
|
||||
// instead.
|
||||
if (consecutive_missing == 4)
|
||||
{
|
||||
I_Error("P_LookForPlayers: No player 1 - 4.\n");
|
||||
}
|
||||
consecutive_missing++;
|
||||
continue;
|
||||
}
|
||||
|
||||
consecutive_missing = 0;
|
||||
|
||||
if (c++ == 2
|
||||
|| actor->lastlook == stop)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue