Merge branch 'new-menus' into profiles

This commit is contained in:
Sally Coolatta 2021-12-25 06:09:53 -05:00
commit e628894b47
72 changed files with 4233 additions and 1276 deletions

View file

@ -113,3 +113,4 @@ k_hud.c
k_menudef.c
k_menufunc.c
k_menudraw.c
k_brightmap.c

View file

@ -795,10 +795,14 @@ static boolean CL_SendJoin(void)
sizeof netbuffer->u.clientcfg.application);
for (i = 0; i <= splitscreen; i++)
CleanupPlayerName(g_localplayers[i], cv_playername[i].zstring);
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
// the MAXPLAYERS addition is necessary to communicate that g_localplayers is not yet safe to reference
CleanupPlayerName(MAXPLAYERS+i, cv_playername[i].zstring);
strncpy(netbuffer->u.clientcfg.names[i], cv_playername[i].zstring, MAXPLAYERNAME);
}
// privacy shield for the local players not joining this session
for (; i < MAXSPLITSCREENPLAYERS; i++)
strncpy(netbuffer->u.clientcfg.names[i], va("Player %c", 'A' + i), MAXPLAYERNAME);
return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak));
}
@ -1334,7 +1338,7 @@ static void CL_ReloadReceivedSavegame(void)
for (i = 0; i < MAXPLAYERS; i++)
{
LUA_InvalidatePlayer(&players[i]);
sprintf(player_names[i], "Player %d", i + 1);
sprintf(player_names[i], "Player %c", 'A' + i);
}
CL_LoadReceivedSavegame(true);
@ -2424,7 +2428,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
doomcom->numslots--;
// Reset the name
sprintf(player_names[playernum], "Player %d", playernum+1);
sprintf(player_names[playernum], "Player %c", 'A' + playernum);
player_name_changes[playernum] = 0;
@ -3236,7 +3240,7 @@ void SV_ResetServer(void)
playeringame[i] = false;
playernode[i] = UINT8_MAX;
memset(playeraddress[i], 0, sizeof(*playeraddress));
sprintf(player_names[i], "Player %d", i + 1);
sprintf(player_names[i], "Player %c", 'A' + i);
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
K_ClearClientPowerLevels();
splitscreen_invitations[i] = -1;
@ -3435,7 +3439,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
P_ForceLocalAngle(newplayer, newplayer->angleturn);
D_SendPlayerConfig();
D_SendPlayerConfig(splitscreenplayer);
addedtogame = true;
if (rejoined)
@ -3581,14 +3585,13 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
LUAh_PlayerJoin(newplayernum);
}
static boolean SV_AddWaitingPlayers(const char *name, const char *name2, const char *name3, const char *name4)
static boolean SV_AddWaitingPlayers(SINT8 node, const char *name, const char *name2, const char *name3, const char *name4)
{
INT32 node, n, newplayer = false;
INT32 n, newplayernum;
UINT8 buf[4 + MAXPLAYERNAME];
UINT8 *buf_p = buf;
INT32 newplayernum;
boolean newplayer = false;
for (node = 0; node < MAXNETNODES; node++)
{
// splitscreen can allow 2+ players in one node
for (; nodewaiting[node] > 0; nodewaiting[node]--)
@ -3707,6 +3710,7 @@ boolean SV_SpawnServer(void)
I_Error("What do you think you're doing?");
return false;
#else
boolean result = false;
if (demo.playback)
G_StopDemo(); // reset engine parameter
if (metalplayback)
@ -3733,7 +3737,14 @@ boolean SV_SpawnServer(void)
else doomcom->numslots = 1;
}
return SV_AddWaitingPlayers(cv_playername[0].zstring, cv_playername[1].zstring, cv_playername[2].zstring, cv_playername[3].zstring);
// strictly speaking, i'm not convinced the following is necessary
// but I'm not confident enough to remove it entirely in case it breaks something
{
SINT8 node = 0;
for (; node < MAXNETNODES; node++)
result |= SV_AddWaitingPlayers(node, cv_playername[0].zstring, cv_playername[1].zstring, cv_playername[2].zstring, cv_playername[3].zstring);
}
return result;
#endif
}
@ -3906,7 +3917,7 @@ static void HandleConnect(SINT8 node)
SV_SendSaveGame(node, false); // send a complete game state
DEBFILE("send savegame\n");
}
SV_AddWaitingPlayers(names[0], names[1], names[2], names[3]);
SV_AddWaitingPlayers(node, names[0], names[1], names[2], names[3]);
joindelay += cv_joindelay.value * TICRATE;
player_joining = true;
}

View file

@ -776,7 +776,7 @@ void D_SRB2Loop(void)
// process tics (but maybe not if realtic == 0)
TryRunTics(realtics);
if (cv_frameinterpolation.value == 1)
if (cv_frameinterpolation.value == 1 && !(paused || P_AutoPause() || hu_stopped))
{
fixed_t entertimefrac = I_GetTimeFrac();
// renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based
@ -815,20 +815,6 @@ void D_SRB2Loop(void)
}
else if (rendertimeout < entertic) // in case the server hang or netsplit
{
#if 0
// Lagless camera! Yay!
if (gamestate == GS_LEVEL && netgame)
{
INT32 i;
for (i = 0; i <= r_splitscreen; i++)
{
if (camera[i].chase)
P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false);
}
}
#endif
// (Only display if not already done for frame interp)
cv_frameinterpolation.value == 0 ? D_Display() : 0;
@ -1424,6 +1410,9 @@ void D_SRB2Main(void)
// setup loading screen
SCR_Startup();
// Do this in background; lots of number crunching
R_InitTranslucencyTables();
CON_SetLoadingProgress(LOADED_ISTARTUPGRAPHICS);
CONS_Printf("HU_Init()...\n");

View file

@ -222,8 +222,6 @@ static void Command_KartGiveItem_f(void);
// CLIENT VARIABLES
// =========================================================================
void SendWeaponPref(UINT8 n);
static CV_PossibleValue_t usemouse_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Force"}, {0, NULL}};
#ifdef LJOYSTICK
@ -1102,6 +1100,7 @@ boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
* is restored to what it was before.
*
* We assume that if playernum is in ::g_localplayers
* (unless clientjoin is true, a necessary evil)
* the console variable ::cv_playername[n] is
* already set to newname. However, the player name table is assumed to
* contain the old name.
@ -1120,6 +1119,10 @@ void CleanupPlayerName(INT32 playernum, const char *newname)
char *tmpname = NULL;
INT32 i;
boolean namefailed = true;
boolean clientjoin = !!(playernum >= MAXPLAYERS);
if (clientjoin)
playernum -= MAXPLAYERS;
buf = Z_StrDup(newname);
@ -1177,17 +1180,20 @@ void CleanupPlayerName(INT32 playernum, const char *newname)
}
// no stealing another player's name
for (i = 0; i < MAXPLAYERS; i++)
if (!clientjoin)
{
if (i != playernum && playeringame[i]
&& strcasecmp(tmpname, player_names[i]) == 0)
for (i = 0; i < MAXPLAYERS; i++)
{
break;
if (i != playernum && playeringame[i]
&& strcasecmp(tmpname, player_names[i]) == 0)
{
break;
}
}
}
if (i < MAXPLAYERS)
break;
if (i < MAXPLAYERS)
break;
}
// name is okay then
namefailed = false;
@ -1198,18 +1204,23 @@ void CleanupPlayerName(INT32 playernum, const char *newname)
// set consvars whether namefailed or not, because even if it succeeded,
// spaces may have been removed
for (i = 0; i <= splitscreen; i++)
if (clientjoin)
CV_StealthSet(&cv_playername[playernum], tmpname);
else
{
if (playernum == g_localplayers[i])
for (i = 0; i <= splitscreen; i++)
{
CV_StealthSet(&cv_playername[i], tmpname);
break;
if (playernum == g_localplayers[i])
{
CV_StealthSet(&cv_playername[i], tmpname);
break;
}
}
}
if (i > splitscreen)
{
I_Assert(((void)"CleanupPlayerName used on non-local player", 0));
if (i > splitscreen)
{
I_Assert(((void)"CleanupPlayerName used on non-local player", 0));
}
}
Z_Free(buf);
@ -1805,33 +1816,28 @@ static void Got_LeaveParty(UINT8 **cp,INT32 playernum)
}
}
void D_SendPlayerConfig(void)
void D_SendPlayerConfig(UINT8 n)
{
UINT8 i;
UINT8 buf[4];
UINT8 *p = buf;
for (i = 0; i <= splitscreen; i++)
SendNameAndColor(n);
SendWeaponPref(n);
if (n == 0)
{
UINT8 buf[4];
UINT8 *p = buf;
SendNameAndColor(i);
SendWeaponPref(i);
if (i == 0)
{
// Send it over
WRITEUINT16(p, vspowerlevel[PWRLV_RACE]);
WRITEUINT16(p, vspowerlevel[PWRLV_BATTLE]);
}
else
{
// Splitscreen players have invalid powerlevel
WRITEUINT16(p, 0);
WRITEUINT16(p, 0);
}
SendNetXCmdForPlayer(i, XD_POWERLEVEL, buf, p-buf);
// Send it over
WRITEUINT16(p, vspowerlevel[PWRLV_RACE]);
WRITEUINT16(p, vspowerlevel[PWRLV_BATTLE]);
}
else
{
// Splitscreen players have invalid powerlevel
WRITEUINT16(p, 0);
WRITEUINT16(p, 0);
}
SendNetXCmdForPlayer(n, XD_POWERLEVEL, buf, p-buf);
}
// Only works for displayplayer, sorry!

View file

@ -207,7 +207,8 @@ void D_RegisterServerCommands(void);
void D_RegisterClientCommands(void);
void CleanupPlayerName(INT32 playernum, const char *newname);
boolean EnsurePlayerNameIsGood(char *name, INT32 playernum);
void D_SendPlayerConfig(void);
void SendWeaponPref(UINT8 n);
void D_SendPlayerConfig(UINT8 n);
void Command_ExitGame_f(void);
void Command_Retry_f(void);
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore

View file

@ -161,10 +161,16 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
for (i = mainwads+1; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
#ifdef DEVELOP
i = 0;
#else
i = mainwads + 1;
#endif
for (; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
{
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
if (i > mainwads && !wadfiles[i]->important)
continue;
if (firstfile)
@ -276,11 +282,16 @@ boolean CL_CheckDownloadable(void)
}
// Downloading locally disabled
#if 0
if (!dlstatus && M_CheckParm("-nodownload"))
dlstatus = 3;
if (!dlstatus)
return true;
#else
if (!dlstatus)
dlstatus = 3;
#endif
// not downloadable, put reason in console
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
@ -489,7 +500,12 @@ INT32 CL_CheckFiles(void)
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files
for (j = mainwads+1; wadfiles[j]; j++)
#ifdef DEVELOP
j = 0;
#else
j = mainwads + 1;
#endif
for (; wadfiles[j]; j++)
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) &&

View file

@ -312,6 +312,7 @@ typedef struct player_s
fixed_t bob;
angle_t viewrollangle;
angle_t old_viewrollangle;
// camera tilt
// TODO: expose to lua
angle_t tilt;
@ -325,6 +326,7 @@ typedef struct player_s
// fun thing for player sprite
angle_t drawangle;
angle_t old_drawangle; // interp
// Bit flags.
// See pflags_t, above.
@ -394,6 +396,8 @@ typedef struct player_s
INT32 aizdrifttilt;
INT32 aizdriftturn;
INT32 underwatertilt;
fixed_t offroad; // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed
UINT8 waterskip; // Water skipping counter

View file

@ -323,6 +323,7 @@ actionpointer_t actionpointers[] =
{{A_SPBChase}, "A_SPBCHASE"},
{{A_SSMineSearch}, "A_SSMINESEARCH"},
{{A_SSMineExplode}, "A_SSMINEEXPLODE"},
{{A_LandMineExplode}, "A_LANDMINEEXPLODE"},
{{A_BallhogExplode}, "A_BALLHOGEXPLODE"},
{{A_LightningFollowPlayer}, "A_LIGHTNINGFOLLOWPLAYER"},
{{A_FZBoomFlash}, "A_FZBOOMFLASH"},
@ -3475,6 +3476,21 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_RANDOMITEM12",
"S_DEADRANDOMITEM",
// Sphere Box (for Battle)
"S_SPHEREBOX1",
"S_SPHEREBOX2",
"S_SPHEREBOX3",
"S_SPHEREBOX4",
"S_SPHEREBOX5",
"S_SPHEREBOX6",
"S_SPHEREBOX7",
"S_SPHEREBOX8",
"S_SPHEREBOX9",
"S_SPHEREBOX10",
"S_SPHEREBOX11",
"S_SPHEREBOX12",
"S_DEADSPHEREBOX",
// Random Item Pop
"S_RANDOMITEMPOP1",
"S_RANDOMITEMPOP2",

View file

@ -109,8 +109,12 @@ static patch_t *ttcheckers; // *vroom* KART
static patch_t *ttkflash; // flash screen
*/
#define NOWAY
#ifdef NOWAY
static patch_t *driver[2]; // Driving character on the waiting screen
static UINT8 *waitcolormap; // colormap for the spinning character
#endif
// ttmode user
static patch_t *ttuser[TTMAX_USER];
@ -2145,14 +2149,17 @@ void F_TitleDemoTicker(void)
void F_StartWaitingPlayers(void)
{
#ifdef NOWAY
INT32 i;
INT32 randskin;
spritedef_t *sprdef;
spriteframe_t *sprframe;
#endif
wipegamestate = GS_TITLESCREEN; // technically wiping from title screen
finalecount = 0;
#ifdef NOWAY
randskin = M_RandomKey(numskins);
if (waitcolormap)
@ -2165,8 +2172,9 @@ void F_StartWaitingPlayers(void)
for (i = 0; i < 2; i++)
{
sprframe = &sprdef->spriteframes[i];
driver[i] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL);
driver[i] = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
}
#endif
}
void F_WaitingPlayersTicker(void)
@ -2183,14 +2191,17 @@ void F_WaitingPlayersTicker(void)
void F_WaitingPlayersDrawer(void)
{
#ifdef NOWAY
UINT32 frame = (finalecount % 8) / 4; // The game only tics every other frame while waitingplayers
INT32 flags = V_FLIP;
#endif
const char *waittext1 = "You will join";
const char *waittext2 = "the next race...";
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
V_DrawCreditString((160 - (V_CreditStringWidth(waittext1)>>1))<<FRACBITS, 48<<FRACBITS, 0, waittext1);
V_DrawCreditString((160 - (V_CreditStringWidth(waittext2)>>1))<<FRACBITS, 64<<FRACBITS, 0, waittext2);
V_DrawFixedPatch((160<<FRACBITS) - driver[frame]->width / 2, 150<<FRACBITS, 1<<FRACBITS, flags, driver[frame], waitcolormap);
#ifdef NOWAY
V_DrawFixedPatch((160<<FRACBITS) - driver[frame]->width / 2, 150<<FRACBITS, 1<<FRACBITS, V_FLIP, driver[frame], waitcolormap);
#endif
}
// ==================

View file

@ -2793,6 +2793,7 @@ void G_DoPlayDemo(char *defdemoname)
demoflags = READUINT8(demo_p);
gametype = READUINT8(demo_p);
G_SetGametype(gametype);
if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running.
G_SkipDemoExtraFiles(&demo_p);

View file

@ -345,7 +345,6 @@ static void kickstartaccel_OnChange(void);
static void kickstartaccel2_OnChange(void);
static void kickstartaccel3_OnChange(void);
static void kickstartaccel4_OnChange(void);
void SendWeaponPref(UINT8 n);
// don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler.

View file

@ -452,7 +452,9 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
UINT8 *pdata;
INT32 blockwidth, blockheight, blocksize;
#ifdef GLENCORE
UINT8 *colormap = colormaps;
#endif
INT32 i;
boolean skyspecial = false; //poor hack for Legacy large skies..
@ -477,12 +479,14 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
grtex->mipmap.height = (UINT16)texture->height;
grtex->mipmap.format = textureformat;
#ifdef GLENCORE
if (encoremap)
colormap += COLORMAP_REMAPOFFSET;
grtex->mipmap.colormap = Z_Calloc(sizeof(*grtex->mipmap.colormap), PU_HWRPATCHCOLMIPMAP, NULL);
grtex->mipmap.colormap->source = colormap;
M_Memcpy(grtex->mipmap.colormap->data, colormap, 256 * sizeof(UINT8));
#endif
blockwidth = texture->width;
blockheight = texture->height;
@ -891,7 +895,9 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum, boolean noencoremap)
GLMipmap_t *grmip;
patch_t *patch;
#ifdef GLENCORE
UINT8 *colormap = colormaps;
#endif
if (flatlumpnum == LUMPERROR)
return;
@ -899,12 +905,16 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum, boolean noencoremap)
patch = HWR_GetCachedGLPatch(flatlumpnum);
grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
#ifdef GLENCORE
if (!noencoremap && encoremap)
colormap += COLORMAP_REMAPOFFSET;
grmip->colormap = Z_Calloc(sizeof(*grmip->colormap), PU_HWRPATCHCOLMIPMAP, NULL);
grmip->colormap->source = colormap;
M_Memcpy(grmip->colormap->data, colormap, 256 * sizeof(UINT8));
#else
(void)noencoremap;
#endif
if (!grmip->downloaded && !grmip->data)
HWR_CacheFlat(grmip, flatlumpnum);

View file

@ -113,7 +113,7 @@ typedef struct
UINT8 splitscreen;
boolean flip; // screenflip
boolean shearing; // 14042019
angle_t viewaiming; // 17052019
float viewaiming; // 17052019
boolean roll;
FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ
FLOAT centerx, centery;
@ -284,7 +284,7 @@ struct FSurfaceInfo
typedef struct FSurfaceInfo FSurfaceInfo;
#define GL_DEFAULTMIX 0x00000000
#define GL_DEFAULTFOG 0xFF000000
#define GL_DEFAULTFOG 0x19000000
//Hurdler: added for backward compatibility
enum hwdsetspecialstate

View file

@ -51,7 +51,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *stransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void);
@ -136,4 +136,4 @@ extern struct hwdriver_s hwdriver;
#endif //not defined _CREATE_DLL_
#endif //__HWR_DRV_H__
#endif //__HWR_DRV_H__

View file

@ -26,7 +26,7 @@
//#define HWR_LOADING_SCREEN
// SRB2Kart
#define GLENCORE
//#define GLENCORE
// -----------
// structures

View file

@ -40,6 +40,7 @@
#include "../r_things.h" // R_GetShadowZ
#include "../d_main.h"
#include "../p_slopes.h"
#include "../k_kart.h" // HITLAGJITTERS
#include "hw_md2.h"
#ifdef NEWCLIP
@ -3628,14 +3629,14 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
FOutVector shadowVerts[4];
FSurfaceInfo sSurf;
float fscale; float fx; float fy; float offset;
float ph;
extracolormap_t *colormap = NULL;
UINT8 i;
SINT8 flip = P_MobjFlip(thing);
UINT32 tFlag = PF_ReverseSubtract;
INT32 light;
fixed_t scalemul;
UINT16 alpha;
fixed_t floordiff;
fixed_t groundz;
fixed_t slopez;
pslope_t *groundslope;
@ -3645,7 +3646,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
fixed_t interpz = thing->z;
// do interpolation
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x);
interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y);
@ -3655,7 +3656,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
{
fixed_t mul = thing->hitlag * (FRACUNIT / 10);
fixed_t mul = thing->hitlag * HITLAGJITTERS;
if (leveltime & 1)
{
@ -3674,33 +3675,32 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
groundz = R_GetShadowZ(thing, &groundslope);
floordiff = abs((flip < 0 ? thing->height : 0) + interpz - groundz);
alpha = floordiff / (4*FRACUNIT) + 75;
if (alpha >= 255) return;
alpha = 255 - alpha;
gpatch = (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE);
if (!(gpatch && ((GLPatch_t *)gpatch->hardware)->mipmap->format)) return;
HWR_GetPatch(gpatch);
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
scalemul = FixedMul(scale, (thing->radius * 2) / gpatch->height);
ph = (float)gpatch->height;
fscale = FIXED_TO_FLOAT(scalemul);
fx = FIXED_TO_FLOAT(interpx);
fy = FIXED_TO_FLOAT(interpy);
if (fscale > 0.0)
{
offset = (ph / 2) * fscale;
}
else
{
return;
}
// 3--2
// | /|
// |/ |
// 0--1
if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
offset = ((gpatch->height)/2) * fscale;
else
offset = (float)((gpatch->height)/2);
shadowVerts[2].x = shadowVerts[3].x = fx + offset;
shadowVerts[1].x = shadowVerts[0].x = fx - offset;
shadowVerts[1].z = shadowVerts[2].z = fy - offset;
@ -3748,10 +3748,15 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
colormap = thing->subsector->sector->extra_colormap;
}
HWR_Lighting(&sSurf, 0, colormap);
sSurf.PolyColor.s.alpha = alpha;
HWR_Lighting(&sSurf, 255, colormap);
sSurf.PolyColor.s.alpha = 255;
HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated, SHADER_SPRITE, false); // sprite shader
if (thing->whiteshadow == true)
{
tFlag = PF_Additive;
}
HWR_ProcessPolygon(&sSurf, shadowVerts, 4, tFlag|PF_Modulated, SHADER_SPRITE, false); // sprite shader
}
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
@ -5055,7 +5060,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
INT32 heightsec, phs;
const boolean splat = R_ThingIsFloorSprite(thing);
const boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat);
angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
float z1, z2;
fixed_t spr_width, spr_height;
@ -5083,20 +5087,28 @@ static void HWR_ProjectSprite(mobj_t *thing)
interpx = thing->x;
interpy = thing->y;
interpz = thing->z;
interpangle = mobjangle;
interpangle = (thing->player ? thing->player->drawangle : thing->angle);
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x);
interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y);
interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z);
interpangle = mobjangle;
if (thing->player)
{
interpangle = thing->player->old_drawangle + FixedMul(rendertimefrac, thing->player->drawangle - thing->player->old_drawangle);
}
else
{
interpangle = thing->old_angle + FixedMul(rendertimefrac, thing->angle - thing->old_angle);
}
}
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
{
fixed_t mul = thing->hitlag * (FRACUNIT / 10);
fixed_t mul = thing->hitlag * HITLAGJITTERS;
if (leveltime & 1)
{
@ -5237,6 +5249,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lumpoff].topoffset;
#ifdef ROTSPRITE
spriterotangle = R_SpriteRotationAngle(thing, NULL);
if (spriterotangle != 0
&& !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))
{
@ -5276,8 +5290,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (papersprite)
{
rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE((mobjangle)>>ANGLETOFINESHIFT));
rightsin = FIXED_TO_FLOAT(FINESINE((interpangle)>>ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE((interpangle)>>ANGLETOFINESHIFT));
}
else
{
@ -5470,8 +5484,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
{
vis->colormap = colormaps;
#ifdef GLENCORE
if (encoremap && (thing->flags & (MF_SCENERY|MF_NOTHINK)) && !(thing->flags & MF_DONTENCOREMAP))
vis->colormap += COLORMAP_REMAPOFFSET;
#endif
}
// set top/bottom coords
@ -5515,7 +5531,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
interpz = thing->z;
// do interpolation
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x);
interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y);
@ -5803,8 +5819,7 @@ static void HWR_DrawSkyBackground(player_t *player)
dometransform.scalez = 1;
dometransform.fovxangle = fpov; // Tails
dometransform.fovyangle = fpov; // Tails
HWR_RollTransform(&dometransform,
R_ViewRollAngle(player));
HWR_RollTransform(&dometransform, viewroll);
dometransform.splitscreen = r_splitscreen;
HWR_GetTexture(texturetranslation[skytexture]);
@ -6096,7 +6111,7 @@ void HWR_RenderSkyboxView(player_t *player)
atransform.fovxangle = fpov; // Tails
atransform.fovyangle = fpov; // Tails
HWR_RollTransform(&atransform, R_ViewRollAngle(player));
HWR_RollTransform(&atransform, viewroll);
atransform.splitscreen = r_splitscreen;
gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
@ -6308,7 +6323,7 @@ void HWR_RenderPlayerView(void)
atransform.fovxangle = fpov; // Tails
atransform.fovyangle = fpov; // Tails
HWR_RollTransform(&atransform, R_ViewRollAngle(player));
HWR_RollTransform(&atransform, viewroll);
atransform.splitscreen = r_splitscreen;
gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));

View file

@ -45,6 +45,7 @@
// SRB2Kart
#include "../k_color.h"
#include "../k_kart.h" // HITLAGJITTERS
#ifdef HAVE_PNG
@ -1372,7 +1373,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
fixed_t interpz = spr->mobj->z;
// do interpolation
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = spr->mobj->old_x + FixedMul(rendertimefrac, spr->mobj->x - spr->mobj->old_x);
interpy = spr->mobj->old_y + FixedMul(rendertimefrac, spr->mobj->y - spr->mobj->old_y);
@ -1382,7 +1383,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
// hitlag vibrating
if (spr->mobj->hitlag > 0 && (spr->mobj->eflags & MFE_DAMAGEHITLAG))
{
fixed_t mul = spr->mobj->hitlag * (FRACUNIT / 10);
fixed_t mul = spr->mobj->hitlag * HITLAGJITTERS;
if (leveltime & 1)
{
@ -1648,23 +1649,26 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.angley = FIXED_TO_FLOAT(anglef);
}
p.rollangle = 0.0f;
if (spr->mobj->rollangle)
{
fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know
fixed_t anglef = AngleFixed(spr->mobj->rollangle);
fixed_t anglef = AngleFixed(R_ModelRotationAngle(spr->mobj, NULL));
p.rollangle = FIXED_TO_FLOAT(anglef);
p.roll = true;
p.rollangle = 0.0f;
// rotation pivot
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius / 2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2);
if (anglef)
{
fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know
// rotation axes relative to camera
p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
p.rollangle = FIXED_TO_FLOAT(anglef);
p.roll = true;
// rotation pivot
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius / 2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2);
// rotation axes relative to camera
p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
}
}
p.anglez = FIXED_TO_FLOAT(AngleFixed(spr->mobj->pitch));
@ -1677,7 +1681,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.mirror = atransform.mirror;
HWD.pfnSetShader(SHADER_MODEL); // model shader
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf);
{
float xs = finalscale * FIXED_TO_FLOAT(spr->mobj->spritexscale);
float ys = finalscale * FIXED_TO_FLOAT(spr->mobj->spriteyscale);
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, xs, ys, flip, hflip, &Surf);
}
}
return true;

View file

@ -715,14 +715,15 @@ static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
"float colorBrightness = sqrt((final_color.r * final_color.r) + (final_color.g * final_color.g) + (final_color.b * final_color.b));\n" \
"float fogBrightness = sqrt((fade_color.r * fade_color.r) + (fade_color.g * fade_color.g) + (fade_color.b * fade_color.b));\n" \
"float colorIntensity = 0.0;\n" \
"if (fogBrightness > colorBrightness) {\n" \
"if (colorBrightness < fogBrightness) {\n" \
"colorIntensity = 1.0 - min(final_color.r, min(final_color.g, final_color.b));\n" \
"colorIntensity = abs(colorIntensity - (1.0 - fogBrightness));\n" \
"colorIntensity = abs(colorIntensity - (1.0 - max(fade_color.r, max(fade_color.g, fade_color.b))));\n" \
"} else {\n" \
"colorIntensity = max(final_color.r, max(final_color.g, final_color.b));\n" \
"colorIntensity = abs(colorIntensity - (fogBrightness));\n" \
"colorIntensity = abs(colorIntensity - min(fade_color.r, min(fade_color.g, fade_color.b)));\n" \
"}\n" \
"colorIntensity *= darkness;\n" \
"colorIntensity *= fade_color.a * 10.0;\n" \
"if (abs(final_color.r - fade_color.r) <= colorIntensity) {\n" \
"final_color.r = fade_color.r;\n" \
"} else if (final_color.r < fade_color.r) {\n" \
@ -2687,7 +2688,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model)
#define BUFFER_OFFSET(i) ((void*)(i))
static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
static GLRGBAFloat poly = {0,0,0,0};
static GLRGBAFloat tint = {0,0,0,0};
@ -2711,10 +2712,11 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
#endif
// Affect input model scaling
scale *= 0.5f;
scalex = scale;
scaley = scale;
scalez = scale;
hscale *= 0.5f;
vscale *= 0.5f;
scalex = hscale;
scaley = vscale;
scalez = hscale;
if (duration != 0 && duration != -1 && tics != -1) // don't interpolate if instantaneous or infinite in length
{
@ -2972,9 +2974,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
// -----------------+
// HWRAPI DrawModel : Draw a model
// -----------------+
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface);
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, hscale, vscale, flipped, hflipped, Surface);
}
// -----------------+

