Merge branch 'master' into spd

This commit is contained in:
toaster 2019-11-29 19:19:55 +00:00
commit de34298bbd
71 changed files with 2949 additions and 1271 deletions

View File

@ -3,6 +3,7 @@
For Sonic Robo Blast 2 Version 2.2
Contributors (alphabetical):
* Foxboy
* FuriousFox
* JJames19119
* Kalaron
* Kristos
@ -44,27 +45,32 @@ formatinterface = "SRB2MapSetIO";
//Sky textures for vanilla maps
defaultskytextures
{
SKY1 = "MAP01,MAP02,MAP03,MAP50,MAPA1,MAPA2,MAPA5,MAPA6,MAPA9,MAPAA,MAPAB,MAPAC,MAPAD,MAPAE,MAPAG,MAPAJ,MAPAK,MAPF0,MAPF1,MAPFA,MAPM0,MAPM8,MAPMA,MAPMB,MAPMC";
SKY4 = "MAP04,MAP06,MAP51,MAPF8,MAPM1";
SKY6 = "MAP05";
SKY7 = "MAP07,MAP08,MAP09,MAP52,MAPM2,MAPM5";
SKY10 = "MAP12,MAP53,MAPM3";
SKY11 = "MAP10,MAP11,MAP16,MAP55,MAPF2,MAPF5,MAPF6,MAPF9,MAPM7";
SKY13 = "MAP13,MAP54,MAPAS";
SKY21 = "MAPAF,MAPF7,MAPM4";
SKY22 = "MAP22,MAP23,MAP24,MAP25,MAP56,MAPAN,MAPAO,MAPF4,MAPM6";
SKY29 = "MAP58,MAPAV";
SKY1 = "MAP01,MAP02,MAP03,MAP33,MAP50,MAP60,MAPF0,MAPM0";
SKY2 = "MAPM7,MAPMB";
SKY4 = "MAP04,MAP06,MAP61,MAPF6,MAPM1";
SKY6 = "MAP05,MAP51,MAPMA";
SKY7 = "MAPM2,MAPM5";
SKY8 = "MAP07,MAP08,MAP09,MAP52,MAP62,MAPF1";
SKY10 = "MAP10,MAP12,MAP53,MAP63,MAPM3";
SKY11 = "MAP11,MAPF7";
SKY13 = "MAP13,MAP64";
SKY14 = "MAP14";
SKY15 = "MAP15,MAP54";
SKY17 = "MAP70";
SKY20 = "MAP32,MAP55,MAP65,MAPF2,MAPF5";
SKY21 = "MAPM4";
SKY22 = "MAP22,MAP23,MAP25,MAP26,MAP27,MAP56,MAP66,MAPF4,MAPM6";
SKY30 = "MAP30";
SKY35 = "MAP41";
SKY40 = "MAP40";
SKY55 = "MAPF3,MAPM9";
SKY66 = "MAPAT";
SKY99 = "MAP57";
SKY103 = "MAPA3,MAPA4,MAPAU";
SKY107 = "MAPA7,MAPA8";
SKY117 = "MAPAH,MAPAI";
SKY127 = "MAPAR";
SKY132 = "MAPAW";
SKY31 = "MAP31";
SKY35 = "MAP42";
SKY40 = "MAP41,MAP71,MAPM9";
SKY55 = "MAPF3,MAPM8";
SKY68 = "MAPF8";
SKY99 = "MAP57,MAPZ0";
SKY159 = "MAP16";
SKY172 = "MAP40";
SKY300 = "MAP72";
SKY301 = "MAP73";
}
// Default lump name for new map
@ -90,9 +96,9 @@ skins
Sonic;
Tails;
Knuckles;
Metalsonic;
Fang;
Amy;
Fang;
Metalsonic;
}
// Gametypes
@ -3422,7 +3428,7 @@ thingtypes
121
{
title = "Minus";
sprite = "MNUSA1";
sprite = "MNUSA0";
width = 24;
height = 32;
}
@ -3457,6 +3463,13 @@ thingtypes
height = 34;
flags8text = "[8] Start on fire";
}
137
{
title = "Dragonbomber";
sprite = "DRABA1";
width = 28;
height = 48;
}
105
{
title = "Jetty-Syn Bomber";
@ -5726,6 +5739,24 @@ thingtypes
width = 24;
height = 32;
}
1505
{
title = "Green Flame";
sprite = "CFLMA0E0";
width = 8;
height = 32;
}
1506
{
arrow = 1;
blocking = 2;
title = "Blue Gargoyle";
sprite = "BGARD1";
width = 16;
height = 40;
flags4text = "[4] Slides when pushed";
flags8text = "[8] Not pushable";
}
}
dreamhill

View File

@ -24,12 +24,47 @@ static boolean lastForward = false;
static boolean lastBlocked = false;
static boolean blocked = false;
static boolean jump_last = false;
static boolean spin_last = false;
static UINT8 anxiety = 0;
static boolean panic = false;
static UINT8 flymode = 0;
static boolean spinmode = false;
static boolean thinkfly = false;
static inline void B_ResetAI(void)
{
jump_last = false;
spin_last = false;
anxiety = 0;
panic = false;
flymode = 0;
spinmode = false;
thinkfly = false;
}
static inline void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
{
boolean forward=false, backward=false, left=false, right=false, jump=false, spin=false;
angle_t angle;
INT16 rangle;
fixed_t dist;
player_t *player = sonic->player, *bot = tails->player;
ticcmd_t *pcmd = &player->cmd;
boolean water = tails->eflags & MFE_UNDERWATER;
SINT8 flip = P_MobjFlip(tails);
boolean _2d = (tails->flags2 & MF2_TWOD) || twodlevel;
fixed_t scale = tails->scale;
fixed_t dist = P_AproxDistance(sonic->x - tails->x, sonic->y - tails->y);
fixed_t zdist = flip * (sonic->z - tails->z);
angle_t ang = R_PointToAngle2(tails->x, tails->y, sonic->x, sonic->y);
fixed_t pmom = P_AproxDistance(sonic->momx, sonic->momy);
fixed_t bmom = P_AproxDistance(tails->momx, tails->momy);
fixed_t followmax = 128 * 8 * scale; // Max follow distance before AI begins to enter "panic" state
fixed_t followthres = 92 * scale; // Distance that AI will try to reach
fixed_t followmin = 32 * scale;
fixed_t comfortheight = 96 * scale;
fixed_t touchdist = 24 * scale;
boolean stalled = (bmom < scale >> 1) && dist > followthres; // Helps to see if the AI is having trouble catching up
// We can't follow Sonic if he's not around!
if (!sonic || sonic->health <= 0)
@ -58,46 +93,263 @@ static inline void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cm
return;
}
// Gather data about the environment
dist = P_AproxDistance(tails->x-sonic->x, tails->y-sonic->y);
if (tails->player->pflags & PF_STARTDASH)
angle = sonic->angle;
// Adapted from CobaltBW's tails_AI.wad
// Check water
if (water)
{
followmin = 0;
followthres = 16*scale;
followmax >>= 1;
thinkfly = false;
}
// Check anxiety
if (spinmode)
{
anxiety = 0;
panic = false;
}
else if (dist > followmax || zdist > comfortheight || stalled)
{
anxiety = min(anxiety + 2, 70);
if (anxiety >= 70)
panic = true;
}
else
angle = R_PointToAngle2(tails->x, tails->y, sonic->x, sonic->y);
// Decide which direction to turn
angle = (tails->angle - angle);
if (angle < ANGLE_180) {
right = true; // We need to turn right
rangle = AngleFixed(angle)>>FRACBITS;
} else {
left = true; // We need to turn left
rangle = 360-(AngleFixed(angle)>>FRACBITS);
{
anxiety = max(anxiety - 1, 0);
panic = false;
}
// Decide to move forward if you're finished turning
if (abs(rangle) < 10) { // We're facing the right way?
left = right = false; // Stop turning
forward = true; // and walk forward instead.
// Orientation
if ((bot->pflags & (PF_SPINNING|PF_STARTDASH)) || flymode == 2)
{
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
}
else
{
cmd->angleturn = (ang - tails->angle) >> FRACBITS;
}
if (dist < (sonic->radius+tails->radius)*3) // We're close enough?
forward = false; // Stop walking.
// Decide when to jump
if (!(tails->player->pflags & (PF_JUMPED|PF_JUMPDOWN))) { // We're not jumping yet...
if (forward && lastForward && blocked && lastBlocked) // We've been stopped by a wall or something
jump = true; // Try to jump up
} else if ((tails->player->pflags & (PF_JUMPDOWN|PF_JUMPED)) == (PF_JUMPDOWN|PF_JUMPED)) { // When we're already jumping...
if (lastForward && blocked) // We're still stuck on something?
// ********
// FLY MODE
// spinmode check
if (spinmode || player->exiting)
thinkfly = false;
else
{
// Activate co-op flight
if (thinkfly && player->pflags & PF_JUMPED)
{
if (!jump_last)
{
jump = true;
flymode = 1;
thinkfly = false;
bot->pflags |= PF_CANCARRY;
}
}
// Check positioning
// Thinker for co-op flight
if (!(water || pmom || bmom)
&& (dist < touchdist)
&& !(pcmd->forwardmove || pcmd->sidemove || player->dashspeed)
&& P_IsObjectOnGround(sonic) && P_IsObjectOnGround(tails)
&& !(player->pflags & PF_STASIS)
&& bot->charability == CA_FLY)
thinkfly = true;
else
thinkfly = false;
// Ready for takeoff
if (flymode == 1)
{
thinkfly = false;
if (zdist < -64*scale || (flip * tails->momz) > scale) // Make sure we're not too high up
spin = true;
else if (!jump_last)
jump = true;
// Abort if the player moves away or spins
if (dist > followthres || player->dashspeed)
flymode = 0;
// Set carried state
if (player->powers[pw_carry] == CR_PLAYER && sonic->tracer == tails)
{
flymode = 2;
}
}
// Read player inputs while carrying
else if (flymode == 2)
{
cmd->forwardmove = pcmd->forwardmove;
cmd->sidemove = pcmd->sidemove;
if (pcmd->buttons & BT_USE)
{
spin = true;
jump = false;
}
else if (!jump_last)
jump = true;
// End flymode
if (player->powers[pw_carry] != CR_PLAYER)
{
flymode = 0;
}
}
}
if (flymode && P_IsObjectOnGround(tails) && !(pcmd->buttons & BT_JUMP))
flymode = 0;
// ********
// SPINNING
if (panic || flymode || !(player->pflags & PF_SPINNING) || (player->pflags & PF_JUMPED))
spinmode = false;
else
{
if (!_2d)
{
// Spindash
if (player->dashspeed)
{
if (dist < followthres && dist > touchdist) // Do positioning
{
cmd->angleturn = (ang - tails->angle) >> FRACBITS;
cmd->forwardmove = 50;
spinmode = true;
}
else if (dist < touchdist)
{
if (!bmom && (!(bot->pflags & PF_SPINNING) || (bot->dashspeed && bot->pflags & PF_SPINNING)))
{
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
spin = true;
}
spinmode = true;
}
else
spinmode = false;
}
// Spin
else if (player->dashspeed == bot->dashspeed && player->pflags & PF_SPINNING)
{
if (bot->pflags & PF_SPINNING || !spin_last)
{
spin = true;
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
cmd->forwardmove = MAXPLMOVE;
spinmode = true;
}
else
spinmode = false;
}
}
// 2D mode
else
{
if (((player->dashspeed && !bmom) || (player->dashspeed == bot->dashspeed && (player->pflags & PF_SPINNING)))
&& ((bot->pflags & PF_SPINNING) || !spin_last))
{
spin = true;
spinmode = true;
}
}
}
// ********
// FOLLOW
if (!(flymode || spinmode))
{
// Too far
if (panic || dist > followthres)
{
if (!_2d)
cmd->forwardmove = MAXPLMOVE;
else if (sonic->x > tails->x)
cmd->sidemove = MAXPLMOVE;
else
cmd->sidemove = -MAXPLMOVE;
}
// Within threshold
else if (!panic && dist > followmin && abs(zdist) < 192*scale)
{
if (!_2d)
cmd->forwardmove = FixedHypot(pcmd->forwardmove, pcmd->sidemove);
else
cmd->sidemove = pcmd->sidemove;
}
// Below min
else if (dist < followmin)
{
// Copy inputs
cmd->angleturn = (sonic->angle - tails->angle) >> FRACBITS;
bot->drawangle = ang;
cmd->forwardmove = 8 * pcmd->forwardmove / 10;
cmd->sidemove = 8 * pcmd->sidemove / 10;
}
}
// ********
// JUMP
if (!(flymode || spinmode))
{
// Flying catch-up
if (bot->pflags & PF_THOKKED)
{
cmd->forwardmove = min(MAXPLMOVE, (dist/scale)>>3);
if (zdist < -64*scale)
spin = true;
else if (zdist > 0 && !jump_last)
jump = true;
}
// Just landed
if (tails->eflags & MFE_JUSTHITFLOOR)
jump = false;
// Start jump
else if (!jump_last && !(bot->pflags & PF_JUMPED) //&& !(player->pflags & PF_SPINNING)
&& ((zdist > 32*scale && player->pflags & PF_JUMPED) // Following
|| (zdist > 64*scale && panic) // Vertical catch-up
|| (stalled && anxiety > 20 && bot->powers[pw_carry] == CR_NONE)
//|| (bmom < scale>>3 && dist > followthres && !(bot->powers[pw_carry])) // Stopped & not in carry state
|| (bot->pflags & PF_SPINNING && !(bot->pflags & PF_JUMPED)))) // Spinning
jump = true;
// Hold jump
else if (bot->pflags & PF_JUMPED && jump_last && tails->momz*flip > 0 && (zdist > 0 || panic))
jump = true;
if (sonic->floorz > tails->floorz) // He's still above us? Jump HIGHER, then!
// Start flying
else if (bot->pflags & PF_JUMPED && panic && !jump_last && bot->charability == CA_FLY)
jump = true;
}
// Decide when to spin
if (sonic->player->pflags & PF_STARTDASH
&& (tails->player->pflags & PF_STARTDASH || (P_AproxDistance(tails->momx, tails->momy) < 2*FRACUNIT && !forward)))
spin = true;
// ********
// HISTORY
jump_last = jump;
spin_last = spin;
// ********
// Thinkfly overlay
if (thinkfly)
{
if (!tails->target)
{
P_SetTarget(&tails->target, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY));
if (tails->target)
{
P_SetTarget(&tails->target->target, tails);
P_SetMobjState(tails->target, S_FLIGHTINDICATOR);
}
}
}
else if (tails->target && tails->target->type == MT_OVERLAY && tails->target->state == states+S_FLIGHTINDICATOR)
{
P_RemoveMobj(tails->target);
P_SetTarget(&tails->target, NULL);
}
// Turn the virtual keypresses into ticcmd_t.
B_KeysToTiccmd(tails, cmd, forward, backward, left, right, false, false, jump, spin);
@ -141,7 +393,7 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin)
{
// don't try to do stuff if your sonic is in a minecart or something
if (players[consoleplayer].powers[pw_carry])
if (players[consoleplayer].powers[pw_carry] && players[consoleplayer].powers[pw_carry] != CR_PLAYER)
return;
// Turn the virtual keypresses into ticcmd_t.
if (twodlevel || mo->flags2 & MF2_TWOD) {
@ -179,6 +431,7 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
cmd->sidemove += MAXPLMOVE<<FRACBITS>>16;
}
} else {
angle_t angle;
if (forward)
cmd->forwardmove += MAXPLMOVE<<FRACBITS>>16;
if (backward)
@ -191,6 +444,15 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
cmd->sidemove -= MAXPLMOVE<<FRACBITS>>16;
if (straferight)
cmd->sidemove += MAXPLMOVE<<FRACBITS>>16;
// cap inputs so the bot can't accelerate faster diagonally
angle = R_PointToAngle2(0, 0, cmd->sidemove << FRACBITS, cmd->forwardmove << FRACBITS);
{
INT32 maxforward = abs(P_ReturnThrustY(NULL, angle, MAXPLMOVE));
INT32 maxside = abs(P_ReturnThrustX(NULL, angle, MAXPLMOVE));
cmd->forwardmove = max(min(cmd->forwardmove, maxforward), -maxforward);
cmd->sidemove = max(min(cmd->sidemove, maxside), -maxside);
}
}
if (jump)
cmd->buttons |= BT_JUMP;
@ -217,7 +479,7 @@ boolean B_CheckRespawn(player_t *player)
// If he's doing any of these things, he probably doesn't want to see us.
if (sonic->player->pflags & (PF_GLIDING|PF_SLIDING|PF_BOUNCING)
|| (sonic->player->panim != PA_IDLE && sonic->player->panim != PA_WALK)
|| (sonic->player->powers[pw_carry]))
|| (sonic->player->powers[pw_carry] && sonic->player->powers[pw_carry] != CR_PLAYER))
return false;
// Low ceiling, do not want!
@ -252,6 +514,8 @@ void B_RespawnBot(INT32 playernum)
if (!sonic || sonic->health <= 0)
return;
B_ResetAI();
player->bot = 1;
P_SpawnPlayer(playernum);
tails = player->mo;

View File

@ -90,6 +90,7 @@ SINT8 nodetoplayer[MAXNETNODES];
SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
tic_t servermaxping = 800; // server's max ping. Defaults to 800
static tic_t nettics[MAXNETNODES]; // what tic the client have received
static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet
static UINT8 nodewaiting[MAXNETNODES];
@ -610,6 +611,11 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->health = LONG(players[i].mo->health);
rsp->angle = (angle_t)LONG(players[i].mo->angle);
#ifdef ROTSPRITE
rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle);
#else
rsp->rollangle = 0;
#endif
rsp->x = LONG(players[i].mo->x);
rsp->y = LONG(players[i].mo->y);
rsp->z = LONG(players[i].mo->z);
@ -760,6 +766,9 @@ static void resynch_read_player(resynch_pak *rsp)
//At this point, the player should have a body, whether they were respawned or not.
P_UnsetThingPosition(players[i].mo);
players[i].mo->angle = (angle_t)LONG(rsp->angle);
#ifdef ROTSPRITE
players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle);
#endif
players[i].mo->eflags = (UINT16)SHORT(rsp->eflags);
players[i].mo->flags = LONG(rsp->flags);
players[i].mo->flags2 = LONG(rsp->flags2);
@ -1292,10 +1301,23 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, ""))
strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33);
if (*mapheaderinfo[gamemap-1]->lvlttl)
{
char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle;
while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0')
{
if (!(*read & 0x80))
{
*writ = toupper(*read);
writ++;
}
read++;
}
*writ = '\0';
//strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33);
}
else
strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 33);
strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32);
netbuffer->u.serverinfo.maptitle[32] = '\0';
@ -1349,7 +1371,11 @@ static void SV_SendPlayerInfo(INT32 node)
netbuffer->u.playerinfo[i].score = LONG(players[i].score);
netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE));
netbuffer->u.playerinfo[i].skin = (UINT8)players[i].skin;
netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin
#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself
% 3
#endif
);
// Extra data
netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor;
@ -1607,7 +1633,7 @@ static void CL_LoadReceivedSavegame(void)
{
CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
CONS_Printf(M_GetText(" ZONE"));
CONS_Printf(M_GetText(" Zone"));
if (actnum > 0)
CONS_Printf(" %2d", actnum);
}
@ -4208,10 +4234,12 @@ static void HandlePacketFromPlayer(SINT8 node)
//Update client ping table from the server.
if (client)
{
INT32 i;
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS];
}
break;
@ -4591,7 +4619,7 @@ static void Local_Maketic(INT32 realtics)
{
I_OsPolling(); // I_Getevent
D_ProcessEvents(); // menu responder, cons responder,
// game responder calls HU_Responder, AM_Responder, F_Responder,
// game responder calls HU_Responder, AM_Responder,
// and G_MapEventsToControls
if (!dedicated) rendergametic = gametic;
// translate inputs (keyboard/mouse/joystick) into game controls
@ -4733,6 +4761,14 @@ void TryRunTics(tic_t realtics)
}
}
/*
Ping Update except better:
We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out.
If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave.
*/
static INT32 pingtimeout[MAXPLAYERS];
static inline void PingUpdate(void)
{
INT32 i;
@ -4753,6 +4789,8 @@ static inline void PingUpdate(void)
laggers[i] = true;
numlaggers++;
}
else
pingtimeout[i] = 0;
}
//kick lagging players... unless everyone but the server's ping sucks.
@ -4763,12 +4801,27 @@ static inline void PingUpdate(void)
{
if (playeringame[i] && laggers[i])
{
char buf[2];
pingtimeout[i]++;
if (pingtimeout[i] > cv_pingtimeout.value)
// ok your net has been bad for too long, you deserve to die.
{
char buf[2];
buf[0] = (char)i;
buf[1] = KICK_MSG_PING_HIGH;
SendNetXCmd(XD_KICK, &buf, 2);
pingtimeout[i] = 0;
buf[0] = (char)i;
buf[1] = KICK_MSG_PING_HIGH;
SendNetXCmd(XD_KICK, &buf, 2);
}
}
/*
you aren't lagging,
but you aren't free yet.
In case you'll keep spiking,
we just make the timer go back down. (Very unstable net must still get kicked).
*/
else
pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1);
}
}
}
@ -4783,10 +4836,13 @@ static inline void PingUpdate(void)
realpingtable[i] = 0; //Reset each as we go.
}
// send the server's maxping as last element of our ping table. This is useful to let us know when we're about to get kicked.
netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value;
//send out our ping packets
for (i = 0; i < MAXNETNODES; i++)
if (nodeingame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1));
pingmeasurecount = 1; //Reset count
}
@ -4816,7 +4872,7 @@ void NetUpdate(void)
if (server)
{
if (netgame && !(gametime % 255))
if (netgame && !(gametime % 35)) // update once per second.
PingUpdate();
// update node latency values so we can take an average later.
for (i = 0; i < MAXPLAYERS; i++)

View File

@ -255,6 +255,7 @@ typedef struct
INT32 health;
angle_t angle;
angle_t rollangle;
fixed_t x;
fixed_t y;
fixed_t z;
@ -423,9 +424,9 @@ typedef struct
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes
msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
} u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t;
@ -487,6 +488,7 @@ extern tic_t jointimeout;
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;

View File

@ -274,7 +274,7 @@ static void D_Display(void)
&& wipetypepre != UINT8_MAX)
{
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
F_WipeEndScreen();
F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN);
}
@ -291,8 +291,11 @@ static void D_Display(void)
switch (gamestate)
{
case GS_TITLESCREEN:
F_TitleScreenDrawer();
break;
if (!titlemapinaction || !curbghide) {
F_TitleScreenDrawer();
break;
}
/* FALLTHRU */
case GS_LEVEL:
if (!gametic)
break;
@ -363,11 +366,56 @@ static void D_Display(void)
// clean up border stuff
// see if the border needs to be initially drawn
if (gamestate == GS_LEVEL)
if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap)))
{
// draw the view directly
D_Render();
if (!automapactive && !dedicated && cv_renderview.value)
{
if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
{
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
objectsdrawn = 0;
#ifdef HWRENDER
if (rendermode != render_soft)
HWR_RenderPlayerView(0, &players[displayplayer]);
else
#endif
if (rendermode != render_none)
R_RenderPlayerView(&players[displayplayer]);
}
// render the second screen
if (splitscreen && players[secondarydisplayplayer].mo)
{
#ifdef HWRENDER
if (rendermode != render_soft)
HWR_RenderPlayerView(1, &players[secondarydisplayplayer]);
else
#endif
if (rendermode != render_none)
{
viewwindowy = vid.height / 2;
M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0]));
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
R_RenderPlayerView(&players[secondarydisplayplayer]);
viewwindowy = 0;
M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0]));
}
}
// Image postprocessing effect
if (rendermode == render_soft)
{
if (postimgtype)
V_DoPostProcessor(0, postimgtype, postimgparam);
if (postimgtype2)
V_DoPostProcessor(1, postimgtype2, postimgparam2);
}
}
if (lastdraw)
{
@ -380,9 +428,14 @@ static void D_Display(void)
lastdraw = false;
}
ST_Drawer();
F_TextPromptDrawer();
HU_Drawer();
if (gamestate == GS_LEVEL)
{
ST_Drawer();
F_TextPromptDrawer();
HU_Drawer();
}
else
F_TitleScreenDrawer();
}
}
@ -435,6 +488,15 @@ static void D_Display(void)
if (rendermode != render_none)
{
F_WipeEndScreen();
// Funny.
if (WipeStageTitle && st_overlay)
{
lt_ticker--;
lt_lasttic = lt_ticker;
ST_preLevelTitleCardDrawer(0, false);
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
F_WipeStartScreen();
}
F_RunWipe(wipetypepost, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN);
}
@ -444,7 +506,7 @@ static void D_Display(void)
framecount = 0;
demostarttime = I_GetTime();
}
wipetypepost = -1;
}
else
@ -485,56 +547,6 @@ static void D_Display(void)
}
}
void D_Render(void)
{
if (!automapactive && !dedicated && cv_renderview.value)
{
if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
{
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
objectsdrawn = 0;
#ifdef HWRENDER
if (rendermode != render_soft)
HWR_RenderPlayerView(0, &players[displayplayer]);
else
#endif
if (rendermode != render_none)
R_RenderPlayerView(&players[displayplayer]);
}
// render the second screen
if (splitscreen && players[secondarydisplayplayer].mo)
{
#ifdef HWRENDER
if (rendermode != render_soft)
HWR_RenderPlayerView(1, &players[secondarydisplayplayer]);
else
#endif
if (rendermode != render_none)
{
viewwindowy = vid.height / 2;
M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0]));
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
R_RenderPlayerView(&players[secondarydisplayplayer]);
viewwindowy = 0;
M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0]));
}
}
// Image postprocessing effect
if (rendermode == render_soft)
{
if (postimgtype)
V_DoPostProcessor(0, postimgtype, postimgparam);
if (postimgtype2)
V_DoPostProcessor(1, postimgtype2, postimgparam2);
}
}
}
// =========================================================================
// D_SRB2Loop
// =========================================================================
@ -655,6 +667,7 @@ void D_SRB2Loop(void)
// consoleplayer -> displayplayer (hear sounds from viewpoint)
S_UpdateSounds(); // move positional sounds
S_UpdateClosedCaptions();
// check for media change, loop music..
I_UpdateCD();
@ -720,6 +733,8 @@ void D_StartTitle(void)
for (i = 0; i < MAXPLAYERS; i++)
CL_ClearPlayer(i);
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
splitscreen = false;
SplitScreen_OnChange();
botingame = false;

View File

@ -54,7 +54,4 @@ const char *D_Home(void);
void D_AdvanceDemo(void);
void D_StartTitle(void);
/* Here for title maps */
void D_Render(void);
#endif //__D_MAIN__

View File

