Merge remote-tracking branch 'refs/remotes/upstream/next' into next

This commit is contained in:
TehRealSalt 2016-10-16 01:39:43 -04:00
commit ee75cbba70
11 changed files with 100 additions and 229 deletions

22
README.md Normal file
View file

@ -0,0 +1,22 @@
# Sonic Robo Blast 2
[![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)
[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/).
## Dependencies
- NASM (x86 builds only)
- SDL2 (Linux/OS X only)
- SDL2-Mixer (Linux/OS X only)
- libupnp (Linux/OS X only)
- libgme (Linux/OS X only)
Warning: 64-bit builds are not netgame compatible with 32-bit builds. Use at your own risk.
## Compiling
See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling)
## Disclaimer
Sonic Team Junior is in no way affiliated with SEGA or Sonic Team. We do not claim ownership of any of SEGA's intellectual property used in SRB2.

View file

@ -1,155 +0,0 @@
Here it is! SRB2 v2.1.14 source code!
(why do we keep the version number up to date
when everything else in this file is hilariously old?
- Inuyasha)
Win32 with Visual C (6SP6+Processor Pack OR 7)
~~~
2 VC++ 6.0 project files are included:
Win32/DirectX/FMOD
src\win32\wLegacy.dsw
You'll need FMOD to compile this version (www.fmod.org)
or
Win32/SDL/SDL_mixer
src\sdl\Win32SDL.dsp
You'll need SDL and SDL_mixer for this version (www.libsdl.org)
Both needs NASM (http://sourceforge.net/projects/nasm)
For PNG screenshot, libPNG, and Zlib (from http://gnuwin32.sourceforge.net/)
No warranty, support, etc. of any kind is offered,
just plain old as is.
Some bits of code are still really scary.
Go nuts!
Win32 with Dev-C++ (http://bloodshed.net/ free!)
~~~
2 Dev-C++ project files are included:
Win32/DirectX/FMOD
src\win32\SRB2.dev
or
Win32/SDL/SDL_mixer
src\sdl\Win32SDL.dev
You'll need SDL and SDL_mixer for this version (www.libsdl.org)
libPNG and Zlib (from http://gnuwin32.sourceforge.net/)
Note there are precompiled libpng.a and libz.a for Mingw
you will need NASM for both SDL/SDL_mixer and DirectX/FMOD
and you need DirectX 6 (or up) Dev-Paks to compile DirectX version
GNU/Linux
~~~
Dependencies:
SDL 1.2.7 or better (from libsdl.org)
SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
libPNG 1.2.7
Zlib 1.2.3
The Xiph.org libogg and libvorbis libraries
The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
installation, so you needn't worry, most likely)
GCC 3.x toolchain and binutils
GNU Make
Build instructions:
make -C src LINUX=1
Build instructions (64 bit):
make -C src LINUX64=1
Build instructions to build for Wii Linux/SRB2Wii on a PowerPC system,
follow cross-compiling instructions for cross-compiling on a x86 system:
make -C src LINUX=1 WIILINUX=1
Build instructions to build for Pandora (Linux) on a ARM system,
follow cross-compiling instructions for cross-compiling on a x86 system:
make -C src PANDORA=1
Solaris
~~~
Dependencies:
SDL 1.2.5 or better (from libsdl.org)
SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
libPNG 1.2.7
Zlib 1.2.3
The Xiph.org libogg and libvorbis libraries
The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
installation, so you needn't worry, most likely)
GCC 3.x toolchain and binutils
GNU Make
You can get all these programs/libraries from the Companion CD (except SDL_mixer and OpenGL)
Build instructions:
gmake -C src SOLARIS=1
FreeBSD
~~~
Dependencies:
SDL 1.2.7 or better (from libsdl.org)
SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
libPNG 1.2.7
Zlib 1.2.3
The Xiph.org libogg and libvorbis libraries
The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
installation, so you needn't worry, most likely)
GCC 3.x toolchain and binutils
GNU Make
Build instructions:
gmake -C src FREEBSD=1
DJGPP/DOS
~~~
Dependencies:
Allegro 3.12 game programming library, (from
http://alleg.sourceforge.net/index.html)
Nasm (use NOASM=1 if you don't have it)
libsocket (from http://homepages.nildram.co.uk/~phekda/richdawe/lsck/) or
Watt-32 (from http://www.bgnett.no/~giva/)
GCC 3.x toolchain and binutils
GNU Make
Build instructions:
make -C src # to link with Watt-32, add WATTCP=1
# for remote debugging over the COM port, add RDB=1
Notes:
use tools\djgpp\all313.diff to update Allegro to a "more usable" version ;)
Example: E:\djgpp\allegro>patch -p# < D:\SRB2Code\1.1\srb2\tools\djgpp\all313.diff
Windows CE
~~~
Dependencies:
SDL 1.27
Build instructions:
use src\SDL\WinCE\SRB2CE.vcw
-------------------------------------------------------------------------------
binaries will turn in up in bin/
note: read the src/makefile for more options
- Sonic Team Junior
http://www.srb2.org

View file

@ -60,6 +60,7 @@
#endif #endif
#ifdef _WINDOWS #ifdef _WINDOWS
#define NONET
#if !defined (HWRENDER) && !defined (NOHW) #if !defined (HWRENDER) && !defined (NOHW)
#define HWRENDER #define HWRENDER
#endif #endif

View file

@ -5579,7 +5579,7 @@ boolean G_CheckDemoStatus(void)
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file.
#endif #endif
saved = FIL_WriteFile(demoname, demobuffer, demo_p - demobuffer); // finally output the file. saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file.
free(demobuffer); free(demobuffer);
demorecording = false; demorecording = false;

View file

@ -56,7 +56,9 @@
//#define NONET //#define NONET
#endif #endif
#ifndef NONET #ifdef NONET
#undef HAVE_MINIUPNPC
#else
#ifdef USE_WINSOCK1 #ifdef USE_WINSOCK1
#include <winsock.h> #include <winsock.h>
#elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__) #elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__)

View file

@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString)
|| stringToUse[startPos] == '\r' || stringToUse[startPos] == '\r'
|| stringToUse[startPos] == '\n' || stringToUse[startPos] == '\n'
|| stringToUse[startPos] == '\0' || stringToUse[startPos] == '\0'
|| stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
|| inComment != 0) || inComment != 0)
&& startPos < stringLength) && startPos < stringLength)
{ {
@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString)
&& stringToUse[endPos] != ',' && stringToUse[endPos] != ','
&& stringToUse[endPos] != '{' && stringToUse[endPos] != '{'
&& stringToUse[endPos] != '}' && stringToUse[endPos] != '}'
&& stringToUse[endPos] != '"' // see above
&& inComment == 0) && inComment == 0)
&& endPos < stringLength) && endPos < stringLength)
{ {

View file

@ -1271,7 +1271,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL); topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL);
bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL); bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL);
if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY)) if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER) && !(thing->flags & MF_NOGRAVITY))
{ {
// If you're inside goowater and slowing down // If you're inside goowater and slowing down
fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale); fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale);