View file

@ -56,7 +56,7 @@ precise_t I_GetPreciseTime(void);
/** \brief Returns the difference between precise times as microseconds.
*/
int I_PreciseToMicros(precise_t);
int I_PreciseToMicros(precise_t d);
/** \brief The I_Sleep function

View file

@ -526,6 +526,7 @@ char sprnames[NUMSPRITES + 1][5] =
//SRB2kart Sprites (sort later)
"RNDM", // Random Item Box
"SBOX", // Sphere Box (for Battle)
"RPOP", // Random Item Box Pop
"SGNS", // Signpost sparkle
"FAST", // Speed boost trail
@ -4061,6 +4062,20 @@ state_t states[NUMSTATES] =
{SPR_RNDM, 22|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM1}, // S_RANDOMITEM12
{SPR_NULL, 0, 0, {A_ItemPop}, 0, 0, S_NULL}, // S_DEADRANDOMITEM
{SPR_SBOX, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX2}, // S_SPHEREBOX1
{SPR_SBOX, 2|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX3}, // S_SPHEREBOX2
{SPR_SBOX, 4|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX4}, // S_SPHEREBOX3
{SPR_SBOX, 6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX5}, // S_SPHEREBOX4
{SPR_SBOX, 8|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX6}, // S_SPHEREBOX5
{SPR_SBOX, 10|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX7}, // S_SPHEREBOX6
{SPR_SBOX, 12|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX8}, // S_SPHEREBOX7
{SPR_SBOX, 14|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX9}, // S_SPHEREBOX8
{SPR_SBOX, 16|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX10}, // S_SPHEREBOX9
{SPR_SBOX, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX11}, // S_SPHEREBOX10
{SPR_SBOX, 20|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX12}, // S_SPHEREBOX11
{SPR_SBOX, 22|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX1}, // S_SPHEREBOX12
{SPR_NULL, 0, 0, {A_ItemPop}, 1, 0, S_NULL}, // S_DEADSPHEREBOX
{SPR_RPOP, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_RANDOMITEMPOP2}, // S_RANDOMITEMPOP1
{SPR_RPOP, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_RANDOMITEMPOP3}, // S_RANDOMITEMPOP2
{SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3
@ -4076,17 +4091,17 @@ state_t states[NUMSTATES] =
//{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM
//{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE
{SPR_SGNS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
{SPR_SGNS, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
{SPR_SGNS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3
{SPR_SGNS, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_SIGNSPARK5}, // S_SIGNSPARK4
{SPR_SGNS, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_SIGNSPARK6}, // S_SIGNSPARK5
{SPR_SGNS, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_SIGNSPARK7}, // S_SIGNSPARK6
{SPR_SGNS, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_SIGNSPARK8}, // S_SIGNSPARK7
{SPR_SGNS, FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_SIGNSPARK9}, // S_SIGNSPARK8
{SPR_SGNS, FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_SIGNSPARK10}, // S_SIGNSPARK9
{SPR_SGNS, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_SIGNSPARK11}, // S_SIGNSPARK10
{SPR_SGNS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_NULL}, // S_SIGNSPARK11
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_SIGNSPARK5}, // S_SIGNSPARK4
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_SIGNSPARK6}, // S_SIGNSPARK5
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_SIGNSPARK7}, // S_SIGNSPARK6
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_SIGNSPARK8}, // S_SIGNSPARK7
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_SIGNSPARK9}, // S_SIGNSPARK8
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_SIGNSPARK10}, // S_SIGNSPARK9
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_SIGNSPARK11}, // S_SIGNSPARK10
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_NULL}, // S_SIGNSPARK11
{SPR_DRIF, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DRIFTSPARK_A2}, // S_DRIFTSPARK_A1
{SPR_DRIF, FF_FULLBRIGHT|FF_TRANS20|1, 1, {NULL}, 0, 0, S_DRIFTSPARK_A3}, // S_DRIFTSPARK_A2
@ -4358,7 +4373,7 @@ state_t states[NUMSTATES] =
{SPR_KRBM, FF_FULLBRIGHT|9, 5, {NULL}, 0, 0, S_NULL}, // S_SLOWBOOM10
{SPR_LNDM, 0, -1, {NULL}, 0, 0, S_LANDMINE}, // S_LANDMINE
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_LANDMINE_EXPLODE
{SPR_NULL, 0, 1, {A_LandMineExplode}, 0, 0, S_NULL}, // S_LANDMINE_EXPLODE
{SPR_BHOG, 0, 3, {A_PlaySound}, sfx_s1bd, 1, S_BALLHOG2}, // S_BALLHOG1
{SPR_BHOG, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BALLHOG3}, // S_BALLHOG2
@ -23017,6 +23032,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SPHEREBOX
-1, // doomednum
S_SPHEREBOX1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_DEADSPHEREBOX, // deathstate
S_NULL, // xdeathstate
sfx_kc2e, // deathsound
60*FRACUNIT, // speed
48*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
100, // mass
MT_RANDOMITEMPOP, // damage
sfx_None, // activesound
MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_RANDOMITEMPOP
-1, // doomednum
S_INVISIBLE, // spawnstate

View file

@ -276,6 +276,7 @@ enum actionnum
A_SPBCHASE,
A_SSMINESEARCH,
A_SSMINEEXPLODE,
A_LANDMINEEXPLODE,
A_BALLHOGEXPLODE,
A_LIGHTNINGFOLLOWPLAYER,
A_FZBOOMFLASH,
@ -546,6 +547,8 @@ void A_JawzExplode();
void A_SPBChase();
void A_SSMineSearch();
void A_SSMineExplode();
void A_LandMineExplode();
void A_LandMineExplode();
void A_BallhogExplode();
void A_LightningFollowPlayer();
void A_FZBoomFlash();
@ -1067,6 +1070,7 @@ typedef enum sprite
// SRB2Kart
SPR_RNDM, // Random Item Box
SPR_SBOX, // Sphere Box (for Battle)
SPR_RPOP, // Random Item Box Pop
SPR_SGNS, // Signpost sparkle
SPR_FAST, // Speed boost trail
@ -4450,6 +4454,21 @@ typedef enum state
S_RANDOMITEM12,
S_DEADRANDOMITEM,
// Sphere Box (for Battle)
S_SPHEREBOX1,
S_SPHEREBOX2,
S_SPHEREBOX3,
S_SPHEREBOX4,
S_SPHEREBOX5,
S_SPHEREBOX6,
S_SPHEREBOX7,
S_SPHEREBOX8,
S_SPHEREBOX9,
S_SPHEREBOX10,
S_SPHEREBOX11,
S_SPHEREBOX12,
S_DEADSPHEREBOX,
// Random Item Pop
S_RANDOMITEMPOP1,
S_RANDOMITEMPOP2,
@ -6462,6 +6481,7 @@ typedef enum mobj_type
// SRB2kart
MT_RANDOMITEM,
MT_SPHEREBOX,
MT_RANDOMITEMPOP,
MT_FLOATINGITEM,
MT_ITEMCAPSULE,

View file

@ -229,6 +229,28 @@ mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT
return emerald;
}
mobj_t *K_SpawnSphereBox(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 amount)
{
mobj_t *drop = P_SpawnMobj(x, y, z, MT_SPHEREBOX);
(void)amount;
drop->angle = angle;
P_Thrust(drop,
FixedAngle(P_RandomFixed() * 180) + angle,
P_RandomRange(4, 12) * mapobjectscale);
drop->momz = flip * 12 * mapobjectscale;
if (drop->eflags & MFE_UNDERWATER)
drop->momz = (117 * drop->momz) / 200;
drop->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT);
drop->extravalue1 = amount;
return drop;
}
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType)
{
UINT8 i;
@ -359,6 +381,12 @@ void K_RunPaperItemSpawners(void)
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
0, 0
);
K_SpawnSphereBox(
battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip),
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
10
);
}
}
else
@ -441,6 +469,14 @@ void K_RunPaperItemSpawners(void)
firstUnspawnedEmerald
);
}
else if (P_RandomChance(FRACUNIT/3))
{
drop = K_SpawnSphereBox(
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
10
);
}
else
{
drop = K_CreatePaperItem(

View file

@ -22,6 +22,7 @@ void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount);
void K_CheckBumpers(void);
void K_CheckEmeralds(player_t *player);
mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT32 emeraldType);
mobj_t *K_SpawnSphereBox(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 amount);
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType);
UINT8 K_NumEmeralds(player_t *player);
void K_RunPaperItemSpawners(void);

View file

@ -273,16 +273,94 @@ boolean K_PlayerUsesBotMovement(player_t *player)
--------------------------------------------------*/
boolean K_BotCanTakeCut(player_t *player)
{
if (!K_ApplyOffroad(player)
if (
#if 1
K_TripwirePass(player) == true
#else
K_ApplyOffroad(player) == false
#endif
|| player->itemtype == KITEM_SNEAKER
|| player->itemtype == KITEM_ROCKETSNEAKER
|| player->itemtype == KITEM_INVINCIBILITY
|| player->itemtype == KITEM_HYUDORO)
)
{
return true;
}
return false;
}
/*--------------------------------------------------
static line_t *K_FindBotController(mobj_t *mo)
Finds if any bot controller linedefs are tagged to the bot's sector.
Input Arguments:-
mo - The bot player's mobj.
Return:-
Linedef of the bot controller. NULL if it doesn't exist.
--------------------------------------------------*/
static line_t *K_FindBotController(mobj_t *mo)
{
msecnode_t *node;
ffloor_t *rover;
INT16 lineNum = -1;
mtag_t tag;
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
{
continue;
}
tag = Tag_FGet(&node->m_sector->tags);
lineNum = P_FindSpecialLineFromTag(2004, tag, -1); // todo: needs to not use P_FindSpecialLineFromTag
if (lineNum != -1)
{
break;
}
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
sector_t *rs = NULL;
if (!(rover->flags & FF_EXISTS))
{
continue;
}
if (mo->z > *rover->topheight || mo->z + mo->height < *rover->bottomheight)
{
continue;
}
rs = &sectors[rover->secnum];
tag = Tag_FGet(&rs->tags);
lineNum = P_FindSpecialLineFromTag(2004, tag, -1);
if (lineNum != -1)
{
break;
}
}
}
if (lineNum != -1)
{
return &lines[lineNum];
}
else
{
return NULL;
}
}
/*--------------------------------------------------
static UINT32 K_BotRubberbandDistance(player_t *player)
@ -346,6 +424,7 @@ fixed_t K_BotRubberband(player_t *player)
fixed_t rubberband = FRACUNIT;
fixed_t max, min;
player_t *firstplace = NULL;
line_t *botController = NULL;
UINT8 i;
if (player->exiting)
@ -354,6 +433,17 @@ fixed_t K_BotRubberband(player_t *player)
return FRACUNIT;
}
botController = K_FindBotController(player->mo);
if (botController != NULL)
{
// No Climb Flag: Disable rubberbanding
if (botController->flags & ML_NOCLIMB)
{
return FRACUNIT;
}
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
@ -430,8 +520,8 @@ fixed_t K_BotTopSpeedRubberband(player_t *player)
}
else
{
// Max at +10% for level 9 bots
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 10);
// Max at +20% for level 9 bots
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 5);
}
// Only allow you to go faster than your regular top speed if you're facing the right direction
@ -488,6 +578,14 @@ fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
return frict;
}
if (player->tiregrease > 0)
{
// This isn't great -- it means rubberbanding will slow down when they hit a spring
// But it's better than the opposite where they accelerate into hyperspace :V
// (would appreciate an actual fix though ... could try being additive instead of multiplicative)
return frict;
}
origFrict = FixedDiv(ORIG_FRICTION, FRACUNIT + (rubberband / 2));
if (frict == ORIG_FRICTION)
@ -567,14 +665,11 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN); // Reduce prediction based on how fast you can turn
const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to
const fixed_t distreduce = K_BotReducePrediction(player);
const fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT);
const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict
const fixed_t speed = max(P_AproxDistance(player->mo->momx, player->mo->momy), K_GetKartSpeed(player, false) / 4);
const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy);
const INT32 startDist = (768 * mapobjectscale) / FRACUNIT;
const INT32 distance = ((FixedMul(speed, distreduce) / FRACUNIT) * futuresight) + startDist;
const INT32 distance = ((speed / FRACUNIT) * futuresight) + startDist;
botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
waypoint_t *wp = player->nextwaypoint;
@ -583,6 +678,9 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
fixed_t smallestradius = INT32_MAX;
angle_t angletonext = ANGLE_MAX;
// Halves radius when encountering a wall on your way to your destination.
fixed_t radreduce = FRACUNIT;
size_t nwp;
size_t i;
@ -595,7 +693,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
{
predict->x = wp->mobj->x;
predict->y = wp->mobj->y;
predict->radius = FixedMul(wp->mobj->radius, radreduce);
predict->radius = wp->mobj->radius;
return predict;
}
@ -635,12 +733,12 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
for (i = 0; i < wp->numnextwaypoints; i++)
{
if (!K_GetWaypointIsEnabled(wp->nextwaypoints[i]))
if (K_GetWaypointIsEnabled(wp->nextwaypoints[i]) == false)
{
continue;
}
if (K_GetWaypointIsShortcut(wp->nextwaypoints[i]) && !K_BotCanTakeCut(player))
if (K_GetWaypointIsShortcut(wp->nextwaypoints[i]) == true && K_BotCanTakeCut(player) == false)
{
continue;
}
@ -673,6 +771,13 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
disttonext = (INT32)wp->nextwaypointdistances[nwp];
if (P_TraceBotTraversal(player->mo, wp->nextwaypoints[nwp]->mobj) == false)
{
// If we can't get a direct path to this waypoint, we don't want to check much further...
disttonext *= 2;
radreduce = FRACUNIT/2;
}
if (disttonext > distanceleft)
{
break;
@ -761,7 +866,7 @@ static UINT8 K_TrySpindash(player_t *player)
return 0;
}
if (speedDiff < (3 * baseAccel / 4))
if (speedDiff < (baseAccel / 4))
{
if (player->botvars.spindashconfirm < BOTSPINDASHCONFIRM)
{
@ -797,70 +902,6 @@ static UINT8 K_TrySpindash(player_t *player)
return 0;
}
/*--------------------------------------------------
static INT16 K_FindBotController(mobj_t *mo)
Finds if any bot controller linedefs are tagged to the bot's sector.
Input Arguments:-
mo - The bot player's mobj.
Return:-
Line number of the bot controller. -1 if it doesn't exist.
--------------------------------------------------*/
static INT16 K_FindBotController(mobj_t *mo)
{
msecnode_t *node;
ffloor_t *rover;
INT16 lineNum = -1;
mtag_t tag;
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
{
continue;
}
tag = Tag_FGet(&node->m_sector->tags);
lineNum = P_FindSpecialLineFromTag(2004, tag, -1); // todo: needs to not use P_FindSpecialLineFromTag
if (lineNum != -1)
{
return lineNum;
}
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
sector_t *rs = NULL;
if (!(rover->flags & FF_EXISTS))
{
continue;
}
if (mo->z > *rover->topheight || mo->z + mo->height < *rover->bottomheight)
{
continue;
}
rs = &sectors[rover->secnum];
tag = Tag_FGet(&rs->tags);
lineNum = P_FindSpecialLineFromTag(2004, tag, -1);
if (lineNum != -1)
{
return lineNum;
}
}
}
return -1;
}
/*--------------------------------------------------
static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
@ -925,6 +966,50 @@ static void K_DrawPredictionDebug(botprediction_t *predict, player_t *player)
}
}
/*--------------------------------------------------
static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController)
Determines inputs for trick panels.
Input Arguments:-
player - Player to generate the ticcmd for.
cmd - The player's ticcmd to modify.
botController - Linedef for the bot controller.
Return:-
None
--------------------------------------------------*/
static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController)
{
// Trick panel state -- do nothing until a controller line is found, in which case do a trick.
if (botController == NULL)
{
return;
}
if (player->trickpanel == 1)
{
INT32 type = (sides[botController->sidenum[0]].rowoffset / FRACUNIT);
// Y Offset: Trick type
switch (type)
{
case 1:
cmd->turning = KART_FULLTURN;
break;
case 2:
cmd->turning = -KART_FULLTURN;
break;
case 3:
cmd->buttons |= BT_FORWARD;
break;
case 4:
cmd->buttons |= BT_BACKWARD;
break;
}
}
}
/*--------------------------------------------------
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
@ -936,7 +1021,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
boolean trySpindash = true;
UINT8 spindash = 0;
INT32 turnamt = 0;
INT16 botController = -1;
line_t *botController = NULL;
// Can't build a ticcmd if we aren't spawned...
if (!player->mo)
@ -959,7 +1044,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
}
// Complete override of all ticcmd functionality
if (LUAh_BotTiccmd(player, cmd))
if (LUAh_BotTiccmd(player, cmd) == true)
{
return;
}
@ -968,30 +1053,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
if (player->trickpanel != 0)
{
// Trick panel state -- do nothing until a controller line is found, in which case do a trick.
if (player->trickpanel == 1 && botController != -1)
{
line_t *controllerLine = &lines[botController];
INT32 type = (sides[controllerLine->sidenum[0]].rowoffset / FRACUNIT);
// Y Offset: Trick type
switch (type)
{
case 1:
cmd->turning = KART_FULLTURN;
break;
case 2:
cmd->turning = -KART_FULLTURN;
break;
case 3:
cmd->buttons |= BT_FORWARD;
break;
case 4:
cmd->buttons |= BT_BACKWARD;
break;
}
}
K_BotTrick(player, cmd, botController);
// Don't do anything else.
return;
@ -1000,20 +1062,19 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
if ((player->nextwaypoint != NULL
&& player->nextwaypoint->mobj != NULL
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|| (botController != -1))
|| (botController != NULL))
{
// Handle steering towards waypoints!
SINT8 turnsign = 0;
angle_t destangle, moveangle, angle;
INT16 anglediff;
if (botController != -1)
if (botController != NULL && (botController->flags & ML_EFFECT1))
{
const fixed_t dist = (player->mo->radius * 4);
line_t *controllerLine = &lines[botController];
// X Offset: Movement direction
destangle = FixedAngle(sides[controllerLine->sidenum[0]].textureoffset);
destangle = FixedAngle(sides[botController->sidenum[0]].textureoffset);
// Overwritten prediction
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
@ -1112,18 +1173,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
// Don't turn at all
turnamt = 0;
}
else
{
// Make minor adjustments
turnamt /= 4;
}
}
if (anglediff > 60)
{
// Actually, don't go too fast...
cmd->forwardmove /= 2;
cmd->buttons |= BT_BRAKE;
}
}
}

View file

@ -15,6 +15,7 @@
#include "k_waypoint.h"
#include "d_player.h"
#include "r_defs.h"
// Maximum value of botvars.difficulty
#define MAXBOTDIFFICULTY 9
@ -185,19 +186,22 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y);
/*--------------------------------------------------
fixed_t K_BotReducePrediction(player_t *player);
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
Finds walls nearby the specified player, to create a multiplier
to pull bot predictions back by.
Tells us if a bot will play more careful around
this sector. Checks FOFs in the sector, as well.
Input Arguments:-
player - Player to compare.
player - Player to check against.
sec - Sector to check against.
x - Linedef cross X position, for slopes
y - Linedef cross Y position, for slopes
Return:-
Multiplier in fixed point scale.
true if avoiding this sector, false otherwise.
--------------------------------------------------*/
fixed_t K_BotReducePrediction(player_t *player);
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y);
/*--------------------------------------------------
@ -219,8 +223,8 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
/*--------------------------------------------------
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
Gives a multiplier for a bot's rubberbanding. Meant to be used for top speed,
acceleration, and handling.
Creates a bot's ticcmd, looking at its surroundings to
try and figure out what it should do.
Input Arguments:-
player - Player to generate the ticcmd for.

View file

@ -86,7 +86,7 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
}
/*--------------------------------------------------
static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
Looks for players around a specified x/y coordinate.
@ -97,9 +97,9 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
radius - The radius to look for players in.
Return:-
true if a player was found around the coordinate, otherwise false.
The player we found, NULL if nothing was found.
--------------------------------------------------*/
static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
static player_t *K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius)
{
UINT8 i;
@ -129,15 +129,15 @@ static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t
if (dist <= radius)
{
return true;
return target;
}
}
return false;
return NULL;
}
/*--------------------------------------------------
static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
Looks for players around the predicted coordinates of their thrown item.
@ -146,9 +146,9 @@ static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t
extra - Extra throwing distance, for aim forward on mines.
Return:-
true if a player was found around the coordinate, otherwise false.
The player we're trying to throw at, NULL if none was found.
--------------------------------------------------*/
static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
static player_t *K_PlayerPredictThrow(player_t *player, UINT8 extra)
{
const fixed_t dist = (30 + (extra * 10)) * player->mo->scale;
const UINT32 airtime = FixedDiv(dist + player->mo->momz, gravity);
@ -159,7 +159,7 @@ static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
}
/*--------------------------------------------------
static boolean K_PlayerInCone(player_t *player, UINT16 cone, boolean flip)
static player_t *K_PlayerInCone(player_t *player, UINT16 cone, boolean flip)
Looks for players in the .
@ -172,7 +172,7 @@ static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra)
Return:-
true if a player was found in the cone, otherwise false.
--------------------------------------------------*/
static boolean K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boolean flip)
static player_t *K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boolean flip)
{
UINT8 i;
@ -222,22 +222,96 @@ static boolean K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boo
{
if (ad >= 180-cone)
{
return true;
return target;
}
}
else
{
if (ad <= cone)
{
return true;
return target;
}
}
}
}
return NULL;
}
/*--------------------------------------------------
static boolean K_RivalBotAggression(player_t *bot, player_t *target)
Returns if a bot is a rival & wants to be aggressive to a player.
Input Arguments:-
bot - Bot to check.
target - Who the bot wants to attack.
Return:-
false if not the rival. false if the target is another bot. Otherwise, true.
--------------------------------------------------*/
static boolean K_RivalBotAggression(player_t *bot, player_t *target)
{
if (bot == NULL || target == NULL)
{
// Invalid.
return false;
}
if (bot->bot == false)
{
// lol
return false;
}
if (bot->botvars.rival == false)
{
// Not the rival, we aren't self-aware.
return false;
}
if (target->bot == false)
{
// This bot knows that the real threat is the player.
return true;
}
// Calling them your friends is misleading, but you'll at least spare them.
return false;
}
/*--------------------------------------------------
static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amount)
Handles updating item confirm values for offense items.
Input Arguments:-
bot - Bot to check.
target - Who the bot wants to attack.
amount - Amount to increase item confirm time by.
Return:-
None
--------------------------------------------------*/
static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amount)
{
if (bot == NULL || target == NULL)
{
return;
}
if (K_RivalBotAggression(bot, target) == true)
{
// Double the rate when you're aggressive.
bot->botvars.itemconfirm += amount << 1;
}
else
{
// Do as normal.
bot->botvars.itemconfirm += amount;
}
}
/*--------------------------------------------------
static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
@ -316,21 +390,21 @@ static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean
}
// Check the predicted throws.
if (K_PlayerPredictThrow(player, 0))
if (K_PlayerPredictThrow(player, 0) != NULL)
{
return true;
}
if (mine)
{
if (K_PlayerPredictThrow(player, 1))
if (K_PlayerPredictThrow(player, 1) != NULL)
{
return true;
}
}
// Check your behind.
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true) != NULL)
{
return true;
}
@ -447,7 +521,6 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
}
}
/*--------------------------------------------------
static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
@ -464,9 +537,17 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
SINT8 throwdir = -1;
player_t *target = NULL;
player->botvars.itemconfirm++;
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
if (target != NULL)
{
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
throwdir = -1;
}
if (abs(turnamt) >= KART_FULLTURN/2)
{
player->botvars.itemconfirm += player->botvars.difficulty / 2;
@ -474,19 +555,15 @@ static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
}
else
{
if (K_PlayerPredictThrow(player, 0))
target = K_PlayerPredictThrow(player, 0);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty * 2;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * 2);
throwdir = 1;
}
}
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
{
player->botvars.itemconfirm += player->botvars.difficulty;
throwdir = -1;
}
if (player->botvars.itemconfirm > 2*TICRATE || player->bananadrag >= TICRATE)
{
K_BotGenericPressItem(player, cmd, throwdir);
@ -509,12 +586,14 @@ static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt)
static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
SINT8 throwdir = 0;
player_t *target = NULL;
player->botvars.itemconfirm++;
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
throwdir = -1;
}
@ -525,27 +604,63 @@ static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
}
else
{
if (K_PlayerPredictThrow(player, 0))
target = K_PlayerPredictThrow(player, 0);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty * 2;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * 2);
throwdir = 0;
}
if (K_PlayerPredictThrow(player, 1))
target = K_PlayerPredictThrow(player, 1);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty * 2;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * 2);
throwdir = 1;
}
}
if (player->botvars.itemconfirm > 2*TICRATE || player->bananadrag >= TICRATE)
{
K_BotGenericPressItem(player, cmd, throwdir);
}
}
/*--------------------------------------------------
static void K_BotItemLandmine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
Item usage for landmine tossing.
Input Arguments:-
player - Bot to do this for.
cmd - Bot's ticcmd to edit.
turnamt - How hard they currently are turning.
Return:-
None
--------------------------------------------------*/
static void K_BotItemLandmine(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
player_t *target = NULL;
player->botvars.itemconfirm++;
if (abs(turnamt) >= KART_FULLTURN/2)
{
player->botvars.itemconfirm += player->botvars.difficulty / 2;
}
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
if (target != NULL)
{
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
}
if (player->botvars.itemconfirm > 2*TICRATE)
{
K_BotGenericPressItem(player, cmd, -1);
}
}
/*--------------------------------------------------
static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
@ -562,18 +677,21 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
{
const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y);
SINT8 throwdir = -1;
player_t *target = NULL;
player->botvars.itemconfirm++;
if (K_PlayerPredictThrow(player, 0))
target = K_PlayerPredictThrow(player, 0);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty / 2;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty / 2);
throwdir = 1;
}
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
throwdir = -1;
}
@ -603,6 +721,7 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
static boolean K_BotRevealsEggbox(player_t *player)
{
const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y);
player_t *target = NULL;
// This is a stealthy spot for an eggbox, lets reveal it!
if (stealth > 1)
@ -611,13 +730,15 @@ static boolean K_BotRevealsEggbox(player_t *player)
}
// Check the predicted throws.
if (K_PlayerPredictThrow(player, 0))
target = K_PlayerPredictThrow(player, 0);
if (target != NULL)
{
return true;
}
// Check your behind.
if (K_PlayerInCone(player, player->mo->radius * 16, 10, true))
target = K_PlayerInCone(player, player->mo->radius * 16, 10, true);
if (target != NULL)
{
return true;
}
@ -644,7 +765,7 @@ static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd)
return;
}
if (K_BotRevealsEggbox(player) || (player->botvars.itemconfirm++ > 20*TICRATE))
if (K_BotRevealsEggbox(player) == true || (player->botvars.itemconfirm++ > 20*TICRATE))
{
K_BotGenericPressItem(player, cmd, 0);
}
@ -666,8 +787,9 @@ static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
{
if (player->position == 1)
{
// Hey, we aren't gonna find anyone up here...
// why don't we slow down a bit? :)
cmd->forwardmove /= 2;
cmd->buttons |= BT_BRAKE;
}
K_BotUseItemNearPlayer(player, cmd, 128*player->mo->scale);
@ -690,23 +812,32 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
const fixed_t topspeed = K_GetKartSpeed(player, false);
fixed_t radius = (player->mo->radius * 32);
SINT8 throwdir = -1;
UINT8 snipeMul = 2;
player_t *target = NULL;
if (player->speed > topspeed)
{
radius = FixedMul(radius, FixedDiv(player->speed, topspeed));
snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!!
}
player->botvars.itemconfirm++;
if (K_PlayerInCone(player, radius, 10, false))
target = K_PlayerInCone(player, radius, 10, false);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty * 2;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * snipeMul);
throwdir = 1;
}
else if (K_PlayerInCone(player, radius, 10, true))
{
player->botvars.itemconfirm += player->botvars.difficulty;
throwdir = -1;
target = K_PlayerInCone(player, radius, 10, true);
if (target != NULL)
{
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
throwdir = -1;
}
}
if (player->botvars.itemconfirm > 5*TICRATE)
@ -732,24 +863,54 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
const fixed_t topspeed = K_GetKartSpeed(player, false);
fixed_t radius = (player->mo->radius * 32);
SINT8 throwdir = 1;
UINT8 snipeMul = 2;
INT32 lastTarg = player->lastjawztarget;
player_t *target = NULL;
if (player->speed > topspeed)
{
radius = FixedMul(radius, FixedDiv(player->speed, topspeed));
snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!!
}
player->botvars.itemconfirm++;
if (K_PlayerInCone(player, radius, 10, true))
target = K_PlayerInCone(player, radius, 10, true);
if (target != NULL)
{
player->botvars.itemconfirm += player->botvars.difficulty;
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
throwdir = -1;
}
if (player->lastjawztarget != -1)
if (lastTarg != -1
&& playeringame[lastTarg] == true
&& players[lastTarg].spectator == false
&& players[lastTarg].mo != NULL
&& P_MobjWasRemoved(players[lastTarg].mo) == false)
{
player->botvars.itemconfirm += player->botvars.difficulty * 2;
throwdir = 1;
mobj_t *targMo = players[lastTarg].mo;
mobj_t *mobj = NULL, *next = NULL;
boolean targettedAlready = false;
target = &players[lastTarg];
// Make sure no other Jawz are targetting this player.
for (mobj = kitemcap; mobj; mobj = next)
{
next = mobj->itnext;
if (mobj->type == MT_JAWZ && mobj->target == targMo)
{
targettedAlready = true;
break;
}
}
if (targettedAlready == false)
{
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * snipeMul);
throwdir = 1;
}
}
if (player->botvars.itemconfirm > 5*TICRATE)
@ -772,7 +933,7 @@ static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemThunder(player_t *player, ticcmd_t *cmd)
{
if (!K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale))
if (K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale) == false)
{
if (player->botvars.itemconfirm > 10*TICRATE)
{
@ -1036,7 +1197,6 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
K_BotItemSneaker(player, cmd);
break;
case KITEM_BANANA:
case KITEM_LANDMINE:
if (!(player->pflags & PF_ITEMOUT))
{
K_BotItemGenericTrapShield(player, cmd, turnamt, false);
@ -1081,6 +1241,9 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
K_BotItemMine(player, cmd, turnamt);
}
break;
case KITEM_LANDMINE:
K_BotItemLandmine(player, cmd, turnamt);
break;
case KITEM_THUNDERSHIELD:
K_BotItemThunder(player, cmd);
break;

View file

@ -122,7 +122,7 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y)
}
}
return (globalsmuggle.randomitems * globalsmuggle.eggboxes);
return (globalsmuggle.randomitems * (globalsmuggle.eggboxes + 1));
}
/*--------------------------------------------------
@ -162,21 +162,11 @@ static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec)
}
/*--------------------------------------------------
static boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
Tells us if a bot will play more careful around
this sector. Checks FOFs in the sector, as well.
Input Arguments:-
player - Player to check against.
sec - Sector to check against.
x - Linedef cross X position, for slopes
y - Linedef cross Y position, for slopes
Return:-
true if avoiding this sector, false otherwise.
See header file for description.
--------------------------------------------------*/
static boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t y)
{
const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP);
INT32 specialflag = 0;
@ -257,171 +247,6 @@ static boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x,
return K_BotHatesThisSectorsSpecial(player, bestsector);
}
/*--------------------------------------------------
static boolean K_FindBlockingWalls(line_t *line)
Blockmap search function.
Reels the bot prediction back in based on solid walls
or other obstacles surrounding the bot.
Input Arguments:-
line - Linedef passed in from iteration.
Return:-
true continues searching, false ends the search early.
--------------------------------------------------*/
static boolean K_FindBlockingWalls(line_t *line)
{
// Condensed version of PIT_CheckLine
const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale);
fixed_t maxstep = maxstepmove;
fixed_t linedist = INT32_MAX;
INT32 lineside = 0;
vertex_t pos;
if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player)
{
return false;
}
if (line->polyobj && !(line->polyobj->flags & POF_SOLID))
{
return true;
}
if (tmbbox[BOXRIGHT] <= line->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= line->bbox[BOXRIGHT]
|| tmbbox[BOXTOP] <= line->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= line->bbox[BOXTOP])
{
return true;
}
if (P_BoxOnLineSide(tmbbox, line) != -1)
{
return true;
}
lineside = P_PointOnLineSide(globalsmuggle.botmo->x, globalsmuggle.botmo->y, line);
// one sided line
if (!line->backsector)
{
if (lineside)
{
// don't hit the back side
return true;
}
goto blocked;
}
if ((line->flags & ML_IMPASSABLE) || (line->flags & ML_BLOCKPLAYERS))
{
goto blocked;
}
// set openrange, opentop, openbottom
P_LineOpening(line, globalsmuggle.botmo);
if (globalsmuggle.botmo->player->waterskip)
maxstep += maxstepmove;
if (P_MobjTouchingSectorSpecial(globalsmuggle.botmo, 1, 13, false))
maxstep <<= 1;
else if (P_MobjTouchingSectorSpecial(globalsmuggle.botmo, 1, 12, false))
maxstep = 0;
if ((openrange < globalsmuggle.botmo->height) // doesn't fit
|| (opentop - globalsmuggle.botmo->z < globalsmuggle.botmo->height) // mobj is too high
|| (openbottom - globalsmuggle.botmo->z > maxstep)) // too big a step up
{
goto blocked;
}
// Treat damage sectors like walls
P_ClosestPointOnLine(globalsmuggle.botmo->x, globalsmuggle.botmo->y, line, &pos);
if (lineside)
{
if (K_BotHatesThisSector(globalsmuggle.botmo->player, line->frontsector, pos.x, pos.y))
goto blocked;
}
else
{
if (K_BotHatesThisSector(globalsmuggle.botmo->player, line->backsector, pos.x, pos.y))
goto blocked;
}
// We weren't blocked!
return true;
blocked:
linedist = K_DistanceOfLineFromPoint(line->v1->x, line->v1->y, line->v2->x, line->v2->y, globalsmuggle.botmo->x, globalsmuggle.botmo->y);
linedist -= (globalsmuggle.botmo->radius * 8); // Maintain a reasonable distance away from it
if (linedist > globalsmuggle.distancetocheck)
{
return true;
}
if (linedist <= 0)
{
globalsmuggle.closestlinedist = 0;
return false;
}
if (linedist < globalsmuggle.closestlinedist)
{
globalsmuggle.closestlinedist = linedist;
}
return true;
}
/*--------------------------------------------------
fixed_t K_BotReducePrediction(player_t *player)
See header file for description.
--------------------------------------------------*/
fixed_t K_BotReducePrediction(player_t *player)
{
INT32 xl, xh, yl, yh, bx, by;
globalsmuggle.botmo = player->mo;
globalsmuggle.distancetocheck = (player->mo->radius * 32);
globalsmuggle.closestlinedist = INT32_MAX;
tmx = player->mo->x;
tmy = player->mo->y;
xl = (unsigned)(tmx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(tmx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(tmy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(tmy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
tmbbox[BOXTOP] = tmy + globalsmuggle.distancetocheck;
tmbbox[BOXBOTTOM] = tmy - globalsmuggle.distancetocheck;
tmbbox[BOXRIGHT] = tmx + globalsmuggle.distancetocheck;
tmbbox[BOXLEFT] = tmx - globalsmuggle.distancetocheck;
// Check for lines that the bot might collide with
for (bx = xl; bx <= xh; bx++)
{
for (by = yl; by <= yh; by++)
{
P_BlockLinesIterator(bx, by, K_FindBlockingWalls);
}
}
if (globalsmuggle.closestlinedist == INT32_MAX)
{
return FRACUNIT;
}
return (FRACUNIT/2) + (FixedDiv(globalsmuggle.closestlinedist, globalsmuggle.distancetocheck) / 2);
}
/*--------------------------------------------------
static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)

256
src/k_brightmap.c Normal file
View file

@ -0,0 +1,256 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2021 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2021 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_brightmap.c
/// \brief Brightmap texture loading.
#include "k_brightmap.h"
#include "doomdata.h"
#include "doomdef.h"
#include "doomtype.h"
#include "fastcmp.h"
#include "r_textures.h"
#include "w_wad.h"
#include "z_zone.h"
static brightmapStorage_t *brightmapStorage = NULL;
static size_t maxBrightmapStorage = 0;
/*--------------------------------------------------
static brightmapStorage_t *K_NewBrightmap(void)
Increases the size of maxBrightmapStorage by 1.
Input Arguments:-
None
Return:-
The new brightmap storage struct.
--------------------------------------------------*/
static brightmapStorage_t *K_NewBrightmap(void)
{
maxBrightmapStorage++;
brightmapStorage = (brightmapStorage_t *)Z_Realloc(brightmapStorage, sizeof(brightmapStorage_t) * (maxBrightmapStorage + 1), PU_STATIC, NULL);
return &brightmapStorage[ maxBrightmapStorage - 1 ];
}
/*--------------------------------------------------
static brightmapStorage_t *K_GetBrightmapStorageByIndex(size_t checkIndex)
See header file for description.
--------------------------------------------------*/
static brightmapStorage_t *K_GetBrightmapStorageByIndex(size_t checkIndex)
{
if (checkIndex >= maxBrightmapStorage)
{
return NULL;
}
return &brightmapStorage[checkIndex];
}
/*--------------------------------------------------
static brightmapStorage_t *K_GetBrightmapStorageByTextureName(const char *checkName)
See header file for description.
--------------------------------------------------*/
static brightmapStorage_t *K_GetBrightmapStorageByTextureName(const char *checkName)
{
size_t i;
if (maxBrightmapStorage == 0)
{
return NULL;
}
for (i = 0; i < maxBrightmapStorage; i++)
{
brightmapStorage_t *bms = &brightmapStorage[i];
if (stricmp(checkName, bms->textureName) == 0)
{
// Name matches.
return bms;
}
}
return NULL;
}
/*--------------------------------------------------
static boolean K_BRIGHTLumpParser(UINT8 *data, size_t size)
Parses inputted lump data as a BRIGHT lump.
Input Arguments:-
data - Pointer to lump data.
size - The length of the lump data.
Return:-
false if any errors occured, otherwise true.
--------------------------------------------------*/
static boolean K_BRIGHTLumpParser(UINT8 *data, size_t size)
{
char *tkn = M_GetToken((char *)data);
size_t pos = 0;
while (tkn && (pos = M_GetTokenPos()) < size)
{
boolean valid = true;
if (stricmp(tkn, "texture") == 0)
{
Z_Free(tkn);
tkn = M_GetToken(NULL);
pos = M_GetTokenPos();
if (tkn && pos < size)
{
brightmapStorage_t *bms = K_GetBrightmapStorageByTextureName(tkn);
if (bms == NULL)
{
bms = K_NewBrightmap();
strncpy(bms->textureName, tkn, 9);
}
Z_Free(tkn);
tkn = M_GetToken(NULL);
pos = M_GetTokenPos();
if (tkn && pos < size)
{
strncpy(bms->brightmapName, tkn, 9);
}
else
{
CONS_Alert(CONS_ERROR, "No brightmap for brightmap definition.\n");
valid = false;
}
}
else
{
CONS_Alert(CONS_ERROR, "No texture for brightmap definition.\n");
valid = false;
}
}
// todo: SPRITE brightmaps?!
else
{
CONS_Alert(CONS_ERROR, "Unknown keyword '%s' found in BRIGHT lump.\n", tkn);
valid = false;
}
Z_Free(tkn);
if (valid == false)
{
return false;
}
tkn = M_GetToken(NULL);
}
Z_Free(tkn);
return true;
}
/*--------------------------------------------------
void K_InitBrightmaps(void)
See header file for description.
--------------------------------------------------*/
void K_InitBrightmaps(void)
{
INT32 wadNum;
size_t i;
I_Assert(brightmapStorage == NULL);
maxBrightmapStorage = 0;
for (wadNum = 0; wadNum < numwadfiles; wadNum++)
{
UINT16 lumpNum;
// Find BRIGHT lump in the WAD
lumpNum = W_CheckNumForNamePwad("BRIGHT", wadNum, 0);
while (lumpNum != INT16_MAX)
{
UINT8 *data;
data = (UINT8 *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC);
// If that didn't exist, we have nothing to do here.
if (data == NULL)
{
lumpNum = W_CheckNumForNamePwad("BRIGHT", (UINT16)wadNum, lumpNum + 1);
continue;
}
else
{
lumpinfo_t *lump_p = &wadfiles[wadNum]->lumpinfo[lumpNum];
size_t size = W_LumpLengthPwad(wadNum, lumpNum);
size_t nameLength = strlen(wadfiles[wadNum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
char *name = malloc(nameLength + 1);
sprintf(name, "%s|%s", wadfiles[wadNum]->filename, lump_p->fullname);
name[nameLength] = '\0';
size = W_LumpLengthPwad(wadNum, lumpNum);
CONS_Printf(M_GetText("Loading BRIGHT from %s\n"), name);
K_BRIGHTLumpParser(data, size);
free(name);
}
lumpNum = W_CheckNumForNamePwad("BRIGHT", (UINT16)wadNum, lumpNum + 1);
}
}
if (maxBrightmapStorage == 0)
{
// No brightmaps were defined.
return;
}
for (i = 0; i < maxBrightmapStorage; i++)
{
brightmapStorage_t *bms = K_GetBrightmapStorageByIndex(i);
INT32 texNum, bmNum;
if (bms == NULL)
{
// Shouldn't happen.
break;
}
texNum = R_CheckTextureNumForName(bms->textureName);
if (texNum != -1)
{
bmNum = R_CheckTextureNumForName(bms->brightmapName);
if (bmNum == -1)
{
texturebrightmaps[texNum] = 0;
}
else
{
texturebrightmaps[texNum] = bmNum;
}
}
}
R_ClearTextureNumCache(false);
// Clear brightmapStorage now that we're done with it.
Z_Free(brightmapStorage);
brightmapStorage = NULL;
}

38
src/k_brightmap.h Normal file
View file

@ -0,0 +1,38 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2021 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2021 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_brightmap.h
/// \brief Brightmap texture loading.
#ifndef __K_BRIGHTMAP_H__
#define __K_BRIGHTMAP_H__
#include "doomdata.h"
#include "doomdef.h"
#include "doomtype.h"
typedef struct brightmapStorage_s
{
// Brightmap storage struct.
// Stores data for brightmap definitions,
// before putting them into texturebrightmaps.
char textureName[9]; // The texture's name.
char brightmapName[9]; // The brightmap's name.
} brightmapStorage_t;
/*--------------------------------------------------
void K_InitBrightmaps(void);
Finds all BRIGHT lumps and processes them.
--------------------------------------------------*/
void K_InitBrightmaps(void);
#endif // __K_BRIGHTMAP_H__

View file

@ -801,7 +801,7 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu
player_t *player;
fixed_t viewpointX, viewpointY, viewpointZ;
angle_t viewpointAngle, viewpointAiming;
angle_t viewpointAngle, viewpointAiming, viewpointRoll;
INT32 screenWidth, screenHeight;
fixed_t screenHalfW, screenHalfH;
@ -829,12 +829,13 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu
cam = &camera[cameraNum];
player = &players[displayplayers[cameraNum]];
if (cam == NULL || player == NULL)
if (cam == NULL || player == NULL || player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
{
// Shouldn't be possible?
return;
}
// TODO: needs da interp
if (cam->chase == true && !player->spectator)
{
// Use the camera's properties.
@ -843,26 +844,45 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu
viewpointZ = cam->z - point->z;
viewpointAngle = (INT32)cam->angle;
viewpointAiming = (INT32)cam->aiming;
viewpointRoll = (INT32)player->viewrollangle;
if (cv_frameinterpolation.value == 1)
{
viewpointX = cam->old_x + FixedMul(rendertimefrac, cam->x - cam->old_x);
viewpointY = cam->old_y + FixedMul(rendertimefrac, cam->y - cam->old_y);
viewpointZ = (cam->old_z + FixedMul(rendertimefrac, cam->z - cam->old_z)) - point->z;
viewpointAngle = (INT32)(cam->old_angle + FixedMul(rendertimefrac, cam->angle - cam->old_angle));
viewpointAiming = (INT32)(cam->old_aiming + FixedMul(rendertimefrac, cam->aiming - cam->old_aiming));
viewpointRoll = (INT32)(player->old_viewrollangle + FixedMul(rendertimefrac, player->viewrollangle - player->old_viewrollangle));
}
}
else
{
// Use player properties.
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
{
// This shouldn't happen.
return;
}
viewpointX = player->mo->x;
viewpointY = player->mo->y;
viewpointZ = player->viewz - point->z;
viewpointAngle = (INT32)player->mo->angle;
viewpointAiming = (INT32)player->aiming;
viewpointRoll = (INT32)player->viewrollangle;
if (cv_frameinterpolation.value == 1)
{
viewpointX = player->mo->old_x + FixedMul(rendertimefrac, player->mo->x - player->mo->old_x);
viewpointY = player->mo->old_y + FixedMul(rendertimefrac, player->mo->y - player->mo->old_y);
viewpointZ = (player->mo->old_z + FixedMul(rendertimefrac, player->viewz - player->mo->old_z)) - point->z; //player->old_viewz
viewpointAngle = (INT32)(player->mo->old_angle + FixedMul(rendertimefrac, player->mo->angle - player->mo->old_angle));
//viewpointAiming = (INT32)(player->mo->old_aiming + FixedMul(rendertimefrac, player->mo->aiming - player->mo->old_aiming));
viewpointRoll = (INT32)(player->old_viewrollangle + FixedMul(rendertimefrac, player->viewrollangle - player->old_viewrollangle));
}
}
viewpointAngle += (INT32)angleOffset;
(void)viewpointRoll; // will be used later...
// Calculate screen size adjustments.
// TODO: Anyone want to make this support non-green resolutions somehow? :V
screenWidth = BASEVIDWIDTH;
@ -2590,6 +2610,7 @@ static void K_drawKartPlayerCheck(void)
UINT8 *colormap = NULL;
UINT8 pnum = 0;
vector3_t v;
vector3_t pPos;
trackingResult_t result;
if (!playeringame[i] || checkplayer->spectator)
@ -2614,7 +2635,22 @@ static void K_drawKartPlayerCheck(void)
v.y = checkplayer->mo->y;
v.z = checkplayer->mo->z;
distance = R_PointToDist2(stplyr->mo->x, stplyr->mo->y, v.x, v.y);
pPos.x = stplyr->mo->x;
pPos.y = stplyr->mo->y;
pPos.z = stplyr->mo->z;
if (cv_frameinterpolation.value == 1)
{
v.x = checkplayer->mo->old_x + FixedMul(rendertimefrac, checkplayer->mo->x - checkplayer->mo->old_x);
v.y = checkplayer->mo->old_y + FixedMul(rendertimefrac, checkplayer->mo->y - checkplayer->mo->old_y);
v.z = checkplayer->mo->old_z + FixedMul(rendertimefrac, checkplayer->mo->z - checkplayer->mo->old_z);
pPos.x = stplyr->mo->old_x + FixedMul(rendertimefrac, stplyr->mo->x - stplyr->mo->old_x);
pPos.y = stplyr->mo->old_y + FixedMul(rendertimefrac, stplyr->mo->y - stplyr->mo->old_y);
pPos.z = stplyr->mo->old_z + FixedMul(rendertimefrac, stplyr->mo->z - stplyr->mo->old_z);
}
distance = R_PointToDist2(pPos.x, pPos.y, v.x, v.y);
if (distance > maxdistance)
{
@ -2801,12 +2837,26 @@ static void K_drawKartNameTags(void)
c.x = thiscam->x;
c.y = thiscam->y;
c.z = thiscam->z;
if (cv_frameinterpolation.value == 1)
{
c.x = thiscam->old_x + FixedMul(rendertimefrac, thiscam->x - thiscam->old_x);
c.y = thiscam->old_y + FixedMul(rendertimefrac, thiscam->y - thiscam->old_y);
c.z = thiscam->old_z + FixedMul(rendertimefrac, thiscam->z - thiscam->old_z);
}
}
else
{
c.x = stplyr->mo->x;
c.y = stplyr->mo->y;
c.z = stplyr->mo->z;
if (cv_frameinterpolation.value == 1)
{
c.x = stplyr->mo->old_x + FixedMul(rendertimefrac, stplyr->mo->x - stplyr->mo->old_x);
c.y = stplyr->mo->old_y + FixedMul(rendertimefrac, stplyr->mo->y - stplyr->mo->old_y);
c.z = stplyr->mo->old_z + FixedMul(rendertimefrac, stplyr->mo->z - stplyr->mo->old_z);
}
}
for (i = 0; i < MAXPLAYERS; i++)
@ -2849,6 +2899,13 @@ static void K_drawKartNameTags(void)
v.y = ntplayer->mo->y;
v.z = ntplayer->mo->z;
if (cv_frameinterpolation.value == 1)
{
v.x = ntplayer->mo->old_x + FixedMul(rendertimefrac, ntplayer->mo->x - ntplayer->mo->old_x);
v.y = ntplayer->mo->old_y + FixedMul(rendertimefrac, ntplayer->mo->y - ntplayer->mo->old_y);
v.z = ntplayer->mo->old_z + FixedMul(rendertimefrac, ntplayer->mo->z - ntplayer->mo->old_z);
}
if (!(ntplayer->mo->eflags & MFE_VERTICALFLIP))
{
v.z += ntplayer->mo->height;
@ -2904,7 +2961,16 @@ static void K_drawKartNameTags(void)
v.x = ntplayer->mo->x;
v.y = ntplayer->mo->y;
v.z = ntplayer->mo->z + (ntplayer->mo->height / 2);
v.z = ntplayer->mo->z;
if (cv_frameinterpolation.value == 1)
{
v.x = ntplayer->mo->old_x + FixedMul(rendertimefrac, ntplayer->mo->x - ntplayer->mo->old_x);
v.y = ntplayer->mo->old_y + FixedMul(rendertimefrac, ntplayer->mo->y - ntplayer->mo->old_y);
v.z = ntplayer->mo->old_z + FixedMul(rendertimefrac, ntplayer->mo->z - ntplayer->mo->old_z);
}
v.z += (ntplayer->mo->height / 2);
if (stplyr->mo->eflags & MFE_VERTICALFLIP)
{
@ -3145,7 +3211,7 @@ static void K_drawKartMinimap(void)
interpx = g->mo->x;
interpy = g->mo->y;
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = g->mo->old_x + FixedMul(rendertimefrac, g->mo->x - g->mo->old_x);
interpy = g->mo->old_y + FixedMul(rendertimefrac, g->mo->y - g->mo->old_y);
@ -3210,7 +3276,7 @@ static void K_drawKartMinimap(void)
interpx = players[i].mo->x;
interpy = players[i].mo->y;
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = players[i].mo->old_x + FixedMul(rendertimefrac, players[i].mo->x - players[i].mo->old_x);
interpy = players[i].mo->old_y + FixedMul(rendertimefrac, players[i].mo->y - players[i].mo->old_y);
@ -3245,7 +3311,7 @@ static void K_drawKartMinimap(void)
interpx = mobj->x;
interpy = mobj->y;
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = mobj->old_x + FixedMul(rendertimefrac, mobj->x - mobj->old_x);
interpy = mobj->old_y + FixedMul(rendertimefrac, mobj->y - mobj->old_y);
@ -3282,7 +3348,7 @@ static void K_drawKartMinimap(void)
interpx = players[localplayers[i]].mo->x;
interpy = players[localplayers[i]].mo->y;
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = players[localplayers[i]].mo->old_x + FixedMul(rendertimefrac, players[localplayers[i]].mo->x - players[localplayers[i]].mo->old_x);
interpy = players[localplayers[i]].mo->old_y + FixedMul(rendertimefrac, players[localplayers[i]].mo->y - players[localplayers[i]].mo->old_y);
@ -3795,7 +3861,7 @@ static void K_drawKartFirstPerson(void)
// hitlag vibrating
if (stplyr->mo->hitlag > 0 && (stplyr->mo->eflags & MFE_DAMAGEHITLAG))
{
fixed_t mul = stplyr->mo->hitlag * (FRACUNIT / 10);
fixed_t mul = stplyr->mo->hitlag * HITLAGJITTERS;
if (r_splitscreen && mul > FRACUNIT)
mul = FRACUNIT;

View file

@ -2682,7 +2682,7 @@ boolean K_ApplyOffroad(player_t *player)
boolean K_SlopeResistance(player_t *player)
{
if (player->invincibilitytimer || player->sneakertimer || player->tiregrease)
if (player->invincibilitytimer || player->sneakertimer || player->tiregrease || player->flamedash)
return true;
return false;
}
@ -2700,6 +2700,19 @@ boolean K_TripwirePass(player_t *player)
return false;
}
boolean K_WaterRun(player_t *player)
{
if (
player->invincibilitytimer ||
player->sneakertimer ||
player->tiregrease ||
player->flamedash ||
player->speed > 2 * K_GetKartSpeed(player, false)
)
return true;
return false;
}
static fixed_t K_FlameShieldDashVar(INT32 val)
{
// 1 second = 75% + 50% top speed
@ -3623,14 +3636,9 @@ void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32
#define MINEQUAKEDIST 4096
// Spawns the purely visual explosion
void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
// Does the proximity screen flash and quake for explosions
void K_MineFlashScreen(mobj_t *source)
{
INT32 i, radius, height;
mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING);
mobj_t *dust;
mobj_t *truc;
INT32 speed, speed2;
INT32 pnum;
player_t *p;
@ -3653,6 +3661,18 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
break; // we can break right now because quakes are global to all split players somehow.
}
}
}
// Spawns the purely visual explosion
void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
{
INT32 i, radius, height;
mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING);
mobj_t *dust;
mobj_t *truc;
INT32 speed, speed2;
K_MineFlashScreen(source);
K_MatchGenericExtraFlags(smoldering, source);
smoldering->tics = TICRATE*3;
@ -4525,13 +4545,18 @@ void K_DriftDustHandling(mobj_t *spawner)
void K_Squish(mobj_t *mo)
{
const fixed_t maxstretch = 4*FRACUNIT;
const fixed_t factor = 3 * mo->height / 2;
const fixed_t factor = 5 * mo->height / 4;
const fixed_t threshold = factor / 6;
const fixed_t old3dspeed = abs(mo->lastmomz);
const fixed_t new3dspeed = abs(mo->momz);
fixed_t old3dspeed = abs(mo->lastmomz);
fixed_t new3dspeed = abs(mo->momz);
const fixed_t delta = abs(old3dspeed - new3dspeed);
fixed_t delta = abs(old3dspeed - new3dspeed);
fixed_t grav = mo->height/3;
fixed_t add = abs(grav - new3dspeed);
if (delta < 2 * add && new3dspeed > grav)
delta += add;
if (delta > threshold)
{
@ -4541,7 +4566,7 @@ void K_Squish(mobj_t *mo)
if (mo->spritexscale > maxstretch)
mo->spritexscale = maxstretch;
if (abs(new3dspeed) > abs(old3dspeed))
if (new3dspeed > old3dspeed || new3dspeed > grav)
{
mo->spritexscale =
FixedDiv(FRACUNIT, mo->spritexscale);
@ -4551,7 +4576,7 @@ void K_Squish(mobj_t *mo)
{
mo->spritexscale -=
(mo->spritexscale - FRACUNIT)
/ (mo->spritexscale < FRACUNIT ? 8 : 2);
/ (mo->spritexscale < FRACUNIT ? 8 : 3);
}
mo->spriteyscale =
@ -7565,10 +7590,12 @@ static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer)
basedrift += (basedrift / greasetics) * player->tiregrease;
}
if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))
#if 0
if (player->mo->eflags & MFE_UNDERWATER)
{
countersteer = FixedMul(countersteer, 3*FRACUNIT/2);
}
#endif
return basedrift + (FixedMul(driftadjust * FRACUNIT, countersteer) / FRACUNIT);
}
@ -7672,9 +7699,10 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
turnfixed = FixedMul(turnfixed, FRACUNIT + player->handleboost);
}
if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))
if ((player->mo->eflags & MFE_UNDERWATER) &&
player->speed > 11 * player->mo->scale)
{
turnfixed = FixedMul(turnfixed, 3*FRACUNIT/2);
turnfixed /= 2;
}
// Weight has a small effect on turning
@ -7683,6 +7711,24 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
return (turnfixed / FRACUNIT);
}
INT32 K_GetUnderwaterTurnAdjust(player_t *player)
{
if ((player->mo->eflags & MFE_UNDERWATER) &&
player->speed > 11 * player->mo->scale)
{
INT32 steer = (K_GetKartTurnValue(player,
player->steering) << TICCMD_REDUCE);
if (!player->drift)
steer = 9 * steer / 5;
return FixedMul(steer, 8 * FixedDiv(player->speed,
2 * K_GetKartSpeed(player, false) / 3));
}
else
return 0;
}
INT32 K_GetKartDriftSparkValue(player_t *player)
{
return (26*4 + player->kartspeed*2 + (9 - player->kartweight))*8;
@ -8449,10 +8495,15 @@ void K_AdjustPlayerFriction(player_t *player)
*/
// Water gets ice physics too
if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))
if ((player->mo->eflags & MFE_TOUCHWATER) &&
!player->offroad)
{
player->mo->friction += 614;
}
else if (player->mo->eflags & MFE_UNDERWATER)
{
player->mo->friction += 312;
}
// Wipeout slowdown
if (player->spinouttimer && player->wipeoutslow)
@ -8583,8 +8634,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
boolean HOLDING_ITEM = (player->pflags & (PF_ITEMOUT|PF_EGGMANOUT));
boolean NO_HYUDORO = (player->stealingtimer == 0);
player->pflags &= ~PF_HITFINISHLINE;
if (!player->exiting)
{
if (player->oldposition < player->position) // But first, if you lost a place,

View file

@ -20,6 +20,7 @@ Make sure this matches the actual number of states
#define KART_NUMINVSPARKLESANIM 12
#define MAXHITLAGTICS 18 //12
#define HITLAGJITTERS (FRACUNIT / 20)
player_t *K_GetItemBoxPlayer(mobj_t *mobj);
angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed);
@ -69,6 +70,7 @@ void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
void K_DestroyBumpers(player_t *player, UINT8 amount);
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source);
void K_MineFlashScreen(mobj_t *source);
void K_SpawnMineExplosion(mobj_t *source, UINT8 color);
void K_RunFinishLineBeam(void);
UINT16 K_DriftSparkColor(player_t *player, INT32 charge);
@ -92,6 +94,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player);
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y);
void K_UpdateSteeringValue(player_t *player, INT16 destSteering);
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue);
INT32 K_GetUnderwaterTurnAdjust(player_t *player);
INT32 K_GetKartDriftSparkValue(player_t *player);
INT32 K_StairJankFlip(INT32 value);
INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage);
@ -108,6 +111,7 @@ void K_MomentumToFacing(player_t *player);
boolean K_ApplyOffroad(player_t *player);
boolean K_SlopeResistance(player_t *player);
boolean K_TripwirePass(player_t *player);
boolean K_WaterRun(player_t *player);
void K_ApplyTripWire(player_t *player, tripwirestate_t state);
INT16 K_GetSpindashChargeTime(player_t *player);
fixed_t K_GetSpindashChargeSpeed(player_t *player);