@ -87,6 +87,7 @@ static void JoinTimeout_OnChange(void);
static void CoopStarposts_OnChange(void);
static void CoopLives_OnChange(void);
static void ExitMove_OnChange(void);
static void Ringslinger_OnChange(void);
static void Gravity_OnChange(void);
@ -341,21 +342,32 @@ consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
consvar_t cv_pingtimeout = {"pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping)
static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
consvar_t cv_showping = {"showping", "Warning", CV_SAVE, showping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// Intermission time Tails 04-19-2002
static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t coopstarposts_cons_t[] = {{0, "Per-player"}, {1, "Shared"}, {2, "Teamwork"}, {0, NULL}};
consvar_t cv_coopstarposts = {"coopstarposts", "Teamwork", CV_NETVAR|CV_CALL|CV_CHEAT, coopstarposts_cons_t, CoopStarposts_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_coopstarposts = {"coopstarposts", "Per-player", CV_NETVAR|CV_CALL, coopstarposts_cons_t, CoopStarposts_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t cooplives_cons_t[] = {{0, "Infinite"}, {1, "Per-player"}, {2, "Avoid Game Over"}, {3, "Single pool"}, {0, NULL}};
consvar_t cv_cooplives = {"cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_CHEAT, cooplives_cons_t, CoopLives_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}};
consvar_t cv_playersforexit = {"playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_exitmove = {"exitmove", "Off", CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -514,6 +526,7 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_inttime);
CV_RegisterVar(&cv_advancemap);
CV_RegisterVar(&cv_playersforexit);
CV_RegisterVar(&cv_exitmove);
CV_RegisterVar(&cv_timelimit);
CV_RegisterVar(&cv_playbackspeed);
CV_RegisterVar(&cv_forceskin);
@ -577,6 +590,8 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep);
CV_RegisterVar(&cv_maxping);
CV_RegisterVar(&cv_pingtimeout);
CV_RegisterVar(&cv_showping);
#ifdef SEENAMES
CV_RegisterVar(&cv_allowseenames);
@ -1213,16 +1228,16 @@ static void SendNameAndColor(void)
}
else if ((foundskin = R_SkinAvailable(cv_skin.string)) != -1 && R_SkinUsable(consoleplayer, foundskin))
{
boolean notsame;
//boolean notsame;
cv_skin.value = foundskin;
notsame = (cv_skin.value != players[consoleplayer].skin);
//notsame = (cv_skin.value != players[consoleplayer].skin);
SetPlayerSkin(consoleplayer, cv_skin.string);
CV_StealthSet(&cv_skin, skins[cv_skin.value].name);
if (notsame)
/*if (notsame)
{
CV_StealthSetValue(&cv_playercolor, skins[cv_skin.value].prefcolor);
@ -1230,7 +1245,7 @@ static void SendNameAndColor(void)
if (players[consoleplayer].mo)
players[consoleplayer].mo->color = (UINT8)players[consoleplayer].skincolor;
}
}*/
}
else
{
@ -1341,15 +1356,16 @@ static void SendNameAndColor2(void)
}
else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUsable(secondplaya, foundskin))
{
boolean notsame;
//boolean notsame;
cv_skin2.value = foundskin;
notsame = (cv_skin2.value != players[secondplaya].skin);
//notsame = (cv_skin2.value != players[secondplaya].skin);
SetPlayerSkin(secondplaya, cv_skin2.string);
CV_StealthSet(&cv_skin2, skins[cv_skin2.value].name);
if (notsame)
/*if (notsame)
{
CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor);
@ -1357,7 +1373,7 @@ static void SendNameAndColor2(void)
if (players[secondplaya].mo)
players[secondplaya].mo->color = players[secondplaya].skincolor;
}
}*/
}
else
{
@ -1924,6 +1940,17 @@ static void Command_Map_f(void)
d = atoi(gametypename);
if (d >= 0 && d < NUMGAMETYPES)
newgametype = d;
else
{
CONS_Alert(CONS_ERROR,
"Gametype number %d is out of range. Use a number between"
" 0 and %d inclusive. ...Or just use the name. :v\n",
d,
NUMGAMETYPES-1);
Z_Free(realmapname);
Z_Free(mapname);
return;
}
}
else
{
@ -2039,7 +2066,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
lastgametype = gametype;
gametype = READUINT8(*cp);
if (gametype != lastgametype)
if (gametype < 0 || gametype >= NUMGAMETYPES)
gametype = lastgametype;
else if (gametype != lastgametype)
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
skipprecutscene = ((flags & (1<<2)) != 0);
@ -3778,6 +3807,17 @@ static void CoopLives_OnChange(void)
}
}
static void ExitMove_OnChange(void)
{
if (!(netgame || multiplayer) || gametype != GT_COOP)
return;
if (cv_exitmove.value)
CONS_Printf(M_GetText("Players can now move after completing the level.\n"));
else
CONS_Printf(M_GetText("Players can no longer move after completing the level.\n"));
}
UINT32 timelimitintics = 0;
/** Deals with a timelimit change by printing the change to the console.
@ -4250,6 +4290,8 @@ void Command_ExitGame_f(void)
for (i = 0; i < MAXPLAYERS; i++)
CL_ClearPlayer(i);
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
splitscreen = false;
SplitScreen_OnChange();
botingame = false;
@ -4310,9 +4352,9 @@ static void Command_Isgamemodified_f(void)
if (savemoddata)
CONS_Printf(M_GetText("modifiedgame is true, but you can save emblem and time data in this mod.\n"));
else if (modifiedgame)
CONS_Printf(M_GetText("modifiedgame is true, secrets will not be unlocked\n"));
CONS_Printf(M_GetText("modifiedgame is true, extras will not be unlocked\n"));
else
CONS_Printf(M_GetText("modifiedgame is false, you can unlock secrets\n"));
CONS_Printf(M_GetText("modifiedgame is false, you can unlock extras\n"));
}
static void Command_Cheats_f(void)

View File

@ -94,7 +94,7 @@ extern consvar_t cv_recycler;
extern consvar_t cv_itemfinder;
extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_playersforexit;
extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_playersforexit, cv_exitmove;
extern consvar_t cv_overtime;
extern consvar_t cv_startinglives;
@ -106,6 +106,9 @@ extern consvar_t cv_ringslinger, cv_soundtest;
extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes;
extern consvar_t cv_maxping;
extern consvar_t cv_pingtimeout;
extern consvar_t cv_showping;
extern consvar_t cv_skipmapcheck;

View File

@ -716,7 +716,7 @@ void SV_FileSendTicker(void)
if (ram)
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile));
p->position = LONG(transfer[i].position);
// Put flag so receiver knows the total size
if (transfer[i].position + size == f->size)
@ -794,7 +794,7 @@ void Got_Filetxpak(void)
// We can receive packet in the wrong order, anyway all os support gaped file
fseek(file->file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file));
file->currentsize += size;
// Finished?

View File

@ -151,6 +151,7 @@ typedef enum
/*** misc ***/
PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs
PF_CANCARRY = 1<<29, // Can carry another player?
PF_FINISHED = 1<<30, // The player finished the level. NOT the same as exiting
// up to 1<<31 is free
} pflags_t;

View File

@ -1201,6 +1201,14 @@ static void readlevelheader(MYFILE *f, INT32 num)
word2 = tmp += 2;
i = atoi(word2); // used for numerical settings
if (fastcmp(word, "LEVELNAME"))
{
deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once
continue;
}
// CHEAP HACK: move this over here for lowercase subtitles
if (fastcmp(word, "SUBTITLE"))
{
@ -1344,12 +1352,6 @@ static void readlevelheader(MYFILE *f, INT32 num)
}
// Strings that can be truncated
else if (fastcmp(word, "LEVELNAME"))
{
deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once
}
else if (fastcmp(word, "SELECTHEADING"))
{
deh_strlcpy(mapheaderinfo[num-1]->selectheading, word2,
@ -1573,6 +1575,20 @@ static void readlevelheader(MYFILE *f, INT32 num)
else
mapheaderinfo[num-1]->levelflags &= ~LF_MIXNIGHTSCOUNTDOWN;
}
else if (fastcmp(word, "WARNINGTITLE"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_WARNINGTITLE;
else
mapheaderinfo[num-1]->levelflags &= ~LF_WARNINGTITLE;
}
else if (fastcmp(word, "NOTITLECARD"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_NOTITLECARD;
else
mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARD;
}
// Individual triggers for menu flags
else if (fastcmp(word, "HIDDEN"))
@ -2781,6 +2797,9 @@ static actionpointer_t actionpointers[] =
{{A_PterabyteHover}, "A_PTERABYTEHOVER"},
{{A_RolloutSpawn}, "A_ROLLOUTSPAWN"},
{{A_RolloutRock}, "A_ROLLOUTROCK"},
{{A_DragonbomberSpawn}, "A_DRAGONBOMERSPAWN"},
{{A_DragonWing}, "A_DRAGONWING"},
{{A_DragonSegment}, "A_DRAGONSEGMENT"},
{{NULL}, "NONE"},
// This NULL entry must be the last in the list
@ -3165,7 +3184,6 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
// Now get the part after
word2 = tmp += 2;
strupr(word2);
value = atoi(word2); // used for numerical settings
@ -3177,22 +3195,26 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num));
else if (fastcmp(word, "CONDITIONSET"))
extraemblems[num-1].conditionset = (UINT8)value;
else if (fastcmp(word, "SPRITE"))
{
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = word2[0];
else
value += 'A'-1;
if (value < 'A' || value > 'Z')
deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num);
else
extraemblems[num-1].sprite = (UINT8)value;
}
else if (fastcmp(word, "COLOR"))
extraemblems[num-1].color = get_number(word2);
else
deh_warning("Extra emblem %d: unknown word '%s'", num, word);
{
strupr(word2);
if (fastcmp(word, "SPRITE"))
{
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = word2[0];
else
value += 'A'-1;
if (value < 'A' || value > 'Z')
deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num);
else
extraemblems[num-1].sprite = (UINT8)value;
}
else if (fastcmp(word, "COLOR"))
extraemblems[num-1].color = get_number(word2);
else
deh_warning("Extra emblem %d: unknown word '%s'", num, word);
}
}
} while (!myfeof(f));
@ -3243,7 +3265,6 @@ static void readunlockable(MYFILE *f, INT32 num)
// Now get the part after
word2 = tmp += 2;
strupr(word2);
i = atoi(word2); // used for numerical settings
@ -3253,54 +3274,58 @@ static void readunlockable(MYFILE *f, INT32 num)
else if (fastcmp(word, "OBJECTIVE"))
deh_strlcpy(unlockables[num].objective, word2,
sizeof (unlockables[num].objective), va("Unlockable %d: objective", num));
else if (fastcmp(word, "HEIGHT"))
unlockables[num].height = (UINT16)i;
else if (fastcmp(word, "CONDITIONSET"))
unlockables[num].conditionset = (UINT8)i;
else if (fastcmp(word, "NOCECHO"))
unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "NOCHECKLIST"))
unlockables[num].nochecklist = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "TYPE"))
{
if (fastcmp(word2, "NONE"))
unlockables[num].type = SECRET_NONE;
else if (fastcmp(word2, "ITEMFINDER"))
unlockables[num].type = SECRET_ITEMFINDER;
else if (fastcmp(word2, "EMBLEMHINTS"))
unlockables[num].type = SECRET_EMBLEMHINTS;
else if (fastcmp(word2, "PANDORA"))
unlockables[num].type = SECRET_PANDORA;
else if (fastcmp(word2, "CREDITS"))
unlockables[num].type = SECRET_CREDITS;
else if (fastcmp(word2, "RECORDATTACK"))
unlockables[num].type = SECRET_RECORDATTACK;
else if (fastcmp(word2, "NIGHTSMODE"))
unlockables[num].type = SECRET_NIGHTSMODE;
else if (fastcmp(word2, "HEADER"))
unlockables[num].type = SECRET_HEADER;
else if (fastcmp(word2, "LEVELSELECT"))
unlockables[num].type = SECRET_LEVELSELECT;
else if (fastcmp(word2, "WARP"))
unlockables[num].type = SECRET_WARP;
else if (fastcmp(word2, "SOUNDTEST"))
unlockables[num].type = SECRET_SOUNDTEST;
else
unlockables[num].type = (INT16)i;
}
else if (fastcmp(word, "VAR"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
i = M_MapNumber(word2[0], word2[1]);
unlockables[num].variable = (INT16)i;
}
else
deh_warning("Unlockable %d: unknown word '%s'", num+1, word);
{
strupr(word2);
if (fastcmp(word, "HEIGHT"))
unlockables[num].height = (UINT16)i;
else if (fastcmp(word, "CONDITIONSET"))
unlockables[num].conditionset = (UINT8)i;
else if (fastcmp(word, "NOCECHO"))
unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "NOCHECKLIST"))
unlockables[num].nochecklist = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "TYPE"))
{
if (fastcmp(word2, "NONE"))
unlockables[num].type = SECRET_NONE;
else if (fastcmp(word2, "ITEMFINDER"))
unlockables[num].type = SECRET_ITEMFINDER;
else if (fastcmp(word2, "EMBLEMHINTS"))
unlockables[num].type = SECRET_EMBLEMHINTS;
else if (fastcmp(word2, "PANDORA"))
unlockables[num].type = SECRET_PANDORA;
else if (fastcmp(word2, "CREDITS"))
unlockables[num].type = SECRET_CREDITS;
else if (fastcmp(word2, "RECORDATTACK"))
unlockables[num].type = SECRET_RECORDATTACK;
else if (fastcmp(word2, "NIGHTSMODE"))
unlockables[num].type = SECRET_NIGHTSMODE;
else if (fastcmp(word2, "HEADER"))
unlockables[num].type = SECRET_HEADER;
else if (fastcmp(word2, "LEVELSELECT"))
unlockables[num].type = SECRET_LEVELSELECT;
else if (fastcmp(word2, "WARP"))
unlockables[num].type = SECRET_WARP;
else if (fastcmp(word2, "SOUNDTEST"))
unlockables[num].type = SECRET_SOUNDTEST;
else
unlockables[num].type = (INT16)i;
}
else if (fastcmp(word, "VAR"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
i = M_MapNumber(word2[0], word2[1]);
unlockables[num].variable = (INT16)i;
}
else
deh_warning("Unlockable %d: unknown word '%s'", num+1, word);
}
}
} while (!myfeof(f)); // finish when the line is empty
@ -4950,22 +4975,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_MINUS_BURST4",
"S_MINUS_BURST5",
"S_MINUS_POPUP",
"S_MINUS_UPWARD1",
"S_MINUS_UPWARD2",
"S_MINUS_UPWARD3",
"S_MINUS_UPWARD4",
"S_MINUS_UPWARD5",
"S_MINUS_UPWARD6",
"S_MINUS_UPWARD7",
"S_MINUS_UPWARD8",
"S_MINUS_DOWNWARD1",
"S_MINUS_DOWNWARD2",
"S_MINUS_DOWNWARD3",
"S_MINUS_DOWNWARD4",
"S_MINUS_DOWNWARD5",
"S_MINUS_DOWNWARD6",
"S_MINUS_DOWNWARD7",
"S_MINUS_DOWNWARD8",
"S_MINUS_AERIAL1",
"S_MINUS_AERIAL2",
"S_MINUS_AERIAL3",
"S_MINUS_AERIAL4",
// Minus dirt
"S_MINUSDIRT1",
@ -5041,6 +5054,26 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PTERABYTE_SWOOPDOWN",
"S_PTERABYTE_SWOOPUP",
// Dragonbomber
"S_DRAGONBOMBER",
"S_DRAGONWING1",
"S_DRAGONWING2",
"S_DRAGONWING3",
"S_DRAGONWING4",
"S_DRAGONTAIL_LOADED",
"S_DRAGONTAIL_EMPTY",
"S_DRAGONTAIL_EMPTYLOOP",
"S_DRAGONTAIL_RELOAD",
"S_DRAGONMINE",
"S_DRAGONMINE_LAND1",
"S_DRAGONMINE_LAND2",
"S_DRAGONMINE_SLOWFLASH1",
"S_DRAGONMINE_SLOWFLASH2",
"S_DRAGONMINE_SLOWLOOP",
"S_DRAGONMINE_FASTFLASH1",
"S_DRAGONMINE_FASTFLASH2",
"S_DRAGONMINE_FASTLOOP",
// Boss Explosion
"S_BOSSEXPLODE",
@ -5343,6 +5376,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FSGNA",
"S_FSGNB",
"S_FSGNC",
"S_FSGND",
// Black Eggman (Boss 7)
"S_BLACKEGG_STND",
@ -7139,6 +7173,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FOUR2",
"S_FIVE2",
"S_FLIGHTINDICATOR",
"S_LOCKON1",
"S_LOCKON2",
"S_LOCKON3",
@ -7322,13 +7358,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FIREFLOWER2",
"S_FIREFLOWER3",
"S_FIREFLOWER4",
"S_FIREBALL1",
"S_FIREBALL2",
"S_FIREBALL3",
"S_FIREBALL4",
"S_FIREBALLEXP1",
"S_FIREBALLEXP2",
"S_FIREBALLEXP3",
"S_FIREBALL",
"S_FIREBALLTRAIL1",
"S_FIREBALLTRAIL2",
"S_SHELL",
"S_PUMA_START1",
"S_PUMA_START2",
@ -7497,6 +7529,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_POPHAT_SHOOT1",
"S_POPHAT_SHOOT2",
"S_POPHAT_SHOOT3",
"S_POPHAT_SHOOT4",
"S_POPSHOT",
"S_POPSHOT_TRAIL",
"S_HIVEELEMENTAL_LOOK",
"S_HIVEELEMENTAL_PREPARE1",
@ -7628,8 +7663,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_DUST3",
"S_DUST4",
"S_WOODDEBRIS",
"S_ROCKSPAWN",
"S_ROCKCRUMBLEA",
@ -7648,7 +7681,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_ROCKCRUMBLEN",
"S_ROCKCRUMBLEO",
"S_ROCKCRUMBLEP",
"S_GFZDEBRIS",
"S_BRICKDEBRIS",
"S_WOODDEBRIS",
#ifdef SEENAMES
"S_NAMECHECK",
@ -7712,6 +7747,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_PTERABYTESPAWNER", // Pterabyte spawner
"MT_PTERABYTEWAYPOINT", // Pterabyte waypoint
"MT_PTERABYTE", // Pterabyte
"MT_DRAGONBOMBER", // Dragonbomber
"MT_DRAGONWING", // Dragonbomber wing
"MT_DRAGONTAIL", // Dragonbomber tail segment
"MT_DRAGONMINE", // Dragonbomber mine
// Generic Boss Items
"MT_BOSSEXPLODE",
@ -8317,6 +8356,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BLUEGOOMBA",
"MT_FIREFLOWER",
"MT_FIREBALL",
"MT_FIREBALLTRAIL",
"MT_SHELL",
"MT_PUMA",
"MT_PUMATRAIL",
@ -8361,6 +8401,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_PENGUINATOR",
"MT_POPHAT",
"MT_POPSHOT",
"MT_POPSHOT_TRAIL",
"MT_HIVEELEMENTAL",
"MT_BUMBLEBORE",
@ -8398,7 +8439,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_EXPLODE", // Robot Explosion
"MT_UWEXPLODE", // Underwater Explosion
"MT_DUST",
"MT_WOODDEBRIS",
"MT_ROCKSPAWNER",
"MT_FALLINGROCK",
"MT_ROCKCRUMBLE1",
@ -8417,7 +8457,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_ROCKCRUMBLE14",
"MT_ROCKCRUMBLE15",
"MT_ROCKCRUMBLE16",
"MT_GFZDEBRIS",
"MT_BRICKDEBRIS",
"MT_WOODDEBRIS",
#ifdef SEENAMES
"MT_NAMECHECK",
@ -8570,6 +8612,7 @@ static const char *const PLAYERFLAG_LIST[] = {
/*** misc ***/
"FORCESTRAFE", // Translate turn inputs into strafe inputs
"CANCARRY", // Can carry?
"FINISHED",
NULL // stop loop here.
};
@ -8856,7 +8899,7 @@ static const char *const MENUTYPES_LIST[] = {
"OP_SCREENSHOTS",
"OP_ERASEDATA",
// Secrets
// Extras
"SR_MAIN",
"SR_PANDORA",
"SR_LEVELSELECT",
@ -9012,6 +9055,8 @@ struct {
{"LF_NOZONE",LF_NOZONE},
{"LF_SAVEGAME",LF_SAVEGAME},
{"LF_MIXNIGHTSCOUNTDOWN",LF_MIXNIGHTSCOUNTDOWN},
{"LF_NOTITLECARD",LF_NOTITLECARD},
{"LF_WARNINGTITLE",LF_WARNINGTITLE},
// And map flags
{"LF2_HIDEINMENU",LF2_HIDEINMENU},
{"LF2_HIDEINSTATS",LF2_HIDEINSTATS},

View File

@ -98,6 +98,9 @@ void I_FinishUpdate (void)
if (cv_ticrate.value)
SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
//blast it to the screen
// this code sucks
//memcpy(dascreen,screens[0],screenwidth*screenheight);

View File

@ -349,6 +349,8 @@ typedef struct
#define LF_NOZONE 16 ///< Don't include "ZONE" on level title
#define LF_SAVEGAME 32 ///< Save the game upon loading this level
#define LF_MIXNIGHTSCOUNTDOWN 64 ///< Play sfx_timeup instead of music change for NiGHTS countdown
#define LF_WARNINGTITLE 128 ///< WARNING! WARNING! WARNING! WARNING!
#define LF_NOTITLECARD 256 ///< Don't start the title card
#define LF2_HIDEINMENU 1 ///< Hide in the multiplayer menu
#define LF2_HIDEINSTATS 2 ///< Hide in the statistics screen
@ -433,7 +435,6 @@ typedef struct
tic_t time; ///< Time in which the level was finished.
UINT32 score; ///< Score when the level was finished.
UINT16 rings; ///< Rings when the level was finished.
boolean gotperfect; ///< Got perfect bonus?
} recorddata_t;
/** Setup for one NiGHTS map.

View File

@ -856,7 +856,7 @@ void F_IntroDrawer(void)
if (rendermode != render_none)
{
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
F_WipeEndScreen();
F_RunWipe(99,true);
}
@ -866,10 +866,11 @@ void F_IntroDrawer(void)
else if (intro_scenenum == 10)
{
// The only fade to white in the entire damn game.
// (not true)
if (rendermode != render_none)
{
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
F_WipeColorFill(0);
F_WipeEndScreen();
F_RunWipe(99,true);
}
@ -879,7 +880,7 @@ void F_IntroDrawer(void)
if (rendermode != render_none)
{
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
F_WipeEndScreen();
F_RunWipe(99,true);
}
@ -926,7 +927,7 @@ void F_IntroDrawer(void)
patch_t *radar = W_CachePatchName("RADAR", PU_CACHE);
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
V_DrawScaledPatch(0, 0, 0, radar);
W_UnlockCachedPatch(radar);
V_DrawString(8, 128, V_ALLOWLOWERCASE, cutscene_disptext);
@ -939,7 +940,7 @@ void F_IntroDrawer(void)
patch_t *grass = W_CachePatchName("SGRASS5", PU_CACHE);
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
V_DrawScaledPatch(0, 0, 0, grass);
W_UnlockCachedPatch(grass);
V_DrawString(8, 128, V_ALLOWLOWERCASE, cutscene_disptext);
@ -952,7 +953,7 @@ void F_IntroDrawer(void)
patch_t *confront = W_CachePatchName("CONFRONT", PU_CACHE);
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
V_DrawSmallScaledPatch(0, 0, 0, confront);
W_UnlockCachedPatch(confront);
V_DrawString(8, 128, V_ALLOWLOWERCASE, cutscene_disptext);
@ -965,7 +966,7 @@ void F_IntroDrawer(void)
patch_t *sdo = W_CachePatchName("SONICDO2", PU_CACHE);
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeColorFill(31);
V_DrawSmallScaledPatch(0, 0, 0, sdo);
W_UnlockCachedPatch(sdo);
V_DrawString(224, 8, V_ALLOWLOWERCASE, cutscene_disptext);
@ -1385,13 +1386,16 @@ boolean F_CreditResponder(event_t *event)
void F_StartGameEvaluation(void)
{
// Credits option in secrets menu
// Credits option in extras menu
if (cursaveslot == -1)
{
S_FadeOutStopMusic(2*MUSICRATE);
F_StartGameEnd();
return;
}
S_FadeOutStopMusic(5*MUSICRATE);
G_SetGamestate(GS_EVALUATION);
// Just in case they're open ... somehow
@ -1537,9 +1541,9 @@ void F_GameEvaluationDrawer(void)
}
}
else if (netgame)
V_DrawString(8, 96, V_YELLOWMAP, "Prizes only\nawarded in\nsingle player!");
V_DrawString(8, 96, V_YELLOWMAP, "Multiplayer games\ncan't unlock\nextras!");
else
V_DrawString(8, 96, V_YELLOWMAP, "Prizes not\nawarded in\nmodified games!");
V_DrawString(8, 96, V_YELLOWMAP, "Modified games\ncan't unlock\nextras!");
}
#endif
}
@ -1586,7 +1590,7 @@ void F_GameEvaluationTicker(void)
{
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8);
HU_SetCEchoDuration(6);
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Prizes only awarded in singleplayer!");
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Multiplayer games can't unlock extras!");
S_StartSound(NULL, sfx_s3k68);
}
else if (!modifiedgame || savemoddata)
@ -1608,7 +1612,7 @@ void F_GameEvaluationTicker(void)
{
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8);
HU_SetCEchoDuration(6);
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Prizes not awarded in modified games!");
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Modified games can't unlock extras!");
S_StartSound(NULL, sfx_s3k68);
}
}
@ -1621,6 +1625,7 @@ void F_GameEvaluationTicker(void)
// ==========
#define INFLECTIONPOINT (6*TICRATE)
#define STOPPINGPOINT (14*TICRATE)
#define SPARKLLOOPTIME 15 // must be odd
void F_StartEnding(void)
@ -1638,7 +1643,7 @@ void F_StartEnding(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
S_StopMusic(); // todo: placeholder
S_StopMusic();
S_StopSounds();
finalecount = -10; // what? this totally isn't a hack. why are you asking?
@ -1679,7 +1684,7 @@ void F_StartEnding(void)
UINT8 skinnum = players[consoleplayer].skin;
spritedef_t *sprdef;
spriteframe_t *sprframe;
if (skins[skinnum].sprites[SPR2_XTRA].numframes >= (XTRA_ENDING+2)+1)
if (skins[skinnum].sprites[SPR2_XTRA].numframes > (XTRA_ENDING+2))
{
sprdef = &skins[skinnum].sprites[SPR2_XTRA];
// character head, skin specific
@ -1712,13 +1717,16 @@ void F_StartEnding(void)
void F_EndingTicker(void)
{
if (++finalecount > INFLECTIONPOINT*2)
if (++finalecount > STOPPINGPOINT)
{
F_StartCredits();
wipetypepre = INT16_MAX;
return;
}
if (finalecount == -8)
S_ChangeMusicInternal((goodending ? "_endg" : "_endb"), false);
if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets
{
endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL);
@ -2105,26 +2113,26 @@ void F_EndingDrawer(void)
if (finalecount < 10)
trans = (10-finalecount)/2;
else if (finalecount > (2*INFLECTIONPOINT) - 20)
else if (finalecount > STOPPINGPOINT - 20)
{
trans = 10 + (finalecount/2) - INFLECTIONPOINT;
trans = 10 + (finalecount - STOPPINGPOINT)/2;
donttouch = true;
}
if (trans != 10)
if (trans < 10)
{
//colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret
V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), str);
V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false);
V_DrawString(40, ((finalecount == (2*INFLECTIONPOINT)-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= (2*INFLECTIONPOINT)-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
}
if (finalecount > (2*INFLECTIONPOINT)-(20+(2*TICRATE)))
if (finalecount > STOPPINGPOINT-(20+(2*TICRATE)))
{
INT32 trans2 = abs((5*FINECOSINE((FixedAngle((finalecount*5)<<FRACBITS)>>ANGLETOFINESHIFT & FINEMASK)))>>FRACBITS)+2;
if (!donttouch)
{
trans = 10 + ((2*INFLECTIONPOINT)-(20+(2*TICRATE))) - finalecount;
trans = 10 + (STOPPINGPOINT-(20+(2*TICRATE))) - finalecount;
if (trans > trans2)
trans2 = trans;
}
@ -2148,7 +2156,6 @@ void F_StartGameEnd(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
S_StopMusic();
S_StopSounds();
// In case menus are still up?!!
@ -2582,9 +2589,7 @@ void F_TitleScreenDrawer(void)
// Draw that sky!
if (curbgcolor >= 0)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
else if (titlemapinaction && curbghide && ! hidetitlemap)
D_Render();
else
else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
// Don't draw outside of the title screen, or if the patch isn't there.
@ -3344,6 +3349,10 @@ void F_TitleScreenTicker(boolean run)
if (run)
finalecount++;
// don't trigger if doing anything besides idling on title
if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN)
return;
// Execute the titlemap camera settings
if (titlemapinaction)
{
@ -3390,10 +3399,6 @@ void F_TitleScreenTicker(boolean run)
}
}
// don't trigger if doing anything besides idling on title
if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN)
return;
// no demos to play? or, are they disabled?
if (!cv_rollingdemos.value || !numDemos)
return;
@ -3546,7 +3551,7 @@ void F_ContinueDrawer(void)
if (timetonext >= (11*TICRATE)+10)
return;
V_DrawLevelTitle(x - (V_LevelNameWidth("CONTINUE")>>1), 16, 0, "CONTINUE");
V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?");
// Two stars...
patch = W_CachePatchName("CONTSTAR", PU_CACHE);

View File

@ -141,11 +141,42 @@ void F_MenuPresTicker(boolean run);
#define FORCEWIPEOFF -2
extern boolean WipeInAction;
extern boolean WipeStageTitle;
typedef enum
{
WIPESTYLE_NORMAL,
WIPESTYLE_LEVEL
} wipestyle_t;
extern wipestyle_t wipestyle;
typedef enum
{
WSF_FADEOUT = 1,
WSF_FADEIN = 1<<1,
WSF_TOWHITE = 1<<2,
WSF_CROSSFADE = 1<<3,
} wipestyleflags_t;
extern wipestyleflags_t wipestyleflags;
#define FADECOLORMAPDIV 8
#define FADECOLORMAPROWS (256/FADECOLORMAPDIV)
#define FADEREDFACTOR 15
#define FADEGREENFACTOR 15
#define FADEBLUEFACTOR 10
extern INT32 lastwipetic;
// Don't know where else to place this constant
// But this file seems appropriate
#define PRELEVELTIME 24 // frames in tics
void F_WipeStartScreen(void);
void F_WipeEndScreen(void);
void F_RunWipe(UINT8 wipetype, boolean drawMenu);
void F_WipeStageTitle(void);
#define F_WipeColorFill(c) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, c)
tic_t F_GetWipeLength(UINT8 wipetype);
boolean F_WipeExists(UINT8 wipetype);

View File

@ -18,6 +18,8 @@
#include "r_draw.h" // transtable
#include "p_pspr.h" // tr_transxxx
#include "p_local.h"
#include "st_stuff.h"
#include "w_wad.h"
#include "z_zone.h"
@ -25,8 +27,15 @@
#include "m_menu.h"
#include "console.h"
#include "d_main.h"
#include "g_game.h"
#include "m_misc.h" // movie mode
#include "doomstat.h"
#ifdef HAVE_BLUA
#include "lua_hud.h" // level title
#endif
#ifdef HWRENDER
#include "hardware/hw_main.h"
#endif
@ -82,8 +91,12 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
//--------------------------------------------------------------------------
boolean WipeInAction = false;
boolean WipeStageTitle = false;
INT32 lastwipetic = 0;
wipestyle_t wipestyle = WIPESTYLE_NORMAL;
wipestyleflags_t wipestyleflags = WSF_CROSSFADE;
#ifndef NOWIPE
static UINT8 *wipe_scr_start; //screen 3
static UINT8 *wipe_scr_end; //screen 4
@ -148,7 +161,10 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
{
// Determine pixel to use from fademask
pcolor = &pMasterPalette[*lump++];
*mask++ = FixedDiv((pcolor->s.red+1)<<FRACBITS, paldiv)>>FRACBITS;
if (wipestyle == WIPESTYLE_LEVEL)
*mask++ = pcolor->s.red / FADECOLORMAPDIV;
else
*mask++ = FixedDiv((pcolor->s.red+1)<<FRACBITS, paldiv)>>FRACBITS;
}
fm.xscale = FixedDiv(vid.width<<FRACBITS, fm.width<<FRACBITS);
@ -169,6 +185,21 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
return NULL;
}
/** Draw the stage title.
*/
void F_WipeStageTitle(void)
{
// draw level title
if ((WipeStageTitle && st_overlay)
&& (wipestyle == WIPESTYLE_LEVEL)
&& !(mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)
&& *mapheaderinfo[gamemap-1]->lvlttl != '\0')
{
ST_runTitleCard();
ST_drawWipeTitleCard();
}
}
/** Wipe ticker
*
* \param fademask pixels to change
@ -251,7 +282,7 @@ static void F_DoWipe(fademask_t *fademask)
relativepos += vid.width;
}
}
else if (*mask == 10)
else if (*mask >= ((wipestyle == WIPESTYLE_LEVEL) ? FADECOLORMAPROWS : 10))
{
// shortcut - memcpy target to work
while (draw_linestogo--)
@ -262,8 +293,25 @@ static void F_DoWipe(fademask_t *fademask)
}
else
{
// pointer to transtable that this mask would use
transtbl = transtables + ((9 - *mask)<<FF_TRANSSHIFT);
if (wipestyle == WIPESTYLE_LEVEL)
{
int nmask;
UINT8 *fade = fadecolormap;
if (wipestyleflags & WSF_TOWHITE)
fade = fadecolormap + (FADECOLORMAPROWS * 256);
nmask = *mask;
if (wipestyleflags & WSF_FADEIN)
nmask = (FADECOLORMAPROWS-1) - nmask;
transtbl = fade + (nmask * 256);
}
else
{
// pointer to transtable that this mask would use
transtbl = transtables + ((9 - *mask)<<FF_TRANSSHIFT);
}
// DRAWING LOOP
while (draw_linestogo--)
@ -273,8 +321,16 @@ static void F_DoWipe(fademask_t *fademask)
e = e_base + relativepos;
draw_rowstogo = draw_rowend - draw_rowstart;
while (draw_rowstogo--)
*w++ = transtbl[ ( *e++ << 8 ) + *s++ ];
if (wipestyle == WIPESTYLE_LEVEL)
{
while (draw_rowstogo--)
*w++ = transtbl[*e++];
}
else
{
while (draw_rowstogo--)
*w++ = transtbl[ ( *e++ << 8 ) + *s++ ];
}
relativepos += vid.width;
}
@ -346,6 +402,15 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
WipeInAction = true;
wipe_scr = screens[0];
// don't know where else to put this.
// this any good?
if ((gamestate == GS_LEVEL || gamestate == GS_TITLESCREEN)
&& (wipestyleflags & (WSF_FADEIN|WSF_FADEOUT)) // only if one of those wipestyleflags are actually set
&& !(wipestyleflags & WSF_CROSSFADE)) // and if not crossfading
wipestyle = WIPESTYLE_LEVEL;
else
wipestyle = WIPESTYLE_NORMAL;
// lastwipetic should either be 0 or the tic we last wiped
// on for fade-to-black
for (;;)
@ -362,10 +427,20 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_DoWipe(wipetype, wipeframe-1); // send in the wipe type and wipeframe because we need to cache the graphic
{
// send in the wipe type and wipe frame because we need to cache the graphic
if (wipestyle == WIPESTYLE_LEVEL)
HWR_DoTintedWipe(wipetype, wipeframe-1);
else
HWR_DoWipe(wipetype, wipeframe-1);
}
else
#endif
F_DoWipe(fmask);
F_DoWipe(fmask);
if (wipestyle == WIPESTYLE_LEVEL)
F_WipeStageTitle();
I_OsPolling();
I_UpdateNoBlit();
@ -377,7 +452,9 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
if (moviemode)
M_SaveFrame();
}
WipeInAction = false;
WipeStageTitle = false;
#endif
}
@ -408,6 +485,8 @@ tic_t F_GetWipeLength(UINT8 wipetype)
#endif
}
/** Does the specified wipe exist?
*/
boolean F_WipeExists(UINT8 wipetype)
{
#ifdef NOWIPE

View File

@ -47,6 +47,10 @@
#include "m_cond.h" // condition sets
#include "md5.h" // demo checksums
#ifdef HAVE_BLUA
#include "lua_hud.h"
#endif
gameaction_t gameaction;
gamestate_t gamestate = GS_NULL;
UINT8 ultimatemode = false;
@ -168,6 +172,7 @@ mapheader_t* mapheaderinfo[NUMMAPS] = {NULL};
static boolean exitgame = false;
static boolean retrying = false;
static boolean retryingmodeattack = false;
UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage.
@ -536,11 +541,99 @@ void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare)
ntemprecords.nummares = mare;
}
//
// G_UpdateRecordReplays
//
// Update replay files/data, etc. for Record Attack
// See G_SetNightsRecords for NiGHTS Attack.
//
static void G_UpdateRecordReplays(void)
{
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath;
char lastdemo[256], bestdemo[256];
UINT8 earnedEmblems;
// Record new best time
if (!mainrecords[gamemap-1])
G_AllocMainRecordData(gamemap-1);
if (players[consoleplayer].score > mainrecords[gamemap-1]->score)
mainrecords[gamemap-1]->score = players[consoleplayer].score;
if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings)
mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);
// Save demo!
bestdemo[255] = '\0';
lastdemo[255] = '\0';
G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].rings));
G_CheckDemoStatus();
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);
if ((gpath = malloc(glen)) == NULL)
I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (FIL_FileExists(lastdemo))
{
UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
}
snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
{ // Better score, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo);
}
snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2)))
{ // Better rings, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo);
}
//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);
Z_Free(buf);
}
free(gpath);
// Check emblems when level data is updated
if ((earnedEmblems = M_CheckLevelEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
// Update timeattack menu's replay availability.
Nextmap_OnChange();
}
void G_SetNightsRecords(void)
{
INT32 i;
UINT32 totalscore = 0;
tic_t totaltime = 0;
UINT8 earnedEmblems;
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath;
@ -640,6 +733,9 @@ void G_SetNightsRecords(void)
}
free(gpath);
if ((earnedEmblems = M_CheckLevelEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
// If the mare count changed, this will update the score display
Nextmap_OnChange();
}
@ -923,11 +1019,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
movebkey = PLAYER1INPUTDOWN(gc_backward);
mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^
(cv_chasecam.value ? cv_chasefreelook.value : cv_alwaysfreelook.value);
((cv_chasecam.value && !player->spectator) ? cv_chasefreelook.value : cv_alwaysfreelook.value);
analogjoystickmove = cv_usejoystick.value && !Joystick.bGamepadStyle;
gamepadjoystickmove = cv_usejoystick.value && Joystick.bGamepadStyle;
thisjoyaiming = (cv_chasecam.value) ? cv_chasefreelook.value : cv_alwaysfreelook.value;
thisjoyaiming = (cv_chasecam.value && !player->spectator) ? cv_chasefreelook.value : cv_alwaysfreelook.value;
// Reset the vertical look if we're no longer joyaiming
if (!thisjoyaiming && joyaiming)
@ -1252,11 +1348,11 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
movebkey = PLAYER2INPUTDOWN(gc_backward);
mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^
(cv_chasecam2.value ? cv_chasefreelook2.value : cv_alwaysfreelook2.value);
((cv_chasecam2.value && !player->spectator) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value);
analogjoystickmove = cv_usejoystick2.value && !Joystick2.bGamepadStyle;
gamepadjoystickmove = cv_usejoystick2.value && Joystick2.bGamepadStyle;
thisjoyaiming = (cv_chasecam2.value) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value;
thisjoyaiming = (cv_chasecam2.value && !player->spectator) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value;
// Reset the vertical look if we're no longer joyaiming
if (!thisjoyaiming && joyaiming)
@ -1703,6 +1799,58 @@ void G_DoLoadLevel(boolean resetplayer)
CON_ClearHUD();
}
//
// Start the title card.
//
void G_StartTitleCard(void)
{
wipestyleflags |= WSF_FADEIN;
wipestyleflags &= ~WSF_FADEOUT;
// The title card has been disabled for this map.
// Oh well.
if (mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)
{
WipeStageTitle = false;
return;
}
// clear the hud
CON_ClearHUD();
// prepare status bar
ST_startTitleCard();
// start the title card
WipeStageTitle = (!titlemapinaction);
}
//
// Run the title card before fading in to the level.
//
void G_PreLevelTitleCard(tic_t ticker, boolean update)
{
tic_t starttime = I_GetTime();
tic_t endtime = starttime + (PRELEVELTIME*NEWTICRATERATIO);
tic_t nowtime = starttime;
tic_t lasttime = starttime;
while (nowtime < endtime)
{
// draw loop
while (!((nowtime = I_GetTime()) - lasttime))
I_Sleep();
lasttime = nowtime;
ST_runTitleCard();
ST_preLevelTitleCardDrawer(ticker, update);
if (moviemode)
M_SaveFrame();
if (takescreenshot) // Only take screenshots after drawing.
M_DoScreenShot();
}
}
INT32 pausedelay = 0;
boolean pausebreakkey = false;
static INT32 camtoggledelay, camtoggledelay2 = 0;
@ -1868,7 +2016,7 @@ boolean G_Responder(event_t *ev)
pausedelay = 1+(NEWTICRATE/2);
else if (++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3))
{
G_SetRetryFlag();
G_SetModeAttackRetryFlag();
return true;
}
pausedelay++; // counteract subsequent subtraction this frame
@ -1992,7 +2140,7 @@ void G_Ticker(boolean run)
if (titledemo)
F_TitleDemoTicker();
P_Ticker(run); // tic the game
ST_Ticker();
ST_Ticker(run);
F_TextPromptTicker();
AM_Ticker();
HU_Ticker();
@ -2175,6 +2323,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
outofcoop = players[player].outofcoop;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER));
if (!betweenmaps)
pflags |= (players[player].pflags & PF_FINISHED);
// As long as we're not in multiplayer, carry over cheatcodes from map to map
if (!(netgame || multiplayer))
pflags |= (players[player].pflags & (PF_GODMODE|PF_NOCLIP|PF_INVIS));
@ -2709,6 +2860,7 @@ void G_DoReborn(INT32 playernum)
// Do a wipe
wipegamestate = -1;
wipestyleflags = WSF_CROSSFADE;
if (camera.chase)
P_ResetCamera(&players[displayplayer], &camera);
@ -2829,10 +2981,35 @@ void G_AddPlayer(INT32 playernum)
if (G_GametypeUsesLives() || ((netgame || multiplayer) && gametype == GT_COOP))
p->lives = cv_startinglives.value;
if (countplayers && !notexiting)
if ((countplayers && !notexiting) || G_IsSpecialStage(gamemap))
P_DoPlayerExit(p);
}
boolean G_EnoughPlayersFinished(void)
{
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
INT32 total = 0;
INT32 exiting = 0;
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].lives <= 0)
continue;
total++;
if ((players[i].pflags & PF_FINISHED) || players[i].exiting)
exiting++;
}
if (exiting)
return exiting * 4 / total >= numneeded;
else
return false;
}
void G_ExitLevel(void)
{
if (gamestate == GS_LEVEL)
@ -2925,7 +3102,7 @@ boolean G_GametypeUsesLives(void)
// Coop, Competitive
if ((gametype == GT_COOP || gametype == GT_COMPETITION)
&& !(modeattacking || metalrecording) // No lives in Time Attack
//&& !G_IsSpecialStage(gamemap)
&& !G_IsSpecialStage(gamemap)
&& !(maptol & TOL_NIGHTS)) // No lives in NiGHTS
return true;
return false;
@ -3038,12 +3215,51 @@ static INT16 RandMap(INT16 tolflags, INT16 pprevmap)
return ix;
}
//
// G_UpdateVisited
//
static void G_UpdateVisited(void)
{
boolean spec = G_IsSpecialStage(gamemap);
// Update visitation flags?
if ((!modifiedgame || savemoddata) // Not modified
&& !multiplayer && !demoplayback && (gametype == GT_COOP) // SP/RA/NiGHTS mode
&& !(spec && stagefailed)) // Not failed the special stage
{
UINT8 earnedEmblems;
// Update visitation flags
mapvisited[gamemap-1] |= MV_BEATEN;
// eh, what the hell
if (ultimatemode)
mapvisited[gamemap-1] |= MV_ULTIMATE;
// may seem incorrect but IS possible in what the main game uses as special stages, and nummaprings will be -1 in NiGHTS
if (nummaprings > 0 && players[consoleplayer].rings >= nummaprings)
mapvisited[gamemap-1] |= MV_PERFECT;
if (!spec)
{
// not available to special stages because they can only really be done in one order in an unmodified game, so impossible for first six and trivial for seventh
if (ALL7EMERALDS(emeralds))
mapvisited[gamemap-1] |= MV_ALLEMERALDS;
}
if (modeattacking == ATTACKING_RECORD)
G_UpdateRecordReplays();
else if (modeattacking == ATTACKING_NIGHTS)
G_SetNightsRecords();
if ((earnedEmblems = M_CompletionEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
}
}
//
// G_DoCompleted
//
static void G_DoCompleted(void)
{
INT32 i;
boolean spec = G_IsSpecialStage(gamemap);
tokenlist = 0; // Reset the list
@ -3076,14 +3292,14 @@ static void G_DoCompleted(void)
nextmap = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1);
// Remember last map for when you come out of the special stage.
if (!G_IsSpecialStage(gamemap))
if (!spec)
lastmap = nextmap;
// If nextmap is actually going to get used, make sure it points to
// a map of the proper gametype -- skip levels that don't support
// the current gametype. (Helps avoid playing boss levels in Race,
// for instance).
if (!token && !G_IsSpecialStage(gamemap)
if (!token && !spec
&& (nextmap >= 0 && nextmap < NUMMAPS))
{
register INT16 cm = nextmap;
@ -3147,7 +3363,7 @@ static void G_DoCompleted(void)
gottoken = false;
}
if (G_IsSpecialStage(gamemap) && !gottoken)
if (spec && !gottoken)
nextmap = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001
automapactive = false;
@ -3166,17 +3382,29 @@ static void G_DoCompleted(void)
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
P_AllocMapHeader(nextmap);
if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed))
{
G_UpdateVisited();
G_AfterIntermission();
}
else
{
G_SetGamestate(GS_INTERMISSION);
Y_StartIntermission();
G_UpdateVisited();
}
}
void G_AfterIntermission(void)
{
Y_CleanupScreenBuffer();
if (modeattacking)
{
M_EndModeAttackRun();
return;
}
HU_ClearCEcho();
if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1) // Start a custom cutscene.
@ -3343,7 +3571,6 @@ void G_LoadGameData(void)
UINT32 recscore;
tic_t rectime;
UINT16 recrings;
boolean gotperf;
UINT8 recmares;
INT32 curmare;
@ -3441,7 +3668,7 @@ void G_LoadGameData(void)
recscore = READUINT32(save_p);
rectime = (tic_t)READUINT32(save_p);
recrings = READUINT16(save_p);
gotperf = (boolean)READUINT8(save_p);
save_p++; // compat
if (recrings > 10000 || recscore > MAXSCORE)
goto datacorrupt;
@ -3453,9 +3680,6 @@ void G_LoadGameData(void)
mainrecords[i]->time = rectime;
mainrecords[i]->rings = recrings;
}
if (gotperf)
mainrecords[i]->gotperfect = gotperf;
}
// Nights records
@ -3587,15 +3811,14 @@ void G_SaveGameData(void)
WRITEUINT32(save_p, mainrecords[i]->score);
WRITEUINT32(save_p, mainrecords[i]->time);
WRITEUINT16(save_p, mainrecords[i]->rings);
WRITEUINT8(save_p, mainrecords[i]->gotperfect);
}
else
{
WRITEUINT32(save_p, 0);
WRITEUINT32(save_p, 0);
WRITEUINT16(save_p, 0);
WRITEUINT8(save_p, 0);
}
WRITEUINT8(save_p, 0); // compat
}
// NiGHTS records
@ -4031,7 +4254,7 @@ char *G_BuildMapTitle(INT32 mapnum)
len += strlen(mapheaderinfo[mapnum-1]->lvlttl);
if (!(mapheaderinfo[mapnum-1]->levelflags & LF_NOZONE))
{
zonetext = M_GetText("ZONE");
zonetext = M_GetText("Zone");
len += strlen(zonetext) + 1; // ' ' + zonetext
}
if (actnum > 0)
@ -4642,6 +4865,12 @@ void G_WriteGhostTic(mobj_t *ghost)
oldghost.flags2 |= MF2_AMBUSH;
}
if (ghost->player->followmobj->scale != ghost->scale)
{
followtic |= FZT_SCALE;
WRITEFIXED(demo_p,ghost->player->followmobj->scale);
}
temp = (INT16)((ghost->player->followmobj->x-ghost->x)>>8);
WRITEINT16(demo_p,temp);
temp = (INT16)((ghost->player->followmobj->y-ghost->y)>>8);
@ -4653,11 +4882,6 @@ void G_WriteGhostTic(mobj_t *ghost)
WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK));
WRITEUINT8(demo_p,ghost->player->followmobj->color);
if (ghost->player->followmobj->scale != ghost->scale)
{
followtic |= FZT_SCALE;
WRITEFIXED(demo_p,ghost->player->followmobj->scale);
}
*followtic_p = followtic;
}
@ -5194,7 +5418,10 @@ void G_ReadMetalTic(mobj_t *metal)
{ // But wait, there's more!
xziptic = READUINT8(metal_p);
if (xziptic & EZT_FLIP)
{
metal->eflags ^= MFE_VERTICALFLIP;
metal->flags2 ^= MF2_OBJECTFLIP;
}
if (xziptic & EZT_SCALE)
{
metal->destscale = READFIXED(metal_p);
@ -6702,6 +6929,22 @@ boolean G_GetRetryFlag(void)
return retrying;
}
void G_SetModeAttackRetryFlag(void)
{
retryingmodeattack = true;
G_SetRetryFlag();
}
void G_ClearModeAttackRetryFlag(void)
{
retryingmodeattack = false;
}
boolean G_GetModeAttackRetryFlag(void)
{
return retryingmodeattack;
}
// Time utility functions
INT32 G_TicsToHours(tic_t tics)
{

View File

@ -140,7 +140,8 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost);
void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar,
boolean SSSG, boolean FLS);
void G_DoLoadLevel(boolean resetplayer);
void G_StartTitleCard(void);
void G_PreLevelTitleCard(tic_t ticker, boolean update);
void G_DeferedPlayDemo(const char *demo);
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
@ -208,6 +209,7 @@ boolean G_GametypeHasSpectators(void);
boolean G_RingSlingerGametype(void);
boolean G_PlatformGametype(void);
boolean G_TagGametype(void);
boolean G_EnoughPlayersFinished(void);
void G_ExitLevel(void);
void G_NextLevel(void);
void G_Continue(void);
@ -223,10 +225,14 @@ void G_AddPlayer(INT32 playernum);
void G_SetExitGameFlag(void);
void G_ClearExitGameFlag(void);
boolean G_GetExitGameFlag(void);
void G_SetRetryFlag(void);
void G_ClearRetryFlag(void);
boolean G_GetRetryFlag(void);
void G_SetModeAttackRetryFlag(void);
void G_ClearModeAttackRetryFlag(void);
boolean G_GetModeAttackRetryFlag(void);
void G_LoadGameData(void);
void G_LoadGameSettings(void);

