Merge remote-tracking branch 'refs/remotes/origin/zarrotsu' into attack-is-back

This commit is contained in:
TehRealSalt 2017-10-17 00:45:30 -04:00
commit cce7b4374a
65 changed files with 745 additions and 331 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.18
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.18.{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 GCC53=1 CCACHE=1 - set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1
build_script: build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean - cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean

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

@ -7,6 +7,23 @@
# and other things # and other things
# #
ifdef GCC63
GCC62=1
endif
ifdef GCC62
GCC61=1
endif
ifdef GCC61
GCC54=1
endif
ifdef GCC54
GCC53=1
endif
ifdef GCC53 ifdef GCC53
GCC52=1 GCC52=1
endif endif
@ -164,19 +181,29 @@ ifdef GCC45
WFLAGS+=-Wunsuffixed-float-constants WFLAGS+=-Wunsuffixed-float-constants
endif endif
endif endif
ifdef NOLDWARNING ifdef NOLDWARNING
LDFLAGS+=-Wl,--as-needed LDFLAGS+=-Wl,--as-needed
endif endif
ifdef ERRORMODE ifdef ERRORMODE
WFLAGS+=-Werror WFLAGS+=-Werror
endif endif
WFLAGS+=$(OLDWFLAGS)
ifdef GCC43 ifdef GCC43
#WFLAGS+=-Wno-error=clobbered #WFLAGS+=-Wno-error=clobbered
endif endif
ifdef GCC46 ifdef GCC46
WFLAGS+=-Wno-error=suggest-attribute=noreturn WFLAGS+=-Wno-error=suggest-attribute=noreturn
endif endif
WFLAGS+=$(OLDWFLAGS) ifdef GCC54
WFLAGS+=-Wno-logical-op -Wno-error=logical-op
endif
ifdef GCC61
WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare
endif
#indicate platform and what interface use with #indicate platform and what interface use with

View File

@ -2546,7 +2546,7 @@ static void Command_Ban(void)
return; return;
else 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);
@ -2554,7 +2554,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)
{ {
@ -2711,12 +2712,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)

View File

@ -716,6 +716,12 @@ void Net_CloseConnection(INT32 node)
if (!node) if (!node)
return; return;
if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
{
CONS_Alert(CONS_WARNING, 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)
@ -991,12 +997,14 @@ void Command_Droprate(void)
packetdroprate = droprate; packetdroprate = droprate;
} }
#ifndef NONET
static boolean ShouldDropPacket(void) static boolean ShouldDropPacket(void)
{ {
return (packetdropquantity[netbuffer->packettype]) return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100; || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
} }
#endif #endif
#endif
// //
// HSendPacket // HSendPacket

View File

@ -2155,7 +2155,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;
@ -2252,7 +2252,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;
@ -3006,6 +3006,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)
{ {
@ -3020,7 +3021,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))
@ -3032,7 +3035,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;
@ -3052,9 +3055,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);
@ -3062,11 +3063,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);
} }
@ -4141,7 +4139,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;
@ -4184,8 +4183,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

@ -6966,7 +6966,7 @@ static const char *const MOBJFLAG_LIST[] = {
"SHOOTABLE", "SHOOTABLE",
"NOSECTOR", "NOSECTOR",
"NOBLOCKMAP", "NOBLOCKMAP",
"AMBUSH", "PAPERCOLLISION",
"PUSHABLE", "PUSHABLE",
"BOSS", "BOSS",
"SPAWNCEILING", "SPAWNCEILING",
@ -7024,6 +7024,7 @@ static const char *const MOBJFLAG2_LIST[] = {
"BOSSNOTRAP", // No Egg Trap after boss "BOSSNOTRAP", // No Egg Trap after boss
"BOSSFLEE", // Boss is fleeing! "BOSSFLEE", // Boss is fleeing!
"BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) "BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
"AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH
NULL NULL
}; };
@ -7355,6 +7356,7 @@ struct {
// Frame settings // Frame settings
{"FF_FRAMEMASK",FF_FRAMEMASK}, {"FF_FRAMEMASK",FF_FRAMEMASK},
{"FF_PAPERSPRITE",FF_PAPERSPRITE},
{"FF_ANIMATE",FF_ANIMATE}, {"FF_ANIMATE",FF_ANIMATE},
{"FF_FULLBRIGHT",FF_FULLBRIGHT}, {"FF_FULLBRIGHT",FF_FULLBRIGHT},
{"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSMASK",FF_TRANSMASK},

View File

@ -1657,11 +1657,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;
@ -1682,11 +1677,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;

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

@ -4227,6 +4227,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 +4271,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;
@ -5064,6 +5066,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
UINT8 flip; UINT8 flip;
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;
@ -5078,7 +5084,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);
@ -5116,31 +5122,60 @@ 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 (sprframe->rotate) if (papersprite)
{ {
// choose a different rotation based on player view // Use the actual view angle, rather than the angle formed
ang = R_PointToAngle(thing->x, thing->y); // uses viewx,viewy // between the view point and the thing
rot = (ang-thing->angle+ANGLE_202h)>>29; // this makes sure paper sprites always appear at the right angle!
//Fab: lumpid is the index for spritewidth,spriteoffset... tables // Note: DO NOT do this in software mode version, it actually
lumpoff = sprframe->lumpid[rot]; // makes papersprites look WORSE there (I know, I've tried)
flip = sprframe->flip & (1<<rot); // 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 else if (sprframe->rotate != SRF_SINGLE)
ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
if (sprframe->rotate == SRF_SINGLE)
{ {
// use single rotation for all views // use single rotation for all views
rot = 0; //Fab: for vis->patch below rot = 0; //Fab: for vis->patch below
lumpoff = sprframe->lumpid[0]; //Fab: see note above lumpoff = sprframe->lumpid[0]; //Fab: see note above
flip = sprframe->flip; // Will only be 0x00 or 0xFF flip = sprframe->flip; // Will only be 0x00 or 0xFF
} }
else
{
// choose a different rotation based on player view
if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right
rot = 6; // F7 slot
else if ((ang >= ANGLE_180) && (sprframe->rotate & SRF_LEFT)) // See from left
rot = 2; // F3 slot
else // Normal behaviour
rot = (ang+ANGLE_202h)>>29;
//Fab: lumpid is the index for spritewidth,spriteoffset... tables
lumpoff = sprframe->lumpid[rot];
flip = sprframe->flip & (1<<rot);
}
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
// 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);
@ -5151,7 +5186,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 (thing->eflags & MFE_VERTICALFLIP) if (thing->eflags & MFE_VERTICALFLIP)
@ -5200,6 +5242,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

@ -1836,7 +1836,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
} }
} }
static inline void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color) static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{ {
INT32 val, count, pindex; INT32 val, count, pindex;
GLfloat s, t; GLfloat s, t;

View File

@ -3031,12 +3031,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392) if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392)
player->mo->friction += 1608; player->mo->friction += 1608;
// Splitscreen camera
if (splitscreen && player == &players[consoleplayer])
CV_SetValue(&cv_cam_dist, 190);
if (splitscreen && player == &players[secondarydisplayplayer])
CV_SetValue(&cv_cam2_dist, 190);
K_KartDrift(player, onground); K_KartDrift(player, onground);
// Quick Turning // Quick Turning

View File