View file

@ -18,6 +18,7 @@
#include "d_event.h"
#include "command.h"
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
#include "g_demo.h" //menudemo_t
// flags for items in the menu
// menu handle (what we do when key is pressed
@ -173,6 +174,9 @@ extern menu_t PLAY_GamemodesDef;
extern menuitem_t PLAY_RaceGamemodesMenu[];
extern menu_t PLAY_RaceGamemodesDef;
extern menuitem_t PLAY_RaceDifficulty[];
extern menu_t PLAY_RaceDifficultyDef;
extern menuitem_t PLAY_CupSelect[];
extern menu_t PLAY_CupSelectDef;
@ -268,6 +272,16 @@ extern menu_t OPTIONS_DataDiscordDef;
extern menuitem_t OPTIONS_DataErase[];
extern menu_t OPTIONS_DataEraseDef;
// EXTRAS
extern menuitem_t EXTRAS_Main[];
extern menu_t EXTRAS_MainDef;
extern menuitem_t EXTRAS_ReplayHut[];
extern menu_t EXTRAS_ReplayHutDef;
extern menuitem_t EXTRAS_ReplayStart[];
extern menu_t EXTRAS_ReplayStartDef;
// PAUSE
extern menuitem_t PAUSE_Main[];
extern menu_t PAUSE_MainDef;
@ -499,6 +513,16 @@ void M_CupSelectTick(void);
void M_LevelSelectHandler(INT32 choice);
void M_LevelSelectTick(void);
// dummy consvars for GP & match race setup
extern consvar_t cv_dummygpdifficulty;
extern consvar_t cv_dummykartspeed;
extern consvar_t cv_dummygpencore;
extern consvar_t cv_dummymatchbots;
void M_SetupDifficultySelect(INT32 choice);
void M_SetupDifficultySelectMP(INT32 choice);
void M_DifficultySelectInputs(INT32 choice);
// Multiplayer menu stuff
// Keep track of multiplayer menu related data
@ -597,6 +621,46 @@ void M_EraseData(INT32 choice); // For data erasing
void M_VideoModeMenu(INT32 choice);
void M_HandleVideoModes(INT32 ch);
// Extras menu:
#define DF_ENCORE 0x40
extern struct extrasmenu_s {
tic_t ticker; // How long the menu's been open for
INT16 offset; // To make the icons move smoothly when we transition!
// For moving the button when we get into a submenu. it's smooth and cool! (normal x/y and target x/y.)
// this is only used during menu transitions. (and will probably remain unused until we get the statistics menu
INT16 extx;
INT16 exty;
INT16 textx;
INT16 texty;
// The replay vars...... oh no......
menudemo_t *demolist;
INT16 replayScrollTitle;
SINT8 replayScrollDelay;
SINT8 replayScrollDir;
} extrasmenu;
void M_InitExtras(INT32 choice); // init for the struct
void M_ExtrasTick(void);
boolean M_ExtrasInputs(INT32 ch);
boolean M_ExtrasQuit(void); // resets buttons when you quit
// Extras: Replay Hut
void M_HandleReplayHutList(INT32 choice);
boolean M_QuitReplayHut(void);
void M_HutStartReplay(INT32 choice);
void M_PrepReplayList(void);
// Pause menu:
// Keep track of some pause menu data for visual goodness.
@ -673,6 +737,8 @@ void M_DrawCupSelect(void);
void M_DrawLevelSelect(void);
void M_DrawTimeAttack(void);
void M_DrawRaceDifficulty(void);
// Multiplayer menu stuff
void M_DrawMPOptSelect(void);
void M_DrawMPHost(void);
@ -692,6 +758,13 @@ void M_DrawGenericOptions(void);
void M_DrawVideoModes(void);
void M_DrawItemToggles(void);
// Extras menu:
void M_DrawExtrasMovingButton(void);
void M_DrawExtras(void);
void M_DrawReplayHut(void);
void M_DrawReplayStartMenu(void);
void M_DrawReplayHutReplayInfo(void);
// Misc menus:
#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make addons!"
#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make addons!"