View File

@ -771,18 +771,25 @@ void HWR_InitTextureCache(void)
gr_textures2 = NULL;
}
// Callback function for HWR_FreeTextureCache.
static void FreeMipmapColormap(INT32 patchnum, void *patch)
{
GLPatch_t* const grpatch = patch;
GLPatch_t* const pat = patch;
(void)patchnum; //unused
while (grpatch->mipmap->nextcolormap)
while (pat->mipmap && pat->mipmap->nextcolormap) // The mipmap must be valid, obviously
{
GLMipmap_t *grmip = grpatch->mipmap->nextcolormap;
grpatch->mipmap->nextcolormap = grmip->nextcolormap;
if (grmip->grInfo.data) Z_Free(grmip->grInfo.data);
free(grmip);
// Confusing at first, but pat->mipmap->nextcolormap
// at the beginning of the loop is the first colormap
// from the linked list of colormaps
GLMipmap_t *next = pat->mipmap->nextcolormap;
// Set the first colormap
// to the one that comes after it
pat->mipmap->nextcolormap = next->nextcolormap;
// Free image data from memory
if (next->grInfo.data)
Z_Free(next->grInfo.data);
// Free the old colormap from memory
free(next);
}
}
@ -799,7 +806,7 @@ void HWR_FreeTextureCache(void)
// Alam: free the Z_Blocks before freeing it's users
// free all skin after each level: must be done after pfnClearMipMapCache!
// free all patch colormaps after each level: must be done after ClearMipMapCache!
for (i = 0; i < numwadfiles; i++)
M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);

View File

@ -380,9 +380,9 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t
{
FSurfaceInfo Surf;
Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff;
if (alphalevel == 13) Surf.FlatColor.s.alpha = softwaretranstogl_lo[cv_translucenthud.value];
else if (alphalevel == 14) Surf.FlatColor.s.alpha = softwaretranstogl[cv_translucenthud.value];
else if (alphalevel == 15) Surf.FlatColor.s.alpha = softwaretranstogl_hi[cv_translucenthud.value];
if (alphalevel == 13) Surf.FlatColor.s.alpha = softwaretranstogl_lo[st_translucency];
else if (alphalevel == 14) Surf.FlatColor.s.alpha = softwaretranstogl[st_translucency];
else if (alphalevel == 15) Surf.FlatColor.s.alpha = softwaretranstogl_hi[st_translucency];
else Surf.FlatColor.s.alpha = softwaretranstogl[10-alphalevel];
flags |= PF_Modulated;
HWD.pfnDrawPolygon(&Surf, v, 4, flags);
@ -538,9 +538,9 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
{
FSurfaceInfo Surf;
Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff;
if (alphalevel == 13) Surf.FlatColor.s.alpha = softwaretranstogl_lo[cv_translucenthud.value];
else if (alphalevel == 14) Surf.FlatColor.s.alpha = softwaretranstogl[cv_translucenthud.value];
else if (alphalevel == 15) Surf.FlatColor.s.alpha = softwaretranstogl_hi[cv_translucenthud.value];
if (alphalevel == 13) Surf.FlatColor.s.alpha = softwaretranstogl_lo[st_translucency];
else if (alphalevel == 14) Surf.FlatColor.s.alpha = softwaretranstogl[st_translucency];
else if (alphalevel == 15) Surf.FlatColor.s.alpha = softwaretranstogl_hi[st_translucency];
else Surf.FlatColor.s.alpha = softwaretranstogl[10-alphalevel];
flags |= PF_Modulated;
HWD.pfnDrawPolygon(&Surf, v, 4, flags);

View File

@ -184,6 +184,7 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_CANG
&lspr[NOLIGHT], // SPR_PYRE
&lspr[NOLIGHT], // SPR_PTER
&lspr[NOLIGHT], // SPR_DRAB
// Generic Boos Items
&lspr[JETLIGHT_L], // SPR_JETF // Boss jet fumes
@ -505,6 +506,7 @@ light_t *t_lspr[NUMSPRITES] =
// Game Indicators
&lspr[NOLIGHT], // SPR_SCOR
&lspr[NOLIGHT], // SPR_DRWN
&lspr[NOLIGHT], // SPR_FLII
&lspr[NOLIGHT], // SPR_LCKN
&lspr[NOLIGHT], // SPR_TTAG
&lspr[NOLIGHT], // SPR_GFLG
@ -584,7 +586,6 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[SUPERSPARK_L], // SPR_BOM3
&lspr[NOLIGHT], // SPR_BOM4
&lspr[REDBALL_L], // SPR_BMNB
&lspr[NOLIGHT], // SPR_WDDB
// Crumbly rocks
&lspr[NOLIGHT], // SPR_ROIA
@ -604,8 +605,10 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_ROIO
&lspr[NOLIGHT], // SPR_ROIP
// Bricks
// Level debris
&lspr[NOLIGHT], // SPR_GFZD
&lspr[NOLIGHT], // SPR_BRIC
&lspr[NOLIGHT], // SPR_WDDB
// Gravity Well Objects
&lspr[NOLIGHT], // SPR_GWLG

View File

@ -40,6 +40,7 @@
#include "../st_stuff.h"
#include "../i_system.h"
#include "../m_cheat.h"
#include "../f_finale.h"
#ifdef ESLOPE
#include "../p_slopes.h"
#endif
@ -111,7 +112,6 @@ static consvar_t cv_grclipwalls = {"gr_clipwalls", "Off", 0, CV_OnOff, NULL, 0,
static consvar_t cv_gralpha = {"gr_alpha", "160", 0, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
static consvar_t cv_grbeta = {"gr_beta", "0", 0, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
static float HWRWipeCounter = 1.0f;
consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfov = {"gr_fov", "90", CV_FLOAT|CV_CALL, grfov_cons_t, CV_grFov_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfogdensity = {"gr_fogdensity", "150", CV_CALL|CV_NOINIT, CV_Unsigned,
@ -1973,7 +1973,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
{
// Single sided line... Deal only with the middletexture (if one exists)
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture && gr_linedef->special != 41) // Ignore horizon line for OGL
if (gr_midtexture && gr_linedef->special != HORIZONSPECIAL) // Ignore horizon line for OGL
{
{
fixed_t texturevpeg;
@ -4068,6 +4068,7 @@ static gr_vissprite_t *HWR_NewVisSprite(void)
return HWR_GetVisSprite(gr_visspritecount++);
}
#ifdef GLBADSHADOWS
// Finds a floor through which light does not pass.
static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
{
@ -4098,6 +4099,7 @@ static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t hei
return floorz;
}
#endif //#ifdef GLBADSHADOWS
//
// HWR_DoCulling
@ -4139,6 +4141,7 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
return false;
}
#ifdef GLBADSHADOWS
static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale)
{
FOutVector swallVerts[4];
@ -4311,6 +4314,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
}
}
#endif //#ifdef GLBADSHADOWS
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts)
@ -4386,6 +4390,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap);
#ifdef GLBADSHADOWS
// Draw shadow BEFORE sprite
if (cv_shadow.value // Shadows enabled
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
@ -4401,6 +4406,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
////////////////////
HWR_DrawSpriteShadow(spr, gpatch, this_scale);
}
#endif //#ifdef GLBADSHADOWS
baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
@ -4788,6 +4794,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap);
#ifdef GLBADSHADOWS
// Draw shadow BEFORE sprite
if (cv_shadow.value // Shadows enabled
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
@ -4803,6 +4810,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
////////////////////
HWR_DrawSpriteShadow(spr, gpatch, this_scale);
}
#endif //#ifdef GLBADSHADOWS
// if it has a dispoffset, push it a little towards the camera
if (spr->dispoffset) {
@ -7017,7 +7025,6 @@ void HWR_StartScreenWipe(void)
void HWR_EndScreenWipe(void)
{
HWRWipeCounter = 0.0f;
//CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n");
HWD.pfnEndScreenWipe();
}
@ -7027,38 +7034,55 @@ void HWR_DrawIntermissionBG(void)
HWD.pfnDrawIntermissionBG();
}
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
//
// hwr mode wipes
//
static lumpnum_t wipelumpnum;
// puts wipe lumpname in wipename[9]
static boolean HWR_WipeCheck(UINT8 wipenum, UINT8 scrnnum)
{
static char lumpname[9] = "FADEmmss";
lumpnum_t lumpnum;
size_t lsize;
if (wipenum > 99 || scrnnum > 99) // not a valid wipe number
return; // shouldn't end up here really, the loop should've stopped running beforehand
// not a valid wipe number
if (wipenum > 99 || scrnnum > 99)
return false; // shouldn't end up here really, the loop should've stopped running beforehand
// puts the numbers into the lumpname
sprintf(&lumpname[4], "%.2hu%.2hu", (UINT16)wipenum, (UINT16)scrnnum);
lumpnum = W_CheckNumForName(lumpname);
// puts the numbers into the wipename
lumpname[4] = '0'+(wipenum/10);
lumpname[5] = '0'+(wipenum%10);
lumpname[6] = '0'+(scrnnum/10);
lumpname[7] = '0'+(scrnnum%10);
wipelumpnum = W_CheckNumForName(lumpname);
if (lumpnum == LUMPERROR) // again, shouldn't be here really
return;
lsize = W_LumpLength(lumpnum);
// again, shouldn't be here really
if (wipelumpnum == LUMPERROR)
return false;
lsize = W_LumpLength(wipelumpnum);
if (!(lsize == 256000 || lsize == 64000 || lsize == 16000 || lsize == 4000))
{
CONS_Alert(CONS_WARNING, "Fade mask lump %s of incorrect size, ignored\n", lumpname);
return; // again, shouldn't get here if it is a bad size
return false; // again, shouldn't get here if it is a bad size
}
HWR_GetFadeMask(lumpnum);
return true;
}
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
{
if (!HWR_WipeCheck(wipenum, scrnnum))
return;
HWR_GetFadeMask(wipelumpnum);
HWD.pfnDoScreenWipe();
}
HWRWipeCounter += 0.05f; // increase opacity of end screen
if (HWRWipeCounter > 1.0f)
HWRWipeCounter = 1.0f;
void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum)
{
// It does the same thing
HWR_DoWipe(wipenum, scrnnum);
}
void HWR_MakeScreenFinalTexture(void)

View File

@ -66,6 +66,7 @@ void HWR_StartScreenWipe(void);
void HWR_EndScreenWipe(void);
void HWR_DrawIntermissionBG(void);
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum);
void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum);
void HWR_MakeScreenFinalTexture(void);
void HWR_DrawScreenFinalTexture(int width, int height);

View File

@ -2587,7 +2587,6 @@ EXPORT void HWRAPI(DoScreenWipe)(void)
tex_downloaded = endScreenWipe;
}
// Create a texture from the screen.
EXPORT void HWRAPI(MakeScreenTexture) (void)
{

View File

@ -2322,13 +2322,14 @@ void HU_Erase(void)
//
// HU_drawPing
//
void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext)
void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags)
{
UINT8 numbars = 1; // how many ping bars do we draw?
UINT8 barcolor = 35; // color we use for the bars (green, yellow or red)
SINT8 i = 0;
SINT8 yoffset = 6;
INT32 dx = x+1 - (V_SmallStringWidth(va("%dms", ping), V_ALLOWLOWERCASE)/2);
INT32 dx = x+1 - (V_SmallStringWidth(va("%dms", ping),
V_ALLOWLOWERCASE|flags)/2);
if (ping < 128)
{
@ -2342,13 +2343,13 @@ void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext)
}
if (!notext || vid.width >= 640) // how sad, we're using a shit resolution.
V_DrawSmallString(dx, y+4, V_ALLOWLOWERCASE, va("%dms", ping));
V_DrawSmallString(dx, y+4, V_ALLOWLOWERCASE|flags, va("%dms", ping));
for (i=0; (i<3); i++) // Draw the ping bar
{
V_DrawFill(x+2 *(i-1), y+yoffset-4, 2, 8-yoffset, 31);
V_DrawFill(x+2 *(i-1), y+yoffset-4, 2, 8-yoffset, 31|flags);
if (i < numbars)
V_DrawFill(x+2 *(i-1), y+yoffset-3, 1, 8-yoffset-1, barcolor);
V_DrawFill(x+2 *(i-1), y+yoffset-3, 1, 8-yoffset-1, barcolor|flags);
yoffset -= 2;
}
@ -2379,7 +2380,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
if (!splitscreen) // don't draw it on splitscreen,
{
if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 253, y+2, playerpingtable[tab[i].num], false);
HU_drawPing(x+ 253, y, playerpingtable[tab[i].num], false, 0);
//else
// V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER");
}
@ -2443,7 +2444,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
V_DrawSmallScaledPatch(x-32, y-4, 0, tagico);
}
if (players[tab[i].num].exiting)
if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
if (gametype == GT_RACE)
@ -2578,7 +2579,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (!splitscreen)
{
if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 135, y+3, playerpingtable[tab[i].num], true);
HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
//else
//V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
}
@ -2702,7 +2703,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (!splitscreen)
{
if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 113, y+2, playerpingtable[tab[i].num], false);
HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
//else
// V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
}
@ -2733,7 +2734,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
strlcpy(name, tab[i].name, 7);
if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 113, y+2, playerpingtable[tab[i].num], false);
HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
//else
// V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
@ -2747,7 +2748,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);
if (players[tab[i].num].exiting)
if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
// Draw emeralds
@ -2841,7 +2842,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
if (!splitscreen) // don't draw it on splitscreen,
{
if (!(tab[i].num == serverplayer))
HU_drawPing(x+ 135, y+3, playerpingtable[tab[i].num], true);
HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
//else
// V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
}

View File

@ -28,7 +28,7 @@
// Level title font
#define LT_FONTSTART '!' // the first font characters
#define LT_FONTEND 'Z' // the last font characters
#define LT_FONTEND 'z' // the last font characters
#define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1)
#define CRED_FONTSTART '!' // the first font character
@ -113,7 +113,7 @@ void HU_Drawer(void);
char HU_dequeueChatChar(void);
void HU_Erase(void);
void HU_clearChatChars(void);
void HU_drawPing(INT32 x, INT32 y, INT32 ping, boolean notext); // Lat': Ping drawer for scoreboard.
void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags); // Lat': Ping drawer for scoreboard.
void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);
void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer);
void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);