View file

@ -1278,25 +1278,23 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next) for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS)) if (!(rover->flags & FF_EXISTS) || !P_InsideANonSolidFFloor(mo, rover)) // P_InsideANonSolidFFloor checks for FF_EXISTS itself, but let's not always call this function
continue; continue;
if (P_InsideANonSolidFFloor(mo, rover)) if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
{ goopgravity = true;
if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
goopgravity = true;
if (rover->master->frontsector->gravity)
{
gravityadd = -FixedMul(gravity,
(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
if (rover->master->frontsector->verticalflip && gravityadd > 0) if (!(rover->master->frontsector->gravity))
mo->eflags |= MFE_VERTICALFLIP; continue;
no3dfloorgrav = false; gravityadd = -FixedMul(gravity,
break; (FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
}
} if (rover->master->frontsector->verticalflip && gravityadd > 0)
mo->eflags |= MFE_VERTICALFLIP;
no3dfloorgrav = false;
break;
} }
} }
@ -1318,28 +1316,20 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (mo->player) if (mo->player)
{ {
if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly] if ((mo->player->pflags & PF_GLIDING)
|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4]))) || (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
gravityadd = gravityadd/3; // less gravity while flying || (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4]))))
if (mo->player->pflags & PF_GLIDING) gravityadd = gravityadd/3; // less gravity while flying/gliding
gravityadd = gravityadd/3; // less gravity while gliding if (mo->player->climbing || (mo->player->pflags & PF_NIGHTSMODE))
if (mo->player->climbing)
gravityadd = 0;
if (mo->player->pflags & PF_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
{ {
UINT8 bits = 0; gravityadd = -gravityadd;
if (mo->flags2 & MF2_OBJECTFLIP) mo->eflags ^= MFE_VERTICALFLIP;
bits ^= 1;
if (mo->player->powers[pw_gravityboots])
bits ^= 1;
if (bits & 1)
{
gravityadd = -gravityadd;
mo->eflags ^= MFE_VERTICALFLIP;
}
} }
if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way
P_PlayerFlip(mo);
} }
else else
{ {
@ -1347,10 +1337,10 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (mo->flags2 & MF2_OBJECTFLIP) if (mo->flags2 & MF2_OBJECTFLIP)
{ {
mo->eflags |= MFE_VERTICALFLIP; mo->eflags |= MFE_VERTICALFLIP;
if (gravityadd < 0) // Don't sink, only rise up
gravityadd *= -1;
if (mo->z + mo->height >= mo->ceilingz) if (mo->z + mo->height >= mo->ceilingz)
gravityadd = 0; gravityadd = 0;
else if (gravityadd < 0) // Don't sink, only rise up
gravityadd *= -1;
} }
else //Otherwise, sort through the other exceptions. else //Otherwise, sort through the other exceptions.
{ {
@ -1396,9 +1386,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (goopgravity) if (goopgravity)
gravityadd = -gravityadd/5; gravityadd = -gravityadd/5;
if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
P_PlayerFlip(mo);
gravityadd = FixedMul(gravityadd, mo->scale); gravityadd = FixedMul(gravityadd, mo->scale);
return gravityadd; return gravityadd;
@ -1553,6 +1540,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
if (node->m_sector->ffloors) if (node->m_sector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next) for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{ {
@ -1565,37 +1553,39 @@ static void P_PushableCheckBustables(mobj_t *mo)
if (!rover->master->frontsector->crumblestate) if (!rover->master->frontsector->crumblestate)
{ {
topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
// Height checks // Height checks
if (rover->flags & FF_SHATTERBOTTOM) if (rover->flags & FF_SHATTERBOTTOM)
{ {
if (mo->z+mo->momz + mo->height < *rover->bottomheight) if (mo->z+mo->momz + mo->height < bottomheight)
continue; continue;
if (mo->z+mo->height > *rover->bottomheight) if (mo->z+mo->height > bottomheight)
continue; continue;
} }
else if (rover->flags & FF_SPINBUST) else if (rover->flags & FF_SPINBUST)
{ {
if (mo->z+mo->momz > *rover->topheight) if (mo->z+mo->momz > topheight)
continue; continue;
if (mo->z+mo->height < *rover->bottomheight) if (mo->z+mo->height < bottomheight)
continue; continue;
} }
else if (rover->flags & FF_SHATTER) else if (rover->flags & FF_SHATTER)
{ {
if (mo->z+mo->momz > *rover->topheight) if (mo->z+mo->momz > topheight)
continue; continue;
if (mo->z+mo->momz + mo->height < *rover->bottomheight) if (mo->z+mo->momz + mo->height < bottomheight)
continue; continue;
} }
else else
{ {
if (mo->z >= *rover->topheight) if (mo->z >= topheight)
continue; continue;
if (mo->z+mo->height < *rover->bottomheight) if (mo->z+mo->height < bottomheight)
continue; continue;
} }
@ -6935,6 +6925,7 @@ void P_MobjThinker(mobj_t *mobj)
{ {
mobj->flags &= ~MF_NOGRAVITY; mobj->flags &= ~MF_NOGRAVITY;
P_SetMobjState(mobj, S_NIGHTSDRONE1); P_SetMobjState(mobj, S_NIGHTSDRONE1);
mobj->flags2 |= MF2_DONTDRAW;
} }
} }
else if (mobj->tracer && mobj->tracer->player) else if (mobj->tracer && mobj->tracer->player)

View file

@ -509,7 +509,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname);
} }
endPos = NULL; endPos = NULL;
#ifndef AVOID_ERRNO #ifndef AVOID_ERRNO
@ -523,7 +523,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
#endif #endif
|| animSpeed < 0) // Number is not positive || animSpeed < 0) // Number is not positive
{ {
I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken);
} }
animdefs[*i].speed = animSpeed; animdefs[*i].speed = animSpeed;
Z_Free(animdefsToken); Z_Free(animdefsToken);

View file

@ -1692,6 +1692,7 @@ static void P_CheckBustableBlocks(player_t *player)
if (node->m_sector->ffloors) if (node->m_sector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next) for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{ {
@ -1717,42 +1718,45 @@ static void P_CheckBustableBlocks(player_t *player)
if (!(rover->flags & FF_SHATTER) && (rover->flags & FF_ONLYKNUX) && !(player->charability == CA_GLIDEANDCLIMB)) if (!(rover->flags & FF_SHATTER) && (rover->flags & FF_ONLYKNUX) && !(player->charability == CA_GLIDEANDCLIMB))
continue; continue;
topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
// Height checks // Height checks
if (rover->flags & FF_SHATTERBOTTOM) if (rover->flags & FF_SHATTERBOTTOM)
{ {
if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight) if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
continue; continue;
if (player->mo->z+player->mo->height > *rover->bottomheight) if (player->mo->z+player->mo->height > bottomheight)
continue; continue;
} }
else if (rover->flags & FF_SPINBUST) else if (rover->flags & FF_SPINBUST)
{ {
if (player->mo->z+player->mo->momz > *rover->topheight) if (player->mo->z+player->mo->momz > topheight)
continue; continue;
if (player->mo->z + player->mo->height < *rover->bottomheight) if (player->mo->z + player->mo->height < bottomheight)
continue; continue;
} }
else if (rover->flags & FF_SHATTER) else if (rover->flags & FF_SHATTER)
{ {
if (player->mo->z + player->mo->momz > *rover->topheight) if (player->mo->z + player->mo->momz > topheight)
continue; continue;
if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight) if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
continue; continue;
} }
else else
{ {
if (player->mo->z >= *rover->topheight) if (player->mo->z >= topheight)
continue; continue;
if (player->mo->z + player->mo->height < *rover->bottomheight) if (player->mo->z + player->mo->height < bottomheight)
continue; continue;
} }
// Impede the player's fall a bit // Impede the player's fall a bit
if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= *rover->topheight) if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight)
player->mo->momz >>= 1; player->mo->momz >>= 1;
else if (rover->flags & FF_SHATTER) else if (rover->flags & FF_SHATTER)
{ {
@ -6976,6 +6980,7 @@ static void P_MovePlayer(player_t *player)
msecnode_t *node; // only place it's being used in P_MovePlayer now msecnode_t *node; // only place it's being used in P_MovePlayer now
fixed_t oldx; fixed_t oldx;
fixed_t oldy; fixed_t oldy;
fixed_t floorz, ceilingz;
oldx = player->mo->x; oldx = player->mo->x;
oldy = player->mo->y; oldy = player->mo->y;
@ -6993,31 +6998,34 @@ static void P_MovePlayer(player_t *player)
if (node->m_sector->ffloors) if (node->m_sector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next) for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS)) continue; if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
continue;
if ((rover->flags & FF_BLOCKPLAYER)) topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
if (topheight > player->mo->z && bottomheight < player->mo->z)
{ {
if (*rover->topheight > player->mo->z && *rover->bottomheight < player->mo->z) P_ResetPlayer(player);
{ S_StartSound(player->mo, sfx_s3k4a);
P_ResetPlayer(player); player->climbing = 5;
S_StartSound(player->mo, sfx_s3k4a); player->mo->momx = player->mo->momy = player->mo->momz = 0;
player->climbing = 5; break;
player->mo->momx = player->mo->momy = player->mo->momz = 0;
break;
}
} }
} }
} }
if (player->mo->z+player->mo->height > node->m_sector->ceilingheight floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
if (player->mo->z+player->mo->height > ceilingz
&& node->m_sector->ceilingpic == skyflatnum) && node->m_sector->ceilingpic == skyflatnum)
continue; continue;
if (node->m_sector->floorheight > player->mo->z if (floorz > player->mo->z || ceilingz < player->mo->z)
|| node->m_sector->ceilingheight < player->mo->z)
{ {
P_ResetPlayer(player); P_ResetPlayer(player);
S_StartSound(player->mo, sfx_s3k4a); S_StartSound(player->mo, sfx_s3k4a);

View file

@ -974,7 +974,7 @@ static void ST_drawNiGHTSHUD(void)
if (cv_debug & DBG_NIGHTSBASIC) if (cv_debug & DBG_NIGHTSBASIC)
minlink = 0; minlink = 0;
// Cheap hack: don't display when the score is showing // Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
if (stplyr->texttimer && stplyr->textvar == 4) if (stplyr->texttimer && stplyr->textvar == 4)
minlink = INT32_MAX; minlink = INT32_MAX;