View file

@ -31,9 +31,9 @@ menuitem_t MainMenu[] =
"Cut to the chase and start the race!", NULL,
M_CharacterSelectInit, 0, 0},
{IT_STRING, "Extra",
{IT_STRING | IT_CALL, "Extras",
"Check out some bonus features.", "MENUI001",
NULL, 0, 0},
M_InitExtras, 0, 0},
{IT_STRING, "Options",
"Configure your controls, settings, and preferences.", NULL,
@ -100,10 +100,10 @@ menu_t PLAY_GamemodesDef = KARTGAMEMODEMENU(PLAY_GamemodesMenu, &PLAY_MainDef);
menuitem_t PLAY_RaceGamemodesMenu[] =
{
{IT_STRING | IT_CALL, "Grand Prix", "Compete for the best rank over five races!",
NULL, M_LevelSelectInit, 2, GT_RACE},
NULL, M_SetupDifficultySelect, 0, 0},
{IT_STRING | IT_CALL, "Match Race", "Play by your own rules in a specialized, single race!",
"MENIMG01", M_LevelSelectInit, 0, GT_RACE},
"MENIMG01", M_SetupDifficultySelect, 1, 0},
{IT_STRING | IT_CALL, "Time Attack", "Record your best time on any track!",
NULL, M_LevelSelectInit, 1, GT_RACE},
@ -113,6 +113,52 @@ menuitem_t PLAY_RaceGamemodesMenu[] =
menu_t PLAY_RaceGamemodesDef = KARTGAMEMODEMENU(PLAY_RaceGamemodesMenu, &PLAY_GamemodesDef);
// difficulty selection:
menuitem_t PLAY_RaceDifficulty[] =
{
// local play
{IT_STRING | IT_CVAR, "Difficulty", "Select the game difficulty",
NULL, &cv_dummygpdifficulty, 0, 0},
// netgames
{IT_STRING | IT_CVAR, "Difficulty", "Select the game speed",
NULL, &cv_dummykartspeed, 0, 0},
// DISABLE THAT OPTION OUTSIDE OF MATCH RACE
{IT_STRING2 | IT_CVAR, "CPU Players", "Enable or disable CPU players.", // 2 whitestring is used by the drawer to know to draw shitstring
NULL, &cv_dummymatchbots, 0, 0},
{IT_STRING2 | IT_CVAR, "Encore", "Enable or disable Encore mode", // 3
NULL, &cv_dummygpencore, 0, 0},
// For GP:
{IT_STRING | IT_CALL, "Cup Select", "Go on and select a cup!", NULL, M_LevelSelectInit, 2, GT_RACE}, // 4
// For Match Race:
{IT_STRING | IT_CALL, "Map Select", "Go on and select a race track!", NULL, M_LevelSelectInit, 0, GT_RACE}, // 5
// For Match Race in NETGAMES:
{IT_STRING | IT_CALL, "Map Select", "Go on and select a race track!", NULL, M_MPSetupNetgameMapSelect, 0, GT_RACE}, // 6
{IT_STRING | IT_CALL, "Back", NULL, NULL, M_GoBack, 0, 0},
};
menu_t PLAY_RaceDifficultyDef = {
sizeof(PLAY_RaceDifficulty) / sizeof(menuitem_t),
&PLAY_RaceGamemodesDef,
0,
PLAY_RaceDifficulty,
0, 0,
0, 0,
1, 10,
M_DrawRaceDifficulty,
NULL,
NULL,
NULL
};
menuitem_t PLAY_CupSelect[] =
{
{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, M_CupSelectHandler, 0, 0},
@ -234,7 +280,7 @@ menuitem_t PLAY_MP_Host[] =
NULL, &cv_dummygametype, 0, 0},
{IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode",
NULL, M_MPSetupNetgameMapSelect, 0, 0},
NULL, M_SetupDifficultySelectMP, 0, 0},
};
@ -1103,6 +1149,96 @@ menu_t OPTIONS_DataEraseDef = {
NULL,
};
// extras menu
menuitem_t EXTRAS_Main[] =
{
{IT_STRING | IT_CALL, "Addons", "Add files to customize your experience.",
NULL, M_Addons, 0, 0},
{IT_STRING | IT_CALL, "Replay Hut", "Play the replays you've saved throughout your many races & battles!",
NULL, M_ReplayHut, 0, 0},
{IT_STRING | IT_CALL, "Statistics", "Look back on some of your greatest achievements such as your playtime and wins!",
NULL, NULL, 0, 0},
{IT_STRING | IT_TRANSTEXT, "Extras Checklist", "View the requirement for some of the secret content you can unlock!",
NULL, NULL, 0, 0},
};
// the extras menu essentially reuses the options menu stuff
menu_t EXTRAS_MainDef = {
sizeof (EXTRAS_Main) / sizeof (menuitem_t),
&MainDef,
0,
EXTRAS_Main,
0, 0,
0, 0,
2, 10,
M_DrawExtras,
M_ExtrasTick,
NULL,
M_ExtrasInputs
};
// extras menu: replay hut
menuitem_t EXTRAS_ReplayHut[] =
{
{IT_KEYHANDLER|IT_NOTHING, "", "", // Dummy menuitem for the replay list
NULL, M_HandleReplayHutList, 0, 0},
{IT_NOTHING, "", "", // Dummy for handling wrapping to the top of the menu..
NULL, NULL, 0, 0},
};
menu_t EXTRAS_ReplayHutDef =
{
sizeof (EXTRAS_ReplayHut)/sizeof (menuitem_t),
&EXTRAS_MainDef,
0,
EXTRAS_ReplayHut,
30, 80,
0, 0,
0, 0,
M_DrawReplayHut,
NULL,
M_QuitReplayHut,
NULL
};
menuitem_t EXTRAS_ReplayStart[] =
{
{IT_CALL |IT_STRING, "Load Addons and Watch", NULL,
NULL, M_HutStartReplay, 0, 0},
{IT_CALL |IT_STRING, "Load Without Addons", NULL,
NULL, M_HutStartReplay, 10, 0},
{IT_CALL |IT_STRING, "Watch Replay", NULL,
NULL, M_HutStartReplay, 10, 0},
{IT_SUBMENU |IT_STRING, "Go Back", NULL,
NULL, &EXTRAS_ReplayHutDef, 30, 0},
};
menu_t EXTRAS_ReplayStartDef =
{
sizeof (EXTRAS_ReplayStart)/sizeof (menuitem_t),
&EXTRAS_ReplayHutDef,
0,
EXTRAS_ReplayStart,
27, 80,
0, 0,
0, 0,
M_DrawReplayStartMenu,
NULL,
NULL,
NULL
};
// -------------------
// In-game/pause menus
// -------------------

View file