View File

@ -72,6 +72,7 @@ char sprnames[NUMSPRITES + 1][5] =
"CANG", // Canarivore gas
"PYRE", // Pyre Fly
"PTER", // Pterabyte
"DRAB", // Dragonbomber
// Generic Boss Items
"JETF", // Boss jet fumes
@ -402,6 +403,7 @@ char sprnames[NUMSPRITES + 1][5] =
// Game Indicators
"SCOR", // Score logo
"DRWN", // Drowning Timer
"FLII", // Flight indicator
"LCKN", // Target
"TTAG", // Tag Sign
"GFLG", // Got Flag sign
@ -481,7 +483,6 @@ char sprnames[NUMSPRITES + 1][5] =
"BOM3", // Boss Explosion 2
"BOM4", // Underwater Explosion
"BMNB", // Mine Explosion
"WDDB", // Wood Debris
// Crumbly rocks
"ROIA",
@ -501,8 +502,10 @@ char sprnames[NUMSPRITES + 1][5] =
"ROIO",
"ROIP",
// Bricks
"BRIC",
// Level debris
"GFZD", // GFZ debris
"BRIC", // Bricks
"WDDB", // Wood Debris
// Gravity Well Objects
"GWLG",
@ -632,7 +635,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
0, // SPR2_TRNS,
FF_SPR2SUPER|SPR2_STND, // SPR2_NSTD,
FF_SPR2SUPER|SPR2_FLT , // SPR2_NFLT,
FF_SPR2SUPER|SPR2_FALL, // SPR2_NFLT,
0, // SPR2_NFLY, (will never be referenced unless skin 0 lacks this)
SPR2_NFLY, // SPR2_NDRL,
FF_SPR2SUPER|SPR2_STUN, // SPR2_NSTN,
@ -1071,23 +1074,11 @@ state_t states[NUMSTATES] =
{SPR_MNUD, 2|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST4}, // S_MINUS_BURST3
{SPR_MNUD, 3|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST5}, // S_MINUS_BURST4
{SPR_MNUD, 4|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUSDIRT2}, // S_MINUS_BURST5
{SPR_MNUS, 0, 1, {A_MinusPopup}, 0, 0, S_MINUS_UPWARD1}, // S_MINUS_POPUP
{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD2}, // S_MINUS_UPWARD1
{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD3}, // S_MINUS_UPWARD2
{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD4}, // S_MINUS_UPWARD3
{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD5}, // S_MINUS_UPWARD4
{SPR_MNUS, 4, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD6}, // S_MINUS_UPWARD5
{SPR_MNUS, 5, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD7}, // S_MINUS_UPWARD6
{SPR_MNUS, 6, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD8}, // S_MINUS_UPWARD7
{SPR_MNUS, 7, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD1}, // S_MINUS_UPWARD8
{SPR_MNUS, 8, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD2}, // S_MINUS_DOWNWARD1
{SPR_MNUS, 9, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD3}, // S_MINUS_DOWNWARD2
{SPR_MNUS, 10, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD4}, // S_MINUS_DOWNWARD3
{SPR_MNUS, 11, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD5}, // S_MINUS_DOWNWARD4
{SPR_MNUS, 12, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD6}, // S_MINUS_DOWNWARD5
{SPR_MNUS, 13, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD7}, // S_MINUS_DOWNWARD6
{SPR_MNUS, 14, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD8}, // S_MINUS_DOWNWARD7
{SPR_MNUS, 15, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD1}, // S_MINUS_DOWNWARD8
{SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1}, // S_MINUS_POPUP
{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2}, // S_MINUS_AERIAL1
{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3}, // S_MINUS_AERIAL2
{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4}, // S_MINUS_AERIAL3
{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1}, // S_MINUS_AERIAL4
{SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1
{SPR_MNUD, 5, 8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2
@ -1163,6 +1154,26 @@ state_t states[NUMSTATES] =
{SPR_PTER, 4, 1, {NULL}, 0, 0, S_PTERABYTE_SWOOPDOWN}, // S_PTERABYTE_SWOOPDOWN
{SPR_PTER, 0, 1, {NULL}, 0, 0, S_PTERABYTE_SWOOPUP}, // S_PTERABYTE_SWOOPUP
// Dragonbomber
{SPR_DRAB, 0, -1, {A_DragonbomberSpawn}, 6, 0, S_NULL}, // S_DRAGONBOMBER
{SPR_DRAB, FF_PAPERSPRITE|7, 1, {A_DragonWing}, 0, 0, S_DRAGONWING2}, // S_DRAGONWING1
{SPR_DRAB, FF_PAPERSPRITE|8, 1, {A_DragonWing}, 0, 0, S_DRAGONWING3}, // S_DRAGONWING2
{SPR_DRAB, FF_PAPERSPRITE|9, 1, {A_DragonWing}, 0, 0, S_DRAGONWING4}, // S_DRAGONWING3
{SPR_DRAB, FF_PAPERSPRITE|10, 1, {A_DragonWing}, 0, 0, S_DRAGONWING1}, // S_DRAGONWING4
{SPR_DRAB, 1, 1, {A_DragonSegment}, 0, 0, S_DRAGONTAIL_LOADED}, // S_DRAGONTAIL_LOADED
{SPR_DRAB, 2, 1, {A_DragonSegment}, 0, 0, S_DRAGONTAIL_EMPTYLOOP}, // S_DRAGONTAIL_EMPTY
{SPR_DRAB, 2, 0, {A_Repeat}, 3*TICRATE, S_DRAGONTAIL_EMPTY, S_DRAGONTAIL_RELOAD}, // S_DRAGONTAIL_EMPTYLOOP
{SPR_DRAB, 1, 0, {A_PlayActiveSound}, 0, 0, S_DRAGONTAIL_LOADED}, // S_DRAGONTAIL_RELOAD
{SPR_DRAB, 3, 1, {A_MinusCheck}, S_DRAGONMINE_LAND1, 0, S_DRAGONMINE}, // S_DRAGONMINE
{SPR_DRAB, 4, 0, {A_PlayActiveSound}, 0, 0, S_DRAGONMINE_LAND2}, // S_DRAGONMINE_LAND1
{SPR_DRAB, 4, 2, {A_Thrust}, 0, 1, S_DRAGONMINE_SLOWFLASH1}, // S_DRAGONMINE_LAND2
{SPR_DRAB, 5, 11, {NULL}, 0, 0, S_DRAGONMINE_SLOWFLASH2}, // S_DRAGONMINE_SLOWFLASH1
{SPR_DRAB, FF_FULLBRIGHT|6, 1, {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_SLOWLOOP}, // S_DRAGONMINE_SLOWFLASH2
{SPR_DRAB, 5, 0, {A_Repeat}, 4, S_DRAGONMINE_SLOWFLASH1, S_DRAGONMINE_FASTFLASH1}, // S_DRAGONMINE_SLOWLOOP
{SPR_DRAB, 5, 3, {NULL}, 0, 0, S_DRAGONMINE_FASTFLASH2}, // S_DRAGONMINE_FASTFLASH1
{SPR_DRAB, FF_FULLBRIGHT|6, 1, {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_FASTLOOP}, // S_DRAGONMINE_FASTFLASH2
{SPR_DRAB, 5, 0, {A_Repeat}, 5, S_DRAGONMINE_FASTFLASH1, S_DEATHSTATE}, // S_DRAGONMINE_FASTLOOP
// Boss Explosion
{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE
@ -1487,6 +1498,7 @@ state_t states[NUMSTATES] =
{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNA
{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNB
{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNC
{SPR_FSGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGND
// Black Eggman (Boss 7)
{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND
@ -3319,6 +3331,9 @@ state_t states[NUMSTATES] =
{SPR_DRWN, 10, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR2
{SPR_DRWN, 11, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE2
// Flight indicator
{SPR_FLII, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 4, S_NULL}, // S_FLIGHTINDICATOR
{SPR_LCKN, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON1
{SPR_LCKN, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON2
{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON3
@ -3527,13 +3542,9 @@ state_t states[NUMSTATES] =
{SPR_FFWR, 3, 3, {NULL}, 0, 0, S_FIREFLOWER1}, // S_FIREFLOWER4
// Thrown Mario Fireball
{SPR_FBLL, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FIREBALL2}, // S_FIREBALL1
{SPR_FBLL, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_FIREBALL3}, // S_FIREBALL2
{SPR_FBLL, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_FIREBALL4}, // S_FIREBALL3
{SPR_FBLL, FF_FULLBRIGHT|3, 3, {NULL}, 0, 0, S_FIREBALL1}, // S_FIREBALL4
{SPR_FBLL, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_FIREBALLEXP2}, // S_FIREBALLEXP1
{SPR_FBLL, FF_FULLBRIGHT|5, 3, {NULL}, 0, 0, S_FIREBALLEXP3}, // S_FIREBALLEXP2
{SPR_FBLL, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_FIREBALLEXP3
{SPR_FBLL, FF_FULLBRIGHT, 1, {A_SpawnObjectRelative}, 0, MT_FIREBALLTRAIL, S_FIREBALL}, // S_FIREBALL
{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 1, {A_SetScale}, FRACUNIT*3/4, 0, S_FIREBALLTRAIL2}, // S_FIREBALLTRAIL1
{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 8, {A_SetScale}, FRACUNIT/6, 1, S_NULL}, // S_FIREBALLTRAIL2
// Turtle Shell
{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHELL
@ -3722,9 +3733,12 @@ state_t states[NUMSTATES] =
{SPR_PENG, 0, 5, {A_FaceTarget}, 0, 0, S_PENGUINATOR_LOOK}, // S_PENGUINATOR_SLIDE5
{SPR_POPH, 0, 2, {A_Look}, (2048<<16)|1, 0, S_POPHAT_LOOK}, // S_POPHAT_LOOK
{SPR_POPH, 1, 2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1
{SPR_POPH, 2, 1, {NULL}, 0, 0, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2
{SPR_POPH, 0, 57, {NULL}, 0, 0, S_POPHAT_LOOK}, // S_POPHAT_SHOOT3
{SPR_POPH, 1, 0, {A_MultiShotDist}, (MT_SPINDUST<<16)|4, 24, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1
{SPR_POPH, 1, 2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2
{SPR_POPH, 2, 1, {NULL}, 0, 0, S_POPHAT_SHOOT4}, // S_POPHAT_SHOOT3
{SPR_POPH, 0, 57, {NULL}, 0, 0, S_POPHAT_LOOK}, // S_POPHAT_SHOOT4
{SPR_POPH, 3, 3, {A_SpawnObjectRelative}, 0, MT_POPSHOT_TRAIL, S_POPSHOT}, // S_POPSHOT
{SPR_NULL, 0, 2, {NULL}, 0, 0, S_SPINDUST1}, // S_POPSHOT_TRAIL
{SPR_HIVE, 0, 5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK
{SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1
@ -3858,8 +3872,6 @@ state_t states[NUMSTATES] =
{SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4}, // S_DUST3
{SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_DUST4
{SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_WOODDEBRIS
{SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN
{SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA
@ -3879,7 +3891,9 @@ state_t states[NUMSTATES] =
{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEO
{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEP
{SPR_GFZD, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_GFZDEBRIS
{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS
{SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_WOODDEBRIS
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
@ -5238,6 +5252,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_DRAGONBOMBER
137, // doomednum
S_DRAGONBOMBER, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
6, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_XPLD_FLICKY, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
10*FRACUNIT, // speed
28*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_BOUNCE|MF_RUNSPAWNFUNC, // flags
S_NULL // raisestate
},
{ // MT_DRAGONWING
-1, // doomednum
S_DRAGONWING1, // 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_XPLD_FLICKY, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
0, // speed
12*FRACUNIT, // radius
12*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP, // flags
S_NULL // raisestate
},
{ // MT_DRAGONTAIL
-1, // doomednum
S_DRAGONTAIL_LOADED, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
MT_DRAGONMINE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_XPLD1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
20*FRACUNIT, // radius
40*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_tink, // activesound
MF_NOGRAVITY|MF_SLIDEME|MF_PAIN, // flags
S_DRAGONTAIL_EMPTY // raisestate
},
{ // MT_DRAGONMINE
-1, // doomednum
S_DRAGONMINE, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_s3k76, // seesound
0, // reactiontime
sfx_s3k89, // attacksound
S_NULL, // painstate
6, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_TNTBARREL_EXPL1, // deathstate
S_NULL, // xdeathstate
sfx_s3k6e, // deathsound
0, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_s3k5d, // activesound
MF_SPECIAL|MF_SHOOTABLE, // flags
S_NULL // raisestate
},
{ // MT_BOSSEXPLODE
-1, // doomednum
S_BOSSEXPLODE, // spawnstate
@ -6115,11 +6237,11 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // meleestate
S_NULL, // missilestate
S_FSGNC, // deathstate
S_NULL, // xdeathstate
S_FSGND, // xdeathstate
sfx_None, // deathsound
0, // speed
124*FRACUNIT, // radius
640*FRACUNIT, // height
74*FRACUNIT, // radius
320*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
@ -13247,7 +13369,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_PAIN|MF_NOGRAVITY, // flags
MF_SPECIAL|MF_PAIN|MF_NOGRAVITY|MF_FIRE, // flags
S_NULL // raisestate
},
@ -13315,7 +13437,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // attacksound
S_NULL, // painstate
12*TICRATE, // painchance (sets how long an unridden rock should last before disappearing - set to 0 to disable)
sfx_None, // painsound
sfx_s3k49, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
@ -18910,31 +19032,58 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_FIREBALL
-1, // doomednum
S_FIREBALL1, // spawnstate
S_FIREBALL, // spawnstate
1000, // spawnhealth
S_FIREBALLEXP1, // seestate
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_FIREBALLEXP1, // meleestate
S_FIREBALLEXP1, // missilestate
S_FIREBALLEXP1, // deathstate
S_FIREBALLEXP1, // xdeathstate
sfx_mario1, // deathsound
10*FRACUNIT, // speed
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
40*FRACUNIT, // speed
4*FRACUNIT, // radius
8*FRACUNIT, // height
0, // display offset
DMG_FIRE, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_FIRE|MF_MISSILE, // flags
MF_FIRE|MF_BOUNCE|MF_MISSILE, // flags
S_NULL // raisestate
},
{ // MT_FIREBALLTRAIL
-1, // doomednum
S_FIREBALLTRAIL1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
0, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_RUNSPAWNFUNC, // flags
S_NULL // raisestate
},
{ // MT_SHELL
1804, // doomednum
S_SHELL, // spawnstate
@ -19989,10 +20138,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_POPSHOT
-1, // doomednum
S_ROCKCRUMBLEI, // spawnstate
S_POPSHOT, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_cannon, // seesound
sfx_kc4c, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -20000,9 +20149,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_XPLD1, // deathstate
S_SONIC3KBOSSEXPLOSION1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
sfx_cybdth, // deathsound
0, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
@ -20014,6 +20163,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_POPSHOT_TRAIL
-1, // doomednum
S_POPSHOT_TRAIL,// spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
4*FRACUNIT, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
4, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags
S_NULL // raisestate
},
{ // MT_HIVEELEMENTAL
127, // doomednum
S_HIVEELEMENTAL_LOOK, // spawnstate
@ -20773,33 +20949,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_WOODDEBRIS
-1, // doomednum
S_WOODDEBRIS, // spawnstate
1, // 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_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_wbreak, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_ROCKSPAWNER
1202, // doomednum
S_ROCKSPAWN, // spawnstate
@ -21286,16 +21435,16 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BRICKDEBRIS
{ // MT_GFZDEBRIS
-1, // doomednum
S_BRICKDEBRIS, // spawnstate
1, // spawnhealth
S_GFZDEBRIS, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
@ -21303,16 +21452,70 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_crumbl, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_BRICKDEBRIS
-1, // doomednum
S_BRICKDEBRIS, // spawnstate
1, // 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_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
100, // mass
0, // damage
sfx_None, // activesound
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_WOODDEBRIS
-1, // doomednum
S_WOODDEBRIS, // spawnstate
1, // 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_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_wbreak, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
#ifdef SEENAMES
{ // MT_NAMECHECK
-1, // doomednum

View File

@ -282,6 +282,9 @@ void A_SpawnPterabytes();
void A_PterabyteHover();
void A_RolloutSpawn();
void A_RolloutRock();
void A_DragonbomberSpawn();
void A_DragonWing();
void A_DragonSegment();
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1
#define NUMMOBJFREESLOTS 512
@ -334,6 +337,7 @@ typedef enum sprite
SPR_CANG, // Canarivore gas
SPR_PYRE, // Pyre Fly
SPR_PTER, // Pterabyte
SPR_DRAB, // Dragonbomber
// Generic Boss Items
SPR_JETF, // Boss jet fumes
@ -664,6 +668,7 @@ typedef enum sprite
// Game Indicators
SPR_SCOR, // Score logo
SPR_DRWN, // Drowning Timer
SPR_FLII, // AI flight indicator
SPR_LCKN, // Target
SPR_TTAG, // Tag Sign
SPR_GFLG, // Got Flag sign
@ -743,7 +748,6 @@ typedef enum sprite
SPR_BOM3, // Boss Explosion 2
SPR_BOM4, // Underwater Explosion
SPR_BMNB, // Mine Explosion
SPR_WDDB, // Wood Debris
// Crumbly rocks
SPR_ROIA,
@ -763,8 +767,10 @@ typedef enum sprite
SPR_ROIO,
SPR_ROIP,
// Bricks
SPR_BRIC,
// Level debris
SPR_GFZD, // GFZ debris
SPR_BRIC, // Bricks
SPR_WDDB, // Wood Debris
// Gravity Well Objects
SPR_GWLG,
@ -1264,22 +1270,10 @@ typedef enum state
S_MINUS_BURST4,
S_MINUS_BURST5,
S_MINUS_POPUP,
S_MINUS_UPWARD1,
S_MINUS_UPWARD2,
S_MINUS_UPWARD3,
S_MINUS_UPWARD4,
S_MINUS_UPWARD5,
S_MINUS_UPWARD6,
S_MINUS_UPWARD7,
S_MINUS_UPWARD8,
S_MINUS_DOWNWARD1,
S_MINUS_DOWNWARD2,
S_MINUS_DOWNWARD3,
S_MINUS_DOWNWARD4,
S_MINUS_DOWNWARD5,
S_MINUS_DOWNWARD6,
S_MINUS_DOWNWARD7,
S_MINUS_DOWNWARD8,
S_MINUS_AERIAL1,
S_MINUS_AERIAL2,
S_MINUS_AERIAL3,
S_MINUS_AERIAL4,
// Minus dirt
S_MINUSDIRT1,
@ -1355,6 +1349,26 @@ typedef enum state
S_PTERABYTE_SWOOPDOWN,
S_PTERABYTE_SWOOPUP,
// Dragonbomber
S_DRAGONBOMBER,
S_DRAGONWING1,
S_DRAGONWING2,
S_DRAGONWING3,
S_DRAGONWING4,
S_DRAGONTAIL_LOADED,
S_DRAGONTAIL_EMPTY,
S_DRAGONTAIL_EMPTYLOOP,
S_DRAGONTAIL_RELOAD,
S_DRAGONMINE,
S_DRAGONMINE_LAND1,
S_DRAGONMINE_LAND2,
S_DRAGONMINE_SLOWFLASH1,
S_DRAGONMINE_SLOWFLASH2,
S_DRAGONMINE_SLOWLOOP,
S_DRAGONMINE_FASTFLASH1,
S_DRAGONMINE_FASTFLASH2,
S_DRAGONMINE_FASTLOOP,
// Boss Explosion
S_BOSSEXPLODE,
@ -1657,6 +1671,7 @@ typedef enum state
S_FSGNA,
S_FSGNB,
S_FSGNC,
S_FSGND,
// Black Eggman (Boss 7)
S_BLACKEGG_STND,
@ -3454,6 +3469,8 @@ typedef enum state
S_FOUR2,
S_FIVE2,
S_FLIGHTINDICATOR,
S_LOCKON1,
S_LOCKON2,
S_LOCKON3,
@ -3637,13 +3654,9 @@ typedef enum state
S_FIREFLOWER2,
S_FIREFLOWER3,
S_FIREFLOWER4,
S_FIREBALL1,
S_FIREBALL2,
S_FIREBALL3,
S_FIREBALL4,
S_FIREBALLEXP1,
S_FIREBALLEXP2,
S_FIREBALLEXP3,
S_FIREBALL,
S_FIREBALLTRAIL1,
S_FIREBALLTRAIL2,
S_SHELL,
S_PUMA_START1,
S_PUMA_START2,
@ -3812,6 +3825,9 @@ typedef enum state
S_POPHAT_SHOOT1,
S_POPHAT_SHOOT2,
S_POPHAT_SHOOT3,
S_POPHAT_SHOOT4,
S_POPSHOT,
S_POPSHOT_TRAIL,
S_HIVEELEMENTAL_LOOK,
S_HIVEELEMENTAL_PREPARE1,
@ -3943,8 +3959,6 @@ typedef enum state
S_DUST3,
S_DUST4,
S_WOODDEBRIS,
S_ROCKSPAWN,
S_ROCKCRUMBLEA,
@ -3964,8 +3978,10 @@ typedef enum state
S_ROCKCRUMBLEO,
S_ROCKCRUMBLEP,
// Bricks
// Level debris
S_GFZDEBRIS,
S_BRICKDEBRIS,
S_WOODDEBRIS,
#ifdef SEENAMES
S_NAMECHECK,
@ -4049,6 +4065,10 @@ typedef enum mobj_type
MT_PTERABYTESPAWNER, // Pterabyte spawner
MT_PTERABYTEWAYPOINT, // Pterabyte waypoint
MT_PTERABYTE, // Pterabyte
MT_DRAGONBOMBER, // Dragonbomber
MT_DRAGONWING, // Dragonbomber wing
MT_DRAGONTAIL, // Dragonbomber tail segment
MT_DRAGONMINE, // Dragonbomber mine
// Generic Boss Items
MT_BOSSEXPLODE,
@ -4654,6 +4674,7 @@ typedef enum mobj_type
MT_BLUEGOOMBA,
MT_FIREFLOWER,
MT_FIREBALL,
MT_FIREBALLTRAIL,
MT_SHELL,
MT_PUMA,
MT_PUMATRAIL,
@ -4698,6 +4719,7 @@ typedef enum mobj_type
MT_PENGUINATOR,
MT_POPHAT,
MT_POPSHOT,
MT_POPSHOT_TRAIL,
MT_HIVEELEMENTAL,
MT_BUMBLEBORE,
@ -4735,7 +4757,6 @@ typedef enum mobj_type
MT_EXPLODE, // Robot Explosion
MT_UWEXPLODE, // Underwater Explosion
MT_DUST,
MT_WOODDEBRIS,
MT_ROCKSPAWNER,
MT_FALLINGROCK,
MT_ROCKCRUMBLE1,
@ -4755,8 +4776,10 @@ typedef enum mobj_type
MT_ROCKCRUMBLE15,
MT_ROCKCRUMBLE16,
// Bricks
// Level debris
MT_GFZDEBRIS,
MT_BRICKDEBRIS,
MT_WOODDEBRIS,
#ifdef SEENAMES
MT_NAMECHECK,

View File

@ -1165,6 +1165,17 @@ static int lib_pElementalFire(lua_State *L)
return 0;
}
static int lib_pDoPlayerFinish(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_DoPlayerFinish(player);
return 0;
}
static int lib_pDoPlayerExit(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -2674,6 +2685,13 @@ static int lib_gSetCustomExitVars(lua_State *L)
return 0;
}
static int lib_gEnoughPlayersFinished(lua_State *L)
{
INLEVEL
lua_pushboolean(L, G_EnoughPlayersFinished());
return 1;
}
static int lib_gExitLevel(lua_State *L)
{
int n = lua_gettop(L); // Num arguments
@ -2869,6 +2887,7 @@ static luaL_Reg lib[] = {
{"P_DoBubbleBounce",lib_pDoBubbleBounce},
{"P_BlackOw",lib_pBlackOw},
{"P_ElementalFire",lib_pElementalFire},
{"P_DoPlayerFinish",lib_pDoPlayerFinish},
{"P_DoPlayerExit",lib_pDoPlayerExit},
{"P_InstaThrust",lib_pInstaThrust},
{"P_ReturnThrustX",lib_pReturnThrustX},
@ -2981,6 +3000,7 @@ static luaL_Reg lib[] = {
{"G_BuildMapName",lib_gBuildMapName},
{"G_DoReborn",lib_gDoReborn},
{"G_SetCustomExitVars",lib_gSetCustomExitVars},
{"G_EnoughPlayersFinished",lib_gEnoughPlayersFinished},
{"G_ExitLevel",lib_gExitLevel},
{"G_IsSpecialStage",lib_gIsSpecialStage},
{"G_GametypeUsesLives",lib_gGametypeUsesLives},

View File

@ -43,3 +43,4 @@ boolean LUA_HudEnabled(enum hud option);
void LUAh_GameHUD(player_t *stplyr);
void LUAh_ScoresHUD(void);
void LUAh_TitleHUD(void);
void LUAh_TitleCardHUD(player_t *stplyr);

View File

@ -92,12 +92,14 @@ static const char *const patch_opt[] = {
enum hudhook {
hudhook_game = 0,
hudhook_scores,
hudhook_title
hudhook_title,
hudhook_titlecard
};
static const char *const hudhook_opt[] = {
"game",
"scores",
"title",
"titlecard",
NULL};
// alignment types for v.drawString
@ -910,9 +912,17 @@ static int libd_RandomChance(lua_State *L)
return 1;
}
// 30/10/18 Lat': Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int
// 30/10/18 Lat': Get st_translucency's value for HUD rendering as a normal V_xxTRANS int
// Could as well be thrown in global vars for ease of access but I guess it makes sense for it to be a HUD fn
static int libd_getlocaltransflag(lua_State *L)
{
HUDONLY
lua_pushinteger(L, (10-st_translucency)*V_10TRANS);
return 1;
}
// Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int
static int libd_getusertransflag(lua_State *L)
{
HUDONLY
lua_pushinteger(L, (10-cv_translucenthud.value)*V_10TRANS); // A bit weird that it's called "translucenthud" yet 10 is fully opaque :V
@ -954,6 +964,7 @@ static luaL_Reg lib_draw[] = {
{"dupy", libd_dupy},
{"renderer", libd_renderer},
{"localTransFlag", libd_getlocaltransflag},
{"userTransFlag", libd_getusertransflag},
{NULL, NULL}
};
@ -1043,6 +1054,9 @@ int LUA_HudLib(lua_State *L)
lua_newtable(L);
lua_rawseti(L, -2, 4); // HUD[3] = title rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 5); // HUD[4] = title card rendering functions array
lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
luaL_newmetatable(L, META_HUDINFO);
@ -1180,4 +1194,38 @@ void LUAh_TitleHUD(void)
hud_running = false;
}
void LUAh_TitleCardHUD(player_t *stplayr)
{
if (!gL || !(hudAvailable & (1<<hudhook_titlecard)))
return;
hud_running = true;
lua_pop(gL, -1);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 5); // HUD[5] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
LUA_PushUserdata(gL, stplayr, META_PLAYER);
lua_pushinteger(gL, lt_ticker);
lua_pushinteger(gL, (lt_endtime + TICRATE));
lua_pushnil(gL);
while (lua_next(gL, -6) != 0) {
lua_pushvalue(gL, -6); // graphics library (HUD[1])
lua_pushvalue(gL, -6); // stplayr
lua_pushvalue(gL, -6); // lt_ticker
lua_pushvalue(gL, -6); // lt_endtime
LUA_Call(gL, 4);
}
lua_pop(gL, -1);
hud_running = false;
}
#endif

View File

@ -744,7 +744,7 @@ static int power_get(lua_State *L)
UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS));
powertype_t p = luaL_checkinteger(L, 2);
if (p >= NUMPOWERS)
return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p);
return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p);
lua_pushinteger(L, powers[p]);
return 1;
}
@ -756,7 +756,7 @@ static int power_set(lua_State *L)
powertype_t p = luaL_checkinteger(L, 2);
UINT16 i = (UINT16)luaL_checkinteger(L, 3);
if (p >= NUMPOWERS)
return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p);
return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p);
if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
powers[p] = i;

View File

@ -16,6 +16,7 @@
#include "doomdef.h"
#include "command.h"
#include "m_argv.h"
#include "m_misc.h"
/** \brief number of arg
*/
@ -161,7 +162,7 @@ void M_FindResponseFile(void)
if (!file)
I_Error("No more free memory for the response file");
if (fread(file, size, 1, handle) != 1)
I_Error("Couldn't read response file because %s", strerror(ferror(handle)));
I_Error("Couldn't read response file because %s", M_FileError(handle));
fclose(handle);
// keep all the command line arguments following @responsefile

View File

@ -284,6 +284,8 @@ void M_SilentUpdateUnlockablesAndEmblems(void)
continue;
unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1);
}
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
}
// Emblem unlocking shit

View File

@ -201,14 +201,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedDiv(fixed_t a, fixed_t b)
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRem(fixed_t x, fixed_t y)
{
const boolean n = x < 0;
x = abs(x);
while (x >= y)
x -= y;
if (n)
return -x;
else
return x;
return x % y;
}
/** \brief The FixedSqrt function

View File

@ -312,9 +312,7 @@ menu_t OP_VideoOptionsDef, OP_VideoModeDef, OP_ColorOptionsDef;
menu_t OP_OpenGLOptionsDef, OP_OpenGLFogDef, OP_OpenGLColorDef;
#endif
menu_t OP_SoundOptionsDef;
#ifdef HAVE_MIXERX
menu_t OP_SoundAdvancedDef;
#endif
//Misc
menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef;
@ -474,25 +472,25 @@ static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dum
// ---------
static menuitem_t MainMenu[] =
{
{IT_STRING|IT_CALL, NULL, "Secrets", M_SecretsMenu, 76},
{IT_STRING|IT_CALL, NULL, "1 player", M_SinglePlayerMenu, 84},
{IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76},
#ifndef NONET
{IT_STRING|IT_SUBMENU, NULL, "multiplayer", &MP_MainDef, 92},
{IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84},
#else
{IT_STRING|IT_CALL, NULL, "multiplayer", M_StartSplitServerMenu, 92},
{IT_STRING|IT_CALL, NULL, "Multiplayer", M_StartSplitServerMenu, 84},
#endif
{IT_STRING|IT_CALL, NULL, "options", M_Options, 100},
{IT_CALL |IT_STRING, NULL, "addons", M_Addons, 108},
{IT_STRING|IT_CALL, NULL, "quit game", M_QuitSRB2, 116},
{IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92},
{IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100},
{IT_STRING|IT_CALL, NULL, "Options", M_Options, 108},
{IT_STRING|IT_CALL, NULL, "Quit Game", M_QuitSRB2, 116},
};
typedef enum
{
secrets = 0,
singleplr,
singleplr = 0,
multiplr,
options,
secrets,
addons,
options,
quitdoom
} main_e;
@ -661,7 +659,7 @@ static menuitem_t SR_PandorasBox[] =
// Sky Room Custom Unlocks
static menuitem_t SR_MainMenu[] =
{
{IT_STRING|IT_SUBMENU,NULL, "Secrets Checklist", &SR_UnlockChecklistDef, 0},
{IT_STRING|IT_SUBMENU,NULL, "Extras Checklist", &SR_UnlockChecklistDef, 0},
{IT_DISABLED, NULL, "", NULL, 0}, // Custom1
{IT_DISABLED, NULL, "", NULL, 0}, // Custom2
{IT_DISABLED, NULL, "", NULL, 0}, // Custom3
@ -726,19 +724,19 @@ static menuitem_t SR_EmblemHintMenu[] =
// Single Player Main
static menuitem_t SP_MainMenu[] =
{
{IT_CALL | IT_STRING, NULL, "Tutorial", M_StartTutorial, 84},
{IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 92},
{IT_SECRET, NULL, "Record Attack", M_TimeAttack, 100},
{IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 108},
{IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 116},
{IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 84},
{IT_SECRET, NULL, "Record Attack", M_TimeAttack, 92},
{IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 100},
{IT_CALL | IT_STRING, NULL, "Tutorial", M_StartTutorial, 108},
{IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 116}
};
enum
{
sptutorial,
sploadgame,
sprecordattack,
spnightsmode,
sptutorial,
spstatistics
};
@ -1224,32 +1222,33 @@ static menuitem_t OP_VideoOptionsMenu[] =
NULL, "HUD Transparency", &cv_translucenthud, 66},
{IT_STRING | IT_CVAR, NULL, "Score/Time/Rings", &cv_timetic, 71},
{IT_STRING | IT_CVAR, NULL, "Show Powerups", &cv_powerupdisplay, 76},
{IT_STRING | IT_CVAR, NULL, "Local ping display", &cv_showping, 81}, // shows ping next to framerate if we want to.
#ifdef SEENAMES
{IT_STRING | IT_CVAR, NULL, "Show player names", &cv_seenames, 81},
{IT_STRING | IT_CVAR, NULL, "Show player names", &cv_seenames, 86},
#endif
{IT_HEADER, NULL, "Console", NULL, 90},
{IT_STRING | IT_CVAR, NULL, "Background color", &cons_backcolor, 96},
{IT_STRING | IT_CVAR, NULL, "Text Size", &cv_constextsize, 101},
{IT_HEADER, NULL, "Console", NULL, 95},
{IT_STRING | IT_CVAR, NULL, "Background color", &cons_backcolor, 101},
{IT_STRING | IT_CVAR, NULL, "Text Size", &cv_constextsize, 106},
{IT_HEADER, NULL, "Chat", NULL, 110},
{IT_STRING | IT_CVAR, NULL, "Chat Mode", &cv_consolechat, 116},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Width", &cv_chatwidth, 121},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Height", &cv_chatheight, 126},
{IT_STRING | IT_CVAR, NULL, "Message Fadeout Time", &cv_chattime, 131},
{IT_STRING | IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 136},
{IT_STRING | IT_CVAR, NULL, "Spam Protection", &cv_chatspamprotection, 141},
{IT_STRING | IT_CVAR, NULL, "Chat background tint", &cv_chatbacktint, 146},
{IT_HEADER, NULL, "Chat", NULL, 115},
{IT_STRING | IT_CVAR, NULL, "Chat Mode", &cv_consolechat, 121},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Width", &cv_chatwidth, 126},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Chat Box Height", &cv_chatheight, 131},
{IT_STRING | IT_CVAR, NULL, "Message Fadeout Time", &cv_chattime, 136},
{IT_STRING | IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 141},
{IT_STRING | IT_CVAR, NULL, "Spam Protection", &cv_chatspamprotection, 146},
{IT_STRING | IT_CVAR, NULL, "Chat background tint", &cv_chatbacktint, 151},
{IT_HEADER, NULL, "Level", NULL, 155},
{IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 161},
{IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 166},
{IT_STRING | IT_CVAR, NULL, "NiGHTS Hoop Draw Dist.", &cv_drawdist_nights, 171},
{IT_HEADER, NULL, "Level", NULL, 160},
{IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 166},
{IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 171},
{IT_STRING | IT_CVAR, NULL, "NiGHTS Hoop Draw Dist.", &cv_drawdist_nights, 176},
{IT_HEADER, NULL, "Diagnostic", NULL, 180},
{IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 186},
{IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 191},
{IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 196},
{IT_HEADER, NULL, "Diagnostic", NULL, 184},
{IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 190},
{IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 195},
{IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 200},
};
static menuitem_t OP_VideoModeMenu[] =
@ -1347,29 +1346,22 @@ static menuitem_t OP_OpenGLColorMenu[] =
static menuitem_t OP_SoundOptionsMenu[] =
{
{IT_HEADER, NULL, "Game Audio", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Sound Effects", &cv_gamesounds, 6},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Sound Volume", &cv_soundvolume, 11},
{IT_STRING | IT_CVAR, NULL, "Sound Effects", &cv_gamesounds, 12},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Sound Volume", &cv_soundvolume, 22},
{IT_STRING | IT_CVAR, NULL, "Digital Music", &cv_gamedigimusic, 21},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Digital Music Volume", &cv_digmusicvolume, 26},
{IT_STRING | IT_CVAR, NULL, "Digital Music", &cv_gamedigimusic, 42},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Digital Music Volume", &cv_digmusicvolume, 52},
{IT_STRING | IT_CVAR, NULL, "MIDI Music", &cv_gamemidimusic, 36},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "MIDI Music Volume", &cv_midimusicvolume, 41},
{IT_STRING | IT_CVAR, NULL, "MIDI Music", &cv_gamemidimusic, 72},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "MIDI Music Volume", &cv_midimusicvolume, 82},
{IT_HEADER, NULL, "Accessibility", NULL, 50},
{IT_STRING | IT_CVAR, NULL, "Closed Captioning", &cv_closedcaptioning, 56},
{IT_STRING | IT_CVAR, NULL, "Reset Music Upon Dying", &cv_resetmusic, 61},
{IT_HEADER, NULL, "Miscellaneous", NULL, 102},
{IT_STRING | IT_CVAR, NULL, "Closed Captioning", &cv_closedcaptioning, 114},
{IT_STRING | IT_CVAR, NULL, "Reset Music Upon Dying", &cv_resetmusic, 124},
{IT_STRING | IT_CVAR, NULL, "Play Sound Effects if Unfocused", &cv_playsoundsifunfocused, 71},
{IT_STRING | IT_CVAR, NULL, "Play Music if Unfocused", &cv_playmusicifunfocused, 76},
#ifdef HAVE_MIXERX
{IT_STRING | IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 94},
#endif
{IT_STRING | IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 144},
};
#ifdef HAVE_MIXERX
#ifdef HAVE_OPENMPT
#define OPENMPT_MENUOFFSET 32
#else
@ -1385,24 +1377,25 @@ static menuitem_t OP_SoundOptionsMenu[] =
static menuitem_t OP_SoundAdvancedMenu[] =
{
#ifdef HAVE_OPENMPT
{IT_HEADER, NULL, "OpenMPT Settings", NULL, 10},
{IT_STRING | IT_CVAR, NULL, "Instrument Filter", &cv_modfilter, 22},
{IT_HEADER, NULL, "OpenMPT Settings", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Instrument Filter", &cv_modfilter, 12},
#endif
#ifdef HAVE_MIXERX
{IT_HEADER, NULL, "MIDI Settings", NULL, OPENMPT_MENUOFFSET+10},
{IT_STRING | IT_CVAR, NULL, "MIDI Player", &cv_midiplayer, OPENMPT_MENUOFFSET+22},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "FluidSynth Sound Font File", &cv_midisoundfontpath, OPENMPT_MENUOFFSET+34},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "TiMidity++ Config Folder", &cv_miditimiditypath, OPENMPT_MENUOFFSET+61},
{IT_HEADER, NULL, "MIDI Settings", NULL, OPENMPT_MENUOFFSET},
{IT_STRING | IT_CVAR, NULL, "MIDI Player", &cv_midiplayer, OPENMPT_MENUOFFSET+12},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "FluidSynth Sound Font File", &cv_midisoundfontpath, OPENMPT_MENUOFFSET+24},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "TiMidity++ Config Folder", &cv_miditimiditypath, OPENMPT_MENUOFFSET+51},
#endif
{IT_HEADER, NULL, "Miscellaneous", NULL, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+10},
{IT_STRING | IT_CVAR, NULL, "Let Levels Force Reset Music", &cv_resetmusicbyheader, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+22},
{IT_HEADER, NULL, "Miscellaneous", NULL, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET},
{IT_STRING | IT_CVAR, NULL, "Play Sound Effects if Unfocused", &cv_playsoundsifunfocused, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+12},
{IT_STRING | IT_CVAR, NULL, "Play Music if Unfocused", &cv_playmusicifunfocused, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+22},
{IT_STRING | IT_CVAR, NULL, "Let Levels Force Reset Music", &cv_resetmusicbyheader, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+32},
};
#undef OPENMPT_MENUOFFSET
#undef MIXERX_MENUOFFSET
#endif
static menuitem_t OP_DataOptionsMenu[] =
{
@ -1454,7 +1447,7 @@ enum
static menuitem_t OP_EraseDataMenu[] =
{
{IT_STRING | IT_CALL, NULL, "Erase Record Data", M_EraseData, 10},
{IT_STRING | IT_CALL, NULL, "Erase Secrets Data", M_EraseData, 20},
{IT_STRING | IT_CALL, NULL, "Erase Extras Data", M_EraseData, 20},
{IT_STRING | IT_CALL, NULL, "\x85" "Erase ALL Data", M_EraseData, 40},
};
@ -1665,7 +1658,7 @@ menu_t SP_MainDef = //CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72);
SP_MainMenu,
M_DrawCenteredMenu,
BASEVIDWIDTH/2, 72,
1, // start at "Start Game" on first entry
0,
NULL
};
@ -1991,12 +1984,10 @@ menu_t OP_ColorOptionsDef =
0,
NULL
};
menu_t OP_SoundOptionsDef = DEFAULTSCROLLMENUSTYLE(
menu_t OP_SoundOptionsDef = DEFAULTMENUSTYLE(
MN_OP_MAIN + (MN_OP_SOUND << 6),
"M_SOUND", OP_SoundOptionsMenu, &OP_MainDef, 30, 30);
#ifdef HAVE_MIXERX
menu_t OP_SoundAdvancedDef = DEFAULTMENUSTYLE(MN_OP_MAIN + (MN_OP_SOUND << 6), "M_SOUND", OP_SoundAdvancedMenu, &OP_SoundOptionsDef, 30, 30);
#endif
menu_t OP_ServerOptionsDef = DEFAULTSCROLLMENUSTYLE(
MN_OP_MAIN + (MN_OP_SERVER << 6),
@ -3363,13 +3354,15 @@ boolean M_Responder(event_t *ev)
//
void M_Drawer(void)
{
boolean wipe = WipeInAction;
if (currentMenu == &MessageDef)
menuactive = true;
if (menuactive)
{
// now that's more readable with a faded background (yeah like Quake...)
if (!WipeInAction && (curfadevalue || (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK)))
if (!wipe && (curfadevalue || (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK)))
V_DrawFadeScreen(0xFF00, (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) ? 16 : curfadevalue);
if (currentMenu->drawroutine)
@ -3431,6 +3424,8 @@ void M_StartControlPanel(void)
if (!Playing())
{
// Secret menu!
MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked()) ? 76 : 84;
MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked()) ? 84 : 92;
MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
currentMenu = &MainDef;
@ -3532,6 +3527,7 @@ void M_StartControlPanel(void)
void M_EndModeAttackRun(void)
{
G_ClearModeAttackRetryFlag();
M_ModeAttackEndGame(0);
}
@ -6692,7 +6688,7 @@ static void M_DrawChecklist(void)
|| !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS)
continue;
V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT), ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name)));
V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name)));
for (j = i+1; j < MAXUNLOCKABLES; j++)
{
@ -7175,7 +7171,7 @@ static void M_DrawSoundTest(void)
titl = va("%s - ", curplaying->title);
}
else
titl = "NONE - ";
titl = "None - ";
i = V_LevelNameWidth(titl);
@ -7189,7 +7185,7 @@ static void M_DrawSoundTest(void)
while (x > y)
{
x -= i;
V_DrawLevelTitle(x, 24, 0, titl);
V_DrawLevelTitle(x, 22, 0, titl);
}
if (curplaying)
@ -8338,16 +8334,12 @@ static void M_SetupChoosePlayer(INT32 choice)
{
INT32 skinnum;
UINT8 i;
UINT8 firstvalid = 255;
UINT8 lastvalid = 0;
UINT8 firstvalid = 255, lastvalid = 255;
boolean allowed = false;
char *and;
(void)choice;
if (!(mapheaderinfo[startmap-1]
&& (mapheaderinfo[startmap-1]->forcecharacter[0] != '\0'
|| (mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS)) // remove this later when everyone gets their own nights sprites, maybe
))
if (!mapheaderinfo[startmap-1] || mapheaderinfo[startmap-1]->forcecharacter[0] == '\0')
{
for (i = 0; i < 32; i++) // Handle charsels, availability, and unlocks.
{
@ -8357,6 +8349,8 @@ static void M_SetupChoosePlayer(INT32 choice)
if (and)
{
char firstskin[SKINNAMESIZE+1];
if (mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS) // skip tagteam characters for NiGHTS levels
continue;
strncpy(firstskin, description[i].skinname, (and - description[i].skinname));
firstskin[(and - description[i].skinname)] = '\0';
description[i].skinnum[0] = R_SkinAvailable(firstskin);
@ -8385,7 +8379,7 @@ static void M_SetupChoosePlayer(INT32 choice)
if (!(description[i].picname[0]))
{
if (skins[skinnum].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1)
if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL)
{
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL];
@ -8410,17 +8404,16 @@ static void M_SetupChoosePlayer(INT32 choice)
}
}
if (firstvalid != 255)
{ // One last bit of order we can't do in the iteration above.
description[firstvalid].prev = lastvalid;
description[lastvalid].next = firstvalid;
}
else // We're being forced into a specific character, so might as well just skip it.
if (firstvalid == lastvalid) // We're being forced into a specific character, so might as well just skip it.
{
M_ChoosePlayer(-1);
M_ChoosePlayer(firstvalid);
return;
}
// One last bit of order we can't do in the iteration above.
description[firstvalid].prev = lastvalid;
description[lastvalid].next = firstvalid;
M_ChangeMenuMusic("_chsel", true);
/* the menus suck -James */
@ -8747,7 +8740,7 @@ static void M_ChoosePlayer(INT32 choice)
UINT8 skinnum;
// skip this if forcecharacter or no characters available
if (choice == -1)
if (choice == 255)
{
skinnum = botskin = 0;
botingame = false;
@ -8859,9 +8852,9 @@ static void M_DrawStatsMaps(int location)
M_DrawMapEmblems(mnum+1, 292, y);
if (mapheaderinfo[mnum]->actnum != 0)
V_DrawString(20, y, V_YELLOWMAP, va("%s %d", mapheaderinfo[mnum]->lvlttl, mapheaderinfo[mnum]->actnum));
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, va("%s %d", mapheaderinfo[mnum]->lvlttl, mapheaderinfo[mnum]->actnum));
else
V_DrawString(20, y, V_YELLOWMAP, mapheaderinfo[mnum]->lvlttl);
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, mapheaderinfo[mnum]->lvlttl);
y += 8;
@ -8905,7 +8898,7 @@ static void M_DrawStatsMaps(int location)
else
V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE));
V_DrawString(20, y, V_YELLOWMAP, va("%s", exemblem->description));
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, va("%s", exemblem->description));
}
y += 8;
@ -9116,7 +9109,7 @@ void M_DrawTimeAttackMenu(void)
// Character face!
{
if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1)
if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL)
{
spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL];
@ -9240,10 +9233,7 @@ void M_DrawTimeAttackMenu(void)
V_DrawString(104-72, 73+lsheadingheight/2, V_YELLOWMAP, "RINGS:");
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->gotperfect)
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE, beststr);
else
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|V_YELLOWMAP, beststr);
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((mapvisited[cv_nextmap.value-1] & MV_PERFECT) ? V_YELLOWMAP : 0), beststr);
V_DrawRightAlignedString(104+72, 83+lsheadingheight/2, V_ALLOWLOWERCASE, reqrings);
}
@ -9395,6 +9385,7 @@ void M_DrawNightsAttackMenu(void)
{
emblem_t *em;
INT32 yHeight;
INT32 xpos;
patch_t *PictureOfLevel;
lumpnum_t lumpnum;
char beststr[40];
@ -9454,17 +9445,23 @@ void M_DrawNightsAttackMenu(void)
{
switch (em->type)
{
case ET_NGRADE: yHeight = 48; break;
case ET_NTIME: yHeight = 68; break;
case ET_NGRADE:
xpos = 104+38;
yHeight = 48;
break;
case ET_NTIME:
xpos = 104+76;
yHeight = 68;
break;
default:
goto skipThisOne;
}
if (em->collected)
V_DrawSmallMappedPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE),
V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE),
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE));
else
V_DrawSmallScaledPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE));
V_DrawSmallScaledPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE));
skipThisOne:
em = M_GetLevelEmblems(-1);
@ -10905,7 +10902,7 @@ static void M_EraseData(INT32 choice)
if (choice == 0)
eschoice = M_GetText("Record Attack data");
else if (choice == 1)
eschoice = M_GetText("Secrets data");
eschoice = M_GetText("Extras data");
else
eschoice = M_GetText("ALL game data");

View File

@ -99,7 +99,7 @@ typedef enum
MN_OP_SCREENSHOTS,
MN_OP_ERASEDATA,
// Secrets
// Extras
MN_SR_MAIN,
MN_SR_PANDORA,
MN_SR_LEVELSELECT,

View File

@ -23,6 +23,8 @@
#include <unistd.h>
#endif
#include <errno.h>
// Extended map support.
#include <ctype.h>
@ -787,7 +789,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl[0] != '\0')
snprintf(lvlttltext, 48, "%s%s%s",
mapheaderinfo[gamemap-1]->lvlttl,
(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE",
(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone",
(mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : "");
else
snprintf(lvlttltext, 48, "Unknown");
@ -2441,3 +2443,13 @@ void M_SetupMemcpy(void)
M_Memcpy = cpu_cpy;
#endif
}
/** Return the appropriate message for a file error or end of file.
*/
const char *M_FileError(FILE *fp)
{
if (ferror(fp))
return strerror(errno);
else
return "end-of-file";
}

View File

@ -94,6 +94,8 @@ void strcatbf(char *s1, const char *s2, const char *s3);
void M_SetupMemcpy(void);
const char *M_FileError(FILE *handle);
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);

View File

@ -312,6 +312,9 @@ void A_SpawnPterabytes(mobj_t *actor);
void A_PterabyteHover(mobj_t *actor);
void A_RolloutSpawn(mobj_t *actor);
void A_RolloutRock(mobj_t *actor);
void A_DragonbomberSpawn(mobj_t *actor);
void A_DragonWing(mobj_t *actor);
void A_DragonSegment(mobj_t *actor);
//for p_enemy.c
@ -2473,12 +2476,8 @@ void A_VultureBlast(mobj_t *actor)
void A_VultureFly(mobj_t *actor)
{
fixed_t speedmax = 18*FRACUNIT;
angle_t angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle;
fixed_t dx = actor->target->x - actor->x;
fixed_t dy = actor->target->y - actor->y;
fixed_t dz = actor->target->z - actor->z;
fixed_t dxy = FixedHypot(dx, dy);
fixed_t dm;
angle_t angledif;
fixed_t dx, dy, dz, dxy, dm;
mobj_t *dust;
fixed_t momm;
@ -2487,6 +2486,18 @@ void A_VultureFly(mobj_t *actor)
return;
#endif
if (!actor->target || P_MobjWasRemoved(actor->target))
{
P_SetMobjState(actor, actor->info->spawnstate);
return;
}
angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle;
dx = actor->target->x - actor->x;
dy = actor->target->y - actor->y;
dz = actor->target->z - actor->z;
dxy = FixedHypot(dx, dy);
if (leveltime % 4 == 0)
S_StartSound(actor, actor->info->activesound);
@ -4070,19 +4081,28 @@ bossjustdie:
mobj_t *pole = P_SpawnMobj(
mo->tracer->x - P_ReturnThrustX(mo->tracer, mo->tracer->angle, speed*time),
mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time),
mo->tracer->floorz + 4*FRACUNIT,
mo->tracer->floorz + (256+1)*FRACUNIT,
MT_FSGNB);
P_SetTarget(&pole->tracer, P_SpawnMobj(
pole->x, pole->y,
pole->z - 256*FRACUNIT,
MT_FSGNB));
P_SetTarget(&pole->tracer->tracer, P_SpawnMobj(
pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT),
pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT),
pole->z + 256*FRACUNIT,
MT_FSGNA));
pole->angle = mo->tracer->angle;
pole->tracer->angle = pole->angle - ANGLE_90;
pole->tracer->flags |= MF_NOCLIPTHING;
P_SetScale(pole, (pole->destscale = 2*FRACUNIT));
P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT));
pole->angle = pole->tracer->angle = mo->tracer->angle;
pole->tracer->tracer->angle = pole->angle - ANGLE_90;
pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
pole->tracer->momx = pole->momx;
pole->tracer->momy = pole->momy;
pole->tracer->tracer->momx = pole->momx;
pole->tracer->tracer->momy = pole->momy;
}
}
else
@ -5121,7 +5141,7 @@ void A_SignPlayer(mobj_t *actor)
return;
#endif
if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins)
if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins || signcolor >= MAXTRANSLATIONS)
return;
// if no face overlay, spawn one
@ -5148,26 +5168,9 @@ void A_SignPlayer(mobj_t *actor)
if (signcolor)
;
else if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor?
{
signcolor = skin->prefoppositecolor;
/*
If you're here from the comment above Color_Opposite,
the following line is the one which is dependent on the
array being symmetrical. It gets the opposite of the
opposite of your desired colour just so it can get the
brightness frame for the End Sign. It's not a great
design choice, but it's constant time array access and
the idea that the colours should be OPPOSITES is kind
of in the name. If you have a better idea, feel free
to let me know. ~toast 2016/07/20
*/
signframe += (15 - Color_Opposite[Color_Opposite[skin->prefoppositecolor - 1][0] - 1][1]);
}
else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor.
{
signcolor = Color_Opposite[actor->target->player->skincolor - 1][0];
signframe += (15 - Color_Opposite[actor->target->player->skincolor - 1][1]);
}
else
signcolor = SKINCOLOR_NONE;
}
@ -5188,10 +5191,10 @@ void A_SignPlayer(mobj_t *actor)
skinnum = P_RandomKey(skincount);
for (skincount = 0; skincount < numskins; skincount++)
{
if (skincheck(skincount))
skinnum++;
if (skincount > skinnum)
break;
if (skincheck(skincount))
skinnum++;
}
}
else // otherwise, advance 1 skin
@ -5203,42 +5206,46 @@ void A_SignPlayer(mobj_t *actor)
skin = &skins[skinnum];
}
else // specific skin
{
skin = &skins[locvar1];
}
facecolor = skin->prefcolor;
if (signcolor)
;
else if (skin->prefoppositecolor)
{
signcolor = skin->prefoppositecolor;
}
else
{
else if (facecolor)
signcolor = Color_Opposite[facecolor - 1][0];
}
signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]);
}
if (skin != NULL && skin->sprites[SPR2_SIGN].numframes) // player face
if (skin && skin->sprites[SPR2_SIGN].numframes) // player face
{
ov->color = facecolor;
ov->skin = skin;
P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN
actor->tracer->color = signcolor;
actor->tracer->frame = signframe;
}
else // Eggman face
{
ov->color = SKINCOLOR_NONE;
P_SetMobjState(ov, actor->info->meleestate); // S_EGGMANSIGN
if (signcolor)
actor->tracer->color = signcolor;
else
actor->tracer->color = signcolor = SKINCOLOR_CARBON;
actor->tracer->frame = signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]);
if (!signcolor)
signcolor = SKINCOLOR_CARBON;
}
actor->tracer->color = signcolor;
/*
If you're here from the comment above Color_Opposite,
the following line is the one which is dependent on the
array being symmetrical. It gets the opposite of the
opposite of your desired colour just so it can get the
brightness frame for the End Sign. It's not a great
design choice, but it's constant time array access and
the idea that the colours should be OPPOSITES is kind
of in the name. If you have a better idea, feel free
to let me know. ~toast 2016/07/20
*/
if (signcolor && signcolor < MAXSKINCOLORS)
signframe += (15 - Color_Opposite[Color_Opposite[signcolor - 1][0] - 1][1]);
actor->tracer->frame = signframe;
}
// Function: A_OverlayThink
@ -5665,10 +5672,10 @@ void A_MinusPopup(mobj_t *actor)
S_StartSound(actor, sfx_s3k82);
for (i = 1; i <= num; i++)
{
mobj_t *rock = P_SpawnMobj(actor->x, actor->y, actor->z + actor->height/4, MT_ROCKCRUMBLE1);
mobj_t *rock = P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_ROCKCRUMBLE1);
P_Thrust(rock, ani*i, FRACUNIT);
rock->momz = 3*FRACUNIT;
P_SetScale(rock, FRACUNIT/3);
P_SetObjectMomZ(rock, 3*FRACUNIT, false);
P_SetScale(rock, rock->scale/3);
}
P_RadiusAttack(actor, actor, 2*actor->radius, 0);
if (actor->tracer)
@ -5682,11 +5689,12 @@ void A_MinusPopup(mobj_t *actor)
// Description: If the minus hits the floor, dig back into the ground.
//
// var1 = State to switch to (if 0, use seestate).
// var2 = unused
// var2 = If not 0, spawn debris when hitting the floor.
//
void A_MinusCheck(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_MinusCheck", actor))
@ -5697,6 +5705,18 @@ void A_MinusCheck(mobj_t *actor)
{
P_SetMobjState(actor, locvar1 ? (statenum_t)locvar1 : actor->info->seestate);
actor->flags = actor->info->flags;
if (locvar2)
{
INT32 i, num = 6;
angle_t ani = FixedAngle(FRACUNIT*360/num);
for (i = 1; i <= num; i++)
{
mobj_t *rock = P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_ROCKCRUMBLE1);
P_Thrust(rock, ani*i, FRACUNIT);
P_SetObjectMomZ(rock, 3*FRACUNIT, false);
P_SetScale(rock, rock->scale/3);
}
}
}
}
@ -14535,6 +14555,9 @@ void A_RolloutRock(mobj_t *actor)
actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves
if (actor->eflags & MFE_JUSTHITFLOOR)
S_StartSound(actor, actor->info->painsound);
if (actor->threshold)
actor->threshold--;
@ -14588,6 +14611,9 @@ void A_RolloutRock(mobj_t *actor)
actor->frame = actor->reactiontime % maxframes; // set frame
if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health)
actor->flags |= MF_PUSHABLE;
if (!(actor->flags & MF_PUSHABLE)) // if being ridden, don't disappear
actor->fuse = 0;
else if (!actor->fuse && actor->movecount == 1) // otherwise if rock has moved, set its fuse
@ -14597,3 +14623,97 @@ void A_RolloutRock(mobj_t *actor)
actor->flags2 ^= MF2_DONTDRAW;
}
// Function: A_DragonbomberSpawn
//
// Description: Spawns the body parts for Dragonbomber
//
// var1 = Tail segments to spawn
// var2 = unused
//
void A_DragonbomberSpawn(mobj_t *actor)
{
UINT8 i;
mobj_t *mo = actor;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DragonbomberSpawn", actor))
return;
#endif
for (i = 0; i < var1; i++) // spawn tail segments
{
mobj_t *segment;
fixed_t x, y;
x = P_ReturnThrustX(mo, mo->angle, -mo->radius << 1);
y = P_ReturnThrustY(mo, mo->angle, -mo->radius << 1);
segment = P_SpawnMobjFromMobj(mo, x, y, 0, MT_DRAGONTAIL);
P_SetTarget(&segment->target, mo);
P_SetTarget(&mo->tracer, segment);
segment->angle = mo->angle;
mo = segment;
}
for (i = 0; i < 2; i++) // spawn wings
{
mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_DRAGONWING);
P_SetTarget(&mo->target, actor);
mo->movedir = ANGLE_90 + i * ANGLE_180;
}
}
// Function: A_DragonWing
//
// Description: Moves actor such that it is placed away from its target at a distance equal to the target's radius in the direction of its target's angle.
// The actor's movedir can be used to offset the angle.
//
// var1 = unused
// var2 = unused
//
void A_DragonWing(mobj_t *actor)
{
mobj_t *target = actor->target;
fixed_t x, y;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DragonWing", actor))
return;
#endif
if (target == NULL || !target->health)
{
P_RemoveMobj(actor);
return;
}
actor->angle = target->angle + actor->movedir;
x = target->x + P_ReturnThrustX(actor, actor->angle, -target->radius);
y = target->y + P_ReturnThrustY(actor, actor->angle, -target->radius);
P_TeleportMove(actor, x, y, target->z);
}
// Function: A_DragonSegment
//
// Description: Moves actor such that it is placed away from its target at an absolute distance equal to the sum of the two mobjs' radii.
//
// var1 = unused
// var2 = unused
//
void A_DragonSegment(mobj_t *actor)
{
mobj_t *target = actor->target;
fixed_t dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
fixed_t radius = actor->radius + target->radius;
angle_t hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
angle_t zangle = R_PointToAngle2(0, target->z, dist, actor->z);
fixed_t hdist = P_ReturnThrustX(target, zangle, radius);
fixed_t xdist = P_ReturnThrustX(target, hangle, hdist);
fixed_t ydist = P_ReturnThrustY(target, hangle, hdist);
fixed_t zdist = P_ReturnThrustY(target, zangle, radius);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DragonSegment", actor))
return;
#endif
actor->angle = hangle;
P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
}