@ -1054,7 +1054,7 @@ void OP_NightsObjectplace(player_t *player)
if (!OP_HeightOkay(player, false)) if (!OP_HeightOkay(player, false))
return; return;
if (player->mo->target->flags & MF_AMBUSH) if (player->mo->target->flags2 & MF2_AMBUSH)
angle = (UINT16)player->anotherflyangle; angle = (UINT16)player->anotherflyangle;
else else
{ {

View File

@ -3842,6 +3842,7 @@ static void M_ChangeLevel(INT32 choice)
static void M_ConfirmSpectate(INT32 choice) static void M_ConfirmSpectate(INT32 choice)
{ {
(void)choice; (void)choice;
// We allow switching to spectator even if team changing is not allowed
M_ClearMenus(true); M_ClearMenus(true);
COM_ImmedExecute("changeteam spectator"); COM_ImmedExecute("changeteam spectator");
} }
@ -3849,6 +3850,11 @@ static void M_ConfirmSpectate(INT32 choice)
static void M_ConfirmEnterGame(INT32 choice) static void M_ConfirmEnterGame(INT32 choice)
{ {
(void)choice; (void)choice;
if (!cv_allowteamchange.value)
{
M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING);
return;
}
M_ClearMenus(true); M_ClearMenus(true);
COM_ImmedExecute("changeteam playing"); COM_ImmedExecute("changeteam playing");
} }

View File

@ -585,7 +585,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;
} }

View File

@ -1111,7 +1111,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;
} }
@ -2634,7 +2634,7 @@ for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
newbox = spawnchance[P_RandomKey(numchoices)]; newbox = spawnchance[P_RandomKey(numchoices)];
item = mobjinfo[newbox].damage; item = mobjinfo[newbox].damage;
remains->flags &= ~MF_AMBUSH; remains->flags2 &= ~MF2_AMBUSH;
break; break;
} }
default: default:
@ -3454,7 +3454,7 @@ void A_BubbleSpawn(mobj_t *actor)
} }
actor->flags2 &= ~MF2_DONTDRAW; actor->flags2 &= ~MF2_DONTDRAW;
if (!(actor->flags & MF_AMBUSH)) if (!(actor->flags2 & MF2_AMBUSH))
{ {
// Quick! Look through players! // Quick! Look through players!
// Don't spawn bubbles unless a player is relatively close by (var2). // Don't spawn bubbles unless a player is relatively close by (var2).
@ -3502,7 +3502,7 @@ void A_FanBubbleSpawn(mobj_t *actor)
if (!(actor->eflags & MFE_UNDERWATER)) if (!(actor->eflags & MFE_UNDERWATER))
return; return;
if (!(actor->flags & MF_AMBUSH)) if (!(actor->flags2 & MF2_AMBUSH))
{ {
// Quick! Look through players! // Quick! Look through players!
// Don't spawn bubbles unless a player is relatively close by (var2). // Don't spawn bubbles unless a player is relatively close by (var2).
@ -4120,7 +4120,7 @@ void A_JetChase(mobj_t *actor)
return; return;
#endif #endif
if (actor->flags & MF_AMBUSH) if (actor->flags2 & MF2_AMBUSH)
return; return;
if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz
@ -5013,7 +5013,7 @@ void A_SlingAppear(mobj_t *actor)
if (firsttime) if (firsttime)
{ {
// This is the outermost link in the chain // This is the outermost link in the chain
spawnee->flags |= MF_AMBUSH; spawnee->flags2 |= MF2_AMBUSH;
firsttime = false; firsttime = false;
} }
@ -5998,7 +5998,7 @@ void A_Boss2Chase(mobj_t *actor)
{ {
actor->watertop = -actor->watertop; actor->watertop = -actor->watertop;
actor->extravalue1 = 18; actor->extravalue1 = 18;
if (actor->flags & MF_AMBUSH) if (actor->flags2 & MF2_AMBUSH)
actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2; actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2;
actor->extravalue2 = actor->extravalue1; actor->extravalue2 = actor->extravalue1;
} }
@ -6024,7 +6024,7 @@ void A_Boss2Chase(mobj_t *actor)
else else
{ {
// Only speed up if you have the 'Deaf' flag. // Only speed up if you have the 'Deaf' flag.
if (actor->flags & MF_AMBUSH) if (actor->flags2 & MF2_AMBUSH)
speedvar = actor->health; speedvar = actor->health;
else else
speedvar = actor->info->spawnhealth; speedvar = actor->info->spawnhealth;
@ -6615,7 +6615,7 @@ void A_BuzzFly(mobj_t *actor)
if (LUA_CallAction("A_BuzzFly", actor)) if (LUA_CallAction("A_BuzzFly", actor))
return; return;
#endif #endif
if (actor->flags & MF_AMBUSH) if (actor->flags2 & MF2_AMBUSH)
return; return;
if (actor->reactiontime) if (actor->reactiontime)
@ -6755,7 +6755,7 @@ void A_GuardChase(mobj_t *actor)
return; // got a new target return; // got a new target
// chase towards player // chase towards player
if (--actor->movecount < 0 || !P_Move(actor, (actor->flags & MF_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed))
{ {
P_NewChaseDir(actor); P_NewChaseDir(actor);
actor->movecount += 5; // Increase tics before change in direction allowed. actor->movecount += 5; // Increase tics before change in direction allowed.
@ -8139,7 +8139,7 @@ void A_ItemPop(mobj_t *actor)
else if (cv_debug && !(actor->target && actor->target->player)) else if (cv_debug && !(actor->target && actor->target->player))
CONS_Printf("ERROR: Powerup has no target!\n"); CONS_Printf("ERROR: Powerup has no target!\n");
remains->flags &= ~MF_AMBUSH; remains->flags2 &= ~MF2_AMBUSH;
P_RemoveMobj(actor); P_RemoveMobj(actor);
} }

View File

@ -1352,7 +1352,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
case MT_SMALLMACECHAIN: case MT_SMALLMACECHAIN:
case MT_BIGMACECHAIN: case MT_BIGMACECHAIN:
// Is this the last link in the chain? // Is this the last link in the chain?
if (toucher->momz > 0 || !(special->flags & MF_AMBUSH) if (toucher->momz > 0 || !(special->flags2 & MF2_AMBUSH)
|| (player->pflags & PF_ITEMHANG) || (player->pflags & PF_MACESPIN)) || (player->pflags & PF_ITEMHANG) || (player->pflags & PF_MACESPIN))
return; return;

View File

@ -492,6 +492,73 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
return true; // didn't hit it return true; // didn't hit it
if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing.
{
fixed_t cosradius, sinradius;
vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef
cosradius = FixedMul(thing->radius, FINECOSINE(thing->angle>>ANGLETOFINESHIFT));
sinradius = FixedMul(thing->radius, FINESINE(thing->angle>>ANGLETOFINESHIFT));
v1.x = thing->x - cosradius;
v1.y = thing->y - sinradius;
v2.x = thing->x + cosradius;
v2.y = thing->y + sinradius;
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = v2.x - v1.x;
junk.dy = v2.y - v1.y;
if (tmthing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues
{
INT32 check1, check2, check3, check4;
cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT));
sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT));
check1 = P_PointOnLineSide(tmx - cosradius, tmy - sinradius, &junk);
check2 = P_PointOnLineSide(tmx + cosradius, tmy + sinradius, &junk);
check3 = P_PointOnLineSide(tmx + tmthing->momx - cosradius, tmy + tmthing->momy - sinradius, &junk);
check4 = P_PointOnLineSide(tmx + tmthing->momx + cosradius, tmy + tmthing->momy + sinradius, &junk);
if ((check1 == check2) && (check2 == check3) && (check3 == check4))
return true; // the line doesn't cross between collider's start or end
}
else
{
if ((P_PointOnLineSide(tmx - tmthing->radius, tmy - tmthing->radius, &junk)
== P_PointOnLineSide(tmx + tmthing->radius, tmy + tmthing->radius, &junk))
&& (P_PointOnLineSide(tmx + tmthing->radius, tmy - tmthing->radius, &junk)
== P_PointOnLineSide(tmx - tmthing->radius, tmy + tmthing->radius, &junk)))
return true; // the line doesn't cross between either pair of opposite corners
}
}
else if (tmthing->flags & MF_PAPERCOLLISION)
{
fixed_t cosradius, sinradius;
vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef
cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT));
sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT));
v1.x = tmx - cosradius;
v1.y = tmy - sinradius;
v2.x = tmx + cosradius;
v2.y = tmy + sinradius;
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = v2.x - v1.x;
junk.dy = v2.y - v1.y;
// no need to check whether thing has MF_PAPERCOLLISION, since checked above
if ((P_PointOnLineSide(thing->x - thing->radius, thing->y - thing->radius, &junk)
== P_PointOnLineSide(thing->x + thing->radius, thing->y + thing->radius, &junk))
&& (P_PointOnLineSide(thing->x + thing->radius, thing->y - thing->radius, &junk)
== P_PointOnLineSide(thing->x - thing->radius, thing->y + thing->radius, &junk)))
return true; // the line doesn't cross between either pair of opposite corners
}
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
{ {
UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type
@ -1717,6 +1784,17 @@ static boolean PIT_CheckLine(line_t *ld)
if (P_BoxOnLineSide(tmbbox, ld) != -1) if (P_BoxOnLineSide(tmbbox, ld) != -1)
return true; return true;
if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag.
{
fixed_t cosradius, sinradius;
cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT));
sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT));
if (P_PointOnLineSide(tmx - cosradius, tmy - sinradius, ld)
== P_PointOnLineSide(tmx + cosradius, tmy + sinradius, ld))
return true; // the line doesn't cross between collider's start or end
}
// A line has been hit // A line has been hit
// The moving thing's destination position will cross // The moving thing's destination position will cross

