Merge remote-tracking branch 'refs/remotes/origin/master' into save-mode

This commit is contained in:
TehRealSalt 2017-07-30 11:13:52 -04:00
commit 0b05b10bdb
129 changed files with 7979 additions and 4429 deletions

63
.circleci/config.yml Normal file
View file

@ -0,0 +1,63 @@
version: 2
jobs:
build:
working_directory: /root/SRB2
docker:
- image: debian:jessie
environment:
CC: ccache gcc -m32
PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
LIBGME_CFLAGS: -I/usr/include
LIBGME_LDFLAGS: -lgme
CCACHE_COMPRESS: true
WFLAGS: -Wno-unsuffixed-float-constants
GCC49: true
#- image: ubuntu:trusty
# environment:
# CC: ccache gcc -m32
# PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
# LIBGME_CFLAGS: -I/usr/include
# LIBGME_LDFLAGS: -lgme
# CCACHE_COMPRESS: true
# WFLAGS: -Wno-unsuffixed-float-constants
# GCC48: true
steps:
- run:
name: Add i386 arch
command: dpkg --add-architecture i386
- run:
name: Update APT listing
command: apt-get -qq update
- run:
name: Support S3 upload
command: apt-get -qq -y install ca-certificates
- restore_cache:
keys:
- v1-SRB2-APT
- run:
name: Install SDK
command: apt-get -qq -y install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx
- save_cache:
key: v1-SRB2-APT
paths:
- /var/cache/apt/archives
- checkout
- run:
name: Clean build
command: make -C src LINUX=1 clean
- restore_cache:
keys:
- v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
- run:
name: Compile
command: make -C src LINUX=1 ERRORMODE=1 -k
- store_artifacts:
path: /root/SRB2/bin/Linux/Release/
destination: bin
- save_cache:
key: v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
paths:
- /root/.ccache

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(SRB2 project(SRB2
VERSION 2.1.17 VERSION 2.1.19
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -2,6 +2,7 @@
[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2) [![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2) [![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
[![CircleCI](https://circleci.com/gh/STJr/SRB2/tree/master.svg?style=svg)](https://circleci.com/gh/STJr/SRB2/tree/master)
[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/). [Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).

View file

@ -1,4 +1,4 @@
version: 2.1.17.{branch}-{build} version: 2.1.19.{branch}-{build}
os: MinGW os: MinGW
environment: environment:
@ -47,7 +47,7 @@ before_build:
- upx -V - upx -V
- ccache -V - ccache -V
- ccache -s - ccache -s
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1 - set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1 NOOBJDUMP=1
build_script: build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean - cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
@ -58,26 +58,29 @@ after_build:
- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt - cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt - cmd: set /P GITSHORT=<%TMP%/gitshort.txt
- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z - set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
- cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore - cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore
- appveyor PushArtifact %BUILD_ARCHIVE% - appveyor PushArtifact %BUILD_ARCHIVE%
- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
- appveyor PushArtifact %BUILDSARCHIVE%
test: off test: off
deploy: #deploy:
- provider: FTP # - provider: FTP
protocol: ftps # protocol: ftps
host: # host:
secure: NsLJEPIBvmwCOj8Tg8RoRQ== # secure: NsLJEPIBvmwCOj8Tg8RoRQ==
username: # username:
secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA= # secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
password: # password:
secure: Hbn6Uy3lT0YZ88yFJ3aW4w== # secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
folder: appveyor # folder: appveyor
application: # application:
active_mode: false # active_mode: false
on: # on:
branch: master # branch: master
appveyor_repo_tag: true # appveyor_repo_tag: true
on_finish: on_finish:

View file

@ -1,3 +1,3 @@
/srb2sdl.exe *.exe
/srb2win.exe *.mo
/r_opengl.dll r_opengl.dll

View file

@ -1,3 +1,3 @@
/srb2sdl.exe *.exe
/srb2win.exe *.mo
/r_opengl.dll r_opengl.dll

8
objs/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
#All folders
SRB2.res
depend.dep
depend.ped
*.o
#VC9 folder only
/VC9/Win32
/VC9/x64

View file

@ -1 +1,2 @@
/depend.dep # DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep # DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,3 +1,2 @@
/SRB2.res # DON'T REMOVE
/depend.dep # This keeps the folder from disappearing
/*.o

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep # DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.ped # DON'T REMOVE
# This keeps the folder from disappearing

2
objs/VC/.gitignore vendored
View file

@ -0,0 +1,2 @@
# DON'T REMOVE
# This keeps the folder from disappearing

4
objs/VC9/.gitignore vendored
View file

@ -1,2 +1,2 @@
/Win32 # DON'T REMOVE
/x64 # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep # DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep # DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep # DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep # DON'T REMOVE
/*.o # This keeps the folder from disappearing

View file

@ -511,13 +511,11 @@ OBJS:=$(i_main_o) \
# For reference, this is the command I use to build a srb2.pot file from the source code. # For reference, this is the command I use to build a srb2.pot file from the source code.
# (The listed source files are the ones containing translated strings). # (The listed source files are the ones containing translated strings).
# FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES # FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES
ifndef NOGETTEXT
ifdef GETTEXT ifdef GETTEXT
POS:=$(BIN)/en.mo POS:=$(BIN)/en.mo
OPTS+=-DGETTEXT OPTS+=-DGETTEXT
endif endif
endif
ifdef DJGPPDOS ifdef DJGPPDOS
all: pre-build $(BIN)/$(EXENAME) all: pre-build $(BIN)/$(EXENAME)

View file

@ -283,9 +283,6 @@ else
ifdef LINUX ifdef LINUX
NASMFORMAT=elf -DLINUX NASMFORMAT=elf -DLINUX
SDL=1 SDL=1
ifndef NOGETTEXT
GETTEXT=1
endif
ifdef LINUX64 ifdef LINUX64
OBJDIR:=$(OBJDIR)/Linux64 OBJDIR:=$(OBJDIR)/Linux64
BIN:=$(BIN)/Linux64 BIN:=$(BIN)/Linux64
@ -321,9 +318,6 @@ else
ifdef MINGW64 ifdef MINGW64
INTERFACE=win32 INTERFACE=win32
#NASMFORMAT=win64 #NASMFORMAT=win64
ifndef NOGETTEXT
#GETTEXT=1
endif
OBJDIR:=$(OBJDIR)/Mingw64 OBJDIR:=$(OBJDIR)/Mingw64
BIN:=$(BIN)/Mingw64 BIN:=$(BIN)/Mingw64
else else
@ -354,9 +348,6 @@ else
ifdef MINGW ifdef MINGW
INTERFACE=win32 INTERFACE=win32
NASMFORMAT=win32 NASMFORMAT=win32
ifndef NOGETTEXT
GETTEXT=1
endif
OBJDIR:=$(OBJDIR)/Mingw OBJDIR:=$(OBJDIR)/Mingw
BIN:=$(BIN)/Mingw BIN:=$(BIN)/Mingw
else else

View file

@ -212,7 +212,7 @@ boolean B_CheckRespawn(player_t *player)
// Check if Sonic is busy first. // Check if Sonic is busy first.
// If he's doing any of these things, he probably doesn't want to see us. // If he's doing any of these things, he probably doesn't want to see us.
if (sonic->player->pflags & (PF_GLIDING|PF_SLIDING|PF_NIGHTSMODE) if (sonic->player->pflags & (PF_GLIDING|PF_SLIDING|PF_BOUNCING)
|| (sonic->player->panim != PA_IDLE && sonic->player->panim != PA_WALK) || (sonic->player->panim != PA_IDLE && sonic->player->panim != PA_WALK)
|| (sonic->player->powers[pw_carry])) || (sonic->player->powers[pw_carry]))
return false; return false;

View file

@ -1165,7 +1165,7 @@ found:
if (var == &cv_forceskin) if (var == &cv_forceskin)
{ {
var->value = R_SkinAvailable(var->string); var->value = R_SkinAvailable(var->string);
if (!R_SkinUnlock(var->value)) if (!R_SkinUsable(-1, var->value))
var->value = -1; var->value = -1;
} }
else else
@ -1361,6 +1361,16 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
return; return;
} }
if (var == &cv_forceskin)
{
INT32 skin = R_SkinAvailable(value);
if ((stricmp(value, "None")) && ((skin == -1) || !R_SkinUsable(-1, skin)))
{
CONS_Printf("Please provide a valid skin name (\"None\" disables).\n");
return;
}
}
// Only add to netcmd buffer if in a netgame, otherwise, just change it. // Only add to netcmd buffer if in a netgame, otherwise, just change it.
if (netgame || multiplayer) if (netgame || multiplayer)
{ {
@ -1478,7 +1488,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
else if (newvalue >= numskins) else if (newvalue >= numskins)
newvalue = -1; newvalue = -1;
} while ((oldvalue != newvalue) } while ((oldvalue != newvalue)
&& !(R_SkinUnlock(newvalue))); && !(R_SkinUsable(-1, newvalue)));
} }
else else
newvalue = var->value + increment; newvalue = var->value + increment;
@ -1551,34 +1561,27 @@ void CV_AddValue(consvar_t *var, INT32 increment)
if (var == &cv_chooseskin) if (var == &cv_chooseskin)
{ {
// Special case for the chooseskin variable, used only directly from the menu // Special case for the chooseskin variable, used only directly from the menu
if (increment > 0) // Going up! newvalue = var->value - 1;
do
{ {
newvalue = var->value - 1; if (increment > 0) // Going up!
do
{ {
newvalue++; newvalue++;
if (newvalue == MAXSKINS) if (newvalue == MAXSKINS)
newvalue = 0; newvalue = 0;
} while (var->PossibleValue[newvalue].strvalue == NULL); }
var->value = newvalue + 1; else if (increment < 0) // Going down!
var->string = var->PossibleValue[newvalue].strvalue;
var->func();
return;
}
else if (increment < 0) // Going down!
{
newvalue = var->value - 1;
do
{ {
newvalue--; newvalue--;
if (newvalue == -1) if (newvalue == -1)
newvalue = MAXSKINS-1; newvalue = MAXSKINS-1;
} while (var->PossibleValue[newvalue].strvalue == NULL); }
var->value = newvalue + 1; } while (var->PossibleValue[newvalue].strvalue == NULL);
var->string = var->PossibleValue[newvalue].strvalue;
var->func(); var->value = newvalue + 1;
return; var->string = var->PossibleValue[newvalue].strvalue;
} var->func();
return;
} }
#ifdef PARANOIA #ifdef PARANOIA
if (currentindice == -1) if (currentindice == -1)

View file

@ -1394,32 +1394,32 @@ static void CON_DrawInput(void)
if (input_sel < c) if (input_sel < c)
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART); V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART);
for (i = 0; i < 3; ++i, x += charwidth) for (i = 0; i < 3; ++i, x += charwidth)
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, true);
} }
else else
V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, true);
for (cend = c + clen; c < cend; ++c, x += charwidth) for (cend = c + clen; c < cend; ++c, x += charwidth)
{ {
if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c)) if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c))
{ {
V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 77 | V_NOSCALESTART); V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 77 | V_NOSCALESTART);
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, true);
} }
else else
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, true);
if (c == input_cur && con_tick >= 4) if (c == input_cur && con_tick >= 4)
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, true);
} }
if (cend == input_cur && con_tick >= 4) if (cend == input_cur && con_tick >= 4)
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, true);
if (rellip) if (rellip)
{ {
if (input_sel > cend) if (input_sel > cend)
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART); V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART);
for (i = 0; i < 3; ++i, x += charwidth) for (i = 0; i < 3; ++i, x += charwidth)
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, true);
} }
} }
@ -1465,11 +1465,11 @@ static void CON_DrawHudlines(void)
else else
{ {
//charwidth = SHORT(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor; //charwidth = SHORT(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
} }
} }
//V_DrawCharacter(x, y, (p[c]&0xff) | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); //V_DrawCharacter(x, y, (p[c]&0xff) | cv_constextsize.value | V_NOSCALESTART, true);
y += charheight; y += charheight;
} }
@ -1607,7 +1607,7 @@ static void CON_DrawConsole(void)
charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; charflags = (*p & 0x7f) << V_CHARCOLORSHIFT;
p++; p++;
} }
V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
} }
} }

View file

@ -528,6 +528,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->skincolor = players[i].skincolor; rsp->skincolor = players[i].skincolor;
rsp->skin = LONG(players[i].skin); rsp->skin = LONG(players[i].skin);
rsp->availabilities = LONG(players[i].availabilities);
// Just in case Lua does something like // Just in case Lua does something like
// modify these at runtime // modify these at runtime
rsp->camerascale = (fixed_t)LONG(players[i].camerascale); rsp->camerascale = (fixed_t)LONG(players[i].camerascale);
@ -551,7 +552,6 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->playerspinheight = (fixed_t)LONG(players[i].spinheight); rsp->playerspinheight = (fixed_t)LONG(players[i].spinheight);
rsp->speed = (fixed_t)LONG(players[i].speed); rsp->speed = (fixed_t)LONG(players[i].speed);
rsp->jumping = players[i].jumping;
rsp->secondjump = players[i].secondjump; rsp->secondjump = players[i].secondjump;
rsp->fly1 = players[i].fly1; rsp->fly1 = players[i].fly1;
rsp->glidetime = (tic_t)LONG(players[i].glidetime); rsp->glidetime = (tic_t)LONG(players[i].glidetime);
@ -657,6 +657,7 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].skincolor = rsp->skincolor; players[i].skincolor = rsp->skincolor;
players[i].skin = LONG(rsp->skin); players[i].skin = LONG(rsp->skin);
players[i].availabilities = LONG(rsp->availabilities);
// Just in case Lua does something like // Just in case Lua does something like
// modify these at runtime // modify these at runtime
players[i].camerascale = (fixed_t)LONG(rsp->camerascale); players[i].camerascale = (fixed_t)LONG(rsp->camerascale);
@ -680,7 +681,6 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].spinheight = (fixed_t)LONG(rsp->playerspinheight); players[i].spinheight = (fixed_t)LONG(rsp->playerspinheight);
players[i].speed = (fixed_t)LONG(rsp->speed); players[i].speed = (fixed_t)LONG(rsp->speed);
players[i].jumping = rsp->jumping;
players[i].secondjump = rsp->secondjump; players[i].secondjump = rsp->secondjump;
players[i].fly1 = rsp->fly1; players[i].fly1 = rsp->fly1;
players[i].glidetime = (tic_t)LONG(rsp->glidetime); players[i].glidetime = (tic_t)LONG(rsp->glidetime);
@ -1364,6 +1364,7 @@ static boolean SV_SendServerConfig(INT32 node)
// which is nice and easy for us to detect // which is nice and easy for us to detect
memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins)); memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins));
memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor));
memset(netbuffer->u.servercfg.playeravailabilities, 0xFF, sizeof(netbuffer->u.servercfg.playeravailabilities));
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -1371,6 +1372,7 @@ static boolean SV_SendServerConfig(INT32 node)
continue; continue;
netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin;
netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor; netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor;
netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)LONG(players[i].availabilities);
} }
memcpy(netbuffer->u.servercfg.server_context, server_context, 8); memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
@ -1561,8 +1563,6 @@ static void CL_LoadReceivedSavegame(void)
automapactive = false; automapactive = false;
// load a base level // load a base level
playerdeadview = false;
if (P_LoadNetGame()) if (P_LoadNetGame())
{ {
const INT32 actnum = mapheaderinfo[gamemap-1]->actnum; const INT32 actnum = mapheaderinfo[gamemap-1]->actnum;
@ -1740,9 +1740,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
{ {
#ifndef NONET #ifndef NONET
INT32 i; INT32 i;
#endif
#ifndef NONET
// serverlist is updated by GetPacket function // serverlist is updated by GetPacket function
if (serverlistcount > 0) if (serverlistcount > 0)
{ {
@ -1776,7 +1774,20 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
serverlist[i].info.fileneeded); serverlist[i].info.fileneeded);
CONS_Printf(M_GetText("Checking files...\n")); CONS_Printf(M_GetText("Checking files...\n"));
i = CL_CheckFiles(); i = CL_CheckFiles();
if (i == 2) // cannot join for some reason if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have too many WAD files loaded\n"
"to add ones the server is using.\n"
"Please restart SRB2 before connecting.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 2) // cannot join for some reason
{ {
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
@ -2308,12 +2319,7 @@ static void ResetNode(INT32 node);
void CL_ClearPlayer(INT32 playernum) void CL_ClearPlayer(INT32 playernum)
{ {
if (players[playernum].mo) if (players[playernum].mo)
{
// Don't leave a NiGHTS ghost!
if ((players[playernum].pflags & PF_NIGHTSMODE) && players[playernum].mo->tracer)
P_RemoveMobj(players[playernum].mo->tracer);
P_RemoveMobj(players[playernum].mo); P_RemoveMobj(players[playernum].mo);
}
memset(&players[playernum], 0, sizeof (player_t)); memset(&players[playernum], 0, sizeof (player_t));
} }
@ -2521,12 +2527,18 @@ static void Command_Nodes(void)
static void Command_Ban(void) static void Command_Ban(void)
{ {
if (COM_Argc() == 1) if (COM_Argc() < 2)
{ {
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n")); CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
return; return;
} }
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || adminplayer == consoleplayer) if (server || adminplayer == consoleplayer)
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH]; XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
@ -2536,9 +2548,10 @@ static void Command_Ban(void)
if (pn == -1 || pn == 0) if (pn == -1 || pn == 0)
return; return;
else
WRITEUINT8(p, pn); WRITEUINT8(p, pn);
if (I_Ban && !I_Ban(node))
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
{ {
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
WRITEUINT8(p, KICK_MSG_GO_AWAY); WRITEUINT8(p, KICK_MSG_GO_AWAY);
@ -2546,7 +2559,8 @@ static void Command_Ban(void)
} }
else else
{ {
Ban_Add(COM_Argv(2)); if (server) // only the server is allowed to do this right now
Ban_Add(COM_Argv(2));
if (COM_Argc() == 2) if (COM_Argc() == 2)
{ {
@ -2579,21 +2593,27 @@ static void Command_Ban(void)
static void Command_Kick(void) static void Command_Kick(void)
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH]; if (COM_Argc() < 2)
UINT8 *p = buf;
if (COM_Argc() == 1)
{ {
CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n")); CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n"));
return; return;
} }
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || adminplayer == consoleplayer) if (server || adminplayer == consoleplayer)
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1)); const SINT8 pn = nametonum(COM_Argv(1));
WRITESINT8(p, pn);
if (pn == -1 || pn == 0) if (pn == -1 || pn == 0)
return; return;
// Special case if we are trying to kick a player who is downloading the game state: // Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only // trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading // take effect after they have finished downloading
@ -2602,6 +2622,9 @@ static void Command_Kick(void)
Net_ConnectionTimeout(playernode[pn]); Net_ConnectionTimeout(playernode[pn]);
return; return;
} }
WRITESINT8(p, pn);
if (COM_Argc() == 2) if (COM_Argc() == 2)
{ {
WRITEUINT8(p, KICK_MSG_GO_AWAY); WRITEUINT8(p, KICK_MSG_GO_AWAY);
@ -2703,12 +2726,14 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
// If a verified admin banned someone, the server needs to know about it. // If a verified admin banned someone, the server needs to know about it.
// If the playernum isn't zero (the server) then the server needs to record the ban. // If the playernum isn't zero (the server) then the server needs to record the ban.
if (server && playernum && msg == KICK_MSG_BANNED) if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN))
{ {
if (I_Ban && !I_Ban(playernode[(INT32)pnum])) if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
{
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
} #ifndef NONET
else
Ban_Add(reason);
#endif
} }
switch (msg) switch (msg)
@ -3406,17 +3431,42 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (node != servernode) if (node != servernode)
DEBFILE(va("Received packet from unknown host %d\n", node)); DEBFILE(va("Received packet from unknown host %d\n", node));
// macro for packets that should only be sent by the server
// if it is NOT from the server, bail out and close the connection!
#define SERVERONLY \
if (node != servernode) \
{ \
Net_CloseConnection(node); \
break; \
}
switch (netbuffer->packettype) switch (netbuffer->packettype)
{ {
case PT_ASKINFOVIAMS: case PT_ASKINFOVIAMS:
#if 0
if (server && serverrunning) if (server && serverrunning)
{ {
INT32 clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); INT32 clientnode;
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); if (ms_RoomId < 0) // ignore if we're not actually on the MS right now
SV_SendPlayerInfo(clientnode); // Send extra info {
Net_CloseConnection(clientnode); Net_CloseConnection(node); // and yes, close connection
// Don't close connection to MS. return;
}
clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
if (clientnode != -1)
{
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
SV_SendPlayerInfo(clientnode); // Send extra info
Net_CloseConnection(clientnode);
// Don't close connection to MS...
}
else
Net_CloseConnection(node); // ...unless the IP address is not valid
} }
else
Net_CloseConnection(node); // you're not supposed to get it, so ignore it
#else
Net_CloseConnection(node);
#endif
break; break;
case PT_ASKINFO: case PT_ASKINFO:
@ -3424,8 +3474,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
{ {
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
SV_SendPlayerInfo(node); // Send extra info SV_SendPlayerInfo(node); // Send extra info
Net_CloseConnection(node);
} }
Net_CloseConnection(node);
break; break;
case PT_SERVERREFUSE: // Negative response of client join request case PT_SERVERREFUSE: // Negative response of client join request
@ -3434,6 +3484,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
SERVERONLY
if (cl_mode == CL_WAITJOINRESPONSE) if (cl_mode == CL_WAITJOINRESPONSE)
{ {
// Save the reason so it can be displayed after quitting the netgame // Save the reason so it can be displayed after quitting the netgame
@ -3465,6 +3516,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
SERVERONLY
/// \note how would this happen? and is it doing the right thing if it does? /// \note how would this happen? and is it doing the right thing if it does?
if (cl_mode != CL_WAITJOINRESPONSE) if (cl_mode != CL_WAITJOINRESPONSE)
break; break;
@ -3497,10 +3549,12 @@ static void HandlePacketFromAwayNode(SINT8 node)
for (j = 0; j < MAXPLAYERS; j++) for (j = 0; j < MAXPLAYERS; j++)
{ {
if (netbuffer->u.servercfg.playerskins[j] == 0xFF if (netbuffer->u.servercfg.playerskins[j] == 0xFF
&& netbuffer->u.servercfg.playercolor[j] == 0xFF) && netbuffer->u.servercfg.playercolor[j] == 0xFF
&& netbuffer->u.servercfg.playeravailabilities[j] == 0xFFFFFFFF)
continue; // not in game continue; // not in game
playeringame[j] = true; playeringame[j] = true;
players[j].availabilities = (UINT32)LONG(netbuffer->u.servercfg.playeravailabilities[j]);
SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]);
players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; players[j].skincolor = netbuffer->u.servercfg.playercolor[j];
} }
@ -3528,13 +3582,18 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
else SERVERONLY
Got_Filetxpak(); Got_Filetxpak();
break; break;
case PT_REQUESTFILE: case PT_REQUESTFILE:
if (server) if (server)
Got_RequestFilePak(node); {
if (!cv_downloading.value || !Got_RequestFilePak(node))
Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway
}
else
Net_CloseConnection(node); // nope
break; break;
case PT_NODETIMEOUT: case PT_NODETIMEOUT:
@ -3557,6 +3616,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
break; // Ignore it break; // Ignore it
} }
#undef SERVERONLY
} }
/** Handles a packet received from a node that is in game /** Handles a packet received from a node that is in game
@ -3589,6 +3649,8 @@ FILESTAMP
{ {
// -------------------------------------------- SERVER RECEIVE ---------- // -------------------------------------------- SERVER RECEIVE ----------
case PT_RESYNCHGET: case PT_RESYNCHGET:
if (client)
break;
SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
break; break;
case PT_CLIENTCMD: case PT_CLIENTCMD:
@ -3655,7 +3717,8 @@ FILESTAMP
} }
// Splitscreen cmd // Splitscreen cmd
if (netbuffer->packettype == PT_CLIENT2CMD && nodetoplayer2[node] >= 0) if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& nodetoplayer2[node] >= 0)
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
&netbuffer->u.client2pak.cmd2, 1); &netbuffer->u.client2pak.cmd2, 1);
@ -3714,6 +3777,27 @@ FILESTAMP
tic_t tic = maketic; tic_t tic = maketic;
UINT8 *textcmd; UINT8 *textcmd;
// ignore if the textcmd has a reported size of zero
// this shouldn't be sent at all
if (!netbuffer->u.textcmd[0])
{
DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
node, netconsole));
Net_UnAcknowledgePacket(node);
break;
}
// ignore if the textcmd size var is actually larger than it should be
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
{
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
node, netconsole));
Net_UnAcknowledgePacket(node);
break;
}
// check if tic that we are making isn't too large else we cannot send it :( // check if tic that we are making isn't too large else we cannot send it :(
// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
j = software_MAXPACKETLENGTH j = software_MAXPACKETLENGTH
@ -3907,7 +3991,7 @@ FILESTAMP
if (client) if (client)
{ {
INT32 i; INT32 i;
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
} }
@ -3917,6 +4001,21 @@ FILESTAMP
case PT_SERVERCFG: case PT_SERVERCFG:
break; break;
case PT_FILEFRAGMENT: case PT_FILEFRAGMENT:
// Only accept PT_FILEFRAGMENT from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
if (server)
{
XBOXSTATIC UINT8 buf[2];
buf[0] = (UINT8)node;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
break;
}
if (client) if (client)
Got_Filetxpak(); Got_Filetxpak();
break; break;
@ -4450,8 +4549,8 @@ static inline void PingUpdate(void)
} }
//send out our ping packets //send out our ping packets
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXNETNODES; i++)
if (playeringame[i]) if (nodeingame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS); HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
pingmeasurecount = 1; //Reset count pingmeasurecount = 1; //Reset count
@ -4481,20 +4580,15 @@ void NetUpdate(void)
gametime = nowtime; gametime = nowtime;
if (!(gametime % 255) && netgame && server)
{
#ifdef NEWPING
PingUpdate();
#endif
}
#ifdef NEWPING #ifdef NEWPING
if (server) if (server)
{ {
if (netgame && !(gametime % 255))
PingUpdate();
// update node latency values so we can take an average later. // update node latency values so we can take an average later.
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
realpingtable[i] += G_TicsToMilliseconds(GetLag(i)); realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
pingmeasurecount++; pingmeasurecount++;
} }
#endif #endif

View file

@ -172,6 +172,7 @@ typedef struct
UINT8 skincolor; UINT8 skincolor;
INT32 skin; INT32 skin;
UINT32 availabilities;
// Just in case Lua does something like // Just in case Lua does something like
// modify these at runtime // modify these at runtime
fixed_t camerascale; fixed_t camerascale;
@ -195,7 +196,6 @@ typedef struct
fixed_t playerspinheight; fixed_t playerspinheight;
fixed_t speed; fixed_t speed;
UINT8 jumping;
UINT8 secondjump; UINT8 secondjump;
UINT8 fly1; UINT8 fly1;
tic_t glidetime; tic_t glidetime;
@ -284,6 +284,7 @@ typedef struct
// 0xFF == not in game; else player skin num // 0xFF == not in game; else player skin num
UINT8 playerskins[MAXPLAYERS]; UINT8 playerskins[MAXPLAYERS];
UINT8 playercolor[MAXPLAYERS]; UINT8 playercolor[MAXPLAYERS];
UINT32 playeravailabilities[MAXPLAYERS];
UINT8 gametype; UINT8 gametype;
UINT8 modifiedgame; UINT8 modifiedgame;

View file

@ -107,8 +107,6 @@ UINT8 window_notinfocus = false;
// //
// DEMO LOOP // DEMO LOOP
// //
//static INT32 demosequence;
static const char *pagename = "MAP1PIC";
static char *startupwadfiles[MAX_WADFILES]; static char *startupwadfiles[MAX_WADFILES];
boolean devparm = false; // started game with -devparm boolean devparm = false; // started game with -devparm
@ -720,9 +718,7 @@ void D_StartTitle(void)
maptol = 0; maptol = 0;
gameaction = ga_nothing; gameaction = ga_nothing;
playerdeadview = false;
displayplayer = consoleplayer = 0; displayplayer = consoleplayer = 0;
//demosequence = -1;
gametype = GT_COOP; gametype = GT_COOP;
paused = false; paused = false;
advancedemo = false; advancedemo = false;
@ -887,27 +883,10 @@ static void IdentifyVersion(void)
#endif #endif
} }
/* ======================================================================== */
// Just print the nice red titlebar like the original SRB2 for DOS.
/* ======================================================================== */
#ifdef PC_DOS #ifdef PC_DOS
static inline void D_Titlebar(char *title1, char *title2) /* ======================================================================== */
{ // Code for printing SRB2's title bar in DOS
// SRB2 banner /* ======================================================================== */
clrscr();
textattr((BLUE<<4)+WHITE);
clreol();
cputs(title1);
// standard srb2 banner
textattr((RED<<4)+WHITE);
clreol();
gotoxy((80-strlen(title2))/2, 2);
cputs(title2);
normvideo();
gotoxy(1,3);
}
#endif
// //
// Center the title string, then add the date and time of compilation. // Center the title string, then add the date and time of compilation.
@ -936,6 +915,31 @@ static inline void D_MakeTitleString(char *s)
strcpy(s, temp); strcpy(s, temp);
} }
static inline void D_Titlebar(void)
{
char title1[82]; // srb2 title banner
char title2[82];
strcpy(title1, "Sonic Robo Blast 2");
strcpy(title2, "Sonic Robo Blast 2");
D_MakeTitleString(title1);
// SRB2 banner
clrscr();
textattr((BLUE<<4)+WHITE);
clreol();
cputs(title1);
// standard srb2 banner
textattr((RED<<4)+WHITE);
clreol();
gotoxy((80-strlen(title2))/2, 2);
cputs(title2);
normvideo();
gotoxy(1,3);
}
#endif
// //
// D_SRB2Main // D_SRB2Main
@ -943,8 +947,6 @@ static inline void D_MakeTitleString(char *s)
void D_SRB2Main(void) void D_SRB2Main(void)
{ {
INT32 p; INT32 p;
char srb2[82]; // srb2 title banner
char title[82];
INT32 pstartmap = 1; INT32 pstartmap = 1;
boolean autostart = false; boolean autostart = false;
@ -987,20 +989,8 @@ void D_SRB2Main(void)
dedicated = M_CheckParm("-dedicated") != 0; dedicated = M_CheckParm("-dedicated") != 0;
#endif #endif
strcpy(title, "Sonic Robo Blast 2");
strcpy(srb2, "Sonic Robo Blast 2");
D_MakeTitleString(srb2);
#ifdef PC_DOS #ifdef PC_DOS
D_Titlebar(srb2, title); D_Titlebar();
#endif
#if defined (__OS2__) && !defined (HAVE_SDL)
// set PM window title
snprintf(pmData->title, sizeof (pmData->title),
"Sonic Robo Blast 2" VERSIONSTRING ": %s",
title);
pmData->title[sizeof (pmData->title) - 1] = '\0';
#endif #endif
if (devparm) if (devparm)
@ -1400,7 +1390,6 @@ void D_SRB2Main(void)
if (dedicated && server) if (dedicated && server)
{ {
pagename = "TITLESKY";
levelstarttic = gametic; levelstarttic = gametic;
G_SetGamestate(GS_LEVEL); G_SetGamestate(GS_LEVEL);
if (!P_SetupLevel(false)) if (!P_SetupLevel(false))

View file

@ -34,7 +34,7 @@ void D_SRB2Loop(void) FUNCNORETURN;
// D_SRB2Main() // D_SRB2Main()
// Not a globally visible function, just included for source reference, // Not a globally visible function, just included for source reference,
// calls all startup code, parses command line options. // calls all startup code, parses command line options.
// If not overrided by user input, calls N_AdvanceDemo. // If not overrided by user input, calls D_AdvanceDemo.
// //
void D_SRB2Main(void); void D_SRB2Main(void);
@ -51,9 +51,6 @@ const char *D_Home(void);
// //
// BASE LEVEL // BASE LEVEL
// //
void D_PageTicker(void);
// pagename is lumpname of a 320x200 patch to fill the screen
void D_PageDrawer(const char *pagename);
void D_AdvanceDemo(void); void D_AdvanceDemo(void);
void D_StartTitle(void); void D_StartTitle(void);

View file

@ -49,7 +49,9 @@ doomcom_t *doomcom = NULL;
/// \brief network packet data, points inside doomcom /// \brief network packet data, points inside doomcom
doomdata_t *netbuffer = NULL; doomdata_t *netbuffer = NULL;
#ifdef DEBUGFILE
FILE *debugfile = NULL; // put some net info in a file during the game FILE *debugfile = NULL; // put some net info in a file during the game
#endif
#define MAXREBOUND 8 #define MAXREBOUND 8
static doomdata_t reboundstore[MAXREBOUND]; static doomdata_t reboundstore[MAXREBOUND];
@ -711,11 +713,24 @@ void Net_CloseConnection(INT32 node)
#else #else
INT32 i; INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0; boolean forceclose = (node & FORCECLOSE) != 0;
if (node == -1)
{
DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n"));
return; // nope, just ignore it
}
node &= ~FORCECLOSE; node &= ~FORCECLOSE;
if (!node) if (!node)
return; return;
if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
{
DEBFILE(va(M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node));
return;
}
nodes[node].flags |= NF_CLOSE; nodes[node].flags |= NF_CLOSE;
// try to Send ack back (two army problem) // try to Send ack back (two army problem)

View file

@ -189,14 +189,13 @@ static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2
static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}};
static CV_PossibleValue_t sleeping_cons_t[] = {{-1, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t sleeping_cons_t[] = {{-1, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}};
static CV_PossibleValue_t competitionboxes_cons_t[] = {{0, "Normal"}, {1, "Random"}, {2, "Teleports"}, static CV_PossibleValue_t competitionboxes_cons_t[] = {{0, "Normal"}, {1, "Random"}, //{2, "Teleports"},
{3, "None"}, {0, NULL}}; {3, "None"}, {0, NULL}};
static CV_PossibleValue_t matchboxes_cons_t[] = {{0, "Normal"}, {1, "Random"}, {2, "Non-Random"}, static CV_PossibleValue_t matchboxes_cons_t[] = {{0, "Normal"}, {1, "Random"}, {2, "Non-Random"},
{3, "None"}, {0, NULL}}; {3, "None"}, {0, NULL}};
static CV_PossibleValue_t chances_cons_t[] = {{0, "MIN"}, {9, "MAX"}, {0, NULL}}; static CV_PossibleValue_t chances_cons_t[] = {{0, "MIN"}, {9, "MAX"}, {0, NULL}};
static CV_PossibleValue_t match_scoring_cons_t[] = {{0, "Normal"}, {1, "Classic"}, {0, NULL}};
static CV_PossibleValue_t pause_cons_t[] = {{0, "Server"}, {1, "All"}, {0, NULL}}; static CV_PossibleValue_t pause_cons_t[] = {{0, "Server"}, {1, "All"}, {0, NULL}};
static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Tics"}, {2, "Centiseconds"}, {0, NULL}}; static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Tics"}, {2, "Centiseconds"}, {0, NULL}};
@ -311,7 +310,6 @@ consvar_t cv_friendlyfire = {"friendlyfire", "Off", CV_NETVAR, CV_OnOff, NULL, 0
consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_OnChange, 0, NULL, NULL, 0, 0, NULL};
// Scoring type options // Scoring type options
consvar_t cv_match_scoring = {"matchscoring", "Normal", CV_NETVAR|CV_CHEAT, match_scoring_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -485,7 +483,6 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_itemrespawntime); CV_RegisterVar(&cv_itemrespawntime);
CV_RegisterVar(&cv_itemrespawn); CV_RegisterVar(&cv_itemrespawn);
CV_RegisterVar(&cv_flagtime); CV_RegisterVar(&cv_flagtime);
CV_RegisterVar(&cv_suddendeath);
// misc // misc
CV_RegisterVar(&cv_friendlyfire); CV_RegisterVar(&cv_friendlyfire);
@ -533,7 +530,6 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_startinglives); CV_RegisterVar(&cv_startinglives);
CV_RegisterVar(&cv_countdowntime); CV_RegisterVar(&cv_countdowntime);
CV_RegisterVar(&cv_runscripts); CV_RegisterVar(&cv_runscripts);
CV_RegisterVar(&cv_match_scoring);
CV_RegisterVar(&cv_overtime); CV_RegisterVar(&cv_overtime);
CV_RegisterVar(&cv_pause); CV_RegisterVar(&cv_pause);
CV_RegisterVar(&cv_mute); CV_RegisterVar(&cv_mute);
@ -616,6 +612,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_screenshot_option); CV_RegisterVar(&cv_screenshot_option);
CV_RegisterVar(&cv_screenshot_folder); CV_RegisterVar(&cv_screenshot_folder);
CV_RegisterVar(&cv_screenshot_colorprofile);
CV_RegisterVar(&cv_moviemode); CV_RegisterVar(&cv_moviemode);
// PNG variables // PNG variables
CV_RegisterVar(&cv_zlib_level); CV_RegisterVar(&cv_zlib_level);
@ -673,7 +670,29 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_resetmusic); CV_RegisterVar(&cv_resetmusic);
// FIXME: not to be here.. but needs be done for config loading // FIXME: not to be here.. but needs be done for config loading
CV_RegisterVar(&cv_usegamma); CV_RegisterVar(&cv_globalgamma);
CV_RegisterVar(&cv_globalsaturation);
CV_RegisterVar(&cv_rhue);
CV_RegisterVar(&cv_yhue);
CV_RegisterVar(&cv_ghue);
CV_RegisterVar(&cv_chue);
CV_RegisterVar(&cv_bhue);
CV_RegisterVar(&cv_mhue);
CV_RegisterVar(&cv_rgamma);
CV_RegisterVar(&cv_ygamma);
CV_RegisterVar(&cv_ggamma);
CV_RegisterVar(&cv_cgamma);
CV_RegisterVar(&cv_bgamma);
CV_RegisterVar(&cv_mgamma);
CV_RegisterVar(&cv_rsaturation);
CV_RegisterVar(&cv_ysaturation);
CV_RegisterVar(&cv_gsaturation);
CV_RegisterVar(&cv_csaturation);
CV_RegisterVar(&cv_bsaturation);
CV_RegisterVar(&cv_msaturation);
// m_menu.c // m_menu.c
CV_RegisterVar(&cv_crosshair); CV_RegisterVar(&cv_crosshair);
@ -731,6 +750,7 @@ void D_RegisterClientCommands(void)
// s_sound.c // s_sound.c
CV_RegisterVar(&cv_soundvolume); CV_RegisterVar(&cv_soundvolume);
CV_RegisterVar(&cv_closedcaptioning);
CV_RegisterVar(&cv_digmusicvolume); CV_RegisterVar(&cv_digmusicvolume);
CV_RegisterVar(&cv_midimusicvolume); CV_RegisterVar(&cv_midimusicvolume);
CV_RegisterVar(&cv_numChannels); CV_RegisterVar(&cv_numChannels);
@ -1011,7 +1031,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true; return true;
// Force skin in effect. // Force skin in effect.
if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1)) if ((cv_forceskin.value != -1) || (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0'))
return false; return false;
// Can change skin in intermission and whatnot. // Can change skin in intermission and whatnot.
@ -1109,6 +1129,8 @@ static void SendNameAndColor(void)
if (!Playing()) if (!Playing())
return; return;
players[consoleplayer].availabilities = R_GetSkinAvailabilities();
// If you're not in a netgame, merely update the skin, color, and name. // If you're not in a netgame, merely update the skin, color, and name.
if (!netgame) if (!netgame)
{ {
@ -1127,7 +1149,7 @@ static void SendNameAndColor(void)
SetPlayerSkinByNum(consoleplayer, 0); SetPlayerSkinByNum(consoleplayer, 0);
CV_StealthSet(&cv_skin, skins[0].name); CV_StealthSet(&cv_skin, skins[0].name);
} }
else if ((foundskin = R_SkinAvailable(cv_skin.string)) != -1 && R_SkinUnlock(foundskin)) else if ((foundskin = R_SkinAvailable(cv_skin.string)) != -1 && R_SkinUsable(consoleplayer, foundskin))
{ {
boolean notsame; boolean notsame;
@ -1174,7 +1196,7 @@ static void SendNameAndColor(void)
// check if player has the skin loaded (cv_skin may have // check if player has the skin loaded (cv_skin may have
// the name of a skin that was available in the previous game) // the name of a skin that was available in the previous game)
cv_skin.value = R_SkinAvailable(cv_skin.string); cv_skin.value = R_SkinAvailable(cv_skin.string);
if ((cv_skin.value < 0) || !R_SkinUnlock(cv_skin.value)) if ((cv_skin.value < 0) || !R_SkinUsable(consoleplayer, cv_skin.value))
{ {
CV_StealthSet(&cv_skin, DEFAULTSKIN); CV_StealthSet(&cv_skin, DEFAULTSKIN);
cv_skin.value = 0; cv_skin.value = 0;
@ -1182,6 +1204,7 @@ static void SendNameAndColor(void)
// Finally write out the complete packet and send it off. // Finally write out the complete packet and send it off.
WRITESTRINGN(p, cv_playername.zstring, MAXPLAYERNAME); WRITESTRINGN(p, cv_playername.zstring, MAXPLAYERNAME);
WRITEUINT32(p, (UINT32)players[consoleplayer].availabilities);
WRITEUINT8(p, (UINT8)cv_playercolor.value); WRITEUINT8(p, (UINT8)cv_playercolor.value);
WRITEUINT8(p, (UINT8)cv_skin.value); WRITEUINT8(p, (UINT8)cv_skin.value);
SendNetXCmd(XD_NAMEANDCOLOR, buf, p - buf); SendNetXCmd(XD_NAMEANDCOLOR, buf, p - buf);
@ -1224,6 +1247,8 @@ static void SendNameAndColor2(void)
if (!Playing()) if (!Playing())
return; return;
players[secondplaya].availabilities = R_GetSkinAvailabilities();
// If you're not in a netgame, merely update the skin, color, and name. // If you're not in a netgame, merely update the skin, color, and name.
if (botingame) if (botingame)
{ {
@ -1252,7 +1277,7 @@ static void SendNameAndColor2(void)
SetPlayerSkinByNum(secondplaya, forcedskin); SetPlayerSkinByNum(secondplaya, forcedskin);
CV_StealthSet(&cv_skin2, skins[forcedskin].name); CV_StealthSet(&cv_skin2, skins[forcedskin].name);
} }
else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUnlock(foundskin)) else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUsable(secondplaya, foundskin))
{ {
boolean notsame; boolean notsame;
@ -1307,6 +1332,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
#endif #endif
READSTRINGN(*cp, name, MAXPLAYERNAME); READSTRINGN(*cp, name, MAXPLAYERNAME);
p->availabilities = READUINT32(*cp);
color = READUINT8(*cp); color = READUINT8(*cp);
skin = READUINT8(*cp); skin = READUINT8(*cp);
@ -1323,6 +1349,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer])) if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer]))
{ {
boolean kick = false; boolean kick = false;
INT32 s;
// team colors // team colors
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
@ -1337,6 +1364,16 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
if (!p->skincolor) if (!p->skincolor)
kick = true; kick = true;
// availabilities
for (s = 0; s < MAXSKINS; s++)
{
if (!skins[s].availability && (p->availabilities & (1 << s)))
{
kick = true;
break;
}
}
if (kick) if (kick)
{ {
XBOXSTATIC UINT8 buf[2]; XBOXSTATIC UINT8 buf[2];
@ -1532,10 +1569,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
// The supplied data are assumed to be good. // The supplied data are assumed to be good.
I_Assert(delay >= 0 && delay <= 2); I_Assert(delay >= 0 && delay <= 2);
if (mapnum != -1)
CV_SetValue(&cv_nextmap, mapnum);
CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n",
mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene); mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene);
if (netgame || multiplayer) if ((netgame || multiplayer) && !((gametype == newgametype) && (newgametype == GT_COOP)))
FLS = false; FLS = false;
if (delay != 2) if (delay != 2)
@ -1569,8 +1609,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
mapchangepending = 0; mapchangepending = 0;
// spawn the server if needed // spawn the server if needed
// reset players if there is a new one // reset players if there is a new one
if (!(adminplayer == consoleplayer) && SV_SpawnServer()) if (!(adminplayer == consoleplayer))
buf[0] &= ~(1<<1); {
if (SV_SpawnServer())
buf[0] &= ~(1<<1);
if (!Playing()) // you failed to start a server somehow, so cancel the map change
return;
}
// Kick bot from special stages // Kick bot from special stages
if (botskin) if (botskin)
@ -1701,9 +1746,19 @@ static void Command_Map_f(void)
} }
} }
// Prevent warping to locked levels
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
// lives hell.
if (!dedicated && M_MapLocked(newmapnum))
{
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
return;
}
// don't use a gametype the map doesn't support // don't use a gametype the map doesn't support
if (cv_debug || COM_CheckParm("-force") || cv_skipmapcheck.value) if (cv_debug || COM_CheckParm("-force") || cv_skipmapcheck.value)
; // The player wants us to trek on anyway. Do so. fromlevelselect = false; // The player wants us to trek on anyway. Do so.
// G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer // G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
// Alternatively, bail if the map header is completely missing anyway. // Alternatively, bail if the map header is completely missing anyway.
else if (!mapheaderinfo[newmapnum-1] else if (!mapheaderinfo[newmapnum-1]
@ -1722,19 +1777,10 @@ static void Command_Map_f(void)
CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, gametypestring); CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, gametypestring);
return; return;
} }
else
fromlevelselect = ((netgame || multiplayer) && ((gametype == newgametype) && (newgametype == GT_COOP)));
// Prevent warping to locked levels D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect);
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
// lives hell.
if (!dedicated && M_MapLocked(newmapnum))
{
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
return;
}
fromlevelselect = false;
D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, false);
} }
/** Receives a map command and changes the map. /** Receives a map command and changes the map.
@ -1800,17 +1846,14 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
if (demoplayback && !timingdemo) if (demoplayback && !timingdemo)
precache = false; precache = false;
if (resetplayer) if (resetplayer && !FLS)
{ emeralds = 0;
if (!FLS || (netgame || multiplayer))
emeralds = 0;
}
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
LUAh_MapChange(); LUAh_MapChange();
#endif #endif
G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene); G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene, FLS);
if (demoplayback && !timingdemo) if (demoplayback && !timingdemo)
precache = true; precache = true;
CON_ToggleOff(); CON_ToggleOff();
@ -2116,7 +2159,7 @@ static void Command_Teamchange_f(void)
return; return;
} }
if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams. if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
{ {
CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n")); CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
return; return;
@ -2213,7 +2256,7 @@ static void Command_Teamchange2_f(void)
return; return;
} }
if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams. if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
{ {
CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n")); CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
return; return;
@ -2967,6 +3010,7 @@ static void Command_Addfile(void)
XBOXSTATIC char buf[256]; XBOXSTATIC char buf[256];
char *buf_p = buf; char *buf_p = buf;
INT32 i; INT32 i;
int musiconly; // W_VerifyNMUSlumps isn't boolean
if (COM_Argc() != 2) if (COM_Argc() != 2)
{ {
@ -2981,7 +3025,9 @@ static void Command_Addfile(void)
if (!isprint(fn[i]) || fn[i] == ';') if (!isprint(fn[i]) || fn[i] == ';')
return; return;
if (!W_VerifyNMUSlumps(fn)) musiconly = W_VerifyNMUSlumps(fn);
if (!musiconly)
{ {
// ... But only so long as they contain nothing more then music and sprites. // ... But only so long as they contain nothing more then music and sprites.
if (netgame && !(server || adminplayer == consoleplayer)) if (netgame && !(server || adminplayer == consoleplayer))
@ -2993,7 +3039,7 @@ static void Command_Addfile(void)
} }
// Add file on your client directly if it is trivial, or you aren't in a netgame. // Add file on your client directly if it is trivial, or you aren't in a netgame.
if (!(netgame || multiplayer) || W_VerifyNMUSlumps(fn)) if (!(netgame || multiplayer) || musiconly)
{ {
P_AddWadFile(fn, NULL); P_AddWadFile(fn, NULL);
return; return;
@ -3013,9 +3059,7 @@ static void Command_Addfile(void)
#else #else
FILE *fhandle; FILE *fhandle;
fhandle = fopen(fn, "rb"); if ((fhandle = W_OpenWadFile(&fn, true)) != NULL)
if (fhandle)
{ {
tic_t t = I_GetTime(); tic_t t = I_GetTime();
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn); CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
@ -3023,11 +3067,8 @@ static void Command_Addfile(void)
CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE); CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
fclose(fhandle); fclose(fhandle);
} }
else else // file not found
{
CONS_Printf(M_GetText("File %s not found.\n"), fn);
return; return;
}
#endif #endif
WRITEMEM(buf_p, md5sum, 16); WRITEMEM(buf_p, md5sum, 16);
} }
@ -3080,7 +3121,13 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
filestatus_t ncs = FS_NOTFOUND; filestatus_t ncs = FS_NOTFOUND;
UINT8 md5sum[16]; UINT8 md5sum[16];
boolean kick = false; boolean kick = false;
boolean toomany = false;
INT32 i; INT32 i;
size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
READSTRINGN(*cp, filename, 240); READSTRINGN(*cp, filename, 240);
READMEM(*cp, md5sum, 16); READMEM(*cp, md5sum, 16);
@ -3106,13 +3153,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
ncs = findfile(filename,md5sum,true); // See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
if (ncs != FS_FOUND) packetsize += nameonlylength(filename) + 22;
if ((numwadfiles >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
toomany = true;
else
ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND || toomany)
{ {
char message[256]; char message[256];
if (ncs == FS_NOTFOUND) if (toomany)
sprintf(message, M_GetText("Too many files loaded to add %s\n"), filename);
else if (ncs == FS_NOTFOUND)
sprintf(message, M_GetText("The server doesn't have %s\n"), filename); sprintf(message, M_GetText("The server doesn't have %s\n"), filename);
else if (ncs == FS_MD5SUMBAD) else if (ncs == FS_MD5SUMBAD)
sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename); sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename);
@ -3182,10 +3241,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND) if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
{ {
Command_ExitGame_f(); Command_ExitGame_f();
if (ncs == FS_NOTFOUND) if (ncs == FS_FOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
}
else if (ncs == FS_NOTFOUND)
{ {
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename); CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING); M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
@ -3203,7 +3267,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
P_AddWadFile(filename, NULL);
G_SetGameModified(true); G_SetGameModified(true);
} }
@ -4042,13 +4105,6 @@ static void Command_Archivetest_f(void)
*/ */
static void ForceSkin_OnChange(void) static void ForceSkin_OnChange(void)
{ {
if ((server || adminplayer == consoleplayer) && ((cv_forceskin.value == -1 && stricmp(cv_forceskin.string, "None")) || !(R_SkinUnlock(cv_forceskin.value))))
{
CONS_Printf("Please provide a valid skin name (\"None\" disables).\n");
CV_SetValue(&cv_forceskin, -1);
return;
}
// NOT in SP, silly! // NOT in SP, silly!
if (!(netgame || multiplayer)) if (!(netgame || multiplayer))
return; return;
@ -4057,7 +4113,7 @@ static void ForceSkin_OnChange(void)
CONS_Printf("The server has lifted the forced skin restrictions.\n"); CONS_Printf("The server has lifted the forced skin restrictions.\n");
else else
{ {
CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value].realname); CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value].name);
ForceAllSkins(cv_forceskin.value); ForceAllSkins(cv_forceskin.value);
} }
} }
@ -4095,7 +4151,8 @@ static void Skin_OnChange(void)
if (!Playing()) if (!Playing())
return; // do whatever you want return; // do whatever you want
if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player. if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return; return;
@ -4138,8 +4195,7 @@ static void Color_OnChange(void)
if (!Playing()) if (!Playing())
return; // do whatever you want return; // do whatever you want
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player. if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return; return;

View file

@ -20,6 +20,12 @@
// console vars // console vars
extern consvar_t cv_playername; extern consvar_t cv_playername;
extern consvar_t cv_playercolor; extern consvar_t cv_playercolor;
extern consvar_t cv_skin;
// secondary splitscreen player
extern consvar_t cv_playername2;
extern consvar_t cv_playercolor2;
extern consvar_t cv_skin2;
#ifdef SEENAMES #ifdef SEENAMES
extern consvar_t cv_seenames, cv_allowseenames; extern consvar_t cv_seenames, cv_allowseenames;
#endif #endif
@ -32,7 +38,6 @@ extern consvar_t cv_joyport2;
#endif #endif
extern consvar_t cv_joyscale; extern consvar_t cv_joyscale;
extern consvar_t cv_joyscale2; extern consvar_t cv_joyscale2;
extern consvar_t cv_controlperkey;
// splitscreen with second mouse // splitscreen with second mouse
extern consvar_t cv_mouse2port; extern consvar_t cv_mouse2port;
@ -40,25 +45,12 @@ extern consvar_t cv_usemouse2;
#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON)
extern consvar_t cv_mouse2opt; extern consvar_t cv_mouse2opt;
#endif #endif
extern consvar_t cv_invertmouse2;
extern consvar_t cv_alwaysfreelook2;
extern consvar_t cv_mousemove2;
extern consvar_t cv_mousesens2;
extern consvar_t cv_mouseysens2;
// normally in p_mobj but the .h is not read // normally in p_mobj but the .h is not read
extern consvar_t cv_itemrespawntime; extern consvar_t cv_itemrespawntime;
extern consvar_t cv_itemrespawn; extern consvar_t cv_itemrespawn;
extern consvar_t cv_flagtime; extern consvar_t cv_flagtime;
extern consvar_t cv_suddendeath;
extern consvar_t cv_skin;
// secondary splitscreen player
extern consvar_t cv_playername2;
extern consvar_t cv_playercolor2;
extern consvar_t cv_skin2;
extern consvar_t cv_touchtag; extern consvar_t cv_touchtag;
extern consvar_t cv_hidetime; extern consvar_t cv_hidetime;
@ -77,9 +69,6 @@ extern consvar_t cv_autobalance;
extern consvar_t cv_teamscramble; extern consvar_t cv_teamscramble;
extern consvar_t cv_scrambleonchange; extern consvar_t cv_scrambleonchange;
extern consvar_t cv_useranalog, cv_useranalog2;
extern consvar_t cv_analog, cv_analog2;
extern consvar_t cv_netstat; extern consvar_t cv_netstat;
#ifdef WALLSPLATS #ifdef WALLSPLATS
extern consvar_t cv_splats; extern consvar_t cv_splats;
@ -101,7 +90,6 @@ extern consvar_t cv_recycler;
extern consvar_t cv_itemfinder; extern consvar_t cv_itemfinder;
extern consvar_t cv_inttime, cv_advancemap, cv_playersforexit; extern consvar_t cv_inttime, cv_advancemap, cv_playersforexit;
extern consvar_t cv_match_scoring;
extern consvar_t cv_overtime; extern consvar_t cv_overtime;
extern consvar_t cv_startinglives; extern consvar_t cv_startinglives;
@ -120,17 +108,7 @@ extern consvar_t cv_maxping;
extern consvar_t cv_skipmapcheck; extern consvar_t cv_skipmapcheck;
extern consvar_t cv_sleep, cv_screenshot_option, cv_screenshot_folder; extern consvar_t cv_sleep;
extern consvar_t cv_moviemode;
extern consvar_t cv_zlib_level, cv_zlib_memory, cv_zlib_strategy;
extern consvar_t cv_zlib_window_bits, cv_zlib_levela, cv_zlib_memorya;
extern consvar_t cv_zlib_strategya, cv_zlib_window_bitsa;
extern consvar_t cv_apng_delay;
typedef enum typedef enum
{ {
@ -211,7 +189,6 @@ void Command_ExitGame_f(void);
void Command_Retry_f(void); void Command_Retry_f(void);
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
void ObjectPlace_OnChange(void);
void ItemFinder_OnChange(void); void ItemFinder_OnChange(void);
void D_SetPassword(const char *pw); void D_SetPassword(const char *pw);

View file

@ -62,7 +62,8 @@
#include <errno.h> #include <errno.h>
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid); // Prototypes
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
// Sender structure // Sender structure
typedef struct filetx_s typedef struct filetx_s
@ -303,7 +304,8 @@ boolean CL_SendRequestFile(void)
} }
// get request filepak and put it on the send queue // get request filepak and put it on the send queue
void Got_RequestFilePak(INT32 node) // returns false if a requested file was not found or cannot be sent
boolean Got_RequestFilePak(INT32 node)
{ {
char wad[MAX_WADPATH+1]; char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd; UINT8 *p = netbuffer->u.textcmd;
@ -314,8 +316,13 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF) if (id == 0xFF)
break; break;
READSTRINGN(p, wad, MAX_WADPATH); READSTRINGN(p, wad, MAX_WADPATH);
SV_SendFile(node, wad, id); if (!SV_SendFile(node, wad, id))
{
SV_AbortSendFiles(node);
return false; // don't read the rest of the files
}
} }
return true; // no problems with any files
} }
/** Checks if the files needed aren't already loaded or on the disk /** Checks if the files needed aren't already loaded or on the disk
@ -330,6 +337,12 @@ INT32 CL_CheckFiles(void)
INT32 i, j; INT32 i, j;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
INT32 ret = 1; INT32 ret = 1;
size_t packetsize = 0;
size_t filestoget = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
// if (M_CheckParm("-nofiles")) // if (M_CheckParm("-nofiles"))
// return 1; // return 1;
@ -378,6 +391,10 @@ INT32 CL_CheckFiles(void)
return 1; return 1;
} }
// See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
for (i = 1; i < fileneedednum; i++) for (i = 1; i < fileneedednum; i++)
{ {
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
@ -397,6 +414,14 @@ INT32 CL_CheckFiles(void)
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important) if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
continue; continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
return 3;
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND) if (fileneeded[i].status != FS_FOUND)
@ -480,7 +505,7 @@ static INT32 filestosend = 0;
* \sa SV_SendRam * \sa SV_SendRam
* *
*/ */
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid) static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
{ {
filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request filetx_t *p; // The new file request
@ -488,7 +513,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value) if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node); CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
// Find the last file in the list and set a pointer to its "next" field // Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist; q = &transfer[node].txlist;
@ -537,7 +562,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
free(p->id.filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return false; // cancel the rest of the requests
} }
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB) // Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
@ -549,7 +574,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
free(p->id.filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return false; // cancel the rest of the requests
} }
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node)); DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
@ -557,6 +582,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
p->fileid = fileid; p->fileid = fileid;
p->next = NULL; // End of list p->next = NULL; // End of list
filestosend++; filestosend++;
return true;
} }
/** Adds a memory block to the file list for a node /** Adds a memory block to the file list for a node

View file

@ -69,7 +69,7 @@ boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void); boolean CL_SendRequestFile(void);
void Got_RequestFilePak(INT32 node); boolean Got_RequestFilePak(INT32 node);
void SV_AbortSendFiles(INT32 node); void SV_AbortSendFiles(INT32 node);
void CloseNetFile(void); void CloseNetFile(void);

View file

@ -32,19 +32,21 @@
// Extra abilities/settings for skins (combinable stuff) // Extra abilities/settings for skins (combinable stuff)
typedef enum typedef enum
{ {
SF_SUPER = 1, // Can turn super in singleplayer/co-op mode. SF_SUPER = 1, // Can turn super in singleplayer/co-op mode?
SF_SUPERANIMS = 1<<1, // If super, use the super sonic animations SF_NOSUPERSPIN = 1<<1, // Should spin frames be played while super?
SF_SUPERSPIN = 1<<2, // Should spin frames be played while super? SF_NOSPINDASHDUST = 1<<2, // Spawn dust particles when charging a spindash?
SF_HIRES = 1<<3, // Draw the sprite 2x as small? SF_HIRES = 1<<3, // Draw the sprite at different size?
SF_NOSKID = 1<<4, // No skid particles etc SF_NOSKID = 1<<4, // No skid particles etc
SF_NOSPEEDADJUST = 1<<5, // Skin-specific version of disablespeedadjust SF_NOSPEEDADJUST = 1<<5, // Skin-specific version of disablespeedadjust
SF_RUNONWATER = 1<<6, // Run on top of water FOFs? SF_RUNONWATER = 1<<6, // Run on top of water FOFs?
SF_NOJUMPSPIN = 1<<7, // SPR2_JUMP defaults to SPR2_SPRG instead of SPR2_SPIN, falling states used, and player height is full when jumping? SF_NOJUMPSPIN = 1<<7, // SPR2_JUMP defaults to SPR2_SPRG instead of SPR2_ROLL, falling states used, and player height is full when jumping?
SF_NOJUMPDAMAGE = 1<<8, // Don't damage enemies, etc whilst jumping? SF_NOJUMPDAMAGE = 1<<8, // Don't damage enemies, etc whilst jumping?
SF_STOMPDAMAGE = 1<<9, // Always damage enemies, etc by landing on them, no matter your vunerability? SF_STOMPDAMAGE = 1<<9, // Always damage enemies, etc by landing on them, no matter your vunerability?
SF_MARIODAMAGE = SF_NOJUMPDAMAGE|SF_STOMPDAMAGE, // The Mario method of being able to damage enemies, etc. SF_MARIODAMAGE = SF_NOJUMPDAMAGE|SF_STOMPDAMAGE, // The Mario method of being able to damage enemies, etc.
SF_MACHINE = 1<<10, // Beep boop. Are you a robot? SF_MACHINE = 1<<10, // Beep boop. Are you a robot?
SF_NOSPINDASHDUST = 1<<11, // Don't spawn dust particles when charging a spindash SF_DASHMODE = 1<<11, // Sonic Advance 2 style top speed increase?
SF_FASTEDGE = 1<<12, // Faster edge teeter?
SF_MULTIABILITY = 1<<13, // Revenge of Final Demo.
// free up to and including 1<<31 // free up to and including 1<<31
} skinflags_t; } skinflags_t;
@ -65,7 +67,7 @@ typedef enum
CA_JUMPBOOST, CA_JUMPBOOST,
CA_AIRDRILL, CA_AIRDRILL,
CA_JUMPTHOK, CA_JUMPTHOK,
CA_DASHMODE, CA_BOUNCE,
CA_TWINSPIN CA_TWINSPIN
} charability_t; } charability_t;
@ -74,7 +76,7 @@ typedef enum
{ {
CA2_NONE=0, CA2_NONE=0,
CA2_SPINDASH, CA2_SPINDASH,
CA2_MULTIABILITY, CA2_GUNSLINGER,
CA2_MELEE CA2_MELEE
} charability2_t; } charability2_t;
@ -118,10 +120,8 @@ typedef enum
// Did you get a time-over? // Did you get a time-over?
PF_TIMEOVER = 1<<10, PF_TIMEOVER = 1<<10,
// Ready for Super?
PF_SUPERREADY = 1<<11,
// Character action status // Character action status
PF_STARTJUMP = 1<<11,
PF_JUMPED = 1<<12, PF_JUMPED = 1<<12,
PF_SPINNING = 1<<13, PF_SPINNING = 1<<13,
PF_STARTDASH = 1<<14, PF_STARTDASH = 1<<14,
@ -133,12 +133,11 @@ typedef enum
// Sliding (usually in water) like Labyrinth/Oil Ocean // Sliding (usually in water) like Labyrinth/Oil Ocean
PF_SLIDING = 1<<17, PF_SLIDING = 1<<17,
/*** NIGHTS STUFF ***/ // Bouncing
// Is the player in NiGHTS mode? PF_BOUNCING = 1<<18,
PF_NIGHTSMODE = 1<<18,
PF_TRANSFERTOCLOSEST = 1<<19,
// Spill rings after falling /*** NIGHTS STUFF ***/
PF_TRANSFERTOCLOSEST = 1<<19,
PF_NIGHTSFALL = 1<<20, PF_NIGHTSFALL = 1<<20,
PF_DRILLING = 1<<21, PF_DRILLING = 1<<21,
PF_SKIDDOWN = 1<<22, PF_SKIDDOWN = 1<<22,
@ -157,10 +156,10 @@ typedef enum
// Used shield ability // Used shield ability
PF_SHIELDABILITY = 1<<28, PF_SHIELDABILITY = 1<<28,
// Force jump damage? // Jump damage?
PF_FORCEJUMPDAMAGE = 1<<29 PF_NOJUMPDAMAGE = 1<<29,
// free up to and including 1<<31 // up to 1<<31 is free
} pflags_t; } pflags_t;
typedef enum typedef enum
@ -171,7 +170,7 @@ typedef enum
PA_EDGE, PA_EDGE,
PA_WALK, PA_WALK,
PA_RUN, PA_RUN,
PA_PEEL, PA_DASH,
PA_PAIN, PA_PAIN,
PA_ROLL, PA_ROLL,
PA_JUMP, PA_JUMP,
@ -223,6 +222,10 @@ typedef enum
CR_GENERIC, CR_GENERIC,
// Tails carry. // Tails carry.
CR_PLAYER, CR_PLAYER,
// NiGHTS mode. Not technically a CARRYING, but doesn't stack with any of the others, so might as well go here.
CR_NIGHTSMODE,
// Old Brak sucks hard, but this gimmick could be used for something better, so we might as well continue supporting it.
CR_BRAKGOOP,
// Specific level gimmicks. // Specific level gimmicks.
CR_ZOOMTUBE, CR_ZOOMTUBE,
CR_ROPEHANG, CR_ROPEHANG,
@ -262,9 +265,7 @@ typedef enum
pw_nights_helper, pw_nights_helper,
pw_nights_linkfreeze, pw_nights_linkfreeze,
//for linedef exec 427 pw_nocontrol, //for linedef exec 427
pw_nocontrol,
pw_ingoop, // In goop
NUMPOWERS NUMPOWERS
} powertype_t; } powertype_t;
@ -340,6 +341,7 @@ typedef struct player_s
UINT8 skincolor; UINT8 skincolor;
INT32 skin; INT32 skin;
UINT32 availabilities;
UINT32 score; // player score UINT32 score; // player score
fixed_t dashspeed; // dashing speed fixed_t dashspeed; // dashing speed
@ -377,7 +379,6 @@ typedef struct player_s
UINT8 gotcontinue; // Got continue from this stage? UINT8 gotcontinue; // Got continue from this stage?
fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values) fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values)
UINT8 jumping; // Holding down jump button
UINT8 secondjump; // Jump counter UINT8 secondjump; // Jump counter
UINT8 fly1; // Tails flying UINT8 fly1; // Tails flying

View file

@ -382,72 +382,20 @@ static void clear_levels(void)
P_AllocMapHeader(gamemap-1); P_AllocMapHeader(gamemap-1);
} }
/* static boolean findFreeSlot(INT32 *num)
// Edits an animated texture slot on the array
// Tails 12-27-2003
static void readAnimTex(MYFILE *f, INT32 num)
{
char s[MAXLINELEN];
char *word;
char *word2;
INT32 i;
do {
if (myfgets(s, sizeof s, f) != NULL)
{
if (s[0] == '\n') break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
// set the value in the appropriate field
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " = ");
if (word2)
strupr(word2);
else
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
if (fastcmp(word, "START"))
strncpy(harddefs[num].startname, word2, 8);
if (fastcmp(word, "END"))
strncpy(harddefs[num].endname, word2, 8);
else if (fastcmp(word, "SPEED")) harddefs[num].speed = i;
else if (fastcmp(word, "ISTEXTURE")) harddefs[num].istexture = i;
else deh_warning("readAnimTex %d: unknown word '%s'", num, word);
}
} while (s[0] != '\n' && !myfeof(f)); //finish when the line is empty
}
*/
static boolean findFreeSlot(INT32 *num, UINT16 wadnum)
{ {
// Send the character select entry to a free slot. // Send the character select entry to a free slot.
while (*num < 32 && (!(PlayerMenu[*num].status & IT_DISABLED) || description[*num].wadnum == wadnum)) // Will kill hidden characters from other files, but that's okay. while (*num < 32 && (description[*num].used))
*num = *num+1; *num = *num+1;
// No more free slots. :( // No more free slots. :(
if (*num >= 32) if (*num >= 32)
return false; return false;
PlayerMenu[*num].status = IT_CALL;
description[*num].wadnum = wadnum;
description[*num].picname[0] = '\0'; // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) description[*num].picname[0] = '\0'; // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...)
// Found one! ^_^ // Found one! ^_^
return true; return (description[*num].used = true);
} }
// Reads a player. // Reads a player.
@ -479,7 +427,7 @@ static void readPlayer(MYFILE *f, INT32 num)
{ {
char *playertext = NULL; char *playertext = NULL;
if (!slotfound && (slotfound = findFreeSlot(&num, f->wad)) == false) if (!slotfound && (slotfound = findFreeSlot(&num)) == false)
goto done; goto done;
for (i = 0; i < MAXLINELEN-3; i++) for (i = 0; i < MAXLINELEN-3; i++)
@ -528,7 +476,7 @@ static void readPlayer(MYFILE *f, INT32 num)
if (fastcmp(word, "PICNAME")) if (fastcmp(word, "PICNAME"))
{ {
if (!slotfound && (slotfound = findFreeSlot(&num, f->wad)) == false) if (!slotfound && (slotfound = findFreeSlot(&num)) == false)
goto done; goto done;
DEH_WriteUndoline(word, &description[num].picname[0], UNDO_NONE); DEH_WriteUndoline(word, &description[num].picname[0], UNDO_NONE);
@ -536,12 +484,6 @@ static void readPlayer(MYFILE *f, INT32 num)
} }
else if (fastcmp(word, "STATUS")) else if (fastcmp(word, "STATUS"))
{ {
// Limit the status to only IT_DISABLED and IT_CALL
if (i)
i = IT_CALL;
else
i = IT_DISABLED;
/* /*
You MAY disable previous entries if you so desire... You MAY disable previous entries if you so desire...
But try to enable something that's already enabled and you will be sent to a free slot. But try to enable something that's already enabled and you will be sent to a free slot.
@ -549,15 +491,15 @@ static void readPlayer(MYFILE *f, INT32 num)
Because of this, you are allowed to edit any previous entries you like, but only if you Because of this, you are allowed to edit any previous entries you like, but only if you
signal that you are purposely doing so by disabling and then reenabling the slot. signal that you are purposely doing so by disabling and then reenabling the slot.
*/ */
if (i != IT_DISABLED && !slotfound && (slotfound = findFreeSlot(&num, f->wad)) == false) if (i && !slotfound && (slotfound = findFreeSlot(&num)) == false)
goto done; goto done;
DEH_WriteUndoline(word, va("%d", PlayerMenu[num].status), UNDO_NONE); DEH_WriteUndoline(word, va("%d", description[num].used), UNDO_NONE);
PlayerMenu[num].status = (INT16)i; description[num].used = (!!i);
} }
else if (fastcmp(word, "SKINNAME")) else if (fastcmp(word, "SKINNAME"))
{ {
// Send to free slot. // Send to free slot.
if (!slotfound && (slotfound = findFreeSlot(&num, f->wad)) == false) if (!slotfound && (slotfound = findFreeSlot(&num)) == false)
goto done; goto done;
DEH_WriteUndoline(word, description[num].skinname, UNDO_NONE); DEH_WriteUndoline(word, description[num].skinname, UNDO_NONE);
@ -1211,6 +1153,12 @@ static void readlevelheader(MYFILE *f, INT32 num)
{ {
deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2, deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num)); sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once
}
else if (fastcmp(word, "SELECTHEADING"))
{
deh_strlcpy(mapheaderinfo[num-1]->selectheading, word2,
sizeof(mapheaderinfo[num-1]->selectheading), va("Level header %d: selectheading", num));
} }
else if (fastcmp(word, "SCRIPTNAME")) else if (fastcmp(word, "SCRIPTNAME"))
{ {
@ -1430,6 +1378,13 @@ static void readlevelheader(MYFILE *f, INT32 num)
else else
mapheaderinfo[num-1]->menuflags &= ~LF2_NOVISITNEEDED; mapheaderinfo[num-1]->menuflags &= ~LF2_NOVISITNEEDED;
} }
else if (fastcmp(word, "WIDEICON"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->menuflags |= LF2_WIDEICON;
else
mapheaderinfo[num-1]->menuflags &= ~LF2_WIDEICON;
}
else else
deh_warning("Level header %d: unknown word '%s'", num, word); deh_warning("Level header %d: unknown word '%s'", num, word);
} }
@ -2113,10 +2068,11 @@ static void readframe(MYFILE *f, INT32 num)
Z_Free(s); Z_Free(s);
} }
static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[]) static void readsound(MYFILE *f, INT32 num)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word; char *word;
char *word2;
char *tmp; char *tmp;
INT32 value; INT32 value;
@ -2130,8 +2086,8 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[])
tmp = strchr(s, '#'); tmp = strchr(s, '#');
if (tmp) if (tmp)
*tmp = '\0'; *tmp = '\0';
if (s == tmp)
value = searchvalue(s); continue; // Skip comment lines, but don't break.
word = strtok(s, " "); word = strtok(s, " ");
if (word) if (word)
@ -2139,21 +2095,16 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[])
else else
break; break;
/* if (fastcmp(word, "OFFSET")) word2 = strtok(NULL, " ");
if (word2)
value = atoi(word2);
else
{ {
value -= 150360; deh_warning("No value for token %s", word);
if (value <= 64) continue;
value /= 8;
else if (value <= 260)
value = (value+4)/8;
else
value = (value+8)/8;
if (value >= -1 && value < sfx_freeslot0 - 1)
S_sfx[num].name = savesfxnames[value+1];
else
deh_warning("Sound %d: offset out of bounds", num);
} }
else */if (fastcmp(word, "SINGULAR"))
if (fastcmp(word, "SINGULAR"))
{ {
DEH_WriteUndoline(word, va("%d", S_sfx[num].singularity), UNDO_NONE); DEH_WriteUndoline(word, va("%d", S_sfx[num].singularity), UNDO_NONE);
S_sfx[num].singularity = value; S_sfx[num].singularity = value;
@ -2168,14 +2119,17 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[])
DEH_WriteUndoline(word, va("%d", S_sfx[num].pitch), UNDO_NONE); DEH_WriteUndoline(word, va("%d", S_sfx[num].pitch), UNDO_NONE);
S_sfx[num].pitch = value; S_sfx[num].pitch = value;
} }
else if (fastcmp(word, "CAPTION") || fastcmp(word, "DESCRIPTION"))
{
deh_strlcpy(S_sfx[num].caption, word2,
sizeof(S_sfx[num].caption), va("Sound effect %d: caption", num));
}
else else
deh_warning("Sound %d : unknown word '%s'",num,word); deh_warning("Sound %d : unknown word '%s'",num,word);
} }
} while (!myfeof(f)); } while (!myfeof(f));
Z_Free(s); Z_Free(s);
(void)savesfxnames;
} }
/** Checks if a game data file name for a mod is good. /** Checks if a game data file name for a mod is good.
@ -2461,6 +2415,7 @@ static void readunlockable(MYFILE *f, INT32 num)
DEH_WriteUndoline("VAR", va("%d", unlockables[num].variable), UNDO_NONE); DEH_WriteUndoline("VAR", va("%d", unlockables[num].variable), UNDO_NONE);
memset(&unlockables[num], 0, sizeof(unlockable_t)); memset(&unlockables[num], 0, sizeof(unlockable_t));
unlockables[num].objective[0] = '/';
do do
{ {
@ -2802,190 +2757,6 @@ static void readconditionset(MYFILE *f, UINT8 setnum)
Z_Free(s); Z_Free(s);
} }
static void readtexture(MYFILE *f, const char *name)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i, j, value;
UINT16 width = 0, height = 0;
INT16 patchcount = 0;
texture_t *texture;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
value = searchvalue(s);
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " ");
if (word2)
strupr(word2);
else
break;
// Width of the texture.
if (fastcmp(word, "WIDTH"))
{
DEH_WriteUndoline(word, va("%d", width), UNDO_NONE);
width = SHORT((UINT16)value);
}
// Height of the texture.
else if (fastcmp(word, "HEIGHT"))
{
DEH_WriteUndoline(word, va("%d", height), UNDO_NONE);
height = SHORT((UINT16)value);
}
// Number of patches the texture has.
else if (fastcmp(word, "NUMPATCHES"))
{
DEH_WriteUndoline(word, va("%d", patchcount), UNDO_NONE);
patchcount = SHORT((UINT16)value);
}
else
deh_warning("readtexture: unknown word '%s'", word);
}
} while (!myfeof(f));
// Error checking.
if (!width)
I_Error("Texture %s has no width!\n", name);
if (!height)
I_Error("Texture %s has no height!\n", name);
if (!patchcount)
I_Error("Texture %s has no patches!\n", name);
// Allocate memory for the texture, and fill in information.
texture = Z_Calloc(sizeof(texture_t) + (sizeof(texpatch_t) * SHORT(patchcount)), PU_STATIC, NULL);
M_Memcpy(texture->name, name, sizeof(texture->name));
texture->width = width;
texture->height = height;
texture->patchcount = patchcount;
texture->holes = false;
// Fill out the texture patches, to allow them to be detected
// accurately by readpatch.
for (i = 0; i < patchcount; i++)
{
texture->patches[i].originx = 0;
texture->patches[i].originy = 0;
texture->patches[i].wad = UINT16_MAX;
texture->patches[i].lump = UINT16_MAX;
}
// Jump to the next empty texture entry.
i = 0;
while (textures[i])
i++;
// Fill the global texture buffer entries.
j = 1;
while (j << 1 <= texture->width)
j <<= 1;
textures[i] = texture;
texturewidthmask[i] = j - 1;
textureheight[i] = texture->height << FRACBITS;
// Clean up.
Z_Free(s);
}
static void readpatch(MYFILE *f, const char *name, UINT16 wad)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i = 0, j = 0, value;
texpatch_t patch = {0, 0, UINT16_MAX, UINT16_MAX, 0, 255, AST_COPY};
// Jump to the texture this patch belongs to, which,
// coincidentally, is always the last one on the buffer cache.
while (textures[i+1])
i++;
// Jump to the next empty patch entry.
while (memcmp(&(textures[i]->patches[j]), &patch, sizeof(patch)))
j++;
patch.wad = wad;
// Set the texture number, but only if the lump exists.
if ((patch.lump = W_CheckNumForNamePwad(name, wad, 0)) == INT16_MAX)
I_Error("readpatch: Missing patch in texture %s", textures[i]->name);
// note: undoing this patch will be done by other means
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
value = searchvalue(s);
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " ");
if (word2)
strupr(word2);
else
break;
// X position of the patch in the texture.
if (fastcmp(word, "X"))
{
//DEH_WriteUndoline(word, va("%d", patch->originx), UNDO_NONE);
patch.originx = (INT16)value;
}
// Y position of the patch in the texture.
else if (fastcmp(word, "Y"))
{
//DEH_WriteUndoline(word, va("%d", patch->originy), UNDO_NONE);
patch.originy = (INT16)value;
}
else
deh_warning("readpatch: unknown word '%s'", word);
}
} while (!myfeof(f));
// Error checking.
/* // Irrelevant. Origins cannot be unsigned.
if (patch.originx == UINT16_MAX)
I_Error("Patch %s on texture %s has no X position!\n", name, textures[i]->name);
if (patch.originy == UINT16_MAX)
I_Error("Patch %s on texture %s has no Y position!\n", name, textures[i]->name);
*/
// Set the patch as that patch number.
textures[i]->patches[j] = patch;
// Clean up.
Z_Free(s);
}
static void readmaincfg(MYFILE *f) static void readmaincfg(MYFILE *f)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -3396,30 +3167,17 @@ static void ignorelines(MYFILE *f)
Z_Free(s); Z_Free(s);
} }
static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) static void DEH_LoadDehackedFile(MYFILE *f)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word; char *word;
char *word2; char *word2;
INT32 i; INT32 i;
// do a copy of this for cross references probleme
//XBOXSTATIC actionf_t saveactions[NUMSTATES];
//XBOXSTATIC const char *savesprnames[NUMSPRITES];
XBOXSTATIC const char *savesfxnames[NUMSFX];
if (!deh_loaded) if (!deh_loaded)
initfreeslots(); initfreeslots();
deh_num_warning = 0; deh_num_warning = 0;
// save values for cross reference
/*
for (i = 0; i < NUMSTATES; i++)
saveactions[i] = states[i].action;
for (i = 0; i < NUMSPRITES; i++)
savesprnames[i] = sprnames[i];
*/
for (i = 0; i < NUMSFX; i++)
savesfxnames[i] = S_sfx[i].name;
gamedataadded = false; gamedataadded = false;
@ -3496,19 +3254,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
if (word2[strlen(word2)-1] == '\n') if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0'; word2[strlen(word2)-1] = '\0';
i = atoi(word2); i = atoi(word2);
if (fastcmp(word, "TEXTURE")) if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT"))
{
// Read texture from spec file.
readtexture(f, word2);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "PATCH"))
{
// Read patch from spec file.
readpatch(f, word2, wad);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_mobjtype(word2); // find a thing by name i = get_mobjtype(word2); // find a thing by name
@ -3521,10 +3267,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
/* else if (fastcmp(word, "ANIMTEX"))
{
readAnimTex(f, i);
}*/
else if (fastcmp(word, "LIGHT")) else if (fastcmp(word, "LIGHT"))
{ {
#ifdef HWRENDER #ifdef HWRENDER
@ -3596,61 +3338,19 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
// <Callum> Added translations to this just in case its re-enabled
/* else if (fastcmp(word, "POINTER"))
{
word = strtok(NULL, " "); // get frame
word = strtok(NULL, ")");
if (word)
{
i = atoi(word);
if (i < NUMSTATES && i >= 0)
{
if (myfgets(s, MAXLINELEN, f))
states[i].action = saveactions[searchvalue(s)];
}
else
{
deh_warning("Pointer: Frame %d doesn't exist", i);
ignorelines(f);
}
}
else
deh_warning("pointer (Frame %d) : missing ')'", i);
}*/
else if (fastcmp(word, "SOUND")) else if (fastcmp(word, "SOUND"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_sfx(word2); // find a sound by name i = get_sfx(word2); // find a sound by name
if (i < NUMSFX && i >= 0) if (i < NUMSFX && i > 0)
readsound(f, i, savesfxnames); readsound(f, i);
else else
{ {
deh_warning("Sound %d out of range (0 - %d)", i, NUMSFX-1); deh_warning("Sound %d out of range (1 - %d)", i, NUMSFX-1);
ignorelines(f); ignorelines(f);
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
/* else if (fastcmp(word, "SPRITE"))
{
if (i < NUMSPRITES && i >= 0)
{
if (myfgets(s, MAXLINELEN, f))
{
INT32 k;
k = (searchvalue(s) - 151328)/8;
if (k >= 0 && k < NUMSPRITES)
sprnames[i] = savesprnames[k];
else
{
deh_warning("Sprite %d: offset out of bounds", i);
ignorelines(f);
}
}
}
else
deh_warning("Sprite %d doesn't exist",i);
}*/
else if (fastcmp(word, "HUDITEM")) else if (fastcmp(word, "HUDITEM"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
@ -3737,7 +3437,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
// no undo support for this insanity yet // no undo support for this insanity yet
//DEH_WriteUndoline(word, word2, UNDO_HEADER); //DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
else if (fastcmp(word, "SRB2")) // Last I heard this crashes the game if you try to use it
// so this is disabled for now
// -- Monster Iestyn
/* else if (fastcmp(word, "SRB2"))
{ {
INT32 ver = searchvalue(strtok(NULL, "\n")); INT32 ver = searchvalue(strtok(NULL, "\n"));
if (ver != PATCHVERSION) if (ver != PATCHVERSION)
@ -3748,6 +3451,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
// Unless you REALLY want to piss people off, // Unless you REALLY want to piss people off,
// define a custom gamedata /before/ doing this!! // define a custom gamedata /before/ doing this!!
// (then again, modifiedgame will prevent game data saving anyway) // (then again, modifiedgame will prevent game data saving anyway)
*/
else if (fastcmp(word, "CLEAR")) else if (fastcmp(word, "CLEAR"))
{ {
boolean clearall = (fastcmp(word2, "ALL")); boolean clearall = (fastcmp(word2, "ALL"));
@ -3821,7 +3525,7 @@ void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump)
W_ReadLumpPwad(wad, lump, f.data); W_ReadLumpPwad(wad, lump, f.data);
f.curpos = f.data; f.curpos = f.data;
f.data[f.size] = 0; f.data[f.size] = 0;
DEH_LoadDehackedFile(&f, wad); DEH_LoadDehackedFile(&f);
DEH_WriteUndoline(va("# uload for wad: %u, lump: %u", wad, lump), NULL, UNDO_DONE); DEH_WriteUndoline(va("# uload for wad: %u, lump: %u", wad, lump), NULL, UNDO_DONE);
Z_Free(f.data); Z_Free(f.data);
} }
@ -3924,12 +3628,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PLAY_WAIT", "S_PLAY_WAIT",
"S_PLAY_WALK", "S_PLAY_WALK",
"S_PLAY_RUN", "S_PLAY_RUN",
"S_PLAY_PEEL", "S_PLAY_DASH",
"S_PLAY_PAIN", "S_PLAY_PAIN",
"S_PLAY_STUN",
"S_PLAY_DEAD", "S_PLAY_DEAD",
"S_PLAY_DRWN", "S_PLAY_DRWN",
"S_PLAY_SPIN", "S_PLAY_ROLL",
"S_PLAY_DASH",
"S_PLAY_GASP", "S_PLAY_GASP",
"S_PLAY_JUMP", "S_PLAY_JUMP",
"S_PLAY_SPRING", "S_PLAY_SPRING",
@ -3937,6 +3641,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PLAY_EDGE", "S_PLAY_EDGE",
"S_PLAY_RIDE", "S_PLAY_RIDE",
// CA2_SPINDASH
"S_PLAY_SPINDASH",
// CA_FLY/SWIM // CA_FLY/SWIM
"S_PLAY_FLY", "S_PLAY_FLY",
"S_PLAY_SWIM", "S_PLAY_SWIM",
@ -3947,30 +3654,25 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PLAY_CLING", "S_PLAY_CLING",
"S_PLAY_CLIMB", "S_PLAY_CLIMB",
// CA_FLOAT/CA_SLOWFALL
"S_PLAY_FLOAT",
"S_PLAY_FLOAT_RUN",
// CA_BOUNCE
"S_PLAY_BOUNCE",
"S_PLAY_BOUNCE_LANDING",
// CA2_GUNSLINGER
"S_PLAY_FIRE",
"S_PLAY_FIRE_FINISH",
// CA_TWINSPIN // CA_TWINSPIN
"S_PLAY_TWINSPIN", "S_PLAY_TWINSPIN",
// CA2_MELEE // CA2_MELEE
"S_PLAY_MELEE", "S_PLAY_MELEE",
"S_PLAY_MELEE_FINISH", "S_PLAY_MELEE_FINISH",
"S_PLAY_MELEE_LANDING",
// SF_SUPERANIMS
"S_PLAY_SUPER_STND",
"S_PLAY_SUPER_WALK",
"S_PLAY_SUPER_RUN",
"S_PLAY_SUPER_PEEL",
"S_PLAY_SUPER_PAIN",
"S_PLAY_SUPER_STUN",
"S_PLAY_SUPER_DEAD",
"S_PLAY_SUPER_DRWN",
"S_PLAY_SUPER_SPIN",
"S_PLAY_SUPER_GASP",
"S_PLAY_SUPER_JUMP",
"S_PLAY_SUPER_SPRING",
"S_PLAY_SUPER_FALL",
"S_PLAY_SUPER_EDGE",
"S_PLAY_SUPER_RIDE",
"S_PLAY_SUPER_FLOAT",
// SF_SUPER // SF_SUPER
"S_PLAY_SUPERTRANS1", "S_PLAY_SUPERTRANS1",
@ -4009,7 +3711,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PLAY_NIGHTS_STAND", "S_PLAY_NIGHTS_STAND",
"S_PLAY_NIGHTS_FLOAT", "S_PLAY_NIGHTS_FLOAT",
"S_PLAY_NIGHTS_PAIN", "S_PLAY_NIGHTS_STUN",
"S_PLAY_NIGHTS_PULL", "S_PLAY_NIGHTS_PULL",
"S_PLAY_NIGHTS_ATTACK", "S_PLAY_NIGHTS_ATTACK",
@ -4831,12 +4533,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Individual Team Rings // Individual Team Rings
"S_TEAMRING", "S_TEAMRING",
// Special Stage Token
"S_EMMY",
// Special Stage Token // Special Stage Token
"S_TOKEN", "S_TOKEN",
"S_MOVINGTOKEN",
// CTF Flags // CTF Flags
"S_REDFLAG", "S_REDFLAG",
@ -4987,6 +4685,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SPIKED1", "S_SPIKED1",
"S_SPIKED2", "S_SPIKED2",
// Wall spikes
"S_WALLSPIKE1",
"S_WALLSPIKE2",
"S_WALLSPIKE3",
"S_WALLSPIKE4",
"S_WALLSPIKE5",
"S_WALLSPIKE6",
"S_WALLSPIKEBASE",
// Starpost // Starpost
"S_STARPOST_IDLE", "S_STARPOST_IDLE",
"S_STARPOST_FLASH", "S_STARPOST_FLASH",
@ -5173,6 +4880,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_DEMONFIRE5", "S_DEMONFIRE5",
"S_DEMONFIRE6", "S_DEMONFIRE6",
// GFZ flowers
"S_GFZFLOWERA", "S_GFZFLOWERA",
"S_GFZFLOWERB", "S_GFZFLOWERB",
"S_GFZFLOWERC", "S_GFZFLOWERC",
@ -5180,6 +4888,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_BERRYBUSH", "S_BERRYBUSH",
"S_BUSH", "S_BUSH",
// Trees (both GFZ and misc)
"S_GFZTREE",
"S_GFZBERRYTREE",
"S_GFZCHERRYTREE",
"S_CHECKERTREE",
"S_CHECKERSUNSETTREE",
"S_FHZTREE", // Frozen Hillside
"S_FHZPINKTREE",
"S_POLYGONTREE",
"S_BUSHTREE",
"S_BUSHREDTREE",
// THZ Plant // THZ Plant
"S_THZFLOWERA", "S_THZFLOWERA",
"S_THZFLOWERB", "S_THZFLOWERB",
@ -5189,6 +4909,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Deep Sea Gargoyle // Deep Sea Gargoyle
"S_GARGOYLE", "S_GARGOYLE",
"S_BIGGARGOYLE",
// DSZ Seaweed // DSZ Seaweed
"S_SEAWEED1", "S_SEAWEED1",
@ -5347,7 +5068,14 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Xmas-specific stuff // Xmas-specific stuff
"S_XMASPOLE", "S_XMASPOLE",
"S_CANDYCANE", "S_CANDYCANE",
"S_SNOWMAN", "S_SNOWMAN", // normal
"S_SNOWMANHAT", // with hat + scarf
"S_LAMPPOST1", // normal
"S_LAMPPOST2", // with snow
"S_HANGSTAR",
// Xmas GFZ bushes
"S_XMASBERRYBUSH",
"S_XMASBUSH",
// Botanic Serenity's loads of scenery states // Botanic Serenity's loads of scenery states
"S_BSZTALLFLOWER_RED", "S_BSZTALLFLOWER_RED",
@ -5539,10 +5267,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PITY4", "S_PITY4",
"S_PITY5", "S_PITY5",
"S_PITY6", "S_PITY6",
"S_PITY7",
"S_PITY8",
"S_PITY9",
"S_PITY10",
"S_FIRS1", "S_FIRS1",
"S_FIRS2", "S_FIRS2",
@ -5934,14 +5658,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FOUR2", "S_FOUR2",
"S_FIVE2", "S_FIVE2",
"S_LOCKON1",
"S_LOCKON2",
// Tag Sign // Tag Sign
"S_TTAG1", "S_TTAG",
// Got Flag Sign // Got Flag Sign
"S_GOTFLAG1", "S_GOTFLAG",
"S_GOTFLAG2", "S_GOTREDFLAG",
"S_GOTFLAG3", "S_GOTBLUEFLAG",
"S_GOTFLAG4",
"S_CORK",
// Red Ring // Red Ring
"S_RRNG1", "S_RRNG1",
@ -6424,8 +6152,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BLUEBALL", // Blue sphere replacement for special stages "MT_BLUEBALL", // Blue sphere replacement for special stages
"MT_REDTEAMRING", //Rings collectable by red team. "MT_REDTEAMRING", //Rings collectable by red team.
"MT_BLUETEAMRING", //Rings collectable by blue team. "MT_BLUETEAMRING", //Rings collectable by blue team.
"MT_EMMY", // emerald token for special stage "MT_TOKEN", // Special Stage Token
"MT_TOKEN", // Special Stage Token (uncollectible part)
"MT_REDFLAG", // Red CTF Flag "MT_REDFLAG", // Red CTF Flag
"MT_BLUEFLAG", // Blue CTF Flag "MT_BLUEFLAG", // Blue CTF Flag
"MT_EMBLEM", "MT_EMBLEM",
@ -6459,6 +6186,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SPECIALSPIKEBALL", "MT_SPECIALSPIKEBALL",
"MT_SPINFIRE", "MT_SPINFIRE",
"MT_SPIKE", "MT_SPIKE",
"MT_WALLSPIKE",
"MT_WALLSPIKEBASE",
"MT_STARPOST", "MT_STARPOST",
"MT_BIGMINE", "MT_BIGMINE",
"MT_BIGAIRMINE", "MT_BIGAIRMINE",
@ -6549,6 +6278,17 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_GFZFLOWER3", "MT_GFZFLOWER3",
"MT_BERRYBUSH", "MT_BERRYBUSH",
"MT_BUSH", "MT_BUSH",
// Trees (both GFZ and misc)
"MT_GFZTREE",
"MT_GFZBERRYTREE",
"MT_GFZCHERRYTREE",
"MT_CHECKERTREE",
"MT_CHECKERSUNSETTREE",
"MT_FHZTREE", // Frozen Hillside
"MT_FHZPINKTREE",
"MT_POLYGONTREE",
"MT_BUSHTREE",
"MT_BUSHREDTREE",
// Techno Hill Scenery // Techno Hill Scenery
"MT_THZFLOWER1", "MT_THZFLOWER1",
@ -6557,6 +6297,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
// Deep Sea Scenery // Deep Sea Scenery
"MT_GARGOYLE", // Deep Sea Gargoyle "MT_GARGOYLE", // Deep Sea Gargoyle
"MT_BIGGARGOYLE", // Deep Sea Gargoyle (Big)
"MT_SEAWEED", // DSZ Seaweed "MT_SEAWEED", // DSZ Seaweed
"MT_WATERDRIP", // Dripping Water source "MT_WATERDRIP", // Dripping Water source
"MT_WATERDROP", // Water drop from dripping water "MT_WATERDROP", // Water drop from dripping water
@ -6625,7 +6366,14 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
// Christmas Scenery // Christmas Scenery
"MT_XMASPOLE", "MT_XMASPOLE",
"MT_CANDYCANE", "MT_CANDYCANE",
"MT_SNOWMAN", "MT_SNOWMAN", // normal
"MT_SNOWMANHAT", // with hat + scarf
"MT_LAMPPOST1", // normal
"MT_LAMPPOST2", // with snow
"MT_HANGSTAR",
// Xmas GFZ bushes
"MT_XMASBERRYBUSH",
"MT_XMASBUSH",
// Botanic Serenity // Botanic Serenity
"MT_BSZTALLFLOWER_RED", "MT_BSZTALLFLOWER_RED",
@ -6732,9 +6480,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SCORE", // score logo "MT_SCORE", // score logo
"MT_DROWNNUMBERS", // Drowning Timer "MT_DROWNNUMBERS", // Drowning Timer
"MT_GOTEMERALD", // Chaos Emerald (intangible) "MT_GOTEMERALD", // Chaos Emerald (intangible)
"MT_LOCKON", // Target
"MT_TAG", // Tag Sign "MT_TAG", // Tag Sign
"MT_GOTFLAG", // Got Flag sign "MT_GOTFLAG", // Got Flag sign
"MT_GOTFLAG2", // Got Flag sign
// Ambient Sounds // Ambient Sounds
"MT_AWATERA", // Ambient Water Sound 1 "MT_AWATERA", // Ambient Water Sound 1
@ -6748,6 +6496,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_RANDOMAMBIENT", "MT_RANDOMAMBIENT",
"MT_RANDOMAMBIENT2", "MT_RANDOMAMBIENT2",
"MT_CORK",
// Ring Weapons // Ring Weapons
"MT_REDRING", "MT_REDRING",
"MT_BOUNCERING", "MT_BOUNCERING",
@ -6971,10 +6721,8 @@ static const char *const PLAYERFLAG_LIST[] = {
// Did you get a time-over? // Did you get a time-over?
"TIMEOVER", "TIMEOVER",
// Ready for Super?
"SUPERREADY",
// Character action status // Character action status
"STARTJUMP",
"JUMPED", "JUMPED",
"SPINNING", "SPINNING",
"STARTDASH", "STARTDASH",
@ -6986,12 +6734,11 @@ static const char *const PLAYERFLAG_LIST[] = {
// Sliding (usually in water) like Labyrinth/Oil Ocean // Sliding (usually in water) like Labyrinth/Oil Ocean
"SLIDING", "SLIDING",
/*** NIGHTS STUFF ***/ // Bouncing
// Is the player in NiGHTS mode? "BOUNCING",
"NIGHTSMODE",
"TRANSFERTOCLOSEST",
// Spill rings after falling /*** NIGHTS STUFF ***/
"TRANSFERTOCLOSEST",
"NIGHTSFALL", "NIGHTSFALL",
"DRILLING", "DRILLING",
"SKIDDOWN", "SKIDDOWN",
@ -7005,7 +6752,7 @@ static const char *const PLAYERFLAG_LIST[] = {
"ANALOGMODE", // Analog mode? "ANALOGMODE", // Analog mode?
"CANCARRY", // Can carry? "CANCARRY", // Can carry?
"SHIELDABILITY", // Thokked with shield ability "SHIELDABILITY", // Thokked with shield ability
"FORCEJUMPDAMAGE", // Force jump damage "NOJUMPDAMAGE", // No jump damage
NULL // stop loop here. NULL // stop loop here.
}; };
@ -7154,8 +6901,7 @@ static const char *const POWERS_LIST[] = {
"NIGHTS_LINKFREEZE", "NIGHTS_LINKFREEZE",
//for linedef exec 427 //for linedef exec 427
"NOCONTROL", "NOCONTROL"
"INGOOP" // In goop
}; };
static const char *const HUDITEMS_LIST[] = { static const char *const HUDITEMS_LIST[] = {
@ -7247,14 +6993,15 @@ struct {
// Frame settings // Frame settings
{"FF_FRAMEMASK",FF_FRAMEMASK}, {"FF_FRAMEMASK",FF_FRAMEMASK},
{"FF_VERTICALFLIP",FF_VERTICALFLIP}, {"FF_SPR2SUPER",FF_SPR2SUPER},
{"FF_PAPERSPRITE",FF_PAPERSPRITE},
{"FF_SPR2ENDSTATE",FF_SPR2ENDSTATE}, {"FF_SPR2ENDSTATE",FF_SPR2ENDSTATE},
{"FF_SPR2MIDSTART",FF_SPR2MIDSTART}, {"FF_SPR2MIDSTART",FF_SPR2MIDSTART},
{"FF_ANIMATE",FF_ANIMATE}, {"FF_ANIMATE",FF_ANIMATE},
{"FF_RANDOMANIM",FF_RANDOMANIM}, {"FF_RANDOMANIM",FF_RANDOMANIM},
{"FF_GLOBALANIM",FF_GLOBALANIM}, {"FF_GLOBALANIM",FF_GLOBALANIM},
{"FF_FULLBRIGHT",FF_FULLBRIGHT}, {"FF_FULLBRIGHT",FF_FULLBRIGHT},
{"FF_VERTICALFLIP",FF_VERTICALFLIP},
{"FF_PAPERSPRITE",FF_PAPERSPRITE},
{"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSMASK",FF_TRANSMASK},
{"FF_TRANSSHIFT",FF_TRANSSHIFT}, {"FF_TRANSSHIFT",FF_TRANSSHIFT},
// new preshifted translucency (used in source) // new preshifted translucency (used in source)
@ -7317,6 +7064,7 @@ struct {
{"LF2_RECORDATTACK",LF2_RECORDATTACK}, {"LF2_RECORDATTACK",LF2_RECORDATTACK},
{"LF2_NIGHTSATTACK",LF2_NIGHTSATTACK}, {"LF2_NIGHTSATTACK",LF2_NIGHTSATTACK},
{"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED}, {"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED},
{"LF2_WIDEICON",LF2_WIDEICON},
// NiGHTS grades // NiGHTS grades
{"GRADE_F",GRADE_F}, {"GRADE_F",GRADE_F},
@ -7378,6 +7126,8 @@ struct {
{"CR_NONE",CR_NONE}, {"CR_NONE",CR_NONE},
{"CR_GENERIC",CR_GENERIC}, {"CR_GENERIC",CR_GENERIC},
{"CR_PLAYER",CR_PLAYER}, {"CR_PLAYER",CR_PLAYER},
{"CR_NIGHTSMODE",CR_NIGHTSMODE},
{"CR_BRAKGOOP",CR_BRAKGOOP},
{"CR_ZOOMTUBE",CR_ZOOMTUBE}, {"CR_ZOOMTUBE",CR_ZOOMTUBE},
{"CR_ROPEHANG",CR_ROPEHANG}, {"CR_ROPEHANG",CR_ROPEHANG},
{"CR_MACESPIN",CR_MACESPIN}, {"CR_MACESPIN",CR_MACESPIN},
@ -7393,8 +7143,8 @@ struct {
// Character flags (skinflags_t) // Character flags (skinflags_t)
{"SF_SUPER",SF_SUPER}, {"SF_SUPER",SF_SUPER},
{"SF_SUPERANIMS",SF_SUPERANIMS}, {"SF_NOSUPERSPIN",SF_NOSUPERSPIN},
{"SF_SUPERSPIN",SF_SUPERSPIN}, {"SF_NOSPINDASHDUST",SF_NOSPINDASHDUST},
{"SF_HIRES",SF_HIRES}, {"SF_HIRES",SF_HIRES},
{"SF_NOSKID",SF_NOSKID}, {"SF_NOSKID",SF_NOSKID},
{"SF_NOSPEEDADJUST",SF_NOSPEEDADJUST}, {"SF_NOSPEEDADJUST",SF_NOSPEEDADJUST},
@ -7404,7 +7154,9 @@ struct {
{"SF_STOMPDAMAGE",SF_STOMPDAMAGE}, {"SF_STOMPDAMAGE",SF_STOMPDAMAGE},
{"SF_MARIODAMAGE",SF_MARIODAMAGE}, {"SF_MARIODAMAGE",SF_MARIODAMAGE},
{"SF_MACHINE",SF_MACHINE}, {"SF_MACHINE",SF_MACHINE},
{"SF_NOSPINDASHDUST",SF_NOSPINDASHDUST}, {"SF_DASHMODE",SF_DASHMODE},
{"SF_FASTEDGE",SF_FASTEDGE},
{"SF_MULTIABILITY",SF_MULTIABILITY},
// Character abilities! // Character abilities!
// Primary // Primary
@ -7422,12 +7174,12 @@ struct {
{"CA_JUMPBOOST",CA_JUMPBOOST}, {"CA_JUMPBOOST",CA_JUMPBOOST},
{"CA_AIRDRILL",CA_AIRDRILL}, {"CA_AIRDRILL",CA_AIRDRILL},
{"CA_JUMPTHOK",CA_JUMPTHOK}, {"CA_JUMPTHOK",CA_JUMPTHOK},
{"CA_DASHMODE",CA_DASHMODE}, {"CA_BOUNCE",CA_BOUNCE},
{"CA_TWINSPIN",CA_TWINSPIN}, {"CA_TWINSPIN",CA_TWINSPIN},
// Secondary // Secondary
{"CA2_NONE",CA2_NONE}, // now slot 0! {"CA2_NONE",CA2_NONE}, // now slot 0!
{"CA2_SPINDASH",CA2_SPINDASH}, {"CA2_SPINDASH",CA2_SPINDASH},
{"CA2_MULTIABILITY",CA2_MULTIABILITY}, {"CA2_GUNSLINGER",CA2_GUNSLINGER},
{"CA2_MELEE",CA2_MELEE}, {"CA2_MELEE",CA2_MELEE},
// Sound flags // Sound flags
@ -7496,7 +7248,7 @@ struct {
{"PA_EDGE",PA_EDGE}, {"PA_EDGE",PA_EDGE},
{"PA_WALK",PA_WALK}, {"PA_WALK",PA_WALK},
{"PA_RUN",PA_RUN}, {"PA_RUN",PA_RUN},
{"PA_PEEL",PA_PEEL}, {"PA_DASH",PA_DASH},
{"PA_PAIN",PA_PAIN}, {"PA_PAIN",PA_PAIN},
{"PA_ROLL",PA_ROLL}, {"PA_ROLL",PA_ROLL},
{"PA_JUMP",PA_JUMP}, {"PA_JUMP",PA_JUMP},
@ -7685,6 +7437,7 @@ struct {
{"V_70TRANS",V_70TRANS}, {"V_70TRANS",V_70TRANS},
{"V_80TRANS",V_80TRANS}, {"V_80TRANS",V_80TRANS},
{"V_90TRANS",V_90TRANS}, {"V_90TRANS",V_90TRANS},
{"V_STATIC",V_STATIC},
{"V_HUDTRANSHALF",V_HUDTRANSHALF}, {"V_HUDTRANSHALF",V_HUDTRANSHALF},
{"V_HUDTRANS",V_HUDTRANS}, {"V_HUDTRANS",V_HUDTRANS},
{"V_HUDTRANSDOUBLE",V_HUDTRANSDOUBLE}, {"V_HUDTRANSDOUBLE",V_HUDTRANSDOUBLE},

View file

@ -90,6 +90,10 @@ static unsigned long nombre = NEWTICRATE*10;
static void I_BlitScreenVesa1(void); //see later static void I_BlitScreenVesa1(void); //see later
void I_FinishUpdate (void) void I_FinishUpdate (void)
{ {
// draw captions if enabled
if (cv_closedcaptioning.value)
SCR_ClosedCaptions();
// draw FPS if enabled // draw FPS if enabled
if (cv_ticrate.value) if (cv_ticrate.value)
SCR_DisplayTicRate(); SCR_DisplayTicRate();

View file

@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update. // it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously. // Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 22 #define MODVERSION 24
// ========================================================================= // =========================================================================
@ -222,7 +222,7 @@ extern FILE *logstream;
// NOTE: it needs more than this to increase the number of players... // NOTE: it needs more than this to increase the number of players...
#define MAXPLAYERS 32 #define MAXPLAYERS 32
#define MAXSKINS MAXPLAYERS #define MAXSKINS 32
#define PLAYERSMASK (MAXPLAYERS-1) #define PLAYERSMASK (MAXPLAYERS-1)
#define MAXPLAYERNAME 21 #define MAXPLAYERNAME 21
@ -543,4 +543,11 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls.
//#define PAPER_COLLISIONCORRECTION //#define PAPER_COLLISIONCORRECTION
/// Hudname padding.
#define SKINNAMEPADDING
/// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink.
/// \note Required for proper collision with moving sloped surfaces that have sector specials on them.
//#define SECTORSPECIALSAFTERTHINK
#endif // __DOOMDEF__ #endif // __DOOMDEF__

View file

@ -242,6 +242,8 @@ typedef struct
UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below
UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus
char selectheading[22]; ///< Level select heading. Allows for controllable grouping.
// Freed animals stuff. // Freed animals stuff.
UINT8 numFlickies; ///< Internal. For freed flicky support. UINT8 numFlickies; ///< Internal. For freed flicky support.
mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
@ -268,6 +270,7 @@ typedef struct
#define LF2_RECORDATTACK 4 ///< Show this map in Time Attack #define LF2_RECORDATTACK 4 ///< Show this map in Time Attack
#define LF2_NIGHTSATTACK 8 ///< Show this map in NiGHTS mode menu #define LF2_NIGHTSATTACK 8 ///< Show this map in NiGHTS mode menu
#define LF2_NOVISITNEEDED 16 ///< Available in time attack/nights mode without visiting the level #define LF2_NOVISITNEEDED 16 ///< Available in time attack/nights mode without visiting the level
#define LF2_WIDEICON 32 ///< If you're in a circumstance where it fits, use a wide map icon
extern mapheader_t* mapheaderinfo[NUMMAPS]; extern mapheader_t* mapheaderinfo[NUMMAPS];
@ -312,7 +315,7 @@ enum GameType
NUMGAMETYPES NUMGAMETYPES
}; };
// If you alter this list, update gametype_cons_t in m_menu.c // If you alter this list, update dehacked.c, and gametype_cons_t and MISC_ChangeGameTypeMenu in m_menu.c
extern tic_t totalplaytime; extern tic_t totalplaytime;
@ -377,6 +380,7 @@ nightsdata_t ntemprecords;
extern UINT32 token; ///< Number of tokens collected in a level extern UINT32 token; ///< Number of tokens collected in a level
extern UINT32 tokenlist; ///< List of tokens collected extern UINT32 tokenlist; ///< List of tokens collected
extern boolean gottoken; ///< Did you get a token? Used for end of act
extern INT32 tokenbits; ///< Used for setting token bits extern INT32 tokenbits; ///< Used for setting token bits
extern INT32 sstimer; ///< Time allotted in the special stage extern INT32 sstimer; ///< Time allotted in the special stage
extern UINT32 bluescore; ///< Blue Team Scores extern UINT32 bluescore; ///< Blue Team Scores
@ -450,19 +454,17 @@ extern mapthing_t *redctfstarts[MAXPLAYERS]; // CTF
#if defined (macintosh) #if defined (macintosh)
#define DEBFILE(msg) I_OutputMsg(msg) #define DEBFILE(msg) I_OutputMsg(msg)
extern FILE *debugfile;
#else #else
#define DEBUGFILE #define DEBUGFILE
#ifdef DEBUGFILE #ifdef DEBUGFILE
#define DEBFILE(msg) { if (debugfile) { fputs(msg, debugfile); fflush(debugfile); } } #define DEBFILE(msg) { if (debugfile) { fputs(msg, debugfile); fflush(debugfile); } }
extern FILE *debugfile;
#else #else
#define DEBFILE(msg) {} #define DEBFILE(msg) {}
extern FILE *debugfile;
#endif #endif
#endif #endif
#ifdef DEBUGFILE #ifdef DEBUGFILE
extern FILE *debugfile;
extern INT32 debugload; extern INT32 debugload;
#endif #endif

View file

@ -434,7 +434,6 @@ void F_StartIntro(void)
G_SetGamestate(GS_INTRO); G_SetGamestate(GS_INTRO);
gameaction = ga_nothing; gameaction = ga_nothing;
playerdeadview = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD(); CON_ClearHUD();
@ -1125,7 +1124,6 @@ void F_StartCredits(void)
} }
gameaction = ga_nothing; gameaction = ga_nothing;
playerdeadview = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD(); CON_ClearHUD();
@ -1272,7 +1270,6 @@ void F_StartGameEvaluation(void)
G_SaveGame((UINT32)cursaveslot); G_SaveGame((UINT32)cursaveslot);
gameaction = ga_nothing; gameaction = ga_nothing;
playerdeadview = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD(); CON_ClearHUD();
@ -1383,7 +1380,6 @@ void F_StartGameEnd(void)
G_SetGamestate(GS_GAMEEND); G_SetGamestate(GS_GAMEEND);
gameaction = ga_nothing; gameaction = ga_nothing;
playerdeadview = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD(); CON_ClearHUD();
@ -1586,7 +1582,6 @@ void F_StartContinue(void)
gameaction = ga_nothing; gameaction = ga_nothing;
keypressed = false; keypressed = false;
playerdeadview = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD(); CON_ClearHUD();
@ -1728,7 +1723,7 @@ static void F_AdvanceToNextScene(void)
void F_EndCutScene(void) void F_EndCutScene(void)
{ {
cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later cutsceneover = true; // do this first, just in case G_EndGame or something wants to turn it back false later
if (runningprecutscene) if (runningprecutscene)
{ {
if (server) if (server)
@ -1743,7 +1738,7 @@ void F_EndCutScene(void)
else if (nextmap < 1100-1) else if (nextmap < 1100-1)
G_NextLevel(); G_NextLevel();
else else
Y_EndGame(); G_EndGame();
} }
} }
@ -1755,7 +1750,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
G_SetGamestate(GS_CUTSCENE); G_SetGamestate(GS_CUTSCENE);
gameaction = ga_nothing; gameaction = ga_nothing;
playerdeadview = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();

View file

@ -86,7 +86,7 @@ INT32 lastwipetic = 0;
static UINT8 *wipe_scr_start; //screen 3 static UINT8 *wipe_scr_start; //screen 3
static UINT8 *wipe_scr_end; //screen 4 static UINT8 *wipe_scr_end; //screen 4
static UINT8 *wipe_scr; //screen 0 (main drawing) static UINT8 *wipe_scr; //screen 0 (main drawing)
static fixed_t paldiv; static fixed_t paldiv = 0;
/** Create fademask_t from lump /** Create fademask_t from lump
* *
@ -145,7 +145,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
while (lsize--) while (lsize--)
{ {
// Determine pixel to use from fademask // Determine pixel to use from fademask
pcolor = &pLocalPalette[*lump++]; pcolor = &pMasterPalette[*lump++];
*mask++ = FixedDiv((pcolor->s.red+1)<<FRACBITS, paldiv)>>FRACBITS; *mask++ = FixedDiv((pcolor->s.red+1)<<FRACBITS, paldiv)>>FRACBITS;
} }
@ -337,7 +337,8 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
UINT8 wipeframe = 0; UINT8 wipeframe = 0;
fademask_t *fmask; fademask_t *fmask;
paldiv = FixedDiv(257<<FRACBITS, 11<<FRACBITS); if (!paldiv)
paldiv = FixedDiv(257<<FRACBITS, 11<<FRACBITS);
// Init the wipe // Init the wipe
WipeInAction = true; WipeInAction = true;

View file

@ -156,6 +156,7 @@ UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage.
UINT16 emeralds; UINT16 emeralds;
UINT32 token; // Number of tokens collected in a level UINT32 token; // Number of tokens collected in a level
UINT32 tokenlist; // List of tokens collected UINT32 tokenlist; // List of tokens collected
boolean gottoken; // Did you get a token? Used for end of act
INT32 tokenbits; // Used for setting token bits INT32 tokenbits; // Used for setting token bits
// Old Special Stage // Old Special Stage
@ -697,8 +698,7 @@ void G_SetNightsRecords(void)
free(gpath); free(gpath);
// If the mare count changed, this will update the score display // If the mare count changed, this will update the score display
CV_AddValue(&cv_nextmap, 1); Nextmap_OnChange();
CV_AddValue(&cv_nextmap, -1);
} }
// for consistency among messages: this modifies the game and removes savemoddata. // for consistency among messages: this modifies the game and removes savemoddata.
@ -1012,14 +1012,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
if (turnleft) if (turnleft)
cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]);
} }
if (cv_analog.value || twodlevel if (twodlevel
|| (player->mo && (player->mo->flags2 & MF2_TWOD)) || (player->mo && (player->mo->flags2 & MF2_TWOD))
|| (!demoplayback && (player->climbing || (!demoplayback && (player->climbing
|| (player->pflags & PF_NIGHTSMODE) || (player->powers[pw_carry] == CR_NIGHTSMODE)
|| (player->pflags & PF_SLIDING) || (player->pflags & (PF_SLIDING|PF_FORCESTRAFE))))) // Analog
|| (player->pflags & PF_FORCESTRAFE)))) // Analog
forcestrafe = true; forcestrafe = true;
if (forcestrafe) // Analog if (forcestrafe)
{ {
if (turnright) if (turnright)
side += sidemove[speed]; side += sidemove[speed];
@ -1032,6 +1031,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
side += ((axis * sidemove[1]) >> 10); side += ((axis * sidemove[1]) >> 10);
} }
} }
else if (cv_analog.value) // Analog
{
if (turnright)
cmd->buttons |= BT_CAMRIGHT;
if (turnleft)
cmd->buttons |= BT_CAMLEFT;
}
else else
{ {
if (turnright) if (turnright)
@ -1119,15 +1125,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
if (PLAYER1INPUTDOWN(gc_use)) if (PLAYER1INPUTDOWN(gc_use))
cmd->buttons |= BT_USE; cmd->buttons |= BT_USE;
// Camera Controls
if (cv_debug || cv_analog.value || demoplayback || objectplacing || player->pflags & PF_NIGHTSMODE)
{
if (PLAYER1INPUTDOWN(gc_camleft))
cmd->buttons |= BT_CAMLEFT;
if (PLAYER1INPUTDOWN(gc_camright))
cmd->buttons |= BT_CAMRIGHT;
}
if (PLAYER1INPUTDOWN(gc_camreset)) if (PLAYER1INPUTDOWN(gc_camreset))
{ {
if (camera.chase && !resetdown) if (camera.chase && !resetdown)
@ -1189,10 +1186,19 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
if (!mouseaiming && cv_mousemove.value) if (!mouseaiming && cv_mousemove.value)
forward += mousey; forward += mousey;
if (cv_analog.value || if ((!demoplayback && (player->climbing
(!demoplayback && (player->climbing
|| (player->pflags & PF_SLIDING)))) // Analog for mouse || (player->pflags & PF_SLIDING)))) // Analog for mouse
side += mousex*2; side += mousex*2;
else if (cv_analog.value)
{
if (mousex)
{
if (mousex > 0)
cmd->buttons |= BT_CAMRIGHT;
else
cmd->buttons |= BT_CAMLEFT;
}
}
else else
cmd->angleturn = (INT16)(cmd->angleturn - (mousex*8)); cmd->angleturn = (INT16)(cmd->angleturn - (mousex*8));
@ -1227,9 +1233,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
cmd->sidemove = (SINT8)(cmd->sidemove + side); cmd->sidemove = (SINT8)(cmd->sidemove + side);
if (cv_analog.value) { if (cv_analog.value) {
cmd->angleturn = (INT16)(thiscam->angle >> 16);
if (player->awayviewtics) if (player->awayviewtics)
cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16);
else
cmd->angleturn = (INT16)(thiscam->angle >> 16);
} }
else else
{ {
@ -1303,12 +1310,11 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
if (turnleft) if (turnleft)
cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]);
} }
if (cv_analog2.value || twodlevel if (twodlevel
|| (player->mo && (player->mo->flags2 & MF2_TWOD)) || (player->mo && (player->mo->flags2 & MF2_TWOD))
|| player->climbing || player->climbing
|| (player->pflags & PF_NIGHTSMODE) || (player->powers[pw_carry] == CR_NIGHTSMODE)
|| (player->pflags & PF_SLIDING) || (player->pflags & (PF_SLIDING|PF_FORCESTRAFE))) // Analog
|| (player->pflags & PF_FORCESTRAFE)) // Analog
forcestrafe = true; forcestrafe = true;
if (forcestrafe) // Analog if (forcestrafe) // Analog
{ {
@ -1323,6 +1329,13 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
side += ((axis * sidemove[1]) >> 10); side += ((axis * sidemove[1]) >> 10);
} }
} }
else if (cv_analog2.value) // Analog
{
if (turnright)
cmd->buttons |= BT_CAMRIGHT;
if (turnleft)
cmd->buttons |= BT_CAMLEFT;
}
else else
{ {
if (turnright) if (turnright)
@ -1407,15 +1420,6 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
if (PLAYER2INPUTDOWN(gc_use)) if (PLAYER2INPUTDOWN(gc_use))
cmd->buttons |= BT_USE; cmd->buttons |= BT_USE;
// Camera Controls
if (cv_debug || cv_analog2.value || player->pflags & PF_NIGHTSMODE)
{
if (PLAYER2INPUTDOWN(gc_camleft))
cmd->buttons |= BT_CAMLEFT;
if (PLAYER2INPUTDOWN(gc_camright))
cmd->buttons |= BT_CAMRIGHT;
}
if (PLAYER2INPUTDOWN(gc_camreset)) if (PLAYER2INPUTDOWN(gc_camreset))
{ {
if (camera2.chase && !resetdown) if (camera2.chase && !resetdown)
@ -1477,9 +1481,19 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
if (!mouseaiming && cv_mousemove2.value) if (!mouseaiming && cv_mousemove2.value)
forward += mouse2y; forward += mouse2y;
if (cv_analog2.value || player->climbing if (player->climbing
|| (player->pflags & PF_SLIDING)) // Analog for mouse || (player->pflags & PF_SLIDING)) // Analog for mouse
side += mouse2x*2; side += mouse2x*2;
else if (cv_analog2.value)
{
if (mouse2x)
{
if (mouse2x > 0)
cmd->buttons |= BT_CAMRIGHT;
else
cmd->buttons |= BT_CAMLEFT;
}
}
else else
cmd->angleturn = (INT16)(cmd->angleturn - (mouse2x*8)); cmd->angleturn = (INT16)(cmd->angleturn - (mouse2x*8));
@ -1527,9 +1541,10 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
} }
if (cv_analog2.value) { if (cv_analog2.value) {
cmd->angleturn = (INT16)(thiscam->angle >> 16);
if (player->awayviewtics) if (player->awayviewtics)
cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16);
else
cmd->angleturn = (INT16)(thiscam->angle >> 16);
} }
else else
{ {
@ -1566,11 +1581,6 @@ static void Analog_OnChange(void)
// cameras are not initialized at this point // cameras are not initialized at this point
if (leveltime > 1)
CV_SetValue(&cv_cam_dist, 128);
if (cv_analog.value || demoplayback)
CV_SetValue(&cv_cam_dist, 192);
if (!cv_chasecam.value && cv_analog.value) { if (!cv_chasecam.value && cv_analog.value) {
CV_SetValue(&cv_analog, 0); CV_SetValue(&cv_analog, 0);
return; return;
@ -1591,11 +1601,6 @@ static void Analog2_OnChange(void)
// cameras are not initialized at this point // cameras are not initialized at this point
if (leveltime > 1)
CV_SetValue(&cv_cam2_dist, 128);
if (cv_analog2.value)
CV_SetValue(&cv_cam2_dist, 192);
if (!cv_chasecam2.value && cv_analog2.value) { if (!cv_chasecam2.value && cv_analog2.value) {
CV_SetValue(&cv_analog2, 0); CV_SetValue(&cv_analog2, 0);
return; return;
@ -2082,6 +2087,7 @@ void G_PlayerReborn(INT32 player)
UINT8 mare; UINT8 mare;
UINT8 skincolor; UINT8 skincolor;
INT32 skin; INT32 skin;
UINT32 availabilities;
tic_t jointime; tic_t jointime;
boolean spectator; boolean spectator;
INT16 bot; INT16 bot;
@ -2106,6 +2112,7 @@ void G_PlayerReborn(INT32 player)
skincolor = players[player].skincolor; skincolor = players[player].skincolor;
skin = players[player].skin; skin = players[player].skin;
availabilities = players[player].availabilities;
camerascale = players[player].camerascale; camerascale = players[player].camerascale;
shieldscale = players[player].shieldscale; shieldscale = players[player].shieldscale;
charability = players[player].charability; charability = players[player].charability;
@ -2151,6 +2158,7 @@ void G_PlayerReborn(INT32 player)
// save player config truth reborn // save player config truth reborn
p->skincolor = skincolor; p->skincolor = skincolor;
p->skin = skin; p->skin = skin;
p->availabilities = availabilities;
p->camerascale = camerascale; p->camerascale = camerascale;
p->shieldscale = shieldscale; p->shieldscale = shieldscale;
p->charability = charability; p->charability = charability;
@ -2301,6 +2309,9 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
if (starpost) //Don't even bother with looking for a place to spawn. if (starpost) //Don't even bother with looking for a place to spawn.
{ {
P_MovePlayerToStarpost(playernum); P_MovePlayerToStarpost(playernum);
#ifdef HAVE_BLUA
LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
#endif
return; return;
} }
@ -2625,7 +2636,7 @@ void G_ExitLevel(void)
CONS_Printf(M_GetText("The round has ended.\n")); CONS_Printf(M_GetText("The round has ended.\n"));
// Remove CEcho text on round end. // Remove CEcho text on round end.
HU_DoCEcho(""); HU_ClearCEcho();
} }
} }
@ -2773,7 +2784,6 @@ static INT16 RandMap(INT16 tolflags, INT16 pprevmap)
static void G_DoCompleted(void) static void G_DoCompleted(void)
{ {
INT32 i; INT32 i;
boolean gottoken = false;
tokenlist = 0; // Reset the list tokenlist = 0; // Reset the list
@ -2859,10 +2869,9 @@ static void G_DoCompleted(void)
if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametype == GT_RACE || gametype == GT_COMPETITION)) if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametype == GT_RACE || gametype == GT_COMPETITION))
nextmap = (INT16)(spstage_start-1); nextmap = (INT16)(spstage_start-1);
if (gametype == GT_COOP && token) if ((gottoken = (gametype == GT_COOP && token)))
{ {
token--; token--;
gottoken = true;
if (!(emeralds & EMERALD1)) if (!(emeralds & EMERALD1))
nextmap = (INT16)(sstage_start - 1); // Special Stage 1 nextmap = (INT16)(sstage_start - 1); // Special Stage 1
@ -2921,7 +2930,7 @@ void G_AfterIntermission(void)
if (nextmap < 1100-1) if (nextmap < 1100-1)
G_NextLevel(); G_NextLevel();
else else
Y_EndGame(); G_EndGame();
} }
} }
@ -3007,6 +3016,38 @@ static void G_DoContinued(void)
gameaction = ga_nothing; gameaction = ga_nothing;
} }
//
// G_EndGame (formerly Y_EndGame)
// Frankly this function fits better in g_game.c than it does in y_inter.c
//
// ...Gee, (why) end the game?
// Because G_AfterIntermission and F_EndCutscene would
// both do this exact same thing *in different ways* otherwise,
// which made it so that you could only unlock Ultimate mode
// if you had a cutscene after the final level and crap like that.
// This function simplifies it so only one place has to be updated
// when something new is added.
void G_EndGame(void)
{
// Only do evaluation and credits in coop games.
if (gametype == GT_COOP)
{
if (nextmap == 1102-1) // end game with credits
{
F_StartCredits();
return;
}
if (nextmap == 1101-1) // end game with evaluation
{
F_StartGameEvaluation();
return;
}
}
// 1100 or competitive multiplayer, so go back to title screen.
D_StartTitle();
}
// //
// G_LoadGameSettings // G_LoadGameSettings
// //
@ -3541,7 +3582,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b
// This is the map command interpretation something like Command_Map_f // This is the map command interpretation something like Command_Map_f
// //
// called at: map cmd execution, doloadgame, doplaydemo // called at: map cmd execution, doloadgame, doplaydemo
void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean skipprecutscene) void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean skipprecutscene, boolean FLS)
{ {
INT32 i; INT32 i;
@ -3571,7 +3612,8 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
if (netgame || multiplayer) if (netgame || multiplayer)
{ {
players[i].lives = cv_startinglives.value; if (!FLS || (players[i].lives < cv_startinglives.value))
players[i].lives = cv_startinglives.value;
players[i].continues = 0; players[i].continues = 0;
} }
else if (pultmode) else if (pultmode)
@ -3585,13 +3627,16 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
players[i].continues = 1; players[i].continues = 1;
} }
if (!((netgame || multiplayer) && (FLS)))
players[i].score = 0;
// The latter two should clear by themselves, but just in case // The latter two should clear by themselves, but just in case
players[i].pflags &= ~(PF_TAGIT|PF_TAGGED|PF_FULLSTASIS); players[i].pflags &= ~(PF_TAGIT|PF_TAGGED|PF_FULLSTASIS);
// Clear cheatcodes too, just in case. // Clear cheatcodes too, just in case.
players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS); players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS);
players[i].score = players[i].xtralife = 0; players[i].xtralife = 0;
} }
// Reset unlockable triggers // Reset unlockable triggers
@ -3625,7 +3670,6 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
mapmusflags |= MUSIC_RELOADRESET; mapmusflags |= MUSIC_RELOADRESET;
ultimatemode = pultmode; ultimatemode = pultmode;
playerdeadview = false;
automapactive = false; automapactive = false;
imcontinuing = false; imcontinuing = false;
@ -3653,6 +3697,9 @@ char *G_BuildMapTitle(INT32 mapnum)
{ {
char *title = NULL; char *title = NULL;
if (!mapheaderinfo[mapnum-1])
P_AllocMapHeader(mapnum-1);
if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, "")) if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, ""))
{ {
size_t len = 1; size_t len = 1;
@ -3886,7 +3933,7 @@ void G_GhostAddColor(ghostcolor_t color)
ghostext.color = (UINT8)color; ghostext.color = (UINT8)color;
} }
void G_GhostAddScale(UINT16 scale) void G_GhostAddScale(fixed_t scale)
{ {
if (!demorecording || !(demoflags & DF_GHOST)) if (!demorecording || !(demoflags & DF_GHOST))
return; return;
@ -3920,12 +3967,8 @@ void G_WriteGhostTic(mobj_t *ghost)
if (!(demoflags & DF_GHOST)) if (!(demoflags & DF_GHOST))
return; // No ghost data to write. return; // No ghost data to write.
if (ghost->player && ghost->player->pflags & PF_NIGHTSMODE && ghost->tracer) if (ghost->player && ghost->player->powers[pw_carry] == CR_NIGHTSMODE) // We're talking about the NiGHTS thing, not the normal platforming thing!
{
// We're talking about the NiGHTS thing, not the normal platforming thing!
ziptic |= GZT_NIGHTS; ziptic |= GZT_NIGHTS;
ghost = ghost->tracer;
}
ziptic_p = demo_p++; // the ziptic, written at the end of this function ziptic_p = demo_p++; // the ziptic, written at the end of this function
@ -4107,11 +4150,9 @@ void G_ConsGhostTic(void)
demo_p++; demo_p++;
if (ziptic & GZT_SPR2) if (ziptic & GZT_SPR2)
demo_p++; demo_p++;
if(ziptic & GZT_NIGHTS) { if (ziptic & GZT_NIGHTS) {
if (!testmo->player || !(testmo->player->pflags & PF_NIGHTSMODE) || !testmo->tracer) if (!testmo->player || !(testmo->player->powers[pw_carry] == CR_NIGHTSMODE))
nightsfail = true; nightsfail = true;
else
testmo = testmo->tracer;
} }
if (ziptic & GZT_EXTRA) if (ziptic & GZT_EXTRA)
@ -5142,7 +5183,7 @@ void G_DoPlayDemo(char *defdemoname)
memset(playeringame,0,sizeof(playeringame)); memset(playeringame,0,sizeof(playeringame));
playeringame[0] = true; playeringame[0] = true;
P_SetRandSeed(randseed); P_SetRandSeed(randseed);
G_InitNew(false, G_BuildMapName(gamemap), true, true); G_InitNew(false, G_BuildMapName(gamemap), true, true, false);
// Set skin // Set skin
SetPlayerSkin(0, skin); SetPlayerSkin(0, skin);

View file

@ -56,6 +56,9 @@ extern INT16 rw_maximums[NUM_WEAPONS];
// used in game menu // used in game menu
extern consvar_t cv_crosshair, cv_crosshair2; extern consvar_t cv_crosshair, cv_crosshair2;
extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_mousemove; extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_mousemove;
extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_mousemove2;
extern consvar_t cv_useranalog, cv_useranalog2;
extern consvar_t cv_analog, cv_analog2;
extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_fireaxis,cv_firenaxis; extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_fireaxis,cv_firenaxis;
extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_fireaxis2,cv_firenaxis2; extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_fireaxis2,cv_firenaxis2;
extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest;
@ -89,7 +92,7 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo);
void G_DoReborn(INT32 playernum); void G_DoReborn(INT32 playernum);
void G_PlayerReborn(INT32 player); void G_PlayerReborn(INT32 player);
void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer,
boolean skipprecutscene); boolean skipprecutscene, boolean FLS);
char *G_BuildMapTitle(INT32 mapnum); char *G_BuildMapTitle(INT32 mapnum);
// XMOD spawning // XMOD spawning
@ -139,7 +142,7 @@ void G_GhostAddSpin(void);
void G_GhostAddRev(void); void G_GhostAddRev(void);
void G_GhostAddColor(ghostcolor_t color); void G_GhostAddColor(ghostcolor_t color);
void G_GhostAddFlip(void); void G_GhostAddFlip(void);
void G_GhostAddScale(UINT16 scale); void G_GhostAddScale(fixed_t scale);
void G_GhostAddHit(mobj_t *victim); void G_GhostAddHit(mobj_t *victim);
void G_WriteGhostTic(mobj_t *ghost); void G_WriteGhostTic(mobj_t *ghost);
void G_ConsGhostTic(void); void G_ConsGhostTic(void);
@ -171,6 +174,7 @@ void G_NextLevel(void);
void G_Continue(void); void G_Continue(void);
void G_UseContinue(void); void G_UseContinue(void);
void G_AfterIntermission(void); void G_AfterIntermission(void);
void G_EndGame(void); // moved from y_inter.c/h and renamed
void G_Ticker(boolean run); void G_Ticker(boolean run);
boolean G_Responder(event_t *ev); boolean G_Responder(event_t *ev);

View file

@ -25,10 +25,10 @@ static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY
static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}}; static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}};
// mouse values are used once // mouse values are used once
consvar_t cv_mousesens = {"mousesens", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mousesens = {"mousesens", "12", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousesens2 = {"mousesens2", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mousesens2 = {"mousesens2", "12", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mouseysens = {"mouseysens", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mouseysens = {"mouseysens", "12", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mouseysens2 = {"mouseysens2", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mouseysens2 = {"mouseysens2", "12", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_controlperkey = {"controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_controlperkey = {"controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
INT32 mousex, mousey; INT32 mousex, mousey;
@ -977,8 +977,6 @@ static const char *gamecontrolname[num_gamecontrols] =
"tossflag", "tossflag",
"use", "use",
"camtoggle", "camtoggle",
"camleft",
"camright",
"camreset", "camreset",
"lookup", "lookup",
"lookdown", "lookdown",
@ -1074,8 +1072,6 @@ void G_Controldefault(void)
gamecontrol[gc_use ][0] = KEY_JOY1+1; //B gamecontrol[gc_use ][0] = KEY_JOY1+1; //B
gamecontrol[gc_use ][1] = '.'; gamecontrol[gc_use ][1] = '.';
gamecontrol[gc_camtoggle ][1] = ','; gamecontrol[gc_camtoggle ][1] = ',';
gamecontrol[gc_camleft ][0] = 'o';
gamecontrol[gc_camright ][0] = 'p';
gamecontrol[gc_camreset ][0] = 'c'; gamecontrol[gc_camreset ][0] = 'c';
gamecontrol[gc_lookup ][0] = KEY_PGUP; gamecontrol[gc_lookup ][0] = KEY_PGUP;
gamecontrol[gc_lookdown ][0] = KEY_PGDN; gamecontrol[gc_lookdown ][0] = KEY_PGDN;
@ -1154,10 +1150,8 @@ void G_Controldefault(void)
#else #else
void G_Controldefault(void) void G_Controldefault(void)
{ {
gamecontrol[gc_forward ][0] = KEY_UPARROW; gamecontrol[gc_forward ][0] = 'w';
gamecontrol[gc_forward ][1] = 'w'; gamecontrol[gc_backward ][0] = 's';
gamecontrol[gc_backward ][0] = KEY_DOWNARROW;
gamecontrol[gc_backward ][1] = 's';
gamecontrol[gc_strafeleft ][0] = 'a'; gamecontrol[gc_strafeleft ][0] = 'a';
gamecontrol[gc_straferight][0] = 'd'; gamecontrol[gc_straferight][0] = 'd';
gamecontrol[gc_turnleft ][0] = KEY_LEFTARROW; gamecontrol[gc_turnleft ][0] = KEY_LEFTARROW;
@ -1178,19 +1172,16 @@ void G_Controldefault(void)
gamecontrol[gc_fire ][1] = KEY_MOUSE1+0; gamecontrol[gc_fire ][1] = KEY_MOUSE1+0;
gamecontrol[gc_firenormal ][0] = 'c'; gamecontrol[gc_firenormal ][0] = 'c';
gamecontrol[gc_tossflag ][0] = '\''; gamecontrol[gc_tossflag ][0] = '\'';
gamecontrol[gc_use ][0] = 'x'; gamecontrol[gc_use ][0] = KEY_LSHIFT;
gamecontrol[gc_camtoggle ][0] = 'v'; gamecontrol[gc_camtoggle ][0] = 'v';
gamecontrol[gc_camleft ][0] = '[';
gamecontrol[gc_camright ][0] = ']';
gamecontrol[gc_camreset ][0] = 'r'; gamecontrol[gc_camreset ][0] = 'r';
gamecontrol[gc_lookup ][0] = KEY_PGUP; gamecontrol[gc_lookup ][0] = KEY_UPARROW;
gamecontrol[gc_lookdown ][0] = KEY_PGDN; gamecontrol[gc_lookdown ][0] = KEY_DOWNARROW;
gamecontrol[gc_centerview ][0] = KEY_END; gamecontrol[gc_centerview ][0] = KEY_END;
gamecontrol[gc_talkkey ][0] = 't'; gamecontrol[gc_talkkey ][0] = 't';
gamecontrol[gc_teamkey ][0] = 'y'; gamecontrol[gc_teamkey ][0] = 'y';
gamecontrol[gc_scores ][0] = KEY_TAB; gamecontrol[gc_scores ][0] = KEY_TAB;
gamecontrol[gc_jump ][0] = 'z'; gamecontrol[gc_jump ][0] = KEY_SPACE;
gamecontrol[gc_jump ][1] = KEY_MOUSE1+1;
gamecontrol[gc_console ][0] = KEY_CONSOLE; gamecontrol[gc_console ][0] = KEY_CONSOLE;
gamecontrol[gc_pause ][0] = KEY_PAUSE; gamecontrol[gc_pause ][0] = KEY_PAUSE;
#ifdef WMINPUT #ifdef WMINPUT

View file

@ -105,8 +105,6 @@ typedef enum
gc_tossflag, gc_tossflag,
gc_use, gc_use,
gc_camtoggle, gc_camtoggle,
gc_camleft,
gc_camright,
gc_camreset, gc_camreset,
gc_lookup, gc_lookup,
gc_lookdown, gc_lookdown,
@ -126,6 +124,8 @@ typedef enum
// mouse values are used once // mouse values are used once
extern consvar_t cv_mousesens, cv_mouseysens; extern consvar_t cv_mousesens, cv_mouseysens;
extern consvar_t cv_mousesens2, cv_mouseysens2;
extern consvar_t cv_controlperkey;
extern INT32 mousex, mousey; extern INT32 mousex, mousey;
extern INT32 mlooky; //mousey with mlookSensitivity extern INT32 mlooky; //mousey with mlookSensitivity

View file

@ -564,8 +564,6 @@ static inline void HWR_SubsecPoly(INT32 num, poly_t *poly)
subsector_t *sub; subsector_t *sub;
seg_t *lseg; seg_t *lseg;
sscount++;
sub = &subsectors[num]; sub = &subsectors[num];
count = sub->numlines; count = sub->numlines;
lseg = &segs[sub->firstline]; lseg = &segs[sub->firstline];

View file

@ -152,7 +152,9 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale);
float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale);
if (alphalevel >= 10 && alphalevel < 13) if (alphalevel == 12)
alphalevel = 0;
else if (alphalevel >= 10 && alphalevel < 13)
return; return;
// make patch ready in hardware cache // make patch ready in hardware cache
@ -252,7 +254,9 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale);
float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale);
if (alphalevel >= 10 && alphalevel < 13) if (alphalevel == 12)
alphalevel = 0;
else if (alphalevel >= 10 && alphalevel < 13)
return; return;
// make patch ready in hardware cache // make patch ready in hardware cache
@ -785,7 +789,7 @@ boolean HWR_Screenshot(const char *lbmname)
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
#ifdef USE_PNG #ifdef USE_PNG
ret = M_SavePNG(lbmname, buf, vid.width, vid.height, NULL); ret = M_SavePNG(lbmname, buf, vid.width, vid.height, false);
#else #else
ret = saveTGA(lbmname, buf, vid.width, vid.height); ret = saveTGA(lbmname, buf, vid.width, vid.height);
#endif #endif

View file

@ -78,6 +78,7 @@ typedef struct gr_vissprite_s
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
UINT8 *colormap; UINT8 *colormap;
INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
float z1, z2;
} gr_vissprite_t; } gr_vissprite_t;
// -------- // --------

View file

@ -226,8 +226,7 @@ light_t *t_lspr[NUMSPRITES] =
// Collectible Items // Collectible Items
&lspr[NOLIGHT], // SPR_RING &lspr[NOLIGHT], // SPR_RING
&lspr[NOLIGHT], // SPR_TRNG &lspr[NOLIGHT], // SPR_TRNG
&lspr[NOLIGHT], // SPR_EMMY &lspr[NOLIGHT], // SPR_TOKE
&lspr[BLUEBALL_L], // SPR_TOKE
&lspr[REDBALL_L], // SPR_RFLG &lspr[REDBALL_L], // SPR_RFLG
&lspr[BLUEBALL_L], // SPR_BFLG &lspr[BLUEBALL_L], // SPR_BFLG
&lspr[NOLIGHT], // SPR_NWNG &lspr[NOLIGHT], // SPR_NWNG
@ -243,6 +242,8 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_SPIK &lspr[NOLIGHT], // SPR_SPIK
&lspr[NOLIGHT], // SPR_SFLM &lspr[NOLIGHT], // SPR_SFLM
&lspr[NOLIGHT], // SPR_USPK &lspr[NOLIGHT], // SPR_USPK
&lspr[NOLIGHT], // SPR_WSPK
&lspr[NOLIGHT], // SPR_WSPB
&lspr[NOLIGHT], // SPR_STPT &lspr[NOLIGHT], // SPR_STPT
&lspr[NOLIGHT], // SPR_BMNE &lspr[NOLIGHT], // SPR_BMNE
@ -293,6 +294,12 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_FWR4 &lspr[NOLIGHT], // SPR_FWR4
&lspr[NOLIGHT], // SPR_BUS1 &lspr[NOLIGHT], // SPR_BUS1
&lspr[NOLIGHT], // SPR_BUS2 &lspr[NOLIGHT], // SPR_BUS2
// Trees (both GFZ and misc)
&lspr[NOLIGHT], // SPR_TRE1
&lspr[NOLIGHT], // SPR_TRE2
&lspr[NOLIGHT], // SPR_TRE3
&lspr[NOLIGHT], // SPR_TRE4
&lspr[NOLIGHT], // SPR_TRE5
// Techno Hill Scenery // Techno Hill Scenery
&lspr[NOLIGHT], // SPR_THZP &lspr[NOLIGHT], // SPR_THZP
@ -334,6 +341,8 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_XMS1 &lspr[NOLIGHT], // SPR_XMS1
&lspr[NOLIGHT], // SPR_XMS2 &lspr[NOLIGHT], // SPR_XMS2
&lspr[NOLIGHT], // SPR_XMS3 &lspr[NOLIGHT], // SPR_XMS3
&lspr[NOLIGHT], // SPR_XMS4
&lspr[NOLIGHT], // SPR_XMS5
// Botanic Serenity Scenery // Botanic Serenity Scenery
&lspr[NOLIGHT], // SPR_BSZ1 &lspr[NOLIGHT], // SPR_BSZ1
@ -345,13 +354,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_BSZ7 &lspr[NOLIGHT], // SPR_BSZ7
&lspr[NOLIGHT], // SPR_BSZ8 &lspr[NOLIGHT], // SPR_BSZ8
// Stalagmites // Misc Scenery
&lspr[NOLIGHT], // SPR_STLG &lspr[NOLIGHT], // SPR_STLG
// Disco Ball
&lspr[NOLIGHT], // SPR_DBAL &lspr[NOLIGHT], // SPR_DBAL
// ATZ Red Crystal
&lspr[NOLIGHT], // SPR_RCRY &lspr[NOLIGHT], // SPR_RCRY
// Powerup Indicators // Powerup Indicators
@ -396,15 +401,20 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_SPRB Graue &lspr[NOLIGHT], // SPR_SPRB Graue
&lspr[NOLIGHT], // SPR_YSPR &lspr[NOLIGHT], // SPR_YSPR
&lspr[NOLIGHT], // SPR_RSPR &lspr[NOLIGHT], // SPR_RSPR
&lspr[NOLIGHT], // SPR_SSWY
&lspr[NOLIGHT], // SPR_SSWR
&lspr[NOLIGHT], // SPR_SSWB
// Environmentals Effects // Environmental Effects
&lspr[NOLIGHT], // SPR_RAIN &lspr[NOLIGHT], // SPR_RAIN
&lspr[NOLIGHT], // SPR_SNO1 &lspr[NOLIGHT], // SPR_SNO1
&lspr[NOLIGHT], // SPR_SPLH &lspr[NOLIGHT], // SPR_SPLH
&lspr[NOLIGHT], // SPR_SPLA &lspr[NOLIGHT], // SPR_SPLA
&lspr[NOLIGHT], // SPR_SMOK &lspr[NOLIGHT], // SPR_SMOK
&lspr[NOLIGHT], // SPR_BUBL &lspr[NOLIGHT], // SPR_BUBL
&lspr[SUPERSPARK_L], // SPR_WZAP &lspr[RINGLIGHT_L], // SPR_WZAP
&lspr[NOLIGHT], // SPR_DUST
&lspr[NOLIGHT], // SPR_FPRT
&lspr[SUPERSPARK_L], // SPR_TFOG &lspr[SUPERSPARK_L], // SPR_TFOG
&lspr[NIGHTSLIGHT_L], // SPR_SEED // Sonic CD flower seed &lspr[NIGHTSLIGHT_L], // SPR_SEED // Sonic CD flower seed
&lspr[NOLIGHT], // SPR_PRTL &lspr[NOLIGHT], // SPR_PRTL
@ -412,9 +422,12 @@ light_t *t_lspr[NUMSPRITES] =
// Game Indicators // Game Indicators
&lspr[NOLIGHT], // SPR_SCOR &lspr[NOLIGHT], // SPR_SCOR
&lspr[NOLIGHT], // SPR_DRWN &lspr[NOLIGHT], // SPR_DRWN
&lspr[NOLIGHT], // SPR_LCKN
&lspr[NOLIGHT], // SPR_TTAG &lspr[NOLIGHT], // SPR_TTAG
&lspr[NOLIGHT], // SPR_GFLG &lspr[NOLIGHT], // SPR_GFLG
&lspr[NOLIGHT], // SPR_CORK
// Ring Weapons // Ring Weapons
&lspr[RINGLIGHT_L], // SPR_RRNG &lspr[RINGLIGHT_L], // SPR_RRNG
&lspr[RINGLIGHT_L], // SPR_RNGB &lspr[RINGLIGHT_L], // SPR_RNGB

View file

@ -1084,9 +1084,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
float endheight = 0.0f, endbheight = 0.0f; float endheight = 0.0f, endbheight = 0.0f;
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x); fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].y); fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x); fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].y); fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly // compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
// use this as a temp var to store P_GetZAt's return value each time // use this as a temp var to store P_GetZAt's return value each time
fixed_t temp; fixed_t temp;
@ -3367,7 +3367,6 @@ static void HWR_Subsector(size_t num)
if (num < numsubsectors) if (num < numsubsectors)
{ {
sscount++;
// subsector // subsector
sub = &subsectors[num]; sub = &subsectors[num];
// sector // sector
@ -3722,6 +3721,9 @@ static void HWR_Subsector(size_t num)
while (count--) while (count--)
{ {
#ifdef POLYOBJECTS
if (!line->polyseg) // ignore segs that belong to polyobjects
#endif
HWR_AddLine(line); HWR_AddLine(line);
line++; line++;
} }
@ -4227,6 +4229,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
GLPatch_t *gpatch; // sprite patch converted to hardware GLPatch_t *gpatch; // sprite patch converted to hardware
FSurfaceInfo Surf; FSurfaceInfo Surf;
const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
//const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE));
if (spr->mobj) if (spr->mobj)
this_scale = FIXED_TO_FLOAT(spr->mobj->scale); this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
if (hires) if (hires)
@ -4270,7 +4273,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
// make a wall polygon (with 2 triangles), using the floor/ceiling heights, // make a wall polygon (with 2 triangles), using the floor/ceiling heights,
// and the 2d map coords of start/end vertices // and the 2d map coords of start/end vertices
wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz; wallVerts[0].z = wallVerts[3].z = spr->z1;
wallVerts[2].z = wallVerts[1].z = spr->z2;
// transform // transform
wv = wallVerts; wv = wallVerts;
@ -5066,6 +5070,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
angle_t ang; angle_t ang;
INT32 heightsec, phs; INT32 heightsec, phs;
const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
float offset;
float ang_scale = 1.0f, ang_scalez = 0.0f;
float z1, z2;
if (!thing) if (!thing)
return; return;
@ -5080,7 +5088,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
// thing is behind view plane? // thing is behind view plane?
if (tz < ZCLIP_PLANE && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
return; return;
tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos); tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
@ -5118,6 +5126,27 @@ static void HWR_ProjectSprite(mobj_t *thing)
I_Error("sprframes NULL for sprite %d\n", thing->sprite); I_Error("sprframes NULL for sprite %d\n", thing->sprite);
#endif #endif
if (papersprite)
{
// Use the actual view angle, rather than the angle formed
// between the view point and the thing
// this makes sure paper sprites always appear at the right angle!
// Note: DO NOT do this in software mode version, it actually
// makes papersprites look WORSE there (I know, I've tried)
// Monster Iestyn - 13/05/17
ang = dup_viewangle - thing->angle;
ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT));
ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT));
if (ang_scale < 0)
{
ang_scale = -ang_scale;
ang_scalez = -ang_scalez;
}
}
else if (sprframe->rotate != SRF_SINGLE)
ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
if (sprframe->rotate == SRF_SINGLE) if (sprframe->rotate == SRF_SINGLE)
{ {
// use single rotation for all views // use single rotation for all views
@ -5128,8 +5157,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
else else
{ {
// choose a different rotation based on player view // choose a different rotation based on player view
ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
rot = 6; // F7 slot rot = 6; // F7 slot
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
@ -5147,9 +5174,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
// calculate edges of the shape // calculate edges of the shape
if (flip) if (flip)
tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale;
else else
tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale;
z1 = tz - (offset * ang_scalez);
tx -= offset * ang_scale;
// project x // project x
x1 = gr_windowcenterx + (tx * gr_centerx / tz); x1 = gr_windowcenterx + (tx * gr_centerx / tz);
@ -5160,7 +5190,14 @@ static void HWR_ProjectSprite(mobj_t *thing)
x1 = tx; x1 = tx;
tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale;
z2 = z1 + (offset * ang_scalez);
tx += offset * ang_scale;
if (papersprite && max(z1, z2) < ZCLIP_PLANE)
return;
x2 = gr_windowcenterx + (tx * gr_centerx / tz); x2 = gr_windowcenterx + (tx * gr_centerx / tz);
if (vflip) if (vflip)
@ -5209,6 +5246,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->patchlumpnum = sprframe->lumppat[rot]; vis->patchlumpnum = sprframe->lumppat[rot];
vis->flip = flip; vis->flip = flip;
vis->mobj = thing; vis->mobj = thing;
vis->z1 = z1;
vis->z2 = z2;
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"

View file

@ -244,6 +244,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
#define pglMaterialfv glMaterialfv #define pglMaterialfv glMaterialfv
/* Raster functions */ /* Raster functions */
#define pglPixelStorei glPixelStorei
#define pglReadPixels glReadPixels #define pglReadPixels glReadPixels
/* Texture mapping */ /* Texture mapping */
@ -262,15 +263,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
/* texture mapping */ //GL_EXT_copy_texture /* texture mapping */ //GL_EXT_copy_texture
#ifndef KOS_GL_COMPATIBILITY #ifndef KOS_GL_COMPATIBILITY
#define pglCopyTexImage2D glCopyTexImage2D #define pglCopyTexImage2D glCopyTexImage2D
#endif
/* GLU functions */
#define pgluBuild2DMipmaps gluBuild2DMipmaps
#endif
#ifndef MINI_GL_COMPATIBILITY
/* 1.3 functions for multitexturing */
#define pglActiveTexture glActiveTexture
#define pglMultiTexCoord2f glMultiTexCoord2f
#endif
#else //!STATIC_OPENGL #else //!STATIC_OPENGL
/* 1.0 functions */ /* 1.0 functions */
@ -365,6 +359,8 @@ typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *pa
static PFNglMaterialfv pglMaterialfv; static PFNglMaterialfv pglMaterialfv;
/* Raster functions */ /* Raster functions */
typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
static PFNglPixelStorei pglPixelStorei;
typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
static PFNglReadPixels pglReadPixels; static PFNglReadPixels pglReadPixels;
@ -391,7 +387,7 @@ static PFNglBindTexture pglBindTexture;
/* texture mapping */ //GL_EXT_copy_texture /* texture mapping */ //GL_EXT_copy_texture
typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
static PFNglCopyTexImage2D pglCopyTexImage2D; static PFNglCopyTexImage2D pglCopyTexImage2D;
#endif
/* GLU functions */ /* GLU functions */
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
@ -403,7 +399,6 @@ static PFNglActiveTexture pglActiveTexture;
typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat); typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
static PFNglMultiTexCoord2f pglMultiTexCoord2f; static PFNglMultiTexCoord2f pglMultiTexCoord2f;
#endif #endif
#endif
#ifndef MINI_GL_COMPATIBILITY #ifndef MINI_GL_COMPATIBILITY
/* 1.2 Parms */ /* 1.2 Parms */
@ -494,6 +489,7 @@ boolean SetupGLfunc(void)
GETOPENGLFUNC(pglLightModelfv , glLightModelfv) GETOPENGLFUNC(pglLightModelfv , glLightModelfv)
GETOPENGLFUNC(pglMaterialfv , glMaterialfv) GETOPENGLFUNC(pglMaterialfv , glMaterialfv)
GETOPENGLFUNC(pglPixelStorei , glPixelStorei)
GETOPENGLFUNC(pglReadPixels , glReadPixels) GETOPENGLFUNC(pglReadPixels , glReadPixels)
GETOPENGLFUNC(pglTexEnvi , glTexEnvi) GETOPENGLFUNC(pglTexEnvi , glTexEnvi)
@ -519,35 +515,23 @@ boolean SetupGLfunc(void)
// This has to be done after the context is created so the version number can be obtained // This has to be done after the context is created so the version number can be obtained
boolean SetupGLFunc13(void) boolean SetupGLFunc13(void)
{ {
#ifdef MINI_GL_COMPATIBILITY
return false;
#else
const GLubyte *version = pglGetString(GL_VERSION); const GLubyte *version = pglGetString(GL_VERSION);
int glmajor, glminor; int glmajor, glminor;
gl13 = false; gl13 = false;
#ifdef MINI_GL_COMPATIBILITY
return false;
#else
#ifdef STATIC_OPENGL
gl13 = true;
#else
// Parse the GL version // Parse the GL version
if (version != NULL) if (version != NULL)
{ {
if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2) if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
{ {
// Look, we gotta prepare for the inevitable arrival of GL 2.0 code... // Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
switch (glmajor) if (glmajor == 1 && glminor >= 3)
{ gl13 = true;
case 1: else if (glmajor > 1)
if (glminor == 3) gl13 = true; gl13 = true;
break;
case 2:
case 3:
case 4:
gl13 = true;
default:
break;
}
} }
} }
@ -568,9 +552,6 @@ boolean SetupGLFunc13(void)
} }
else else
DBG_Printf("GL_ARB_multitexture support: disabled\n"); DBG_Printf("GL_ARB_multitexture support: disabled\n");
#undef GETOPENGLFUNC
#endif
return true; return true;
#endif #endif
} }
@ -897,7 +878,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1); GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
GLubyte *row = malloc(dst_stride); GLubyte *row = malloc(dst_stride);
if (!row) return; if (!row) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(i = 0; i < height/2; i++) for(i = 0; i < height/2; i++)
{ {
memcpy(row, top, dst_stride); memcpy(row, top, dst_stride);
@ -913,7 +896,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
INT32 j; INT32 j;
GLubyte *image = malloc(width*height*3*sizeof (*image)); GLubyte *image = malloc(width*height*3*sizeof (*image));
if (!image) return; if (!image) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = height-1; i >= 0; i--) for (i = height-1; i >= 0; i--)
{ {
for (j = 0; j < width; j++) for (j = 0; j < width; j++)
@ -1815,13 +1800,11 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
min_filter = GL_NEAREST; min_filter = GL_NEAREST;
#endif #endif
} }
#ifndef STATIC_OPENGL
if (!pgluBuild2DMipmaps) if (!pgluBuild2DMipmaps)
{ {
MipMap = GL_FALSE; MipMap = GL_FALSE;
min_filter = GL_LINEAR; min_filter = GL_LINEAR;
} }
#endif
Flush(); //??? if we want to change filter mode by texture, remove this Flush(); //??? if we want to change filter mode by texture, remove this
break; break;

View file

@ -91,7 +91,7 @@ patch_t *tallminus;
patch_t *emeraldpics[7]; patch_t *emeraldpics[7];
patch_t *tinyemeraldpics[7]; patch_t *tinyemeraldpics[7];
static patch_t *emblemicon; static patch_t *emblemicon;
static patch_t *tokenicon; patch_t *tokenicon;
//------------------------------------------- //-------------------------------------------
// misc vars // misc vars
@ -840,7 +840,7 @@ static void HU_DrawChat(void)
else else
{ {
//charwidth = SHORT(hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor; //charwidth = SHORT(hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, true);
} }
c += charwidth; c += charwidth;
} }
@ -857,7 +857,7 @@ static void HU_DrawChat(void)
else else
{ {
//charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor; //charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, !cv_allcaps.value); V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, true);
} }
c += charwidth; c += charwidth;
@ -869,7 +869,7 @@ static void HU_DrawChat(void)
} }
if (hu_tick < 4) if (hu_tick < 4)
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, !cv_allcaps.value); V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
} }
@ -1226,9 +1226,9 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
} }
else else
{ {
if (players[tab[i].num].powers[pw_super]) if (players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS] || players[tab[i].num].mo->state > &states[S_PLAY_SUPER_TRANS9]))
{ {
colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE);
V_DrawSmallMappedPatch (x, y-4, 0, superprefix[players[tab[i].num].skin], colormap); V_DrawSmallMappedPatch (x, y-4, 0, superprefix[players[tab[i].num].skin], colormap);
} }
else else

View file

@ -21,7 +21,7 @@
//------------------------------------ //------------------------------------
// heads up font // heads up font
//------------------------------------ //------------------------------------
#define HU_FONTSTART '\x1F' // the first font character #define HU_FONTSTART '\x19' // the first font character
#define HU_FONTEND '~' #define HU_FONTEND '~'
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) #define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
@ -71,6 +71,7 @@ extern patch_t *rmatcico;
extern patch_t *bmatcico; extern patch_t *bmatcico;
extern patch_t *tagico; extern patch_t *tagico;
extern patch_t *tallminus; extern patch_t *tallminus;
extern patch_t *tokenicon;
// set true when entering a chat message // set true when entering a chat message
extern boolean chat_on; extern boolean chat_on;
@ -78,9 +79,6 @@ extern boolean chat_on;
// set true whenever the tab rankings are being shown for any reason // set true whenever the tab rankings are being shown for any reason
extern boolean hu_showscores; extern boolean hu_showscores;
// P_DeathThink sets this true to show scores while dead, in multiplayer
extern boolean playerdeadview;
// init heads up data at game startup. // init heads up data at game startup.
void HU_Init(void); void HU_Init(void);

File diff suppressed because it is too large Load diff

View file

@ -320,7 +320,6 @@ typedef enum sprite
// Collectible Items // Collectible Items
SPR_RING, SPR_RING,
SPR_TRNG, // Team Rings SPR_TRNG, // Team Rings
SPR_EMMY, // emerald test
SPR_TOKE, // Special Stage Token SPR_TOKE, // Special Stage Token
SPR_RFLG, // Red CTF Flag SPR_RFLG, // Red CTF Flag
SPR_BFLG, // Blue CTF Flag SPR_BFLG, // Blue CTF Flag
@ -337,6 +336,8 @@ typedef enum sprite
SPR_SPIK, // Spike Ball SPR_SPIK, // Spike Ball
SPR_SFLM, // Spin fire SPR_SFLM, // Spin fire
SPR_USPK, // Floor spike SPR_USPK, // Floor spike
SPR_WSPK, // Wall spike
SPR_WSPB, // Wall spike base
SPR_STPT, // Starpost SPR_STPT, // Starpost
SPR_BMNE, // Big floating mine SPR_BMNE, // Big floating mine
@ -387,6 +388,12 @@ typedef enum sprite
SPR_FWR4, SPR_FWR4,
SPR_BUS1, // GFZ Bush w/ berries SPR_BUS1, // GFZ Bush w/ berries
SPR_BUS2, // GFZ Bush w/o berries SPR_BUS2, // GFZ Bush w/o berries
// Trees (both GFZ and misc)
SPR_TRE1, // GFZ
SPR_TRE2, // Checker
SPR_TRE3, // Frozen Hillside
SPR_TRE4, // Polygon
SPR_TRE5, // Bush tree
// Techno Hill Scenery // Techno Hill Scenery
SPR_THZP, // THZ1 Flower SPR_THZP, // THZ1 Flower
@ -425,9 +432,11 @@ typedef enum sprite
// Egg Rock Scenery // Egg Rock Scenery
// Christmas Scenery // Christmas Scenery
SPR_XMS1, SPR_XMS1, // Christmas Pole
SPR_XMS2, SPR_XMS2, // Candy Cane
SPR_XMS3, SPR_XMS3, // Snowman
SPR_XMS4, // Lamppost
SPR_XMS5, // Hanging Star
// Botanic Serenity Scenery // Botanic Serenity Scenery
SPR_BSZ1, // Tall flowers SPR_BSZ1, // Tall flowers
@ -450,7 +459,7 @@ typedef enum sprite
SPR_ARMB, // Armageddon Shield Ring, Back SPR_ARMB, // Armageddon Shield Ring, Back
SPR_WIND, // Whirlwind Shield Orb SPR_WIND, // Whirlwind Shield Orb
SPR_MAGN, // Attract Shield Orb SPR_MAGN, // Attract Shield Orb
SPR_ELEM, // Elemental Shield Orb and Fire SPR_ELEM, // Elemental Shield Orb
SPR_FORC, // Force Shield Orb SPR_FORC, // Force Shield Orb
SPR_PITY, // Pity Shield Orb SPR_PITY, // Pity Shield Orb
SPR_FIRS, // Flame Shield Orb SPR_FIRS, // Flame Shield Orb
@ -507,9 +516,12 @@ typedef enum sprite
// Game Indicators // Game Indicators
SPR_SCOR, // Score logo SPR_SCOR, // Score logo
SPR_DRWN, // Drowning Timer SPR_DRWN, // Drowning Timer
SPR_LCKN, // Target
SPR_TTAG, // Tag Sign SPR_TTAG, // Tag Sign
SPR_GFLG, // Got Flag sign SPR_GFLG, // Got Flag sign
SPR_CORK,
// Ring Weapons // Ring Weapons
SPR_RRNG, // Red Ring SPR_RRNG, // Red Ring
SPR_RNGB, // Bounce Ring SPR_RNGB, // Bounce Ring
@ -594,21 +606,21 @@ typedef enum sprite
NUMSPRITES NUMSPRITES
} spritenum_t; } spritenum_t;
// Make sure to be conscious of FF_FRAMEMASK whenever you change this table. // Make sure to be conscious of FF_FRAMEMASK and the fact sprite2 is stored as a UINT8 whenever you change this table.
// Currently, FF_FRAMEMASK is 0x1ff, or 511 - and NUMSPRITEFREESLOTS is 256. // Currently, FF_FRAMEMASK is 0xff, or 255 - but the second half is used by FF_SPR2SUPER, so the limitation is 0x7f.
// Since this is zero-based, there can be at most 256 different SPR2_'s without changing that. // Since this is zero-based, there can be at most 128 different SPR2_'s without changing that.
enum playersprite enum playersprite
{ {
SPR2_STND = 0, SPR2_STND = 0,
SPR2_WAIT, SPR2_WAIT,
SPR2_WALK, SPR2_WALK,
SPR2_RUN , SPR2_RUN ,
SPR2_PEEL, SPR2_DASH,
SPR2_PAIN, SPR2_PAIN,
SPR2_STUN,
SPR2_DEAD, SPR2_DEAD,
SPR2_DRWN, // drown SPR2_DRWN, // drown
SPR2_SPIN, SPR2_ROLL,
SPR2_DASH, // spindash charge
SPR2_GASP, SPR2_GASP,
SPR2_JUMP, SPR2_JUMP,
SPR2_SPNG, // spring SPR2_SPNG, // spring
@ -616,8 +628,7 @@ enum playersprite
SPR2_EDGE, SPR2_EDGE,
SPR2_RIDE, SPR2_RIDE,
SPR2_SIGN, // end sign head SPR2_SPIN, // spindash
SPR2_LIFE, // life monitor icon
SPR2_FLY , SPR2_FLY ,
SPR2_SWIM, SPR2_SWIM,
@ -627,36 +638,28 @@ enum playersprite
SPR2_CLNG, // cling SPR2_CLNG, // cling
SPR2_CLMB, // climb SPR2_CLMB, // climb
SPR2_FLT , // float
SPR2_FRUN, // float run
SPR2_BNCE, // bounce
SPR2_BLND, // bounce landing
SPR2_FIRE, // fire
SPR2_TWIN, // twinspin SPR2_TWIN, // twinspin
SPR2_MLEE, // melee SPR2_MLEE, // melee
SPR2_MLEL, // melee land
SPR2_TRNS, // super transformation SPR2_TRNS, // transformation
SPR2_SSTD, // super stand
SPR2_SWLK, // super walk
SPR2_SRUN, // super run
SPR2_SPEE, // super peelout
SPR2_SPAN, // super pain
SPR2_SSTN, // super stun
SPR2_SDTH, // super death
SPR2_SDRN, // super drown
SPR2_SSPN, // super spin
SPR2_SGSP, // super gasp
SPR2_SJMP, // super jump
SPR2_SSPG, // super spring
SPR2_SFAL, // super fall
SPR2_SEDG, // super edge
SPR2_SRID, // super ride
SPR2_SFLT, // super float
SPR2_NTRN, // NiGHTS transformation
SPR2_NSTD, // NiGHTS stand SPR2_NSTD, // NiGHTS stand
SPR2_NFLT, // NiGHTS float SPR2_NFLT, // NiGHTS float
SPR2_NPAN, // NiGHTS pain SPR2_NSTN, // NiGHTS stun
SPR2_NPUL, // NiGHTS pull SPR2_NPUL, // NiGHTS pull
SPR2_NATK, // NiGHTS attack SPR2_NATK, // NiGHTS attack
// NiGHTS flight. // NiGHTS flight
SPR2_NGT0, SPR2_NGT0,
SPR2_NGT1, SPR2_NGT1,
SPR2_NGT2, SPR2_NGT2,
@ -671,7 +674,7 @@ enum playersprite
SPR2_NGTB, SPR2_NGTB,
SPR2_NGTC, SPR2_NGTC,
// NiGHTS drill. // NiGHTS drill
SPR2_DRL0, SPR2_DRL0,
SPR2_DRL1, SPR2_DRL1,
SPR2_DRL2, SPR2_DRL2,
@ -686,8 +689,11 @@ enum playersprite
SPR2_DRLB, SPR2_DRLB,
SPR2_DRLC, SPR2_DRLC,
SPR2_SIGN, // end sign head
SPR2_LIFE, // life monitor icon
SPR2_FIRSTFREESLOT, SPR2_FIRSTFREESLOT,
SPR2_LASTFREESLOT = SPR2_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1, SPR2_LASTFREESLOT = 0x7f,
NUMPLAYERSPRITES NUMPLAYERSPRITES
}; };
@ -713,19 +719,22 @@ typedef enum state
S_PLAY_WAIT, S_PLAY_WAIT,
S_PLAY_WALK, S_PLAY_WALK,
S_PLAY_RUN, S_PLAY_RUN,
S_PLAY_PEEL, S_PLAY_DASH,
S_PLAY_PAIN, S_PLAY_PAIN,
S_PLAY_STUN,
S_PLAY_DEAD, S_PLAY_DEAD,
S_PLAY_DRWN, S_PLAY_DRWN,
S_PLAY_SPIN, S_PLAY_ROLL,
S_PLAY_DASH,
S_PLAY_GASP, S_PLAY_GASP,
S_PLAY_JUMP, // spin jump S_PLAY_JUMP,
S_PLAY_SPRING, S_PLAY_SPRING,
S_PLAY_FALL, S_PLAY_FALL,
S_PLAY_EDGE, S_PLAY_EDGE,
S_PLAY_RIDE, S_PLAY_RIDE,
// CA2_SPINDASH
S_PLAY_SPINDASH,
// CA_FLY/SWIM // CA_FLY/SWIM
S_PLAY_FLY, S_PLAY_FLY,
S_PLAY_SWIM, S_PLAY_SWIM,
@ -736,30 +745,25 @@ typedef enum state
S_PLAY_CLING, S_PLAY_CLING,
S_PLAY_CLIMB, S_PLAY_CLIMB,
// CA_FLOAT/CA_SLOWFALL
S_PLAY_FLOAT,
S_PLAY_FLOAT_RUN,
// CA_BOUNCE
S_PLAY_BOUNCE,
S_PLAY_BOUNCE_LANDING,
// CA2_GUNSLINGER
S_PLAY_FIRE,
S_PLAY_FIRE_FINISH,
// CA_TWINSPIN // CA_TWINSPIN
S_PLAY_TWINSPIN, S_PLAY_TWINSPIN,
// CA2_MELEE // CA2_MELEE
S_PLAY_MELEE, S_PLAY_MELEE,
S_PLAY_MELEE_FINISH, S_PLAY_MELEE_FINISH,
S_PLAY_MELEE_LANDING,
// SF_SUPERANIMS
S_PLAY_SUPER_STND,
S_PLAY_SUPER_WALK,
S_PLAY_SUPER_RUN,
S_PLAY_SUPER_PEEL,
S_PLAY_SUPER_PAIN,
S_PLAY_SUPER_STUN,
S_PLAY_SUPER_DEAD,
S_PLAY_SUPER_DRWN,
S_PLAY_SUPER_SPIN,
S_PLAY_SUPER_GASP,
S_PLAY_SUPER_JUMP, // see note above
S_PLAY_SUPER_SPRING,
S_PLAY_SUPER_FALL,
S_PLAY_SUPER_EDGE,
S_PLAY_SUPER_RIDE,
S_PLAY_SUPER_FLOAT,
// SF_SUPER // SF_SUPER
S_PLAY_SUPER_TRANS, S_PLAY_SUPER_TRANS,
@ -798,7 +802,7 @@ typedef enum state
S_PLAY_NIGHTS_STAND, S_PLAY_NIGHTS_STAND,
S_PLAY_NIGHTS_FLOAT, S_PLAY_NIGHTS_FLOAT,
S_PLAY_NIGHTS_PAIN, S_PLAY_NIGHTS_STUN,
S_PLAY_NIGHTS_PULL, S_PLAY_NIGHTS_PULL,
S_PLAY_NIGHTS_ATTACK, S_PLAY_NIGHTS_ATTACK,
@ -1620,12 +1624,8 @@ typedef enum state
// Individual Team Rings // Individual Team Rings
S_TEAMRING, S_TEAMRING,
// Special Stage Token
S_EMMY,
// Special Stage Token // Special Stage Token
S_TOKEN, S_TOKEN,
S_MOVINGTOKEN,
// CTF Flags // CTF Flags
S_REDFLAG, S_REDFLAG,
@ -1776,6 +1776,15 @@ typedef enum state
S_SPIKED1, S_SPIKED1,
S_SPIKED2, S_SPIKED2,
// Wall spikes
S_WALLSPIKE1,
S_WALLSPIKE2,
S_WALLSPIKE3,
S_WALLSPIKE4,
S_WALLSPIKE5,
S_WALLSPIKE6,
S_WALLSPIKEBASE,
// Starpost // Starpost
S_STARPOST_IDLE, S_STARPOST_IDLE,
S_STARPOST_FLASH, S_STARPOST_FLASH,
@ -1964,6 +1973,7 @@ typedef enum state
S_DEMONFIRE5, S_DEMONFIRE5,
S_DEMONFIRE6, S_DEMONFIRE6,
// GFZ flowers
S_GFZFLOWERA, S_GFZFLOWERA,
S_GFZFLOWERB, S_GFZFLOWERB,
S_GFZFLOWERC, S_GFZFLOWERC,
@ -1971,6 +1981,18 @@ typedef enum state
S_BERRYBUSH, S_BERRYBUSH,
S_BUSH, S_BUSH,
// Trees (both GFZ and misc)
S_GFZTREE,
S_GFZBERRYTREE,
S_GFZCHERRYTREE,
S_CHECKERTREE,
S_CHECKERSUNSETTREE,
S_FHZTREE, // Frozen Hillside
S_FHZPINKTREE,
S_POLYGONTREE,
S_BUSHTREE,
S_BUSHREDTREE,
// THZ Plant // THZ Plant
S_THZFLOWERA, S_THZFLOWERA,
S_THZFLOWERB, S_THZFLOWERB,
@ -1980,6 +2002,7 @@ typedef enum state
// Deep Sea Gargoyle // Deep Sea Gargoyle
S_GARGOYLE, S_GARGOYLE,
S_BIGGARGOYLE,
// DSZ Seaweed // DSZ Seaweed
S_SEAWEED1, S_SEAWEED1,
@ -2138,7 +2161,14 @@ typedef enum state
// Xmas-specific stuff // Xmas-specific stuff
S_XMASPOLE, S_XMASPOLE,
S_CANDYCANE, S_CANDYCANE,
S_SNOWMAN, S_SNOWMAN, // normal
S_SNOWMANHAT, // with hat + scarf
S_LAMPPOST1, // normal
S_LAMPPOST2, // with snow
S_HANGSTAR,
// Xmas GFZ bushes
S_XMASBERRYBUSH,
S_XMASBUSH,
// Botanic Serenity's loads of scenery states // Botanic Serenity's loads of scenery states
S_BSZTALLFLOWER_RED, S_BSZTALLFLOWER_RED,
@ -2330,10 +2360,6 @@ typedef enum state
S_PITY4, S_PITY4,
S_PITY5, S_PITY5,
S_PITY6, S_PITY6,
S_PITY7,
S_PITY8,
S_PITY9,
S_PITY10,
S_FIRS1, S_FIRS1,
S_FIRS2, S_FIRS2,
@ -2725,14 +2751,18 @@ typedef enum state
S_FOUR2, S_FOUR2,
S_FIVE2, S_FIVE2,
S_LOCKON1,
S_LOCKON2,
// Tag Sign // Tag Sign
S_TTAG1, S_TTAG,
// Got Flag Sign // Got Flag Sign
S_GOTFLAG1, S_GOTFLAG,
S_GOTFLAG2, S_GOTREDFLAG,
S_GOTFLAG3, S_GOTBLUEFLAG,
S_GOTFLAG4,
S_CORK,
// Red Ring // Red Ring
S_RRNG1, S_RRNG1,
@ -3234,8 +3264,7 @@ typedef enum mobj_type
MT_BLUEBALL, // Blue sphere replacement for special stages MT_BLUEBALL, // Blue sphere replacement for special stages
MT_REDTEAMRING, //Rings collectable by red team. MT_REDTEAMRING, //Rings collectable by red team.
MT_BLUETEAMRING, //Rings collectable by blue team. MT_BLUETEAMRING, //Rings collectable by blue team.
MT_EMMY, // emerald token for special stage MT_TOKEN, // Special Stage token for special stage
MT_TOKEN, // Special Stage Token (uncollectible part)
MT_REDFLAG, // Red CTF Flag MT_REDFLAG, // Red CTF Flag
MT_BLUEFLAG, // Blue CTF Flag MT_BLUEFLAG, // Blue CTF Flag
MT_EMBLEM, MT_EMBLEM,
@ -3269,6 +3298,8 @@ typedef enum mobj_type
MT_SPECIALSPIKEBALL, MT_SPECIALSPIKEBALL,
MT_SPINFIRE, MT_SPINFIRE,
MT_SPIKE, MT_SPIKE,
MT_WALLSPIKE,
MT_WALLSPIKEBASE,
MT_STARPOST, MT_STARPOST,
MT_BIGMINE, MT_BIGMINE,
MT_BIGAIRMINE, MT_BIGAIRMINE,
@ -3359,6 +3390,17 @@ typedef enum mobj_type
MT_GFZFLOWER3, MT_GFZFLOWER3,
MT_BERRYBUSH, MT_BERRYBUSH,
MT_BUSH, MT_BUSH,
// Trees (both GFZ and misc)
MT_GFZTREE,
MT_GFZBERRYTREE,
MT_GFZCHERRYTREE,
MT_CHECKERTREE,
MT_CHECKERSUNSETTREE,
MT_FHZTREE, // Frozen Hillside
MT_FHZPINKTREE,
MT_POLYGONTREE,
MT_BUSHTREE,
MT_BUSHREDTREE,
// Techno Hill Scenery // Techno Hill Scenery
MT_THZFLOWER1, MT_THZFLOWER1,
@ -3367,6 +3409,7 @@ typedef enum mobj_type
// Deep Sea Scenery // Deep Sea Scenery
MT_GARGOYLE, // Deep Sea Gargoyle MT_GARGOYLE, // Deep Sea Gargoyle
MT_BIGGARGOYLE, // Deep Sea Gargoyle (Big)
MT_SEAWEED, // DSZ Seaweed MT_SEAWEED, // DSZ Seaweed
MT_WATERDRIP, // Dripping Water source MT_WATERDRIP, // Dripping Water source
MT_WATERDROP, // Water drop from dripping water MT_WATERDROP, // Water drop from dripping water
@ -3435,7 +3478,14 @@ typedef enum mobj_type
// Christmas Scenery // Christmas Scenery
MT_XMASPOLE, MT_XMASPOLE,
MT_CANDYCANE, MT_CANDYCANE,
MT_SNOWMAN, MT_SNOWMAN, // normal
MT_SNOWMANHAT, // with hat + scarf
MT_LAMPPOST1, // normal
MT_LAMPPOST2, // with snow
MT_HANGSTAR,
// Xmas GFZ bushes
MT_XMASBERRYBUSH,
MT_XMASBUSH,
// Botanic Serenity scenery // Botanic Serenity scenery
MT_BSZTALLFLOWER_RED, MT_BSZTALLFLOWER_RED,
@ -3542,9 +3592,9 @@ typedef enum mobj_type
MT_SCORE, // score logo MT_SCORE, // score logo
MT_DROWNNUMBERS, // Drowning Timer MT_DROWNNUMBERS, // Drowning Timer
MT_GOTEMERALD, // Chaos Emerald (intangible) MT_GOTEMERALD, // Chaos Emerald (intangible)
MT_LOCKON, // Target
MT_TAG, // Tag Sign MT_TAG, // Tag Sign
MT_GOTFLAG, // Got Flag sign MT_GOTFLAG, // Got Flag sign
MT_GOTFLAG2, // Got Flag sign
// Ambient Sounds // Ambient Sounds
MT_AWATERA, // Ambient Water Sound 1 MT_AWATERA, // Ambient Water Sound 1
@ -3558,6 +3608,8 @@ typedef enum mobj_type
MT_RANDOMAMBIENT, MT_RANDOMAMBIENT,
MT_RANDOMAMBIENT2, MT_RANDOMAMBIENT2,
MT_CORK,
// Ring Weapons // Ring Weapons
MT_REDRING, MT_REDRING,
MT_BOUNCERING, MT_BOUNCERING,

View file

@ -445,10 +445,32 @@ static int lib_pIsValidSprite2(lua_State *L)
INLEVEL INLEVEL
if (!mobj) if (!mobj)
return LUA_ErrInvalid(L, "mobj_t"); return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes > 0))); lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes)));
return 1; return 1;
} }
// P_SpawnLockOn doesn't exist either, but we want to expose making a local mobj without encouraging hacks.
static int lib_pSpawnLockOn(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *lockon = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
statenum_t state = luaL_checkinteger(L, 3);
NOHUD
INLEVEL
if (!lockon)
return LUA_ErrInvalid(L, "mobj_t");
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
P_SetMobjStateNF(visual, state);
}
return 0;
}
static int lib_pSpawnMissile(lua_State *L) static int lib_pSpawnMissile(lua_State *L)
{ {
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -793,6 +815,17 @@ static int lib_pStealPlayerScore(lua_State *L)
return 0; return 0;
} }
static int lib_pGetJumpFlags(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, P_GetJumpFlags(player));
return 1;
}
static int lib_pPlayerInPain(lua_State *L) static int lib_pPlayerInPain(lua_State *L)
{ {
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -1055,11 +1088,12 @@ static int lib_pLookForEnemies(lua_State *L)
{ {
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean nonenemies = lua_opttrueboolean(L, 2); boolean nonenemies = lua_opttrueboolean(L, 2);
boolean bullet = lua_optboolean(L, 3);
NOHUD NOHUD
INLEVEL INLEVEL
if (!player) if (!player)
return LUA_ErrInvalid(L, "player_t"); return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_LookForEnemies(player, nonenemies)); LUA_PushUserdata(L, P_LookForEnemies(player, nonenemies, bullet), META_MOBJ);
return 1; return 1;
} }
@ -2147,6 +2181,31 @@ static int lib_sSoundPlaying(lua_State *L)
return 1; return 1;
} }
// This doesn't really exist, but we're providing it as a handy netgame-safe wrapper for stuff that should be locally handled.
static int lib_sStartMusicCaption(lua_State *L)
{
player_t *player = NULL;
const char *caption = luaL_checkstring(L, 1);
UINT16 lifespan = (UINT16)luaL_checkinteger(L, 2);
//HUDSAFE
INLEVEL
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (lifespan && (!player || P_IsLocalPlayer(player)))
{
strlcpy(S_sfx[sfx_None].caption, caption, sizeof(S_sfx[sfx_None].caption));
S_StartCaption(sfx_None, -1, lifespan);
}
return 0;
}
// G_GAME // G_GAME
//////////// ////////////
@ -2327,6 +2386,7 @@ static luaL_Reg lib[] = {
{"P_SpawnMobj",lib_pSpawnMobj}, {"P_SpawnMobj",lib_pSpawnMobj},
{"P_RemoveMobj",lib_pRemoveMobj}, {"P_RemoveMobj",lib_pRemoveMobj},
{"P_IsValidSprite2", lib_pIsValidSprite2}, {"P_IsValidSprite2", lib_pIsValidSprite2},
{"P_SpawnLockOn", lib_pSpawnLockOn},
{"P_SpawnMissile",lib_pSpawnMissile}, {"P_SpawnMissile",lib_pSpawnMissile},
{"P_SpawnXYZMissile",lib_pSpawnXYZMissile}, {"P_SpawnXYZMissile",lib_pSpawnXYZMissile},
{"P_SpawnPointMissile",lib_pSpawnPointMissile}, {"P_SpawnPointMissile",lib_pSpawnPointMissile},
@ -2354,6 +2414,7 @@ static luaL_Reg lib[] = {
{"P_GetPlayerControlDirection",lib_pGetPlayerControlDirection}, {"P_GetPlayerControlDirection",lib_pGetPlayerControlDirection},
{"P_AddPlayerScore",lib_pAddPlayerScore}, {"P_AddPlayerScore",lib_pAddPlayerScore},
{"P_StealPlayerScore",lib_pStealPlayerScore}, {"P_StealPlayerScore",lib_pStealPlayerScore},
{"P_GetJumpFlags",lib_pGetJumpFlags},
{"P_PlayerInPain",lib_pPlayerInPain}, {"P_PlayerInPain",lib_pPlayerInPain},
{"P_DoPlayerPain",lib_pDoPlayerPain}, {"P_DoPlayerPain",lib_pDoPlayerPain},
{"P_ResetPlayer",lib_pResetPlayer}, {"P_ResetPlayer",lib_pResetPlayer},
@ -2457,6 +2518,7 @@ static luaL_Reg lib[] = {
{"S_OriginPlaying",lib_sOriginPlaying}, {"S_OriginPlaying",lib_sOriginPlaying},
{"S_IdPlaying",lib_sIdPlaying}, {"S_IdPlaying",lib_sIdPlaying},
{"S_SoundPlaying",lib_sSoundPlaying}, {"S_SoundPlaying",lib_sSoundPlaying},
{"S_StartMusicCaption", lib_sStartMusicCaption},
// g_game // g_game
{"G_BuildMapName",lib_gBuildMapName}, {"G_BuildMapName",lib_gBuildMapName},

View file

@ -266,4 +266,4 @@ int LUA_BlockmapLib(lua_State *L)
return 0; return 0;
} }
#endif #endif

View file

@ -46,6 +46,7 @@ enum hook {
hook_ShieldSpawn, hook_ShieldSpawn,
hook_ShieldSpecial, hook_ShieldSpecial,
hook_MobjMoveBlocked, hook_MobjMoveBlocked,
hook_MapThingSpawn,
hook_MAX // last hook hook_MAX // last hook
}; };
@ -83,5 +84,6 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
#define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb #define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities #define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked) #define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
#endif #endif

View file

@ -57,6 +57,7 @@ const char *const hookNames[hook_MAX+1] = {
"ShieldSpawn", "ShieldSpawn",
"ShieldSpecial", "ShieldSpecial",
"MobjMoveBlocked", "MobjMoveBlocked",
"MapThingSpawn",
NULL NULL
}; };
@ -128,6 +129,7 @@ static int lib_addHook(lua_State *L)
case hook_MobjRemoved: case hook_MobjRemoved:
case hook_HurtMsg: case hook_HurtMsg:
case hook_MobjMoveBlocked: case hook_MobjMoveBlocked:
case hook_MapThingSpawn:
hook.s.mt = MT_NULL; hook.s.mt = MT_NULL;
if (lua_isnumber(L, 2)) if (lua_isnumber(L, 2))
hook.s.mt = lua_tonumber(L, 2); hook.s.mt = lua_tonumber(L, 2);
@ -187,6 +189,7 @@ static int lib_addHook(lua_State *L)
case hook_BossDeath: case hook_BossDeath:
case hook_MobjRemoved: case hook_MobjRemoved:
case hook_MobjMoveBlocked: case hook_MobjMoveBlocked:
case hook_MapThingSpawn:
lastp = &mobjhooks[hook.s.mt]; lastp = &mobjhooks[hook.s.mt];
break; break;
case hook_JumpSpecial: case hook_JumpSpecial:
@ -1073,4 +1076,66 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc)
// stack: tables // stack: tables
} }
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing)
{
hook_p hookp;
boolean hooked = false;
if (!gL || !(hooksAvailable[hook_MapThingSpawn/8] & (1<<(hook_MapThingSpawn%8))))
return false;
lua_settop(gL, 0);
// Look for all generic mobj map thing spawn hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_MapThingSpawn)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, mo, META_MOBJ);
LUA_PushUserdata(gL, mthing, META_MAPTHING);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MapThingSpawn)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, mo, META_MOBJ);
LUA_PushUserdata(gL, mthing, META_MAPTHING);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return hooked;
}
#endif #endif

View file

@ -31,6 +31,7 @@ enum sfxinfo_read {
sfxinfor_singular, sfxinfor_singular,
sfxinfor_priority, sfxinfor_priority,
sfxinfor_flags, // "pitch" sfxinfor_flags, // "pitch"
sfxinfor_caption,
sfxinfor_skinsound sfxinfor_skinsound
}; };
const char *const sfxinfo_ropt[] = { const char *const sfxinfo_ropt[] = {
@ -38,18 +39,21 @@ const char *const sfxinfo_ropt[] = {
"singular", "singular",
"priority", "priority",
"flags", "flags",
"caption",
"skinsound", "skinsound",
NULL}; NULL};
enum sfxinfo_write { enum sfxinfo_write {
sfxinfow_singular = 0, sfxinfow_singular = 0,
sfxinfow_priority, sfxinfow_priority,
sfxinfow_flags // "pitch" sfxinfow_flags, // "pitch"
sfxinfow_caption
}; };
const char *const sfxinfo_wopt[] = { const char *const sfxinfo_wopt[] = {
"singular", "singular",
"priority", "priority",
"flags", "flags",
"caption",
NULL}; NULL};
// //
@ -769,8 +773,8 @@ static int lib_getSfxInfo(lua_State *L)
lua_remove(L, 1); lua_remove(L, 1);
i = luaL_checkinteger(L, 1); i = luaL_checkinteger(L, 1);
if (i >= NUMSFX) if (i == 0 || i >= NUMSFX)
return luaL_error(L, "sfxinfo[] index %d out of range (0 - %d)", i, NUMSFX-1); return luaL_error(L, "sfxinfo[] index %d out of range (1 - %d)", i, NUMSFX-1);
LUA_PushUserdata(L, &S_sfx[i], META_SFXINFO); LUA_PushUserdata(L, &S_sfx[i], META_SFXINFO);
return 1; return 1;
} }
@ -783,9 +787,9 @@ static int lib_setSfxInfo(lua_State *L)
lua_remove(L, 1); lua_remove(L, 1);
{ {
UINT32 i = luaL_checkinteger(L, 1); UINT32 i = luaL_checkinteger(L, 1);
if (i >= NUMSFX) if (i == 0 || i >= NUMSFX)
return luaL_error(L, "sfxinfo[] index %d out of range (0 - %d)", i, NUMSFX-1); return luaL_error(L, "sfxinfo[] index %d out of range (1 - %d)", i, NUMSFX-1);
info = &S_sfx[i]; // get the mobjinfo to assign to. info = &S_sfx[i]; // get the sfxinfo to assign to.
} }
luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table. luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
lua_remove(L, 1); // pop mobjtype num, don't need it any more. lua_remove(L, 1); // pop mobjtype num, don't need it any more.
@ -814,6 +818,9 @@ static int lib_setSfxInfo(lua_State *L)
case sfxinfow_flags: case sfxinfow_flags:
info->pitch = (INT32)luaL_checkinteger(L, 3); info->pitch = (INT32)luaL_checkinteger(L, 3);
break; break;
case sfxinfow_caption:
strlcpy(info->caption, luaL_checkstring(L, 3), sizeof(info->caption));
break;
default: default:
break; break;
} }
@ -851,11 +858,14 @@ static int sfxinfo_get(lua_State *L)
case sfxinfor_flags: case sfxinfor_flags:
lua_pushinteger(L, sfx->pitch); lua_pushinteger(L, sfx->pitch);
return 1; return 1;
case sfxinfor_caption:
lua_pushstring(L, sfx->caption);
return 1;
case sfxinfor_skinsound: case sfxinfor_skinsound:
lua_pushinteger(L, sfx->skinsound); lua_pushinteger(L, sfx->skinsound);
return 1; return 1;
default: default:
return luaL_error(L, "impossible error"); return luaL_error(L, "Field does not exist in sfxinfo_t");
} }
return 0; return 0;
} }
@ -886,8 +896,11 @@ static int sfxinfo_set(lua_State *L)
case sfxinfow_flags: case sfxinfow_flags:
sfx->pitch = luaL_checkinteger(L, 1); sfx->pitch = luaL_checkinteger(L, 1);
break; break;
case sfxinfow_caption:
strlcpy(sfx->caption, luaL_checkstring(L, 1), sizeof(sfx->caption));
break;
default: default:
return luaL_error(L, "impossible error"); return luaL_error(L, "Field does not exist in sfxinfo_t");
} }
return 0; return 0;
} }

View file

@ -511,7 +511,8 @@ static int mobj_set(lua_State *L)
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
if (fastcmp(skins[i].name, skin)) if (fastcmp(skins[i].name, skin))
{ {
mo->skin = &skins[i]; if (!mo->player || R_SkinUsable(mo->player-players, i))
mo->skin = &skins[i];
return 0; return 0;
} }
return luaL_error(L, "mobj.skin '%s' not found!", skin); return luaL_error(L, "mobj.skin '%s' not found!", skin);

View file

@ -194,8 +194,6 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->gotcontinue); lua_pushinteger(L, plr->gotcontinue);
else if (fastcmp(field,"speed")) else if (fastcmp(field,"speed"))
lua_pushfixed(L, plr->speed); lua_pushfixed(L, plr->speed);
else if (fastcmp(field,"jumping"))
lua_pushboolean(L, plr->jumping);
else if (fastcmp(field,"secondjump")) else if (fastcmp(field,"secondjump"))
lua_pushinteger(L, plr->secondjump); lua_pushinteger(L, plr->secondjump);
else if (fastcmp(field,"fly1")) else if (fastcmp(field,"fly1"))
@ -459,8 +457,6 @@ static int player_set(lua_State *L)
plr->gotcontinue = (UINT8)luaL_checkinteger(L, 3); plr->gotcontinue = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"speed")) else if (fastcmp(field,"speed"))
plr->speed = luaL_checkfixed(L, 3); plr->speed = luaL_checkfixed(L, 3);
else if (fastcmp(field,"jumping"))
plr->jumping = luaL_checkboolean(L, 3);
else if (fastcmp(field,"secondjump")) else if (fastcmp(field,"secondjump"))
plr->secondjump = (UINT8)luaL_checkinteger(L, 3); plr->secondjump = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"fly1")) else if (fastcmp(field,"fly1"))

View file

@ -596,14 +596,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex)); mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO); WRITEUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT8(save_p, info - mobjinfo); WRITEUINT16(save_p, info - mobjinfo);
break; break;
} }
case ARCH_STATE: case ARCH_STATE:
{ {
state_t *state = *((state_t **)lua_touserdata(gL, myindex)); state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE); WRITEUINT8(save_p, ARCH_STATE);
WRITEUINT8(save_p, state - states); WRITEUINT16(save_p, state - states);
break; break;
} }
case ARCH_MOBJ: case ARCH_MOBJ:

View file

@ -16,89 +16,127 @@
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
#define META_ITERATIONSTATE "iteration state"
static const char *const iter_opt[] = { static const char *const iter_opt[] = {
"all", "all",
"mobj", "mobj",
NULL}; NULL};
static const actionf_p1 iter_funcs[] = {
NULL,
(actionf_p1)P_MobjThinker
};
struct iterationState {
actionf_p1 filter;
int next;
};
static int iterationState_gc(lua_State *L)
{
struct iterationState *it = luaL_checkudata(L, -1, META_ITERATIONSTATE);
if (it->next != LUA_REFNIL)
{
luaL_unref(L, LUA_REGISTRYINDEX, it->next);
it->next = LUA_REFNIL;
}
return 0;
}
#define push_thinker(th) {\
if ((th)->function.acp1 == (actionf_p1)P_MobjThinker) \
LUA_PushUserdata(L, (th), META_MOBJ); \
else \
lua_pushlightuserdata(L, (th)); \
}
static int lib_iterateThinkers(lua_State *L) static int lib_iterateThinkers(lua_State *L)
{ {
int state = luaL_checkoption(L, 1, "mobj", iter_opt); thinker_t *th = NULL, *next = NULL;
struct iterationState *it;
thinker_t *th = NULL;
actionf_p1 searchFunc;
const char *searchMeta;
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!"); return luaL_error(L, "This function can only be used in a level!");
lua_settop(L, 2); it = luaL_checkudata(L, 1, META_ITERATIONSTATE);
lua_remove(L, 1); // remove state now.
switch(state) lua_settop(L, 2);
if (lua_isnil(L, 2))
th = &thinkercap;
else if (lua_isuserdata(L, 2))
{ {
case 0: if (lua_islightuserdata(L, 2))
searchFunc = NULL; th = lua_touserdata(L, 2);
searchMeta = NULL; else
break; {
case 1: th = *(thinker_t **)lua_touserdata(L, -1);
default: if (!th)
searchFunc = (actionf_p1)P_MobjThinker; {
searchMeta = META_MOBJ; if (it->next == LUA_REFNIL)
break; return 0;
lua_rawgeti(L, LUA_REGISTRYINDEX, it->next);
if (lua_islightuserdata(L, -1))
next = lua_touserdata(L, -1);
else
next = *(thinker_t **)lua_touserdata(L, -1);
}
}
} }
if (!lua_isnil(L, 1)) { luaL_unref(L, LUA_REGISTRYINDEX, it->next);
if (lua_islightuserdata(L, 1)) it->next = LUA_REFNIL;
th = (thinker_t *)lua_touserdata(L, 1);
else if (searchMeta)
th = *((thinker_t **)luaL_checkudata(L, 1, searchMeta));
else
th = *((thinker_t **)lua_touserdata(L, 1));
} else
th = &thinkercap;
if (!th) // something got our userdata invalidated! if (th && !next)
return 0; next = th->next;
if (!next)
return luaL_error(L, "next thinker invalidated during iteration");
if (searchFunc == NULL) for (; next != &thinkercap; next = next->next)
{ if (!it->filter || next->function.acp1 == it->filter)
if ((th = th->next) != &thinkercap)
{ {
if (th->function.acp1 == (actionf_p1)P_MobjThinker) push_thinker(next);
LUA_PushUserdata(L, th, META_MOBJ); if (next->next != &thinkercap)
else {
lua_pushlightuserdata(L, th); push_thinker(next->next);
it->next = luaL_ref(L, LUA_REGISTRYINDEX);
}
return 1; return 1;
} }
return 0;
}
for (th = th->next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != searchFunc)
continue;
LUA_PushUserdata(L, th, searchMeta);
return 1;
}
return 0; return 0;
} }
static int lib_startIterate(lua_State *L) static int lib_startIterate(lua_State *L)
{ {
struct iterationState *it;
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!"); return luaL_error(L, "This function can only be used in a level!");
luaL_checkoption(L, 1, iter_opt[0], iter_opt);
lua_pushcfunction(L, lib_iterateThinkers); lua_pushvalue(L, lua_upvalueindex(1));
lua_pushvalue(L, 1); it = lua_newuserdata(L, sizeof(struct iterationState));
luaL_getmetatable(L, META_ITERATIONSTATE);
lua_setmetatable(L, -2);
it->filter = iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
it->next = LUA_REFNIL;
return 2; return 2;
} }
#undef push_thinker
int LUA_ThinkerLib(lua_State *L) int LUA_ThinkerLib(lua_State *L)
{ {
luaL_newmetatable(L, META_ITERATIONSTATE);
lua_pushcfunction(L, iterationState_gc);
lua_setfield(L, -2, "__gc");
lua_pop(L, 1);
lua_createtable(L, 0, 1); lua_createtable(L, 0, 1);
lua_pushcfunction(L, lib_startIterate); lua_pushcfunction(L, lib_iterateThinkers);
lua_pushcclosure(L, lib_startIterate, 1);
lua_setfield(L, -2, "iterate"); lua_setfield(L, -2, "iterate");
lua_setglobal(L, "thinkers"); lua_setglobal(L, "thinkers");
return 0; return 0;

View file

@ -18,6 +18,7 @@
#include "z_zone.h" #include "z_zone.h"
#include "v_video.h" #include "v_video.h"
#include "i_video.h" #include "i_video.h"
#include "m_misc.h"
// GIFs are always little-endian // GIFs are always little-endian
#include "byteptr.h" #include "byteptr.h"
@ -396,7 +397,6 @@ static void GIF_headwrite(void)
{ {
UINT8 *gifhead = Z_Malloc(800, PU_STATIC, NULL); UINT8 *gifhead = Z_Malloc(800, PU_STATIC, NULL);
UINT8 *p = gifhead; UINT8 *p = gifhead;
RGBA_t *c;
INT32 i; INT32 i;
UINT16 rwidth, rheight; UINT16 rwidth, rheight;
@ -427,12 +427,17 @@ static void GIF_headwrite(void)
WRITEUINT8(p, 0x00); WRITEUINT8(p, 0x00);
// write color table // write color table
for (i = 0; i < 256; ++i)
{ {
c = &pLocalPalette[i]; RGBA_t *pal = ((cv_screenshot_colorprofile.value)
WRITEUINT8(p, c->s.red); ? pLocalPalette
WRITEUINT8(p, c->s.green); : pMasterPalette);
WRITEUINT8(p, c->s.blue);
for (i = 0; i < 256; i++)
{
WRITEUINT8(p, pal[i].s.red);
WRITEUINT8(p, pal[i].s.green);
WRITEUINT8(p, pal[i].s.blue);
}
} }
// write extension block // write extension block

View file

@ -942,7 +942,7 @@ boolean OP_FreezeObjectplace(void)
if (!objectplacing) if (!objectplacing)
return false; return false;
if ((maptol & TOL_NIGHTS) && (players[consoleplayer].pflags & PF_NIGHTSMODE)) if ((maptol & TOL_NIGHTS) && (players[consoleplayer].powers[pw_carry] == CR_NIGHTSMODE))
return false; return false;
return true; return true;
@ -968,7 +968,7 @@ void OP_NightsObjectplace(player_t *player)
if (player->pflags & PF_ATTACKDOWN) if (player->pflags & PF_ATTACKDOWN)
{ {
// Are ANY objectplace buttons pressed? If no, remove flag. // Are ANY objectplace buttons pressed? If no, remove flag.
if (!(cmd->buttons & (BT_ATTACK|BT_TOSSFLAG|BT_USE|BT_CAMRIGHT|BT_CAMLEFT))) if (!(cmd->buttons & (BT_ATTACK|BT_TOSSFLAG|BT_USE|BT_WEAPONNEXT|BT_WEAPONPREV)))
player->pflags &= ~PF_ATTACKDOWN; player->pflags &= ~PF_ATTACKDOWN;
// Do nothing. // Do nothing.
@ -1019,7 +1019,7 @@ void OP_NightsObjectplace(player_t *player)
} }
// This places a ring! // This places a ring!
if (cmd->buttons & BT_CAMRIGHT) if (cmd->buttons & BT_WEAPONNEXT)
{ {
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_ATTACKDOWN;
if (!OP_HeightOkay(player, false)) if (!OP_HeightOkay(player, false))
@ -1030,7 +1030,7 @@ void OP_NightsObjectplace(player_t *player)
} }
// This places a wing item! // This places a wing item!
if (cmd->buttons & BT_CAMLEFT) if (cmd->buttons & BT_WEAPONPREV)
{ {
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_ATTACKDOWN;
if (!OP_HeightOkay(player, false)) if (!OP_HeightOkay(player, false))
@ -1255,7 +1255,7 @@ void Command_ObjectPlace_f(void)
{ {
objectplacing = true; objectplacing = true;
if ((players[0].pflags & PF_NIGHTSMODE)) if ((players[0].powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!COM_CheckParm("-silent")) if (!COM_CheckParm("-silent"))
@ -1326,7 +1326,7 @@ void Command_ObjectPlace_f(void)
// Don't touch the NiGHTS Objectplace stuff. // Don't touch the NiGHTS Objectplace stuff.
// ... or if the mo mysteriously vanished. // ... or if the mo mysteriously vanished.
if (!players[0].mo || (players[0].pflags & PF_NIGHTSMODE)) if (!players[0].mo || (players[0].powers[pw_carry] == CR_NIGHTSMODE))
return; return;
// If still in dummy state, get out of it. // If still in dummy state, get out of it.

View file

@ -573,31 +573,31 @@ extraemblem_t extraemblems[MAXEXTRAEMBLEMS] =
unlockable_t unlockables[MAXUNLOCKABLES] = unlockable_t unlockables[MAXUNLOCKABLES] =
{ {
// Name, Objective, Menu Height, ConditionSet, Unlock Type, Variable, NoCecho, NoChecklist // Name, Objective, Menu Height, ConditionSet, Unlock Type, Variable, NoCecho, NoChecklist
/* 01 */ {"Record Attack", "Complete Greenflower Zone, Act 1", 0, 1, SECRET_RECORDATTACK, 0, true, true, 0}, /* 01 */ {"Record Attack", "/", 0, 1, SECRET_RECORDATTACK, 0, true, true, 0},
/* 02 */ {"NiGHTS Mode", "Complete Floral Field", 0, 2, SECRET_NIGHTSMODE, 0, true, true, 0}, /* 02 */ {"NiGHTS Mode", "/", 0, 2, SECRET_NIGHTSMODE, 0, true, true, 0},
/* 03 */ {"Play Credits", "Complete 1P Mode", 30, 10, SECRET_CREDITS, 0, true, true, 0}, /* 03 */ {"Play Credits", "/", 30, 10, SECRET_CREDITS, 0, true, true, 0},
/* 04 */ {"Sound Test", "Complete 1P Mode", 40, 10, SECRET_SOUNDTEST, 0, false, false, 0}, /* 04 */ {"Sound Test", "/", 40, 10, SECRET_SOUNDTEST, 0, false, false, 0},
/* 05 */ {"EXTRA LEVELS", "", 60, 0, SECRET_HEADER, 0, true, true, 0}, /* 05 */ {"EXTRA LEVELS", "/", 58, 0, SECRET_HEADER, 0, true, true, 0},
/* 06 */ {"Aerial Garden Zone", "Complete 1P Mode w/ all emeralds", 70, 11, SECRET_WARP, 40, false, false, 0}, /* 06 */ {"Aerial Garden Zone", "/", 70, 11, SECRET_WARP, 40, false, false, 0},
/* 07 */ {"Azure Temple Zone", "Complete Aerial Garden Zone", 80, 20, SECRET_WARP, 41, false, false, 0}, /* 07 */ {"Azure Temple Zone", "/", 80, 20, SECRET_WARP, 41, false, false, 0},
/* 08 */ {"BONUS LEVELS", "", 100, 0, SECRET_HEADER, 0, true, true, 0}, /* 08 */ {"BONUS LEVELS", "/", 98, 0, SECRET_HEADER, 0, true, true, 0},
/* 09 */ {"PLACEHOLDER", "PLACEHOLDER", 0, 0, SECRET_NONE, 0, true, true, 0}, /* 09 */ {"PLACEHOLDER", "/", 0, 0, SECRET_NONE, 0, true, true, 0},
/* 10 */ {"Mario Koopa Blast", "Collect 60 Emblems", 110, 42, SECRET_WARP, 30, false, false, 0}, /* 10 */ {"Mario Koopa Blast", "/", 110, 42, SECRET_WARP, 30, false, false, 0},
/* 11 */ {"PLACEHOLDER", "PLACEHOLDER", 0, 0, SECRET_NONE, 0, true, true, 0}, /* 11 */ {"PLACEHOLDER", "/", 0, 0, SECRET_NONE, 0, true, true, 0},
/* 12 */ {"Spring Hill Zone", "Collect 100 Emblems", 0, 44, SECRET_NONE, 0, false, false, 0}, /* 12 */ {"Spring Hill Zone", "/", 0, 44, SECRET_NONE, 0, false, false, 0},
/* 13 */ {"Black Hole", "A Rank in all Special Stages", 0, 50, SECRET_NONE, 0, false, true, 0}, /* 13 */ {"Black Hole", "Get grade A in all Special Stages", 0, 50, SECRET_NONE, 0, false, true, 0},
/* 14 */ {"Emblem Hints", "Collect 40 Emblems", 0, 41, SECRET_EMBLEMHINTS, 0, false, true, 0}, /* 14 */ {"Emblem Hints", "/", 0, 41, SECRET_EMBLEMHINTS, 0, false, true, 0},
/* 15 */ {"Emblem Radar", "Collect 80 Emblems", 0, 43, SECRET_ITEMFINDER, 0, false, true, 0}, /* 15 */ {"Emblem Radar", "/", 0, 43, SECRET_ITEMFINDER, 0, false, true, 0},
/* 16 */ {"Pandora's Box", "Collect All Emblems", 0, 45, SECRET_PANDORA, 0, false, false, 0}, /* 16 */ {"Pandora's Box", "/", 0, 45, SECRET_PANDORA, 0, false, false, 0},
/* 17 */ {"Level Select", "Collect All Emblems", 20, 45, SECRET_LEVELSELECT, 1, false, true, 0}, /* 17 */ {"Level Select", "/", 20, 45, SECRET_LEVELSELECT, 1, false, true, 0},
}; };
// Default number of emblems and extra emblems // Default number of emblems and extra emblems

File diff suppressed because it is too large Load diff

View file

@ -66,7 +66,7 @@ void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtyp
// Called by linux_x/i_video_xshm.c // Called by linux_x/i_video_xshm.c
void M_QuitResponse(INT32 ch); void M_QuitResponse(INT32 ch);
// Determines whether to show a level in the list // Determines whether to show a level in the list (platter version does not need to be exposed)
boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt);
@ -149,8 +149,6 @@ typedef struct menuitem_s
UINT8 alphaKey; UINT8 alphaKey;
} menuitem_t; } menuitem_t;
extern menuitem_t PlayerMenu[32];
typedef struct menu_s typedef struct menu_s
{ {
const char *menutitlepic; const char *menutitlepic;
@ -174,14 +172,36 @@ extern menu_t SP_LoadDef;
// Stuff for customizing the player select screen // Stuff for customizing the player select screen
typedef struct typedef struct
{ {
boolean used;
char notes[441]; char notes[441];
char picname[8]; char picname[8];
char skinname[SKINNAMESIZE*2+2]; // skin&skin\0 char skinname[SKINNAMESIZE*2+2]; // skin&skin\0
UINT16 wadnum; // for duplicate characters
UINT8 prev; UINT8 prev;
UINT8 next; UINT8 next;
} description_t; } description_t;
// level select platter
typedef struct
{
char header[22+5]; // mapheader_t lvltttl max length + " ZONE"
INT32 maplist[3];
char mapnames[3][17+1];
boolean mapavailable[4]; // mapavailable[3] == wide or not
} levelselectrow_t;
typedef struct
{
UINT8 numrows;
levelselectrow_t *rows;
} levelselect_t;
// experimental level select end
// descriptions for gametype select screen
typedef struct
{
char notes[441];
} gtdesc_t;
// mode descriptions for video mode menu // mode descriptions for video mode menu
typedef struct typedef struct
{ {
@ -222,6 +242,9 @@ void M_ForceSaveSlotSelected(INT32 sslot);
void M_CheatActivationResponder(INT32 ch); void M_CheatActivationResponder(INT32 ch);
// Level select updating
void Nextmap_OnChange(void);
// Screenshot menu updating // Screenshot menu updating
void Moviemode_mode_Onchange(void); void Moviemode_mode_Onchange(void);
void Screenshot_option_Onchange(void); void Screenshot_option_Onchange(void);
@ -263,14 +286,14 @@ void Screenshot_option_Onchange(void);
NULL\ NULL\
} }
#define MAPICONMENUSTYLE(header, source, prev)\ #define MAPPLATTERMENUSTYLE(header, source)\
{\ {\
header,\ header,\
sizeof (source)/sizeof (menuitem_t),\ sizeof (source)/sizeof (menuitem_t),\
prev,\ &MainDef,\
source,\ source,\
M_DrawServerMenu,\ M_DrawLevelPlatterMenu,\
27,40,\ 0,0,\
0,\ 0,\
NULL\ NULL\
} }

View file

@ -100,6 +100,8 @@ static CV_PossibleValue_t screenshot_cons_t[] = {{0, "Default"}, {1, "HOME"}, {2
consvar_t cv_screenshot_option = {"screenshot_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Screenshot_option_Onchange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_screenshot_option = {"screenshot_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Screenshot_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_screenshot_folder = {"screenshot_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_screenshot_folder = {"screenshot_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}}; static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}};
consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL};
@ -585,7 +587,7 @@ static const char *Newsnapshotfile(const char *pathname, const char *ext)
i += add * result; i += add * result;
if (add < 0 || add > 9999) if (i < 0 || i > 9999)
return NULL; return NULL;
} }
@ -610,20 +612,25 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext)
CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
} }
static void M_PNGhdr(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_uint_32 width, PNG_CONST png_uint_32 height, PNG_CONST png_byte *palette) static void M_PNGhdr(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_uint_32 width, PNG_CONST png_uint_32 height, const boolean palette)
{ {
const png_byte png_interlace = PNG_INTERLACE_NONE; //PNG_INTERLACE_ADAM7 const png_byte png_interlace = PNG_INTERLACE_NONE; //PNG_INTERLACE_ADAM7
if (palette) if (palette)
{ {
png_colorp png_PLTE = png_malloc(png_ptr, sizeof(png_color)*256); //palette png_colorp png_PLTE = png_malloc(png_ptr, sizeof(png_color)*256); //palette
const png_byte *pal = palette;
png_uint_16 i; png_uint_16 i;
RGBA_t *pal = ((cv_screenshot_colorprofile.value)
? pLocalPalette
: pMasterPalette);
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
{ {
png_PLTE[i].red = *pal; pal++; png_PLTE[i].red = pal[i].s.red;
png_PLTE[i].green = *pal; pal++; png_PLTE[i].green = pal[i].s.green;
png_PLTE[i].blue = *pal; pal++; png_PLTE[i].blue = pal[i].s.blue;
} }
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE,
png_interlace, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_interlace, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info_before_PLTE(png_ptr, png_info_ptr); png_write_info_before_PLTE(png_ptr, png_info_ptr);
@ -924,7 +931,7 @@ static void M_PNGfix_acTL(png_structp png_ptr, png_infop png_info_ptr)
fseek(apng_FILE, oldpos, SEEK_SET); fseek(apng_FILE, oldpos, SEEK_SET);
} }
static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) static boolean M_SetupaPNG(png_const_charp filename, boolean palette)
{ {
apng_FILE = fopen(filename,"wb+"); // + mode for reading apng_FILE = fopen(filename,"wb+"); // + mode for reading
if (!apng_FILE) if (!apng_FILE)
@ -966,7 +973,7 @@ static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal)
png_set_compression_strategy(apng_ptr, cv_zlib_strategya.value); png_set_compression_strategy(apng_ptr, cv_zlib_strategya.value);
png_set_compression_window_bits(apng_ptr, cv_zlib_window_bitsa.value); png_set_compression_window_bits(apng_ptr, cv_zlib_window_bitsa.value);
M_PNGhdr(apng_ptr, apng_info_ptr, vid.width, vid.height, pal); M_PNGhdr(apng_ptr, apng_info_ptr, vid.width, vid.height, palette);
M_PNGText(apng_ptr, apng_info_ptr, true); M_PNGText(apng_ptr, apng_info_ptr, true);
@ -1007,9 +1014,9 @@ static inline moviemode_t M_StartMovieAPNG(const char *pathname)
} }
if (rendermode == render_soft) if (rendermode == render_soft)
ret = M_SetupaPNG(va(pandf,pathname,freename), W_CacheLumpName(GetPalette(), PU_CACHE)); ret = M_SetupaPNG(va(pandf,pathname,freename), true);
else else
ret = M_SetupaPNG(va(pandf,pathname,freename), NULL); ret = M_SetupaPNG(va(pandf,pathname,freename), false);
if (!ret) if (!ret)
{ {
@ -1215,11 +1222,10 @@ void M_StopMovie(void)
* \param palette Palette of image data * \param palette Palette of image data
* \note if palette is NULL, BGR888 format * \note if palette is NULL, BGR888 format
*/ */
boolean M_SavePNG(const char *filename, void *data, int width, int height, const UINT8 *palette) boolean M_SavePNG(const char *filename, void *data, int width, int height, const boolean palette)
{ {
png_structp png_ptr; png_structp png_ptr;
png_infop png_info_ptr; png_infop png_info_ptr;
PNG_CONST png_byte *PLTE = (const png_byte *)palette;
#ifdef PNG_SETJMP_SUPPORTED #ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD #ifdef USE_FAR_KEYWORD
jmp_buf jmpbuf; jmp_buf jmpbuf;
@ -1282,7 +1288,7 @@ boolean M_SavePNG(const char *filename, void *data, int width, int height, const
png_set_compression_strategy(png_ptr, cv_zlib_strategy.value); png_set_compression_strategy(png_ptr, cv_zlib_strategy.value);
png_set_compression_window_bits(png_ptr, cv_zlib_window_bits.value); png_set_compression_window_bits(png_ptr, cv_zlib_window_bits.value);
M_PNGhdr(png_ptr, png_info_ptr, width, height, PLTE); M_PNGhdr(png_ptr, png_info_ptr, width, height, palette);
M_PNGText(png_ptr, png_info_ptr, false); M_PNGText(png_ptr, png_info_ptr, false);
@ -1329,7 +1335,7 @@ typedef struct
* \param palette Palette of image data * \param palette Palette of image data
*/ */
#if NUMSCREENS > 2 #if NUMSCREENS > 2
static boolean WritePCXfile(const char *filename, const UINT8 *data, int width, int height, const UINT8 *palette) static boolean WritePCXfile(const char *filename, const UINT8 *data, int width, int height)
{ {
int i; int i;
size_t length; size_t length;
@ -1370,8 +1376,20 @@ static boolean WritePCXfile(const char *filename, const UINT8 *data, int width,
// write the palette // write the palette
*pack++ = 0x0c; // palette ID byte *pack++ = 0x0c; // palette ID byte
for (i = 0; i < 768; i++)
*pack++ = *palette++; // write color table
{
RGBA_t *pal = ((cv_screenshot_colorprofile.value)
? pLocalPalette
: pMasterPalette);
for (i = 0; i < 256; i++)
{
*pack++ = pal[i].s.red;
*pack++ = pal[i].s.green;
*pack++ = pal[i].s.blue;
}
}
// write output file // write output file
length = pack - (UINT8 *)pcx; length = pack - (UINT8 *)pcx;
@ -1445,11 +1463,9 @@ void M_DoScreenShot(void)
if (rendermode != render_none) if (rendermode != render_none)
{ {
#ifdef USE_PNG #ifdef USE_PNG
ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, true);
W_CacheLumpName(GetPalette(), PU_CACHE));
#else #else
ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height);
W_CacheLumpName(GetPalette(), PU_CACHE));
#endif #endif
} }

View file

@ -19,6 +19,7 @@
#include "tables.h" #include "tables.h"
#include "d_event.h" // Screenshot responder #include "d_event.h" // Screenshot responder
#include "command.h"
typedef enum { typedef enum {
MM_OFF = 0, MM_OFF = 0,
@ -28,6 +29,12 @@ typedef enum {
} moviemode_t; } moviemode_t;
extern moviemode_t moviemode; extern moviemode_t moviemode;
extern consvar_t cv_screenshot_option, cv_screenshot_folder, cv_screenshot_colorprofile;
extern consvar_t cv_moviemode;
extern consvar_t cv_zlib_memory, cv_zlib_level, cv_zlib_strategy, cv_zlib_window_bits;
extern consvar_t cv_zlib_memorya, cv_zlib_levela, cv_zlib_strategya, cv_zlib_window_bitsa;
extern consvar_t cv_apng_delay;
void M_StartMovie(void); void M_StartMovie(void);
void M_SaveFrame(void); void M_SaveFrame(void);
void M_StopMovie(void); void M_StopMovie(void);
@ -57,7 +64,7 @@ void FIL_ForceExtension(char *path, const char *extension);
boolean FIL_CheckExtension(const char *in); boolean FIL_CheckExtension(const char *in);
#ifdef HAVE_PNG #ifdef HAVE_PNG
boolean M_SavePNG(const char *filename, void *data, int width, int height, const UINT8 *palette); boolean M_SavePNG(const char *filename, void *data, int width, int height, const boolean palette);
#endif #endif
extern boolean takescreenshot; extern boolean takescreenshot;

View file

@ -1145,7 +1145,7 @@ void A_JetJawChomp(mobj_t *actor)
if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)
|| actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) || actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
{ {
P_SetMobjState(actor, actor->info->spawnstate); P_SetMobjStateNF(actor, actor->info->spawnstate);
return; return;
} }
@ -3170,6 +3170,8 @@ void A_Invincibility(mobj_t *actor)
S_StopMusic(); S_StopMusic();
if (mariomode) if (mariomode)
G_GhostAddColor(GHC_INVINCIBLE); G_GhostAddColor(GHC_INVINCIBLE);
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
} }
} }
@ -3208,6 +3210,8 @@ void A_SuperSneakers(mobj_t *actor)
S_StopMusic(); S_StopMusic();
S_ChangeMusicInternal("_shoes", false); S_ChangeMusicInternal("_shoes", false);
} }
strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
} }
} }
@ -4182,12 +4186,15 @@ void A_SignPlayer(mobj_t *actor)
actor->frame += Color_Opposite[actor->target->player->skincolor*2+1]; actor->frame += Color_Opposite[actor->target->player->skincolor*2+1];
} }
// spawn an overlay of the player's face. if (skin->sprites[SPR2_SIGN].numframes)
ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); {
P_SetTarget(&ov->target, actor); // spawn an overlay of the player's face.
ov->color = actor->target->player->skincolor; ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
ov->skin = skin; P_SetTarget(&ov->target, actor);
P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN ov->color = actor->target->player->skincolor;
ov->skin = skin;
P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN
}
} }
// Function: A_OverlayThink // Function: A_OverlayThink
@ -4517,7 +4524,7 @@ void A_MinusDigging(mobj_t *actor)
// If we're close enough to our target, pop out of the ground // If we're close enough to our target, pop out of the ground
if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius
&& abs(actor->target->z - actor->z) < actor->height) && abs(actor->target->z - actor->z) < 2*actor->height)
P_SetMobjState(actor, actor->info->missilestate); P_SetMobjState(actor, actor->info->missilestate);
// Snap to ground // Snap to ground
@ -5599,7 +5606,10 @@ void A_MixUp(mobj_t *actor)
// No mix-up monitors in hide and seek or time only race. // No mix-up monitors in hide and seek or time only race.
// The random factor is okay for other game modes, but in these, it is cripplingly unfair. // The random factor is okay for other game modes, but in these, it is cripplingly unfair.
if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE) if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE)
{
S_StartSound(actor, sfx_lose);
return; return;
}
numplayers = 0; numplayers = 0;
memset(teleported, 0, sizeof (teleported)); memset(teleported, 0, sizeof (teleported));
@ -5608,7 +5618,7 @@ void A_MixUp(mobj_t *actor)
// and grab their xyz coords // and grab their xyz coords
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
&& !players[i].exiting && !players[i].powers[pw_super]) && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{ {
if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
continue; continue;
@ -5727,7 +5737,7 @@ void A_MixUp(mobj_t *actor)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && players[i].playerstate == PST_LIVE if (playeringame[i] && players[i].playerstate == PST_LIVE
&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super]) && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{ {
if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
continue; continue;
@ -5777,7 +5787,7 @@ void A_MixUp(mobj_t *actor)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && players[i].playerstate == PST_LIVE if (playeringame[i] && players[i].playerstate == PST_LIVE
&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super]) && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{ {
if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
continue; continue;
@ -5807,7 +5817,7 @@ void A_MixUp(mobj_t *actor)
if (teleported[i]) if (teleported[i])
{ {
if (playeringame[i] && players[i].playerstate == PST_LIVE if (playeringame[i] && players[i].playerstate == PST_LIVE
&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super]) && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{ {
if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
continue; continue;
@ -5949,7 +5959,7 @@ void A_RecyclePowers(mobj_t *actor)
for (j = 0; j < NUMPOWERS; j++) for (j = 0; j < NUMPOWERS; j++)
{ {
if (j == pw_flashing || j == pw_underwater || j == pw_spacetime if (j == pw_flashing || j == pw_underwater || j == pw_spacetime || j == pw_carry
|| j == pw_tailsfly || j == pw_extralife || j == pw_nocontrol || j == pw_super) || j == pw_tailsfly || j == pw_extralife || j == pw_nocontrol || j == pw_super)
continue; continue;
players[recv_pl].powers[j] = powers[send_pl][j]; players[recv_pl].powers[j] = powers[send_pl][j];
@ -8235,7 +8245,7 @@ void A_OrbitNights(mobj_t* actor)
#endif #endif
if (!actor->target || !actor->target->player || if (!actor->target || !actor->target->player ||
!(actor->target->player->pflags & PF_NIGHTSMODE) || !actor->target->player->nightstime !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE) || !actor->target->player->nightstime
// Also remove this object if they no longer have a NiGHTS helper // Also remove this object if they no longer have a NiGHTS helper
|| (ishelper && !actor->target->player->powers[pw_nights_helper])) || (ishelper && !actor->target->player->powers[pw_nights_helper]))
{ {

View file

@ -1776,9 +1776,9 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
case MT_SCORE: case MT_SCORE:
case MT_DROWNNUMBERS: case MT_DROWNNUMBERS:
case MT_GOTEMERALD: case MT_GOTEMERALD:
case MT_LOCKON:
case MT_TAG: case MT_TAG:
case MT_GOTFLAG: case MT_GOTFLAG:
case MT_GOTFLAG2:
case MT_HOOP: case MT_HOOP:
case MT_HOOPCOLLIDE: case MT_HOOPCOLLIDE:
case MT_NIGHTSCORE: case MT_NIGHTSCORE:
@ -2061,6 +2061,33 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
P_RemoveThinker(&nobaddies->thinker); P_RemoveThinker(&nobaddies->thinker);
} }
//
// P_IsObjectOnRealGround
//
// Helper function for T_EachTimeThinker
// Like P_IsObjectOnGroundIn, except ONLY THE REAL GROUND IS CONSIDERED, NOT FOFS
// I'll consider whether to make this a more globally accessible function or whatever in future
// -- Monster Iestyn
//
static boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec)
{
// Is the object in reverse gravity?
if (mo->eflags & MFE_VERTICALFLIP)
{
// Detect if the player is on the ceiling.
if (mo->z+mo->height >= P_GetSpecialTopZ(mo, sec, sec))
return true;
}
// Nope!
else
{
// Detect if the player is on the floor.
if (mo->z <= P_GetSpecialBottomZ(mo, sec, sec))
return true;
}
return false;
}
// //
// P_HavePlayersEnteredArea // P_HavePlayersEnteredArea
// //
@ -2113,6 +2140,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
boolean inAndOut = false; boolean inAndOut = false;
boolean floortouch = false; boolean floortouch = false;
fixed_t bottomheight, topheight; fixed_t bottomheight, topheight;
msecnode_t *node;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -2174,7 +2202,23 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
if ((netgame || multiplayer) && players[j].spectator) if ((netgame || multiplayer) && players[j].spectator)
continue; continue;
if (players[j].mo->subsector->sector != targetsec) if (players[j].mo->subsector->sector == targetsec)
;
else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
for (node = players[j].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == targetsec)
{
insector = true;
break;
}
}
if (!insector)
continue;
}
else
continue; continue;
topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec); topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec);
@ -2224,10 +2268,30 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
if ((netgame || multiplayer) && players[i].spectator) if ((netgame || multiplayer) && players[i].spectator)
continue; continue;
if (players[i].mo->subsector->sector != sec) if (players[i].mo->subsector->sector == sec)
;
else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sec)
{
insector = true;
break;
}
}
if (!insector)
continue;
}
else
continue; continue;
if (floortouch == true && P_IsObjectOnGroundIn(players[i].mo, sec)) if (!(players[i].mo->subsector->sector == sec
|| P_PlayerTouchingSectorSpecial(&players[i], 2, (GETSECSPECIAL(sec->special, 2))) == sec))
continue;
if (floortouch == true && P_IsObjectOnRealGround(players[i].mo, sec))
{ {
if (i & 1) if (i & 1)
eachtime->var2s[i/2] |= 1; eachtime->var2s[i/2] |= 1;
@ -2557,6 +2621,12 @@ void T_PlaneDisplace(planedisplace_t *pd)
direction = (control->floorheight > pd->last_height) ? 1 : -1; direction = (control->floorheight > pd->last_height) ? 1 : -1;
diff = FixedMul(control->floorheight-pd->last_height, pd->speed); diff = FixedMul(control->floorheight-pd->last_height, pd->speed);
if (pd->reverse) // reverse direction?
{
direction *= -1;
diff *= -1;
}
if (pd->type == pd_floor || pd->type == pd_both) if (pd->type == pd_floor || pd->type == pd_both)
T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, 0, 0, direction); // move floor T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, 0, 0, direction); // move floor
if (pd->type == pd_ceiling || pd->type == pd_both) if (pd->type == pd_ceiling || pd->type == pd_both)
@ -2923,7 +2993,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
fixed_t leftx, rightx; fixed_t leftx, rightx;
fixed_t topy, bottomy; fixed_t topy, bottomy;
fixed_t topz, bottomz; fixed_t topz, bottomz;
fixed_t widthfactor, heightfactor; fixed_t widthfactor = FRACUNIT, heightfactor = FRACUNIT;
fixed_t a, b, c; fixed_t a, b, c;
mobjtype_t type = MT_ROCKCRUMBLE1; mobjtype_t type = MT_ROCKCRUMBLE1;
fixed_t spacing = (32<<FRACBITS); fixed_t spacing = (32<<FRACBITS);
@ -3240,14 +3310,6 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
} }
else else
{ {
if (thing->type == MT_EMMY && thing->spawnpoint && (thing->spawnpoint->options & MTF_OBJECTSPECIAL))
{
mobj_t *tokenobj = P_SpawnMobj(sector->soundorg.x, sector->soundorg.y, topheight, MT_TOKEN);
P_SetTarget(&thing->tracer, tokenobj);
P_SetTarget(&tokenobj->target, thing);
P_SetMobjState(tokenobj, mobjinfo[MT_TOKEN].seestate);
}
// "Powerup rise" sound // "Powerup rise" sound
S_StartSound(puncher, sfx_mario9); // Puncher is "close enough" S_StartSound(puncher, sfx_mario9); // Puncher is "close enough"
} }

View file

@ -257,6 +257,8 @@ void P_DoMatchSuper(player_t *player)
S_StopMusic(); S_StopMusic();
if (mariomode) if (mariomode)
G_GhostAddColor(GHC_INVINCIBLE); G_GhostAddColor(GHC_INVINCIBLE);
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
} }
@ -278,6 +280,8 @@ void P_DoMatchSuper(player_t *player)
S_StopMusic(); S_StopMusic();
if (mariomode) if (mariomode)
G_GhostAddColor(GHC_INVINCIBLE); G_GhostAddColor(GHC_INVINCIBLE);
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
} }
} }
@ -367,11 +371,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; return;
} }
if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| (player->pflags & (PF_SPINNING|PF_GLIDING)) || (player->pflags & (PF_SPINNING|PF_GLIDING))
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0)) || ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| player->powers[pw_invulnerability] || player->powers[pw_super] || player->powers[pw_invulnerability] || player->powers[pw_super]
|| elementalpierce) // Do you possess the ability to subdue the object? || elementalpierce) // Do you possess the ability to subdue the object?
{ {
@ -379,9 +383,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{ {
if (elementalpierce == 2) if (elementalpierce == 2)
P_DoBubbleBounce(player); P_DoBubbleBounce(player);
else else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
toucher->momz = -toucher->momz; toucher->momz = -toucher->momz;
} }
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
toucher->momx = -toucher->momx; toucher->momx = -toucher->momx;
toucher->momy = -toucher->momy; toucher->momy = -toucher->momy;
P_DamageMobj(special, toucher, toucher, 1, 0); P_DamageMobj(special, toucher, toucher, 1, 0);
@ -406,7 +412,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
/////ENEMIES!!////////////////////////////////////////// /////ENEMIES!!//////////////////////////////////////////
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
if (special->type == MT_GSNAPPER && !(((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce) || player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce)
&& toucher->z < special->z + special->height && toucher->z + toucher->height > special->z) && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z)
{ {
@ -416,23 +422,30 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
else if (special->type == MT_SHARP else if (special->type == MT_SHARP
&& ((special->state == &states[special->info->xdeathstate]) || (toucher->z > special->z + special->height/2))) && ((special->state == &states[special->info->xdeathstate]) || (toucher->z > special->z + special->height/2)))
{ {
// Cannot hit sharp from above or when red and angry if (player->pflags & PF_BOUNCING)
P_DamageMobj(toucher, special, special, 1, 0); {
toucher->momz = -toucher->momz;
P_DoAbilityBounce(player, false);
}
else // Cannot hit sharp from above or when red and angry
P_DamageMobj(toucher, special, special, 1, 0);
} }
else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) else if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| (player->pflags & (PF_SPINNING|PF_GLIDING)) || (player->pflags & (PF_SPINNING|PF_GLIDING))
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0)) || ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
{ {
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
{ {
if (elementalpierce == 2) if (elementalpierce == 2)
P_DoBubbleBounce(player); P_DoBubbleBounce(player);
else else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
toucher->momz = -toucher->momz; toucher->momz = -toucher->momz;
} }
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
P_DamageMobj(special, toucher, toucher, 1, 0); P_DamageMobj(special, toucher, toucher, 1, 0);
} }
@ -557,21 +570,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Gameplay related collectibles // // Gameplay related collectibles //
// ***************************** // // ***************************** //
// Special Stage Token // Special Stage Token
case MT_EMMY: case MT_TOKEN:
if (player->bot) if (player->bot)
return; return;
tokenlist += special->health; tokenlist += special->health;
P_AddPlayerScore(player, 1000);
if (ALL7EMERALDS(emeralds)) // Got all 7 if (ALL7EMERALDS(emeralds)) // Got all 7
{ {
P_GivePlayerRings(player, 50); if (!(netgame || multiplayer))
nummaprings += 50; // no cheating towards Perfect! {
player->continues += 1;
players->gotcontinue = true;
if (P_IsLocalPlayer(player))
S_StartSound(NULL, sfx_s3kac);
}
} }
else else
token++; token++;
if (special->tracer) // token BG
P_RemoveMobj(special->tracer);
break; break;
// Emerald Hunt // Emerald Hunt
@ -756,12 +773,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
else //Initial transformation. Don't allow second chances in special stages! else //Initial transformation. Don't allow second chances in special stages!
{ {
if (player->pflags & PF_NIGHTSMODE) if (player->powers[pw_carry] == CR_NIGHTSMODE)
return; return;
S_StartSound(toucher, sfx_supert); S_StartSound(toucher, sfx_supert);
} }
if (!(netgame || multiplayer) && !(player->pflags & PF_NIGHTSMODE)) if (!(netgame || multiplayer) && !(player->powers[pw_carry] == CR_NIGHTSMODE))
P_SetTarget(&special->tracer, toucher); P_SetTarget(&special->tracer, toucher);
P_NightserizePlayer(player, special->health); // Transform! P_NightserizePlayer(player, special->health); // Transform!
return; return;
@ -885,7 +902,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; return;
// make sure everything is as it should be, THEN take rings from players in special stages // make sure everything is as it should be, THEN take rings from players in special stages
if (player->pflags & PF_NIGHTSMODE && !toucher->target) if (player->powers[pw_carry] == CR_NIGHTSMODE && !toucher->target)
return; return;
if (player->mare != special->threshold) // wrong mare if (player->mare != special->threshold) // wrong mare
@ -923,7 +940,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (player->bumpertime < TICRATE/4) if (player->bumpertime < TICRATE/4)
{ {
S_StartSound(toucher, special->info->seesound); S_StartSound(toucher, special->info->seesound);
if (player->pflags & PF_NIGHTSMODE) if (player->powers[pw_carry] == CR_NIGHTSMODE)
{ {
player->bumpertime = TICRATE/2; player->bumpertime = TICRATE/2;
if (special->threshold > 0) if (special->threshold > 0)
@ -979,14 +996,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
return; return;
case MT_NIGHTSSUPERLOOP: case MT_NIGHTSSUPERLOOP:
if (player->bot || !(player->pflags & PF_NIGHTSMODE)) if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
player->powers[pw_nights_superloop] = (UINT16)special->info->speed; player->powers[pw_nights_superloop] = (UINT16)special->info->speed;
else else
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
players[i].powers[pw_nights_superloop] = (UINT16)special->info->speed; players[i].powers[pw_nights_superloop] = (UINT16)special->info->speed;
if (special->info->deathsound != sfx_None) if (special->info->deathsound != sfx_None)
S_StartSound(NULL, special->info->deathsound); S_StartSound(NULL, special->info->deathsound);
@ -1001,14 +1018,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSDRILLREFILL: case MT_NIGHTSDRILLREFILL:
if (player->bot || !(player->pflags & PF_NIGHTSMODE)) if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
player->drillmeter = special->info->speed; player->drillmeter = special->info->speed;
else else
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
players[i].drillmeter = special->info->speed; players[i].drillmeter = special->info->speed;
if (special->info->deathsound != sfx_None) if (special->info->deathsound != sfx_None)
S_StartSound(NULL, special->info->deathsound); S_StartSound(NULL, special->info->deathsound);
@ -1023,7 +1040,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSHELPER: case MT_NIGHTSHELPER:
if (player->bot || !(player->pflags & PF_NIGHTSMODE)) if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
{ {
@ -1037,7 +1054,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{ {
mobj_t *flickyobj; mobj_t *flickyobj;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && players[i].pflags & PF_NIGHTSMODE) { if (playeringame[i] && players[i].mo && players[i].powers[pw_carry] == CR_NIGHTSMODE) {
players[i].powers[pw_nights_helper] = (UINT16)special->info->speed; players[i].powers[pw_nights_helper] = (UINT16)special->info->speed;
flickyobj = P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z + players[i].mo->info->height, MT_NIGHTOPIANHELPER); flickyobj = P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z + players[i].mo->info->height, MT_NIGHTOPIANHELPER);
P_SetTarget(&flickyobj->target, players[i].mo); P_SetTarget(&flickyobj->target, players[i].mo);
@ -1055,7 +1072,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSEXTRATIME: case MT_NIGHTSEXTRATIME:
if (player->bot || !(player->pflags & PF_NIGHTSMODE)) if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
{ {
@ -1066,7 +1083,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
else else
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
{ {
players[i].nightstime += special->info->speed; players[i].nightstime += special->info->speed;
players[i].startedtime += special->info->speed; players[i].startedtime += special->info->speed;
@ -1085,7 +1102,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSLINKFREEZE: case MT_NIGHTSLINKFREEZE:
if (player->bot || !(player->pflags & PF_NIGHTSMODE)) if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
{ {
@ -1095,7 +1112,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
else else
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
{ {
players[i].powers[pw_nights_linkfreeze] += (UINT16)special->info->speed; players[i].powers[pw_nights_linkfreeze] += (UINT16)special->info->speed;
players[i].linktimer = 2*TICRATE; players[i].linktimer = 2*TICRATE;
@ -1153,7 +1170,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
players[i].drillmeter += TICRATE/2; players[i].drillmeter += TICRATE/2;
} }
else if (player->bot) else if (player->bot)
@ -1336,9 +1353,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
toucher->momz = -toucher->momz; toucher->momz = -toucher->momz;
if (player->pflags & PF_GLIDING) if (player->pflags & PF_GLIDING)
{ {
player->pflags &= ~(PF_GLIDING|PF_JUMPED); player->pflags &= ~(PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE);
P_SetPlayerMobjState(toucher, S_PLAY_FALL); P_SetPlayerMobjState(toucher, S_PLAY_FALL);
} }
player->homing = 0;
// Play a bounce sound? // Play a bounce sound?
S_StartSound(toucher, special->info->painsound); S_StartSound(toucher, special->info->painsound);
@ -1346,7 +1364,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; return;
case MT_BLACKEGGMAN_GOOPFIRE: case MT_BLACKEGGMAN_GOOPFIRE:
if (toucher->state != &states[S_PLAY_PAIN] && !player->powers[pw_flashing]) if (!player->powers[pw_flashing])
{ {
toucher->momx = 0; toucher->momx = 0;
toucher->momy = 0; toucher->momy = 0;
@ -1354,13 +1372,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (toucher->momz != 0) if (toucher->momz != 0)
special->momz = toucher->momz; special->momz = toucher->momz;
player->powers[pw_ingoop] = 2; player->powers[pw_carry] = CR_BRAKGOOP;
P_SetTarget(&toucher->tracer, special);
if (player->powers[pw_carry] == CR_GENERIC)
{
P_SetTarget(&toucher->tracer, NULL);
player->powers[pw_carry] = CR_NONE;
}
P_ResetPlayer(player); P_ResetPlayer(player);
@ -1372,8 +1385,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_SetMobjState(special->target, special->target->info->raisestate); P_SetMobjState(special->target, special->target->info->raisestate);
} }
} }
else
player->powers[pw_ingoop] = 0;
return; return;
case MT_EGGSHIELD: case MT_EGGSHIELD:
{ {
@ -1403,17 +1414,18 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
toucher->momz = -toucher->momz; toucher->momz = -toucher->momz;
if (player->pflags & PF_GLIDING) if (player->pflags & PF_GLIDING)
{ {
player->pflags &= ~(PF_GLIDING|PF_JUMPED); player->pflags &= ~(PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE);
P_SetPlayerMobjState(toucher, S_PLAY_FALL); P_SetPlayerMobjState(toucher, S_PLAY_FALL);
} }
player->homing = 0;
// Play a bounce sound? // Play a bounce sound?
S_StartSound(toucher, special->info->painsound); S_StartSound(toucher, special->info->painsound);
return; return;
} }
else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) else if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0)) || ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| (player->pflags & (PF_SPINNING|PF_GLIDING)) || (player->pflags & (PF_SPINNING|PF_GLIDING))
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
{ {
@ -1463,7 +1475,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{ {
player->powers[pw_carry] = CR_MACESPIN; player->powers[pw_carry] = CR_MACESPIN;
S_StartSound(toucher, sfx_spin); S_StartSound(toucher, sfx_spin);
P_SetPlayerMobjState(toucher, S_PLAY_SPIN); P_SetPlayerMobjState(toucher, S_PLAY_ROLL);
} }
else else
player->powers[pw_carry] = CR_GENERIC; player->powers[pw_carry] = CR_GENERIC;
@ -2093,7 +2105,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{ {
if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording! if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording!
G_StopMetalRecording(); G_StopMetalRecording();
if (gametype == GT_MATCH && cv_match_scoring.value == 0 // note, no team match suicide penalty if (gametype == GT_MATCH // note, no team match suicide penalty
&& ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player))) && ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player)))
{ // Suicide penalty { // Suicide penalty
if (target->player->score >= 50) if (target->player->score >= 50)
@ -2597,7 +2609,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
} }
player->powers[pw_flashing] = flashingtics; player->powers[pw_flashing] = flashingtics;
P_SetPlayerMobjState(target, S_PLAY_NIGHTS_PAIN); P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN);
S_StartSound(target, sfx_nghurt); S_StartSound(target, sfx_nghurt);
if (oldnightstime > 10*TICRATE if (oldnightstime > 10*TICRATE
@ -2724,7 +2736,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
{ {
player->pflags &= ~(PF_SLIDING|PF_NIGHTSMODE); player->pflags &= ~PF_SLIDING;
player->powers[pw_carry] = CR_NONE; player->powers[pw_carry] = CR_NONE;
@ -2820,10 +2832,7 @@ static inline void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *so
P_InstaThrust(player->mo, ang, fallbackspeed); P_InstaThrust(player->mo, ang, fallbackspeed);
if (player->charflags & SF_SUPERANIMS) P_SetPlayerMobjState(player->mo, S_PLAY_STUN);
P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_STUN);
else
P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
P_ResetPlayer(player); P_ResetPlayer(player);
@ -2886,7 +2895,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source,
{ {
// Award no points when players shoot each other when cv_friendlyfire is on. // Award no points when players shoot each other when cv_friendlyfire is on.
if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo))
P_AddPlayerScore(source->player, cv_match_scoring.value == 1 ? 25 : 50); P_AddPlayerScore(source->player, 50);
} }
} }
@ -3069,7 +3078,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (player->pflags & PF_GODMODE) if (player->pflags & PF_GODMODE)
return false; return false;
if (!(target->player->pflags & (PF_NIGHTSMODE|PF_NIGHTSFALL)) && (maptol & TOL_NIGHTS)) if (!(target->player->powers[pw_carry] == CR_NIGHTSMODE || target->player->pflags & PF_NIGHTSFALL) && (maptol & TOL_NIGHTS))
return false; return false;
switch (damagetype) switch (damagetype)
@ -3091,7 +3100,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
} }
} }
if (player->pflags & PF_NIGHTSMODE) // NiGHTS damage handling if (player->powers[pw_carry] == CR_NIGHTSMODE) // NiGHTS damage handling
{ {
if (!force) if (!force)
{ {
@ -3119,14 +3128,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false; // Don't get hurt by fire generated from friends. return false; // Don't get hurt by fire generated from friends.
} }
// Sudden-Death mode
if (source && source->type == MT_PLAYER)
{
if ((gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF) && cv_suddendeath.value
&& !player->powers[pw_flashing] && !player->powers[pw_invulnerability])
damagetype = DMG_INSTAKILL;
}
// Player hits another player // Player hits another player
if (!force && source && source->player) if (!force && source && source->player)
{ {

View file

@ -72,7 +72,6 @@
// both the head and tail of the thinker list // both the head and tail of the thinker list
extern thinker_t thinkercap; extern thinker_t thinkercap;
extern INT32 runcount;
void P_InitThinkers(void); void P_InitThinkers(void);
void P_AddThinker(thinker_t *thinker); void P_AddThinker(thinker_t *thinker);
@ -130,6 +129,7 @@ void P_ResetCamera(player_t *player, camera_t *thiscam);
boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam);
void P_SlideCameraMove(camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam);
boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled); boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled);
pflags_t P_GetJumpFlags(player_t *player);
boolean P_PlayerInPain(player_t *player); boolean P_PlayerInPain(player_t *player);
void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor); void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor);
void P_ResetPlayer(player_t *player); void P_ResetPlayer(player_t *player);
@ -150,11 +150,16 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings);
void P_GivePlayerLives(player_t *player, INT32 numlives); void P_GivePlayerLives(player_t *player, INT32 numlives);
UINT8 P_GetNextEmerald(void); UINT8 P_GetNextEmerald(void);
void P_GiveEmerald(boolean spawnObj); void P_GiveEmerald(boolean spawnObj);
#if 0
void P_ResetScore(player_t *player); void P_ResetScore(player_t *player);
#else
#define P_ResetScore(player) player->scoreadd = 0
#endif
boolean P_AutoPause(void); boolean P_AutoPause(void);
void P_DoJumpShield(player_t *player); void P_DoJumpShield(player_t *player);
void P_DoBubbleBounce(player_t *player); void P_DoBubbleBounce(player_t *player);
void P_DoAbilityBounce(player_t *player, boolean changemomz);
void P_BlackOw(player_t *player); void P_BlackOw(player_t *player);
void P_ElementalFire(player_t *player, boolean cropcircle); void P_ElementalFire(player_t *player, boolean cropcircle);
@ -169,12 +174,16 @@ fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move);
fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move); fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move);
void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move); void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
boolean P_LookForEnemies(player_t *player, boolean nonenemies); mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet);
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius); void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_SuperReady(player_t *player); boolean P_SuperReady(player_t *player);
void P_DoJump(player_t *player, boolean soundandstate); void P_DoJump(player_t *player, boolean soundandstate);
#if 0
boolean P_AnalogMove(player_t *player); boolean P_AnalogMove(player_t *player);
#else
#define P_AnalogMove(player) (player->pflags & PF_ANALOGMODE)
#endif
boolean P_TransferToNextMare(player_t *player); boolean P_TransferToNextMare(player_t *player);
UINT8 P_FindLowestMare(void); UINT8 P_FindLowestMare(void);
void P_FindEmerald(void); void P_FindEmerald(void);

View file

@ -115,7 +115,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
fixed_t offx, offy; fixed_t offx, offy;
fixed_t vertispeed = spring->info->mass; fixed_t vertispeed = spring->info->mass;
fixed_t horizspeed = spring->info->damage; fixed_t horizspeed = spring->info->damage;
UINT8 jumping, secondjump; UINT8 secondjump;
if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic
return false; return false;
@ -124,20 +124,25 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (object->player && object->player->spectator) if (object->player && object->player->spectator)
return false; return false;
if (object->player && (object->player->pflags & PF_NIGHTSMODE)) if (object->player && (object->player->powers[pw_carry] == CR_NIGHTSMODE))
{ {
/*Someone want to make these work like bumpers?*/ /*Someone want to make these work like bumpers?*/
return false; return false;
} }
#ifdef ESLOPE if (object->player
object->standingslope = NULL; // Okay, now we can't return - no launching off at silly angles for you. && ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY)
#endif || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2)))
{
S_StartSound(object, sfx_s3k8b);
horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3);
vertispeed = FixedMul(vertispeed, (6*FRACUNIT)/5); // aprox square root of above
}
object->eflags |= MFE_SPRUNG; // apply this flag asap! object->eflags |= MFE_SPRUNG; // apply this flag asap!
spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
if (horizspeed && vertispeed) // Mimic SA if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA
{ {
object->momx = object->momy = 0; object->momx = object->momy = 0;
P_TryMove(object, spring->x, spring->y, true); P_TryMove(object, spring->x, spring->y, true);
@ -203,32 +208,36 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
} }
} }
pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY); // I still need these. pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY|PF_BOUNCING); // I still need these.
jumping = object->player->jumping;
secondjump = object->player->secondjump; secondjump = object->player->secondjump;
P_ResetPlayer(object->player); P_ResetPlayer(object->player);
if (spring->info->painchance) if (spring->info->painchance)
{ {
object->player->pflags |= PF_JUMPED; object->player->pflags |= P_GetJumpFlags(object->player);
P_SetPlayerMobjState(object, S_PLAY_JUMP); P_SetPlayerMobjState(object, S_PLAY_JUMP);
} }
else if (P_MobjFlip(object)*vertispeed > 0) else if (!vertispeed || (pflags & PF_BOUNCING)) // horizontal spring or bouncing
P_SetPlayerMobjState(object, S_PLAY_SPRING);
else if (P_MobjFlip(object)*vertispeed < 0)
P_SetPlayerMobjState(object, S_PLAY_FALL);
else // horizontal spring
{ {
if (pflags & (PF_JUMPED|PF_SPINNING) && (object->player->panim == PA_ROLL || object->player->panim == PA_JUMP || object->player->panim == PA_FALL)) if ((pflags & PF_BOUNCING)
|| (pflags & (PF_JUMPED|PF_SPINNING) && (object->player->panim == PA_ROLL || object->player->panim == PA_JUMP || object->player->panim == PA_FALL)))
{ {
object->player->pflags |= pflags; object->player->pflags |= pflags;
object->player->jumping = jumping;
object->player->secondjump = secondjump; object->player->secondjump = secondjump;
} }
else else
P_SetPlayerMobjState(object, S_PLAY_WALK); P_SetPlayerMobjState(object, S_PLAY_WALK);
} }
else if (P_MobjFlip(object)*vertispeed > 0)
P_SetPlayerMobjState(object, S_PLAY_SPRING);
else
P_SetPlayerMobjState(object, S_PLAY_FALL);
} }
#ifdef ESLOPE
object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you.
#endif
return true; return true;
} }
@ -324,9 +333,6 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
if (tails->bot == 1) if (tails->bot == 1)
return; return;
if (sonic->pflags & PF_NIGHTSMODE)
return;
if ((sonic->mo->eflags & MFE_VERTICALFLIP) != (tails->mo->eflags & MFE_VERTICALFLIP)) if ((sonic->mo->eflags & MFE_VERTICALFLIP) != (tails->mo->eflags & MFE_VERTICALFLIP))
return; // Both should be in same gravity return; // Both should be in same gravity
@ -377,6 +383,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
else { else {
if (sonic-players == consoleplayer && botingame) if (sonic-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, true); CV_SetValue(&cv_analog2, true);
P_SetTarget(&sonic->mo->tracer, NULL);
sonic->powers[pw_carry] = CR_NONE; sonic->powers[pw_carry] = CR_NONE;
} }
} }
@ -460,9 +467,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
// CA_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes. // SF_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes.
if ((tmthing->player) if ((tmthing->player)
&& (((tmthing->player->charability == CA_DASHMODE) && (tmthing->player->dashmode >= 3*TICRATE) && (((tmthing->player->charflags & SF_DASHMODE) && (tmthing->player->dashmode >= 3*TICRATE)
&& (thing->flags & (MF_MONITOR) || thing->type == MT_SPIKE)) && (thing->flags & (MF_MONITOR) || thing->type == MT_SPIKE))
|| ((((tmthing->player->charability == CA_TWINSPIN) && (tmthing->player->panim == PA_ABILITY)) || ((((tmthing->player->charability == CA_TWINSPIN) && (tmthing->player->panim == PA_ABILITY))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)) || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2))
@ -499,7 +506,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
// Don't collide with your buddies while NiGHTS-flying. // Don't collide with your buddies while NiGHTS-flying.
if (tmthing->player && thing->player && (maptol & TOL_NIGHTS) if (tmthing->player && thing->player && (maptol & TOL_NIGHTS)
&& ((tmthing->player->pflags & PF_NIGHTSMODE) || (thing->player->pflags & PF_NIGHTSMODE))) && ((tmthing->player->powers[pw_carry] == CR_NIGHTSMODE) || (thing->player->powers[pw_carry] == CR_NIGHTSMODE)))
return true; return true;
blockdist = thing->radius + tmthing->radius; blockdist = thing->radius + tmthing->radius;
@ -785,7 +792,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
{ {
// Hop on the missile for a ride! // Hop on the missile for a ride!
thing->player->powers[pw_carry] = CR_GENERIC; thing->player->powers[pw_carry] = CR_GENERIC;
thing->player->pflags &= ~PF_JUMPED; thing->player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE);
P_SetTarget(&thing->tracer, tmthing); P_SetTarget(&thing->tracer, tmthing);
P_SetTarget(&tmthing->target, thing); // Set owner to the player P_SetTarget(&tmthing->target, thing); // Set owner to the player
P_SetTarget(&tmthing->tracer, NULL); // Disable homing-ness P_SetTarget(&tmthing->tracer, NULL); // Disable homing-ness
@ -896,7 +903,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
// must be flying in the SAME DIRECTION as the last time you came through. // must be flying in the SAME DIRECTION as the last time you came through.
// not (your direction) xor (stored direction) // not (your direction) xor (stored direction)
// In other words, you can't u-turn and respawn rings near the drone. // In other words, you can't u-turn and respawn rings near the drone.
if (pl->bonustime && (pl->pflags & PF_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && ( if (pl->bonustime && (pl->powers[pw_carry] == CR_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && (
!(pl->anotherflyangle >= 90 && pl->anotherflyangle <= 270) !(pl->anotherflyangle >= 90 && pl->anotherflyangle <= 270)
^ (droneobj->extravalue1 >= 90 && droneobj->extravalue1 <= 270) ^ (droneobj->extravalue1 >= 90 && droneobj->extravalue1 <= 270)
)) ))
@ -928,11 +935,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->eflags & MFE_VERTICALFLIP) if (tmthing->eflags & MFE_VERTICALFLIP)
{ {
if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale)
&& thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz
&& !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && thing->eflags & MFE_VERTICALFLIP))
P_DamageMobj(thing, tmthing, tmthing, 1, 0); P_DamageMobj(thing, tmthing, tmthing, 1, 0);
} }
else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale)
&& thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz
&& !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && !(thing->eflags & MFE_VERTICALFLIP)))
P_DamageMobj(thing, tmthing, tmthing, 1, 0); P_DamageMobj(thing, tmthing, tmthing, 1, 0);
} }
else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?! else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?!
@ -940,14 +949,55 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->eflags & MFE_VERTICALFLIP) if (thing->eflags & MFE_VERTICALFLIP)
{ {
if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale)
&& tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale)) && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale)
&& !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && tmthing->eflags & MFE_VERTICALFLIP))
P_DamageMobj(tmthing, thing, thing, 1, 0); P_DamageMobj(tmthing, thing, thing, 1, 0);
} }
else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)
&& tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)
&& !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && !(tmthing->eflags & MFE_VERTICALFLIP)))
P_DamageMobj(tmthing, thing, thing, 1, 0); P_DamageMobj(tmthing, thing, thing, 1, 0);
} }
if (tmthing->type == MT_WALLSPIKE && tmthing->flags & MF_SOLID && thing->player) // wall spike impales player
{
fixed_t bottomz, topz;
bottomz = tmthing->z;
topz = tmthing->z + tmthing->height;
if (tmthing->eflags & MFE_VERTICALFLIP)
bottomz -= FixedMul(FRACUNIT, tmthing->scale);
else
topz += FixedMul(FRACUNIT, tmthing->scale);
if (thing->z + thing->height > bottomz // above bottom
&& thing->z < topz) // below top
{ // don't check angle, the player was clearly in the way in this case
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE);
}
}
else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tmthing->player)
{
fixed_t bottomz, topz;
bottomz = thing->z;
topz = thing->z + thing->height;
if (thing->eflags & MFE_VERTICALFLIP)
bottomz -= FixedMul(FRACUNIT, thing->scale);
else
topz += FixedMul(FRACUNIT, thing->scale);
if (tmthing->z + tmthing->height > bottomz // above bottom
&& tmthing->z < topz // below top
&& !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer
{ // use base as a reference point to determine what angle you touched the spike at
angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y);
angle_t diffangle = thing->angle - touchangle;
if (diffangle > ANGLE_180)
diffangle = InvAngle(diffangle);
if (diffangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked!
P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE);
}
}
if (thing->flags & MF_PUSHABLE) if (thing->flags & MF_PUSHABLE)
{ {
if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM) if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM)
@ -1005,7 +1055,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->player-players == consoleplayer && botingame) if (thing->player-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, true); CV_SetValue(&cv_analog2, true);
if (thing->player->powers[pw_carry] == CR_PLAYER) if (thing->player->powers[pw_carry] == CR_PLAYER)
{
P_SetTarget(&thing->tracer, NULL);
thing->player->powers[pw_carry] = CR_NONE; thing->player->powers[pw_carry] = CR_NONE;
}
} }
if (thing->player) if (thing->player)
@ -1063,11 +1116,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->flags & MF_MONITOR if (thing->flags & MF_MONITOR
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) && (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED) || ((tmthing->player->pflags & PF_JUMPED)
&& (tmthing->player->pflags & PF_FORCEJUMPDAMAGE && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| !(tmthing->player->charflags & SF_NOJUMPSPIN)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE) || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|| elementalpierce)) || elementalpierce))
{ {
@ -1084,11 +1136,15 @@ static boolean PIT_CheckThing(mobj_t *thing)
{ {
if (elementalpierce == 2) if (elementalpierce == 2)
P_DoBubbleBounce(player); P_DoBubbleBounce(player);
else else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
} }
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
{
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
return false; return false;
}
else else
*z -= *momz; // to ensure proper collision. *z -= *momz; // to ensure proper collision.
} }
@ -1100,16 +1156,17 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now... if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now...
return false; // "cancel" P_TryMove via blocking so you keep your current position return false; // "cancel" P_TryMove via blocking so you keep your current position
} }
else if (tmthing->flags & MF_SPRING && (thing->player || thing->flags & MF_PUSHABLE))
; // Fix a few nasty spring-jumping bugs that happen sometimes.
// Monitors are not treated as solid to players who are jumping, spinning or gliding, // Monitors are not treated as solid to players who are jumping, spinning or gliding,
// unless it's a CTF team monitor and you're on the wrong team // unless it's a CTF team monitor and you're on the wrong team
else if (thing->flags & MF_MONITOR && tmthing->player else if (thing->flags & MF_MONITOR && tmthing->player
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) && (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED) || ((tmthing->player->pflags & PF_JUMPED)
&& (tmthing->player->pflags & PF_FORCEJUMPDAMAGE && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| !(tmthing->player->charflags & SF_NOJUMPSPIN)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE) || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))) && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)))
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))) && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2)))
; ;
@ -1139,11 +1196,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
if (thing->flags & MF_SPRING)
;
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// since return false doesn't handle momentum properly, // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high // we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z + tmthing->height > topz else if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz) && tmthing->z + tmthing->height < tmthing->ceilingz)
{ {
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
@ -1155,8 +1214,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
#endif #endif
tmfloorthing = thing; // needed for side collision tmfloorthing = thing; // needed for side collision
} }
else if (thing->flags & MF_SPRING)
;
else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height) else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
{ {
tmceilingz = topz; tmceilingz = topz;
@ -1185,11 +1242,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
if (thing->flags & MF_SPRING)
;
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// since return false doesn't handle momentum properly, // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high // we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z < topz else if (tmthing->player && tmthing->z < topz
&& tmthing->z > tmthing->floorz) && tmthing->z > tmthing->floorz)
{ {
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
@ -1201,8 +1260,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
#endif #endif
tmfloorthing = thing; // needed for side collision tmfloorthing = thing; // needed for side collision
} }
else if (thing->flags & MF_SPRING)
;
else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z) else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
{ {
tmfloorz = topz; tmfloorz = topz;
@ -1512,7 +1569,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE))
; ;
else if (!((rover->flags & FF_BLOCKPLAYER && thing->player) else if (!((rover->flags & FF_BLOCKPLAYER && thing->player)
|| (rover->flags & FF_BLOCKOTHERS && !thing->player) || (rover->flags & FF_BLOCKOTHERS && !thing->player)
|| rover->flags & FF_QUICKSAND)) || rover->flags & FF_QUICKSAND))
continue; continue;
@ -2890,7 +2947,7 @@ isblocking:
slidemo->player->climbing = 5; slidemo->player->climbing = 5;
} }
slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_THOKKED); slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED);
slidemo->player->glidetime = 0; slidemo->player->glidetime = 0;
slidemo->player->secondjump = 0; slidemo->player->secondjump = 0;

View file

@ -187,32 +187,41 @@ static void P_CyclePlayerMobjState(mobj_t *mobj)
// //
// P_GetMobjSprite2 // P_GetMobjSprite2
// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
// //
UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2) UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2)
{ {
player_t *player = mobj->player; player_t *player = mobj->player;
skin_t *skin = ((skin_t *)mobj->skin); skin_t *skin = ((skin_t *)mobj->skin);
UINT8 super = (spr2 & FF_SPR2SUPER);
if (!skin) if (!skin)
return 0; return 0;
while ((skin->sprites[spr2].numframes <= 0) while (!(skin->sprites[spr2].numframes)
&& spr2 != SPR2_STND) && spr2 != SPR2_STND)
{ {
if (spr2 & FF_SPR2SUPER)
{
spr2 &= ~FF_SPR2SUPER;
continue;
}
switch(spr2) switch(spr2)
{ {
case SPR2_PEEL:
spr2 = SPR2_RUN;
break;
case SPR2_RUN: case SPR2_RUN:
spr2 = SPR2_WALK; spr2 = SPR2_WALK;
break; break;
case SPR2_STUN:
spr2 = SPR2_PAIN;
break;
case SPR2_DRWN: case SPR2_DRWN:
spr2 = SPR2_DEAD; spr2 = SPR2_DEAD;
break; break;
case SPR2_DASH: case SPR2_SPIN:
spr2 = SPR2_SPIN; spr2 = SPR2_ROLL;
break; break;
case SPR2_GASP: case SPR2_GASP:
spr2 = SPR2_SPNG; spr2 = SPR2_SPNG;
@ -221,7 +230,7 @@ UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2)
spr2 = ((player spr2 = ((player
? player->charflags ? player->charflags
: skin->flags) : skin->flags)
& SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_SPIN; & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL;
break; break;
case SPR2_SPNG: // spring case SPR2_SPNG: // spring
spr2 = SPR2_FALL; spr2 = SPR2_FALL;
@ -233,11 +242,11 @@ UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2)
spr2 = SPR2_FALL; spr2 = SPR2_FALL;
break; break;
case SPR2_FLY: case SPR2_FLY :
spr2 = SPR2_SPNG; spr2 = SPR2_SPNG;
break; break;
case SPR2_SWIM: case SPR2_SWIM:
spr2 = SPR2_FLY; spr2 = SPR2_FLY ;
break; break;
case SPR2_TIRE: case SPR2_TIRE:
spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
@ -247,91 +256,59 @@ UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2)
spr2 = SPR2_FLY; spr2 = SPR2_FLY;
break; break;
case SPR2_CLMB: case SPR2_CLMB:
spr2 = SPR2_SPIN; spr2 = SPR2_ROLL;
break; break;
case SPR2_CLNG: case SPR2_CLNG:
spr2 = SPR2_CLMB; spr2 = SPR2_CLMB;
break; break;
case SPR2_FLT :
spr2 = SPR2_WALK;
break;
case SPR2_FRUN:
spr2 = SPR2_RUN ;
break;
case SPR2_DASH:
spr2 = SPR2_FRUN;
break;
case SPR2_BNCE:
spr2 = SPR2_FALL;
break;
case SPR2_BLND:
spr2 = SPR2_ROLL;
break;
case SPR2_TWIN: case SPR2_TWIN:
spr2 = SPR2_SPIN; spr2 = SPR2_ROLL;
break; break;
case SPR2_MLEE: case SPR2_MLEE:
spr2 = SPR2_TWIN; spr2 = SPR2_TWIN;
break; break;
// Super sprites fallback to regular sprites
case SPR2_SWLK:
spr2 = SPR2_WALK;
break;
case SPR2_SRUN:
spr2 = SPR2_RUN;
break;
case SPR2_SPEE:
spr2 = SPR2_PEEL;
break;
case SPR2_SPAN:
spr2 = SPR2_PAIN;
break;
case SPR2_SSTN:
spr2 = SPR2_SPAN;
break;
case SPR2_SDTH:
spr2 = SPR2_DEAD;
break;
case SPR2_SDRN:
spr2 = SPR2_DRWN;
break;
case SPR2_SSPN:
spr2 = SPR2_SPIN;
break;
case SPR2_SGSP:
spr2 = SPR2_GASP;
break;
case SPR2_SJMP:
spr2 = ((player
? player->charflags
: skin->flags)
& SF_NOJUMPSPIN) ? SPR2_SSPG : SPR2_SSPN;
break;
case SPR2_SSPG:
spr2 = SPR2_SPNG;
break;
case SPR2_SFAL:
spr2 = SPR2_FALL;
break;
case SPR2_SEDG:
spr2 = SPR2_EDGE;
break;
case SPR2_SRID:
spr2 = SPR2_RIDE;
break;
case SPR2_SFLT:
spr2 = SPR2_SWLK;
break;
// NiGHTS sprites. // NiGHTS sprites.
case SPR2_NTRN:
spr2 = SPR2_TRNS;
break;
case SPR2_NSTD: case SPR2_NSTD:
spr2 = SPR2_SSTD; spr2 = SPR2_STND;
super = FF_SPR2SUPER;
break; break;
case SPR2_NFLT: case SPR2_NFLT:
spr2 = (skin->flags & SF_SUPERANIMS) ? SPR2_SFLT : SPR2_FALL; // This is skin-exclusive so the default NiGHTS skin changing system plays nice. spr2 = SPR2_FLT ;
super = FF_SPR2SUPER;
break;
case SPR2_NSTN:
spr2 = SPR2_STUN;
break; break;
case SPR2_NPUL: case SPR2_NPUL:
spr2 = SPR2_NFLT; spr2 = SPR2_NSTN;
break;
case SPR2_NPAN:
spr2 = SPR2_NPUL;
break; break;
case SPR2_NATK: case SPR2_NATK:
spr2 = SPR2_SSPN; spr2 = SPR2_ROLL;
super = FF_SPR2SUPER;
break; break;
/*case SPR2_NGT0: /*case SPR2_NGT0:
spr2 = SPR2_STND; spr2 = SPR2_NFLT;
break;*/ break;*/
case SPR2_NGT1: case SPR2_NGT1:
case SPR2_NGT7: case SPR2_NGT7:
@ -390,7 +367,10 @@ UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2)
spr2 = SPR2_STND; spr2 = SPR2_STND;
break; break;
} }
spr2 |= super;
} }
return spr2; return spr2;
} }
@ -427,45 +407,17 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
else if (state == S_PLAY_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) else if (state == S_PLAY_SWIM && !(player->mo->eflags & MFE_UNDERWATER))
return P_SetPlayerMobjState(player->mo, S_PLAY_FLY); return P_SetPlayerMobjState(player->mo, S_PLAY_FLY);
// Catch state changes for Super Sonic // Catch SF_NOSUPERSPIN jumps for Supers
if (player->powers[pw_super] && (player->charflags & SF_SUPERANIMS)) if (player->powers[pw_super] && (player->charflags & SF_NOSUPERSPIN))
{ {
switch (state) if (state == S_PLAY_JUMP)
{ {
case S_PLAY_STND: if (player->mo->state-states == S_PLAY_WALK)
case S_PLAY_WAIT: return P_SetPlayerMobjState(mobj, S_PLAY_FLOAT);
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_STND); return true;
case S_PLAY_WALK:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_WALK);
case S_PLAY_RUN:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_RUN);
case S_PLAY_PEEL:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_PEEL);
case S_PLAY_PAIN:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_PAIN);
case S_PLAY_DEAD:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_DEAD);
case S_PLAY_DRWN:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_DRWN);
case S_PLAY_SPIN:
if (!(player->charflags & SF_SUPERSPIN))
return true;
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_SPIN);
case S_PLAY_GASP:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_GASP);
case S_PLAY_JUMP:
if (!(player->charflags & SF_SUPERSPIN))
return true;
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_JUMP);
case S_PLAY_SPRING:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_SPRING);
case S_PLAY_FALL:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_FALL);
case S_PLAY_EDGE:
return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_EDGE);
default:
break;
} }
else if (player->mo->state-states == S_PLAY_FLOAT && state == S_PLAY_STND)
return true;
} }
// You were in pain state after taking a hit, and you're moving out of pain state now? // You were in pain state after taking a hit, and you're moving out of pain state now?
else if (mobj->state == &states[mobj->info->painstate] && player->powers[pw_flashing] == flashingtics && state != mobj->info->painstate) else if (mobj->state == &states[mobj->info->painstate] && player->powers[pw_flashing] == flashingtics && state != mobj->info->painstate)
@ -481,61 +433,56 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
{ {
case S_PLAY_STND: case S_PLAY_STND:
case S_PLAY_WAIT: case S_PLAY_WAIT:
case S_PLAY_SUPER_STND:
player->panim = PA_IDLE; player->panim = PA_IDLE;
break; break;
case S_PLAY_EDGE: case S_PLAY_EDGE:
case S_PLAY_SUPER_EDGE:
player->panim = PA_EDGE; player->panim = PA_EDGE;
break; break;
case S_PLAY_WALK: case S_PLAY_WALK:
case S_PLAY_SUPER_WALK: case S_PLAY_FLOAT:
case S_PLAY_SUPER_FLOAT:
player->panim = PA_WALK; player->panim = PA_WALK;
break; break;
case S_PLAY_RUN: case S_PLAY_RUN:
case S_PLAY_SUPER_RUN: case S_PLAY_FLOAT_RUN:
player->panim = PA_RUN; player->panim = PA_RUN;
break; break;
case S_PLAY_PEEL: case S_PLAY_DASH:
case S_PLAY_SUPER_PEEL: player->panim = PA_DASH;
player->panim = PA_PEEL;
break; break;
case S_PLAY_PAIN: case S_PLAY_PAIN:
case S_PLAY_SUPER_PAIN: case S_PLAY_STUN:
case S_PLAY_SUPER_STUN:
player->panim = PA_PAIN; player->panim = PA_PAIN;
break; break;
case S_PLAY_SPIN: case S_PLAY_ROLL:
//case S_PLAY_DASH: -- everyone can ROLL thanks to zoom tubes... //case S_PLAY_SPINDASH: -- everyone can ROLL thanks to zoom tubes...
case S_PLAY_SUPER_SPIN:
player->panim = PA_ROLL; player->panim = PA_ROLL;
break; break;
case S_PLAY_JUMP: case S_PLAY_JUMP:
case S_PLAY_SUPER_JUMP:
player->panim = PA_JUMP; player->panim = PA_JUMP;
break; break;
case S_PLAY_SPRING: case S_PLAY_SPRING:
case S_PLAY_SUPER_SPRING:
player->panim = PA_SPRING; player->panim = PA_SPRING;
break; break;
case S_PLAY_FALL: case S_PLAY_FALL:
case S_PLAY_SUPER_FALL:
player->panim = PA_FALL; player->panim = PA_FALL;
break; break;
case S_PLAY_FLY: case S_PLAY_FLY:
case S_PLAY_SWIM: case S_PLAY_SWIM:
case S_PLAY_GLIDE: case S_PLAY_GLIDE:
case S_PLAY_BOUNCE:
case S_PLAY_BOUNCE_LANDING:
case S_PLAY_TWINSPIN: case S_PLAY_TWINSPIN:
player->panim = PA_ABILITY; player->panim = PA_ABILITY;
break; break;
case S_PLAY_DASH: // ...but the act of SPINDASHING is charability2 specific. case S_PLAY_SPINDASH: // ...but the act of SPINDASHING is charability2 specific.
case S_PLAY_FIRE:
case S_PLAY_FIRE_FINISH:
case S_PLAY_MELEE: case S_PLAY_MELEE:
case S_PLAY_MELEE_FINISH: case S_PLAY_MELEE_FINISH:
case S_PLAY_MELEE_LANDING:
player->panim = PA_ABILITY2; player->panim = PA_ABILITY2;
break; break;
case S_PLAY_RIDE: case S_PLAY_RIDE:
case S_PLAY_SUPER_RIDE:
player->panim = PA_RIDE; player->panim = PA_RIDE;
break; break;
default: default:
@ -562,7 +509,9 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
mobj->tics = st->tics; mobj->tics = st->tics;
// Adjust the player's animation speed to match their velocity. // Adjust the player's animation speed to match their velocity.
if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST)) if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE))
mobj->tics = 2;
else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST))
{ {
fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor)); fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor));
if (player->panim == PA_FALL) if (player->panim == PA_FALL)
@ -598,7 +547,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
else else
mobj->tics = 2; mobj->tics = 2;
} }
else if (P_IsObjectOnGround(mobj) || player->powers[pw_super]) // Only if on the ground or superflying. else if (P_IsObjectOnGround(mobj) || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]) // Only if on the ground or superflying.
{ {
if (player->panim == PA_WALK) if (player->panim == PA_WALK)
{ {
@ -609,7 +558,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
else else
mobj->tics = 4; mobj->tics = 4;
} }
else if ((player->panim == PA_RUN) || (player->panim == PA_PEEL)) else if ((player->panim == PA_RUN) || (player->panim == PA_DASH))
{ {
if (speed > 52<<FRACBITS) if (speed > 52<<FRACBITS)
mobj->tics = 1; mobj->tics = 1;
@ -627,7 +576,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1; UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
UINT8 numframes; UINT8 numframes;
UINT8 spr2 = P_GetMobjSprite2(mobj, st->frame & FF_FRAMEMASK); UINT8 spr2 = P_GetMobjSprite2(mobj, (((player->powers[pw_super]) ? FF_SPR2SUPER : 0)|st->frame) & FF_FRAMEMASK);
if (skin) if (skin)
numframes = skin->sprites[spr2].numframes; numframes = skin->sprites[spr2].numframes;
@ -1646,11 +1595,8 @@ static void P_PlayerFlip(mobj_t *mo)
G_GhostAddFlip(); G_GhostAddFlip();
// Flip aiming to match! // Flip aiming to match!
if (mo->player->pflags & PF_NIGHTSMODE) // NiGHTS doesn't use flipcam if (mo->player->powers[pw_carry] == CR_NIGHTSMODE) // NiGHTS doesn't use flipcam
{ ;
if (mo->tracer)
mo->tracer->eflags ^= MFE_VERTICALFLIP;
}
else if (mo->player->pflags & PF_FLIPCAM) else if (mo->player->pflags & PF_FLIPCAM)
{ {
mo->player->aiming = InvAngle(mo->player->aiming); mo->player->aiming = InvAngle(mo->player->aiming);
@ -1746,7 +1692,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|| (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly] || (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
|| mo->state-states == S_PLAY_FLY_TIRED))) || mo->state-states == S_PLAY_FLY_TIRED)))
gravityadd = gravityadd/3; // less gravity while flying/gliding gravityadd = gravityadd/3; // less gravity while flying/gliding
if (mo->player->climbing || (mo->player->pflags & PF_NIGHTSMODE)) if (mo->player->climbing || (mo->player->powers[pw_carry] == CR_NIGHTSMODE))
gravityadd = 0; gravityadd = 0;
if (!(mo->flags2 & MF2_OBJECTFLIP) != !(mo->player->powers[pw_gravityboots])) // negated to turn numeric into bool - would be double negated, but not needed if both would be if (!(mo->flags2 & MF2_OBJECTFLIP) != !(mo->player->powers[pw_gravityboots])) // negated to turn numeric into bool - would be double negated, but not needed if both would be
@ -1898,9 +1844,12 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
// spinning friction // spinning friction
if (player->pflags & PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH)) if (player->pflags & PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH))
{ {
const fixed_t ns = FixedDiv(549*ORIG_FRICTION,500*FRACUNIT); if (twodlevel || player->mo->flags2 & MF2_TWOD) // Otherwise handled in P_3DMovement
mo->momx = FixedMul(mo->momx, ns); {
mo->momy = FixedMul(mo->momy, ns); const fixed_t ns = FixedDiv(549*ORIG_FRICTION,500*FRACUNIT);
mo->momx = FixedMul(mo->momx, ns);
mo->momy = FixedMul(mo->momy, ns);
}
} }
else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale) else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale)
&& abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale) && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale)
@ -2326,7 +2275,7 @@ void P_XYMovement(mobj_t *mo)
// Check the gravity status. // Check the gravity status.
P_CheckGravity(mo, false); P_CheckGravity(mo, false);
if (player && !moved && player->pflags & PF_NIGHTSMODE && mo->target) if (player && !moved && player->powers[pw_carry] == CR_NIGHTSMODE && mo->target)
{ {
angle_t fa; angle_t fa;
@ -2369,7 +2318,7 @@ void P_XYMovement(mobj_t *mo)
if (player && player->homing) // no friction for homing if (player && player->homing) // no friction for homing
return; return;
if (player && player->pflags & PF_NIGHTSMODE) if (player && player->powers[pw_carry] == CR_NIGHTSMODE)
return; // no friction for NiGHTS players return; // no friction for NiGHTS players
#ifdef ESLOPE #ifdef ESLOPE
@ -2592,6 +2541,9 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
I_Assert(mo != NULL); I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo)); I_Assert(!P_MobjWasRemoved(mo));
if (mo->player && mo->player->pflags & PF_GODMODE)
return false;
if (((mo->z <= mo->subsector->sector->floorheight if (((mo->z <= mo->subsector->sector->floorheight
&& !(mo->eflags & MFE_VERTICALFLIP) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR)) && !(mo->eflags & MFE_VERTICALFLIP) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR))
|| (mo->z + mo->height >= mo->subsector->sector->ceilingheight || (mo->z + mo->height >= mo->subsector->sector->ceilingheight
@ -2608,10 +2560,18 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover)
I_Assert(mo != NULL); I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo)); I_Assert(!P_MobjWasRemoved(mo));
if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 {
&& !(rover->master->flags & ML_BLOCKMONSTERS) fixed_t topheight =
&& ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > *rover->topheight - FixedMul(16*FRACUNIT, mo->scale))) #ifdef ESLOPE
return true; *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) :
#endif
*rover->topheight;
if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
&& !(rover->master->flags & ML_BLOCKMONSTERS)
&& ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale)))
return true;
}
return false; return false;
} }
@ -2850,7 +2810,7 @@ static boolean P_ZMovement(mobj_t *mo)
mo->z = mo->floorz; mo->z = mo->floorz;
#ifdef ESLOPE #ifdef ESLOPE
if (mo->standingslope) // You're still on the ground; why are we here? if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here?
{ {
mo->momz = 0; mo->momz = 0;
return true; return true;
@ -3151,7 +3111,7 @@ static void P_PlayerZMovement(mobj_t *mo)
else else
mo->z = mo->floorz; mo->z = mo->floorz;
if (mo->player->pflags & PF_NIGHTSMODE) if (mo->player->powers[pw_carry] == CR_NIGHTSMODE)
{ {
// bounce off floor if you were flying towards it // bounce off floor if you were flying towards it
if ((mo->eflags & MFE_VERTICALFLIP && mo->player->flyangle > 0 && mo->player->flyangle < 180) if ((mo->eflags & MFE_VERTICALFLIP && mo->player->flyangle > 0 && mo->player->flyangle < 180)
@ -3259,60 +3219,69 @@ static void P_PlayerZMovement(mobj_t *mo)
// aren't pressing any controls. // aren't pressing any controls.
if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING)) if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING))
{ {
mo->momx = mo->momx/2; mo->momx >>= 1;
mo->momy = mo->momy/2; mo->momy >>= 1;
} }
} }
if (mo->health) if (mo->health && !P_CheckDeathPitCollide(mo))
{ {
if (mo->player->pflags & PF_GLIDING) // ground gliding if (mo->player->pflags & PF_GLIDING) // ground gliding
{ {
mo->player->skidtime = TICRATE; mo->player->skidtime = TICRATE;
mo->tics = -1; mo->tics = -1;
} }
else if (mo->player->charability2 == CA2_MELEE && mo->player->panim == PA_ABILITY2) else if (mo->player->charability2 == CA2_MELEE && (mo->player->panim == PA_ABILITY2 && mo->state-states != S_PLAY_MELEE_LANDING))
{ {
P_InstaThrust(mo, mo->angle, 0); P_SetPlayerMobjState(mo, S_PLAY_MELEE_LANDING);
P_SetPlayerMobjState(mo, S_PLAY_STND); mo->tics = (mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(mo->movefactor)))>>FRACBITS;
S_StartSound(mo, sfx_s3k8b);
mo->player->pflags |= PF_FULLSTASIS;
} }
else if (mo->player->pflags & PF_JUMPED || (mo->player->pflags & (PF_SPINNING|PF_USEDOWN)) != (PF_SPINNING|PF_USEDOWN) else if (mo->player->pflags & PF_JUMPED || (mo->player->pflags & (PF_SPINNING|PF_USEDOWN)) != (PF_SPINNING|PF_USEDOWN)
|| mo->player->powers[pw_tailsfly] || mo->state-states == S_PLAY_FLY_TIRED) || mo->player->powers[pw_tailsfly] || mo->state-states == S_PLAY_FLY_TIRED)
{ {
if (mo->player->cmomx || mo->player->cmomy) if (mo->player->cmomx || mo->player->cmomy)
{ {
if (mo->player->charability == CA_DASHMODE && mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_PEEL) if (mo->player->charflags & SF_DASHMODE && mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_DASH)
P_SetPlayerMobjState(mo, S_PLAY_PEEL); P_SetPlayerMobjState(mo, S_PLAY_DASH);
else if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN) else if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale)
&& (mo->player->panim != PA_RUN || mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(mo, S_PLAY_RUN); P_SetPlayerMobjState(mo, S_PLAY_RUN);
else if ((mo->player->rmomx || mo->player->rmomy) && (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_SUPER_FLOAT)) else if ((mo->player->rmomx || mo->player->rmomy)
&& (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_FLOAT))
P_SetPlayerMobjState(mo, S_PLAY_WALK); P_SetPlayerMobjState(mo, S_PLAY_WALK);
else if (!mo->player->rmomx && !mo->player->rmomy && mo->player->panim != PA_IDLE) else if (!mo->player->rmomx && !mo->player->rmomy && mo->player->panim != PA_IDLE)
P_SetPlayerMobjState(mo, S_PLAY_STND); P_SetPlayerMobjState(mo, S_PLAY_STND);
} }
else else
{ {
if (mo->player->charability == CA_DASHMODE && mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_PEEL) if (mo->player->charflags & SF_DASHMODE && mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_DASH)
P_SetPlayerMobjState(mo, S_PLAY_PEEL); P_SetPlayerMobjState(mo, S_PLAY_DASH);
if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN) else if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale)
&& (mo->player->panim != PA_RUN || mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(mo, S_PLAY_RUN); P_SetPlayerMobjState(mo, S_PLAY_RUN);
else if ((mo->momx || mo->momy) && (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_SUPER_FLOAT)) else if ((mo->momx || mo->momy)
&& (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_FLOAT))
P_SetPlayerMobjState(mo, S_PLAY_WALK); P_SetPlayerMobjState(mo, S_PLAY_WALK);
else if (!mo->momx && !mo->momy && mo->player->panim != PA_IDLE) else if (!mo->momx && !mo->momy && mo->player->panim != PA_IDLE)
P_SetPlayerMobjState(mo, S_PLAY_STND); P_SetPlayerMobjState(mo, S_PLAY_STND);
} }
} }
if (mo->player->pflags & PF_JUMPED) if ((mo->player->charability2 == CA2_SPINDASH) && !(mo->player->pflags & PF_THOKKED) && (mo->player->cmd.buttons & BT_USE) && (FixedHypot(mo->momx, mo->momy) > (5*mo->scale)))
mo->player->pflags &= ~PF_SPINNING; {
else if (!(mo->player->pflags & PF_USEDOWN)) mo->player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(mo, S_PLAY_ROLL);
S_StartSound(mo, sfx_spin);
}
else
mo->player->pflags &= ~PF_SPINNING; mo->player->pflags &= ~PF_SPINNING;
if (!(mo->player->pflags & PF_GLIDING)) if (!(mo->player->pflags & PF_GLIDING))
mo->player->pflags &= ~(PF_JUMPED|PF_FORCEJUMPDAMAGE); mo->player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE);
mo->player->pflags &= ~(PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); mo->player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/);
mo->player->jumping = 0;
mo->player->secondjump = 0; mo->player->secondjump = 0;
mo->player->glidetime = 0; mo->player->glidetime = 0;
mo->player->climbing = 0; mo->player->climbing = 0;
@ -3346,6 +3315,16 @@ static void P_PlayerZMovement(mobj_t *mo)
clipmomz = false; clipmomz = false;
} }
} }
if (mo->player->pflags & PF_BOUNCING)
{
P_MobjCheckWater(mo);
mo->momz *= -1;
P_DoAbilityBounce(mo->player, true);
if (mo->player->scoreadd)
mo->player->scoreadd--;
clipmomz = false;
}
} }
} }
if (!(mo->player->pflags & PF_SPINNING)) if (!(mo->player->pflags & PF_SPINNING))
@ -3394,7 +3373,7 @@ nightsdone:
else else
mo->z = mo->ceilingz - mo->height; mo->z = mo->ceilingz - mo->height;
if (mo->player->pflags & PF_NIGHTSMODE) if (mo->player->powers[pw_carry] == CR_NIGHTSMODE)
{ {
// bounce off ceiling if you were flying towards it // bounce off ceiling if you were flying towards it
if ((mo->eflags & MFE_VERTICALFLIP && mo->player->flyangle > 180 && mo->player->flyangle <= 359) if ((mo->eflags & MFE_VERTICALFLIP && mo->player->flyangle > 180 && mo->player->flyangle <= 359)
@ -3607,11 +3586,17 @@ static boolean P_SceneryZMovement(mobj_t *mo)
// //
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
{ {
if (!(player->pflags & PF_NIGHTSMODE) && !player->homing fixed_t topheight =
&& ((player->powers[pw_super] || player->charflags & SF_RUNONWATER) && player->mo->ceilingz-*rover->topheight >= player->mo->height) #ifdef ESLOPE
*rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) :
#endif
*rover->topheight;
if (!player->powers[pw_carry] && !player->homing
&& ((player->powers[pw_super] || player->charflags & SF_RUNONWATER || player->dashmode >= 3*TICRATE) && player->mo->ceilingz-topheight >= player->mo->height)
&& (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale) && (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale)
&& !(player->pflags & PF_SLIDING) && !(player->pflags & PF_SLIDING)
&& abs(player->mo->z - *rover->topheight) < FixedMul(30*FRACUNIT, player->mo->scale)) && abs(player->mo->z - topheight) < FixedMul(30*FRACUNIT, player->mo->scale))
return true; return true;
return false; return false;
@ -4013,7 +3998,7 @@ void P_DestroyRobots(void)
continue; // not a mobj thinker continue; // not a mobj thinker
mo = (mobj_t *)think; mo = (mobj_t *)think;
if (mo->health <= 0 || !(mo->flags & MF_ENEMY || mo->flags & MF_BOSS)) if (mo->health <= 0 || !(mo->flags & (MF_ENEMY|MF_BOSS)))
continue; // not a valid enemy continue; // not a valid enemy
if (mo->type == MT_PLAYER) // Don't chase after other players! if (mo->type == MT_PLAYER) // Don't chase after other players!
@ -4036,7 +4021,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
|| (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD))) || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)))
itsatwodlevel = true; itsatwodlevel = true;
if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) if (player->pflags & PF_FLIPCAM && !(player->powers[pw_carry] == CR_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP)
postimg = postimg_flip; postimg = postimg_flip;
else if (player->awayviewtics) else if (player->awayviewtics)
{ {
@ -4169,6 +4154,9 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
// momentum movement // momentum movement
mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN; mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN;
if (mobj->state-states == S_PLAY_BOUNCE_LANDING)
goto animonly; // no need for checkposition - doesn't move at ALL
// Zoom tube // Zoom tube
if (mobj->tracer) if (mobj->tracer)
{ {
@ -4289,9 +4277,9 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
} }
else else
{ {
if (!(mobj->player->pflags & PF_NIGHTSMODE)) // "jumping" is used for drilling if (!(mobj->player->powers[pw_carry] == CR_NIGHTSMODE)) // used for drilling
mobj->player->jumping = 0; mobj->player->pflags &= ~PF_STARTJUMP;
mobj->player->pflags &= ~PF_JUMPED; mobj->player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE);
if (mobj->player->secondjump || mobj->player->powers[pw_tailsfly]) if (mobj->player->secondjump || mobj->player->powers[pw_tailsfly])
{ {
mobj->player->secondjump = 0; mobj->player->secondjump = 0;
@ -5491,10 +5479,10 @@ static void P_Boss7Thinker(mobj_t *mobj)
if (players[i].mo->health <= 0) if (players[i].mo->health <= 0)
continue; continue;
if (players[i].powers[pw_ingoop]) if (players[i].powers[pw_carry] == CR_BRAKGOOP)
{ {
closestNum = -1; closestNum = -1;
closestdist = 16384*FRACUNIT; // Just in case... closestdist = INT32_MAX; // Just in case...
// Find waypoint he is closest to // Find waypoint he is closest to
for (th = thinkercap.next; th != &thinkercap; th = th->next) for (th = thinkercap.next; th != &thinkercap; th = th->next)
@ -6903,7 +6891,7 @@ void P_MobjThinker(mobj_t *mobj)
return; return;
if (/*(mobj->target) -- the following is implicit by P_AddShield if (/*(mobj->target) -- the following is implicit by P_AddShield
&& (mobj->target->player) && (mobj->target->player)
&& */ (mobj->target->player->homing)) && */ (mobj->target->player->homing) && (mobj->target->player->pflags & PF_SHIELDABILITY))
{ {
P_SetMobjState(mobj, mobj->info->painstate); P_SetMobjState(mobj, mobj->info->painstate);
mobj->tics++; mobj->tics++;
@ -7038,6 +7026,25 @@ void P_MobjThinker(mobj_t *mobj)
return; return;
} }
break; break;
case MT_LOCKON:
if (!mobj->target)
{
P_RemoveMobj(mobj);
return;
}
mobj->x = mobj->target->x;
mobj->y = mobj->target->y;
mobj->eflags |= (mobj->target->eflags & MFE_VERTICALFLIP);
mobj->destscale = mobj->target->destscale;
P_SetScale(mobj, mobj->target->scale);
if (!(mobj->eflags & MFE_VERTICALFLIP))
mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale);
else
mobj->z = mobj->target->z - FixedMul((16 + abs((leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height;
break;
case MT_DROWNNUMBERS: case MT_DROWNNUMBERS:
if (!mobj->target) if (!mobj->target)
{ {
@ -7309,7 +7316,6 @@ void P_MobjThinker(mobj_t *mobj)
ns = 4 * FRACUNIT; ns = 4 * FRACUNIT;
mo2->momx = FixedMul(FINESINE(fa),ns); mo2->momx = FixedMul(FINESINE(fa),ns);
mo2->momy = FixedMul(FINECOSINE(fa),ns); mo2->momy = FixedMul(FINECOSINE(fa),ns);
mo2->angle = fa << ANGLETOFINESHIFT;
if (P_RandomChance(FRACUNIT/4)) // I filled a spreadsheet trying to get the equivalent chance to the original P_RandomByte hack! if (P_RandomChance(FRACUNIT/4)) // I filled a spreadsheet trying to get the equivalent chance to the original P_RandomByte hack!
S_StartSound(mo2, mobj->info->deathsound); S_StartSound(mo2, mobj->info->deathsound);
@ -7321,6 +7327,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetTarget(&flicky->target, mo2); P_SetTarget(&flicky->target, mo2);
flicky->momx = mo2->momx; flicky->momx = mo2->momx;
flicky->momy = mo2->momy; flicky->momy = mo2->momy;
flicky->angle = fa << ANGLETOFINESHIFT;
} }
mobj->fuse--; mobj->fuse--;
@ -7366,6 +7373,35 @@ void P_MobjThinker(mobj_t *mobj)
} }
else switch (mobj->type) else switch (mobj->type)
{ {
case MT_WALLSPIKEBASE:
if (!mobj->target) {
P_RemoveMobj(mobj);
return;
}
mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK);
if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle
{
mobj_t *target = mobj->target; // shortcut
const fixed_t baseradius = target->radius/2 - FixedMul(FRACUNIT, target->scale);
P_UnsetThingPosition(mobj);
mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius);
mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius);
P_SetThingPosition(mobj);
mobj->angle = target->angle + ANGLE_90;
}
break;
case MT_FALLINGROCK:
// Despawn rocks here in case zmovement code can't do so (blame slopes)
if (!mobj->momx && !mobj->momy && !mobj->momz
&& ((mobj->eflags & MFE_VERTICALFLIP) ?
mobj->z + mobj->height >= mobj->ceilingz
: mobj->z <= mobj->floorz))
{
P_RemoveMobj(mobj);
return;
}
P_MobjCheckWater(mobj);
break;
case MT_EMERALDSPAWN: case MT_EMERALDSPAWN:
if (mobj->threshold) if (mobj->threshold)
{ {
@ -7652,7 +7688,7 @@ void P_MobjThinker(mobj_t *mobj)
} }
else if (mobj->tracer && mobj->tracer->player) else if (mobj->tracer && mobj->tracer->player)
{ {
if (!(mobj->tracer->player->pflags & PF_NIGHTSMODE)) if (!(mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE))
{ {
mobj->flags &= ~MF_NOGRAVITY; mobj->flags &= ~MF_NOGRAVITY;
mobj->flags2 &= ~MF2_DONTDRAW; mobj->flags2 &= ~MF2_DONTDRAW;
@ -7704,7 +7740,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetTarget(&mobj->target, NULL); P_SetTarget(&mobj->target, NULL);
} }
if (mobj->tracer->player->pflags & PF_NIGHTSMODE) if (mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE)
{ {
if (mobj->tracer->player->bonustime) if (mobj->tracer->player->bonustime)
{ {
@ -8047,6 +8083,10 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
if (mobj->spawnpoint) if (mobj->spawnpoint)
mobj->fuse += mobj->spawnpoint->angle; mobj->fuse += mobj->spawnpoint->angle;
break; break;
case MT_WALLSPIKE:
P_SetMobjState(mobj, mobj->state->nextstate);
mobj->fuse = mobj->info->speed;
break;
case MT_NIGHTSCORE: case MT_NIGHTSCORE:
P_RemoveMobj(mobj); P_RemoveMobj(mobj);
return; return;
@ -8438,9 +8478,17 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
// Collision helper can be stood on but not pushed // Collision helper can be stood on but not pushed
mobj->flags2 |= MF2_STANDONME; mobj->flags2 |= MF2_STANDONME;
break; break;
case MT_WALLSPIKE:
case MT_SPIKE: case MT_SPIKE:
mobj->flags2 |= MF2_STANDONME; mobj->flags2 |= MF2_STANDONME;
break; break;
case MT_GFZTREE:
case MT_GFZBERRYTREE:
case MT_GFZCHERRYTREE:
case MT_LAMPPOST1:
case MT_LAMPPOST2:
mobj->flags2 |= MF2_STANDONME;
break;
case MT_DETON: case MT_DETON:
mobj->movedir = 0; mobj->movedir = 0;
break; break;
@ -8506,6 +8554,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break; break;
case MT_EGGCAPSULE: case MT_EGGCAPSULE:
mobj->extravalue1 = -1; // timer for how long a player has been at the capsule mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
break;
case MT_REDTEAMRING: case MT_REDTEAMRING:
mobj->color = skincolor_redteam; mobj->color = skincolor_redteam;
break; break;
@ -8770,7 +8819,6 @@ consvar_t cv_itemrespawntime = {"respawnitemtime", "30", CV_NETVAR|CV_CHEAT, res
consvar_t cv_itemrespawn = {"respawnitem", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_itemrespawn = {"respawnitem", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t flagtime_cons_t[] = {{0, "MIN"}, {300, "MAX"}, {0, NULL}}; static CV_PossibleValue_t flagtime_cons_t[] = {{0, "MIN"}, {300, "MAX"}, {0, NULL}};
consvar_t cv_flagtime = {"flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_flagtime = {"flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_suddendeath = {"suddendeath", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
void P_SpawnPrecipitation(void) void P_SpawnPrecipitation(void)
{ {
@ -9455,7 +9503,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
} }
if (metalrecording) // Metal Sonic can't use these things. if (metalrecording) // Metal Sonic can't use these things.
if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_EMMY || i == MT_STARPOST) if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST)
return; return;
if (i >= MT_EMERALD1 && i <= MT_EMERALD7) // Pickupable Emeralds if (i >= MT_EMERALD1 && i <= MT_EMERALD7) // Pickupable Emeralds
@ -9513,7 +9561,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
// Yeah, this is a dirty hack. // Yeah, this is a dirty hack.
if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR) if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR)
{ {
if (gametype == GT_COMPETITION) if (gametype == GT_COMPETITION || gametype == GT_RACE)
{ {
// Set powerup boxes to user settings for competition. // Set powerup boxes to user settings for competition.
if (cv_competitionboxes.value == 1) // Random if (cv_competitionboxes.value == 1) // Random
@ -9569,7 +9617,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
return; return;
// Emerald Tokens -->> Score Tokens // Emerald Tokens -->> Score Tokens
else if (i == MT_EMMY) else if (i == MT_TOKEN)
return; /// \todo return; /// \todo
// 1UPs -->> Score TVs // 1UPs -->> Score TVs
@ -9586,7 +9634,8 @@ void P_SpawnMapThing(mapthing_t *mthing)
if (ultimatemode) if (ultimatemode)
{ {
if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX
|| i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX) || i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX
|| i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX)
return; // No shields in Ultimate mode return; // No shields in Ultimate mode
if (i == MT_RING_BOX && !G_IsSpecialStage(gamemap)) if (i == MT_RING_BOX && !G_IsSpecialStage(gamemap))
@ -9596,7 +9645,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
// They're likely facets of the level's design and therefore required to progress. // They're likely facets of the level's design and therefore required to progress.
} }
if (i == MT_EMMY && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++))) if (i == MT_TOKEN && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++)))
return; // you already got this token, or there are too many, or the gametype's not right return; // you already got this token, or there are too many, or the gametype's not right
// Objectplace landing point // Objectplace landing point
@ -9615,7 +9664,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS); ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS);
else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE)
z = ONFLOORZ; z = ONFLOORZ;
else if (i == MT_SPECIALSPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_EMMY) else if (i == MT_SPECIALSPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN)
{ {
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)
{ {
@ -9705,14 +9754,23 @@ void P_SpawnMapThing(mapthing_t *mthing)
mobj = P_SpawnMobj(x, y, z, i); mobj = P_SpawnMobj(x, y, z, i);
mobj->spawnpoint = mthing; mobj->spawnpoint = mthing;
#ifdef HAVE_BLUA
if (LUAh_MapThingSpawn(mobj, mthing))
{
if (P_MobjWasRemoved(mobj))
return;
}
else if (P_MobjWasRemoved(mobj))
return;
else
#endif
switch(mobj->type) switch(mobj->type)
{ {
case MT_SKYBOX: case MT_SKYBOX:
mobj->angle = 0;
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
skyboxmo[1] = mobj; skyboxcenterpnts[mthing->extrainfo] = mobj;
else else
skyboxmo[0] = mobj; skyboxviewpnts[mthing->extrainfo] = mobj;
break; break;
case MT_FAN: case MT_FAN:
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
@ -9757,20 +9815,16 @@ void P_SpawnMapThing(mapthing_t *mthing)
mobjtype_t macetype = MT_SMALLMACE; mobjtype_t macetype = MT_SMALLMACE;
boolean firsttime; boolean firsttime;
mobj_t *spawnee; mobj_t *spawnee;
size_t line; INT32 line;
const size_t mthingi = (size_t)(mthing - mapthings); const size_t mthingi = (size_t)(mthing - mapthings);
// Why does P_FindSpecialLineFromTag not work here?!? // Find the corresponding linedef special, using angle as tag
// Monster Iestyn: tag lists haven't been initialised yet for the map, that's why // P_FindSpecialLineFromTag works here now =D
for (line = 0; line < numlines; line++) line = P_FindSpecialLineFromTag(9, mthing->angle, -1);
{
if (lines[line].special == 9 && lines[line].tag == mthing->angle)
break;
}
if (line == numlines) if (line == -1)
{ {
CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return; return;
} }
/* /*
@ -9868,18 +9922,15 @@ ML_NOCLIMB : Direction not controllable
fixed_t radius, speed, bottomheight, topheight; fixed_t radius, speed, bottomheight, topheight;
INT32 type, numdivisions, time, anglespeed; INT32 type, numdivisions, time, anglespeed;
angle_t angledivision; angle_t angledivision;
size_t line; INT32 line;
const size_t mthingi = (size_t)(mthing - mapthings); const size_t mthingi = (size_t)(mthing - mapthings);
for (line = 0; line < numlines; line++) // Find the corresponding linedef special, using angle as tag
{ line = P_FindSpecialLineFromTag(15, mthing->angle, -1);
if (lines[line].special == 15 && lines[line].tag == mthing->angle)
break;
}
if (line == numlines) if (line == -1)
{ {
CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return; return;
} }
@ -10012,28 +10063,10 @@ ML_NOCLIMB : Direction not controllable
mobj->radius = (mthing->angle & 16383)*FRACUNIT; mobj->radius = (mthing->angle & 16383)*FRACUNIT;
} }
} }
else if (i == MT_EMMY) else if (i == MT_TOKEN)
{ {
if (mthing->options & MTF_OBJECTSPECIAL) // Mario Block version if (mthing->options & MTF_OBJECTSPECIAL) // Mario Block version
mobj->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); mobj->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT);
else
{
fixed_t zheight = mobj->z;
mobj_t *tokenobj;
if (mthing->options & MTF_OBJECTFLIP)
zheight += mobj->height-FixedMul(mobjinfo[MT_TOKEN].height, mobj->scale); // align with emmy properly!
tokenobj = P_SpawnMobj(x, y, zheight, MT_TOKEN);
P_SetTarget(&mobj->tracer, tokenobj);
tokenobj->destscale = mobj->scale;
P_SetScale(tokenobj, mobj->scale);
if (mthing->options & MTF_OBJECTFLIP) // flip token to match emmy
{
tokenobj->eflags |= MFE_VERTICALFLIP;
tokenobj->flags2 |= MF2_OBJECTFLIP;
}
}
// We advanced tokenbits earlier due to the return check. // We advanced tokenbits earlier due to the return check.
// Subtract 1 here for the correct value. // Subtract 1 here for the correct value.
@ -10093,6 +10126,38 @@ ML_NOCLIMB : Direction not controllable
P_SetThingPosition(mobj); P_SetThingPosition(mobj);
} }
} }
else if (i == MT_WALLSPIKE)
{
// Pop up spikes!
if (mthing->options & MTF_OBJECTSPECIAL)
{
mobj->flags &= ~MF_SCENERY;
mobj->fuse = mobj->info->speed;
}
// Use per-thing collision for spikes if the deaf flag is checked.
if (mthing->options & MTF_AMBUSH && !metalrecording)
{
P_UnsetThingPosition(mobj);
mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIPHEIGHT);
mobj->flags |= MF_SOLID;
P_SetThingPosition(mobj);
}
// spawn base
{
const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so...
const fixed_t baseradius = mobj->radius/2 - FixedMul(FRACUNIT, mobj->scale);
mobj_t *base = P_SpawnMobj(
mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius),
mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius),
mobj->z, MT_WALLSPIKEBASE);
base->angle = mobjangle + ANGLE_90;
base->destscale = mobj->destscale;
P_SetScale(base, mobj->scale);
P_SetTarget(&base->target, mobj);
P_SetTarget(&mobj->tracer, base);
}
}
//count 10 ring boxes into the number of rings equation too. //count 10 ring boxes into the number of rings equation too.
if (i == MT_RING_BOX) if (i == MT_RING_BOX)

View file

@ -35,9 +35,11 @@
#pragma interface #pragma interface
#endif #endif
/// \brief Frame flags: only the frame number - 0 to 511 (Frames from 0 to 63, Sprite2 number uses full range) /// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 63, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER)
#define FF_FRAMEMASK 0x1ff #define FF_FRAMEMASK 0xff
/// \brief Frame flags - SPR2: Super sprite2
#define FF_SPR2SUPER 0x80
/// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation /// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation
#define FF_SPR2ENDSTATE 0x1000 #define FF_SPR2ENDSTATE 0x1000
/// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation /// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation

View file

@ -152,7 +152,6 @@ static void P_NetArchivePlayers(void)
WRITESINT8(save_p, players[i].xtralife); WRITESINT8(save_p, players[i].xtralife);
WRITEUINT8(save_p, players[i].gotcontinue); WRITEUINT8(save_p, players[i].gotcontinue);
WRITEFIXED(save_p, players[i].speed); WRITEFIXED(save_p, players[i].speed);
WRITEUINT8(save_p, players[i].jumping);
WRITEUINT8(save_p, players[i].secondjump); WRITEUINT8(save_p, players[i].secondjump);
WRITEUINT8(save_p, players[i].fly1); WRITEUINT8(save_p, players[i].fly1);
WRITEUINT8(save_p, players[i].scoreadd); WRITEUINT8(save_p, players[i].scoreadd);
@ -332,7 +331,6 @@ static void P_NetUnArchivePlayers(void)
players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter
players[i].gotcontinue = READUINT8(save_p); // got continue from stage players[i].gotcontinue = READUINT8(save_p); // got continue from stage
players[i].speed = READFIXED(save_p); // Player's speed (distance formula of MOMX and MOMY values) players[i].speed = READFIXED(save_p); // Player's speed (distance formula of MOMX and MOMY values)
players[i].jumping = READUINT8(save_p); // Jump counter
players[i].secondjump = READUINT8(save_p); players[i].secondjump = READUINT8(save_p);
players[i].fly1 = READUINT8(save_p); // Tails flying players[i].fly1 = READUINT8(save_p); // Tails flying
players[i].scoreadd = READUINT8(save_p); // Used for multiple enemy attack bonus players[i].scoreadd = READUINT8(save_p); // Used for multiple enemy attack bonus

View file

@ -199,6 +199,8 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
const INT16 num = (INT16)(i-1); const INT16 num = (INT16)(i-1);
DEH_WriteUndoline("LEVELNAME", mapheaderinfo[num]->lvlttl, UNDO_NONE); DEH_WriteUndoline("LEVELNAME", mapheaderinfo[num]->lvlttl, UNDO_NONE);
mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->lvlttl[0] = '\0';
DEH_WriteUndoline("SELECTHEADING", mapheaderinfo[num]->selectheading, UNDO_NONE);
mapheaderinfo[num]->selectheading[0] = '\0';
DEH_WriteUndoline("SUBTITLE", mapheaderinfo[num]->subttl, UNDO_NONE); DEH_WriteUndoline("SUBTITLE", mapheaderinfo[num]->subttl, UNDO_NONE);
mapheaderinfo[num]->subttl[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0';
DEH_WriteUndoline("ACT", va("%d", mapheaderinfo[num]->actnum), UNDO_NONE); DEH_WriteUndoline("ACT", va("%d", mapheaderinfo[num]->actnum), UNDO_NONE);
@ -2276,6 +2278,17 @@ void P_LoadThingsOnly(void)
// Search through all the thinkers. // Search through all the thinkers.
mobj_t *mo; mobj_t *mo;
thinker_t *think; thinker_t *think;
INT32 i, viewid = -1, centerid = -1; // for skyboxes
// check if these are any of the normal viewpoint/centerpoint mobjs in the level or not
if (skyboxmo[0] || skyboxmo[1])
for (i = 0; i < 16; i++)
{
if (skyboxmo[0] && skyboxmo[0] == skyboxviewpnts[i])
viewid = i; // save id just in case
if (skyboxmo[1] && skyboxmo[1] == skyboxcenterpnts[i])
centerid = i; // save id just in case
}
for (think = thinkercap.next; think != &thinkercap; think = think->next) for (think = thinkercap.next; think != &thinkercap; think = think->next)
{ {
@ -2293,6 +2306,10 @@ void P_LoadThingsOnly(void)
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
P_LoadThings(); P_LoadThings();
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0];
skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
P_SpawnSecretItems(true); P_SpawnSecretItems(true);
} }
@ -2574,8 +2591,7 @@ boolean P_SetupLevel(boolean skipprecip)
postimgtype = postimgtype2 = postimg_none; postimgtype = postimgtype2 = postimg_none;
if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0' if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0')
&& atoi(mapheaderinfo[gamemap-1]->forcecharacter) != 255)
P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter); P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter);
// chasecam on in chaos, race, coop // chasecam on in chaos, race, coop
@ -2585,8 +2601,9 @@ boolean P_SetupLevel(boolean skipprecip)
if (!dedicated) if (!dedicated)
{ {
if (!cv_cam_speed.changed) // Salt: CV_ClearChangedFlags() messes with your settings :(
CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue); /*if (!cv_cam_speed.changed)
CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue);*/
if (!cv_chasecam.changed) if (!cv_chasecam.changed)
CV_SetValue(&cv_chasecam, chase); CV_SetValue(&cv_chasecam, chase);
@ -2727,15 +2744,25 @@ boolean P_SetupLevel(boolean skipprecip)
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
skyboxmo[i] = NULL; skyboxmo[i] = NULL;
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
P_MapStart(); P_MapStart();
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
// init gravity, tag lists,
// anything that P_ResetDynamicSlopes/P_LoadThings needs to know
P_InitSpecials();
#ifdef ESLOPE #ifdef ESLOPE
P_ResetDynamicSlopes(); P_ResetDynamicSlopes();
#endif #endif
P_LoadThings(); P_LoadThings();
// skybox mobj defaults
skyboxmo[0] = skyboxviewpnts[0];
skyboxmo[1] = skyboxcenterpnts[0];
P_SpawnSecretItems(loademblems); P_SpawnSecretItems(loademblems);
@ -2749,8 +2776,6 @@ boolean P_SetupLevel(boolean skipprecip)
if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
globalweather = mapheaderinfo[gamemap-1]->weather;
#ifdef HWRENDER // not win32 only 19990829 by Kin #ifdef HWRENDER // not win32 only 19990829 by Kin
if (rendermode != render_soft && rendermode != render_none) if (rendermode != render_soft && rendermode != render_none)
{ {
@ -2776,8 +2801,6 @@ boolean P_SetupLevel(boolean skipprecip)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
{ {
players[i].pflags &= ~PF_NIGHTSMODE;
// Start players with pity shields if possible // Start players with pity shields if possible
players[i].pity = -1; players[i].pity = -1;
@ -2882,22 +2905,21 @@ boolean P_SetupLevel(boolean skipprecip)
camera.angle = FixedAngle((fixed_t)thing->angle << FRACBITS); camera.angle = FixedAngle((fixed_t)thing->angle << FRACBITS);
} }
} }
if (!cv_cam_height.changed) // Salt: CV_ClearChangedFlags() messes with your settings :(
/*if (!cv_cam_height.changed)
CV_Set(&cv_cam_height, cv_cam_height.defaultvalue); CV_Set(&cv_cam_height, cv_cam_height.defaultvalue);
if (!cv_cam_dist.changed)
CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue);
if (!cv_cam_rotate.changed)
CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue);
if (!cv_cam2_height.changed) if (!cv_cam2_height.changed)
CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue); CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue);
if (!cv_cam_dist.changed)
CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue);
if (!cv_cam2_dist.changed) if (!cv_cam2_dist.changed)
CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue); CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/
// Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P
if (!cv_cam_rotate.changed)
CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue);
if (!cv_cam2_rotate.changed) if (!cv_cam2_rotate.changed)
CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue); CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue);

View file

@ -103,12 +103,20 @@ static fixed_t P_InterceptVector2(divline_t *v2, divline_t *v1)
static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los) static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
{ {
size_t i; size_t i;
sector_t *polysec;
if (!(po->flags & POF_RENDERALL))
return true; // the polyobject isn't visible, so we can ignore it
polysec = po->lines[0]->backsector;
for (i = 0; i < po->numLines; ++i) for (i = 0; i < po->numLines; ++i)
{ {
line_t *line = po->lines[i]; line_t *line = po->lines[i];
divline_t divl; divline_t divl;
const vertex_t *v1,*v2; const vertex_t *v1,*v2;
fixed_t frac;
fixed_t topslope, bottomslope;
// already checked other side? // already checked other side?
if (line->validcount == validcount) if (line->validcount == validcount)
@ -140,7 +148,22 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
continue; continue;
// stop because it is not two sided // stop because it is not two sided
return false; //if (!(po->flags & POF_TESTHEIGHT))
//return false;
frac = P_InterceptVector2(&los->strace, &divl);
// get slopes of top and bottom of this polyobject line
topslope = FixedDiv(polysec->ceilingheight - los->sightzstart , frac);
bottomslope = FixedDiv(polysec->floorheight - los->sightzstart , frac);
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
return false; // view completely blocked
// TODO: figure out if it's worth considering partially blocked cases or not?
// maybe to adjust los's top/bottom slopes if needed
//if (los->topslope <= los->bottomslope)
//return false;
} }
return true; return true;

View file

@ -46,7 +46,9 @@
#include <errno.h> #include <errno.h>
#endif #endif
mobj_t *skyboxmo[2]; mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
// Amount (dx, dy) vector linedef is shifted right to get scroll amount // Amount (dx, dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5 #define SCROLL_SHIFT 5
@ -111,7 +113,7 @@ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinker
static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec); static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec);
static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer); static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer);
static void P_AddSpikeThinker(sector_t *sec, INT32 referrer); static void P_AddSpikeThinker(sector_t *sec, INT32 referrer);
static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee); static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee, UINT8 reverse);
//SoM: 3/7/2000: New sturcture without limits. //SoM: 3/7/2000: New sturcture without limits.
@ -454,7 +456,8 @@ void P_ParseAnimationDefintion(SINT8 istexture)
// Search for existing animdef // Search for existing animdef
for (i = 0; i < maxanims; i++) for (i = 0; i < maxanims; i++)
if (stricmp(animdefsToken, animdefs[i].startname) == 0) if (animdefs[i].istexture == istexture // Check if it's the same type!
&& stricmp(animdefsToken, animdefs[i].startname) == 0)
{ {
//CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken); //CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
@ -1746,7 +1749,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
case 305: // continuous case 305: // continuous
case 306: // each time case 306: // each time
case 307: // once case 307: // once
if (!(actor && actor->player && actor->player->charability != dist/10)) if (!(actor && actor->player && actor->player->charability == dist/10))
return false; return false;
break; break;
case 309: // continuous case 309: // continuous
@ -2442,73 +2445,81 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 414: // Play SFX case 414: // Play SFX
{ {
fixed_t sfxnum; INT32 sfxnum;
sfxnum = sides[line->sidenum[0]].toptexture; sfxnum = sides[line->sidenum[0]].toptexture;
if (line->tag != 0 && line->flags & ML_EFFECT5) if (sfxnum == sfx_None)
return; // Do nothing!
if (sfxnum < sfx_None || sfxnum >= NUMSFX)
{ {
sector_t *sec; CONS_Debug(DBG_GAMELOGIC, "Line type 414 Executor: sfx number %d is invalid!\n", sfxnum);
return;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) }
if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set
{
if (line->flags & ML_EFFECT5) // Repeat Midtexture
{ {
sec = &sectors[secnum]; // Additionally play the sound from tagged sectors' soundorgs
S_StartSound(&sec->soundorg, sfxnum); sector_t *sec;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
S_StartSound(&sec->soundorg, sfxnum);
}
}
else if (mo) // A mobj must have triggered the executor
{
// Only trigger if mobj is touching the tag
ffloor_t *rover;
boolean foundit = false;
for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
{
if (rover->master->frontsector->tag != line->tag)
continue;
if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
foundit = true;
}
if (mo->subsector->sector->tag == line->tag)
foundit = true;
if (!foundit)
return;
} }
} }
else if (line->tag != 0 && mo)
if (line->flags & ML_NOCLIMB)
{ {
// Only trigger if mobj is touching the tag // play the sound from nowhere, but only if display player triggered it
ffloor_t *rover; if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer]))
boolean foundit = false;
for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
{
if (rover->master->frontsector->tag != line->tag)
continue;
if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
foundit = true;
}
if (mo->subsector->sector->tag == line->tag)
foundit = true;
if (!foundit)
return;
}
if (sfxnum < NUMSFX && sfxnum > sfx_None)
{
if (line->flags & ML_NOCLIMB)
{
// play the sound from nowhere, but only if display player triggered it
if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer]))
S_StartSound(NULL, sfxnum);
}
else if (line->flags & ML_EFFECT4)
{
// play the sound from nowhere
S_StartSound(NULL, sfxnum); S_StartSound(NULL, sfxnum);
} }
else if (line->flags & ML_BLOCKMONSTERS) else if (line->flags & ML_EFFECT4)
{ {
// play the sound from calling sector's soundorg // play the sound from nowhere
if (callsec) S_StartSound(NULL, sfxnum);
S_StartSound(&callsec->soundorg, sfxnum); }
else if (mo) else if (line->flags & ML_BLOCKMONSTERS)
S_StartSound(&mo->subsector->sector->soundorg, sfxnum); {
} // play the sound from calling sector's soundorg
if (callsec)
S_StartSound(&callsec->soundorg, sfxnum);
else if (mo) else if (mo)
{ S_StartSound(&mo->subsector->sector->soundorg, sfxnum);
// play the sound from mobj that triggered it }
S_StartSound(mo, sfxnum); else if (mo)
} {
// play the sound from mobj that triggered it
S_StartSound(mo, sfxnum);
} }
} }
break; break;
@ -3044,7 +3055,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 443: // Calls a named Lua function case 443: // Calls a named Lua function
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
LUAh_LinedefExecute(line, mo, callsec); if (line->text)
LUAh_LinedefExecute(line, mo, callsec);
else
CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(line-lines));
#else #else
CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n"); CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n");
#endif #endif
@ -3156,6 +3170,47 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
} }
break; break;
case 448: // Change skybox viewpoint/centerpoint
if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB))
{
INT32 viewid = sides[line->sidenum[0]].textureoffset>>FRACBITS;
INT32 centerid = sides[line->sidenum[0]].rowoffset>>FRACBITS;
if ((line->flags & (ML_EFFECT4|ML_BLOCKMONSTERS)) == ML_EFFECT4) // Solid Midtexture is on but Block Enemies is off?
{
CONS_Alert(CONS_WARNING,
M_GetText("Skybox switch linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"),
line->tag);
}
else
{
// set viewpoint mobj
if (!(line->flags & ML_EFFECT4)) // Solid Midtexture turns off viewpoint setting
{
if (viewid >= 0 && viewid < 16)
skyboxmo[0] = skyboxviewpnts[viewid];
else
skyboxmo[0] = NULL;
}
// set centerpoint mobj
if (line->flags & ML_BLOCKMONSTERS) // Block Enemies turns ON centerpoint setting
{
if (centerid >= 0 && centerid < 16)
skyboxmo[1] = skyboxcenterpnts[centerid];
else
skyboxmo[1] = NULL;
}
}
CONS_Debug(DBG_GAMELOGIC, "Line type 448 Executor: viewid = %d, centerid = %d, viewpoint? = %s, centerpoint? = %s\n",
viewid,
centerid,
((line->flags & ML_EFFECT4) ? "no" : "yes"),
((line->flags & ML_BLOCKMONSTERS) ? "yes" : "no"));
}
break;
case 450: // Execute Linedef Executor - for recursion case 450: // Execute Linedef Executor - for recursion
P_LinedefExecute(line->tag, mo, NULL); P_LinedefExecute(line->tag, mo, NULL);
break; break;
@ -3523,7 +3578,7 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
// //
// Is player standing on the sector's "ground"? // Is player standing on the sector's "ground"?
// //
static inline boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) static boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec)
{ {
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING); return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING);
@ -3575,7 +3630,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
P_DamageMobj(player->mo, NULL, NULL, 1, 0); P_DamageMobj(player->mo, NULL, NULL, 1, 0);
break; break;
case 2: // Damage (Water) case 2: // Damage (Water)
if ((roversector || P_MobjReadyToTrigger(player->mo, sector)) && (player->powers[pw_underwater] || player->pflags & PF_NIGHTSMODE)) if ((roversector || P_MobjReadyToTrigger(player->mo, sector)) && (player->powers[pw_underwater] || player->powers[pw_carry] == CR_NIGHTSMODE))
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_WATER); P_DamageMobj(player->mo, NULL, NULL, 1, DMG_WATER);
break; break;
case 3: // Damage (Fire) case 3: // Damage (Fire)
@ -3656,14 +3711,49 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
{ {
if (roversector) if (roversector)
{ {
if (players[i].mo->subsector->sector != roversector) if (players[i].mo->subsector->sector == roversector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == roversector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
}
else
goto DoneSection2; goto DoneSection2;
if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector)) if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector))
goto DoneSection2; goto DoneSection2;
} }
else else
{ {
if (players[i].mo->subsector->sector != sector) if (players[i].mo->subsector->sector == sector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
}
else
goto DoneSection2; goto DoneSection2;
if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector)) if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector))
@ -3792,7 +3882,7 @@ DoneSection2:
if (!(player->pflags & PF_SPINNING)) if (!(player->pflags & PF_SPINNING))
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
} }
player->powers[pw_flashing] = TICRATE/3; player->powers[pw_flashing] = TICRATE/3;
@ -3953,7 +4043,7 @@ DoneSection2:
if (!(player->pflags & PF_SPINNING) && P_IsObjectOnGround(player->mo) && (player->charability2 == CA2_SPINDASH)) if (!(player->pflags & PF_SPINNING) && P_IsObjectOnGround(player->mo) && (player->charability2 == CA2_SPINDASH))
{ {
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartAttackSound(player->mo, sfx_spin); S_StartAttackSound(player->mo, sfx_spin);
if (abs(player->rmomx) < FixedMul(5*FRACUNIT, player->mo->scale) if (abs(player->rmomx) < FixedMul(5*FRACUNIT, player->mo->scale)
@ -4030,12 +4120,12 @@ DoneSection2:
player->powers[pw_carry] = CR_ZOOMTUBE; player->powers[pw_carry] = CR_ZOOMTUBE;
player->speed = speed; player->speed = speed;
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY); player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_SLIDING|PF_CANCARRY);
player->climbing = 0; player->climbing = 0;
if (player->mo->state-states != S_PLAY_SPIN) if (player->mo->state-states != S_PLAY_ROLL)
{ {
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_spin); S_StartSound(player->mo, sfx_spin);
} }
} }
@ -4110,12 +4200,12 @@ DoneSection2:
player->powers[pw_carry] = CR_ZOOMTUBE; player->powers[pw_carry] = CR_ZOOMTUBE;
player->speed = speed; player->speed = speed;
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY); player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_SLIDING|PF_CANCARRY);
player->climbing = 0; player->climbing = 0;
if (player->mo->state-states != S_PLAY_SPIN) if (player->mo->state-states != S_PLAY_ROLL)
{ {
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_spin); S_StartSound(player->mo, sfx_spin);
} }
} }
@ -4128,7 +4218,7 @@ DoneSection2:
{ {
player->laps++; player->laps++;
if (player->pflags & PF_NIGHTSMODE) if (player->powers[pw_carry] == CR_NIGHTSMODE)
player->drillmeter += 48*20; player->drillmeter += 48*20;
if (player->laps >= (UINT8)cv_numlaps.value) if (player->laps >= (UINT8)cv_numlaps.value)
@ -4418,7 +4508,7 @@ DoneSection2:
S_StartSound(player->mo, sfx_s3k4a); S_StartSound(player->mo, sfx_s3k4a);
player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY); player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_SLIDING|PF_CANCARRY);
player->climbing = 0; player->climbing = 0;
P_SetThingPosition(player->mo); P_SetThingPosition(player->mo);
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
@ -4444,6 +4534,7 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
{ {
sector_t *sector; sector_t *sector;
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
sector = mo->subsector->sector; sector = mo->subsector->sector;
if (!sector->ffloors) if (!sector->ffloors)
@ -4451,8 +4542,6 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
fixed_t topheight, bottomheight;
if (!rover->master->frontsector->special) if (!rover->master->frontsector->special)
continue; continue;
@ -4500,6 +4589,8 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
return NULL; return NULL;
} }
#define TELEPORTED (player->mo->subsector->sector != originalsector)
/** Checks if a player is standing on or is inside a 3D floor (e.g. water) and /** Checks if a player is standing on or is inside a 3D floor (e.g. water) and
* applies any specials. * applies any specials.
* *
@ -4508,12 +4599,12 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
*/ */
static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
{ {
sector_t *originalsector = player->mo->subsector->sector;
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
fixed_t topheight, bottomheight;
if (!rover->master->frontsector->special) if (!rover->master->frontsector->special)
continue; continue;
@ -4557,7 +4648,10 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
// This FOF has the special we're looking for, but are we allowed to touch it? // This FOF has the special we're looking for, but are we allowed to touch it?
if (sector == player->mo->subsector->sector if (sector == player->mo->subsector->sector
|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH)) || (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
{
P_ProcessSpecialSector(player, rover->master->frontsector, sector); P_ProcessSpecialSector(player, rover->master->frontsector, sector);
if TELEPORTED return;
}
} }
// Allow sector specials to be applied to polyobjects! // Allow sector specials to be applied to polyobjects!
@ -4568,7 +4662,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
boolean touching = false; boolean touching = false;
boolean inside = false; boolean inside = false;
while(po) while (po)
{ {
if (po->flags & POF_NOSPECIALS) if (po->flags & POF_NOSPECIALS)
{ {
@ -4644,6 +4738,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
} }
P_ProcessSpecialSector(player, polysec, sector); P_ProcessSpecialSector(player, polysec, sector);
if TELEPORTED return;
po = (polyobj_t *)(po->link.next); po = (polyobj_t *)(po->link.next);
} }
@ -4748,40 +4843,43 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
*/ */
void P_PlayerInSpecialSector(player_t *player) void P_PlayerInSpecialSector(player_t *player)
{ {
sector_t *sector; sector_t *originalsector;
sector_t *loopsector;
msecnode_t *node; msecnode_t *node;
if (!player->mo) if (!player->mo)
return; return;
// Do your ->subsector->sector first originalsector = player->mo->subsector->sector;
sector = player->mo->subsector->sector;
P_PlayerOnSpecial3DFloor(player, sector);
// After P_PlayerOnSpecial3DFloor, recheck if the player is in that sector,
// because the player can be teleported in between these times.
if (sector == player->mo->subsector->sector)
P_RunSpecialSectorCheck(player, sector);
// Iterate through touching_sectorlist P_PlayerOnSpecial3DFloor(player, originalsector); // Handle FOFs first.
if TELEPORTED return;
P_RunSpecialSectorCheck(player, originalsector);
if TELEPORTED return;
// Iterate through touching_sectorlist for SF_TRIGGERSPECIAL_TOUCH
for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{ {
sector = node->m_sector; loopsector = node->m_sector;
if (sector == player->mo->subsector->sector) // Don't duplicate if (loopsector == originalsector) // Don't duplicate
continue; continue;
// Check 3D floors... // Check 3D floors...
P_PlayerOnSpecial3DFloor(player, sector); P_PlayerOnSpecial3DFloor(player, loopsector);
if TELEPORTED return;
if (!(sector->flags & SF_TRIGGERSPECIAL_TOUCH)) if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH))
return; continue;
// After P_PlayerOnSpecial3DFloor, recheck if the player is in that sector,
// because the player can be teleported in between these times. P_RunSpecialSectorCheck(player, loopsector);
if (sector == player->mo->subsector->sector) if TELEPORTED return;
P_RunSpecialSectorCheck(player, sector);
} }
} }
#undef TELEPORTED
/** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up. /** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up.
* *
* \sa P_CheckTimeLimit, P_CheckPointLimit * \sa P_CheckTimeLimit, P_CheckPointLimit
@ -5173,10 +5271,11 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
* \param speed Rate of movement relative to control sector * \param speed Rate of movement relative to control sector
* \param control Control sector. * \param control Control sector.
* \param affectee Target sector. * \param affectee Target sector.
* \param reverse Reverse direction?
* \sa P_SpawnSpecials, T_PlaneDisplace * \sa P_SpawnSpecials, T_PlaneDisplace
* \author Monster Iestyn * \author Monster Iestyn
*/ */
static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee) static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee, UINT8 reverse)
{ {
planedisplace_t *displace; planedisplace_t *displace;
@ -5190,6 +5289,7 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control,
displace->last_height = sectors[control].floorheight; displace->last_height = sectors[control].floorheight;
displace->speed = speed; displace->speed = speed;
displace->type = type; displace->type = type;
displace->reverse = reverse;
} }
/** Adds a Mario block thinker, which changes the block's texture between blank /** Adds a Mario block thinker, which changes the block's texture between blank
@ -5541,6 +5641,45 @@ static void P_RunLevelLoadExecutors(void)
} }
} }
/** Before things are loaded, initialises certain stuff in case they're needed
* by P_ResetDynamicSlopes or P_LoadThings. This was split off from
* P_SpawnSpecials, in case you couldn't tell.
*
* \sa P_SpawnSpecials, P_InitTagLists
* \author Monster Iestyn
*/
void P_InitSpecials(void)
{
// Set the default gravity. Custom gravity overrides this setting.
gravity = FRACUNIT/2;
// Defaults in case levels don't have them set.
sstimer = 90*TICRATE + 6;
totalrings = 1;
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
// Set curWeather
switch (mapheaderinfo[gamemap-1]->weather)
{
case PRECIP_SNOW: // snow
case PRECIP_RAIN: // rain
case PRECIP_STORM: // storm
case PRECIP_STORM_NORAIN: // storm w/o rain
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
curWeather = mapheaderinfo[gamemap-1]->weather;
break;
default: // blank/none
curWeather = PRECIP_NONE;
break;
}
// Set globalweather
globalweather = mapheaderinfo[gamemap-1]->weather;
P_InitTagLists(); // Create xref tables for tags
}
/** After the map has loaded, scans for specials that spawn 3Dfloors and /** After the map has loaded, scans for specials that spawn 3Dfloors and
* thinkers. * thinkers.
* *
@ -5562,15 +5701,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
// but currently isn't. // but currently isn't.
(void)fromnetsave; (void)fromnetsave;
// Set the default gravity. Custom gravity overrides this setting.
gravity = FRACUNIT/2;
// Defaults in case levels don't have them set.
sstimer = 90*TICRATE + 6;
totalrings = 1;
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
// Init special SECTORs. // Init special SECTORs.
sector = sectors; sector = sectors;
for (i = 0; i < numsectors; i++, sector++) for (i = 0; i < numsectors; i++, sector++)
@ -5619,20 +5749,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
} }
} }
if (mapheaderinfo[gamemap-1]->weather == 2) // snow
curWeather = PRECIP_SNOW;
else if (mapheaderinfo[gamemap-1]->weather == 3) // rain
curWeather = PRECIP_RAIN;
else if (mapheaderinfo[gamemap-1]->weather == 1) // storm
curWeather = PRECIP_STORM;
else if (mapheaderinfo[gamemap-1]->weather == 5) // storm w/o rain
curWeather = PRECIP_STORM_NORAIN;
else if (mapheaderinfo[gamemap-1]->weather == 6) // storm w/o lightning
curWeather = PRECIP_STORM_NOSTRIKES;
else
curWeather = PRECIP_NONE;
P_InitTagLists(); // Create xref tables for tags
P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line
P_SpawnScrollers(); // Add generalized scrollers P_SpawnScrollers(); // Add generalized scrollers
@ -5909,15 +6025,15 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 66: // Displace floor by front sector case 66: // Displace floor by front sector
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s); P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB));
break; break;
case 67: // Displace ceiling by front sector case 67: // Displace ceiling by front sector
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s); P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB));
break; break;
case 68: // Displace both floor AND ceiling by front sector case 68: // Displace both floor AND ceiling by front sector
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s); P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB));
break; break;
case 100: // FOF (solid, opaque, shadows) case 100: // FOF (solid, opaque, shadows)
@ -7301,7 +7417,7 @@ static inline boolean PIT_PushThing(mobj_t *thing)
return false; return false;
// Allow this to affect pushable objects at some point? // Allow this to affect pushable objects at some point?
if (thing->player && (!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) || thing->player->pflags & PF_NIGHTSMODE)) if (thing->player && (!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) || thing->player->powers[pw_carry] == CR_NIGHTSMODE))
{ {
INT32 dist; INT32 dist;
INT32 speed; INT32 speed;
@ -7332,7 +7448,7 @@ static inline boolean PIT_PushThing(mobj_t *thing)
// Written with bits and pieces of P_HomingAttack // Written with bits and pieces of P_HomingAttack
if ((speed > 0) && (P_CheckSight(thing, tmpusher->source))) if ((speed > 0) && (P_CheckSight(thing, tmpusher->source)))
{ {
if (!(thing->player->pflags & PF_NIGHTSMODE)) if (thing->player->powers[pw_carry] != CR_NIGHTSMODE)
{ {
// only push wrt Z if health & 1 (mapthing has ambush flag) // only push wrt Z if health & 1 (mapthing has ambush flag)
if (tmpusher->source->health & 1) if (tmpusher->source->health & 1)
@ -7661,11 +7777,11 @@ void T_Pusher(pusher_t *p)
{ {
if (p->slider && thing->player) if (p->slider && thing->player)
{ {
boolean jumped = (thing->player->pflags & PF_JUMPED); pflags_t jumped = (thing->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE));
P_ResetPlayer (thing->player); P_ResetPlayer (thing->player);
if (jumped) if (jumped)
thing->player->pflags |= PF_JUMPED; thing->player->pflags |= jumped;
thing->player->pflags |= PF_SLIDING; thing->player->pflags |= PF_SLIDING;
P_SetPlayerMobjState (thing, thing->info->painstate); // Whee! P_SetPlayerMobjState (thing, thing->info->painstate); // Whee!

View file

@ -17,7 +17,9 @@
#ifndef __P_SPEC__ #ifndef __P_SPEC__
#define __P_SPEC__ #define __P_SPEC__
extern mobj_t *skyboxmo[2]; extern mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
extern mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
// GETSECSPECIAL (specialval, section) // GETSECSPECIAL (specialval, section)
// //
@ -32,6 +34,7 @@ void P_InitPicAnims(void);
void P_SetupLevelFlatAnims(void); void P_SetupLevelFlatAnims(void);
// at map load // at map load
void P_InitSpecials(void);
void P_SpawnSpecials(INT32 fromnetsave); void P_SpawnSpecials(INT32 fromnetsave);
// every tic // every tic
@ -458,6 +461,7 @@ typedef struct
INT32 control; ///< Control sector used to control plane positions. INT32 control; ///< Control sector used to control plane positions.
fixed_t last_height; ///< Last known height of control sector. fixed_t last_height; ///< Last known height of control sector.
fixed_t speed; ///< Plane movement speed. fixed_t speed; ///< Plane movement speed.
UINT8 reverse; ///< Move in reverse direction to control sector?
/** Types of plane displacement effects. /** Types of plane displacement effects.
*/ */
enum enum

View file

@ -163,6 +163,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle
if (playeringame[p] && players[p].mo && players[p].powers[pw_carry] == CR_PLAYER && players[p].mo->tracer == thing) if (playeringame[p] && players[p].mo && players[p].powers[pw_carry] == CR_PLAYER && players[p].mo->tracer == thing)
{ {
players[p].powers[pw_carry] = CR_NONE; players[p].powers[pw_carry] = CR_NONE;
P_SetTarget(&players[p].mo->tracer, NULL);
break; break;
} }
thing->player->cmomx = thing->player->cmomy = 0; thing->player->cmomx = thing->player->cmomy = 0;

File diff suppressed because it is too large Load diff

View file

@ -210,7 +210,7 @@ void R_PortalClearClipSegs(INT32 start, INT32 end)
// //
// It assumes that Doom has already ruled out a door being closed because // It assumes that Doom has already ruled out a door being closed because
// of front-back closure (e.g. front floor is taller than back ceiling). // of front-back closure (e.g. front floor is taller than back ceiling).
static inline INT32 R_DoorClosed(void) static INT32 R_DoorClosed(void)
{ {
return return
@ -1222,6 +1222,9 @@ static void R_Subsector(size_t num)
while (count--) while (count--)
{ {
// CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); // CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime);
#ifdef POLYOBJECTS
if (!line->polyseg) // ignore segs that belong to polyobjects
#endif
R_AddLine(line); R_AddLine(line);
line++; line++;
curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */ curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */

Some files were not shown because too many files have changed in this diff Show more