View File

@ -148,15 +148,19 @@ void P_ResetStarposts(void)
//
boolean P_CanPickupItem(player_t *player, boolean weapon)
{
if (player->bot && weapon)
if (!player->mo || player->mo->health <= 0)
return false;
if (player->bot)
{
if (weapon)
return false;
return P_CanPickupItem(&players[consoleplayer], true); // weapon is true to prevent infinite recursion if p1 is bot - doesn't occur in vanilla, but may be relevant for mods
}
if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] < UINT16_MAX)
return false;
if (player->mo && player->mo->health <= 0)
return false;
return true;
}
@ -2521,7 +2525,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0))
;
else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != INFLIVES)
else if (!target->player->bot && !target->player->spectator && (target->player->lives != INFLIVES)
&& G_GametypeUsesLives())
{
target->player->lives -= 1; // Lose a life Tails 03-11-2000
@ -2678,6 +2682,17 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->flags = (target->flags|MF_NOCLIPHEIGHT) & ~MF_NOGRAVITY;
break;
case MT_DRAGONBOMBER:
{
mobj_t *segment = target;
while (segment->tracer != NULL)
{
P_KillMobj(segment->tracer, NULL, NULL, 0);
segment = segment->tracer;
}
break;
}
case MT_EGGMOBILE3:
{
mobj_t *mo2;
@ -2741,7 +2756,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
case MT_EGGTRAP:
// Time for birdies! Yaaaaaaaay!
target->fuse = TICRATE*2;
target->fuse = TICRATE;
break;
case MT_MINECART:
@ -2803,13 +2818,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if (flip)
momz *= -1;
#define makechunk(angtweak, xmov, ymov) \
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);\
chunk->eflags |= flip;\
chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\
P_SetMobjState(chunk, target->info->xdeathstate);\
chunk->health = 0;\
chunk->angle = angtweak;\
chunk->destscale = scale;\
P_SetScale(chunk, scale);\
P_UnsetThingPosition(chunk);\
chunk->flags = MF_NOCLIP;\
chunk->x += xmov;\
@ -2828,14 +2840,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if (flip)
momz *= -1;
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);
chunk->eflags |= flip;
chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);
P_SetMobjState(chunk, target->info->deathstate);
chunk->health = 0;
chunk->angle = ang + ANGLE_180;
chunk->destscale = scale;
P_SetScale(chunk, scale);
P_UnsetThingPosition(chunk);
chunk->flags = MF_NOCLIP;
chunk->x -= xoffs;
@ -2878,13 +2886,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
sprflip = P_RandomChance(FRACUNIT/2);
#define makechunk(angtweak, xmov, ymov) \
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);\
chunk->eflags |= flip;\
chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\
P_SetMobjState(chunk, target->info->xdeathstate);\
chunk->health = 0;\
chunk->angle = target->angle;\
chunk->destscale = scale;\
P_SetScale(chunk, scale);\
P_UnsetThingPosition(chunk);\
chunk->flags = MF_NOCLIP;\
chunk->x += xmov - forwardxoffs;\
@ -2906,14 +2911,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
sprflip = P_RandomChance(FRACUNIT/2);
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);
chunk->eflags |= flip;
chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);
P_SetMobjState(chunk, target->info->deathstate);
chunk->health = 0;
chunk->angle = target->angle;
chunk->destscale = scale;
P_SetScale(chunk, scale);
P_UnsetThingPosition(chunk);
chunk->flags = MF_NOCLIP;
chunk->x += forwardxoffs - xoffs;
@ -3002,6 +3004,10 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN);
S_StartSound(target, sfx_nghurt);
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
if (oldnightstime > 10*TICRATE
&& player->nightstime < 10*TICRATE)
{
@ -3517,7 +3523,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// Make sure that boxes cannot be popped by enemies, red rings, etc.
if (target->flags & MF_MONITOR && ((!source || !source->player || source->player->bot)
|| (inflictor && inflictor->type >= MT_REDRING && inflictor->type <= MT_GRENADERING)))
|| (inflictor && (inflictor->type == MT_REDRING || (inflictor->type >= MT_THROWNBOUNCE && inflictor->type <= MT_THROWNGRENADE)))))
return false;
}