@ -245,7 +245,10 @@ void M_Drawer(void)
}
else if (!WipeInAction && currentMenu != &PAUSE_PlaybackMenuDef)
{
V_DrawCustomFadeScreen("FADEMAP0", 4); // now that's more readable with a faded background (yeah like Quake...)
if (rendermode == render_opengl) // OGL can't handle what SW is doing so let's fake it;
V_DrawFadeScreen(122, 3); // palette index aproximation...
else // Software can keep its unique fade
V_DrawCustomFadeScreen("FADEMAP0", 4); // now that's more readable with a faded background (yeah like Quake...)
}
if (currentMenu->drawroutine)
@ -342,7 +345,7 @@ static const char *M_CreateSecretMenuOption(const char *str)
//
void M_DrawGenericMenu(void)
{
INT32 x = 0, y = 0, w, i, cursory = 0;
INT32 x = currentMenu->x, y = currentMenu->y, w, i, cursory = 0;
M_DrawMenuTooltips();
@ -1022,6 +1025,135 @@ void M_DrawCharacterSelect(void)
M_DrawCharSelectCursor(priority);
}
// DIFFICULTY SELECT
// This is a mix of K_DrawKartGamemodeMenu and the generic menu drawer depending on what we need.
// This is only ever used here (I hope because this is starting to pile up on hacks to look like the old m_menu.c lol...)
void M_DrawRaceDifficulty(void)
{
UINT8 n = currentMenu->numitems-4;
patch_t *box = W_CachePatchName("M_DBOX", PU_CACHE);
INT32 i;
INT32 x = 120;
INT32 y = 48;
M_DrawMenuTooltips();
// Draw the box for difficulty...
V_DrawFixedPatch((111 + 24*menutransition.tics)*FRACUNIT, 33*FRACUNIT, FRACUNIT, 0, box, NULL);
if (menutransition.tics)
{
x += 24 * menutransition.tics;
}
for (i = 0; i < currentMenu->numitems; i++)
{
if (i >= n)
{
x = GM_STARTX + (GM_XOFFSET * 5 / 2);
y = GM_STARTY + (GM_YOFFSET * 5 / 2);
if (i < currentMenu->numitems-1)
{
x -= GM_XOFFSET;
y -= GM_YOFFSET;
}
if (menutransition.tics)
{
x += 24 * menutransition.tics;
}
}
switch (currentMenu->menuitems[i].status & IT_DISPLAY)
{
// This is HACKY......
case IT_STRING2:
{
INT32 f = (i == itemOn) ? highlightflags : 0;
V_DrawString(140 + 24*menutransition.tics, y, f, currentMenu->menuitems[i].text);
if (currentMenu->menuitems[i].status & IT_CVAR)
{
// implicitely we'll only take care of normal cvars
INT32 cx = 260 + 24*menutransition.tics;
consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction;
V_DrawCenteredString(cx, y, f, cv->string);
if (i == itemOn)
{
INT32 w = V_StringWidth(cv->string, 0)/2;
V_DrawCharacter(cx - 10 - w - (skullAnimCounter/5), y, '\x1C' | highlightflags, false); // left arrow
V_DrawCharacter(cx + w + 2 + (skullAnimCounter/5), y, '\x1D' | highlightflags, false); // right arrow
}
}
y += 12;
break;
}
case IT_STRING:
{
UINT8 *colormap = NULL;
if (i == itemOn)
{
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
}
else
{
colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_MOSS, GTC_CACHE);
}
if (currentMenu->menuitems[i].status & IT_CVAR)
{
INT32 fx = (x - 24*menutransition.tics);
INT32 centx = fx + (320-fx)/2 + (menutransition.tics*24); // undo the menutransition movement to redo it here otherwise the text won't move at the same speed lole.
// implicitely we'll only take care of normal consvars
consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction;
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, W_CachePatchName("MENUSHRT", PU_CACHE), colormap);
V_DrawCenteredGamemodeString(centx, y - 3, V_ALLOWLOWERCASE, colormap, cv->string);
if (i == itemOn)
{
patch_t *arr_r = W_CachePatchName("GM_ARRL", PU_CACHE);
patch_t *arr_l = W_CachePatchName("GM_ARRR", PU_CACHE);
V_DrawFixedPatch((centx-54 - arr_r->width - (skullAnimCounter/5))*FRACUNIT, (y-3)*FRACUNIT, FRACUNIT, 0, arr_r, colormap);
V_DrawFixedPatch((centx+54 + (skullAnimCounter/5))*FRACUNIT, (y-3)*FRACUNIT, FRACUNIT, 0, arr_l, colormap);
}
}
else // not a cvar
{
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, W_CachePatchName("MENUPLTR", PU_CACHE), colormap);
V_DrawGamemodeString(x + 16, y - 3, V_ALLOWLOWERCASE, colormap, currentMenu->menuitems[i].text);
}
x += GM_XOFFSET;
y += GM_YOFFSET;
break;
}
}
}
}
// LEVEL SELECT
static void M_DrawCupPreview(INT16 y, cupheader_t *cup)
@ -2113,6 +2245,60 @@ void M_DrawItemToggles(void)
}
// EXTRAS:
// Copypasted from options but separate either way in case we want it to look more unique later down the line.
void M_DrawExtrasMovingButton(void)
{
patch_t *butt = W_CachePatchName("OPT_BUTT", PU_CACHE);
UINT8 *c = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
V_DrawFixedPatch((extrasmenu.extx)*FRACUNIT, (extrasmenu.exty)*FRACUNIT, FRACUNIT, 0, butt, c);
V_DrawCenteredGamemodeString((extrasmenu.extx)-3, (extrasmenu.exty) - 16, V_ALLOWLOWERCASE, c, EXTRAS_MainDef.menuitems[EXTRAS_MainDef.lastOn].text);
}
void M_DrawExtras(void)
{
UINT8 i;
INT32 x = 140 - (48*itemOn) + extrasmenu.offset;
INT32 y = 70 + extrasmenu.offset;
patch_t *buttback = W_CachePatchName("OPT_BUTT", PU_CACHE);
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
UINT8 *c = NULL;
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
for (i=0; i < currentMenu->numitems; i++)
{
INT32 py = y - (itemOn*48);
INT32 px = x - menutransition.tics*64;
INT32 tflag = 0;
if (i == itemOn)
c = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
else
c = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLACK, GTC_CACHE);
if (currentMenu->menuitems[i].status & IT_TRANSTEXT)
tflag = V_TRANSLUCENT;
if (!(menutransition.tics && i == itemOn))
{
V_DrawFixedPatch(px*FRACUNIT, py*FRACUNIT, FRACUNIT, 0, buttback, c);
V_DrawCenteredGamemodeString(px-3, py - 16, V_ALLOWLOWERCASE|tflag, (i == itemOn ? c : NULL), currentMenu->menuitems[i].text);
}
y += 48;
x += 48;
}
M_DrawMenuTooltips();
if (menutransition.tics)
M_DrawExtrasMovingButton();
}
//
// INGAME / PAUSE MENUS
//
@ -2407,6 +2593,385 @@ void M_DrawPlaybackMenu(void)
}
// replay hut...
// ...dear lord this is messy, but Ima be real I ain't fixing this.
#define SCALEDVIEWWIDTH (vid.width/vid.dupx)
#define SCALEDVIEWHEIGHT (vid.height/vid.dupy)
void M_DrawReplayHutReplayInfo(void)
{
lumpnum_t lumpnum;
patch_t *patch;
UINT8 *colormap;
INT32 x, y, w, h;
switch (extrasmenu.demolist[dir_on[menudepthleft]].type)
{
case MD_NOTLOADED:
V_DrawCenteredString(160, 40, V_SNAPTOTOP, "Loading replay information...");
break;
case MD_INVALID:
V_DrawCenteredString(160, 40, V_SNAPTOTOP|warningflags, "This replay cannot be played.");
break;
case MD_SUBDIR:
break; // Can't think of anything to draw here right now
case MD_OUTDATED:
V_DrawThinString(17, 64, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version.");
/* FALLTHRU */
default:
// Draw level stuff
x = 15; y = 15;
// A 160x100 image of the level as entry MAPxxP
//CONS_Printf("%d %s\n", extrasmenu.demolist[dir_on[menudepthleft]].map, G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map));
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map)));
if (lumpnum != LUMPERROR)
patch = W_CachePatchNum(lumpnum, PU_CACHE);
else
patch = W_CachePatchName("M_NOLVL", PU_CACHE);
if (!(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE))
V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch);
else
{
w = SHORT(patch->width);
h = SHORT(patch->height);
V_DrawSmallScaledPatch(x+(w>>1), y, V_SNAPTOTOP|V_FLIP, patch);
{
static angle_t rubyfloattime = 0;
const fixed_t rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT);
V_DrawFixedPatch((x+(w>>2))<<FRACBITS, ((y+(h>>2))<<FRACBITS) - (rubyheight<<1), FRACUNIT, V_SNAPTOTOP, W_CachePatchName("RUBYICON", PU_CACHE), NULL);
rubyfloattime += (ANGLE_MAX/NEWTICRATE);
}
}
x += 85;
if (mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map-1])
V_DrawString(x, y, V_SNAPTOTOP, G_BuildMapTitle(extrasmenu.demolist[dir_on[menudepthleft]].map));
else
V_DrawString(x, y, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT, "Level is not loaded.");
if (extrasmenu.demolist[dir_on[menudepthleft]].numlaps)
V_DrawThinString(x, y+9, V_SNAPTOTOP|V_ALLOWLOWERCASE, va("(%d laps)", extrasmenu.demolist[dir_on[menudepthleft]].numlaps));
V_DrawString(x, y+20, V_SNAPTOTOP|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].gametype == GT_RACE ?
va("Race (%s speed)", kartspeed_cons_t[(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE) + 1].strvalue) :
"Battle Mode");
if (!extrasmenu.demolist[dir_on[menudepthleft]].standings[0].ranking)
{
// No standings were loaded!
V_DrawString(x, y+39, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT, "No standings available.");
break;
}
V_DrawThinString(x, y+29, V_SNAPTOTOP|highlightflags, "WINNER");
V_DrawString(x+38, y+30, V_SNAPTOTOP|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].standings[0].name);
if (extrasmenu.demolist[dir_on[menudepthleft]].gametype == GT_RACE)
{
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "TIME");
V_DrawRightAlignedString(x+84, y+40, V_SNAPTOTOP, va("%d'%02d\"%02d",
G_TicsToMinutes(extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore, true),
G_TicsToSeconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore),
G_TicsToCentiseconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore)
));
}
else
{
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "SCORE");
V_DrawString(x+32, y+40, V_SNAPTOTOP, va("%d", extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore));
}
// Character face!
// Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this)
// and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid.
if (extrasmenu.demolist[dir_on[menudepthleft]].standings[0].skin != 0xFF)
{
patch = faceprefix[extrasmenu.demolist[dir_on[menudepthleft]].standings[0].skin][FACE_WANTED];
colormap = R_GetTranslationColormap(
extrasmenu.demolist[dir_on[menudepthleft]].standings[0].skin,
extrasmenu.demolist[dir_on[menudepthleft]].standings[0].color,
GTC_MENUCACHE);
}
else
{
patch = W_CachePatchName("M_NOWANT", PU_CACHE);
colormap = R_GetTranslationColormap(
TC_RAINBOW,
extrasmenu.demolist[dir_on[menudepthleft]].standings[0].color,
GTC_MENUCACHE);
}
V_DrawMappedPatch(BASEVIDWIDTH-15 - SHORT(patch->width), y+20, V_SNAPTOTOP, patch, colormap);
break;
}
}
void M_DrawReplayHut(void)
{
INT32 x, y, cursory = 0;
INT16 i;
INT16 replaylistitem = currentMenu->numitems-2;
boolean processed_one_this_frame = false;
static UINT16 replayhutmenuy = 0;
M_DrawEggaChannel();
// Draw menu choices
x = currentMenu->x;
y = currentMenu->y;
if (itemOn > replaylistitem)
{
itemOn = replaylistitem;
dir_on[menudepthleft] = sizedirmenu-1;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
}
else if (itemOn < replaylistitem)
{
dir_on[menudepthleft] = 0;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
}
if (itemOn == replaylistitem)
{
INT32 maxy;
// Scroll menu items if needed
cursory = y + currentMenu->menuitems[replaylistitem].mvar1 + dir_on[menudepthleft]*10;
maxy = y + currentMenu->menuitems[replaylistitem].mvar1 + sizedirmenu*10;
if (cursory > maxy - 20)
cursory = maxy - 20;
if (cursory - replayhutmenuy > SCALEDVIEWHEIGHT-50)
replayhutmenuy += (cursory-SCALEDVIEWHEIGHT-replayhutmenuy + 51)/2;
else if (cursory - replayhutmenuy < 110)
replayhutmenuy += (max(0, cursory-110)-replayhutmenuy - 1)/2;
}
else
replayhutmenuy /= 2;
y -= replayhutmenuy;
// Draw static menu items
for (i = 0; i < replaylistitem; i++)
{
INT32 localy = y + currentMenu->menuitems[i].mvar1;
if (localy < 65)
continue;
if (i == itemOn)
cursory = localy;
if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING)
V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT, currentMenu->menuitems[i].text);
else
V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[i].text);
}
y += currentMenu->menuitems[replaylistitem].mvar1;
for (i = 0; i < (INT16)sizedirmenu; i++)
{
INT32 localy = y+i*10;
INT32 localx = x;
if (localy < 65)
continue;
if (localy >= SCALEDVIEWHEIGHT)
break;
if (extrasmenu.demolist[i].type == MD_NOTLOADED && !processed_one_this_frame)
{
processed_one_this_frame = true;
G_LoadDemoInfo(&extrasmenu.demolist[i]);
}
if (extrasmenu.demolist[i].type == MD_SUBDIR)
{
localx += 8;
V_DrawScaledPatch(x - 4, localy, V_SNAPTOTOP|V_SNAPTOLEFT, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_RBACK" : "M_RFLDR", PU_CACHE));
}
if (itemOn == replaylistitem && i == (INT16)dir_on[menudepthleft])
{
cursory = localy;
if (extrasmenu.replayScrollDelay)
extrasmenu.replayScrollDelay--;
else if (extrasmenu.replayScrollDir > 0)
{
if (extrasmenu.replayScrollTitle < (V_StringWidth(extrasmenu.demolist[i].title, 0) - (SCALEDVIEWWIDTH - (x<<1)))<<1)
extrasmenu.replayScrollTitle++;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = -1;
}
}
else
{
if (extrasmenu.replayScrollTitle > 0)
extrasmenu.replayScrollTitle--;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
}
}
V_DrawString(localx - (extrasmenu.replayScrollTitle>>1), localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags|V_ALLOWLOWERCASE, extrasmenu.demolist[i].title);
}
else
V_DrawString(localx, localy, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, extrasmenu.demolist[i].title);
}
// Draw scrollbar
y = sizedirmenu*10 + currentMenu->menuitems[replaylistitem].mvar1 + 30;
if (y > SCALEDVIEWHEIGHT-80)
{
V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|159);
V_DrawFill(BASEVIDWIDTH-3, 76 + (SCALEDVIEWHEIGHT-80) * replayhutmenuy / y, 2, (((SCALEDVIEWHEIGHT-80) * (SCALEDVIEWHEIGHT-80))-1) / y - 1, V_SNAPTOTOP|V_SNAPTORIGHT|149);
}
// Draw the cursor
V_DrawScaledPatch(currentMenu->x - 24, cursory, V_SNAPTOTOP|V_SNAPTOLEFT,
W_CachePatchName("M_CURSOR", PU_CACHE));
V_DrawString(currentMenu->x, cursory, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[itemOn].text);
// Now draw some replay info!
V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159);
if (itemOn == replaylistitem)
{
M_DrawReplayHutReplayInfo();
}
}
void M_DrawReplayStartMenu(void)
{
const char *warning;
UINT8 i;
M_DrawEggaChannel();
M_DrawGenericMenu();
#define STARTY 62-(extrasmenu.replayScrollTitle>>1)
// Draw rankings beyond first
for (i = 1; i < MAXPLAYERS && extrasmenu.demolist[dir_on[menudepthleft]].standings[i].ranking; i++)
{
patch_t *patch;
UINT8 *colormap;
V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, V_SNAPTOTOP|highlightflags, va("%2d", extrasmenu.demolist[dir_on[menudepthleft]].standings[i].ranking));
V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_SNAPTOTOP|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].standings[i].name);
if (extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1)
V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, "NO CONTEST");
else if (extrasmenu.demolist[dir_on[menudepthleft]].gametype == GT_RACE)
V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d'%02d\"%02d",
G_TicsToMinutes(extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore, true),
G_TicsToSeconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore),
G_TicsToCentiseconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore)
));
else
V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore));
// Character face!
// Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this)
// and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid.
if (extrasmenu.demolist[dir_on[menudepthleft]].standings[i].skin != 0xFF)
{
patch = faceprefix[extrasmenu.demolist[dir_on[menudepthleft]].standings[i].skin][FACE_RANK];
colormap = R_GetTranslationColormap(
extrasmenu.demolist[dir_on[menudepthleft]].standings[i].skin,
extrasmenu.demolist[dir_on[menudepthleft]].standings[i].color,
GTC_MENUCACHE);
}
else
{
patch = W_CachePatchName("M_NORANK", PU_CACHE);
colormap = R_GetTranslationColormap(
TC_RAINBOW,
extrasmenu.demolist[dir_on[menudepthleft]].standings[i].color,
GTC_MENUCACHE);
}
V_DrawMappedPatch(BASEVIDWIDTH-5 - SHORT(patch->width), STARTY + i*20, V_SNAPTOTOP, patch, colormap);
}
#undef STARTY
// Handle scrolling rankings
if (extrasmenu.replayScrollDelay)
extrasmenu.replayScrollDelay--;
else if (extrasmenu.replayScrollDir > 0)
{
if (extrasmenu.replayScrollTitle < (i*20 - SCALEDVIEWHEIGHT + 100)<<1)
extrasmenu.replayScrollTitle++;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = -1;
}
}
else
{
if (extrasmenu.replayScrollTitle > 0)
extrasmenu.replayScrollTitle--;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
}
}
V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159);
M_DrawReplayHutReplayInfo();
V_DrawString(10, 72, V_SNAPTOTOP|highlightflags|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].title);
// Draw a warning prompt if needed
switch (extrasmenu.demolist[dir_on[menudepthleft]].addonstatus)
{
case DFILE_ERROR_CANNOTLOAD:
warning = "Some addons in this replay cannot be loaded.\nYou can watch anyway, but desyncs may occur.";
break;
case DFILE_ERROR_NOTLOADED:
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
warning = "Loading addons will mark your game as modified, and Record Attack may be unavailable.\nYou can watch without loading addons, but desyncs may occur.";
break;
case DFILE_ERROR_EXTRAFILES:
warning = "You have addons loaded that were not present in this replay.\nYou can watch anyway, but desyncs may occur.";
break;
case DFILE_ERROR_OUTOFORDER:
warning = "You have this replay's addons loaded, but they are out of order.\nYou can watch anyway, but desyncs may occur.";
break;
default:
return;
}
V_DrawSmallString(4, BASEVIDHEIGHT-14, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, warning);
}
// Draw misc menus:
// Addons (this is merely copypasted, original code by toaster)
@ -2494,6 +3059,14 @@ void M_DrawAddons(void)
M_CacheAddonPatches();
// hack: If we're calling this from GS_MENU, that means we're in the extras menu!
// so draw the apropriate background
if (gamestate == GS_MENU)
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
// hack - need to refresh at end of frame to handle addfile...
if (refreshdirmenu & M_AddonsRefresh())
{

View file

@ -169,6 +169,9 @@ static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}
static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}};
static CV_PossibleValue_t dummygametype_cons_t[] = {{0, "Race"}, {1, "Battle"}, {0, NULL}};
static CV_PossibleValue_t dummygpdifficulty_cons_t[] = {{0, "Easy"}, {1, "Normal"}, {2, "Hard"}, {3, "Master"}, {0, NULL}};
static CV_PossibleValue_t dummykartspeed_cons_t[] = {{-1, "Auto"}, {0, "Easy"}, {1, "Normal"}, {2, "Hard"}, {0, NULL}};
//static consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDDEN, dummyteam_cons_t, NULL);
//static cv_dummyspectate = CVAR_INITconsvar_t ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
@ -179,6 +182,26 @@ consvar_t cv_dummyip = CVAR_INIT ("dummyip", "", CV_HIDDEN, NULL, NULL);
consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
consvar_t cv_dummygpdifficulty = CVAR_INIT ("dummygpdifficulty", "Normal", CV_HIDDEN, dummygpdifficulty_cons_t, NULL);
consvar_t cv_dummykartspeed = CVAR_INIT ("dummykartspeed", "Auto", CV_HIDDEN, dummykartspeed_cons_t, NULL);
consvar_t cv_dummygpencore = CVAR_INIT ("dummygpdifficulty", "No", CV_HIDDEN, CV_YesNo, NULL);
static CV_PossibleValue_t dummymatchbots_cons_t[] = {
{0, "Off"},
{1, "Lv.1"},
{2, "Lv.2"},
{3, "Lv.3"},
{4, "Lv.4"},
{5, "Lv.5"},
{6, "Lv.6"},
{7, "Lv.7"},
{8, "Lv.8"},
{9, "Lv.9"},
{0, NULL}
};
consvar_t cv_dummymatchbots = CVAR_INIT ("dummymatchbots", "Off", CV_HIDDEN|CV_SAVE, dummymatchbots_cons_t, NULL); // Save this one if you wanna test your stuff without bots for instance
// ==========================================================================
// CVAR ONCHANGE EVENTS GO HERE
// ==========================================================================
@ -1563,6 +1586,11 @@ void M_Init(void)
CV_RegisterVar(&cv_dummygametype);
CV_RegisterVar(&cv_dummyip);
CV_RegisterVar(&cv_dummygpdifficulty);
CV_RegisterVar(&cv_dummykartspeed);
CV_RegisterVar(&cv_dummygpencore);
CV_RegisterVar(&cv_dummymatchbots);
M_UpdateMenuBGImage(true);
#if 0
@ -2372,6 +2400,63 @@ boolean M_CharacterSelectQuit(void)
return true;
}
// DIFFICULTY SELECT
void M_SetupDifficultySelect(INT32 choice)
{
// check what we picked.
choice = currentMenu->menuitems[itemOn].mvar1;
// setup the difficulty menu and then remove choices depending on choice
PLAY_RaceDifficultyDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_RaceDifficultyDef, false);
PLAY_RaceDifficulty[0].status = IT_STRING|IT_CVAR;
PLAY_RaceDifficulty[1].status = IT_DISABLED;
PLAY_RaceDifficulty[2].status = IT_DISABLED;
PLAY_RaceDifficulty[3].status = IT_DISABLED;
PLAY_RaceDifficulty[4].status = IT_DISABLED;
PLAY_RaceDifficulty[5].status = IT_DISABLED;
PLAY_RaceDifficulty[6].status = IT_DISABLED;
if (choice) // Match Race
{
PLAY_RaceDifficulty[2].status = IT_STRING2|IT_CVAR; // CPUs on/off use string2 to signify not to use the normal gm font drawer
PLAY_RaceDifficulty[3].status = IT_STRING2|IT_CVAR; // Encore on/off use string2 to signify not to use the normal gm font drawer
PLAY_RaceDifficulty[5].status = IT_STRING|IT_CALL; // Level Select (Match Race)
itemOn = 5; // Select cup select by default.
}
else // GP
{
PLAY_RaceDifficulty[3].status = IT_STRING2|IT_CVAR; // Encore on/off use string2 to signify not to use the normal gm font drawer
PLAY_RaceDifficulty[4].status = IT_STRING|IT_CALL; // Level Select (GP)
itemOn = 4; // Select cup select by default.
}
}
// calls the above but changes the cvar we set
void M_SetupDifficultySelectMP(INT32 choice)
{
(void) choice;
PLAY_RaceDifficultyDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_RaceDifficultyDef, false);
PLAY_RaceDifficulty[0].status = IT_DISABLED;
PLAY_RaceDifficulty[1].status = IT_STRING|IT_CVAR;
PLAY_RaceDifficulty[2].status = IT_STRING2|IT_CVAR; // CPUs on/off use string2 to signify not to use the normal gm font drawer
PLAY_RaceDifficulty[3].status = IT_STRING2|IT_CVAR; // Encore on/off use string2 to signify not to use the normal gm font drawer
PLAY_RaceDifficulty[4].status = IT_DISABLED;
PLAY_RaceDifficulty[5].status = IT_DISABLED;
PLAY_RaceDifficulty[6].status = IT_STRING|IT_CALL;
itemOn = 6; // Select cup select by default.
// okay this is REALLY stupid but this fixes the host menu re-folding on itself when we go back.
mpmenu.modewinextend[0][0] = 1;
}
// LEVEL SELECT
//
@ -2610,10 +2695,11 @@ void M_CupSelectHandler(INT32 choice)
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
// TODO: game settings screen
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
grandprixinfo.masterbots = false;
grandprixinfo.encore = false;
// read our dummy cvars
grandprixinfo.gamespeed = min(KARTSPEED_HARD, cv_dummygpdifficulty.value);
grandprixinfo.masterbots = (cv_dummygpdifficulty.value == 3);
grandprixinfo.encore = (boolean)cv_dummygpencore.value;
grandprixinfo.cup = newcup;
@ -2769,9 +2855,18 @@ void M_LevelSelectHandler(INT32 choice)
SV_StartSinglePlayerServer();
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
netgame = levellist.netgame; // ^ ditto.
}
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
// this is considered to be CV_CHEAT however...
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string); // Match the kartbot value to the dummy match bots value.
if (netgame) // check for the dummy kartspeed value
CV_StealthSet(&cv_kartspeed, cv_dummykartspeed.string);
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_dummygpencore.value == 1), 1, 1, false, false);
}
else // directly do the map change
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
M_ClearMenus(true);
}
@ -3403,6 +3498,103 @@ void M_HandleItemToggles(INT32 choice)
}
// Extras menu;
// this is copypasted from the options menu but all of these are different functions in case we ever want it to look more unique
struct extrasmenu_s extrasmenu;
void M_InitExtras(INT32 choice)
{
(void)choice;
extrasmenu.ticker = 0;
extrasmenu.offset = 0;
extrasmenu.extx = 0;
extrasmenu.exty = 0;
extrasmenu.textx = 0;
extrasmenu.texty = 0;
M_SetupNextMenu(&EXTRAS_MainDef, false);
}
// For statistics, will maybe remain unused for a while
boolean M_ExtrasQuit(void)
{
extrasmenu.textx = 140-1;
extrasmenu.texty = 70+1;
return true; // Always allow quitting, duh.
}
void M_ExtrasTick(void)
{
extrasmenu.offset /= 2;
extrasmenu.ticker++;
extrasmenu.extx += (extrasmenu.textx - extrasmenu.extx)/2;
extrasmenu.exty += (extrasmenu.texty - extrasmenu.exty)/2;
if (abs(extrasmenu.extx - extrasmenu.exty) < 2)
{
extrasmenu.extx = extrasmenu.textx;
extrasmenu.exty = extrasmenu.texty; // Avoid awkward 1 px errors.
}
// Move the button for cool animations
if (currentMenu == &EXTRAS_MainDef)
{
M_ExtrasQuit(); // reset the options button.
}
else
{
extrasmenu.textx = 160;
extrasmenu.texty = 50;
}
}
boolean M_ExtrasInputs(INT32 ch)
{
switch (ch)
{
case KEY_DOWNARROW:
{
extrasmenu.offset += 48;
M_NextOpt();
S_StartSound(NULL, sfx_menu1);
if (itemOn == 0)
extrasmenu.offset -= currentMenu->numitems*48;
return true;
}
case KEY_UPARROW:
{
extrasmenu.offset -= 48;
M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
if (itemOn == currentMenu->numitems-1)
extrasmenu.offset += currentMenu->numitems*48;
return true;
}
case KEY_ENTER:
{
if (currentMenu->menuitems[itemOn].status & IT_TRANSTEXT)
return true; // No.
extrasmenu.extx = 140;
extrasmenu.exty = 70; // Default position for the currently selected option.
return false; // Don't eat.
}
}
return false;
}
// =====================
// PAUSE / IN-GAME MENUS
// =====================
@ -3711,12 +3903,223 @@ void M_PlaybackQuit(INT32 choice)
D_StartTitle();
}
void M_PrepReplayList(void)
{
size_t i;
if (extrasmenu.demolist)
Z_Free(extrasmenu.demolist);
extrasmenu.demolist = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL);
for (i = 0; i < sizedirmenu; i++)
{
if (dirmenu[i][DIR_TYPE] == EXT_UP)
{
extrasmenu.demolist[i].type = MD_SUBDIR;
sprintf(extrasmenu.demolist[i].title, "UP");
}
else if (dirmenu[i][DIR_TYPE] == EXT_FOLDER)
{
extrasmenu.demolist[i].type = MD_SUBDIR;
strncpy(extrasmenu.demolist[i].title, dirmenu[i] + DIR_STRING, 64);
}
else
{
extrasmenu.demolist[i].type = MD_NOTLOADED;
snprintf(extrasmenu.demolist[i].filepath, 255, "%s%s", menupath, dirmenu[i] + DIR_STRING);
sprintf(extrasmenu.demolist[i].title, ".....");
}
}
}
void M_ReplayHut(INT32 choice)
{
(void)choice;
extrasmenu.replayScrollTitle = 0;
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
if (!demo.inreplayhut)
{
snprintf(menupath, 1024, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home);
menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath);
}
if (!preparefilemenu(false, true))
{
M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING);
return;
}
else if (!demo.inreplayhut)
dir_on[menudepthleft] = 0;
demo.inreplayhut = true;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
M_PrepReplayList();
menuactive = true;
M_SetupNextMenu(&EXTRAS_ReplayHutDef, false);
//G_SetGamestate(GS_TIMEATTACK);
//titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
demo.rewinding = false;
CL_ClearRewinds();
//S_ChangeMusicInternal("replst", true);
}
// key handler
void M_HandleReplayHutList(INT32 choice)
{
switch (choice)
{
case KEY_UPARROW:
if (dir_on[menudepthleft])
dir_on[menudepthleft]--;
else
return;
//M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
break;
case KEY_DOWNARROW:
if (dir_on[menudepthleft] < sizedirmenu-1)
dir_on[menudepthleft]++;
else
return;
//itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item
S_StartSound(NULL, sfx_menu1);
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
break;
case KEY_ESCAPE:
M_QuitReplayHut();
break;
case KEY_ENTER:
switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE])
{
case EXT_FOLDER:
strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING);
if (menudepthleft)
{
menupathindex[--menudepthleft] = strlen(menupath);
menupath[menupathindex[menudepthleft]] = 0;
if (!preparefilemenu(false, true))
{
S_StartSound(NULL, sfx_s224);
M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(true, true))
{
M_QuitReplayHut();
return;
}
}
else
{
S_StartSound(NULL, sfx_menu1);
dir_on[menudepthleft] = 1;
M_PrepReplayList();
}
}
else
{
S_StartSound(NULL, sfx_s26d);
M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[menudepthleft]] = 0;
}
break;
case EXT_UP:
S_StartSound(NULL, sfx_menu1);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(false, true))
{
M_QuitReplayHut();
return;
}
M_PrepReplayList();
break;
default:
// We can't just use M_SetupNextMenu because that'll run ReplayDef's quitroutine and boot us back to the title screen!
currentMenu->lastOn = itemOn;
currentMenu = &EXTRAS_ReplayStartDef;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
switch (extrasmenu.demolist[dir_on[menudepthleft]].addonstatus)
{
case DFILE_ERROR_CANNOTLOAD:
// Only show "Watch Replay Without Addons"
EXTRAS_ReplayStart[0].status = IT_DISABLED;
EXTRAS_ReplayStart[1].status = IT_CALL|IT_STRING;
//EXTRAS_ReplayStart[1].alphaKey = 0;
EXTRAS_ReplayStart[2].status = IT_DISABLED;
itemOn = 1;
break;
case DFILE_ERROR_NOTLOADED:
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
// Show "Load Addons and Watch Replay" and "Watch Replay Without Addons"
EXTRAS_ReplayStart[0].status = IT_CALL|IT_STRING;
EXTRAS_ReplayStart[1].status = IT_CALL|IT_STRING;
//EXTRAS_ReplayStart[1].alphaKey = 10;
EXTRAS_ReplayStart[2].status = IT_DISABLED;
itemOn = 0;
break;
case DFILE_ERROR_EXTRAFILES:
case DFILE_ERROR_OUTOFORDER:
default:
// Show "Watch Replay"
EXTRAS_ReplayStart[0].status = IT_DISABLED;
EXTRAS_ReplayStart[1].status = IT_DISABLED;
EXTRAS_ReplayStart[2].status = IT_CALL|IT_STRING;
//EXTRAS_ReplayStart[2].alphaKey = 0;
itemOn = 2;
break;
}
}
break;
}
}
boolean M_QuitReplayHut(void)
{
// D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate.
menuactive = false;
D_StartTitle();
if (extrasmenu.demolist)
Z_Free(extrasmenu.demolist);
extrasmenu.demolist = NULL;
demo.inreplayhut = false;
return true;
}
void M_HutStartReplay(INT32 choice)
{
(void)choice;
M_ClearMenus(false);
demo.loadfiles = (itemOn == 0);
demo.ignorefiles = (itemOn != 0);
G_DoPlayDemo(extrasmenu.demolist[dir_on[menudepthleft]].filepath);
}
static void Splitplayers_OnChange(void)
{
#if 0

View file

@ -310,6 +310,7 @@ void A_JawzExplode(mobj_t *actor);
void A_SPBChase(mobj_t *actor);
void A_SSMineSearch(mobj_t *actor);
void A_SSMineExplode(mobj_t *actor);
void A_LandMineExplode(mobj_t *actor);
void A_BallhogExplode(mobj_t *actor);
void A_LightningFollowPlayer(mobj_t *actor);
void A_FZBoomFlash(mobj_t *actor);
@ -11194,10 +11195,13 @@ void A_MineExplode(mobj_t *actor)
A_Scream(actor);
actor->flags = MF_NOGRAVITY|MF_NOCLIP;
/*
quake.epicenter = NULL;
quake.radius = 512*FRACUNIT;
quake.intensity = 8*FRACUNIT;
quake.time = TICRATE/3;
*/
P_StartQuake(8<<FRACBITS, TICRATE/3);
P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, 0, true);
P_MobjCheckWater(actor);
@ -12204,9 +12208,9 @@ void A_Boss5BombExplode(mobj_t *actor)
P_DustRing(locvar1, 4, actor->x, actor->y, actor->z+actor->height, 2*actor->radius, 0, FRACUNIT, actor->scale);
P_DustRing(locvar1, 6, actor->x, actor->y, actor->z+actor->height/2, 3*actor->radius, FRACUNIT, FRACUNIT, actor->scale);
//P_StartQuake(9*actor->scale, TICRATE/6, {actor->x, actor->y, actor->z}, 20*actor->radius);
//P_StartQuake(9*FRACUNIT, TICRATE/6, {actor->x, actor->y, actor->z}, 20*actor->radius);
// the above does not exist, so we set the quake values directly instead
quake.intensity = 9*actor->scale;
quake.intensity = 9*FRACUNIT;
quake.time = TICRATE/6;
// the following quake values have no effect atm? ah well, may as well set them anyway
{
@ -13250,6 +13254,8 @@ void A_ChangeHeight(mobj_t *actor)
void A_ItemPop(mobj_t *actor)
{
INT32 locvar1 = var1;
mobj_t *remains;
mobjtype_t explode;
@ -13304,7 +13310,9 @@ void A_ItemPop(mobj_t *actor)
if (actor->info->deathsound)
S_StartSound(remains, actor->info->deathsound);
if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumpers <= 0))
if (locvar1 == 1)
P_GivePlayerSpheres(actor->target->player, actor->extravalue1);
else if (locvar1 == 0)
actor->target->player->itemroulette = 1;
remains->flags2 &= ~MF2_AMBUSH;
@ -14132,6 +14140,50 @@ void A_SSMineExplode(mobj_t *actor)
actor->flags2 |= MF2_DEBRIS; // Set this flag to ensure that the explosion won't be effective more than 1 frame.
}
void A_LandMineExplode(mobj_t *actor)
{
mobj_t *expl;
INT32 colour = SKINCOLOR_KETCHUP; // we spell words properly here
INT32 i;
mobj_t *smoldering;
if (LUA_CallAction(A_LANDMINEEXPLODE, actor))
return;
// we'll base the explosion "timer" off of some stupid variable like uh... cvmem!
// Yeah let's use cvmem since nobody uses that
if (actor->target && !P_MobjWasRemoved(actor->target))
colour = actor->target->color;
K_MineFlashScreen(actor);
// Spawn smoke remains:
smoldering = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOLDERING);
P_SetScale(smoldering, actor->scale);
smoldering->tics = TICRATE*3;
actor->fuse = actor->tics; // disappear when this state ends.
// spawn a few physics explosions
for (i = 0; i < 15; i++)
{
expl = P_SpawnMobj(actor->x, actor->y, actor->z + actor->scale, MT_BOOMEXPLODE);
expl->color = colour;
expl->tics = (i+1);
//K_MatchGenericExtraFlags(expl, actor);
P_SetScale(expl, actor->scale*4);
expl->momx = P_RandomRange(-3, 3)*actor->scale/2;
expl->momy = P_RandomRange(-3, 3)*actor->scale/2;
// 100/45 = 2.22 fu/t
expl->momz = ((i+1)*actor->scale*5/2)*P_MobjFlip(expl);
}
}
void A_BallhogExplode(mobj_t *actor)
{
mobj_t *mo2;

View file

@ -268,12 +268,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!P_CanPickupItem(player, 1))
return;
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
{
return;
}
special->momx = special->momy = special->momz = 0;
P_SetTarget(&special->target, toucher);
P_KillMobj(special, toucher, toucher, DMG_NORMAL);
break;
case MT_SPHEREBOX:
if (player->bumpers <= 0)
return;
P_SetTarget(&special->target, toucher);
P_KillMobj(special, toucher, toucher, DMG_NORMAL);
break;
@ -510,16 +512,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!(P_CanPickupItem(player, 0)))
return;
// Reached the cap, don't waste 'em!
if (player->spheres >= 40)
return;
// Not alive
if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0))
return;
special->momx = special->momy = special->momz = 0;
player->spheres++;
P_GivePlayerSpheres(player, 1);
break;
// Secret emblem thingy

View file

@ -112,6 +112,10 @@ typedef struct camera_s
fixed_t pan;
// SRB2Kart: camera pitches on slopes
angle_t pitch;
// Interpolation data
fixed_t old_x, old_y, old_z;
angle_t old_angle, old_aiming;
} camera_t;
// demo freecam or something before i commit die
@ -171,7 +175,7 @@ void P_RestoreMusic(player_t *player);
boolean P_EndingMusic(player_t *player);
mobj_t *P_SpawnGhostMobj(mobj_t *mobj);
INT32 P_GivePlayerRings(player_t *player, INT32 num_rings);
void P_GivePlayerSpheres(player_t *player, INT32 num_spheres);
INT32 P_GivePlayerSpheres(player_t *player, INT32 num_spheres);
void P_GivePlayerLives(player_t *player, INT32 numlives);
UINT8 P_GetNextEmerald(void);
void P_GiveEmerald(boolean spawnObj);
@ -329,6 +333,7 @@ void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab);
mobj_t *P_GetClosestAxis(mobj_t *source);
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover);
boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover);
void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot);
@ -399,6 +404,8 @@ boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing);
boolean P_IsLineTripWire(const line_t *ld);
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
fixed_t P_BaseStepUp(void);
fixed_t P_GetThingStepUp(mobj_t *thing);
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
boolean P_Move(mobj_t *actor, fixed_t speed);
boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
@ -408,6 +415,7 @@ void P_BouncePlayerMove(mobj_t *mo);
void P_BounceMove(mobj_t *mo);
boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2);
boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2);
void P_CheckHoopPosition(mobj_t *hoopthing, fixed_t x, fixed_t y, fixed_t z, fixed_t radius);
boolean P_CheckSector(sector_t *sector, boolean crunch);