View File

@ -2525,7 +2525,7 @@ static boolean P_ZMovement(mobj_t *mo)
&& abs(mom.y) < FixedMul(STOPSPEED, mo->scale) && abs(mom.y) < FixedMul(STOPSPEED, mo->scale)
&& abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) && abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale))
{ {
if (mo->flags & MF_AMBUSH) if (mo->flags2 & MF2_AMBUSH)
{ {
// If deafed, give the tumbleweed another random kick if it runs out of steam. // If deafed, give the tumbleweed another random kick if it runs out of steam.
mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale);
@ -6724,7 +6724,7 @@ void P_MobjThinker(mobj_t *mobj)
flame->angle = mobj->angle; flame->angle = mobj->angle;
if (mobj->flags & MF_AMBUSH) // Wave up and down instead of side-to-side if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side
flame->momz = mobj->fuse << (FRACBITS-2); flame->momz = mobj->fuse << (FRACBITS-2);
else else
flame->angle += FixedAngle(mobj->fuse*FRACUNIT); flame->angle += FixedAngle(mobj->fuse*FRACUNIT);
@ -6759,7 +6759,7 @@ void P_MobjThinker(mobj_t *mobj)
strength -= ((20*FRACUNIT)/16)*mobj->movedir; strength -= ((20*FRACUNIT)/16)*mobj->movedir;
// If deaf'd, the object spawns on the ceiling. // If deaf'd, the object spawns on the ceiling.
if (mobj->flags & MF_AMBUSH) if (mobj->flags2 & MF2_AMBUSH)
{ {
mobj->z = mobj->ceilingz-mobj->height; mobj->z = mobj->ceilingz-mobj->height;
flame->momz = -strength; flame->momz = -strength;
@ -7804,7 +7804,7 @@ void P_MobjThinker(mobj_t *mobj)
case MT_EGGMANBOX: // Eggman box case MT_EGGMANBOX: // Eggman box
case MT_GRAVITYBOX: // Gravity box case MT_GRAVITYBOX: // Gravity box
case MT_QUESTIONBOX: case MT_QUESTIONBOX:
if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) if ((mobj->flags2 & MF2_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX)
{ {
mobjtype_t spawnchance[64]; mobjtype_t spawnchance[64];
INT32 numchoices = 0, i = 0; INT32 numchoices = 0, i = 0;
@ -7832,11 +7832,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
i = P_RandomKey(numchoices); // Gotta love those random numbers! i = P_RandomKey(numchoices); // Gotta love those random numbers!
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]);
// If the monitor respawns randomly, transfer the flag. // Transfer flags2 (strongbox, objectflip, ambush)
if (mobj->flags & MF_AMBUSH)
newmobj->flags |= MF_AMBUSH;
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2; newmobj->flags2 = mobj->flags2;
} }
else else
@ -9786,7 +9782,7 @@ ML_NOCLIMB : Direction not controllable
if (firsttime) if (firsttime)
{ {
// This is the outermost link in the chain // This is the outermost link in the chain
spawnee->flags |= MF_AMBUSH; spawnee->flags2 |= MF2_AMBUSH;
firsttime = false; firsttime = false;
} }
@ -9858,7 +9854,7 @@ ML_NOCLIMB : Direction not controllable
{ {
// Inverted if uppermost bit is set // Inverted if uppermost bit is set
if (mthing->angle & 16384) if (mthing->angle & 16384)
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
if (mthing->angle > 0) if (mthing->angle > 0)
mobj->radius = (mthing->angle & 16383)*FRACUNIT; mobj->radius = (mthing->angle & 16383)*FRACUNIT;
@ -10039,7 +10035,7 @@ ML_NOCLIMB : Direction not controllable
mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum ||
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum || mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum) mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum)
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
} }
else if (mthing->type != mobjinfo[MT_AXIS].doomednum && else if (mthing->type != mobjinfo[MT_AXIS].doomednum &&
@ -10047,7 +10043,7 @@ ML_NOCLIMB : Direction not controllable
mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum && mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum &&
mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum && mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum &&
mthing->type != mobjinfo[MT_STARPOST].doomednum) mthing->type != mobjinfo[MT_STARPOST].doomednum)
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
} }
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
@ -10386,7 +10382,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
P_SetMobjState(mobj, mobj->info->seestate); P_SetMobjState(mobj, mobj->info->seestate);
mobj->angle = FixedAngle(mthing->angle*FRACUNIT); mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
mthing->mobj = mobj; mthing->mobj = mobj;
} }
// All manners of rings and coins // All manners of rings and coins
@ -10463,7 +10459,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
} }
mobj->angle = FixedAngle(mthing->angle*FRACUNIT); mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
mthing->mobj = mobj; mthing->mobj = mobj;
} }
// *** // ***
@ -10519,7 +10515,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
mobj->angle = FixedAngle(mthing->angle*FRACUNIT); mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
if (mthing->options & MTF_AMBUSH) if (mthing->options & MTF_AMBUSH)
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
} }
} }
// Diagonal rings (handles both types) // Diagonal rings (handles both types)
@ -10577,7 +10573,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
mobj->angle = FixedAngle(mthing->angle*FRACUNIT); mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
if (mthing->options & MTF_AMBUSH) if (mthing->options & MTF_AMBUSH)
mobj->flags |= MF_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
} }
} }
// Rings of items (all six of them) // Rings of items (all six of them)

View File

@ -107,8 +107,8 @@ typedef enum
MF_NOSECTOR = 1<<3, MF_NOSECTOR = 1<<3,
// Don't use the blocklinks (inert but displayable) // Don't use the blocklinks (inert but displayable)
MF_NOBLOCKMAP = 1<<4, MF_NOBLOCKMAP = 1<<4,
// Not to be activated by sound, deaf monster. // Thin, paper-like collision bound (for visual equivalent, see FF_PAPERSPRITE)
MF_AMBUSH = 1<<5, MF_PAPERCOLLISION = 1<<5,
// You can push this object. It can activate switches and things by pushing it on top. // You can push this object. It can activate switches and things by pushing it on top.
MF_PUSHABLE = 1<<6, MF_PUSHABLE = 1<<6,
// Object is a boss. // Object is a boss.
@ -193,6 +193,7 @@ typedef enum
MF2_BOSSNOTRAP = 1<<25, // No Egg Trap after boss MF2_BOSSNOTRAP = 1<<25, // No Egg Trap after boss
MF2_BOSSFLEE = 1<<26, // Boss is fleeing! MF2_BOSSFLEE = 1<<26, // Boss is fleeing!
MF2_BOSSDEAD = 1<<27, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) MF2_BOSSDEAD = 1<<27, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
MF2_AMBUSH = 1<<28, // Alternate behaviour typically set by MTF_AMBUSH
// free: to and including 1<<31 // free: to and including 1<<31
} mobjflag2_t; } mobjflag2_t;