View File

@ -172,6 +172,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle);
void P_DoPityCheck(player_t *player);
void P_PlayerThink(player_t *player);
void P_PlayerAfterThink(player_t *player);
void P_DoPlayerFinish(player_t *player);
void P_DoPlayerExit(player_t *player);
void P_NightserizePlayer(player_t *player, INT32 ptime);
@ -322,6 +323,7 @@ SINT8 P_MobjFlip(mobj_t *mobj);
fixed_t P_GetMobjGravity(mobj_t *mo);
FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
void P_CalcChasePostImg(player_t *player, camera_t *thiscam);
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab);

View File

@ -592,7 +592,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
if (!(tails->pflags & PF_CANCARRY))
return;
if (tails->bot == 1)
if (sonic->pflags & PF_FINISHED)
return;
if ((sonic->mo->eflags & MFE_VERTICALFLIP) != (tails->mo->eflags & MFE_VERTICALFLIP))
@ -661,31 +661,32 @@ static void P_SlapStick(mobj_t *fang, mobj_t *pole)
momx2 = fang->momx/dist;
momy2 = fang->momy/dist;
pole->tracer->momx = momx1 + (dist-1)*momx2;
pole->tracer->momy = momy1 + (dist-1)*momy2;
pole->tracer->tracer->momx = momx1 + (dist-1)*momx2;
pole->tracer->tracer->momy = momy1 + (dist-1)*momy2;
fang->momx = (dist-1)*momx1 + momx2;
fang->momy = (dist-1)*momy1 + momy2;
#undef dist
P_SetMobjState(pole, pole->info->deathstate);
P_SetObjectMomZ(pole->tracer, 6*FRACUNIT, false);
pole->tracer->flags &= ~(MF_NOGRAVITY|MF_NOCLIP);
pole->tracer->movedir = ANGLE_67h;
if ((R_PointToAngle(fang->x - pole->tracer->x, fang->y - pole->tracer->y) - pole->angle) > ANGLE_180)
pole->tracer->movedir = InvAngle(pole->tracer->movedir);
P_SetObjectMomZ(pole->tracer->tracer, 6*FRACUNIT, false);
pole->tracer->tracer->flags &= ~(MF_NOGRAVITY|MF_NOCLIP);
pole->tracer->tracer->movedir = ANGLE_67h;
if ((R_PointToAngle(fang->x - pole->tracer->tracer->x, fang->y - pole->tracer->tracer->y) - pole->angle) > ANGLE_180)
pole->tracer->tracer->movedir = InvAngle(pole->tracer->movedir);
P_SetObjectMomZ(fang, 14*FRACUNIT, false);
fang->flags |= MF_NOGRAVITY|MF_NOCLIP;
P_SetMobjState(fang, fang->info->xdeathstate);
pole->tracer->tics = pole->tics = fang->tics;
pole->tracer->tracer->tics = pole->tracer->tics = pole->tics = fang->tics;
var1 = var2 = 0;
A_Scream(pole->tracer);
A_Scream(pole->tracer->tracer);
S_StartSound(fang, sfx_altdi1);
P_SetTarget(&pole->tracer->tracer, NULL);
P_SetMobjState(pole->tracer, pole->info->xdeathstate);
P_SetTarget(&pole->tracer, NULL);
P_SetMobjState(pole, pole->info->deathstate);
}
static void P_PlayerBarrelCollide(mobj_t *toucher, mobj_t *barrel)
@ -783,12 +784,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)
{
mobjtype_t type = thing->type;
mobj_t *iter;
if (thing->flags & MF_SOLID)
S_StartSound(tmthing, thing->info->deathsound);
for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext)
if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(thing, tmthing, tmthing, 0);
for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext)
if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(iter, tmthing, tmthing, 0);
}
else
{
@ -822,12 +823,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)
{
mobjtype_t type = thing->type;
mobj_t *iter;
if (thing->flags & MF_SOLID)
S_StartSound(tmthing, thing->info->deathsound);
for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext)
if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(thing, tmthing, tmthing, 0);
for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext)
if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(iter, tmthing, tmthing, 0);
}
else
{
@ -1020,7 +1021,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
if ((thing->flags & MF_PUSHABLE) // not carrying a player
&& (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something
&& ((tmthing->eflags & MFE_VERTICALFLIP) == (thing->eflags & MFE_VERTICALFLIP))
&& (P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < (thing->radius))
&& (P_MobjFlip(tmthing)*tmthing->momz <= 0)
&& ((!(tmthing->eflags & MFE_VERTICALFLIP) && abs(thing->z + thing->height - tmthing->z) < (thing->height>>2))
|| (tmthing->eflags & MFE_VERTICALFLIP && abs(tmthing->z + tmthing->height - thing->z) < (thing->height>>2))))
@ -1032,7 +1032,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
P_SetPlayerMobjState(tmthing, S_PLAY_WALK);
tmthing->player->powers[pw_carry] = CR_ROLLOUT;
P_SetTarget(&tmthing->tracer, thing);
P_SetObjectMomZ(thing, tmthing->momz, true);
if (!P_IsObjectOnGround(thing))
thing->momz += tmthing->momz;
return true;
}
}
@ -1063,6 +1064,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
thing->momy = tmthing->momy;
tmthing->momx = tempmomx;
tmthing->momy = tempmomy;
S_StartSound(thing, thing->info->painsound);
}
}
@ -1089,7 +1091,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; // overhead
if (thing->z + thing->height < tmthing->z)
return true; // underneath
if (!thing->tracer)
if (!thing->tracer || !thing->tracer->tracer)
return true;
P_SlapStick(tmthing, thing);
// no return value was used in the original prototype script at this point,
@ -1349,6 +1351,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
P_DamageMobj(thing, tmthing, tmthing->target, 1, damagetype);
}
// Fireball touched an enemy
// Don't bounce though, just despawn right there
if ((tmthing->type == MT_FIREBALL) && (thing->flags & MF_ENEMY))
P_KillMobj(tmthing, NULL, NULL, 0);
// don't traverse any more
if (tmthing->type == MT_SHELL)
@ -1712,8 +1719,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
}
if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM) && (thing->player))
; // springs and gas jets should never be able to step up onto a player
if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
; // springs, gas jets and springs should never be able to step up onto a player
// z checking at last
// Treat noclip things as non-solid!
else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID
@ -3464,7 +3471,7 @@ isblocking:
}
// see about climbing on the wall
if (!(checkline->flags & ML_NOCLIMB))
if (!(checkline->flags & ML_NOCLIMB) && checkline->special != HORIZONSPECIAL)
{
boolean canclimb;
angle_t climbangle, climbline;
@ -3751,6 +3758,33 @@ void P_SlideMove(mobj_t *mo)
v2.x = tmhitthing->x + cosradius;
v2.y = tmhitthing->y + sinradius;
// Can we box collision our way into smooth movement..?
if (sinradius && mo->y + mo->radius <= min(v1.y, v2.y))
{
mo->momy = 0;
P_TryMove(mo, mo->x + mo->momx, min(v1.y, v2.y) - mo->radius, true);
return;
}
else if (sinradius && mo->y - mo->radius >= max(v1.y, v2.y))
{
mo->momy = 0;
P_TryMove(mo, mo->x + mo->momx, max(v1.y, v2.y) + mo->radius, true);
return;
}
else if (cosradius && mo->x + mo->radius <= min(v1.x, v2.x))
{
mo->momx = 0;
P_TryMove(mo, min(v1.x, v2.x) - mo->radius, mo->y + mo->momy, true);
return;
}
else if (cosradius && mo->x - mo->radius >= max(v1.x, v2.x))
{
mo->momx = 0;
P_TryMove(mo, max(v1.x, v2.x) + mo->radius, mo->y + mo->momy, true);
return;
}
// nope, gotta fuck around with a fake linedef!
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = 2*cosradius; // v2.x - v1.x;

View File

@ -246,6 +246,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
{
case S_PLAY_STND:
case S_PLAY_WAIT:
case S_PLAY_NIGHTS_STAND:
player->panim = PA_IDLE;
break;
case S_PLAY_EDGE:
@ -269,6 +270,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
break;
case S_PLAY_ROLL:
//case S_PLAY_SPINDASH: -- everyone can ROLL thanks to zoom tubes...
case S_PLAY_NIGHTS_ATTACK:
player->panim = PA_ROLL;
break;
case S_PLAY_JUMP:
@ -278,6 +280,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
player->panim = PA_SPRING;
break;
case S_PLAY_FALL:
case S_PLAY_NIGHTS_FLOAT:
player->panim = PA_FALL;
break;
case S_PLAY_FLY:
@ -3405,7 +3408,7 @@ void P_MobjCheckWater(mobj_t *mobj)
// Drown timer setting
if ((p->powers[pw_shield] & SH_PROTECTWATER) // Has water protection
|| (p->exiting) // Or exiting
|| (p->exiting) || (p->pflags & PF_FINISHED) // Or finished/exiting
|| (maptol & TOL_NIGHTS) // Or in NiGHTS mode
|| (mariomode)) // Or in Mario mode...
{
@ -3721,17 +3724,10 @@ void P_DestroyRobots(void)
}
}
// P_CameraThinker
//
// Process the mobj-ish required functions of the camera
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled)
// the below is chasecam only, if you're curious. check out P_CalcPostImg in p_user.c for first person
void P_CalcChasePostImg(player_t *player, camera_t *thiscam)
{
boolean itsatwodlevel = false;
postimg_t postimg = postimg_none;
if (twodlevel
|| (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD))
|| (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)))
itsatwodlevel = true;
if (player->pflags & PF_FLIPCAM && !(player->powers[pw_carry] == CR_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP)
postimg = postimg_flip;
@ -3759,13 +3755,27 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
postimg = postimg_heat;
}
if (postimg != postimg_none)
{
if (splitscreen && player == &players[secondarydisplayplayer])
postimgtype2 = postimg;
else
postimgtype = postimg;
}
if (postimg == postimg_none)
return;
if (splitscreen && player == &players[secondarydisplayplayer])
postimgtype2 = postimg;
else
postimgtype = postimg;
}
// P_CameraThinker
//
// Process the mobj-ish required functions of the camera
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled)
{
boolean itsatwodlevel = false;
if (twodlevel
|| (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD))
|| (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)))
itsatwodlevel = true;
P_CalcChasePostImg(player, thiscam);
if (thiscam->momx || thiscam->momy)
{
@ -4535,23 +4545,29 @@ static void P_Boss3Thinker(mobj_t *mobj)
}
else if (mobj->movecount) // Firing mode
{
// look for a new target
P_BossTargetPlayer(mobj, false);
if (!mobj->target || !mobj->target->player)
return;
// Always face your target.
A_FaceTarget(mobj);
// Check if the attack animation is running. If not, play it.
if (mobj->state < &states[mobj->info->missilestate] || mobj->state > &states[mobj->info->raisestate])
{
// look for a new target
P_BossTargetPlayer(mobj, true);
if (!mobj->target || !mobj->target->player)
return;
if (mobj->health <= mobj->info->damage) // pinch phase
mobj->movecount--; // limited number of shots before diving again
if (mobj->movecount)
P_SetMobjState(mobj, mobj->info->missilestate+1);
}
else if (mobj->target && mobj->target->player)
{
angle_t diff = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) - mobj->angle;
if (diff > ANGLE_180)
diff = InvAngle(InvAngle(diff)/4);
else
diff /= 4;
mobj->angle += diff;
}
}
else if (mobj->threshold >= 0) // Traveling mode
{
@ -4666,13 +4682,10 @@ static void P_Boss3Thinker(mobj_t *mobj)
S_StartSound(mobj, shock->info->seesound);
// look for a new target
P_BossTargetPlayer(mobj, false);
P_BossTargetPlayer(mobj, true);
if (mobj->target && mobj->target->player)
{
A_FaceTarget(mobj);
P_SetMobjState(mobj, mobj->info->missilestate);
}
}
else if (mobj->flags2 & (MF2_STRONGBOX|MF2_CLASSICPUSH)) // just hit the bottom of your tube
{
@ -7076,7 +7089,7 @@ static void P_SpawnMinecartSegments(mobj_t *mobj, boolean mode)
seg = P_SpawnMobj(x, y, z, MT_MINECARTSEG);
P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i));
if (i >= 2)
seg->extravalue1 = (i == 2) ? -18 : 18;
seg->extravalue1 = (i == 2) ? -20 : 20;
else
{
seg->extravalue2 = (i == 0) ? 24 : -24;
@ -8227,7 +8240,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->flags2 ^= MF2_DONTDRAW;
break;
case MT_EGGTRAP: // Egg Capsule animal release
if (mobj->fuse > 0 && mobj->fuse < 2*TICRATE-(TICRATE/7))
if (mobj->fuse > 0)// && mobj->fuse < TICRATE-(TICRATE/7))
{
INT32 i;
fixed_t x,y,z;
@ -8236,9 +8249,9 @@ void P_MobjThinker(mobj_t *mobj)
mobj_t *flicky;
z = mobj->subsector->sector->floorheight + FRACUNIT + (P_RandomKey(64)<<FRACBITS);
for (i = 0; i < 2; i++)
for (i = 0; i < 3; i++)
{
const angle_t fa = (P_RandomByte()*FINEANGLES/16) & FINEMASK;
const angle_t fa = P_RandomKey(FINEANGLES) & FINEMASK;
ns = 64 * FRACUNIT;
x = mobj->x + FixedMul(FINESINE(fa),ns);
y = mobj->y + FixedMul(FINECOSINE(fa),ns);
@ -8690,6 +8703,13 @@ void P_MobjThinker(mobj_t *mobj)
case MT_KOOPA:
P_KoopaThinker(mobj);
break;
case MT_FIREBALL:
if (P_AproxDistance(mobj->momx, mobj->momy) <= 16*FRACUNIT) // Once fireballs lose enough speed, kill them
{
P_KillMobj(mobj, NULL, NULL, 0);
return;
}
break;
case MT_REDRING:
if (((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz))
&& mobj->flags & MF_MISSILE)
@ -9622,6 +9642,90 @@ void P_MobjThinker(mobj_t *mobj)
}
break;
}
case MT_DRAGONBOMBER:
{
#define DRAGONTURNSPEED ANG2
mobj->movecount = (mobj->movecount + 9) % 360;
P_SetObjectMomZ(mobj, 4*FINESINE(((mobj->movecount*ANG1) >> ANGLETOFINESHIFT) & FINEMASK), false);
if (mobj->threshold > 0) // are we dropping mines?
{
mobj->threshold--;
if (mobj->threshold == 0) // if the timer hits 0, look for a mine to drop!
{
mobj_t *segment = mobj;
while (segment->tracer != NULL && !P_MobjWasRemoved(segment->tracer) && segment->tracer->state == &states[segment->tracer->info->spawnstate])
{
segment = segment->tracer;
}
if (segment != mobj) // found an unactivated segment?
{
mobj_t *mine = P_SpawnMobjFromMobj(segment, 0, 0, 0, segment->info->painchance);
mine->angle = segment->angle;
P_InstaThrust(mine, mobj->angle, P_AproxDistance(mobj->momx, mobj->momy) >> 1);
P_SetObjectMomZ(mine, -2*FRACUNIT, true);
S_StartSound(mine, mine->info->seesound);
P_SetMobjState(segment, segment->info->raisestate);
mobj->threshold = mobj->info->painchance;
}
}
}
if (mobj->target != NULL) // Are we chasing a player?
{
fixed_t dist = P_AproxDistance(mobj->x - mobj->target->x, mobj->y - mobj->target->y);
if (dist > 2000 * mobj->scale) // Not anymore!
P_SetTarget(&mobj->target, NULL);
else
{
fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale);
fixed_t z = mobj->target->z + (mobj->height >> 1) + (mobj->flags & MFE_VERTICALFLIP ? -128*mobj->scale : 128*mobj->scale + mobj->target->height);
angle_t diff = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) - mobj->angle;
if (diff > ANGLE_180)
mobj->angle -= DRAGONTURNSPEED;
else
mobj->angle += DRAGONTURNSPEED;
if (!mobj->threshold && dist < 512 * mobj->scale) // Close enough to drop bombs
{
mobj->threshold = mobj->info->painchance;
}
mobj->momz += max(min(z - mobj->z, vspeed), -vspeed);
}
}
else // Can we find a player to chase?
{
if (mobj->tracer == NULL || mobj->tracer->state != &states[mobj->tracer->info->spawnstate]
|| !P_LookForPlayers(mobj, true, false, 2000*mobj->scale)) // if not, circle around the spawnpoint
{
if (!mobj->spawnpoint) // unless we don't have one, in which case uhhh just circle around wherever we currently are I guess??
mobj->angle += DRAGONTURNSPEED;
else
{
fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale);
fixed_t x = mobj->spawnpoint->x << FRACBITS;
fixed_t y = mobj->spawnpoint->y << FRACBITS;
fixed_t z = mobj->spawnpoint->z << FRACBITS;
angle_t diff = R_PointToAngle2(mobj->x, mobj->y, x, y) - mobj->angle;
if (diff > ANGLE_180)
mobj->angle -= DRAGONTURNSPEED;
else
mobj->angle += DRAGONTURNSPEED;
mobj->momz += max(min(z - mobj->z, vspeed), -vspeed);
}
}
}
P_InstaThrust(mobj, mobj->angle, FixedMul(mobj->info->speed, mobj->scale));
#undef DRAGONTURNSPEED
}
break;
case MT_MINUS:
#ifdef ROTSPRITE
{
if (P_IsObjectOnGround(mobj))
mobj->rollangle = 0;
else
mobj->rollangle = R_PointToAngle2(0, 0, mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1));
}
#endif
break;
case MT_SPINFIRE:
if (mobj->flags & MF_NOGRAVITY)
{
@ -11207,7 +11311,7 @@ void P_SpawnPlayer(INT32 playernum)
mobj->radius = FixedMul(skins[p->skin].radius, mobj->scale);
mobj->height = P_GetPlayerHeight(p);
if (!leveltime && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage
if (!leveltime && !p->spectator && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage
{
if (maptol & TOL_NIGHTS)
{

View File

@ -2704,6 +2704,7 @@ boolean P_SetupLevel(boolean skipprecip)
// Cancel all d_main.c fadeouts (keep fade in though).
wipegamestate = FORCEWIPEOFF;
wipestyleflags = 0;
// Special stage fade to white
// This is handled BEFORE sounds are stopped.
@ -2724,11 +2725,22 @@ boolean P_SetupLevel(boolean skipprecip)
S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE);
#ifdef HWRENDER
// uh..........
if (rendermode == render_opengl)
F_WipeColorFill(0);
#endif
F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_speclevel_towhite], false);
I_OsPolling();
I_FinishUpdate(); // page flip or blit buffer
if (moviemode)
M_SaveFrame();
nowtime = lastwipetic;
// Hold on white for extra effect.
@ -2745,6 +2757,13 @@ boolean P_SetupLevel(boolean skipprecip)
ranspecialwipe = 1;
}
if (G_GetModeAttackRetryFlag())
{
if (modeattacking)
wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE);
G_ClearModeAttackRetryFlag();
}
// Make sure all sounds are stopped before Z_FreeTags.
S_StopSounds();
S_ClearSfx();
@ -2762,7 +2781,13 @@ boolean P_SetupLevel(boolean skipprecip)
if (rendermode != render_none && !ranspecialwipe)
{
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
wipestyleflags |= WSF_FADEOUT;
#ifdef HWRENDER
// uh..........
if (rendermode == render_opengl)
F_WipeColorFill(31);
#endif
F_WipeEndScreen();
// for titlemap: run a specific wipe if specified
@ -2787,12 +2812,12 @@ boolean P_SetupLevel(boolean skipprecip)
{
// Don't include these in the fade!
char tx[64];
V_DrawSmallString(1, 191, V_ALLOWLOWERCASE, M_GetText("Speeding off to..."));
V_DrawSmallString(1, 191, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Speeding off to..."));
snprintf(tx, 63, "%s%s%s",
mapheaderinfo[gamemap-1]->lvlttl,
(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE",
(mapheaderinfo[gamemap-1]->actnum > 0) ? va(", Act %d",mapheaderinfo[gamemap-1]->actnum) : "");
V_DrawSmallString(1, 195, V_ALLOWLOWERCASE, tx);
(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone",
(mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : "");
V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, tx);
I_UpdateNoVsync();
}
@ -3177,7 +3202,7 @@ boolean P_SetupLevel(boolean skipprecip)
// Remove the loading shit from the screen
if (rendermode != render_none && !titlemapinaction)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
F_WipeColorFill(levelfadecol);
if (precache || dedicated)
R_PrecacheLevel();
@ -3226,44 +3251,22 @@ boolean P_SetupLevel(boolean skipprecip)
#endif
}
// Stage title!
if (rendermode != render_none
&& (!titlemapinaction)
&& ranspecialwipe != 2
&& *mapheaderinfo[gamemap-1]->lvlttl != '\0'
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_stagetitle)
#endif
)
{
tic_t starttime = I_GetTime();
tic_t endtime = starttime + (10*NEWTICRATERATIO);
tic_t nowtime = starttime;
tic_t lasttime = starttime;
while (nowtime < endtime)
{
// draw loop
while (!((nowtime = I_GetTime()) - lasttime))
I_Sleep();
lasttime = nowtime;
// No render mode, stop here.
if (rendermode == render_none)
return true;
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
stplyr = &players[consoleplayer];
ST_drawLevelTitle(nowtime - starttime);
if (splitscreen)
{
stplyr = &players[secondarydisplayplayer];
ST_drawLevelTitle(nowtime - starttime);
}
// Title card!
G_StartTitleCard();
I_OsPolling();
I_UpdateNoBlit();
I_FinishUpdate(); // page flip or blit buffer
// Can the title card actually run, though?
if (!WipeStageTitle)
return true;
if (ranspecialwipe == 2)
return true;
if (moviemode) // make sure we save frames for the white hold too
M_SaveFrame();
}
}
// If so...
if ((!(mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)) && (*mapheaderinfo[gamemap-1]->lvlttl != '\0'))
G_PreLevelTitleCard(lt_ticker, true);
return true;
}

View File