View file

@ -310,6 +310,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (spring->eflags & MFE_VERTICALFLIP)
vertispeed *= -1;
if ((spring->eflags ^ object->eflags) & MFE_VERTICALFLIP)
vertispeed *= 2;
// Vertical springs teleport you on TOP of them.
if (vertispeed > 0)
{
@ -1848,7 +1851,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
continue;
}
if (thing->player && P_CheckSolidLava(rover))
if (thing->player && P_CheckSolidFFloorSurface(thing->player, rover))
;
else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE))
;
@ -2414,6 +2417,56 @@ boolean PIT_PushableMoved(mobj_t *thing)
return true;
}
static boolean P_WaterRunning(mobj_t *thing)
{
ffloor_t *rover = thing->floorrover;
return rover && (rover->flags & FF_SWIMMABLE) &&
P_IsObjectOnGround(thing);
}
static boolean P_WaterStepUp(mobj_t *thing)
{
player_t *player = thing->player;
return (player && player->waterskip) ||
P_WaterRunning(thing);
}
fixed_t P_BaseStepUp(void)
{
return FixedMul(MAXSTEPMOVE, mapobjectscale);
}
fixed_t P_GetThingStepUp(mobj_t *thing)
{
const fixed_t maxstepmove = P_BaseStepUp();
fixed_t maxstep = maxstepmove;
if (thing->type == MT_SKIM)
{
// Skim special (not needed for kart?)
return 0;
}
if (P_WaterStepUp(thing) == true)
{
// Add some extra stepmove when waterskipping
maxstep += maxstepmove;
}
if (P_MobjTouchingSectorSpecial(thing, 1, 13, false))
{
// If using type Section1:13, double the maxstep.
maxstep <<= 1;
}
else if (P_MobjTouchingSectorSpecial(thing, 1, 12, false))
{
// If using type Section1:12, no maxstep. For short walls, like Egg Zeppelin
maxstep = 0;
}
return maxstep;
}
//
// P_TryMove
// Attempt to move to a new position.
@ -2475,21 +2528,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
if (!(thing->flags & MF_NOCLIP))
{
//All things are affected by their scale.
const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale);
fixed_t maxstep = maxstepmove;
if (thing->player && thing->player->waterskip)
maxstep += maxstepmove; // Add some extra stepmove when waterskipping
// If using type Section1:13, double the maxstep.
if (P_MobjTouchingSectorSpecial(thing, 1, 13, false))
maxstep <<= 1;
// If using type Section1:12, no maxstep. For short walls, like Egg Zeppelin
else if (P_MobjTouchingSectorSpecial(thing, 1, 12, false))
maxstep = 0;
if (thing->type == MT_SKIM)
maxstep = 0;
fixed_t maxstep = P_GetThingStepUp(thing);
if (tmceilingz - tmfloorz < thing->height)
{
@ -2726,7 +2765,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
if (!(thing->flags & MF_NOCLIP))
{
const fixed_t maxstep = FixedMul(MAXSTEPMOVE, mapobjectscale);
const fixed_t maxstep = P_BaseStepUp();
if (tmceilingz - tmfloorz < thing->height)
return false; // doesn't fit
@ -3188,7 +3227,7 @@ static boolean PTR_LineIsBlocking(line_t *li)
if (opentop - slidemo->z < slidemo->height)
return true; // mobj is too high
if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, mapobjectscale))
if (openbottom - slidemo->z > P_GetThingStepUp(slidemo))
return true; // too big a step up
return false;

View file

@ -730,7 +730,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
if (!(rover->flags & FF_EXISTS))
continue;
if (mobj->player && P_CheckSolidLava(rover))
if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover))
;
else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
@ -772,7 +772,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
if (!(rover->flags & FF_EXISTS))
continue;
if (mobj->player && P_CheckSolidLava(rover))
if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover))
;
else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))

View file

@ -1879,7 +1879,7 @@ void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype)
topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL);
bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL);
if (mo->player && P_CheckSolidLava(rover)) // only the player should stand on lava
if (mo->player && P_CheckSolidFFloorSurface(mo->player, rover)) // only the player should stand on lava or run on water
;
else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only
continue;
@ -2940,6 +2940,33 @@ boolean P_SceneryZMovement(mobj_t *mo)
return true;
}
// P_CanRunOnWater
//
// Returns true if player can waterrun on the 3D floor
//
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
{
boolean flip = player->mo->eflags & MFE_VERTICALFLIP;
fixed_t surfaceheight = flip ? player->mo->waterbottom : player->mo->watertop;
fixed_t playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z;
fixed_t clip = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight);
fixed_t span = player->mo->watertop - player->mo->waterbottom;
return
clip > -(player->mo->height / 2) &&
span > player->mo->height &&
player->speed / 5 > abs(player->mo->momz) &&
player->speed > K_GetKartSpeed(player, false) &&
K_WaterRun(player) &&
(rover->flags & FF_SWIMMABLE);
}
boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover)
{
return P_CheckSolidLava(rover) ||
P_CanRunOnWater(player, rover);
}
//
// P_MobjCheckWater
//
@ -2955,7 +2982,10 @@ void P_MobjCheckWater(mobj_t *mobj)
ffloor_t *rover;
player_t *p = mobj->player; // Will just be null if not a player.
fixed_t height = mobj->height;
fixed_t halfheight = height / 2;
boolean wasgroundpounding = false;
fixed_t top2 = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y);
fixed_t bot2 = P_GetSectorFloorZAt(sector, mobj->x, mobj->y);
// Default if no water exists.
mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT;
@ -2966,24 +2996,31 @@ void P_MobjCheckWater(mobj_t *mobj)
for (rover = sector->ffloors; rover; rover = rover->next)
{
fixed_t topheight, bottomheight;
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE)
|| (((rover->flags & FF_BLOCKPLAYER) && mobj->player)
|| ((rover->flags & FF_BLOCKOTHERS) && !mobj->player)))
continue;
topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y);
bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y);
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE)
|| (((rover->flags & FF_BLOCKPLAYER) && mobj->player)
|| ((rover->flags & FF_BLOCKOTHERS) && !mobj->player)))
{
if (topheight < top2 && topheight > thingtop)
top2 = topheight;
if (bottomheight > bot2 && bottomheight < mobj->z)
bot2 = bottomheight;
continue;
}
if (mobj->eflags & MFE_VERTICALFLIP)
{
if (topheight < (thingtop - (height>>1))
|| bottomheight > thingtop)
if (topheight < (thingtop - halfheight)
|| bottomheight > (thingtop + halfheight))
continue;
}
else
{
if (topheight < mobj->z
|| bottomheight > (mobj->z + (height>>1)))
if (topheight < (mobj->z - halfheight)
|| bottomheight > (mobj->z + halfheight))
continue;
}
@ -3011,19 +3048,87 @@ void P_MobjCheckWater(mobj_t *mobj)
}
}
if (mobj->watertop > top2)
mobj->watertop = top2;
if (mobj->waterbottom < bot2)
mobj->waterbottom = bot2;
// Spectators and dead players don't get to do any of the things after this.
if (p && (p->spectator || p->playerstate != PST_LIVE))
return;
// The rest of this code only executes on a water state change.
if (waterwasnotset || !!(mobj->eflags & MFE_UNDERWATER) == wasinwater)
if (!!(mobj->eflags & MFE_UNDERWATER) == wasinwater)
return;
if (p && !p->waterskip &&
p->curshield != KSHIELD_BUBBLE && wasinwater)
{
S_StartSound(mobj, sfx_s3k38);
}
if ((p) // Players
|| (mobj->flags & MF_PUSHABLE) // Pushables
|| ((mobj->info->flags & MF_PUSHABLE) && mobj->fuse) // Previously pushable, might be moving still
)
{
// Time to spawn the bubbles!
{
INT32 i;
INT32 bubblecount;
UINT8 prandom[4];
mobj_t *bubble;
mobjtype_t bubbletype;
if (mobj->eflags & MFE_GOOWATER || wasingoo)
S_StartSound(mobj, sfx_ghit);
else if (mobj->eflags & MFE_TOUCHLAVA)
S_StartSound(mobj, sfx_splash);
else
S_StartSound(mobj, sfx_splish); // And make a sound!
bubblecount = FixedDiv(abs(mobj->momz), mobj->scale)>>(FRACBITS-1);
// Max bubble count
if (bubblecount > 128)
bubblecount = 128;
// Create tons of bubbles
for (i = 0; i < bubblecount; i++)
{
// P_RandomByte()s are called individually to allow consistency
// across various compilers, since the order of function calls
// in C is not part of the ANSI specification.
prandom[0] = P_RandomByte();
prandom[1] = P_RandomByte();
prandom[2] = P_RandomByte();
prandom[3] = P_RandomByte();
bubbletype = MT_SMALLBUBBLE;
if (!(prandom[0] & 0x3)) // medium bubble chance up to 64 from 32
bubbletype = MT_MEDIUMBUBBLE;
bubble = P_SpawnMobj(
mobj->x + FixedMul((prandom[1]<<(FRACBITS-3)) * (prandom[0]&0x80 ? 1 : -1), mobj->scale),
mobj->y + FixedMul((prandom[2]<<(FRACBITS-3)) * (prandom[0]&0x40 ? 1 : -1), mobj->scale),
mobj->z + FixedMul((prandom[3]<<(FRACBITS-2)), mobj->scale), bubbletype);
if (bubble)
{
if (P_MobjFlip(mobj)*mobj->momz < 0)
bubble->momz = mobj->momz >> 4;
else
bubble->momz = 0;
bubble->destscale = mobj->scale;
P_SetScale(bubble, mobj->scale);
}
}
}
if (waterwasnotset)
return;
// Check to make sure you didn't just cross into a sector to jump out of
// that has shallower water than the block you were originally in.
if ((!(mobj->eflags & MFE_VERTICALFLIP) && mobj->watertop-mobj->floorz <= height>>1)
@ -3108,59 +3213,6 @@ void P_MobjCheckWater(mobj_t *mobj)
P_SetScale(splish, mobj->scale);
}
}
// Time to spawn the bubbles!
{
INT32 i;
INT32 bubblecount;
UINT8 prandom[4];
mobj_t *bubble;
mobjtype_t bubbletype;
if (mobj->eflags & MFE_GOOWATER || wasingoo)
S_StartSound(mobj, sfx_ghit);
else if (mobj->eflags & MFE_TOUCHLAVA)
S_StartSound(mobj, sfx_splash);
else
S_StartSound(mobj, sfx_splish); // And make a sound!
bubblecount = FixedDiv(abs(mobj->momz), mobj->scale)>>(FRACBITS-1);
// Max bubble count
if (bubblecount > 128)
bubblecount = 128;
// Create tons of bubbles
for (i = 0; i < bubblecount; i++)
{
// P_RandomByte()s are called individually to allow consistency
// across various compilers, since the order of function calls
// in C is not part of the ANSI specification.
prandom[0] = P_RandomByte();
prandom[1] = P_RandomByte();
prandom[2] = P_RandomByte();
prandom[3] = P_RandomByte();
bubbletype = MT_SMALLBUBBLE;
if (!(prandom[0] & 0x3)) // medium bubble chance up to 64 from 32
bubbletype = MT_MEDIUMBUBBLE;
bubble = P_SpawnMobj(
mobj->x + FixedMul((prandom[1]<<(FRACBITS-3)) * (prandom[0]&0x80 ? 1 : -1), mobj->scale),
mobj->y + FixedMul((prandom[2]<<(FRACBITS-3)) * (prandom[0]&0x40 ? 1 : -1), mobj->scale),
mobj->z + FixedMul((prandom[3]<<(FRACBITS-2)), mobj->scale), bubbletype);
if (bubble)
{
if (P_MobjFlip(mobj)*mobj->momz < 0)
bubble->momz = mobj->momz >> 4;
else
bubble->momz = 0;
bubble->destscale = mobj->scale;
P_SetScale(bubble, mobj->scale);
}
}
}
}
}
@ -3661,6 +3713,9 @@ void P_PrecipThinker(precipmobj_t *mobj)
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
P_CycleStateAnimation((mobj_t *)mobj);
@ -4049,7 +4104,7 @@ boolean P_BossTargetPlayer(mobj_t *actor, boolean closest)
player = &players[actor->lastlook];
if (player->bot || player->spectator)
if (player->spectator)
continue; // ignore notarget
if (!player->mo || P_MobjWasRemoved(player->mo))
@ -8551,6 +8606,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
break;
case MT_RANDOMITEM:
case MT_SPHEREBOX:
if (gametype == GT_BATTLE && mobj->threshold == 70)
{
mobj->color = K_RainbowColor(leveltime);
@ -8822,6 +8878,9 @@ void P_MobjThinker(mobj_t *mobj)
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
// Remove dead target/tracer.
if (mobj->target && P_MobjWasRemoved(mobj->target))
@ -9328,6 +9387,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
thing->shadowscale = 12*FRACUNIT/5;
break;
case MT_RANDOMITEM:
case MT_SPHEREBOX:
thing->shadowscale = FRACUNIT/2;
thing->whiteshadow = false;
break;
@ -9930,7 +9990,13 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
}
}
// OK so we kind of need NOTHINK objects to still think
// because otherwise they can never update their
// interpolation values. They might need some other kind
// of system, so consider this temporary...
#if 0
if (!(mobj->flags & MF_NOTHINK))
#endif
P_AddThinker(THINK_MOBJ, &mobj->thinker);
if (mobj->skin) // correct inadequecies above.
@ -9970,6 +10036,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
return mobj;
}
@ -10026,6 +10095,9 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
return mobj;
}

View file

@ -285,6 +285,7 @@ typedef struct mobj_s
// More drawing info: to determine current sprite.
angle_t angle, pitch, roll; // orientation
angle_t old_angle, old_pitch, old_roll; // orientation interpolation
angle_t rollangle;
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
@ -424,6 +425,7 @@ typedef struct precipmobj_s
// More drawing info: to determine current sprite.
angle_t angle, pitch, roll; // orientation
angle_t old_angle, old_pitch, old_roll; // orientation interpolation
angle_t rollangle;
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h

View file

@ -239,6 +239,8 @@ static void P_NetArchivePlayers(void)
WRITEINT32(save_p, players[i].aizdrifttilt);
WRITEINT32(save_p, players[i].aizdriftturn);
WRITEINT32(save_p, players[i].underwatertilt);
WRITEFIXED(save_p, players[i].offroad);
WRITEUINT8(save_p, players[i].waterskip);
@ -495,6 +497,8 @@ static void P_NetUnArchivePlayers(void)
players[i].aizdrifttilt = READINT32(save_p);
players[i].aizdriftturn = READINT32(save_p);
players[i].underwatertilt = READINT32(save_p);
players[i].offroad = READFIXED(save_p);
players[i].waterskip = READUINT8(save_p);

View file

@ -91,6 +91,7 @@
#include "k_waypoint.h"
#include "k_bot.h"
#include "k_grandprix.h"
#include "k_brightmap.h"
// Replay names have time
#if !defined (UNDER_CE)
@ -4457,6 +4458,9 @@ boolean P_AddWadFile(const char *wadfilename)
// Reload ANIMDEFS
P_InitPicAnims();
// Reload BRIGHT
K_InitBrightmaps();
// Flush and reload HUD graphics
ST_UnloadGraphics();
HU_LoadGraphics();

View file

@ -18,6 +18,9 @@
#include "r_main.h"
#include "r_state.h"
#include "k_bot.h" // K_BotHatesThisSector
#include "k_kart.h" // K_TripwirePass
//
// P_CheckSight
//
@ -572,7 +575,7 @@ static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb
if (P_IsLineBlocking(line, tb->compareThing) == true)
{
// This line will block us
// This line will always block us
return false;
}
}
@ -656,3 +659,192 @@ boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2)
// the head node is the last node output
return P_CrossBSPNodeBlocking((INT32)numnodes - 1, &tb);
}
//
// ANOTHER version, this time for bot traversal.
// (TODO: since we have so many versions of this function, the differences
// should maybe just be a function var that gets called?)
//
static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t *tb)
{
seg_t *seg;
INT32 count;
#ifdef RANGECHECK
if (num >= numsubsectors)
I_Error("P_CrossBotTraversalSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
#endif
// haleyjd 02/23/06: this assignment should be after the above check
seg = segs + subsectors[num].firstline;
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
{
line_t *line = seg->linedef;
divline_t divl;
const vertex_t *v1,*v2;
fixed_t maxstep = INT32_MAX;
if (seg->glseg)
continue;
// already checked other side?
if (line->validcount == validcount)
continue;
line->validcount = validcount;
// OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test
if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] ||
line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] ||
line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] ||
line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM])
continue;
v1 = line->v1;
v2 = line->v2;
// line isn't crossed?
if (P_DivlineSide(v1->x, v1->y, &tb->strace) ==
P_DivlineSide(v2->x, v2->y, &tb->strace))
continue;
// stop because it is not two sided anyway
if (!(line->flags & ML_TWOSIDED))
return false;
divl.dx = v2->x - (divl.x = v1->x);
divl.dy = v2->y - (divl.y = v1->y);
// line isn't crossed?
if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) ==
P_DivlineSide(tb->t2x, tb->t2y, &divl))
continue;
if (P_IsLineBlocking(line, tb->compareThing) == true)
{
// This line will always block us
return false;
}
// set openrange, opentop, openbottom
P_LineOpening(line, tb->compareThing);
maxstep = P_GetThingStepUp(tb->compareThing);
if ((openrange < tb->compareThing->height) // doesn't fit
|| (opentop - tb->compareThing->z < tb->compareThing->height) // mobj is too high
|| (openbottom - tb->compareThing->z > maxstep)) // too big a step up
{
// This line situationally blocks us
return false;
}
// Treat damage sectors like walls
if (tb->compareThing->player != NULL)
{
boolean alreadyHates = K_BotHatesThisSector(tb->compareThing->player, tb->compareThing->subsector->sector, tb->compareThing->x, tb->compareThing->y);
if (alreadyHates == false)
{
INT32 lineside = 0;
vertex_t pos;
P_ClosestPointOnLine(tb->compareThing->x, tb->compareThing->y, line, &pos);
lineside = P_PointOnLineSide(tb->compareThing->x, tb->compareThing->y, line);
if (K_BotHatesThisSector(tb->compareThing->player, ((lineside == 1) ? line->frontsector : line->backsector), pos.x, pos.y))
{
// This line does not block us, but we don't want to be in it.
return false;
}
}
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
{
// Can't go through trip wire.
return false;
}
}
}
// passed the subsector ok
return true;
}
static boolean P_CrossBSPNodeBotTraversal(INT32 bspnum, register traceblocking_t *tb)
{
while (!(bspnum & NF_SUBSECTOR))
{
register node_t *bsp = nodes + bspnum;
INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1;
if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp))
bspnum = bsp->children[side]; // doesn't touch the other side
else // the partition plane is crossed here
{
if (!P_CrossBSPNodeBotTraversal(bsp->children[side], tb))
return false; // cross the starting side
else
bspnum = bsp->children[side^1]; // cross the ending side
}
}
return P_CrossBotTraversalSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb);
}
boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2)
{
const sector_t *s1, *s2;
size_t pnum;
traceblocking_t tb;
// First check for trivial rejection.
if (!t1 || !t2)
return false;
I_Assert(!P_MobjWasRemoved(t1));
I_Assert(!P_MobjWasRemoved(t2));
if (!t1->subsector || !t2->subsector
|| !t1->subsector->sector || !t2->subsector->sector)
return false;
s1 = t1->subsector->sector;
s2 = t2->subsector->sector;
pnum = (s1-sectors)*numsectors + (s2-sectors);
if (rejectmatrix != NULL)
{
// Check in REJECT table.
if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
return false;
}
// killough 11/98: shortcut for melee situations
// same subsector? obviously visible
// haleyjd 02/23/06: can't do this if there are polyobjects in the subsec
if (!t1->subsector->polyList &&
t1->subsector == t2->subsector)
return true;
validcount++;
tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x);
tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y);
if (t1->x > t2->x)
tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x;
else
tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x;
if (t1->y > t2->y)
tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y;
else
tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y;
tb.compareThing = t1;
// the head node is the last node output
return P_CrossBSPNodeBotTraversal((INT32)numnodes - 1, &tb);
}

View file

@ -2982,9 +2982,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// reasonable defaults.
if (!quake.intensity)
quake.intensity = 8<<FRACBITS;
quake.intensity = 8*mapobjectscale;
if (!quake.radius)
quake.radius = 512<<FRACBITS;
quake.radius = 512*mapobjectscale;
break;
}
@ -8752,6 +8752,6 @@ static void P_SpawnPushers(void)
// epicenter and radius are not yet used.
void P_StartQuake(fixed_t intensity, tic_t time)
{
quake.intensity = intensity;
quake.intensity = FixedMul(intensity, mapobjectscale);
quake.time = time;
}

View file

@ -500,6 +500,26 @@ INT32 P_GivePlayerRings(player_t *player, INT32 num_rings)
return num_rings;
}
INT32 P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
{
num_spheres += player->spheres;
// Not alive
if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0))
return 0;
if (num_spheres > 40) // Reached the cap, don't waste 'em!
num_spheres = 40;
else if (num_spheres < 0)
num_spheres = 0;
num_spheres -= player->spheres;
player->spheres += num_spheres;
return num_spheres;
}
//
// P_GivePlayerLives
//
@ -1145,6 +1165,9 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->old_x = mobj->old_x;
ghost->old_y = mobj->old_y;
ghost->old_z = mobj->old_z;
ghost->old_angle = (mobj->player ? mobj->player->old_drawangle : mobj->old_angle);
ghost->old_pitch = mobj->old_pitch;
ghost->old_roll = mobj->old_roll;
return ghost;
}
@ -1769,6 +1792,55 @@ static void P_3dMovement(player_t *player)
if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration...
movepushforward = FixedMul(movepushforward, player->mo->movefactor);
{
INT32 a = K_GetUnderwaterTurnAdjust(player);
INT32 adj = 0;
if (a)
{
const fixed_t maxadj = ANG10/4;
adj = a / 4;
if (adj > 0)
{
if (adj > maxadj)
adj = maxadj;
}
else if (adj < 0)
{
if (adj < -(maxadj))
adj = -(maxadj);
}
if (abs(player->underwatertilt + adj) > abs(a))
adj = (a - player->underwatertilt);
if (abs(a) < abs(player->underwatertilt))
adj = 0;
movepushangle += a;
}
if (adj)
{
player->underwatertilt += adj;
if (abs(player->underwatertilt) > ANG30)
{
player->underwatertilt =
player->underwatertilt > 0 ? ANG30
: -(ANG30);
}
}
else
{
player->underwatertilt =
FixedMul(player->underwatertilt,
7*FRACUNIT/8);
}
}
totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward);
totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward);
}
@ -2055,6 +2127,10 @@ void P_MovePlayer(player_t *player)
else if (player->drift != 0)
{
INT32 a = (ANGLE_45 / 5) * player->drift;
if (player->mo->eflags & MFE_UNDERWATER)
a /= 2;
player->drawangle += a;
}
}
@ -2446,6 +2522,8 @@ static void P_ConsiderAllGone(void)
//
static void P_DeathThink(player_t *player)
{
boolean playerGone = false;
player->deltaviewheight = 0;
if (player->deadtimer < INT32_MAX)
@ -2466,7 +2544,19 @@ static void P_DeathThink(player_t *player)
K_KartPlayerHUDUpdate(player);
if (player->lives > 0 && !(player->pflags & PF_NOCONTEST) && player->deadtimer > TICRATE)
if (player->pflags & PF_NOCONTEST)
{
playerGone = true;
}
else if (player->bot == false)
{
if (G_GametypeUsesLives() == true && player->lives == 0)
{
playerGone = true;
}
}
if (playerGone == false && player->deadtimer > TICRATE)
{
player->playerstate = PST_REBORN;
}
@ -2850,6 +2940,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
subsector_t *newsubsec;
#endif
thiscam->old_x = thiscam->x;
thiscam->old_y = thiscam->y;
thiscam->old_z = thiscam->z;
thiscam->old_angle = thiscam->angle;
thiscam->old_aiming = thiscam->aiming;
democam.soundmobj = NULL; // reset this each frame, we don't want the game crashing for stupid reasons now do we
// We probably shouldn't move the camera if there is no player or player mobj somehow
@ -4174,10 +4270,10 @@ void P_PlayerThink(player_t *player)
player->playerstate = PST_DEAD;
}
if (player->mo->hitlag > 0)
{
return;
}
player->old_drawangle = player->drawangle;
player->old_viewrollangle = player->viewrollangle;
player->pflags &= ~PF_HITFINISHLINE;
if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj))
{
@ -4194,6 +4290,11 @@ void P_PlayerThink(player_t *player)
if (player->awayviewtics && player->awayviewtics != -1)
player->awayviewtics--;
if (player->mo->hitlag > 0)
{
return;
}
// Track airtime
if (P_IsObjectOnGround(player->mo))
{

View file

@ -30,6 +30,9 @@
#include "byteptr.h"
#include "dehacked.h"
// DRRR
#include "k_brightmap.h"
//
// Graphics.
// SRB2 graphics for walls and sprites
@ -615,6 +618,7 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
{
double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb, cdestbright;
double maskamt = 0, othermask = 0;
double fmaskamt = 0, fothermask = 0;
UINT8 cr = R_GetRgbaR(extra_colormap->rgba),
cg = R_GetRgbaG(extra_colormap->rgba),
@ -622,8 +626,8 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
ca = R_GetRgbaA(extra_colormap->rgba),
cfr = R_GetRgbaR(extra_colormap->fadergba),
cfg = R_GetRgbaG(extra_colormap->fadergba),
cfb = R_GetRgbaB(extra_colormap->fadergba);
// cfa = R_GetRgbaA(extra_colormap->fadergba); // unused in software
cfb = R_GetRgbaB(extra_colormap->fadergba),
cfa = R_GetRgbaA(extra_colormap->fadergba);
UINT8 fadestart = extra_colormap->fadestart,
fadedist = extra_colormap->fadeend - extra_colormap->fadestart;
@ -654,14 +658,11 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
cdestb = cfb;
cdestbright = sqrt((cfr*cfr) + (cfg*cfg) + (cfb*cfb));
// fade alpha unused in software
// maskamt = (double)(cfa/24.0l);
// othermask = 1 - maskamt;
// maskamt /= 0xff;
fmaskamt = (double)(cfa/24.0l);
fothermask = 1 - fmaskamt;
//fmaskamt /= 0xff;
// cdestr *= maskamt;
// cdestg *= maskamt;
// cdestb *= maskamt;
(void)fothermask; // unused, but don't feel like commenting it out
/////////////////////
// This code creates the colormap array used by software renderer
@ -701,16 +702,16 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
if (cbrightness < cdestbright)
{
cbest = 255.0l - min(r, min(g, b));
cdist = 255.0l - cdestbright;
cdist = 255.0l - max(cdestr, max(cdestg, cdestb));
}
else
{
cbest = max(r, max(g, b));
cdist = cdestbright;
cdist = min(cdestr, min(cdestg, cdestb));
}
// Add/subtract this value during fading.
brightChange[i] = fabs(cbest - cdist) / (double)fadedist;
brightChange[i] = (fabs(cbest - cdist) / (double)fadedist) * fmaskamt;
}
// Now allocate memory for the actual colormap array itself!
@ -1177,6 +1178,9 @@ void R_InitTextureData(void)
CONS_Printf("P_InitPicAnims()...\n");
P_InitPicAnims();
CONS_Printf("K_InitBrightmaps()...\n");
K_InitBrightmaps();
}
//

View file

@ -26,6 +26,7 @@
#include "z_zone.h"
#include "console.h" // Until buffering gets finished
#include "k_color.h" // SRB2kart
#include "i_threads.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -71,12 +72,14 @@ UINT8 *topleft;
// =========================================================================
lighttable_t *dc_colormap;
lighttable_t *dc_fullbright;
INT32 dc_x = 0, dc_yl = 0, dc_yh = 0;
fixed_t dc_iscale, dc_texturemid;
UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bit,
// soo lets make it a byte on all system for the ASM code
UINT8 *dc_source;
UINT8 *dc_brightmap;
// -----------------------
// translucency stuff here
@ -108,6 +111,7 @@ INT32 dc_numlights = 0, dc_maxlights, dc_texheight;
INT32 ds_y, ds_x1, ds_x2;
lighttable_t *ds_colormap;
lighttable_t *ds_fullbright;
lighttable_t *ds_translation; // Lactozilla: Sprite splat drawer
fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
@ -117,6 +121,7 @@ UINT16 ds_flatwidth, ds_flatheight;
boolean ds_powersoftwo;
UINT8 *ds_source; // points to the start of a flat
UINT8 *ds_brightmap; // start of brightmap flat
UINT8 *ds_transmap; // one of the translucency tables
// Vectors for Software's tilted slope drawers
@ -192,6 +197,29 @@ CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "
#define TRANSTAB_AMTMUL10 (255.0f / 10.0f)
static void R_AllocateBlendTables(void)
{
INT32 i;
for (i = 0; i < NUMBLENDMAPS; i++)
{
if (i == blendtab_modulate)
continue;
blendtables[i] = Z_MallocAlign((NUMTRANSTABLES + 1) * 0x10000, PU_STATIC, NULL, 16);
}
// Modulation blending only requires a single table
blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16);
}
#ifdef HAVE_THREADS
static void R_GenerateBlendTables_Thread(void *userdata)
{
(void)userdata;
R_GenerateBlendTables();
}
#endif
/** \brief Initializes the translucency tables used by the Software renderer.
*/
void R_InitTranslucencyTables(void)
@ -212,20 +240,20 @@ void R_InitTranslucencyTables(void)
W_ReadLump(W_GetNumForName("TRANS80"), transtables+0x70000);
W_ReadLump(W_GetNumForName("TRANS90"), transtables+0x80000);
R_AllocateBlendTables();
#ifdef HAVE_THREADS
I_spawn_thread("blend-tables",
R_GenerateBlendTables_Thread, NULL);
#else
R_GenerateBlendTables();
#endif
}
void R_GenerateBlendTables(void)
{
INT32 i;
for (i = 0; i < NUMBLENDMAPS; i++)
{
if (i == blendtab_modulate)
continue;
blendtables[i] = Z_MallocAlign((NUMTRANSTABLES + 1) * 0x10000, PU_STATIC, NULL, 16);
}
for (i = 0; i <= 9; i++)
{
const size_t offs = (0x10000 * i);
@ -236,8 +264,6 @@ void R_GenerateBlendTables(void)
R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, AST_REVERSESUBTRACT, alpha);
}
// Modulation blending only requires a single table
blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16);
R_GenerateTranslucencyTable(blendtables[blendtab_modulate], AST_MODULATE, 0);
}