View File

@ -36,7 +36,9 @@
#endif #endif
/// \brief Frame flags: only the frame number /// \brief Frame flags: only the frame number
#define FF_FRAMEMASK 0x3fff #define FF_FRAMEMASK 0x1ff
/// \brief Frame flags: Thin, paper-like sprite (for collision equivalent, see MF_PAPERCOLLISION)
#define FF_PAPERSPRITE 0x800
/// \brief Frame flags: Simple stateless animation /// \brief Frame flags: Simple stateless animation
#define FF_ANIMATE 0x4000 #define FF_ANIMATE 0x4000
/// \brief Frame flags: frame always appears full bright /// \brief Frame flags: frame always appears full bright

View File

@ -2547,8 +2547,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);
@ -2851,20 +2852,22 @@ boolean P_SetupLevel(boolean skipprecip)
} }
} }
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

@ -3044,7 +3044,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

View File

@ -631,7 +631,7 @@ static void P_DeNightserizePlayer(player_t *player)
if (!(mo2->type == MT_NIGHTSDRONE)) if (!(mo2->type == MT_NIGHTSDRONE))
continue; continue;
if (mo2->flags & MF_AMBUSH) if (mo2->flags2 & MF2_AMBUSH)
P_DamageMobj(player->mo, NULL, NULL, 10000); P_DamageMobj(player->mo, NULL, NULL, 10000);
break; break;
@ -5092,7 +5092,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
boolean transfer1last = false; boolean transfer1last = false;
boolean transfer2last = false; boolean transfer2last = false;
vertex_t vertices[4]; vertex_t vertices[4];
fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags & MF_AMBUSH ? -1 : 1); fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags2 & MF2_AMBUSH ? -1 : 1);
// Find next waypoint // Find next waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next) for (th = thinkercap.next; th != &thinkercap; th = th->next)
@ -5757,7 +5757,7 @@ static void P_NiGHTSMovement(player_t *player)
// The 'ambush' flag says you should rotate // The 'ambush' flag says you should rotate
// the other way around the axis. // the other way around the axis.
if (player->mo->target->flags & MF_AMBUSH) if (player->mo->target->flags2 & MF2_AMBUSH)
backwardaxis = true; backwardaxis = true;
player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y);
@ -8063,18 +8063,18 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0,
static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {45, "MAX"}, {0, NULL}}; static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {45, "MAX"}, {0, NULL}};
static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}}; static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}};
consvar_t cv_cam_dist = {"cam_dist", "128", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_dist = {"cam_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam_height = {"cam_height", "40", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_height = {"cam_height", "50", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam_speed = {"cam_speed", "0.25", CV_FLOAT, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_speed = {"cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", 0, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam2_dist = {"cam2_dist", "128", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_dist = {"cam2_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam2_height = {"cam2_height", "40", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_height = {"cam2_height", "50", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam2_speed = {"cam2_speed", "0.25", CV_FLOAT, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_speed = {"cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", 0, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
fixed_t t_cam_dist = -42; fixed_t t_cam_dist = -42;
fixed_t t_cam_height = -42; fixed_t t_cam_height = -42;
@ -8128,7 +8128,7 @@ void P_ResetCamera(player_t *player, 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)
{ {
angle_t angle = 0, focusangle = 0, focusaiming = 0; angle_t angle = 0, focusangle = 0, focusaiming = 0;
fixed_t x, y, z, dist, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; fixed_t x, y, z, dist, height, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
INT32 camrotate; INT32 camrotate;
boolean camstill, cameranoclip; boolean camstill, cameranoclip;
mobj_t *mo; mobj_t *mo;
@ -8250,7 +8250,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
} }
else if (player->mo->target) else if (player->mo->target)
{ {
if (player->mo->target->flags & MF_AMBUSH) if (player->mo->target->flags2 & MF2_AMBUSH)
angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y);
else else
angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y); angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y);
@ -8354,6 +8354,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
} }
*/ */
height = camheight;
// sets ideal cam pos // sets ideal cam pos
if (twodlevel || (mo->flags2 & MF2_TWOD)) if (twodlevel || (mo->flags2 & MF2_TWOD))
dist = 480<<FRACBITS; dist = 480<<FRACBITS;
@ -8363,6 +8365,20 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
{ {
dist = camdist; dist = camdist;
// x1.5 dist for splitscreen
if (splitscreen)
{
dist = FixedMul(dist, 3*FRACUNIT/2);
height = FixedMul(height, 3*FRACUNIT/2);
}
// x1.2 dist for analog
if (P_AnalogMove(player))
{
dist = FixedMul(dist, 6*FRACUNIT/5);
height = FixedMul(height, 6*FRACUNIT/5);
}
if (player->climbing || player->exiting || player->playerstate == PST_DEAD || (player->pflags & (PF_MACESPIN|PF_ITEMHANG|PF_ROPEHANG))) if (player->climbing || player->exiting || player->playerstate == PST_DEAD || (player->pflags & (PF_MACESPIN|PF_ITEMHANG|PF_ROPEHANG)))
dist <<= 1; dist <<= 1;
} }

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

View File

@ -722,23 +722,35 @@ typedef struct
#pragma pack() #pragma pack()
#endif #endif
typedef enum
{
SRF_SINGLE = 0, // 0-angle for all rotations
SRF_3D = 1, // Angles 1-8
SRF_LEFT = 2, // Left side has single patch
SRF_RIGHT = 4, // Right side has single patch
SRF_2D = 6, // SRF_LEFT|SRF_RIGHT
SRF_NONE = 0xff // Initial value
} spriterotateflags_t; // SRF's up!
// //
// Sprites are patches with a special naming convention so they can be // Sprites are patches with a special naming convention so they can be
// recognized by R_InitSprites. // recognized by R_InitSprites.
// The base name is NNNNFx or NNNNFxFx, with x indicating the rotation, // The base name is NNNNFx or NNNNFxFx, with x indicating the rotation,
// x = 0, 1-7. // x = 0, 1-8, L/R
// The sprite and frame specified by a thing_t is range checked at run time. // The sprite and frame specified by a thing_t is range checked at run time.
// A sprite is a patch_t that is assumed to represent a three dimensional // A sprite is a patch_t that is assumed to represent a three dimensional
// object and may have multiple rotations predrawn. // object and may have multiple rotations predrawn.
// Horizontal flipping is used to save space, thus NNNNF2F5 defines a mirrored patch. // Horizontal flipping is used to save space, thus NNNNF2F5 defines a mirrored patch.
// Some sprites will only have one picture used for all views: NNNNF0 // Some sprites will only have one picture used for all views: NNNNF0
// Some sprites will take the entirety of the left side: NNNNFL
// Or the right side: NNNNFR
// Or both, mirrored: NNNNFLFR
// //
typedef struct typedef struct
{ {
// If false use 0 for any position.
// Note: as eight entries are available, we might as well insert the same // Note: as eight entries are available, we might as well insert the same
// name eight times. // name eight times.
UINT8 rotate; UINT8 rotate; // see spriterotateflags_t above
// Lump to use for view angles 0-7. // Lump to use for view angles 0-7.
lumpnum_t lumppat[8]; // lump number 16 : 16 wad : lump lumpnum_t lumppat[8]; // lump number 16 : 16 wad : lump

View File

@ -101,7 +101,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
lumppat <<= 16; lumppat <<= 16;
lumppat += lump; lumppat += lump;
if (frame >= 64 || rotation > 8) if (frame >= 64 || !(R_ValidSpriteAngle(rotation)))
I_Error("R_InstallSpriteLump: Bad frame characters in lump %s", W_CheckNameForNum(lumppat)); I_Error("R_InstallSpriteLump: Bad frame characters in lump %s", W_CheckNameForNum(lumppat));
if (maxframe ==(size_t)-1 || frame > maxframe) if (maxframe ==(size_t)-1 || frame > maxframe)
@ -110,31 +110,65 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
if (rotation == 0) if (rotation == 0)
{ {
// the lump should be used for all rotations // the lump should be used for all rotations
if (sprtemp[frame].rotate == 0) if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate != SRF_NONE) // Let's complain for both 1-8 and L/R rotations.
if (sprtemp[frame].rotate == 1)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn);
sprtemp[frame].rotate = 0; sprtemp[frame].rotate = SRF_SINGLE;
for (r = 0; r < 8; r++) for (r = 0; r < 8; r++)
{ {
sprtemp[frame].lumppat[r] = lumppat; sprtemp[frame].lumppat[r] = lumppat;
sprtemp[frame].lumpid[r] = lumpid; sprtemp[frame].lumpid[r] = lumpid;
} }
sprtemp[frame].flip = flipped ? UINT8_MAX : 0; sprtemp[frame].flip = flipped ? UINT8_MAX : 0; // 11111111 in binary
return;
}
if (rotation == ROT_L || rotation == ROT_R)
{
UINT8 rightfactor = ((rotation == ROT_R) ? 4 : 0);
// the lump should be used for half of all rotations
if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate == SRF_3D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
// Let's not complain about multiple L/R rotations. It's not worth the effort.
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
if (sprtemp[frame].rotate == (SRF_3D|SRF_2D))
sprtemp[frame].rotate = SRF_2D; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
for (r = 0; r < 4; r++) // Thanks to R_PrecacheLevel, we can't leave sprtemp[*].lumppat[*] == LUMPERROR... so we load into the front/back angle too.
{
sprtemp[frame].lumppat[r + rightfactor] = lumppat;
sprtemp[frame].lumpid[r + rightfactor] = lumpid;
}
sprtemp[frame].flip |= (flipped ? (0x0F << rightfactor) : 0); // 00001111 or 11110000 in binary, depending on rotation being ROT_L or ROT_R
return; return;
} }
// the lump is only used for one rotation // the lump is only used for one rotation
if (sprtemp[frame].rotate == 0) if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8 rotations and a rot = 0 lump\n", spritename, cn);
else if ((sprtemp[frame].rotate != SRF_3D) && (sprtemp[frame].rotate != SRF_NONE))
sprtemp[frame].rotate = 1; CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
// make 0 based // make 0 based
rotation--; rotation--;
if (rotation == 0 || rotation == 4) // Front or back...
sprtemp[frame].rotate = SRF_3D; // Prevent L and R changeover
else if (rotation > 3) // Right side
sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover
else // if (rotation <= 3) // Left side
sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover
if (sprtemp[frame].lumppat[rotation] != LUMPERROR) if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation);
@ -196,7 +230,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
frame = R_Char2Frame(lumpinfo[l].name[4]); frame = R_Char2Frame(lumpinfo[l].name[4]);
rotation = (UINT8)(lumpinfo[l].name[5] - '0'); rotation = (UINT8)(lumpinfo[l].name[5] - '0');
if (frame >= 64 || rotation > 8) // Give an actual NAME error -_-... if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) // Give an actual NAME error -_-...
{ {
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l)); CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue; continue;
@ -279,16 +313,23 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
{ {
switch (sprtemp[frame].rotate) switch (sprtemp[frame].rotate)
{ {
case 0xff: case SRF_NONE:
// no rotations were found for that frame at all // no rotations were found for that frame at all
I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame)); I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
break; break;
case 0: case SRF_SINGLE:
// only the first rotation is needed // only the first rotation is needed
break; break;
case 1: case SRF_2D: // both Left and Right rotations
// we test to see whether the left and right slots are present
if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations",
sprname, R_Frame2Char(frame));
break;
default:
// must have all 8 frames // must have all 8 frames
for (rotation = 0; rotation < 8; rotation++) for (rotation = 0; rotation < 8; rotation++)
// we test the patch lump, or the id lump whatever // we test the patch lump, or the id lump whatever
@ -755,11 +796,18 @@ static void R_DrawVisSprite(vissprite_t *vis)
if (overflow_test < 0) overflow_test = -overflow_test; if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
if (vis->scalestep) // handles right edge too
{
overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*(vis->scale + (vis->scalestep*(vis->x2 - vis->x1))))>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto
}
colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap; dc_colormap = vis->colormap;
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"
{ {
// translate green skin to another color // translate certain pixels to white
colfunc = transcolfunc; colfunc = transcolfunc;
if (vis->mobj->type == MT_CYBRAKDEMON) if (vis->mobj->type == MT_CYBRAKDEMON)
dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
@ -815,13 +863,10 @@ static void R_DrawVisSprite(vissprite_t *vis)
if (!dc_colormap) if (!dc_colormap)
dc_colormap = colormaps; dc_colormap = colormaps;
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
dc_texturemid = vis->texturemid; dc_texturemid = vis->texturemid;
dc_texheight = 0; dc_texheight = 0;
frac = vis->startfrac; frac = vis->startfrac;
spryscale = vis->scale;
sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
windowtop = windowbottom = sprbotscreen = INT32_MAX; windowtop = windowbottom = sprbotscreen = INT32_MAX;
if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES)
@ -833,28 +878,29 @@ static void R_DrawVisSprite(vissprite_t *vis)
if (!vis->isScaled) if (!vis->isScaled)
{ {
vis->scale = FixedMul(vis->scale, this_scale); vis->scale = FixedMul(vis->scale, this_scale);
spryscale = vis->scale; vis->scalestep = FixedMul(vis->scalestep, this_scale);
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
vis->xiscale = FixedDiv(vis->xiscale,this_scale); vis->xiscale = FixedDiv(vis->xiscale,this_scale);
vis->isScaled = true; vis->isScaled = true;
} }
dc_texturemid = FixedDiv(dc_texturemid,this_scale); dc_texturemid = FixedDiv(dc_texturemid,this_scale);
}
//Oh lordy, mercy me. Don't freak out if sprites go offscreen! spryscale = vis->scale;
/*if (vis->xiscale > 0)
frac = FixedDiv(frac, this_scale);
else if (vis->x1 <= 0)
frac = (vis->x1 - vis->x2) * vis->xiscale;*/
if (!(vis->scalestep))
{
sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
//dc_hires = 1; dc_iscale = FixedDiv(FRACUNIT, vis->scale);
} }
x1 = vis->x1; x1 = vis->x1;
x2 = vis->x2; x2 = vis->x2;
if (vis->x1 < 0) if (vis->x1 < 0)
{
spryscale += vis->scalestep*(-vis->x1);
vis->x1 = 0; vis->x1 = 0;
}
if (vis->x2 >= vid.width) if (vis->x2 >= vid.width)
vis->x2 = vid.width-1; vis->x2 = vid.width-1;
@ -870,10 +916,16 @@ static void R_DrawVisSprite(vissprite_t *vis)
#else #else
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS]));
#endif #endif
if (vis->scalestep)
{
sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
dc_iscale = (0xffffffffu / (unsigned)spryscale);
}
if (vis->vflip) if (vis->vflip)
R_DrawFlippedMaskedColumn(column, patch->height); R_DrawFlippedMaskedColumn(column, patch->height);
else else
R_DrawMaskedColumn(column); R_DrawMaskedColumn(column);
spryscale += vis->scalestep;
} }
colfunc = basecolfunc; colfunc = basecolfunc;
@ -892,12 +944,18 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
#endif #endif
fixed_t frac; fixed_t frac;
patch_t *patch; patch_t *patch;
INT64 overflow_test;
//Fab : R_InitSprites now sets a wad lump number //Fab : R_InitSprites now sets a wad lump number
patch = W_CacheLumpNum(vis->patch, PU_CACHE); patch = W_CacheLumpNum(vis->patch, PU_CACHE);
if (!patch) if (!patch)
return; return;
// Check for overflow
overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
if (vis->transmap) if (vis->transmap)
{ {
colfunc = fuzzcolfunc; colfunc = fuzzcolfunc;
@ -968,7 +1026,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
if (testheight <= sprite->gz) if (testheight <= sprite->gz)
return; return;
cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->scale))>>FRACBITS); cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->sortscale))>>FRACBITS);
if (cutfrac < 0) if (cutfrac < 0)
continue; continue;
if (cutfrac > viewheight) if (cutfrac > viewheight)
@ -1041,7 +1099,7 @@ static void R_ProjectSprite(mobj_t *thing)
fixed_t tr_x, tr_y; fixed_t tr_x, tr_y;
fixed_t gxt, gyt; fixed_t gxt, gyt;
fixed_t tx, tz; fixed_t tx, tz;
fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! fixed_t xscale, yscale, sortscale; //added : 02-02-98 : aaargll..if I were a math-guy!!!
INT32 x1, x2; INT32 x1, x2;
@ -1056,8 +1114,11 @@ static void R_ProjectSprite(mobj_t *thing)
vissprite_t *vis; vissprite_t *vis;
angle_t ang; angle_t ang = 0; // gcc 4.6 and lower fix
fixed_t iscale; fixed_t iscale;
fixed_t scalestep; // toast '16
fixed_t offset, offset2;
boolean papersprite = (thing->frame & FF_PAPERSPRITE);
//SoM: 3/17/2000 //SoM: 3/17/2000
fixed_t gz, gzt; fixed_t gz, gzt;
@ -1065,6 +1126,8 @@ static void R_ProjectSprite(mobj_t *thing)
INT32 light = 0; INT32 light = 0;
fixed_t this_scale = thing->scale; fixed_t this_scale = thing->scale;
fixed_t ang_scale = FRACUNIT;
// transform the origin point // transform the origin point
tr_x = thing->x - viewx; tr_x = thing->x - viewx;
tr_y = thing->y - viewy; tr_y = thing->y - viewy;
@ -1075,7 +1138,7 @@ static void R_ProjectSprite(mobj_t *thing)
tz = gxt-gyt; tz = gxt-gyt;
// thing is behind view plane? // thing is behind view plane?
if (tz < FixedMul(MINZ, this_scale)) if (!(papersprite) && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later
return; return;
gxt = -FixedMul(tr_x, viewsin); gxt = -FixedMul(tr_x, viewsin);
@ -1088,7 +1151,7 @@ static void R_ProjectSprite(mobj_t *thing)
// aspect ratio stuff // aspect ratio stuff
xscale = FixedDiv(projection, tz); xscale = FixedDiv(projection, tz);
yscale = FixedDiv(projectiony, tz); sortscale = FixedDiv(projectiony, tz);
// decide which patch to use for sprite relative to player // decide which patch to use for sprite relative to player
#ifdef RANGECHECK #ifdef RANGECHECK
@ -1130,22 +1193,36 @@ static void R_ProjectSprite(mobj_t *thing)
I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite); I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite);
#endif #endif
if (sprframe->rotate) if (sprframe->rotate != SRF_SINGLE || papersprite)
{ {
// choose a different rotation based on player view ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
ang = R_PointToAngle (thing->x, thing->y); if (papersprite)
rot = (ang-thing->angle+ANGLE_202h)>>29; ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT));
//Fab: lumpid is the index for spritewidth,spriteoffset... tables
lump = sprframe->lumpid[rot];
flip = sprframe->flip & (1<<rot);
} }
else
if (sprframe->rotate == SRF_SINGLE)
{ {
// use single rotation for all views // use single rotation for all views
rot = 0; //Fab: for vis->patch below rot = 0; //Fab: for vis->patch below
lump = sprframe->lumpid[0]; //Fab: see note above lump = sprframe->lumpid[0]; //Fab: see note above
flip = sprframe->flip; // Will only be 0x00 or 0xFF flip = sprframe->flip; // Will only be 0x00 or 0xFF
} }
else
{
// choose a different rotation based on player view
//ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right
rot = 6; // F7 slot
else if ((ang >= ANGLE_180) && (sprframe->rotate & SRF_LEFT)) // See from left
rot = 2; // F3 slot
else // Normal behaviour
rot = (ang+ANGLE_202h)>>29;
//Fab: lumpid is the index for spritewidth,spriteoffset... tables
lump = sprframe->lumpid[rot];
flip = sprframe->flip & (1<<rot);
}
I_Assert(lump < max_spritelumps); I_Assert(lump < max_spritelumps);
@ -1154,22 +1231,77 @@ static void R_ProjectSprite(mobj_t *thing)
// calculate edges of the shape // calculate edges of the shape
if (flip) if (flip)
tx -= FixedMul(spritecachedinfo[lump].width-spritecachedinfo[lump].offset, this_scale); offset = spritecachedinfo[lump].offset - spritecachedinfo[lump].width;
else else
tx -= FixedMul(spritecachedinfo[lump].offset, this_scale); offset = -spritecachedinfo[lump].offset;
offset = FixedMul(offset, this_scale);
tx += FixedMul(offset, ang_scale);
x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS; x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
// off the right side? // off the right side?
if (x1 > viewwidth) if (x1 > viewwidth)
return; return;
tx += FixedMul(spritecachedinfo[lump].width, this_scale); offset2 = FixedMul(spritecachedinfo[lump].width, this_scale);
tx += FixedMul(offset2, ang_scale);
x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1; x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1;
// off the left side // off the left side
if (x2 < 0) if (x2 < 0)
return; return;
if (papersprite)
{
fixed_t yscale2, cosmul, sinmul, tz2;
INT32 range;
if (ang >= ANGLE_180)
{
offset *= -1;
offset2 *= -1;
}
cosmul = FINECOSINE(thing->angle>>ANGLETOFINESHIFT);
sinmul = FINESINE(thing->angle>>ANGLETOFINESHIFT);
tr_x += FixedMul(offset, cosmul);
tr_y += FixedMul(offset, sinmul);
gxt = FixedMul(tr_x, viewcos);
gyt = -FixedMul(tr_y, viewsin);
tz = gxt-gyt;
yscale = FixedDiv(projectiony, tz);
if (yscale < 64) return; // Fix some funky visuals
tr_x += FixedMul(offset2, cosmul);
tr_y += FixedMul(offset2, sinmul);
gxt = FixedMul(tr_x, viewcos);
gyt = -FixedMul(tr_y, viewsin);
tz2 = gxt-gyt;
yscale2 = FixedDiv(projectiony, tz2);
if (yscale2 < 64) return; // ditto
if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
return;
if (x2 > x1)
range = (x2 - x1);
else
range = 1;
scalestep = (yscale2 - yscale)/range;
// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
// sortscale = max(yscale, yscale2);
// sortscale = min(yscale, yscale2);
}
else
{
scalestep = 0;
yscale = sortscale;
}
xscale = FixedMul(xscale, ang_scale);
// PORTAL SPRITE CLIPPING // PORTAL SPRITE CLIPPING
if (portalrender) if (portalrender)
{ {
@ -1251,6 +1383,7 @@ static void R_ProjectSprite(mobj_t *thing)
vis->heightsec = heightsec; //SoM: 3/17/2000 vis->heightsec = heightsec; //SoM: 3/17/2000
vis->mobjflags = thing->flags; vis->mobjflags = thing->flags;
vis->scale = yscale; //<<detailshift; vis->scale = yscale; //<<detailshift;
vis->sortscale = sortscale;
vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15 vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15
vis->gx = thing->x; vis->gx = thing->x;
vis->gy = thing->y; vis->gy = thing->y;
@ -1260,6 +1393,7 @@ static void R_ProjectSprite(mobj_t *thing)
vis->pz = thing->z; vis->pz = thing->z;
vis->pzt = vis->pz + vis->thingheight; vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz; vis->texturemid = vis->gzt - viewz;
vis->scalestep = scalestep;
vis->mobj = thing; // Easy access! Tails 06-07-2002 vis->mobj = thing; // Easy access! Tails 06-07-2002
@ -1277,8 +1411,8 @@ static void R_ProjectSprite(mobj_t *thing)
vis->xscale = xscale; //SoM: 4/17/2000 vis->xscale = xscale; //SoM: 4/17/2000
vis->sector = thing->subsector->sector; vis->sector = thing->subsector->sector;
vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS);
vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS);
vis->cut = SC_NONE; vis->cut = SC_NONE;
if (thing->subsector->sector->numlights) if (thing->subsector->sector->numlights)
vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap; vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap;
@ -1299,7 +1433,10 @@ static void R_ProjectSprite(mobj_t *thing)
} }
if (vis->x1 > x1) if (vis->x1 > x1)
{
vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1); vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1);
vis->scale += scalestep*(vis->x1 - x1);
}
//Fab: lumppat is the lump number of the patch to use, this is different //Fab: lumppat is the lump number of the patch to use, this is different
// than lumpid for sprites-in-pwad : the graphics are patched // than lumpid for sprites-in-pwad : the graphics are patched
@ -1458,7 +1595,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
// store information in a vissprite // store information in a vissprite
vis = R_NewVisSprite(); vis = R_NewVisSprite();
vis->scale = yscale; //<<detailshift; vis->scale = vis->sortscale = yscale; //<<detailshift;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15 vis->dispoffset = 0; // Monster Iestyn: 23/11/15
vis->gx = thing->x; vis->gx = thing->x;
vis->gy = thing->y; vis->gy = thing->y;
@ -1468,6 +1605,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->pz = thing->z; vis->pz = thing->z;
vis->pzt = vis->pz + vis->thingheight; vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz; vis->texturemid = vis->gzt - viewz;
vis->scalestep = 0;
vis->x1 = x1 < 0 ? 0 : x1; vis->x1 = x1 < 0 ? 0 : x1;
vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
@ -1646,14 +1784,14 @@ void R_SortVisSprites(void)
bestscale = bestdispoffset = INT32_MAX; bestscale = bestdispoffset = INT32_MAX;
for (ds = unsorted.next; ds != &unsorted; ds = ds->next) for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
{ {
if (ds->scale < bestscale) if (ds->sortscale < bestscale)
{ {
bestscale = ds->scale; bestscale = ds->sortscale;
bestdispoffset = ds->dispoffset; bestdispoffset = ds->dispoffset;
best = ds; best = ds;
} }
// order visprites of same scale by dispoffset, smallest first // order visprites of same scale by dispoffset, smallest first
else if (ds->scale == bestscale && ds->dispoffset < bestdispoffset) else if (ds->sortscale == bestscale && ds->dispoffset < bestdispoffset)
{ {
bestdispoffset = ds->dispoffset; bestdispoffset = ds->dispoffset;
best = ds; best = ds;
@ -1844,7 +1982,7 @@ static void R_CreateDrawNodes(void)
{ {
for (i = x1; i <= x2; i++) for (i = x1; i <= x2; i++)
{ {
if (r2->seg->frontscale[i] > rover->scale) if (r2->seg->frontscale[i] > rover->sortscale)
break; break;
} }
if (i > x2) if (i > x2)
@ -1864,10 +2002,10 @@ static void R_CreateDrawNodes(void)
continue; continue;
scale = r2->thickseg->scale1 > r2->thickseg->scale2 ? r2->thickseg->scale1 : r2->thickseg->scale2; scale = r2->thickseg->scale1 > r2->thickseg->scale2 ? r2->thickseg->scale1 : r2->thickseg->scale2;
if (scale <= rover->scale) if (scale <= rover->sortscale)
continue; continue;
scale = r2->thickseg->scale1 + (r2->thickseg->scalestep * (sintersect - r2->thickseg->x1)); scale = r2->thickseg->scale1 + (r2->thickseg->scalestep * (sintersect - r2->thickseg->x1));
if (scale <= rover->scale) if (scale <= rover->sortscale)
continue; continue;
#ifdef ESLOPE #ifdef ESLOPE
@ -1917,11 +2055,11 @@ static void R_CreateDrawNodes(void)
continue; continue;
scale = r2->seg->scale1 > r2->seg->scale2 ? r2->seg->scale1 : r2->seg->scale2; scale = r2->seg->scale1 > r2->seg->scale2 ? r2->seg->scale1 : r2->seg->scale2;
if (scale <= rover->scale) if (scale <= rover->sortscale)
continue; continue;
scale = r2->seg->scale1 + (r2->seg->scalestep * (sintersect - r2->seg->x1)); scale = r2->seg->scale1 + (r2->seg->scalestep * (sintersect - r2->seg->x1));
if (rover->scale < scale) if (rover->sortscale < scale)
{ {
entry = R_CreateDrawNode(NULL); entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry; (entry->prev = r2->prev)->next = entry;
@ -1937,8 +2075,8 @@ static void R_CreateDrawNodes(void)
if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt)
continue; continue;
if (r2->sprite->scale > rover->scale if (r2->sprite->sortscale > rover->sortscale
|| (r2->sprite->scale == rover->scale && r2->sprite->dispoffset > rover->dispoffset)) || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset))
{ {
entry = R_CreateDrawNode(NULL); entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry; (entry->prev = r2->prev)->next = entry;
@ -2091,8 +2229,8 @@ void R_ClipSprites(void)
scale = ds->scale2; scale = ds->scale2;
} }
if (scale < spr->scale || if (scale < spr->sortscale ||
(lowscale < spr->scale && (lowscale < spr->sortscale &&
!R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) !R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
{ {
// masked mid texture? // masked mid texture?
@ -2143,7 +2281,7 @@ void R_ClipSprites(void)
fixed_t mh, h; fixed_t mh, h;
INT32 phs = viewplayer->mo->subsector->sector->heightsec; INT32 phs = viewplayer->mo->subsector->sector->heightsec;
if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && if ((mh = sectors[spr->heightsec].floorheight) > spr->gz &&
(h = centeryfrac - FixedMul(mh -= viewz, spr->scale)) >= 0 && (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 &&
(h >>= FRACBITS) < viewheight) (h >>= FRACBITS) < viewheight)
{ {
if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight))
@ -2161,7 +2299,7 @@ void R_ClipSprites(void)
} }
if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt &&
(h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 &&
(h >>= FRACBITS) < viewheight) (h >>= FRACBITS) < viewheight)
{ {
if (phs != -1 && viewz >= sectors[phs].ceilingheight) if (phs != -1 && viewz >= sectors[phs].ceilingheight)

View File

@ -17,6 +17,10 @@
#include "sounds.h" #include "sounds.h"
#include "r_plane.h" #include "r_plane.h"
// "Left" and "Right" character symbols for additional rotation functionality
#define ROT_L ('L' - '0')
#define ROT_R ('R' - '0')
// number of sprite lumps for spritewidth,offset,topoffset lookup tables // number of sprite lumps for spritewidth,offset,topoffset lookup tables
// Fab: this is a hack : should allocate the lookup tables per sprite // Fab: this is a hack : should allocate the lookup tables per sprite
#define MAXVISSPRITES 2048 // added 2-2-98 was 128 #define MAXVISSPRITES 2048 // added 2-2-98 was 128
@ -136,7 +140,8 @@ typedef struct vissprite_s
fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors
fixed_t startfrac; // horizontal position of x1 fixed_t startfrac; // horizontal position of x1
fixed_t scale; fixed_t scale, sortscale; // sortscale only differs from scale for flat sprites
fixed_t scalestep; // only for flat sprites, 0 otherwise
fixed_t xiscale; // negative if flipped fixed_t xiscale; // negative if flipped
fixed_t texturemid; fixed_t texturemid;
@ -235,4 +240,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn)
#endif #endif
} }
FUNCMATH FUNCINLINE static ATTRINLINE boolean R_ValidSpriteAngle(UINT8 rotation)
{
return ((rotation <= 8) || (rotation == ROT_L) || (rotation == ROT_R));
}
#endif //__R_THINGS__ #endif //__R_THINGS__

View File

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.17; CURRENT_PROJECT_VERSION = 2.1.18;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.17; CURRENT_PROJECT_VERSION = 2.1.18;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View File

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.17; CURRENT_PROJECT_VERSION = 2.1.18;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.17; CURRENT_PROJECT_VERSION = 2.1.18;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View File

@ -758,79 +758,80 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
{ {
UINT8 *dest; UINT8 *dest;
const UINT8 *deststop; const UINT8 *deststop;
INT32 u, v, dupx, dupy;
if (rendermode == render_none)
return;
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode != render_soft && rendermode != render_none) if (rendermode != render_soft && !con_startup)
{ {
HWR_DrawFill(x, y, w, h, c); HWR_DrawFill(x, y, w, h, c);
return; return;
} }
#endif #endif
dupx = vid.dupx; if (!(c & V_NOSCALESTART))
dupy = vid.dupy;
if (!screens[0])
return;
if (c & V_NOSCALESTART)
{
dest = screens[0] + y*vid.width + x;
deststop = screens[0] + vid.rowbytes * vid.height;
}
else
{ {
INT32 dupx = vid.dupx, dupy = vid.dupy;
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
{ // Clear the entire screen, from dest to deststop. Yes, this really works. { // Clear the entire screen, from dest to deststop. Yes, this really works.
memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp); memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
return; return;
} }
dest = screens[0] + y*dupy*vid.width + x*dupx; x *= dupx;
deststop = screens[0] + vid.rowbytes * vid.height; y *= dupy;
w *= dupx;
h *= dupy;
if (w == BASEVIDWIDTH) // Center it if necessary
w = vid.width; if (vid.width != BASEVIDWIDTH * dupx)
else
w *= dupx;
if (h == BASEVIDHEIGHT)
h = vid.height;
else
h *= dupy;
if (x && y && x + w < vid.width && y + h < vid.height)
{ {
// Center it if necessary // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
if (vid.width != BASEVIDWIDTH * dupx) // so center this imaginary screen
{ if (c & V_SNAPTORIGHT)
// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, x += (vid.width - (BASEVIDWIDTH * dupx));
// so center this imaginary screen else if (!(c & V_SNAPTOLEFT))
if (c & V_SNAPTORIGHT) x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
dest += (vid.width - (BASEVIDWIDTH * dupx)); }
else if (!(c & V_SNAPTOLEFT)) if (vid.height != BASEVIDHEIGHT * dupy)
dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2; {
} // same thing here
if (vid.height != BASEVIDHEIGHT * dupy) if (c & V_SNAPTOBOTTOM)
{ y += (vid.height - (BASEVIDHEIGHT * dupy));
// same thing here else if (!(c & V_SNAPTOTOP))
if (c & V_SNAPTOBOTTOM) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
else if (!(c & V_SNAPTOTOP))
dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
}
} }
} }
if (x >= vid.width || y >= vid.height)
return; // off the screen
if (x < 0)
{
w += x;
x = 0;
}
if (y < 0)
{
h += y;
y = 0;
}
if (w <= 0 || h <= 0)
return; // zero width/height wouldn't draw anything
if (x + w > vid.width)
w = vid.width - x;
if (y + h > vid.height)
h = vid.height - y;
dest = screens[0] + y*vid.width + x;
deststop = screens[0] + vid.rowbytes * vid.height;
c &= 255; c &= 255;
for (v = 0; v < h; v++, dest += vid.width) for (;(--h >= 0) && dest < deststop; dest += vid.width)
for (u = 0; u < w; u++) memset(dest, (UINT8)(c&255), w * vid.bpp);
{
if (dest > deststop)
return;
dest[u] = (UINT8)c;
}
} }
// //

View File

@ -133,6 +133,47 @@ void W_Shutdown(void)
static char filenamebuf[MAX_WADPATH]; static char filenamebuf[MAX_WADPATH];
// W_OpenWadFile
// Helper function for opening the WAD file.
// Returns the FILE * handle for the file, or NULL if not found or could not be opened
// If "useerrors" is true then print errors in the console, else just don't bother
// "filename" may be modified to have the correct path the actual file is located in, if necessary
FILE *W_OpenWadFile(const char **filename, boolean useerrors)
{
FILE *handle;
strncpy(filenamebuf, *filename, MAX_WADPATH);
filenamebuf[MAX_WADPATH - 1] = '\0';
*filename = filenamebuf;
// open wad file
if ((handle = fopen(*filename, "rb")) == NULL)
{
// If we failed to load the file with the path as specified by
// the user, strip the directories and search for the file.
nameonly(filenamebuf);
// If findfile finds the file, the full path will be returned
// in filenamebuf == *filename.
if (findfile(filenamebuf, NULL, true))
{
if ((handle = fopen(*filename, "rb")) == NULL)
{
if (useerrors)
CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), *filename);
return NULL;
}
}
else
{
if (useerrors)
CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), *filename);
return NULL;
}
}
return handle;
}
// search for all DEHACKED lump in all wads and load it // search for all DEHACKED lump in all wads and load it
static inline void W_LoadDehackedLumps(UINT16 wadnum) static inline void W_LoadDehackedLumps(UINT16 wadnum)
{ {
@ -234,7 +275,6 @@ static void W_InvalidateLumpnumCache(void)
memset(lumpnumcache, 0, sizeof (lumpnumcache)); memset(lumpnumcache, 0, sizeof (lumpnumcache));
} }
// Allocate a wadfile, setup the lumpinfo (directory) and // Allocate a wadfile, setup the lumpinfo (directory) and
// lumpcache, add the wadfile to the current active wadfiles // lumpcache, add the wadfile to the current active wadfiles
// //
@ -271,33 +311,9 @@ UINT16 W_LoadWadFile(const char *filename)
return INT16_MAX; return INT16_MAX;
} }
strncpy(filenamebuf, filename, MAX_WADPATH);
filenamebuf[MAX_WADPATH - 1] = '\0';
filename = filenamebuf;
// open wad file // open wad file
if ((handle = fopen(filename, "rb")) == NULL) if ((handle = W_OpenWadFile(&filename, true)) == NULL)
{ return INT16_MAX;
// If we failed to load the file with the path as specified by
// the user, strip the directories and search for the file.
nameonly(filenamebuf);
// If findfile finds the file, the full path will be returned
// in filenamebuf == filename.
if (findfile(filenamebuf, NULL, true))
{
if ((handle = fopen(filename, "rb")) == NULL)
{
CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), filename);
return INT16_MAX;
}
}
else
{
CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), filename);
return INT16_MAX;
}
}
// Check if wad files will overflow fileneededbuffer. Only the filename part // Check if wad files will overflow fileneededbuffer. Only the filename part
// is send in the packet; cf. // is send in the packet; cf.
@ -1115,21 +1131,11 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
size_t i, j; size_t i, j;
int goodfile = false; int goodfile = false;
if (!checklist) I_Error("No checklist for %s\n", filename); if (!checklist)
strlcpy(filenamebuf, filename, MAX_WADPATH); I_Error("No checklist for %s\n", filename);
filename = filenamebuf;
// open wad file // open wad file
if ((handle = fopen(filename, "rb")) == NULL) if ((handle = W_OpenWadFile(&filename, false)) == NULL)
{ return -1;
nameonly(filenamebuf); // leave full path here
if (findfile(filenamebuf, NULL, true))
{
if ((handle = fopen(filename, "rb")) == NULL)
return -1;
}
else
return -1;
}
// detect dehacked file with the "soc" extension // detect dehacked file with the "soc" extension
if (stricmp(&filename[strlen(filename) - 4], ".soc") != 0 if (stricmp(&filename[strlen(filename) - 4], ".soc") != 0

View File

@ -82,6 +82,8 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
void W_Shutdown(void); void W_Shutdown(void);
// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
FILE *W_OpenWadFile(const char **filename, boolean useerrors);
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
UINT16 W_LoadWadFile(const char *filename); UINT16 W_LoadWadFile(const char *filename);
#ifdef DELFILE #ifdef DELFILE