@ -2721,6 +2721,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set
{
// Play sounds from tagged sectors' origins.
if (line->flags & ML_EFFECT5) // Repeat Midtexture
{
// Additionally play the sound from tagged sectors' soundorgs
@ -2732,31 +2733,45 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
S_StartSound(&sec->soundorg, sfxnum);
}
}
else if (mo) // A mobj must have triggered the executor
// Play the sound without origin for anyone, as long as they're inside tagged areas.
else
{
// Only trigger if mobj is touching the tag
UINT8 i = 0;
mobj_t* camobj = players[displayplayer].mo;
ffloor_t *rover;
boolean foundit = false;
for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
for (i = 0; i < 2; camobj = players[secondarydisplayplayer].mo, i++)
{
if (rover->master->frontsector->tag != line->tag)
if (!camobj)
continue;
if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
if (foundit || (camobj->subsector->sector->tag == line->tag))
{
foundit = true;
break;
}
if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
// Only trigger if mobj is touching the tag
for(rover = camobj->subsector->sector->ffloors; rover; rover = rover->next)
{
if (rover->master->frontsector->tag != line->tag)
continue;
foundit = true;
if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector))
continue;
if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, sectors + rover->secnum, camobj->subsector->sector))
continue;
foundit = true;
break;
}
}
if (mo->subsector->sector->tag == line->tag)
foundit = true;
if (!foundit)
return;
if (foundit)
S_StartSound(NULL, sfxnum);
}
}
else
@ -4439,59 +4454,55 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
case 3: // Linedef executor requires all players present
/// \todo check continues for proper splitscreen support?
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && !players[i].bot && players[i].mo && (gametype != GT_COOP || players[i].lives > 0))
{
if (!playeringame[i])
continue;
if (!players[i].mo)
continue;
if (players[i].spectator)
continue;
if (players[i].bot)
continue;
if (gametype == GT_COOP && players[i].lives <= 0)
continue;
if (roversector)
{
if (roversector)
if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
if (players[i].mo->subsector->sector == roversector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == roversector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
if (P_ThingIsOnThe3DFloor(players[i].mo, sector, node->m_sector))
break;
}
else
if (!node)
goto DoneSection2;
if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector))
}
else if (players[i].mo->subsector && !P_ThingIsOnThe3DFloor(players[i].mo, sector, players[i].mo->subsector->sector)) // this function handles basically everything for us lmao
goto DoneSection2;
}
else
{
if (players[i].mo->subsector->sector == sector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sector)
break;
}
if (!node)
goto DoneSection2;
}
else
{
if (players[i].mo->subsector->sector == sector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
}
else
goto DoneSection2;
goto DoneSection2;
if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector))
goto DoneSection2;
}
if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector))
goto DoneSection2;
}
}
/* FALLTHRU */
case 4: // Linedef executor that doesn't require touching floor
case 5: // Linedef executor
@ -4675,7 +4686,7 @@ DoneSection2:
{
INT32 lineindex;
P_DoPlayerExit(player);
P_DoPlayerFinish(player);
P_SetupSignExit(player);
// important: use sector->tag on next line instead of player->mo->subsector->tag

View File

@ -481,6 +481,9 @@ static inline void P_DoSpecialStageStuff(void)
tic_t oldnightstime = players[i].nightstime;
countspheres += players[i].spheres;
if (!oldnightstime)
continue;
// If in water, deplete timer 6x as fast.
if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER))
players[i].nightstime -= 5;
@ -506,12 +509,11 @@ static inline void P_DoSpecialStageStuff(void)
{
// Halt all the players
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
if (playeringame[i] && !players[i].exiting)
{
players[i].mo->momx = players[i].mo->momy = 0;
players[i].exiting = (14*TICRATE)/5 + 1;
}
sstimer = 0;
P_GiveEmerald(true);
P_RestoreMusic(&players[consoleplayer]);

View File

@ -343,13 +343,15 @@ void P_GiveEmerald(boolean spawnObj)
continue;
emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD);
if (!emmo)
continue;
P_SetTarget(&emmo->target, players[i].mo);
P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
P_SetTarget(&players[i].mo->tracer, emmo);
if (pnum == 255)
{
i = pnum;
pnum = i;
continue;
}
@ -636,6 +638,10 @@ static void P_DeNightserizePlayer(player_t *player)
player->marebonuslap = 0;
player->flyangle = 0;
player->anotherflyangle = 0;
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
P_SetTarget(&player->mo->target, NULL);
P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL));
@ -762,6 +768,9 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->secondjump = 0;
player->flyangle = 0;
player->anotherflyangle = 0;
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
player->powers[pw_shield] = SH_NONE;
player->powers[pw_super] = 0;
@ -1216,6 +1225,7 @@ void P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
//
void P_GivePlayerLives(player_t *player, INT32 numlives)
{
UINT8 prevlives = player->lives;
if (!player)
return;
@ -1232,10 +1242,9 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0)
{
UINT8 prevlives = player->lives;
P_GivePlayerRings(player, 100*numlives);
if (player->lives - prevlives >= numlives)
return;
goto docooprespawn;
numlives = (numlives + prevlives - player->lives);
}
@ -1249,6 +1258,15 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
player->lives = 99;
else if (player->lives < 1)
player->lives = 1;
docooprespawn:
if (cv_coopstarposts.value)
return;
if (prevlives > 0)
return;
if (!player->spectator)
return;
P_SpectatorJoinGame(player);
}
void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound)
@ -2124,6 +2142,34 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do
}
/** Called when \p player finishes the level.
*
* Only use for cases where the player should be able to move
* while waiting for others to finish. Otherwise, use P_DoPlayerExit().
*
* In single player or if ::cv_exitmove is disabled, this will also cause
* P_PlayerThink() to call P_DoPlayerExit(), so you do not need to
* make a special cases for those.
*
* \param player The player who finished the level.
* \sa P_DoPlayerExit
*
*/
void P_DoPlayerFinish(player_t *player)
{
if (player->pflags & PF_FINISHED)
return;
player->pflags |= PF_FINISHED;
if (netgame)
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);
player->powers[pw_underwater] = 0;
player->powers[pw_spacetime] = 0;
P_RestoreMusic(player);
}
//
// P_DoPlayerExit
//
@ -2158,12 +2204,14 @@ void P_DoPlayerExit(player_t *player)
player->pflags |= P_GetJumpFlags(player);
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
}
else if (player->pflags & PF_STARTDASH)
{
player->pflags &= ~PF_STARTDASH;
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
player->powers[pw_underwater] = 0;
player->powers[pw_spacetime] = 0;
P_RestoreMusic(player);
if (playeringame[player-players] && netgame && !circuitmap)
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);
}
#define SPACESPECIAL 12
@ -2263,7 +2311,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
else if (!player->skidtime)
player->pflags &= ~PF_GLIDING;
}
else if (player->charability == CA_GLIDEANDCLIMB && player->pflags & PF_THOKKED && !(player->pflags & PF_SHIELDABILITY) && player->mo->state-states == S_PLAY_FALL)
else if (player->charability == CA_GLIDEANDCLIMB && player->pflags & PF_THOKKED && !(player->pflags & (PF_JUMPED|PF_SHIELDABILITY)) && player->mo->state-states == S_PLAY_FALL)
{
if (player->mo->state-states != S_PLAY_GLIDE_LANDING)
{
@ -2326,11 +2374,23 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
;
else if (player->panim != PA_IDLE && player->panim != PA_WALK && player->panim != PA_RUN && player->panim != PA_DASH)
{
fixed_t runspd = FixedMul(player->runspeed, player->mo->scale);
// See comments in P_MovePlayer for explanation of changes.
if (player->powers[pw_super])
runspd = FixedMul(runspd, 5*FRACUNIT/3);
runspd = FixedMul(runspd, player->mo->movefactor);
if (maptol & TOL_2D)
runspd = FixedMul(runspd, 2*FRACUNIT/3);
if (player->cmomx || player->cmomy)
{
if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
else if (player->speed >= runspd
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
else if ((player->rmomx || player->rmomy)
@ -2343,7 +2403,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
{
if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
else if (player->speed >= runspd
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
else if ((player->mo->momx || player->mo->momy)
@ -2827,7 +2887,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
{
tic_t timeleft = (player->powers[pw_spacetime]) ? player->powers[pw_spacetime] : player->powers[pw_underwater];
if (player->exiting)
if (player->exiting || (player->pflags & PF_FINISHED))
player->powers[pw_underwater] = player->powers[pw_spacetime] = 0;
timeleft--; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity
@ -3478,7 +3538,7 @@ static void P_DoClimbing(player_t *player)
{
P_SetObjectMomZ(player->mo, 2*FRACUNIT, true);
if (cmd->forwardmove)
P_SetObjectMomZ(player->mo, 2*player->mo->momz/3, false);
player->mo->momz = 2*player->mo->momz/3;
}
if (thrust)
P_Thrust(player->mo, player->mo->angle, FixedMul(4*FRACUNIT, player->mo->scale)); // Lil' boost up.
@ -3993,12 +4053,14 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
if (player->pflags & PF_ATTACKDOWN || player->climbing || (G_TagGametype() && !(player->pflags & PF_TAGIT)))
return;
if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->weapondelay))
{
player->pflags |= PF_ATTACKDOWN;
mo = P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0);
P_InstaThrust(mo, player->mo->angle, ((mo->info->speed>>FRACBITS)*player->mo->scale) + player->speed);
if (mo)
P_InstaThrust(mo, player->mo->angle, ((mo->info->speed>>FRACBITS)*player->mo->scale) + player->speed);
S_StartSound(player->mo, sfx_mario7);
P_SetWeaponDelay(player, TICRATE); // Short delay between fireballs so you can't spam them everywhere
return;
}
@ -4017,8 +4079,8 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING);
if (mo)
mo->fuse = 3*TICRATE; // Bounce Ring time
if (mo)
mo->fuse = 3*TICRATE; // Bounce Ring time
}
// Rail ring
else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring])
@ -4391,7 +4453,11 @@ void P_DoJump(player_t *player, boolean soundandstate)
}
else if (player->powers[pw_carry] == CR_ROLLOUT)
{
player->mo->momz = 9*FRACUNIT + player->mo->tracer->momz;
player->mo->momz = 9*FRACUNIT;
if (P_MobjFlip(player->mo->tracer)*player->mo->tracer->momz > 0)
player->mo->momz += player->mo->tracer->momz;
if (!P_IsObjectOnGround(player->mo->tracer))
P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true);
player->powers[pw_carry] = CR_NONE;
player->mo->tracer->flags |= MF_PUSHABLE;
P_SetTarget(&player->mo->tracer->tracer, NULL);
@ -4562,6 +4628,13 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
// Revving
else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH))
{
if (player->speed > 5*player->mo->scale)
{
player->pflags &= ~PF_STARTDASH;
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_spin);
break;
}
if (player->dashspeed < player->maxdash)
{
#define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash)
@ -4577,7 +4650,6 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
G_GhostAddRev();
}
}
// If not moving up or down, and travelling faster than a speed of five while not holding
// down the spin button and not spinning.
// AKA Just go into a spin on the ground, you idiot. ;)
@ -4729,10 +4801,10 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
// Rolling normally
if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH)
&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale) && canstand)
&& player->speed < 5*player->mo->scale && canstand)
{
if (GETSECSPECIAL(player->mo->subsector->sector->special, 4) == 7 || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player)))
P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale));
P_InstaThrust(player->mo, player->mo->angle, 10*player->mo->scale);
else
{
player->skidtime = 0;
@ -5295,7 +5367,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer
player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_STARTDASH);
player->pflags |= (PF_THOKKED|PF_CANCARRY);
if (player->bot == 1)
player->pflags |= PF_THOKKED;
else
player->pflags |= (PF_THOKKED|PF_CANCARRY);
}
break;
case CA_GLIDEANDCLIMB:
@ -5496,7 +5571,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
else
potentialmomz = ((player->speed < 10*player->mo->scale)
? (player->speed - 10*player->mo->scale)/5
: 0);
: -1); // Should be 0, but made negative to ensure P_PlayerHitFloor runs upon touching ground
if (P_MobjFlip(player->mo)*player->mo->momz < potentialmomz)
player->mo->momz = P_MobjFlip(player->mo)*potentialmomz;
player->pflags &= ~PF_SPINNING;
@ -5891,6 +5966,8 @@ static void P_3dMovement(player_t *player)
// When sliding, don't allow forward/back
if (player->pflags & PF_SLIDING)
cmd->forwardmove = 0;
else if (onground && player->mo->state == states+S_PLAY_PAIN)
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
player->aiming = cmd->aiming<<FRACBITS;
@ -7705,6 +7782,9 @@ void P_ElementalFire(player_t *player, boolean cropcircle)
else
ground = player->mo->floorz;
if (cropcircle)
ground += P_MobjFlip(player->mo);
if (cropcircle)
{
#define numangles 8
@ -7882,6 +7962,11 @@ static void P_MovePlayer(player_t *player)
cmd = &player->cmd;
runspd = FixedMul(player->runspeed, player->mo->scale);
// This was done in Sonic 3 & Knuckles, but has been missed in Sonic Mania and the Taxman/Stealth mobile remakes. Thanks to NeoHazard for his 2017 blogpost on the matter, because this oversight otherwise almost made it all the way to 2.2's release.
//https://s3unlocked.blogspot.com/2017/12/over-threshold.html
if (player->powers[pw_super])
runspd = FixedMul(runspd, 5*FRACUNIT/3);
// Let's have some movement speed fun on low-friction surfaces, JUST for players... (high friction surfaces shouldn't have any adjustment, since the acceleration in this game is super high and that ends up cheesing high-friction surfaces.)
runspd = FixedMul(runspd, player->mo->movefactor);
@ -8364,7 +8449,7 @@ static void P_MovePlayer(player_t *player)
// Tails Put-Put noise
if (player->charability == CA_FLY
&& player->bot != 1
&& (player->pflags & PF_CANCARRY)
&& !(player->mo->eflags & MFE_UNDERWATER)
&& leveltime % 10 == 0
&& !player->spectator)
@ -9420,7 +9505,6 @@ static void P_DeathThink(player_t *player)
}
else if ((netgame || multiplayer) && player->deadtimer >= 8*TICRATE)
{
INT32 i, deadtimercheck = INT32_MAX;
// In a net/multiplayer game, and out of lives
@ -9590,8 +9674,25 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
mo = player->mo;
if (player->exiting && mo->target && mo->target->type == MT_SIGN)
sign = mo->target;
if (player->playerstate == PST_REBORN)
{
P_CalcChasePostImg(player, thiscam);
return true;
}
if (player->exiting)
{
if (mo->target && mo->target->type == MT_SIGN && mo->target->spawnpoint
&& !(gametype == GT_COOP && (netgame || multiplayer) && cv_exitmove.value))
sign = mo->target;
else if ((player->powers[pw_carry] == CR_NIGHTSMODE)
&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6]))
{
P_CalcChasePostImg(player, thiscam);
return true;
}
}
cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!!
@ -9671,7 +9772,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camorbit = (!stricmp(cv_cam_orbit.defaultvalue, "off")) ? false : true;
camrotate = atoi(cv_cam_rotate.defaultvalue);
camdist = FixedMul((INT32)(atof(cv_cam_dist.defaultvalue) * FRACUNIT), mo->scale);
camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), FixedMul(player->camerascale, mo->scale));
camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), mo->scale);
}
else if (thiscam == &camera)
{
@ -9680,7 +9781,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camorbit = cv_cam_orbit.value;
camrotate = cv_cam_rotate.value;
camdist = FixedMul(cv_cam_dist.value, mo->scale);
camheight = FixedMul(cv_cam_height.value, FixedMul(player->camerascale, mo->scale));
camheight = FixedMul(cv_cam_height.value, mo->scale);
}
else // Camera 2
{
@ -9689,9 +9790,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camorbit = cv_cam2_orbit.value;
camrotate = cv_cam2_rotate.value;
camdist = FixedMul(cv_cam2_dist.value, mo->scale);
camheight = FixedMul(cv_cam2_height.value, FixedMul(player->camerascale, mo->scale));
camheight = FixedMul(cv_cam2_height.value, mo->scale);
}
if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE))
camheight = FixedMul(camheight, player->camerascale);
#ifdef REDSANALOG
if (P_AnalogMove(player) && (player->cmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)) {
camstill = true;
@ -9802,9 +9906,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
dist <<= 1;
}
if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE))
dist = FixedMul(dist, player->camerascale);
checkdist = (dist = FixedMul(dist, player->camerascale));
checkdist = dist;
if (checkdist < 128*FRACUNIT)
checkdist = 128*FRACUNIT;
@ -9889,10 +9994,20 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
pviewheight = FixedMul(41*player->height/48, mo->scale);
if (mo->eflags & MFE_VERTICALFLIP)
z = mo->z + mo->height - pviewheight - camheight + distz;
if (sign)
{
if (mo->eflags & MFE_VERTICALFLIP)
z = sign->ceilingz - pviewheight - camheight;
else
z = sign->floorz + pviewheight + camheight;
}
else
z = mo->z + pviewheight + camheight + distz;
{
if (mo->eflags & MFE_VERTICALFLIP)
z = mo->z + mo->height - pviewheight - camheight + distz;
else
z = mo->z + pviewheight + camheight + distz;
}
// move camera down to move under lower ceilings
newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1));
@ -10112,17 +10227,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (!camstill && !resetcalled && !paused)
thiscam->angle = R_PointToAngle2(thiscam->x, thiscam->y, viewpointx, viewpointy);
if (sign)
{
viewpointx = sign->x + FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
viewpointy = sign->y + FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
}
else
{
viewpointx = mo->x + FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
viewpointy = mo->y + FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
}
/*
if (twodlevel || (mo->flags2 & MF2_TWOD))
thiscam->angle = angle;
@ -10166,9 +10270,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
dist = FixedHypot(f1, f2);
if (mo->eflags & MFE_VERTICALFLIP)
angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, mo->z + mo->height - P_GetPlayerHeight(player));
angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, (sign ? sign->ceilingz : mo->z + mo->height) - P_GetPlayerHeight(player));
else
angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + P_GetPlayerHeight(player));
angle = R_PointToAngle2(0, thiscam->z, dist, (sign ? sign->floorz : mo->z) + P_GetPlayerHeight(player));
if (player->playerstate != PST_DEAD)
angle += (focusaiming < ANGLE_180 ? focusaiming/2 : InvAngle(InvAngle(focusaiming)/2)); // overcomplicated version of '((signed)focusaiming)/2;'
@ -10328,6 +10432,7 @@ boolean P_SpectatorJoinGame(player_t *player)
return false;
}
// the below is first person only, if you're curious. check out P_CalcChasePostImg in p_mobj.c for chasecam
static void P_CalcPostImg(player_t *player)
{
sector_t *sector = player->mo->subsector->sector;
@ -11400,6 +11505,14 @@ void P_PlayerThink(player_t *player)
}
}
if (player->pflags & PF_FINISHED)
{
if ((gametype == GT_COOP && cv_exitmove.value) && !G_EnoughPlayersFinished())
player->exiting = 0;
else
P_DoPlayerExit(player);
}
// check water content, set stuff in mobj
P_MobjCheckWater(player->mo);
@ -12276,7 +12389,7 @@ void P_PlayerAfterThink(player_t *player)
player->mo->momz = tails->momz;
}
if (gametype == GT_COOP)
if (gametype == GT_COOP && (!tails->player || tails->player->bot != 1))
{
player->mo->angle = tails->angle;

View File

@ -24,6 +24,7 @@
#include "z_zone.h"
#include "p_setup.h" // levelflats
#include "v_video.h" // pMasterPalette
#include "f_finale.h" // wipes
#include "byteptr.h"
#include "dehacked.h"
@ -113,6 +114,7 @@ INT32 *texturetranslation;
sprcache_t *spritecachedinfo;
lighttable_t *colormaps;
lighttable_t *fadecolormap;
// for debugging/info purposes
size_t flatmemory, spritememory, texturememory;
@ -1455,18 +1457,111 @@ static void R_InitSpriteLumps(void)
Z_Malloc(max_spritelumps*sizeof(*spritecachedinfo), PU_STATIC, &spritecachedinfo);
}
//
// R_CreateFadeColormaps
//
static void R_CreateFadeColormaps(void)
{
UINT8 px, fade;
RGBA_t rgba;
INT32 r, g, b;
size_t len, i;
len = (256 * FADECOLORMAPROWS);
fadecolormap = Z_MallocAlign(len*2, PU_STATIC, NULL, 8);
for (i = 0; i < len*2; i++)
fadecolormap[i] = (i%256);
// Load in the light tables, now 64k aligned for smokie...
{
lumpnum_t lump = W_CheckNumForName("FADECMAP");
lumpnum_t wlump = W_CheckNumForName("FADEWMAP");
// to black
if (lump != LUMPERROR)
W_ReadLumpHeader(lump, fadecolormap, len, 0U);
// to white
if (wlump != LUMPERROR)
W_ReadLumpHeader(wlump, fadecolormap+len, len, 0U);
// missing "to white" colormap lump
if (lump != LUMPERROR && wlump == LUMPERROR)
goto makewhite;
// missing "to black" colormap lump
else if (lump == LUMPERROR && wlump != LUMPERROR)
goto makeblack;
// both lumps found
else if (lump != LUMPERROR && wlump != LUMPERROR)
return;
}
#define GETCOLOR \
px = colormaps[i%256]; \
fade = (i/256) * (256 / FADECOLORMAPROWS); \
rgba = V_GetColor(px);
// to black
makeblack:
for (i = 0; i < len; i++)
{
// find pixel and fade amount
GETCOLOR;
// subtractive color blending
r = rgba.s.red - FADEREDFACTOR*fade/10;
g = rgba.s.green - FADEGREENFACTOR*fade/10;
b = rgba.s.blue - FADEBLUEFACTOR*fade/10;
// clamp values
if (r < 0) r = 0;
if (g < 0) g = 0;
if (b < 0) b = 0;
// find nearest color in palette
fadecolormap[i] = NearestColor(r,g,b);
}
// to white
makewhite:
for (i = len; i < len*2; i++)
{
// find pixel and fade amount
GETCOLOR;
// additive color blending
r = rgba.s.red + FADEREDFACTOR*fade/10;
g = rgba.s.green + FADEGREENFACTOR*fade/10;
b = rgba.s.blue + FADEBLUEFACTOR*fade/10;
// clamp values
if (r > 255) r = 255;
if (g > 255) g = 255;
if (b > 255) b = 255;
// find nearest color in palette
fadecolormap[i] = NearestColor(r,g,b);
}
#undef GETCOLOR
}
//
// R_InitColormaps
//
static void R_InitColormaps(void)
{
size_t len;
lumpnum_t lump;
// Load in the light tables
lump = W_GetNumForName("COLORMAP");
colormaps = Z_MallocAlign(W_LumpLength (lump), PU_STATIC, NULL, 8);
len = W_LumpLength(lump);
colormaps = Z_MallocAlign(len, PU_STATIC, NULL, 8);
W_ReadLump(lump, colormaps);
// Make colormap for fades
R_CreateFadeColormaps();
// Init Boom colormaps.
R_ClearColormaps();
#ifdef EXTRACOLORMAPLUMPS
@ -1495,6 +1590,9 @@ void R_ReInitColormaps(UINT16 num)
}
W_ReadLumpHeader(lump, colormaps, W_LumpLength(basecolormaplump), 0U);
if (fadecolormap)
Z_Free(fadecolormap);
R_CreateFadeColormaps();
// Init Boom colormaps.
R_ClearColormaps();

View File

@ -410,6 +410,8 @@ typedef enum
ST_NEGATIVE
} slopetype_t;
#define HORIZONSPECIAL 41
typedef struct line_s
{
// Vertices, from v1 to v2.

View File

@ -123,8 +123,12 @@ consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChan
consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif //#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
#ifdef GLBADSHADOWS
consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif //#ifdef GLBADSHADOWS
consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
@ -1172,8 +1176,12 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_chasecam);
CV_RegisterVar(&cv_chasecam2);
#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
CV_RegisterVar(&cv_shadow);
#endif //#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
#ifdef GLBADSHADOWS
CV_RegisterVar(&cv_shadowoffs);
#endif //#ifdef GLBADSHADOWS
CV_RegisterVar(&cv_skybox);
CV_RegisterVar(&cv_cam_dist);

View File

@ -76,7 +76,12 @@ extern consvar_t cv_showhud, cv_translucenthud;
extern consvar_t cv_homremoval;
extern consvar_t cv_chasecam, cv_chasecam2;
extern consvar_t cv_flipcam, cv_flipcam2;
extern consvar_t cv_shadow, cv_shadowoffs;
#if defined(FLOORSPLATS) || defined(GLBADSHADOWS)
extern consvar_t cv_shadow;
#endif
#ifdef GLBADSHADOWS
extern conscar_t cv_shadowoffs;
#endif //#ifdef GLBADSHADOWS
extern consvar_t cv_translucency;
extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip;
extern consvar_t cv_skybox;

View File

@ -1007,6 +1007,8 @@ void R_DrawSinglePlane(visplane_t *pl)
R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum));
// Raw flats always have dimensions that are powers-of-two numbers.
ds_powersoftwo = true;
if (spanfunc == basespanfunc)
spanfunc = mmxspanfunc;
break;
default:
switch (type)

View File

@ -2694,7 +2694,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
worldbottomslope >>= 4;
#endif
if (linedef->special == 41) { // HORIZON LINES
if (linedef->special == HORIZONSPECIAL) { // HORIZON LINES
topstep = bottomstep = 0;
topfrac = bottomfrac = (centeryfrac>>4);
topfrac++; // Prevent 1px HOM
@ -2825,7 +2825,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#ifdef ESLOPE
ffloor[i].f_pos_slope >>= 4;
#endif
if (linedef->special == 41) // Horizon lines extend FOFs in contact with them too.
if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too.
{
ffloor[i].f_step = 0;
ffloor[i].f_frac = (centeryfrac>>4);

View File

@ -38,6 +38,7 @@ typedef struct
extern sprcache_t *spritecachedinfo;
extern lighttable_t *colormaps;
extern lighttable_t *fadecolormap;
// Boom colormaps.
extern extracolormap_t *extra_colormaps;

View File

@ -1137,8 +1137,6 @@ static void R_ProjectSprite(mobj_t *thing)
UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS;
#endif
fixed_t ang_scale = FRACUNIT;
// transform the origin point
tr_x = thing->x - viewx;
tr_y = thing->y - viewy;
@ -1196,20 +1194,20 @@ static void R_ProjectSprite(mobj_t *thing)
#ifdef ROTSPRITE
sprinfo = NULL;
#endif
}
if (rot >= sprdef->numframes)
{
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
rot = thing->frame&FF_FRAMEMASK;
if (!thing->skin)
if (rot >= sprdef->numframes)
{
thing->state->sprite = thing->sprite;
thing->state->frame = thing->frame;
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
if (thing->sprite == thing->state->sprite && thing->frame == thing->state->frame)
{
thing->state->sprite = states[S_UNKNOWN].sprite;
thing->state->frame = states[S_UNKNOWN].frame;
}
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
rot = thing->frame&FF_FRAMEMASK;
}
}
@ -1223,8 +1221,6 @@ static void R_ProjectSprite(mobj_t *thing)
if (sprframe->rotate != SRF_SINGLE || papersprite)
{
ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle);
if (papersprite)
ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT));
}
if (sprframe->rotate == SRF_SINGLE)
@ -1286,24 +1282,11 @@ static void R_ProjectSprite(mobj_t *thing)
else
offset = -spr_offset;
offset = FixedMul(offset, this_scale);
tx += FixedMul(offset, ang_scale);
x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
// off the right side?
if (x1 > viewwidth)
return;
offset2 = FixedMul(spr_width, this_scale);
tx += FixedMul(offset2, ang_scale);
x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - (papersprite ? 2 : 1);
// off the left side
if (x2 < 0)
return;
if (papersprite)
{
fixed_t yscale2, cosmul, sinmul, tz2;
fixed_t xscale2, yscale2, cosmul, sinmul, tz2;
INT32 range;
if (ang >= ANGLE_180)
@ -1323,6 +1306,16 @@ static void R_ProjectSprite(mobj_t *thing)
yscale = FixedDiv(projectiony, tz);
if (yscale < 64) return; // Fix some funky visuals
gxt = -FixedMul(tr_x, viewsin);
gyt = FixedMul(tr_y, viewcos);
tx = -(gyt + gxt);
xscale = FixedDiv(projection, tz);
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
// off the right side?
if (x1 > viewwidth)
return;
tr_x += FixedMul(offset2, cosmul);
tr_y += FixedMul(offset2, sinmul);
gxt = FixedMul(tr_x, viewcos);
@ -1331,15 +1324,25 @@ static void R_ProjectSprite(mobj_t *thing)
yscale2 = FixedDiv(projectiony, tz2);
if (yscale2 < 64) return; // ditto
gxt = -FixedMul(tr_x, viewsin);
gyt = FixedMul(tr_y, viewcos);
tx = -(gyt + gxt);
xscale2 = FixedDiv(projection, tz2);
x2 = (centerxfrac + FixedMul(tx,xscale2))>>FRACBITS; x2--;
// off the left side
if (x2 < 0)
return;
if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
return;
if (x2 > x1)
range = (x2 - x1);
else
if ((range = x2 - x1) <= 0)
range = 1;
scalestep = (yscale2 - yscale)/range ?: 1;
scalestep = (yscale2 - yscale)/range;
scalestep = scalestep ? scalestep : 1;
xscale = FixedDiv(range<<FRACBITS, abs(offset2))+1;
// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
// sortscale = max(yscale, yscale2);
@ -1349,9 +1352,20 @@ static void R_ProjectSprite(mobj_t *thing)
{
scalestep = 0;
yscale = sortscale;
}
tx += offset;
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
xscale = FixedMul(xscale, ang_scale);
// off the right side?
if (x1 > viewwidth)
return;
tx += offset2;
x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--;
// off the left side
if (x2 < 0)
return;
}
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
{

View File

@ -860,7 +860,6 @@ static INT32 actualmidimusicvolume;
void S_UpdateSounds(void)
{
INT32 audible, cnum, volume, sep, pitch;
UINT8 i;
channel_t *c;
listener_t listener;
@ -1017,28 +1016,30 @@ void S_UpdateSounds(void)
notinlevel:
I_UpdateSound();
}
void S_UpdateClosedCaptions(void)
{
UINT8 i;
boolean gamestopped = (paused || P_AutoPause());
for (i = 0; i < NUMCAPTIONS; i++) // update captions
{
boolean gamestopped = (paused || P_AutoPause());
for (i = 0; i < NUMCAPTIONS; i++) // update captions
if (!closedcaptions[i].s)
continue;
if (i == 0 && (closedcaptions[0].s-S_sfx == sfx_None) && gamestopped)
continue;
if (!(--closedcaptions[i].t))
{
if (!closedcaptions[i].s)
continue;
if (i == 0 && (closedcaptions[0].s-S_sfx == sfx_None) && gamestopped)
continue;
if (!(--closedcaptions[i].t))
{
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;
}
else if (closedcaptions[i].c && !I_SoundIsPlaying(closedcaptions[i].c->handle))
{
closedcaptions[i].c = NULL;
if (closedcaptions[i].t > CAPTIONFADETICS)
closedcaptions[i].t = CAPTIONFADETICS;
}
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;
}
else if (closedcaptions[i].c && !I_SoundIsPlaying(closedcaptions[i].c->handle))
{
closedcaptions[i].c = NULL;
if (closedcaptions[i].t > CAPTIONFADETICS)
closedcaptions[i].t = CAPTIONFADETICS;
}
}
}
@ -1685,7 +1686,7 @@ boolean S_PrepareSoundTest(void)
soundtestdefs[pos++] = def;
if (def->soundtestcond > 0 && !(mapvisited[def->soundtestcond-1] & MV_BEATEN))
continue;
if (def->soundtestcond < 0 && !M_Achieved(1-def->soundtestcond))
if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond))
continue;
def->allowed = true;
}

View File

@ -303,6 +303,7 @@ boolean S_FadeOutStopMusic(UINT32 ms);
// Updates music & sounds
//
void S_UpdateSounds(void);
void S_UpdateClosedCaptions(void);
FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);

View File

@ -421,13 +421,24 @@ void SCR_DisplayTicRate(void)
else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP;
V_DrawString(vid.width-(72*vid.dupx), h,
V_YELLOWMAP|V_NOSCALESTART|V_HUDTRANS, "FPS:");
V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:");
V_DrawString(vid.width-(40*vid.dupx), h,
ticcntcolor|V_NOSCALESTART|V_HUDTRANS, va("%02d/%02u", totaltics, TICRATE));
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d/%02u", totaltics, TICRATE));
lasttic = ontic;
}
void SCR_DisplayLocalPing(void)
{
UINT32 ping = playerpingtable[consoleplayer]; // consoleplayer's ping is everyone's ping in a splitnetgame :P
if (cv_showping.value == 1 || (cv_showping.value == 2 && servermaxping && ping > servermaxping)) // only show 2 (warning) if our ping is at a bad level
{
INT32 dispy = cv_ticrate.value ? 180 : 189;
HU_drawPing(307, dispy, ping, true, V_SNAPTORIGHT | V_SNAPTOBOTTOM);
}
}
void SCR_ClosedCaptions(void)
{
UINT8 i;

View File

@ -167,5 +167,6 @@ FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
// move out to main code for consistency
void SCR_DisplayTicRate(void);
void SCR_ClosedCaptions(void);
void SCR_DisplayLocalPing(void);
#undef DNWH
#endif //__SCREEN_H__

View File

@ -1176,11 +1176,11 @@ void I_FinishUpdate(void)
if (cv_closedcaptioning.value)
SCR_ClosedCaptions();
if (st_overlay)
{
if (cv_ticrate.value)
SCR_DisplayTicRate();
}
if (cv_ticrate.value)
SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
if (rendermode == render_soft && screens[0])
{

View File

@ -92,7 +92,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"pstop", false, 100, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"},
{"steam1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001
{"steam2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001
{"wbreak", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"},
{"wbreak", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"},
{"ambmac", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machinery"},
{"spsmsh", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy impact"},
@ -208,7 +208,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"shrpsp", true, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spincushion"},
{"shrpgo", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"},
{"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning out"},
{"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"},
{"mspogo", true, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"},
{"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"},
{"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"},
{"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"},
@ -779,7 +779,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"kc49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop-shot"},
{"kc4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power up"},
{"kc4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},

View File

@ -23,6 +23,7 @@
#include "v_video.h"
#include "z_zone.h"
#include "hu_stuff.h"
#include "console.h"
#include "s_sound.h"
#include "i_system.h"
#include "m_menu.h"
@ -186,14 +187,18 @@ boolean ST_SameTeam(player_t *a, player_t *b)
static boolean st_stopped = true;
void ST_Ticker(void)
void ST_Ticker(boolean run)
{
if (st_stopped)
return;
if (run)
ST_runTitleCard();
}
// 0 is default, any others are special palettes.
INT32 st_palette = 0;
INT32 st_translucency = 10;
void ST_doPaletteStuff(void)
{
@ -348,12 +353,12 @@ void ST_LoadGraphics(void)
// made separate so that skins code can reload custom face graphics
void ST_LoadFaceGraphics(INT32 skinnum)
{
if (skins[skinnum].sprites[SPR2_XTRA].numframes)
if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_LIFEPIC)
{
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC];
faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes)
if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC)
{
sprdef = &skins[skinnum].sprites[SPR2_XTRA|FF_SPR2SUPER];
sprframe = &sprdef->spriteframes[0];
@ -818,7 +823,7 @@ static void ST_drawLivesArea(void)
face = superprefix[stplyr->skin];
V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y,
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, face, colormap);
if (cv_translucenthud.value == 10 && stplyr->powers[pw_super] == 1 && stplyr->mo->tracer)
if (st_translucency == 10 && stplyr->powers[pw_super] == 1 && stplyr->mo->tracer)
{
INT32 v_supertrans = (stplyr->mo->tracer->frame & FF_TRANSMASK) >> FF_TRANSSHIFT;
if (v_supertrans < 10)
@ -1160,16 +1165,142 @@ static void ST_drawInput(void)
V_DrawThinString(x, y, hudinfo[HUD_LIVES].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!");
}
void ST_drawLevelTitle(tic_t titletime)
static patch_t *lt_patches[3];
static INT32 lt_scroll = 0;
static INT32 lt_mom = 0;
static INT32 lt_zigzag = 0;
tic_t lt_ticker = 0, lt_lasttic = 0;
tic_t lt_exitticker = 0, lt_endtime = 0;
//
// Load the graphics for the title card.
//
static void ST_cacheLevelTitle(void)
{
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE))
{
lt_patches[0] = (patch_t *)W_CachePatchName("LTACTBLU", PU_HUDGFX);
lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGZAG", PU_HUDGFX);
lt_patches[2] = (patch_t *)W_CachePatchName("LTZZTEXT", PU_HUDGFX);
}
else // boss map
{
lt_patches[0] = (patch_t *)W_CachePatchName("LTACTRED", PU_HUDGFX);
lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGRED", PU_HUDGFX);
lt_patches[2] = (patch_t *)W_CachePatchName("LTZZWARN", PU_HUDGFX);
}
}
//
// Start the title card.
//
void ST_startTitleCard(void)
{
// cache every HUD patch used
ST_cacheLevelTitle();
// initialize HUD variables
lt_ticker = lt_exitticker = lt_lasttic = 0;
lt_endtime = 2*TICRATE + (10*NEWTICRATERATIO);
lt_scroll = BASEVIDWIDTH * FRACUNIT;
lt_zigzag = -((lt_patches[1])->width * FRACUNIT);
lt_mom = 0;
}
//
// What happens before drawing the title card.
// Which is just setting the HUD translucency.
//
void ST_preDrawTitleCard(void)
{
if (lt_ticker >= (lt_endtime + TICRATE))
return;
if (!lt_exitticker)
st_translucency = 0;
else
st_translucency = max(0, min((INT32)lt_exitticker-4, cv_translucenthud.value));
}
//
// Run the title card.
// Called from ST_Ticker.
//
void ST_runTitleCard(void)
{
if (lt_ticker >= (lt_endtime + TICRATE))
return;
if (!(paused || P_AutoPause()))
{
// tick
lt_ticker++;
if (lt_ticker >= lt_endtime)
lt_exitticker++;
// scroll to screen (level title)
if (!lt_exitticker)
{
if (abs(lt_scroll) > FRACUNIT)
lt_scroll -= (lt_scroll>>2);
else
lt_scroll = 0;
}
// scroll away from screen (level title)
else
{
lt_mom -= FRACUNIT*6;
lt_scroll += lt_mom;
}
// scroll to screen (zigzag)
if (!lt_exitticker)
{
if (abs(lt_zigzag) > FRACUNIT)
lt_zigzag -= (lt_zigzag>>2);
else
lt_zigzag = 0;
}
// scroll away from screen (zigzag)
else
lt_zigzag += lt_mom;
}
}
//
// Draw the title card itself.
//
void ST_drawTitleCard(void)
{
char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl;
char *subttl = mapheaderinfo[gamemap-1]->subttl;
INT32 actnum = mapheaderinfo[gamemap-1]->actnum;
INT32 lvlttly, zoney, lvlttlxpos, ttlnumxpos, zonexpos;
INT32 lvlttlxpos, ttlnumxpos, zonexpos;
INT32 subttlxpos = BASEVIDWIDTH/2;
INT32 ttlscroll = FixedInt(lt_scroll);
INT32 zzticker;
patch_t *actpat, *zigzag, *zztext;
if (!(titletime > 2 && titletime-3 < 110))
#ifdef HAVE_BLUA
if (!LUA_HudEnabled(hud_stagetitle))
goto luahook;
#endif
if (lt_ticker >= (lt_endtime + TICRATE))
#ifdef HAVE_BLUA
goto luahook;
#else
return;
#endif
if ((lt_ticker-lt_lasttic) > 1)
lt_ticker = lt_lasttic+1;
ST_cacheLevelTitle();
actpat = lt_patches[0];
zigzag = lt_patches[1];
zztext = lt_patches[2];
lvlttlxpos = ((BASEVIDWIDTH/2) - (V_LevelNameWidth(lvlttl)/2));
@ -1177,72 +1308,71 @@ void ST_drawLevelTitle(tic_t titletime)
lvlttlxpos -= V_LevelActNumWidth(actnum);
ttlnumxpos = lvlttlxpos + V_LevelNameWidth(lvlttl);
zonexpos = ttlnumxpos - V_LevelNameWidth(M_GetText("ZONE"));
zonexpos = ttlnumxpos - V_LevelNameWidth(M_GetText("Zone"));
ttlnumxpos++;
if (lvlttlxpos < 0)
lvlttlxpos = 0;
#if 0 // toaster's experiment. srb2&toast.exe one day, maybe? Requires stuff below to be converted to fixed point.
#define MIDTTLY 79
#define MIDZONEY 105
#define MIDDIFF 4
if (titletime < 10)
if (!splitscreen || (splitscreen && stplyr == &players[displayplayer]))
{
fixed_t z = ((titletime - 3)<<FRACBITS)/7;
INT32 ttlh = V_LevelNameHeight(lvlttl);
zoney = (200<<FRACBITS) - ((200 - (MIDZONEY + MIDDIFF))*z);
lvlttly = ((MIDTTLY + ttlh - MIDDIFF)*z) - (ttlh<<FRACBITS);
zzticker = lt_ticker;
V_DrawScaledPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag);
V_DrawScaledPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag);
V_DrawScaledPatch(FixedInt(lt_zigzag), (-zigzag->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext);
V_DrawScaledPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext);
}
else if (titletime < 105)
{
fixed_t z = (((titletime - 10)*MIDDIFF)<<(FRACBITS+1))/95;
zoney = ((MIDZONEY + MIDDIFF)<<FRACBITS) - z;
lvlttly = ((MIDTTLY - MIDDIFF)<<FRACBITS) + z;
}
else
{
fixed_t z = ((titletime - 105)<<FRACBITS)/7;
INT32 zoneh = V_LevelNameHeight(M_GetText("ZONE"));
zoney = (MIDZONEY + zoneh - MIDDIFF)*(FRACUNIT - z) - (zoneh<<FRACBITS);
lvlttly = ((MIDTTLY + MIDDIFF)<<FRACBITS) + ((200 - (MIDTTLY + MIDDIFF))*z);
}
#undef MIDTTLY
#undef MIDZONEY
#undef MIDDIFF
#else
// There's no consistent algorithm that can accurately define the old positions
// so I just ended up resorting to a single switch statement to define them
switch (titletime-3)
{
case 0: zoney = 200; lvlttly = 0; break;
case 1: zoney = 188; lvlttly = 12; break;
case 2: zoney = 176; lvlttly = 24; break;
case 3: zoney = 164; lvlttly = 36; break;
case 4: zoney = 152; lvlttly = 48; break;
case 5: zoney = 140; lvlttly = 60; break;
case 6: zoney = 128; lvlttly = 72; break;
case 105: zoney = 80; lvlttly = 104; break;
case 106: zoney = 56; lvlttly = 128; break;
case 107: zoney = 32; lvlttly = 152; break;
case 108: zoney = 8; lvlttly = 176; break;
case 109: zoney = 0; lvlttly = 200; break;
default: zoney = 104; lvlttly = 80; break;
}
#endif
if (actnum)
V_DrawLevelActNum(ttlnumxpos, zoney, V_PERPLAYER, actnum);
V_DrawLevelTitle(lvlttlxpos, lvlttly, V_PERPLAYER, lvlttl);
{
if (!splitscreen)
V_DrawScaledPatch(ttlnumxpos + ttlscroll, 104 - ttlscroll, 0, actpat);
V_DrawLevelActNum(ttlnumxpos + ttlscroll, 104, V_PERPLAYER, actnum);
}
V_DrawLevelTitle(lvlttlxpos - ttlscroll, 80, V_PERPLAYER, lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
V_DrawLevelTitle(zonexpos, zoney, V_PERPLAYER, M_GetText("ZONE"));
V_DrawLevelTitle(zonexpos + ttlscroll, 104, V_PERPLAYER, M_GetText("Zone"));
V_DrawCenteredString(subttlxpos - ttlscroll, 135, V_PERPLAYER|V_ALLOWLOWERCASE, subttl);
if (lvlttly+48 < 200)
V_DrawCenteredString(subttlxpos, lvlttly+48, V_PERPLAYER|V_ALLOWLOWERCASE, subttl);
lt_lasttic = lt_ticker;
#ifdef HAVE_BLUA
luahook:
LUAh_TitleCardHUD(stplyr);
#endif
}
//
// Drawer for G_PreLevelTitleCard.
//
void ST_preLevelTitleCardDrawer(tic_t ticker, boolean update)
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
if (ticker < PRELEVELTIME-1)
ST_drawWipeTitleCard();
I_OsPolling();
I_UpdateNoBlit();
if (update)
I_FinishUpdate(); // page flip or blit buffer
}
//
// Draw the title card while on a wipe.
// Also used in G_PreLevelTitleCard.
//
void ST_drawWipeTitleCard(void)
{
stplyr = &players[consoleplayer];
ST_preDrawTitleCard();
ST_drawTitleCard();
if (splitscreen)
{
stplyr = &players[secondarydisplayplayer];
ST_preDrawTitleCard();
ST_drawTitleCard();
}
}
static void ST_drawPowerupHUD(void)
@ -2106,7 +2236,7 @@ static void ST_drawTextHUD(void)
textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game"))
}
if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && stplyr->exiting)
if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && (stplyr->exiting || (stplyr->pflags & PF_FINISHED)))
{
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
if (numneeded)
@ -2121,7 +2251,7 @@ static void ST_drawTextHUD(void)
continue;
total++;
if (players[i].exiting)
if (players[i].exiting || (players[i].pflags & PF_FINISHED))
exiting++;
}
@ -2394,12 +2524,25 @@ static void ST_doItemFinderIconsAndSound(void)
S_StartSound(NULL, sfx_emfind);
}
//
// Draw the status bar overlay, customisable: the user chooses which
// kind of information to overlay
//
static void ST_overlayDrawer(void)
{
//hu_showscores = auto hide score/time/rings when tab rankings are shown
// Decide whether to draw the stage title or not
boolean stagetitle = false;
// Check for a valid level title
// If the HUD is enabled
// And, if Lua is running, if the HUD library has the stage title enabled
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD) && *mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer)))
{
stagetitle = true;
ST_preDrawTitleCard();
}
// hu_showscores = auto hide score/time/rings when tab rankings are shown
if (!(hu_showscores && (netgame || multiplayer)))
{
if ((maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap)) &&
@ -2550,12 +2693,8 @@ static void ST_overlayDrawer(void)
#endif
// draw level title Tails
if (*mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer))
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_stagetitle)
#endif
)
ST_drawLevelTitle(timeinmap+70);
if (stagetitle && (!WipeInAction) && (!WipeStageTitle))
ST_drawTitleCard();
if (!hu_showscores && (netgame || multiplayer)
#ifdef HAVE_BLUA
@ -2631,6 +2770,8 @@ void ST_Drawer(void)
}
}
st_translucency = cv_translucenthud.value;
if (st_overlay)
{
// No deadview!

View File

@ -24,7 +24,7 @@
//
// Called by main loop.
void ST_Ticker(void);
void ST_Ticker(boolean run);
// Called by main loop.
void ST_Drawer(void);
@ -47,8 +47,16 @@ void ST_ReloadSkinFaceGraphics(void);
void ST_doPaletteStuff(void);
// level title draw
void ST_drawLevelTitle(tic_t titletime);
// title card
void ST_startTitleCard(void);
void ST_runTitleCard(void);
void ST_drawTitleCard(void);
void ST_preDrawTitleCard(void);
void ST_preLevelTitleCardDrawer(tic_t ticker, boolean update);
void ST_drawWipeTitleCard(void);
extern tic_t lt_ticker, lt_lasttic;
extern tic_t lt_exitticker, lt_endtime;
// return if player a is in the same team as player b
boolean ST_SameTeam(player_t *a, player_t *b);
@ -59,6 +67,7 @@ boolean ST_SameTeam(player_t *a, player_t *b);
extern boolean st_overlay; // sb overlay on or off when fullscreen
extern INT32 st_palette; // 0 is default, any others are special palettes.
extern INT32 st_translucency;
extern lumpnum_t st_borderpatchnum;
// patches, also used in intermission

View File

@ -75,7 +75,7 @@ strcasestr (const char *s, const char *q)
if (!( (intptr_t)up|(intptr_t)lp ))
return 0;
if (!lp || up < lp)
if (!lp || ( up && up < lp ))
{
ppa = &up;
ppb = &lp;

View File

@ -18,7 +18,9 @@
#include "p_local.h" // stplyr
#include "g_game.h" // players
#include "v_video.h"
#include "st_stuff.h"
#include "hu_stuff.h"
#include "f_finale.h"
#include "r_draw.h"
#include "console.h"
@ -574,11 +576,11 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 13)
alphalevel = hudminusalpha[cv_translucenthud.value];
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 14)
alphalevel = 10 - cv_translucenthud.value;
alphalevel = 10 - st_translucency;
else if (alphalevel == 15)
alphalevel = hudplusalpha[cv_translucenthud.value];
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
return; // invis
@ -874,11 +876,11 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 13)
alphalevel = hudminusalpha[cv_translucenthud.value];
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 14)
alphalevel = 10 - cv_translucenthud.value;
alphalevel = 10 - st_translucency;
else if (alphalevel == 15)
alphalevel = hudplusalpha[cv_translucenthud.value];
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
return; // invis
@ -1074,7 +1076,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
//
void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor)
{
if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes >= 4)
if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CONTINUE)
{
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE];
@ -1393,11 +1395,11 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 13)
alphalevel = hudminusalpha[cv_translucenthud.value];
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 14)
alphalevel = 10 - cv_translucenthud.value;
alphalevel = 10 - st_translucency;
else if (alphalevel == 15)
alphalevel = hudplusalpha[cv_translucenthud.value];
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
return; // invis
@ -1860,7 +1862,9 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength)
{
const UINT8 *fadetable = ((color & 0xFF00) // Color is not palette index?
? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade.
? ((UINT8 *)(((color & 0x0F00) == 0x0A00) ? fadecolormap // Do fadecolormap fade.
: (((color & 0x0F00) == 0x0B00) ? fadecolormap + (256 * FADECOLORMAPROWS) // Do white fadecolormap fade.
: colormaps)) + strength*256) // Do COLORMAP fade.
: ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade.
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
UINT8 *buf = screens[0];
@ -1898,14 +1902,15 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color)
{
UINT8 *deststop, *buf;
boxheight = ((boxheight * 4) + (boxheight/2)*5);
if (color >= 256 && color < 512)
{
boxheight = ((boxheight * 4) + (boxheight/2)*5);
V_DrawFill((BASEVIDWIDTH-(vid.width/vid.dupx))/2, BASEVIDHEIGHT-boxheight, (vid.width/vid.dupx),boxheight, (color-256)|V_SNAPTOBOTTOM);
return;
}
boxheight *= vid.dupy;
if (color == INT32_MAX)
color = cons_backcolor.value;
@ -1947,7 +1952,7 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color)
// heavily simplified -- we don't need to know x or y position,
// just the start and stop positions
deststop = screens[0] + vid.rowbytes * vid.height;
buf = deststop - vid.rowbytes * boxheight * vid.dupy; // 4 lines of space plus gaps between and some leeway
buf = deststop - vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); // 4 lines of space plus gaps between and some leeway
for (; buf < deststop; ++buf)
*buf = promptbgmap[*buf];
}
@ -2899,7 +2904,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
continue;
}
c = toupper(*ch) - LT_FONTSTART;
c = *ch - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
{
cx += 16*dupx;
@ -2934,7 +2939,7 @@ INT32 V_LevelNameWidth(const char *string)
{
if (string[i] & 0x80)
continue;
c = toupper(string[i]) - LT_FONTSTART;
c = string[i] - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
w += 16;
else
@ -2953,7 +2958,7 @@ INT32 V_LevelNameHeight(const char *string)
for (i = 0; i < strlen(string); i++)
{
c = toupper(string[i]) - LT_FONTSTART;
c = string[i] - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
continue;
@ -2964,7 +2969,7 @@ INT32 V_LevelNameHeight(const char *string)
return w;
}
// For ST_drawLevelTitle
// For ST_drawTitleCard
// Returns the width of the act num patch
INT32 V_LevelActNumWidth(INT32 num)
{

View File

@ -106,6 +106,10 @@ extern RGBA_t *pMasterPalette;
#define V_HUDTRANSHALF 0x000D0000
#define V_HUDTRANS 0x000E0000 // draw the hud translucent
#define V_HUDTRANSDOUBLE 0x000F0000
// Macros follow
#define V_USERHUDTRANSHALF ((10-(cv_translucenthud.value/2))<<V_ALPHASHIFT)
#define V_USERHUDTRANS ((10-cv_translucenthud.value)<<V_ALPHASHIFT)
#define V_USERHUDTRANSDOUBLE ((10-min(cv_translucenthud.value*2, 10))<<V_ALPHASHIFT)
#define V_AUTOFADEOUT 0x00100000 // used by CECHOs, automatic fade out when almost over
#define V_RETURN8 0x00200000 // 8 pixel return instead of 12

View File

@ -383,7 +383,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
// read the header
if (fread(&header, 1, sizeof header, handle) < sizeof header)
{
CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), strerror(ferror(handle)));
CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), M_FileError(handle));
return NULL;
}
@ -406,7 +406,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
if (fseek(handle, header.infotableofs, SEEK_SET) == -1
|| fread(fileinfo, 1, i, handle) < i)
{
CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), strerror(ferror(handle)));
CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), M_FileError(handle));
free(fileinfov);
return NULL;
}
@ -427,7 +427,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
handle) < sizeof realsize)
{
I_Error("corrupt compressed file: %s; maybe %s", /// \todo Avoid the bailout?
filename, strerror(ferror(handle)));
filename, M_FileError(handle));
}
realsize = LONG(realsize);
if (realsize != 0)
@ -565,7 +565,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
fseek(handle, -4, SEEK_CUR);
if (fread(&zend, 1, sizeof zend, handle) < sizeof zend)
{
CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", strerror(ferror(handle)));
CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle));
return NULL;
}
numlumps = zend.entries;
@ -582,7 +582,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t))
{
CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", strerror(ferror(handle)));
CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle));
Z_Free(lumpinfo);
free(zentries);
return NULL;
@ -602,7 +602,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
fullname = malloc(zentry->namelen + 1);
if (fgets(fullname, zentry->namelen + 1, handle) != fullname)
{
CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", strerror(ferror(handle)));
CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle));
Z_Free(lumpinfo);
free(zentries);
free(fullname);

View File

@ -371,6 +371,9 @@ void I_FinishUpdate(void)
if (cv_ticrate.value)
SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
//
if (bDIBMode)
{

View File

@ -166,13 +166,11 @@ static INT32 endtic = -1;
intertype_t intertype = int_none;
static void Y_RescaleScreenBuffer(void);
static void Y_CleanupScreenBuffer(void);
static void Y_AwardCoopBonuses(void);
static void Y_AwardSpecialStageBonus(void);
static void Y_CalculateCompetitionWinners(void);
static void Y_CalculateTimeRaceWinners(void);
static void Y_CalculateMatchWinners(void);
static void Y_FollowIntermission(void);
static void Y_UnloadData(void);
// Stuff copy+pasted from st_stuff.c
@ -293,7 +291,7 @@ static void Y_RescaleScreenBuffer(void)
//
// Free all related memory.
//
static void Y_CleanupScreenBuffer(void)
void Y_CleanupScreenBuffer(void)
{
// Who knows?
if (y_buffer == NULL)
@ -399,10 +397,13 @@ void Y_IntermissionDrawer(void)
// draw the "got through act" lines and act number
V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1);
V_DrawLevelTitle(data.coop.passedx2, 49+V_LevelNameHeight(data.coop.passed2)+2, 0, data.coop.passed2);
{
INT32 h = V_LevelNameHeight(data.coop.passed2);
V_DrawLevelTitle(data.coop.passedx2, 49+h+2, 0, data.coop.passed2);
if (data.coop.actnum)
V_DrawLevelActNum(244, 57, 0, data.coop.actnum);
if (data.coop.actnum)
V_DrawLevelActNum(244, 42+h, 0, data.coop.actnum);
}
bonusy = 150;
// Total
@ -485,10 +486,10 @@ void Y_IntermissionDrawer(void)
if (drawsection == 1)
{
const char *ringtext = "\x82" "50 RINGS, NO SHIELD";
const char *tut1text = "\x82" "PRESS " "\x80" "SPIN";
const char *tut2text = "\x82" "MID-" "\x80" "JUMP";
ttheight = 16;
const char *ringtext = "\x82" "50 rings, no shield";
const char *tut1text = "\x82" "press " "\x80" "spin";
const char *tut2text = "\x82" "mid-" "\x80" "jump";
ttheight = 8;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3);
@ -497,9 +498,9 @@ void Y_IntermissionDrawer(void)
ttheight = 108;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext);
ttheight += V_LevelNameHeight(ringtext) + 2;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text);
ttheight += V_LevelNameHeight(tut1text) + 2;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text);
ttheight += V_LevelNameHeight(tut2text) + 2;
V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text);
}
else
@ -816,7 +817,7 @@ void Y_IntermissionDrawer(void)
}
}
}
else if (intertype == int_classicrace)
else if (intertype == int_comp)
{
INT32 x = 4;
INT32 y = 48;
@ -950,7 +951,7 @@ void Y_Ticker(void)
if (!--timer)
{
Y_EndIntermission();
Y_FollowIntermission();
G_AfterIntermission();
return;
}
}
@ -958,7 +959,7 @@ void Y_Ticker(void)
else if (intertic == endtic)
{
Y_EndIntermission();
Y_FollowIntermission();
G_AfterIntermission();
return;
}
@ -1142,7 +1143,7 @@ void Y_Ticker(void)
if (data.match.numplayers != D_NumPlayers())
Y_CalculateMatchWinners();
}
else if (intertype == int_race || intertype == int_classicrace) // race
else if (intertype == int_race || intertype == int_comp) // race
{
if (!intertic) // first time only
S_ChangeMusicInternal("_inter", true); // loop it
@ -1151,96 +1152,6 @@ void Y_Ticker(void)
}
}
//
// Y_UpdateRecordReplays
//
// Update replay files/data, etc. for Record Attack
// See G_SetNightsRecords for NiGHTS Attack.
//
static void Y_UpdateRecordReplays(void)
{
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath;
char lastdemo[256], bestdemo[256];
UINT8 earnedEmblems;
// Record new best time
if (!mainrecords[gamemap-1])
G_AllocMainRecordData(gamemap-1);
if (players[consoleplayer].score > mainrecords[gamemap-1]->score)
mainrecords[gamemap-1]->score = players[consoleplayer].score;
if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings)
mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);
if (data.coop.gotperfbonus)
mainrecords[gamemap-1]->gotperfect = true;
// Save demo!
bestdemo[255] = '\0';
lastdemo[255] = '\0';
G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].rings));
G_CheckDemoStatus();
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);
if ((gpath = malloc(glen)) == NULL)
I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (FIL_FileExists(lastdemo))
{
UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
}
snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
{ // Better score, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo);
}
snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2)))
{ // Better rings, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo);
}
//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);
Z_Free(buf);
}
free(gpath);
// Check emblems when level data is updated
if ((earnedEmblems = M_CheckLevelEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
// Update timeattack menu's replay availability.
Nextmap_OnChange();
}
//
// Y_StartIntermission
//
@ -1249,7 +1160,6 @@ static void Y_UpdateRecordReplays(void)
void Y_StartIntermission(void)
{
INT32 i;
UINT8 completionEmblems = M_CompletionEmblems();
intertic = -1;
@ -1262,10 +1172,7 @@ void Y_StartIntermission(void)
{
timer = 0;
if (G_IsSpecialStage(gamemap))
intertype = (maptol & TOL_NIGHTS) ? int_nightsspec : int_spec;
else
intertype = (maptol & TOL_NIGHTS) ? int_nights : int_coop;
intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop;
}
else
{
@ -1280,14 +1187,7 @@ void Y_StartIntermission(void)
}
if (gametype == GT_COOP)
{
// Nights intermission is single player only
// Don't add it here
if (G_IsSpecialStage(gamemap))
intertype = int_spec;
else
intertype = int_coop;
}
intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop;
else if (gametype == GT_TEAMMATCH)
intertype = int_teammatch;
else if (gametype == GT_MATCH
@ -1297,7 +1197,7 @@ void Y_StartIntermission(void)
else if (gametype == GT_RACE)
intertype = int_race;
else if (gametype == GT_COMPETITION)
intertype = int_classicrace;
intertype = int_comp;
else if (gametype == GT_CTF)
intertype = int_ctf;
}
@ -1312,20 +1212,6 @@ void Y_StartIntermission(void)
switch (intertype)
{
case int_nights:
// Can't fail
G_SetNightsRecords();
// Check records
{
UINT8 earnedEmblems = M_CheckLevelEmblems();
if (earnedEmblems)
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
}
// fall back into the coop intermission for now
intertype = int_coop;
/* FALLTHRU */
case int_coop: // coop or single player, normal level
{
// award time and ring bonuses
@ -1334,24 +1220,6 @@ void Y_StartIntermission(void)
// setup time data
data.coop.tics = players[consoleplayer].realtime;
if ((!modifiedgame || savemoddata) && !multiplayer && !demoplayback)
{
// Update visitation flags
mapvisited[gamemap-1] |= MV_BEATEN;
if (ALL7EMERALDS(emeralds))
mapvisited[gamemap-1] |= MV_ALLEMERALDS;
if (ultimatemode)
mapvisited[gamemap-1] |= MV_ULTIMATE;
if (data.coop.gotperfbonus)
mapvisited[gamemap-1] |= MV_PERFECT;
if (modeattacking == ATTACKING_RECORD)
Y_UpdateRecordReplays();
if (completionEmblems)
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)completionEmblems, completionEmblems > 1 ? "s" : "");
}
for (i = 0; i < 4; ++i)
data.coop.bonuspatches[i] = W_CachePatchName(data.coop.bonuses[i].patch, PU_STATIC);
data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_STATIC);
@ -1384,21 +1252,21 @@ void Y_StartIntermission(void)
// too long so just show "YOU GOT THROUGH THE ACT"
if (strlen(skins[players[consoleplayer].skin].realname) > 13)
{
strcpy(data.coop.passed1, "YOU GOT");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT");
strcpy(data.coop.passed1, "you got");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
}
// long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if (strlen(skins[players[consoleplayer].skin].realname) > 8)
{
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "PASSED ACT" : "PASSED THE ACT");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act");
}
// length is okay for normal use
else
{
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s GOT",
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got",
skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
}
// set X positions
@ -1418,40 +1286,8 @@ void Y_StartIntermission(void)
break;
}
case int_nightsspec:
if (modeattacking && stagefailed)
{
// Nuh-uh. Get out of here.
Y_EndIntermission();
Y_FollowIntermission();
break;
}
if (!stagefailed)
G_SetNightsRecords();
// Check records
{
UINT8 earnedEmblems = M_CheckLevelEmblems();
if (earnedEmblems)
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
}
// fall back into the special stage intermission for now
intertype = int_spec;
/* FALLTHRU */
case int_spec: // coop or single player, special stage
{
// Update visitation flags?
if ((!modifiedgame || savemoddata) && !multiplayer && !demoplayback)
{
if (!stagefailed)
mapvisited[gamemap-1] |= MV_BEATEN;
// all emeralds/ultimate/perfect emblems won't be possible in ss, oh well?
if (completionEmblems)
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)completionEmblems, completionEmblems > 1 ? "s" : "");
}
// give out ring bonuses
Y_AwardSpecialStageBonus();
@ -1498,7 +1334,7 @@ void Y_StartIntermission(void)
// set up the "got through act" message according to skin name
if (stagefailed)
{
strcpy(data.spec.passed2, "SPECIAL STAGE");
strcpy(data.spec.passed2, "Special Stage");
data.spec.passed1[0] = '\0';
}
else if (ALL7EMERALDS(emeralds))
@ -1507,13 +1343,13 @@ void Y_StartIntermission(void)
sizeof data.spec.passed1, "%s",
skins[players[consoleplayer].skin].realname);
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
strcpy(data.spec.passed2, "GOT THEM ALL!");
strcpy(data.spec.passed2, "got them all!");
if (players[consoleplayer].charflags & SF_SUPER)
{
strcpy(data.spec.passed3, "CAN NOW BECOME");
strcpy(data.spec.passed3, "can now become");
snprintf(data.spec.passed4,
sizeof data.spec.passed4, "SUPER %s",
sizeof data.spec.passed4, "Super %s",
skins[players[consoleplayer].skin].realname);
data.spec.passed4[sizeof data.spec.passed4 - 1] = '\0';
}
@ -1523,13 +1359,13 @@ void Y_StartIntermission(void)
if (strlen(skins[players[consoleplayer].skin].realname) <= SKINNAMESIZE-5)
{
snprintf(data.spec.passed1,
sizeof data.spec.passed1, "%s GOT",
sizeof data.spec.passed1, "%s got",
skins[players[consoleplayer].skin].realname);
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
}
else
strcpy(data.spec.passed1, "YOU GOT");
strcpy(data.spec.passed2, "A CHAOS EMERALD");
strcpy(data.spec.passed1, "You got");
strcpy(data.spec.passed2, "a Chaos Emerald");
if (P_GetNextEmerald() > 6)
{
data.spec.passed2[15] = '?';
@ -1637,7 +1473,7 @@ void Y_StartIntermission(void)
break;
}
case int_classicrace: // classic (full race)
case int_comp: // classic (full race)
{
// find out who won
Y_CalculateCompetitionWinners();
@ -2192,23 +2028,6 @@ void Y_EndIntermission(void)
usebuffer = false;
}
//
// Y_FollowIntermission
//
static void Y_FollowIntermission(void)
{
if (modeattacking)
{
M_EndModeAttackRun();
return;
}
// This handles whether to play a post-level cutscene, end the game,
// or simply go to the next level.
// No need to duplicate the code here!
G_AfterIntermission();
}
#define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL
//
@ -2221,8 +2040,6 @@ static void Y_UnloadData(void)
if (rendermode != render_soft)
return;
Y_CleanupScreenBuffer();
// unload the background patches
UNLOAD(bgpatch);
UNLOAD(widebgpatch);
@ -2258,7 +2075,7 @@ static void Y_UnloadData(void)
break;
default:
//without this default,
//int_none, int_tag, int_chaos, and int_classicrace
//int_none, int_tag, int_chaos, and int_comp
//are not handled
break;
}

View File

@ -16,6 +16,7 @@ void Y_Ticker(void);
void Y_StartIntermission(void);
void Y_EndIntermission(void);
void Y_ConsiderScreenBuffer(void);
void Y_CleanupScreenBuffer(void);
typedef enum
{
@ -26,9 +27,7 @@ typedef enum
// int_tag, // Tag
int_ctf, // CTF
int_spec, // Special Stage
int_nights, // NiGHTS into Dreams
int_nightsspec,// NiGHTS special stage
int_race, // Race
int_classicrace, // Competition
int_comp, // Competition
} intertype_t;
extern intertype_t intertype;