View file

@ -32,11 +32,13 @@ extern UINT8 *topleft;
// -------------------------
extern lighttable_t *dc_colormap;
extern lighttable_t *dc_fullbright;
extern INT32 dc_x, dc_yl, dc_yh;
extern fixed_t dc_iscale, dc_texturemid;
extern UINT8 dc_hires;
extern UINT8 *dc_source; // first pixel in a column
extern UINT8 *dc_brightmap; // brightmap texture column, can be NULL
// translucency stuff here
extern UINT8 *dc_transmap;
@ -57,6 +59,7 @@ extern INT32 dc_texheight;
extern INT32 ds_y, ds_x1, ds_x2;
extern lighttable_t *ds_colormap;
extern lighttable_t *ds_fullbright;
extern lighttable_t *ds_translation;
extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
@ -66,6 +69,7 @@ extern UINT16 ds_flatwidth, ds_flatheight;
extern boolean ds_powersoftwo;
extern UINT8 *ds_source;
extern UINT8 *ds_brightmap;
extern UINT8 *ds_transmap;
typedef struct {
@ -167,6 +171,7 @@ void R_DrawViewBorder(void);
#endif
#define TRANSPARENTPIXEL 255
#define BRIGHTPIXEL 0
// -----------------
// 8bpp DRAWING CODE

File diff suppressed because it is too large Load diff

View file

@ -83,10 +83,7 @@ static void R_SetupFreelook(player_t *player, boolean skybox)
void R_InterpolateView(fixed_t frac)
{
boolean skybox = false;
INT32 i;
if (FIXED_TO_FLOAT(frac) < 0)
if (frac < 0)
frac = 0;
if (frac > FRACUNIT)
frac = FRACUNIT;
@ -97,31 +94,20 @@ void R_InterpolateView(fixed_t frac)
viewangle = oldview->angle + R_LerpAngle(oldview->angle, newview->angle, frac);
aimingangle = oldview->aim + R_LerpAngle(oldview->aim, newview->aim, frac);
viewroll = oldview->roll + R_LerpAngle(oldview->roll, newview->roll, frac);
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
// this is gonna create some interesting visual errors for long distance teleports...
// might want to recalculate the view sector every frame instead...
viewplayer = newview->player;
viewsector = R_PointInSubsector(viewx, viewy)->sector;
// well, this ain't pretty
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (newview == &skyview_new[i])
{
skybox = true;
break;
}
}
R_SetupFreelook(newview->player, skybox);
R_SetupFreelook(newview->player, newview->sky);
}
void R_UpdateViewInterpolation(void)
{
INT32 i;
UINT8 i;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
@ -132,7 +118,7 @@ void R_UpdateViewInterpolation(void)
void R_SetViewContext(enum viewcontext_e _viewcontext)
{
INT32 i;
UINT8 i = 0;
I_Assert(_viewcontext >= VIEWCONTEXT_PLAYER1
&& _viewcontext <= VIEWCONTEXT_SKY4);

View file

@ -41,6 +41,7 @@ typedef struct {
angle_t angle;
angle_t aim;
angle_t roll;
fixed_t cos;
fixed_t sin;
mobj_t *mobj;

View file

@ -71,7 +71,7 @@ size_t framecount;
size_t loopcount;
fixed_t viewx, viewy, viewz;
angle_t viewangle, aimingangle;
angle_t viewangle, aimingangle, viewroll;
UINT8 viewssnum;
fixed_t viewcos, viewsin;
sector_t *viewsector;
@ -149,10 +149,6 @@ static void ChaseCam_OnChange(void);
static void ChaseCam2_OnChange(void);
static void ChaseCam3_OnChange(void);
static void ChaseCam4_OnChange(void);
void SendWeaponPref(void);
void SendWeaponPref2(void);
void SendWeaponPref3(void);
void SendWeaponPref4(void);
consvar_t cv_tailspickup = CVAR_INIT ("tailspickup", "On", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL);
consvar_t cv_chasecam[MAXSPLITSCREENPLAYERS] = {
@ -656,7 +652,7 @@ void R_CheckViewMorph(int s)
float fisheyemap[MAXVIDWIDTH/2 + 1];
#endif
angle_t rollangle = R_ViewRollAngle(&players[displayplayers[s]]);
angle_t rollangle = viewroll;
#ifdef WOUGHMP_WOUGHMP
fixed_t fisheye = cv_cam2_turnmultiplier.value; // temporary test value
#endif
@ -1141,7 +1137,7 @@ void R_Init(void)
R_InitLightTables();
//I_OutputMsg("\nR_InitTranslucencyTables\n");
R_InitTranslucencyTables();
//R_InitTranslucencyTables();
R_InitDrawNodes();
@ -1206,8 +1202,8 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
void R_SetupFrame(player_t *player)
{
camera_t *thiscam = &camera[0];
boolean chasecam = false;
UINT8 i;
boolean chasecam = (cv_chasecam[0].value != 0);
UINT8 i = 0;
for (i = 0; i <= r_splitscreen; i++)
{
@ -1221,12 +1217,17 @@ void R_SetupFrame(player_t *player)
}
if (i > r_splitscreen)
return; // shouldn't be possible, but just in case
{
i = 0; // Shouldn't be possible, but just in case.
thiscam = &camera[0];
chasecam = (cv_chasecam[0].value != 0);
R_SetViewContext(VIEWCONTEXT_PLAYER1);
}
if (player->spectator) // no spectator chasecam
chasecam = false; // force chasecam off
if (chasecam && !thiscam->chase)
if (chasecam && (thiscam && !thiscam->chase))
{
P_ResetCamera(player, thiscam);
thiscam->chase = true;
@ -1270,6 +1271,7 @@ void R_SetupFrame(player_t *player)
newview->aim = localaiming[i];
}
}
newview->roll = R_ViewRollAngle(player);
newview->z += quake.z;
newview->player = player;
@ -1302,7 +1304,7 @@ void R_SetupFrame(player_t *player)
// newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT);
// newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
R_InterpolateView(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT);
R_InterpolateView(rendertimefrac);
}
void R_SkyboxFrame(player_t *player)
@ -1310,22 +1312,21 @@ void R_SkyboxFrame(player_t *player)
camera_t *thiscam = &camera[0];
UINT8 i = 0;
if (r_splitscreen)
for (i = 0; i <= r_splitscreen; i++)
{
for (i = 1; i <= r_splitscreen; i++)
if (player == &players[displayplayers[i]])
{
if (player == &players[displayplayers[i]])
{
thiscam = &camera[i];
R_SetViewContext(VIEWCONTEXT_SKY1 + i);
break;
}
thiscam = &camera[i];
R_SetViewContext(VIEWCONTEXT_SKY1 + i);
break;
}
}
if (i > r_splitscreen)
{
i = 0;
}
if (i > r_splitscreen)
{
i = 0; // Shouldn't be possible, but just in case.
thiscam = &camera[0];
R_SetViewContext(VIEWCONTEXT_SKY1);
}
// cut-away view stuff
@ -1343,7 +1344,7 @@ void R_SkyboxFrame(player_t *player)
newview->aim = player->awayviewaiming;
newview->angle = player->awayviewmobj->angle;
}
else if (thiscam->chase)
else if (thiscam && thiscam->chase)
{
newview->aim = thiscam->aiming;
newview->angle = thiscam->angle;
@ -1359,6 +1360,7 @@ void R_SkyboxFrame(player_t *player)
}
}
newview->angle += r_viewmobj->angle;
newview->roll = R_ViewRollAngle(player);
newview->player = player;
@ -1445,7 +1447,7 @@ void R_SkyboxFrame(player_t *player)
// newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT);
// newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
R_InterpolateView(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT);
R_InterpolateView(rendertimefrac);
}
boolean R_ViewpointHasChasecam(player_t *player)

View file

@ -42,6 +42,7 @@ patch_t *Patch_GetRotatedSprite(
INT32 R_GetRollAngle(angle_t rollangle);
angle_t R_GetPitchRollAngle(mobj_t *mobj, player_t *viewPlayer);
angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer);
angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer);
#endif

View file

@ -42,7 +42,11 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
angle_t rollAngle = 0;
if (sliptideLift)
if (player->mo->eflags & MFE_UNDERWATER)
{
rollAngle -= player->underwatertilt;
}
else if (sliptideLift)
{
/* (from side) tilt downward if turning
toward camera, upward if away. */
@ -60,10 +64,9 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
return rollAngle;
}
angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer)
angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer)
{
angle_t rollOrPitch = R_GetPitchRollAngle(mobj, viewPlayer);
angle_t rollAngle = (rollOrPitch + mobj->rollangle);
angle_t rollAngle = mobj->rollangle;
if (mobj->player)
{
@ -73,6 +76,12 @@ angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer)
return rollAngle;
}
angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer)
{
angle_t rollOrPitch = R_GetPitchRollAngle(mobj, viewPlayer);
return (rollOrPitch + R_ModelRotationAngle(mobj, viewPlayer));
}
INT32 R_GetRollAngle(angle_t rollangle)
{
INT32 ra = AngleFixed(rollangle)>>FRACBITS;

View file

@ -105,6 +105,7 @@ typedef struct
} spriteinfo_t;
// Portable Network Graphics
#define PNG_HEADER_SIZE (8)
boolean Picture_IsLumpPNG(const UINT8 *d, size_t s);
#define Picture_ThrowPNGError(lumpname, wadfilename) I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .png - please convert to either Doom or Flat (raw) image format.", lumpname, wadfilename); // Fears Of LJ Sonic

View file

@ -235,7 +235,9 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
}
if (currentplane->slope)
{
ds_colormap = colormaps;
}
else
{
pindex = distance >> LIGHTZSHIFT;
@ -244,8 +246,13 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
ds_colormap = planezlight[pindex];
}
ds_fullbright = colormaps;
if (encoremap && !currentplane->noencore)
{
ds_colormap += COLORMAP_REMAPOFFSET;
ds_fullbright += COLORMAP_REMAPOFFSET;
}
if (currentplane->extra_colormap)
ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps);
@ -641,7 +648,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
// Reset column drawer function (note: couldn't we just call walldrawerfunc directly?)
// (that is, unless we'll need to switch drawers in future for some reason)
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
// use correct aspect ratio scale
dc_iscale = skyscale[viewssnum];
@ -651,8 +658,12 @@ static void R_DrawSkyPlane(visplane_t *pl)
// Because of this hack, sky is not affected
// by sector colormaps (INVUL inverse mapping is not implemented in SRB2 so is irrelevant).
dc_colormap = colormaps;
dc_fullbright = colormaps;
if (encoremap)
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
dc_texturemid = skytexturemid;
dc_texheight = textureheight[skytexture]
>>FRACBITS;
@ -669,6 +680,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
dc_source =
R_GetColumn(texturetranslation[skytexture],
-angle); // get negative of angle for each column to display sky correct way round! --Monster Iestyn 27/01/18
dc_brightmap = NULL;
colfunc();
}
}
@ -808,7 +820,8 @@ void R_DrawSinglePlane(visplane_t *pl)
}
planeripple.active = false;
spanfunc = spanfuncs[BASEDRAWFUNC];
ds_brightmap = NULL;
R_SetSpanFunc(BASEDRAWFUNC, false, false);
if (pl->polyobj)
{
@ -965,6 +978,17 @@ void R_DrawSinglePlane(visplane_t *pl)
R_CheckFlatLength(ds_flatwidth * ds_flatheight);
}
if (type == LEVELFLAT_TEXTURE)
{
// Get the span's brightmap.
// FLATS not supported, SORRY!!
INT32 bmNum = R_GetTextureBrightmap(levelflat->u.texture.num);
if (bmNum != 0)
{
ds_brightmap = (UINT8 *)R_GenerateTextureAsFlat(bmNum);
}
}
if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later
&& viewangle != pl->viewangle+pl->plangle)
{
@ -1080,15 +1104,7 @@ void R_DrawSinglePlane(visplane_t *pl)
planezlight = zlight[light];
// Use the correct span drawer depending on the powers-of-twoness
if (!ds_powersoftwo)
{
if (spanfuncs_npo2[spanfunctype])
spanfunc = spanfuncs_npo2[spanfunctype];
else
spanfunc = spanfuncs[spanfunctype];
}
else
spanfunc = spanfuncs[spanfunctype];
R_SetSpanFunc(spanfunctype, !ds_powersoftwo, ds_brightmap != NULL);
// set the maximum value for unsigned
pl->top[pl->maxx+1] = 0xffff;

View file

@ -36,6 +36,7 @@ static boolean markceiling;
static boolean maskedtexture;
static INT32 toptexture, bottomtexture, midtexture;
static INT32 topbrightmap, bottombrightmap, midbrightmap;
static INT32 numthicksides, numbackffloors;
angle_t rw_normalangle;
@ -83,7 +84,7 @@ static fixed_t *maskedtextureheight = NULL;
// multi-patch textures. They are not normally needed as multi-patch
// textures don't have holes in it. At least not for now.
static void R_Render2sidedMultiPatchColumn(column_t *column)
static void R_Render2sidedMultiPatchColumn(column_t *column, column_t *brightmap)
{
INT32 topscreen, bottomscreen;
@ -93,6 +94,8 @@ static void R_Render2sidedMultiPatchColumn(column_t *column)
dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS;
dc_brightmap = NULL;
if (windowtop != INT32_MAX && windowbottom != INT32_MAX)
{
dc_yl = ((windowtop + FRACUNIT)>>FRACBITS);
@ -110,10 +113,14 @@ static void R_Render2sidedMultiPatchColumn(column_t *column)
if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0)
{
dc_source = (UINT8 *)column + 3;
if (brightmap != NULL)
{
dc_brightmap = (UINT8 *)brightmap + 3;
}
if (colfunc == colfuncs[BASEDRAWFUNC])
if (R_CheckColumnFunc(BASEDRAWFUNC) == true)
(colfuncs[COLDRAWFUNC_TWOSMULTIPATCH])();
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
else if (R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == true)
(colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS])();
else
colfunc();
@ -132,12 +139,12 @@ transnum_t R_GetLinedefTransTable(line_t *ldef)
void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{
size_t pindex;
column_t *col;
INT32 lightnum, texnum, i;
column_t *col, *bmCol = NULL;
INT32 lightnum, texnum, bmnum, i;
fixed_t height, realbot;
lightlist_t *light;
r_lightlist_t *rlight;
void (*colfunc_2s)(column_t *);
void (*colfunc_2s)(column_t *, column_t *);
line_t *ldef;
sector_t *front, *back;
INT32 times, repeats;
@ -155,6 +162,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
frontsector = curline->frontsector;
backsector = curline->backsector;
texnum = R_GetTextureNum(curline->sidedef->midtexture);
bmnum = R_GetTextureBrightmap(texnum);
windowbottom = windowtop = sprbotscreen = INT32_MAX;
ldef = curline->linedef;
@ -188,16 +196,18 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if (transtable != NUMTRANSMAPS && (blendmode || transtable))
{
dc_transmap = R_GetBlendTable(blendmode, transtable);
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
R_SetColumnFunc(COLDRAWFUNC_FUZZY, bmnum != 0);
}
else if (ldef->special == 909)
{
colfunc = colfuncs[COLDRAWFUNC_FOG];
R_SetColumnFunc(COLDRAWFUNC_FOG, bmnum != 0);
windowtop = frontsector->ceilingheight;
windowbottom = frontsector->floorheight;
}
else
colfunc = colfuncs[BASEDRAWFUNC];
{
R_SetColumnFunc(BASEDRAWFUNC, bmnum != 0);
}
if (curline->polyseg && curline->polyseg->translucency > 0)
{
@ -205,7 +215,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
return;
dc_transmap = R_GetTranslucencyTable(curline->polyseg->translucency);
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
R_SetColumnFunc(COLDRAWFUNC_FUZZY, bmnum != 0);
}
range = max(ds->x2-ds->x1, 1);
@ -215,6 +225,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
if (bmnum) { R_CheckTextureCache(bmnum); }
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes)
@ -265,7 +277,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->extra_colormap = *light->extra_colormap;
rlight->flags = light->flags;
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
if ((R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == false)
|| (rlight->flags & FF_FOG)
|| (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
@ -282,13 +294,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
}
else
{
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
if ((R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == false)
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
else
lightnum = LIGHTLEVELS - 1;
if (colfunc == colfuncs[COLDRAWFUNC_FOG]
if ((R_CheckColumnFunc(COLDRAWFUNC_FOG) == true)
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
;
else
@ -400,6 +412,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// draw the texture
col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3);
if (bmnum) { bmCol = (column_t *)((UINT8 *)R_GetColumn(bmnum, maskedtexturecol[dc_x]) - 3); }
for (i = 0; i < dc_numlights; i++)
{
@ -431,8 +444,12 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if (height <= windowtop)
{
dc_colormap = rlight->rcolormap;
dc_fullbright = colormaps;
if (encoremap && !(ldef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
continue;
}
@ -440,7 +457,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if (windowbottom >= realbot)
{
windowbottom = realbot;
colfunc_2s(col);
colfunc_2s(col, bmCol);
for (i++; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
@ -449,15 +466,19 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
continue;
}
colfunc_2s(col);
colfunc_2s(col, bmCol);
windowtop = windowbottom + 1;
dc_colormap = rlight->rcolormap;
dc_fullbright = colormaps;
if (encoremap && !(ldef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
}
windowbottom = realbot;
if (windowtop < windowbottom)
colfunc_2s(col);
colfunc_2s(col, bmCol);
spryscale += rw_scalestep;
continue;
@ -470,8 +491,12 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
pindex = MAXLIGHTSCALE - 1;
dc_colormap = walllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(ldef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
if (frontsector->extra_colormap)
dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
@ -481,6 +506,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// draw the texture
col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3);
if (bmnum) { bmCol = (column_t *)((UINT8 *)R_GetColumn(bmnum, maskedtexturecol[dc_x]) - 3); }
#if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red
if (curline->dontrenderme && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES))
@ -535,19 +561,20 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
}
else
#endif
colfunc_2s(col);
colfunc_2s(col, bmCol);
}
spryscale += rw_scalestep;
}
}
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
}
// Loop through R_DrawMaskedColumn calls
static void R_DrawRepeatMaskedColumn(column_t *col)
static void R_DrawRepeatMaskedColumn(column_t *col, column_t *bm)
{
while (sprtopscreen < sprbotscreen) {
R_DrawMaskedColumn(col);
R_DrawMaskedColumn(col, bm);
if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
sprtopscreen = INT32_MAX;
else
@ -555,10 +582,10 @@ static void R_DrawRepeatMaskedColumn(column_t *col)
}
}
static void R_DrawRepeatFlippedMaskedColumn(column_t *col)
static void R_DrawRepeatFlippedMaskedColumn(column_t *col, column_t *bm)
{
do {
R_DrawFlippedMaskedColumn(col);
R_DrawFlippedMaskedColumn(col, bm);
sprtopscreen += dc_texheight*spryscale;
} while (sprtopscreen < sprbotscreen);
}
@ -582,9 +609,9 @@ static boolean R_IsFFloorTranslucent(visffloor_t *pfloor)
void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{
size_t pindex;
column_t * col;
column_t * col, *bmCol = NULL;
INT32 lightnum;
INT32 texnum;
INT32 texnum, bmnum;
sector_t tempsec;
INT32 templight;
INT32 i, p;
@ -605,7 +632,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
fixed_t left_top, left_bottom; // needed here for slope skewing
pslope_t *skewslope = NULL;
void (*colfunc_2s) (column_t *);
void (*colfunc_2s) (column_t *, column_t *);
// Calculate light table.
// Use different light tables
@ -616,14 +643,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
bmnum = R_GetTextureBrightmap(texnum);
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, bmnum != 0);
if (pfloor->master->flags & ML_TFERLINE)
{
size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum;
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
bmnum = R_GetTextureBrightmap(texnum);
}
if (pfloor->flags & FF_TRANSLUCENT)
@ -641,10 +670,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
}
if (fuzzy)
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
{
R_SetColumnFunc(COLDRAWFUNC_FUZZY, bmnum != 0);
}
}
else if (pfloor->flags & FF_FOG)
colfunc = colfuncs[COLDRAWFUNC_FOG];
{
R_SetColumnFunc(COLDRAWFUNC_FOG, bmnum != 0);
}
range = max(ds->x2-ds->x1, 1);
//SoM: Moved these up here so they are available for my lightlist calculations
@ -752,7 +785,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
else if (pfloor->flags & FF_FOG)
lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
else if (R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == true)
lightnum = LIGHTLEVELS-1;
else
lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)
@ -833,6 +866,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
if (bmnum) { R_CheckTextureCache(bmnum); }
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes)
@ -916,6 +951,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// Get data for the column
col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3);
if (bmnum) { bmCol = (column_t *)((UINT8 *)R_GetColumn(bmnum, maskedtexturecol[dc_x]) - 3); }
// SoM: New code does not rely on R_DrawColumnShadowed_8 which
// will (hopefully) put less strain on the stack.
@ -998,8 +1034,12 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (lighteffect)
{
dc_colormap = rlight->rcolormap;
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
}
if (solid && windowtop < bheight)
windowtop = bheight;
@ -1011,7 +1051,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{
windowbottom = sprbotscreen;
// draw the texture
colfunc_2s (col);
colfunc_2s (col, bmCol);
for (i++; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
@ -1022,7 +1062,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
continue;
}
// draw the texture
colfunc_2s (col);
colfunc_2s (col, bmCol);
if (solid)
windowtop = bheight;
else
@ -1030,14 +1070,18 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (lighteffect)
{
dc_colormap = rlight->rcolormap;
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
}
}
windowbottom = sprbotscreen;
// draw the texture, if there is any space left
if (windowtop < windowbottom)
colfunc_2s (col);
colfunc_2s (col, bmCol);
spryscale += rw_scalestep;
continue;
@ -1050,9 +1094,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
pindex = MAXLIGHTSCALE - 1;
dc_colormap = walllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap)
dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
@ -1060,11 +1108,12 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps);
// draw the texture
colfunc_2s (col);
colfunc_2s (col, bmCol);
spryscale += rw_scalestep;
}
}
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
#undef CLAMPMAX
#undef CLAMPMIN
@ -1311,8 +1360,12 @@ static void R_RenderSegLoop (void)
pindex = MAXLIGHTSCALE-1;
dc_colormap = walllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
dc_x = rw_x;
dc_iscale = 0xffffffffu / (unsigned)rw_scale;
@ -1350,7 +1403,7 @@ static void R_RenderSegLoop (void)
else
dc_lightlist[i].rcolormap = xwalllights[pindex];
colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
R_SetColumnFunc(COLDRAWFUNC_SHADOWED, false);
}
}
@ -1366,8 +1419,11 @@ static void R_RenderSegLoop (void)
dc_yh = yh;
dc_texturemid = rw_midtexturemid;
dc_source = R_GetColumn(midtexture,texturecolumn);
dc_brightmap = (midbrightmap ? R_GetColumn(midbrightmap, texturecolumn) : NULL);
dc_texheight = textureheight[midtexture]>>FRACBITS;
R_SetColumnFunc(colfunctype, dc_brightmap != NULL);
//profile stuff ---------------------------------------------------------
#ifdef TIMING
ProfZeroTimer();
@ -1427,7 +1483,9 @@ static void R_RenderSegLoop (void)
dc_yh = mid;
dc_texturemid = rw_toptexturemid;
dc_source = R_GetColumn(toptexture,texturecolumn);
dc_brightmap = (topbrightmap ? R_GetColumn(topbrightmap, texturecolumn) : NULL);
dc_texheight = textureheight[toptexture]>>FRACBITS;
R_SetColumnFunc(colfunctype, dc_brightmap != NULL);
colfunc();
ceilingclip[rw_x] = (INT16)mid;
}
@ -1462,9 +1520,10 @@ static void R_RenderSegLoop (void)
dc_yl = mid;
dc_yh = yh;
dc_texturemid = rw_bottomtexturemid;
dc_source = R_GetColumn(bottomtexture,
texturecolumn);
dc_source = R_GetColumn(bottomtexture,texturecolumn);
dc_brightmap = (bottombrightmap ? R_GetColumn(bottombrightmap, texturecolumn) : NULL);
dc_texheight = textureheight[bottomtexture]>>FRACBITS;
R_SetColumnFunc(colfunctype, dc_brightmap != NULL);
colfunc();
floorclip[rw_x] = (INT16)mid;
}
@ -1558,7 +1617,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
memset(&segleft, 0x00, sizeof(segleft));
memset(&segright, 0x00, sizeof(segright));
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
if (ds_p == drawsegs+maxdrawsegs)
{
@ -1738,6 +1797,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
worldbottomslope -= viewz;
midtexture = toptexture = bottomtexture = maskedtexture = 0;
midbrightmap = topbrightmap = bottombrightmap = 0;
ds_p->maskedtexturecol = NULL;
ds_p->numthicksides = numthicksides = 0;
ds_p->thicksidecol = NULL;
@ -1785,6 +1845,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
fixed_t texheight;
// single sided line
midtexture = R_GetTextureNum(sidedef->midtexture);
midbrightmap = R_GetTextureBrightmap(midtexture);
texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
@ -2021,11 +2082,14 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (!toptexture) //Second side has no texture, use the first side's instead.
toptexture = R_GetTextureNum(sidedef->toptexture);
topbrightmap = R_GetTextureBrightmap(toptexture);
texheight = textureheight[toptexture];
}
else
{
toptexture = R_GetTextureNum(sidedef->toptexture);
topbrightmap = R_GetTextureBrightmap(toptexture);
texheight = textureheight[toptexture];
}
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@ -2052,6 +2116,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
{
// bottom texture
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
bottombrightmap = R_GetTextureBrightmap(bottomtexture);
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGBOTTOM)
@ -2772,7 +2837,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
rw_bsilheight = &(ds_p->bsilheight);
R_RenderSegLoop();
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
if (portalline) // if curline is a portal, set portalrender for drawseg
ds_p->portalpass = portalrender+1;

View file

@ -311,11 +311,6 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
}
player->skincolor = newcolor = skin->prefcolor;
if (player->bot && botingame)
{
botskin = (UINT8)(skinnum + 1);
botcolor = skin->prefcolor;
}
}
#endif

View file

@ -444,6 +444,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
}
ds_colormap = vis->colormap;
ds_fullbright = colormaps;
ds_translation = R_GetSpriteTranslation(vis);
if (ds_translation == NULL)
ds_translation = colormaps;
@ -468,10 +469,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
else
ds_transmap = NULL;
if (ds_powersoftwo)
spanfunc = spanfuncs[spanfunctype];
else
spanfunc = spanfuncs_npo2[spanfunctype];
R_SetSpanFunc(spanfunctype, !ds_powersoftwo, false);
if (maxy >= vid.height)
maxy = vid.height-1;

View file

@ -54,6 +54,9 @@ extern extracolormap_t *extra_colormaps;
// for global animation
extern INT32 *texturetranslation;
// for brightmaps
extern INT32 *texturebrightmaps;
// Sprites
extern size_t numspritelumps, max_spritelumps;
@ -93,7 +96,7 @@ extern side_t *spawnsides;
// POV data.
//
extern fixed_t viewx, viewy, viewz;
extern angle_t viewangle, aimingangle;
extern angle_t viewangle, aimingangle, viewroll;
extern UINT8 viewssnum; // splitscreen view number
extern boolean viewsky, skyVisible;
extern boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisible of each splitscreen player

View file

@ -55,6 +55,7 @@ INT32 *texturewidth;
fixed_t *textureheight; // needed for texture pegging
INT32 *texturetranslation;
INT32 *texturebrightmaps;
// Painfully simple texture id cacheing to make maps load faster. :3
static struct {
@ -500,6 +501,20 @@ INT32 R_GetTextureNum(INT32 texnum)
return texturetranslation[texnum];
}
//
// R_GetTextureBrightmap
//
// Returns the actual texture id that we should use.
// This can either be the texture's brightmap,
// or 0 if not valid.
//
INT32 R_GetTextureBrightmap(INT32 texnum)
{
if (texnum < 0 || texnum >= numtextures)
return 0;
return texturebrightmaps[texnum];
}
//
// R_CheckTextureCache
//
@ -725,6 +740,7 @@ Rloadflats (INT32 i, INT32 w)
UINT16 texstart, texend;
texture_t *texture;
texpatch_t *patch;
UINT8 header[PNG_HEADER_SIZE];
// Yes
if (wadfiles[w]->type == RET_PK3)
@ -743,7 +759,6 @@ Rloadflats (INT32 i, INT32 w)
// Work through each lump between the markers in the WAD.
for (j = 0; j < (texend - texstart); j++)
{
UINT8 *flatlump;
UINT16 wadnum = (UINT16)w;
lumpnum_t lumpnum = texstart + j;
size_t lumplength;
@ -755,7 +770,7 @@ Rloadflats (INT32 i, INT32 w)
continue; // If it is then SKIP IT
}
flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0);
lumplength = W_LumpLengthPwad(wadnum, lumpnum);
switch (lumplength)
@ -790,12 +805,14 @@ Rloadflats (INT32 i, INT32 w)
M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength))
if (Picture_IsLumpPNG(header, lumplength))
{
UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
INT32 width, height;
Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, NULL, NULL, lumplength);
texture->width = (INT16)width;
texture->height = (INT16)height;
Z_Free(flatlump);
}
else
#endif
@ -814,8 +831,6 @@ Rloadflats (INT32 i, INT32 w)
patch->lump = texstart + j;
patch->flip = 0;
Z_Unlock(flatlump);
texturewidth[i] = texture->width;
textureheight[i] = texture->height << FRACBITS;
i++;
@ -835,8 +850,8 @@ Rloadtextures (INT32 i, INT32 w)
UINT16 j;
UINT16 texstart, texend, texturesLumpPos;
texture_t *texture;
softwarepatch_t *patchlump;
texpatch_t *patch;
softwarepatch_t patchlump;
// Get the lump numbers for the markers in the WAD, if they exist.
if (wadfiles[w]->type == RET_PK3)
@ -876,7 +891,7 @@ Rloadtextures (INT32 i, INT32 w)
continue; // If it is then SKIP IT
}
patchlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
W_ReadLumpHeaderPwad(wadnum, lumpnum, &patchlump, PNG_HEADER_SIZE, 0);
#ifndef NO_PNG_LUMPS
lumplength = W_LumpLengthPwad(wadnum, lumpnum);
#endif
@ -888,18 +903,20 @@ Rloadtextures (INT32 i, INT32 w)
M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength))
if (Picture_IsLumpPNG((UINT8 *)&patchlump, lumplength))
{
UINT8 *png = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
INT32 width, height;
Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, NULL, NULL, lumplength);
Picture_PNGDimensions(png, &width, &height, NULL, NULL, lumplength);
texture->width = (INT16)width;
texture->height = (INT16)height;
Z_Free(png);
}
else
#endif
{
texture->width = SHORT(patchlump->width);
texture->height = SHORT(patchlump->height);
texture->width = SHORT(patchlump.width);
texture->height = SHORT(patchlump.height);
}
texture->type = TEXTURETYPE_SINGLEPATCH;
@ -915,8 +932,6 @@ Rloadtextures (INT32 i, INT32 w)
patch->lump = texstart + j;
patch->flip = 0;
Z_Unlock(patchlump);
texturewidth[i] = texture->width;
textureheight[i] = texture->height << FRACBITS;
i++;
@ -944,6 +959,7 @@ void R_LoadTextures(void)
Z_Free(textures[i]);
Z_Free(texturecache[i]);
}
Z_Free(texturebrightmaps);
Z_Free(texturetranslation);
Z_Free(textures);
}
@ -1044,9 +1060,14 @@ void R_LoadTextures(void)
textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4));
// Create translation table for global animation.
texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL);
// Create brightmap texture table.
texturebrightmaps = Z_Malloc((numtextures + 1) * sizeof(*texturebrightmaps), PU_STATIC, NULL);
for (i = 0; i < numtextures; i++)
{
texturetranslation[i] = i;
texturebrightmaps[i] = 0;
}
for (i = 0, w = 0; w < numwadfiles; w++)
{

View file

@ -82,6 +82,7 @@ void R_FlushTextureCache(void);
UINT8 *R_GenerateTexture(size_t texnum);
UINT8 *R_GenerateTextureAsFlat(size_t texnum);
INT32 R_GetTextureNum(INT32 texnum);
INT32 R_GetTextureBrightmap(INT32 texnum);
void R_CheckTextureCache(INT32 tex);
void R_ClearTextureNumCache(boolean btell);

View file

@ -35,7 +35,6 @@
#include "p_slopes.h"
#include "d_netfil.h" // blargh. for nameonly().
#include "m_cheat.h" // objectplace
#include "k_color.h" // SRB2kart
#include "p_local.h" // stplyr
#ifdef HWRENDER
#include "hardware/hw_md2.h"
@ -44,6 +43,10 @@
#include "hardware/hw_drv.h"
#endif
// SRB2kart
#include "k_color.h"
#include "k_kart.h" // HITLAGJITTERS
#define MINZ (FRACUNIT*4)
#define BASEYCENTER (BASEVIDHEIGHT/2)
@ -283,16 +286,18 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
#ifndef NO_PNG_LUMPS
{
softwarepatch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC);
UINT8 header[PNG_HEADER_SIZE];
size_t len = W_LumpLengthPwad(wadnum, l);
if (Picture_IsLumpPNG((UINT8 *)png, len))
W_ReadLumpHeaderPwad(wadnum, l, header, sizeof header, 0);
if (Picture_IsLumpPNG(header, len))
{
UINT8 *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC);
Picture_PNGDimensions((UINT8 *)png, &width, &height, &topoffset, &leftoffset, len);
isPNG = true;
Z_Free(png);
}
Z_Free(png);
}
if (!isPNG)
@ -599,7 +604,7 @@ INT16 *mceilingclip;
fixed_t spryscale = 0, sprtopscreen = 0, sprbotscreen = 0;
fixed_t windowtop = 0, windowbottom = 0;
void R_DrawMaskedColumn(column_t *column)
void R_DrawMaskedColumn(column_t *column, column_t *brightmap)
{
INT32 topscreen;
INT32 bottomscreen;
@ -608,6 +613,9 @@ void R_DrawMaskedColumn(column_t *column)
basetexturemid = dc_texturemid;
R_SetColumnFunc(colfunctype, brightmap != NULL);
dc_brightmap = NULL;
for (; column->topdelta != 0xff ;)
{
// calculate unclipped screen coordinates
@ -642,6 +650,11 @@ void R_DrawMaskedColumn(column_t *column)
if (dc_yl <= dc_yh && dc_yh > 0)
{
dc_source = (UINT8 *)column + 3;
if (brightmap != NULL)
{
dc_brightmap = (UINT8 *)brightmap + 3;
}
dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
// Drawn by R_DrawColumn.
@ -656,6 +669,10 @@ void R_DrawMaskedColumn(column_t *column)
#endif
}
column = (column_t *)((UINT8 *)column + column->length + 4);
if (brightmap != NULL)
{
brightmap = (column_t *)((UINT8 *)brightmap + brightmap->length + 4);
}
}
dc_texturemid = basetexturemid;
@ -663,7 +680,7 @@ void R_DrawMaskedColumn(column_t *column)
INT32 lengthcol; // column->length : for flipped column function pointers and multi-patch on 2sided wall = texture->height
void R_DrawFlippedMaskedColumn(column_t *column)
void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap)
{
INT32 topscreen;
INT32 bottomscreen;
@ -671,6 +688,9 @@ void R_DrawFlippedMaskedColumn(column_t *column)
INT32 topdelta, prevdelta = -1;
UINT8 *d,*s;
R_SetColumnFunc(colfunctype, brightmap != NULL);
dc_brightmap = NULL;
for (; column->topdelta != 0xff ;)
{
// calculate unclipped screen coordinates
@ -709,6 +729,14 @@ void R_DrawFlippedMaskedColumn(column_t *column)
dc_source = ZZ_Alloc(column->length);
for (s = (UINT8 *)column+2+column->length, d = dc_source; d < dc_source+column->length; --s)
*d++ = *s;
if (brightmap != NULL)
{
dc_brightmap = ZZ_Alloc(brightmap->length);
for (s = (UINT8 *)brightmap+2+brightmap->length, d = dc_brightmap; d < dc_brightmap+brightmap->length; --s)
*d++ = *s;
}
dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
// Still drawn by R_DrawColumn.
@ -721,6 +749,10 @@ void R_DrawFlippedMaskedColumn(column_t *column)
Z_Free(dc_source);
}
column = (column_t *)((UINT8 *)column + column->length + 4);
if (brightmap != NULL)
{
brightmap = (column_t *)((UINT8 *)brightmap + brightmap->length + 4);
}
}
dc_texturemid = basetexturemid;
@ -776,7 +808,7 @@ UINT8 *R_GetSpriteTranslation(vissprite_t *vis)
static void R_DrawVisSprite(vissprite_t *vis)
{
column_t *column;
void (*localcolfunc)(column_t *);
void (*localcolfunc)(column_t *, column_t *);
INT32 texturecolumn;
INT32 pwidth;
fixed_t frac;
@ -800,26 +832,27 @@ static void R_DrawVisSprite(vissprite_t *vis)
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto
}
colfunc = colfuncs[BASEDRAWFUNC]; // hack: this isn't resetting properly somewhere.
R_SetColumnFunc(BASEDRAWFUNC, false); // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap;
dc_fullbright = colormaps;
dc_translation = R_GetSpriteTranslation(vis);
if (R_SpriteIsFlashing(vis)) // Bosses "flash"
colfunc = colfuncs[COLDRAWFUNC_TRANS]; // translate certain pixels to white
R_SetColumnFunc(COLDRAWFUNC_TRANS, false); // translate certain pixels to white
else if (vis->mobj->color && vis->transmap) // Color mapping
{
colfunc = colfuncs[COLDRAWFUNC_TRANSTRANS];
R_SetColumnFunc(COLDRAWFUNC_TRANSTRANS, false);
dc_transmap = vis->transmap;
}
else if (vis->transmap)
{
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
R_SetColumnFunc(COLDRAWFUNC_FUZZY, false);
dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table
}
else if (vis->mobj->color) // translate green skin to another color
colfunc = colfuncs[COLDRAWFUNC_TRANS];
R_SetColumnFunc(COLDRAWFUNC_TRANS, false);
else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome.
colfunc = colfuncs[COLDRAWFUNC_TRANS];
R_SetColumnFunc(COLDRAWFUNC_TRANS, false);
if (vis->extra_colormap && !(vis->renderflags & RF_NOCOLORMAPS))
{
@ -831,8 +864,13 @@ static void R_DrawVisSprite(vissprite_t *vis)
if (!dc_colormap)
dc_colormap = colormaps;
dc_fullbright = colormaps;
if (encoremap && !vis->mobj->color && !(vis->mobj->flags & MF_DONTENCOREMAP))
dc_colormap += COLORMAP_REMAPOFFSET;
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
dc_texturemid = vis->texturemid;
dc_texheight = 0;
@ -905,7 +943,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn]));
localcolfunc (column);
localcolfunc (column, NULL);
}
}
else if (vis->cut & SC_SHEAR)
@ -927,7 +965,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
#endif
sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
localcolfunc (column);
localcolfunc (column, NULL);
}
}
else
@ -947,11 +985,11 @@ static void R_DrawVisSprite(vissprite_t *vis)
#else
column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS]));
#endif
localcolfunc (column);
localcolfunc (column, NULL);
}
}
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
dc_hires = 0;
vis->x1 = x1;
@ -981,13 +1019,17 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
if (vis->transmap)
{
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
R_SetColumnFunc(COLDRAWFUNC_FUZZY, false);
dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table
}
dc_colormap = colormaps;
dc_fullbright = colormaps;
if (encoremap)
{
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
dc_texturemid = vis->texturemid;
@ -1016,10 +1058,10 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
#else
column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS]));
#endif
R_DrawMaskedColumn(column);
R_DrawMaskedColumn(column, NULL);
}
colfunc = colfuncs[BASEDRAWFUNC];
R_SetColumnFunc(BASEDRAWFUNC, false);
}
//
@ -1431,31 +1473,29 @@ static void R_ProjectSprite(mobj_t *thing)
fixed_t interpx = thing->x;
fixed_t interpy = thing->y;
fixed_t interpz = thing->z;
angle_t interpangle = thing->angle;
// use player drawangle if player
if (thing->player) interpangle = thing->player->drawangle;
angle_t interpangle = (thing->player ? thing->player->drawangle : thing->angle);
// do interpolation
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x);
interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y);
interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z);
if (thing->player)
{
interpangle = thing->player->drawangle;
interpangle = thing->player->old_drawangle + FixedMul(rendertimefrac, thing->player->drawangle - thing->player->old_drawangle);
}
else
{
interpangle = thing->angle;
interpangle = thing->old_angle + FixedMul(rendertimefrac, thing->angle - thing->old_angle);
}
}
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
{
fixed_t mul = thing->hitlag * (FRACUNIT / 10);
fixed_t mul = thing->hitlag * HITLAGJITTERS;
if (leveltime & 1)
{
@ -1777,7 +1817,7 @@ static void R_ProjectSprite(mobj_t *thing)
fixed_t linkscale;
thing = thing->tracer;
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = thing->old_x + FixedMul(thing->x - thing->old_x, rendertimefrac);
interpy = thing->old_y + FixedMul(thing->y - thing->old_y, rendertimefrac);
@ -2126,7 +2166,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
fixed_t interpz = thing->z;
// do interpolation
if (cv_frameinterpolation.value == 1 && !paused)
if (cv_frameinterpolation.value == 1)
{
interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x);
interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y);

View file

@ -47,8 +47,8 @@ extern fixed_t windowtop;
extern fixed_t windowbottom;
extern INT32 lengthcol;
void R_DrawMaskedColumn(column_t *column);
void R_DrawFlippedMaskedColumn(column_t *column);
void R_DrawMaskedColumn(column_t *column, column_t *brightmap);
void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap);
// ----------------
// SPRITE RENDERING

View file

@ -49,10 +49,17 @@
// --------------------------------------------
void (*colfunc)(void);
void (*colfuncs[COLDRAWFUNC_MAX])(void);
#ifdef USE_COL_SPAN_ASM
void (*colfuncs_asm[COLDRAWFUNC_MAX])(void);
#endif
int colfunctype;
void (*spanfunc)(void);
void (*spanfuncs[SPANDRAWFUNC_MAX])(void);
void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
#ifdef USE_COL_SPAN_ASM
void (*spanfuncs_asm[SPANDRAWFUNC_MAX])(void);
#endif
// ------------------
// global video state
@ -118,9 +125,6 @@ void SCR_SetDrawFuncs(void)
colfuncs[BASEDRAWFUNC] = R_DrawColumn_8;
spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8;
colfunc = colfuncs[BASEDRAWFUNC];
spanfunc = spanfuncs[BASEDRAWFUNC];
colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8;
colfuncs[COLDRAWFUNC_TRANS] = R_DrawTranslatedColumn_8;
colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8;
@ -160,26 +164,29 @@ void SCR_SetDrawFuncs(void)
spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8;
spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed
#ifdef RUSEASM
#if (defined(RUSEASM) && defined(USE_COL_SPAN_ASM))
if (R_ASM)
{
if (R_MMX)
{
colfuncs[BASEDRAWFUNC] = R_DrawColumn_8_MMX;
//colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
//colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_MMX;
spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8_MMX;
colfuncs_asm[BASEDRAWFUNC] = R_DrawColumn_8_MMX;
//colfuncs_asm[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
//colfuncs_asm[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
colfuncs_asm[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_MMX;
spanfuncs_asm[BASEDRAWFUNC] = R_DrawSpan_8_MMX;
}
else
{
colfuncs[BASEDRAWFUNC] = R_DrawColumn_8_ASM;
//colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
//colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_ASM;
colfuncs_asm[BASEDRAWFUNC] = R_DrawColumn_8_ASM;
//colfuncs_asm[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM;
//colfuncs_asm[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM;
colfuncs_asm[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_ASM;
}
}
#endif
R_SetColumnFunc(BASEDRAWFUNC, false);
R_SetSpanFunc(BASEDRAWFUNC, false, false);
}
/* else if (vid.bpp > 1)
{
@ -201,6 +208,65 @@ void SCR_SetDrawFuncs(void)
*/
}
void R_SetColumnFunc(size_t id, boolean brightmapped)
{
I_Assert(id < COLDRAWFUNC_MAX);
colfunctype = id;
#ifdef USE_COL_SPAN_ASM
if (colfuncs_asm[id] != NULL && brightmapped == false)
{
colfunc = colfuncs_asm[id];
}
else
#endif
{
colfunc = colfuncs[id];
}
}
void R_SetSpanFunc(size_t id, boolean npo2, boolean brightmapped)
{
I_Assert(id < COLDRAWFUNC_MAX);
if (spanfuncs_npo2[id] != NULL && npo2 == true)
{
spanfunc = spanfuncs_npo2[id];
}
#ifdef USE_COL_SPAN_ASM
else if (spanfuncs_asm[id] != NULL && brightmapped == false)
{
spanfunc = spanfuncs_asm[id];
}
#endif
else
{
spanfunc = spanfuncs[id];
}
}
boolean R_CheckColumnFunc(size_t id)
{
size_t i;
if (colfunc == NULL)
{
// Shouldn't happen.
return false;
}
for (i = 0; i < COLDRAWFUNC_MAX; i++)
{
if (colfunc == colfuncs[id] || colfunc == colfuncs_asm[id])
{
return true;
}
}
return false;
}
void SCR_SetMode(void)
{
if (dedicated)
@ -447,9 +513,46 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
// XMOD FPS display
// moved out of os-specific code for consistency
static boolean fpsgraph[TICRATE];
static boolean ticsgraph[TICRATE];
static tic_t lasttic;
static UINT32 fpstime = 0;
static UINT32 lastupdatetime = 0;
#define FPSUPDATERATE 1/20 // What fraction of a second to update at. The fraction will not simplify to 0, trust me.
#define FPSMAXSAMPLES 16
static UINT32 fpssamples[FPSMAXSAMPLES];
static UINT32 fpssampleslen = 0;
static UINT32 fpssum = 0;
double aproxfps = 0.0f;
void SCR_CalcAproxFps(void)
{
tic_t i = 0;
if (I_PreciseToMicros(fpstime - lastupdatetime) > 1000000 * FPSUPDATERATE)
{
if (fpssampleslen == FPSMAXSAMPLES)
{
fpssum -= fpssamples[0];
for (i = 1; i < fpssampleslen; i++)
fpssamples[i-1] = fpssamples[i];
}
else
fpssampleslen++;
fpssamples[fpssampleslen-1] = I_GetPreciseTime() - fpstime;
fpssum += fpssamples[fpssampleslen-1];
aproxfps = 1000000 / (I_PreciseToMicros(fpssum) / (double)fpssampleslen);
lastupdatetime = I_GetPreciseTime();
}
fpstime = I_GetPreciseTime();
}
void SCR_DisplayTicRate(void)
{
tic_t i;
@ -458,25 +561,51 @@ void SCR_DisplayTicRate(void)
const UINT8 *ticcntcolor = NULL;
for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i)
fpsgraph[i % TICRATE] = false;
ticsgraph[i % TICRATE] = false;
fpsgraph[ontic % TICRATE] = true;
ticsgraph[ontic % TICRATE] = true;
for (i = 0;i < TICRATE;++i)
if (fpsgraph[i])
if (ticsgraph[i])
++totaltics;
if (totaltics <= TICRATE/2) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
else if (totaltics == TICRATE) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE);
// draw "FPS"
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
// draw total frame:
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, TICRATE, ticcntcolor);
// draw "/"
V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
// draw our actual framerate
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, totaltics, ticcntcolor);
if (cv_frameinterpolation.value == 1)
{
if (aproxfps <= 15.0f) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
else if (aproxfps >= 60.0f) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE);
/*
if (cv_fpscap.value != 0)
{
// draw total frame:
//V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, cv_fpscap.value, ticcntcolor);
// draw "/"
//V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
// draw our actual framerate
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, aproxfps, ticcntcolor);
}
else
*/
{
// draw our actual framerate
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, aproxfps, ticcntcolor);
}
}
else
{
if (totaltics <= 15) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
else if (totaltics >= TICRATE) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE);
// draw total frame:
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, TICRATE, ticcntcolor);
// draw "/"
V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
// draw our actual framerate
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, totaltics, ticcntcolor);
}
lasttic = ontic;

View file

@ -116,6 +116,8 @@ extern vmode_t specialmodes[NUMSPECIALMODES];
// color mode dependent drawer function pointers
// ---------------------------------------------
#define USE_COL_SPAN_ASM 0
#define BASEDRAWFUNC 0
enum
@ -135,6 +137,10 @@ enum
extern void (*colfunc)(void);
extern void (*colfuncs[COLDRAWFUNC_MAX])(void);
#ifdef USE_COL_SPAN_ASM
extern void (*colfuncs_asm[COLDRAWFUNC_MAX])(void);
#endif
extern int colfunctype;
enum
{
@ -163,6 +169,9 @@ enum
extern void (*spanfunc)(void);
extern void (*spanfuncs[SPANDRAWFUNC_MAX])(void);
extern void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
#ifdef USE_COL_SPAN_ASM
extern void (*spanfuncs_asm[SPANDRAWFUNC_MAX])(void);
#endif
// -----
// CPUID
@ -181,6 +190,7 @@ extern boolean R_SSE2;
extern viddef_t vid;
extern INT32 setmodeneeded; // mode number to set if needed, or 0
extern UINT8 setrenderneeded;
extern double aproxfps;
void SCR_ChangeRenderer(void);
@ -204,6 +214,13 @@ void SCR_SetMode(void);
// Set drawer functions for Software
void SCR_SetDrawFuncs(void);
// Set current column / span drawers
void R_SetColumnFunc(size_t id, boolean brightmapped);
void R_SetSpanFunc(size_t id, boolean npo2, boolean brightmapped);
// Compare current column drawer
boolean R_CheckColumnFunc(size_t id);
// Recalc screen size dependent stuff
void SCR_Recalc(void);
@ -213,6 +230,8 @@ void SCR_CheckDefaultMode(void);
// Set the mode number which is saved in the config
void SCR_SetDefaultMode(void);
void SCR_CalcAproxFps(void);
FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
// move out to main code for consistency

View file

@ -1216,6 +1216,8 @@ void I_FinishUpdate(void)
if (I_SkipFrame())
return;
SCR_CalcAproxFps();
if (st_overlay)
{
if (cv_ticrate.value)

View file

@ -1480,10 +1480,10 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
int zErr; // Helper var.
z_stream strm;
unsigned long rawSize = l->disksize;
unsigned long decSize = l->size;
unsigned long decSize = size;
rawData = Z_Malloc(rawSize, PU_STATIC, NULL);
decData = Z_Malloc(decSize, PU_STATIC, NULL);
decData = dest;
if (fread(rawData, 1, rawSize, handle) < rawSize)
I_Error("wad %d, lump %d: cannot read compressed data", wad, lump);
@ -1501,12 +1501,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
zErr = inflateInit2(&strm, -15);
if (zErr == Z_OK)
{
zErr = inflate(&strm, Z_FINISH);
if (zErr == Z_STREAM_END)
{
M_Memcpy(dest, decData, size);
}
else
zErr = inflate(&strm, Z_SYNC_FLUSH);
if (zErr != Z_OK && zErr != Z_STREAM_END)
{
size = 0;
zerr(zErr);
@ -1520,7 +1516,6 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
}
Z_Free(rawData);
Z_Free(decData);
#ifdef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)dest, size))

View file

@ -1322,7 +1322,7 @@ static void Y_VoteStops(SINT8 pick, SINT8 level)
if (gametype != votelevels[level][1])
{
INT16 lastgametype = gametype;
gametype = votelevels[level][1];
G_SetGametype(votelevels[level][1]);
D_GameTypeChanged(lastgametype);
forceresetplayers = true;
}