diff --git a/readme.txt b/readme.txt index 7a33a55d..14d9c92e 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -Here it is! SRB2 v2.1.2 source code! +Here it is! SRB2 v2.1.5 source code! Win32 with Visual C (6SP6+Processor Pack OR 7) @@ -58,6 +58,10 @@ Build instructions: make -C src LINUX=1 +Build instructions (64 bit): + +make -C src LINUX64=1 + Build instructions to build for Wii Linux/SRB2Wii on a PowerPC system, follow cross-compiling instructions for cross-compiling on a x86 system: diff --git a/src/am_map.c b/src/am_map.c index 9c2aee2c..70714fac 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -25,36 +25,64 @@ #endif // For use if I do walls with outsides/insides -static const UINT8 GREENS = (10*16); -static const UINT8 GREENRANGE = 16; -static const UINT8 GRAYS = (0*16); -static const UINT8 GRAYSRANGE = 16; -static const UINT8 DBLACK = 31; -static const UINT8 DWHITE = 0; +static const UINT8 REDS = (8*16); +static const UINT8 REDRANGE = 16; +static const UINT8 GRAYS = (1*16); +static const UINT8 GRAYSRANGE = 16; +static const UINT8 BROWNS = (3*16); +static const UINT8 BROWNRANGE = 16; +static const UINT8 YELLOWS = (7*16); +static const UINT8 YELLOWRANGE = 8; +static const UINT8 GREENS = (10*16); +static const UINT8 GREENRANGE = 16; +static const UINT8 DBLACK = 31; +static const UINT8 DWHITE = 0; + +static const UINT8 NOCLIMBREDS = 248; +static const UINT8 NOCLIMBREDRANGE = 8; +static const UINT8 NOCLIMBGRAYS = 204; +static const UINT8 NOCLIMBGRAYSRANGE = 4; +static const UINT8 NOCLIMBBROWNS = (2*16); +static const UINT8 NOCLIMBBROWNRANGE = 16; +static const UINT8 NOCLIMBYELLOWS = (11*16); +static const UINT8 NOCLIMBYELLOWRANGE = 8; + #ifdef _NDS #undef BACKGROUND #endif // Automap colors -#define BACKGROUND DBLACK -#define YOURCOLORS DWHITE -#define YOURRANGE 0 -#define WALLCOLORS REDS -#define WALLRANGE REDRANGE -#define TSWALLCOLORS GRAYS -#define TSWALLRANGE GRAYSRANGE -#define FDWALLCOLORS BROWNS -#define FDWALLRANGE BROWNRANGE -#define CDWALLCOLORS YELLOWS -#define CDWALLRANGE YELLOWRANGE -#define THINGCOLORS GREENS -#define THINGRANGE GREENRANGE -#define SECRETWALLCOLORS WALLCOLORS -#define SECRETWALLRANGE WALLRANGE -#define GRIDCOLORS (GRAYS + GRAYSRANGE/2) -#define GRIDRANGE 0 -#define XHAIRCOLORS GRAYS +#define BACKGROUND DBLACK +#define YOURCOLORS DWHITE +#define YOURRANGE 0 +#define WALLCOLORS (REDS + REDRANGE/2) +#define WALLRANGE (REDRANGE/2) +#define NOCLIMBWALLCOLORS (NOCLIMBREDS + NOCLIMBREDRANGE/2) +#define NOCLIMBWALLRANGE (NOCLIMBREDRANGE/2) +#define THOKWALLCOLORS REDS +#define THOKWALLRANGE REDRANGE +#define NOCLIMBTHOKWALLCOLORS NOCLIMBREDS +#define NOCLIMBTHOKWALLRANGE NOCLIMBREDRANGE +#define TSWALLCOLORS GRAYS +#define TSWALLRANGE GRAYSRANGE +#define NOCLIMBTSWALLCOLORS NOCLIMBGRAYS +#define NOCLIMBTSWALLRANGE NOCLIMBGRAYSRANGE +#define FDWALLCOLORS BROWNS +#define FDWALLRANGE BROWNRANGE +#define NOCLIMBFDWALLCOLORS NOCLIMBBROWNS +#define NOCLIMBFDWALLRANGE NOCLIMBBROWNRANGE +#define CDWALLCOLORS YELLOWS +#define CDWALLRANGE YELLOWRANGE +#define NOCLIMBCDWALLCOLORS NOCLIMBYELLOWS +#define NOCLIMBCDWALLRANGE NOCLIMBYELLOWRANGE +#define THINGCOLORS GREENS +#define THINGRANGE GREENRANGE +#define SECRETWALLCOLORS WALLCOLORS +#define SECRETWALLRANGE WALLRANGE +#define GRIDCOLORS (GRAYS + GRAYSRANGE/2) +#define GRIDRANGE 0 +#define XHAIRCOLORS GRAYS // drawing stuff #define FB 0 @@ -1009,7 +1037,75 @@ static inline void AM_drawWalls(void) l.b.x = lines[i].v2->x; l.b.y = lines[i].v2->y; - AM_drawMline(&l, GRAYS + 3); +// AM_drawMline(&l, GRAYS + 3); // Old, everything-is-gray automap + if (!lines[i].backsector) // 1-sided + { + if (lines[i].flags & ML_NOCLIMB) + { + AM_drawMline(&l, NOCLIMBWALLCOLORS+lightlev); + } + else + { + AM_drawMline(&l, WALLCOLORS+lightlev); + } + } + else if (lines[i].backsector->floorheight == lines[i].backsector->ceilingheight // Back is thok barrier + || lines[i].frontsector->floorheight == lines[i].frontsector->ceilingheight) // Front is thok barrier + { + if (lines[i].backsector->floorheight == lines[i].backsector->ceilingheight + && lines[i].frontsector->floorheight == lines[i].frontsector->ceilingheight) // BOTH are thok barriers + { + if (lines[i].flags & ML_NOCLIMB) + { + AM_drawMline(&l, NOCLIMBTSWALLCOLORS+lightlev); + } + else + { + AM_drawMline(&l, TSWALLCOLORS+lightlev); + } + } + else + { + if (lines[i].flags & ML_NOCLIMB) + { + AM_drawMline(&l, NOCLIMBTHOKWALLCOLORS+lightlev); + } + else + { + AM_drawMline(&l, THOKWALLCOLORS+lightlev); + } + } + } + else + { + if (lines[i].flags & ML_NOCLIMB) { + if (lines[i].backsector->floorheight + != lines[i].frontsector->floorheight) { + AM_drawMline(&l, NOCLIMBFDWALLCOLORS + lightlev); // floor level change + } + else if (lines[i].backsector->ceilingheight + != lines[i].frontsector->ceilingheight) { + AM_drawMline(&l, NOCLIMBCDWALLCOLORS+lightlev); // ceiling level change + } + else { + AM_drawMline(&l, NOCLIMBTSWALLCOLORS+lightlev); + } + } + else + { + if (lines[i].backsector->floorheight + != lines[i].frontsector->floorheight) { + AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change + } + else if (lines[i].backsector->ceilingheight + != lines[i].frontsector->ceilingheight) { + AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change + } + else { + AM_drawMline(&l, TSWALLCOLORS+lightlev); + } + } + } } } diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f4b262ba..c6008e86 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -95,10 +95,21 @@ 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]; static tic_t firstticstosend; // min of the nettics -static INT16 consistancy[BACKUPTICS]; static tic_t tictoclear = 0; // optimize d_clearticcmd static tic_t maketic; +static INT16 consistancy[BACKUPTICS]; + +// Resynching shit! +static UINT32 resynch_score[MAXNETNODES]; // "score" for kicking -- if this gets too high then cfail kick +static UINT16 resynch_delay[MAXNETNODES]; // delay time before the player can be considered to have desynched +static UINT32 resynch_status[MAXNETNODES]; // 0 bit means synched for that player, 1 means possibly desynched +static UINT8 resynch_sent[MAXNETNODES][MAXNETNODES]; // what synch packets have we attempted to send to the player +static UINT8 resynch_inprogress[MAXNETNODES]; +static UINT8 resynch_local_inprogress = false; // WE are desynched and getting packets to fix it. +static UINT8 player_joining = false; +UINT8 hu_resynching = 0; + // client specific static ticcmd_t localcmds; static ticcmd_t localcmds2; @@ -463,6 +474,544 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) // end extra data function for lmps // ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// resynch player data +// ----------------------------------------------------------------- +static inline void resynch_write_player(resynch_pak *rsp, const size_t i) +{ + size_t j; + + rsp->playernum = (UINT8)i; + + // Do not send anything visual related. + // Only send data that we need to know for physics. + rsp->playerstate = (UINT8)players[i].playerstate; //playerstate_t + rsp->pflags = (UINT32)LONG(players[i].pflags); //pflags_t + rsp->panim = (UINT8)players[i].panim; //panim_t + + rsp->aiming = (angle_t)LONG(players[i].aiming); + rsp->currentweapon = LONG(players[i].currentweapon); + rsp->ringweapons = LONG(players[i].ringweapons); + + for (j = 0; j < NUMPOWERS; ++j) + rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); + + // Score is resynched in the rspfirm resync packet + rsp->health = 0; // resynched with mo health + rsp->lives = players[i].lives; + rsp->continues = players[i].continues; + rsp->scoreadd = players[i].scoreadd; + rsp->xtralife = players[i].xtralife; + rsp->pity = players[i].pity; + + rsp->skincolor = players[i].skincolor; + rsp->skin = LONG(players[i].skin); + // Just in case Lua does something like + // modify these at runtime + rsp->normalspeed = (fixed_t)LONG(players[i].normalspeed); + rsp->runspeed = (fixed_t)LONG(players[i].runspeed); + rsp->thrustfactor = players[i].thrustfactor; + rsp->accelstart = players[i].accelstart; + rsp->acceleration = players[i].acceleration; + rsp->charability = players[i].charability; + rsp->charability2 = players[i].charability2; + rsp->charflags = (UINT32)LONG(players[i].charflags); + rsp->thokitem = (UINT32)LONG(players[i].thokitem); //mobjtype_t + rsp->spinitem = (UINT32)LONG(players[i].spinitem); //mobjtype_t + rsp->revitem = (UINT32)LONG(players[i].revitem); //mobjtype_t + rsp->actionspd = LONG(players[i].actionspd); + rsp->mindash = LONG(players[i].mindash); + rsp->maxdash = LONG(players[i].maxdash); + rsp->jumpfactor = (fixed_t)LONG(players[i].jumpfactor); + + rsp->speed = (fixed_t)LONG(players[i].speed); + rsp->jumping = players[i].jumping; + rsp->secondjump = players[i].secondjump; + rsp->fly1 = players[i].fly1; + rsp->glidetime = (tic_t)LONG(players[i].glidetime); + rsp->climbing = players[i].climbing; + rsp->deadtimer = players[i].deadtimer; + rsp->exiting = (tic_t)LONG(players[i].exiting); + rsp->homing = players[i].homing; + rsp->cmomx = (fixed_t)LONG(players[i].cmomx); + rsp->cmomy = (fixed_t)LONG(players[i].cmomy); + rsp->rmomx = (fixed_t)LONG(players[i].rmomx); + rsp->rmomy = (fixed_t)LONG(players[i].rmomy); + + rsp->weapondelay = LONG(players[i].weapondelay); + rsp->tossdelay = LONG(players[i].tossdelay); + + rsp->starpostx = SHORT(players[i].starpostx); + rsp->starposty = SHORT(players[i].starposty); + rsp->starpostz = SHORT(players[i].starpostz); + rsp->starpostnum = LONG(players[i].starpostnum); + rsp->starposttime = (tic_t)LONG(players[i].starposttime); + rsp->starpostangle = (angle_t)LONG(players[i].starpostangle); + + rsp->maxlink = LONG(players[i].maxlink); + rsp->dashspeed = (fixed_t)LONG(players[i].dashspeed); + rsp->dashtime = LONG(players[i].dashtime); + rsp->angle_pos = (angle_t)LONG(players[i].angle_pos); + rsp->old_angle_pos = (angle_t)LONG(players[i].old_angle_pos); + rsp->bumpertime = (tic_t)LONG(players[i].bumpertime); + rsp->flyangle = LONG(players[i].flyangle); + rsp->drilltimer = (tic_t)LONG(players[i].drilltimer); + rsp->linkcount = LONG(players[i].linkcount); + rsp->linktimer = (tic_t)LONG(players[i].linktimer); + rsp->anotherflyangle = LONG(players[i].anotherflyangle); + rsp->nightstime = (tic_t)LONG(players[i].nightstime); + rsp->drillmeter = LONG(players[i].drillmeter); + rsp->drilldelay = players[i].drilldelay; + rsp->bonustime = players[i].bonustime; + rsp->mare = players[i].mare; + rsp->lastsidehit = SHORT(players[i].lastsidehit); + rsp->lastlinehit = SHORT(players[i].lastlinehit); + + rsp->losstime = (tic_t)LONG(players[i].losstime); + rsp->timeshit = players[i].timeshit; + rsp->onconveyor = LONG(players[i].onconveyor); + + rsp->hasmo = false; + //Transfer important mo information if the player has a body. + //This lets us resync players even if they are dead. + if (!players[i].mo) + return; + rsp->hasmo = true; + + rsp->health = LONG(players[i].mo->health); + + rsp->angle = (angle_t)LONG(players[i].mo->angle); + rsp->x = LONG(players[i].mo->x); + rsp->y = LONG(players[i].mo->y); + rsp->z = LONG(players[i].mo->z); + rsp->momx = LONG(players[i].mo->momx); + rsp->momy = LONG(players[i].mo->momy); + rsp->momz = LONG(players[i].mo->momz); + rsp->friction = LONG(players[i].mo->friction); + rsp->movefactor = LONG(players[i].mo->movefactor); + + rsp->tics = LONG(players[i].mo->tics); + rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :( + rsp->eflags = (UINT32)LONG(players[i].mo->eflags); + rsp->flags = LONG(players[i].mo->flags); + rsp->flags2 = LONG(players[i].mo->flags2); + + rsp->radius = LONG(players[i].mo->radius); + rsp->height = LONG(players[i].mo->height); + rsp->scale = LONG(players[i].mo->scale); + rsp->destscale = LONG(players[i].mo->destscale); + rsp->scalespeed = LONG(players[i].mo->scalespeed); +} + +static void resynch_read_player(resynch_pak *rsp) +{ + INT32 i = rsp->playernum, j; + mobj_t *savedmo = players[i].mo; + + // Do not send anything visual related. + // Only send data that we need to know for physics. + players[i].playerstate = (UINT8)rsp->playerstate; //playerstate_t + players[i].pflags = (UINT32)LONG(rsp->pflags); //pflags_t + players[i].panim = (UINT8)rsp->panim; //panim_t + + players[i].aiming = (angle_t)LONG(rsp->aiming); + players[i].currentweapon = LONG(rsp->currentweapon); + players[i].ringweapons = LONG(rsp->ringweapons); + + for (j = 0; j < NUMPOWERS; ++j) + players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); + + // Score is resynched in the rspfirm resync packet + players[i].health = rsp->health; + players[i].lives = rsp->lives; + players[i].continues = rsp->continues; + players[i].scoreadd = rsp->scoreadd; + players[i].xtralife = rsp->xtralife; + players[i].pity = rsp->pity; + + players[i].skincolor = rsp->skincolor; + players[i].skin = LONG(rsp->skin); + // Just in case Lua does something like + // modify these at runtime + players[i].normalspeed = (fixed_t)LONG(rsp->normalspeed); + players[i].runspeed = (fixed_t)LONG(rsp->runspeed); + players[i].thrustfactor = rsp->thrustfactor; + players[i].accelstart = rsp->accelstart; + players[i].acceleration = rsp->acceleration; + players[i].charability = rsp->charability; + players[i].charability2 = rsp->charability2; + players[i].charflags = (UINT32)LONG(rsp->charflags); + players[i].thokitem = (UINT32)LONG(rsp->thokitem); //mobjtype_t + players[i].spinitem = (UINT32)LONG(rsp->spinitem); //mobjtype_t + players[i].revitem = (UINT32)LONG(rsp->revitem); //mobjtype_t + players[i].actionspd = LONG(rsp->actionspd); + players[i].mindash = LONG(rsp->mindash); + players[i].maxdash = LONG(rsp->maxdash); + players[i].jumpfactor = (fixed_t)LONG(rsp->jumpfactor); + + players[i].speed = (fixed_t)LONG(rsp->speed); + players[i].jumping = rsp->jumping; + players[i].secondjump = rsp->secondjump; + players[i].fly1 = rsp->fly1; + players[i].glidetime = (tic_t)LONG(rsp->glidetime); + players[i].climbing = rsp->climbing; + players[i].deadtimer = rsp->deadtimer; + players[i].exiting = (tic_t)LONG(rsp->exiting); + players[i].homing = rsp->homing; + players[i].cmomx = (fixed_t)LONG(rsp->cmomx); + players[i].cmomy = (fixed_t)LONG(rsp->cmomy); + players[i].rmomx = (fixed_t)LONG(rsp->rmomx); + players[i].rmomy = (fixed_t)LONG(rsp->rmomy); + + players[i].weapondelay = LONG(rsp->weapondelay); + players[i].tossdelay = LONG(rsp->tossdelay); + + players[i].starpostx = SHORT(rsp->starpostx); + players[i].starposty = SHORT(rsp->starposty); + players[i].starpostz = SHORT(rsp->starpostz); + players[i].starpostnum = LONG(rsp->starpostnum); + players[i].starposttime = (tic_t)LONG(rsp->starposttime); + players[i].starpostangle = (angle_t)LONG(rsp->starpostangle); + + players[i].maxlink = LONG(rsp->maxlink); + players[i].dashspeed = (fixed_t)LONG(rsp->dashspeed); + players[i].dashtime = LONG(rsp->dashtime); + players[i].angle_pos = (angle_t)LONG(rsp->angle_pos); + players[i].old_angle_pos = (angle_t)LONG(rsp->old_angle_pos); + players[i].bumpertime = (tic_t)LONG(rsp->bumpertime); + players[i].flyangle = LONG(rsp->flyangle); + players[i].drilltimer = (tic_t)LONG(rsp->drilltimer); + players[i].linkcount = LONG(rsp->linkcount); + players[i].linktimer = (tic_t)LONG(rsp->linktimer); + players[i].anotherflyangle = LONG(rsp->anotherflyangle); + players[i].nightstime = (tic_t)LONG(rsp->nightstime); + players[i].drillmeter = LONG(rsp->drillmeter); + players[i].drilldelay = rsp->drilldelay; + players[i].bonustime = rsp->bonustime; + players[i].mare = rsp->mare; + players[i].lastsidehit = SHORT(rsp->lastsidehit); + players[i].lastlinehit = SHORT(rsp->lastlinehit); + + players[i].losstime = (tic_t)LONG(rsp->losstime); + players[i].timeshit = rsp->timeshit; + players[i].onconveyor = LONG(rsp->onconveyor); + + //We get a packet for each player in game. + if (!playeringame[i]) + return; + + //...but keep old mo even if it is corrupt or null! + players[i].mo = savedmo; + + //Transfer important mo information if they have a valid mo. + if (!rsp->hasmo) + return; + + //server thinks player has a body. + //Give them a new body that can be then manipulated by the server's info. + if (!players[i].mo) //client thinks it has no body. + P_SpawnPlayer(i); + + //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); + players[i].mo->eflags = (UINT32)LONG(rsp->eflags); + players[i].mo->flags = LONG(rsp->flags); + players[i].mo->flags2 = LONG(rsp->flags2); + players[i].mo->friction = LONG(rsp->friction); + players[i].mo->health = LONG(rsp->health); + players[i].mo->momx = LONG(rsp->momx); + players[i].mo->momy = LONG(rsp->momy); + players[i].mo->momz = LONG(rsp->momz); + players[i].mo->movefactor = LONG(rsp->movefactor); + players[i].mo->tics = LONG(rsp->tics); + P_SetMobjStateNF(players[i].mo, LONG(rsp->statenum)); + players[i].mo->x = LONG(rsp->x); + players[i].mo->y = LONG(rsp->y); + players[i].mo->z = LONG(rsp->z); + players[i].mo->radius = LONG(rsp->radius); + players[i].mo->height = LONG(rsp->height); + // P_SetScale is redundant for this, as all related variables are already restored properly. + players[i].mo->scale = LONG(rsp->scale); + players[i].mo->destscale = LONG(rsp->destscale); + players[i].mo->scalespeed = LONG(rsp->scalespeed); + + // And finally, SET THE MOBJ SKIN damn it. + players[i].mo->skin = &skins[players[i].skin]; + players[i].mo->color = players[i].skincolor; + + P_SetThingPosition(players[i].mo); +} + +static inline void resynch_write_ctf(resynchend_pak *rst) +{ + mobj_t *mflag; + UINT8 i, j; + + for (i = 0, mflag = redflag; i < 2; ++i, mflag = blueflag) + { + rst->flagx[i] = rst->flagy[i] = rst->flagz[i] = 0; + rst->flagloose[i] = rst->flagflags[i] = 0; + rst->flagplayer[i] = -1; + + if (!mflag) + { + // Should be held by a player + for (j = 0; j < MAXPLAYERS; ++j) + { + // GF_REDFLAG is 1, GF_BLUEFLAG is 2 + // redflag handling is i=0, blueflag is i=1 + // so check for gotflag == (i+1) + if (!playeringame[j] || players[j].gotflag != (i+1)) + continue; + rst->flagplayer[i] = (SINT8)j; + break; + } + if (j == MAXPLAYERS) + I_Error("One of the flags has gone completely missing!"); + + continue; + } + + rst->flagx[i] = (fixed_t)LONG(mflag->x); + rst->flagy[i] = (fixed_t)LONG(mflag->y); + rst->flagz[i] = (fixed_t)LONG(mflag->z); + rst->flagflags[i] = LONG(mflag->flags2); + rst->flagloose[i] = LONG(mflag->fuse); // Dropped or not? + } +} + +static inline void resynch_read_ctf(resynchend_pak *p) +{ + UINT8 i; + + for (i = 0; i < MAXPLAYERS; ++i) + players[i].gotflag = 0; + + // Red flag + if (p->flagplayer[0] != -1) // Held by a player + { + if (!playeringame[p->flagplayer[0]]) + I_Error("Invalid red flag player %d who isn't in the game!", (INT32)p->flagplayer[0]); + players[p->flagplayer[0]].gotflag = GF_REDFLAG; + if (redflag) + { + P_RemoveMobj(redflag); + redflag = NULL; + } + } + else + { + if (!redflag) + redflag = P_SpawnMobj(0,0,0,MT_REDFLAG); + + P_UnsetThingPosition(redflag); + redflag->x = (fixed_t)LONG(p->flagx[0]); + redflag->y = (fixed_t)LONG(p->flagy[0]); + redflag->z = (fixed_t)LONG(p->flagz[0]); + redflag->flags2 = LONG(p->flagflags[0]); + redflag->fuse = LONG(p->flagloose[0]); + P_SetThingPosition(redflag); + } + + // Blue flag + if (p->flagplayer[1] != -1) // Held by a player + { + if (!playeringame[p->flagplayer[1]]) + I_Error("Invalid blue flag player %d who isn't in the game!", (INT32)p->flagplayer[1]); + players[p->flagplayer[1]].gotflag = GF_REDFLAG; + if (blueflag) + { + P_RemoveMobj(blueflag); + blueflag = NULL; + } + } + else + { + if (!blueflag) + blueflag = P_SpawnMobj(0,0,0,MT_BLUEFLAG); + + P_UnsetThingPosition(blueflag); + blueflag->x = (fixed_t)LONG(p->flagx[0]); + blueflag->y = (fixed_t)LONG(p->flagy[0]); + blueflag->z = (fixed_t)LONG(p->flagz[0]); + blueflag->flags2 = LONG(p->flagflags[0]); + blueflag->fuse = LONG(p->flagloose[0]); + P_SetThingPosition(blueflag); + } +} + +static inline void resynch_write_others(resynchend_pak *rst) +{ + UINT8 i; + + rst->ingame = rst->ctfteam = 0; + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (!playeringame[i]) + { + rst->score[i] = 0; + rst->numboxes[i] = 0; + rst->totalring[i] = 0; + rst->realtime[i] = 0; + rst->laps[i] = 0; + continue; + } + + if (!players[i].spectator) + { + rst->ingame |= (1< 1) + rst->ctfteam |= (1<score[i] = (UINT32)LONG(players[i].score); + rst->numboxes[i] = SHORT(players[i].numboxes); + rst->totalring[i] = SHORT(players[i].totalring); + rst->realtime[i] = (tic_t)LONG(players[i].realtime); + rst->laps[i] = players[i].laps; + } + + // endian safeness + rst->ingame = (UINT32)LONG(rst->ingame); + rst->ctfteam = (UINT32)LONG(rst->ctfteam); +} + +static inline void resynch_read_others(resynchend_pak *p) +{ + UINT8 i; + UINT32 loc_ingame = (UINT32)LONG(p->ingame); + UINT32 loc_ctfteam = (UINT32)LONG(p->ctfteam); + + for (i = 0; i < MAXPLAYERS; ++i) + { + // We don't care if they're in the game or not, just write all the data. + if (loc_ingame & (1<score[i]); + players[i].numboxes = SHORT(p->numboxes[i]); + players[i].totalring = SHORT(p->totalring[i]); + players[i].realtime = (tic_t)LONG(p->realtime[i]); + players[i].laps = p->laps[i]; + } +} + +static void SV_InitResynchVars(INT32 node) +{ + resynch_delay[node] = TICRATE; // initial one second delay + resynch_score[node] = 0; // clean slate + resynch_status[node] = 0x00; + resynch_inprogress[node] = false; + memset(resynch_sent[node], 0, MAXNETNODES); +} + +static void SV_RequireResynch(INT32 node) +{ + INT32 i; + + resynch_delay[node] = 10; // Delay before you can fail sync again + resynch_score[node] += 200; // Add score for initial desynch + resynch_status[node] = 0xFF; // No players assumed synched + resynch_inprogress[node] = true; // so we know to send a PT_RESYNCHEND after sync + + // Initial setup + memset(resynch_sent[node], 0, MAXNETNODES); + for (i = 0; i < MAXPLAYERS; ++i) + { + if (!playeringame[i]) // Player not in game so just drop it from required synch + resynch_status[node] &= ~(1<>1)+1; + } +} + +static void SV_SendResynch(INT32 node) +{ + INT32 i, j; + + // resynched? + if (!resynch_status[node]) + { + // you are now synched + resynch_inprogress[node] = false; + + netbuffer->packettype = PT_RESYNCHEND; + + netbuffer->u.resynchend.randomseed = P_GetRandSeed(); + if (gametype == GT_CTF) + resynch_write_ctf(&netbuffer->u.resynchend); + resynch_write_others(&netbuffer->u.resynchend); + + HSendPacket(node, true, 0, (sizeof(resynchend_pak))); + return; + } + + netbuffer->packettype = PT_RESYNCHING; + for (i = 0, j = 0; i < MAXPLAYERS; ++i) + { + // if already synched don't bother + if (!(resynch_status[node] & 1<u.resynchpak, i); + HSendPacket(node, false, 0, (sizeof(resynch_pak))); + + resynch_sent[node][i] = TICRATE; + resynch_score[node] += 2; // penalty for send + + if (++j > 3) + break; + } + + if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250) + { + XBOXSTATIC UINT8 buf[2]; + buf[0] = (UINT8)nodetoplayer[node]; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + resynch_score[node] = 0; + } +} + +static void CL_AcknowledgeResynch(resynch_pak *rsp) +{ + resynch_read_player(rsp); + + netbuffer->packettype = PT_RESYNCHGET; + netbuffer->u.resynchgot = rsp->playernum; + HSendPacket(servernode, true, 0, sizeof(UINT8)); +} + +static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg) +{ + if (rsg >= MAXPLAYERS) + resynch_score[node] += 16384; // lol. + else + { + resynch_status[node] &= ~(1<playernum = (UINT8)i; - - con->playerstate = (UINT8)players[i].playerstate; - G_MoveTiccmd(&con->cmd, &players[i].cmd, 1); - con->viewz = LONG(players[i].viewz); - con->viewheight = LONG(players[i].viewheight); - con->deltaviewheight = LONG(players[i].deltaviewheight); - con->bob = LONG(players[i].bob); - con->aiming = (angle_t)LONG(players[i].aiming); - con->awayviewaiming = (angle_t)LONG(players[i].awayviewaiming); - con->phealth = LONG(players[i].health); - con->pity = players[i].pity; - con->currentweapon = LONG(players[i].currentweapon); - con->ringweapons = LONG(players[i].ringweapons); - - for (j = 0; j < NUMPOWERS; j++) - con->powers[j] = (UINT16)SHORT(players[i].powers[j]); - - con->pflags = (UINT32)LONG(players[i].pflags); - con->panim = (UINT8)players[i].panim; - con->flashcount = LONG(players[i].flashcount); - con->skincolor = players[i].skincolor; - con->skin = LONG(players[i].skin); - con->score = (UINT32)LONG(players[i].score); - con->maxlink = LONG(players[i].maxlink); - con->dashspeed = LONG(players[i].dashspeed); - con->dashtime = LONG(players[i].dashtime); - con->normalspeed = LONG(players[i].normalspeed); - con->runspeed = LONG(players[i].runspeed); - con->thrustfactor = players[i].thrustfactor; - con->accelstart = players[i].accelstart; - con->acceleration = players[i].acceleration; - con->charability = players[i].charability; - con->charability2 = players[i].charability2; - con->charflags = (UINT32)LONG(players[i].charflags); - con->thokitem = (UINT32)LONG(players[i].thokitem); - con->spinitem = (UINT32)LONG(players[i].spinitem); - con->revitem = (UINT32)LONG(players[i].revitem); - con->actionspd = LONG(players[i].actionspd); - con->mindash = LONG(players[i].mindash); - con->maxdash = LONG(players[i].maxdash); - con->jumpfactor = LONG(players[i].jumpfactor); - con->lives = LONG(players[i].lives); - con->continues = LONG(players[i].continues); - con->xtralife = LONG(players[i].xtralife); - con->speed = LONG(players[i].speed); - con->jumping = LONG(players[i].jumping); - con->secondjump =players[i].secondjump; - con->fly1 = players[i].fly1; - con->scoreadd = (UINT32)LONG(players[i].scoreadd); - con->glidetime = (tic_t)LONG(players[i].glidetime); - con->climbing = players[i].climbing; - con->deadtimer = LONG(players[i].deadtimer); - con->exiting = (tic_t)LONG(players[i].exiting); - con->homing = players[i].homing; - con->skidtime = (tic_t)LONG(players[i].skidtime); - con->cmomx = LONG(players[i].cmomx); - con->cmomy = LONG(players[i].cmomy); - con->rmomx = LONG(players[i].rmomx); - con->rmomy = LONG(players[i].rmomy); - con->numboxes = LONG(players[i].numboxes); - con->totalring = LONG(players[i].totalring); - con->realtime = (tic_t)LONG(players[i].realtime); - con->laps = (UINT32)LONG(players[i].laps); - con->ctfteam = LONG(players[i].ctfteam); - con->gotflag = (UINT16)SHORT(players[i].gotflag); - con->weapondelay = LONG(players[i].weapondelay); - con->tossdelay = LONG(players[i].tossdelay); - con->starpostx = SHORT(players[i].starpostx); - con->starposty = SHORT(players[i].starposty); - con->starpostz = SHORT(players[i].starpostz); - con->starpostnum = LONG(players[i].starpostnum); - con->starposttime = (tic_t)LONG(players[i].starposttime); - con->starpostangle = (angle_t)LONG(players[i].starpostangle); - con->angle_pos = (angle_t)LONG(players[i].angle_pos); - con->old_angle_pos = (angle_t)LONG(players[i].old_angle_pos); - con->bumpertime = (tic_t)LONG(players[i].bumpertime); - con->flyangle = LONG(players[i].flyangle); - con->drilltimer = (tic_t)LONG(players[i].drilltimer); - con->linkcount = LONG(players[i].linkcount); - con->linktimer = (tic_t)LONG(players[i].linktimer); - con->anotherflyangle = LONG(players[i].anotherflyangle); - con->nightstime = (tic_t)LONG(players[i].nightstime); - con->drillmeter = LONG(players[i].drillmeter); - con->drilldelay = players[i].drilldelay; - con->bonustime = (UINT8)players[i].bonustime; - con->mare = players[i].mare; - con->lastsidehit = SHORT(players[i].lastsidehit); - con->lastlinehit = SHORT(players[i].lastlinehit); - con->losstime = (tic_t)LONG(players[i].losstime); - con->timeshit = (UINT8)players[i].timeshit; - con->onconveyor = LONG(players[i].onconveyor); - con->spectator = (UINT8)players[i].spectator; - con->jointime = (tic_t)LONG(players[i].jointime); - - con->hasmo = false; - //Transfer important mo information if the player has a body. - //This lets us resync players even if they are dead. - if (!players[i].mo) - return; - - con->hasmo = true; - con->angle = (angle_t)LONG(players[i].mo->angle); - con->eflags = (UINT32)LONG(players[i].mo->eflags); - con->flags = LONG(players[i].mo->flags); - con->flags2 = LONG(players[i].mo->flags2); - con->friction = LONG(players[i].mo->friction); - con->health = LONG(players[i].mo->health); - con->momx = LONG(players[i].mo->momx); - con->momy = LONG(players[i].mo->momy); - con->momz = LONG(players[i].mo->momz); - con->movefactor = LONG(players[i].mo->movefactor); - con->tics = LONG(players[i].mo->tics); - con->statenum = (statenum_t)LONG(players[i].mo->state-states); // :( - con->x = LONG(players[i].mo->x); - con->y = LONG(players[i].mo->y); - con->z = LONG(players[i].mo->z); - con->radius = LONG(players[i].mo->radius); - con->height = LONG(players[i].mo->height); - con->scale = LONG(players[i].mo->scale); - con->destscale = LONG(players[i].mo->destscale); - con->scalespeed = LONG(players[i].mo->scalespeed); -} - -static void readconplayer(cons_pak *con, const INT32 playernum) -{ - size_t i; - mobj_t *savedmo = players[playernum].mo; - - //We get a packet for each player in game. - - //Restore CTF information - if (gametype == GT_CTF) - { - // Remove old flags. - if (redflag) - { - P_RemoveMobj(redflag); - redflag = NULL; - } - if (blueflag) - { - P_RemoveMobj(blueflag); - blueflag = NULL; - } - - // Spawn the flags if players aren't carrying them. - if (con->rflagloose != 2) - { - mobj_t *newflag = P_SpawnMobj(con->rflagx << FRACBITS, con->rflagy << FRACBITS, con->rflagz << FRACBITS, MT_REDFLAG); - newflag->flags |= MF_SPECIAL; - newflag->flags2 = con->rflags2; - newflag->fuse = con->rfuse; - newflag->spawnpoint = rflagpoint; - redflag = newflag; - } - - if (con->bflagloose != 2) - { - mobj_t *newflag = P_SpawnMobj(con->bflagx << FRACBITS, con->bflagy << FRACBITS, con->bflagz << FRACBITS, MT_BLUEFLAG); - newflag->flags |= MF_SPECIAL; - newflag->flags2 = con->bflags2; - newflag->fuse = con->bfuse; - newflag->spawnpoint = bflagpoint; - blueflag = newflag; - } - } - - if (!playeringame[playernum]) - return; - - //Tranfer player information. - players[playernum].playerstate = (playerstate_t)con->playerstate; - G_MoveTiccmd(&players[playernum].cmd, &con->cmd, 1); - players[playernum].viewz = LONG(con->viewz); - players[playernum].viewheight = LONG(con->viewheight); - players[playernum].deltaviewheight = LONG(con->deltaviewheight); - players[playernum].bob = LONG(con->bob); - players[playernum].aiming = (angle_t)LONG(con->aiming); - players[playernum].awayviewaiming = (angle_t)LONG(con->awayviewaiming); - players[playernum].health = LONG(con->phealth); - players[playernum].pity = con->pity; - players[playernum].currentweapon = LONG(con->currentweapon); - players[playernum].ringweapons = LONG(con->ringweapons); - - for (i = 0; i < NUMPOWERS; i++) - players[playernum].powers[i] = (UINT16)SHORT(con->powers[i]); - - players[playernum].pflags = (pflags_t)LONG(con->pflags); - players[playernum].panim = (panim_t)con->panim; - players[playernum].flashcount = LONG(con->flashcount); - players[playernum].skincolor = con->skincolor; - players[playernum].skin = LONG(con->skin); - players[playernum].score = (UINT32)LONG(con->score); - players[playernum].maxlink = LONG(con->maxlink); - players[playernum].dashspeed = LONG(con->dashspeed); - players[playernum].dashtime = LONG(con->dashtime); - players[playernum].normalspeed = LONG(con->normalspeed); - players[playernum].runspeed = LONG(con->runspeed); - players[playernum].thrustfactor = con->thrustfactor; - players[playernum].accelstart = con->accelstart; - players[playernum].acceleration = con->acceleration; - players[playernum].charability = con->charability; - players[playernum].charability2 = con->charability2; - players[playernum].charflags = (UINT32)LONG(con->charflags); - players[playernum].thokitem = (mobjtype_t)LONG(con->thokitem); - players[playernum].spinitem = (mobjtype_t)LONG(con->spinitem); - players[playernum].revitem = (mobjtype_t)LONG(con->revitem); - players[playernum].actionspd = LONG(con->actionspd); - players[playernum].mindash = LONG(con->mindash); - players[playernum].maxdash = LONG(con->maxdash); - players[playernum].jumpfactor = LONG(con->jumpfactor); - players[playernum].lives = LONG(con->lives); - players[playernum].continues = LONG(con->continues); - players[playernum].xtralife = LONG(con->xtralife); - players[playernum].speed = LONG(con->speed); - players[playernum].jumping = LONG(con->jumping); - players[playernum].secondjump = con->secondjump; - players[playernum].fly1 = con->fly1; - players[playernum].scoreadd = (UINT32)LONG(con->scoreadd); - players[playernum].glidetime = (tic_t)LONG(con->glidetime); - players[playernum].climbing = con->climbing; - players[playernum].deadtimer = LONG(con->deadtimer); - players[playernum].exiting = (tic_t)LONG(con->exiting); - players[playernum].homing = con->homing; - players[playernum].skidtime = (tic_t)LONG(con->skidtime); - players[playernum].cmomx = LONG(con->cmomx); - players[playernum].cmomy = LONG(con->cmomy); - players[playernum].rmomx = LONG(con->rmomx); - players[playernum].rmomy = LONG(con->rmomy); - players[playernum].numboxes = LONG(con->numboxes); - players[playernum].totalring = LONG(con->totalring); - players[playernum].realtime = (tic_t)LONG(con->realtime); - players[playernum].laps = (UINT32)LONG(con->laps); - players[playernum].ctfteam = LONG(con->ctfteam); - players[playernum].gotflag = (UINT16)SHORT(con->gotflag); - players[playernum].weapondelay = LONG(con->weapondelay); - players[playernum].tossdelay = LONG(con->tossdelay); - players[playernum].starpostx = LONG(con->starpostx); - players[playernum].starposty = LONG(con->starposty); - players[playernum].starpostz = LONG(con->starpostz); - players[playernum].starpostnum = LONG(con->starpostnum); - players[playernum].starposttime = (tic_t)LONG(con->starposttime); - players[playernum].starpostangle = (angle_t)LONG(con->starpostangle); - players[playernum].angle_pos = (angle_t)LONG(con->angle_pos); - players[playernum].old_angle_pos = (angle_t)LONG(con->old_angle_pos); - players[playernum].bumpertime = (tic_t)LONG(con->bumpertime); - players[playernum].flyangle = LONG(con->flyangle); - players[playernum].drilltimer = (tic_t)LONG(con->drilltimer); - players[playernum].linkcount = LONG(con->linkcount); - players[playernum].linktimer = (tic_t)LONG(con->linktimer); - players[playernum].anotherflyangle = LONG(con->anotherflyangle); - players[playernum].nightstime = (tic_t)LONG(con->nightstime); - players[playernum].drillmeter = LONG(con->drillmeter); - players[playernum].drilldelay = con->drilldelay; - players[playernum].bonustime = (boolean)con->bonustime; - players[playernum].mare = con->mare; - players[playernum].lastsidehit = SHORT(con->lastsidehit); - players[playernum].lastlinehit = SHORT(con->lastlinehit); - players[playernum].losstime = (tic_t)LONG(con->losstime); - players[playernum].timeshit = (UINT8)con->timeshit; - players[playernum].onconveyor = LONG(con->onconveyor); - players[playernum].spectator = (boolean)con->spectator; - players[playernum].jointime = (tic_t)LONG(con->jointime); - - //...but keep old mo even if it is corrupt or null! - players[playernum].mo = savedmo; - - //Transfer important mo information if they have a valid mo. - if (!con->hasmo) - return; - //server thinks player has a body. - //Give them a new body that can be then manipulated by the server's info. - if (!players[playernum].mo) //client thinks it has no body. - P_SpawnPlayer(playernum); - - //At this point, the player should have a body, whether they were respawned or not. - P_UnsetThingPosition(players[playernum].mo); - players[playernum].mo->angle = (angle_t)LONG(con->angle); - players[playernum].mo->eflags = (UINT32)LONG(con->eflags); - players[playernum].mo->flags = LONG(con->flags); - players[playernum].mo->flags2 = LONG(con->flags2); - players[playernum].mo->friction = LONG(con->friction); - players[playernum].mo->health = LONG(con->health); - players[playernum].mo->momx = LONG(con->momx); - players[playernum].mo->momy = LONG(con->momy); - players[playernum].mo->momz = LONG(con->momz); - players[playernum].mo->movefactor = LONG(con->movefactor); - players[playernum].mo->tics = LONG(con->tics); - P_SetPlayerMobjState(players[playernum].mo, LONG(con->statenum)); - players[playernum].mo->x = LONG(con->x); - players[playernum].mo->y = LONG(con->y); - players[playernum].mo->z = LONG(con->z); - players[playernum].mo->radius = LONG(con->radius); - players[playernum].mo->height = LONG(con->height); - // P_SetScale is redundant for this, as all related variables are already restored properly. - players[playernum].mo->scale = LONG(con->scale); - players[playernum].mo->destscale = LONG(con->destscale); - players[playernum].mo->scalespeed = LONG(con->scalespeed); - - // And finally, SET THE MOBJ SKIN damn it. - players[playernum].mo->skin = &skins[players[playernum].skin]; - players[playernum].mo->color = players[playernum].skincolor; - - P_SetThingPosition(players[playernum].mo); -} - -static inline void handlectfconstuff(cons_pak *con) -{ - if (redflag) - { - // Flag is loose - if (redflag->fuse) - { - con->rflagloose = 1; - con->rflagx = SHORT(redflag->x >> FRACBITS); - con->rflagy = SHORT(redflag->y >> FRACBITS); - con->rflagz = SHORT(redflag->z >> FRACBITS); - con->rflags2 = LONG(redflag->flags2); - con->rfuse = LONG(redflag->fuse); - } - else // flag is at base - { - con->rflagloose = 0; - con->rflagx = SHORT(rflagpoint->x); - con->rflagy = SHORT(rflagpoint->y); - con->rflagz = SHORT(rflagpoint->z); - con->rflags2 = 0; - con->rfuse = 0; - } - } - else // player has flag - con->rflagloose = 2; - - if (blueflag) - { - // Flag is loose - if (blueflag->fuse) - { - con->bflagloose = 1; - con->bflagx = SHORT(blueflag->x >> FRACBITS); - con->bflagy = SHORT(blueflag->y >> FRACBITS); - con->bflagz = SHORT(blueflag->z >> FRACBITS); - con->bflags2 = LONG(blueflag->flags2); - con->bfuse = LONG(blueflag->fuse); - } - else // flag is at base - { - con->bflagloose = 0; - con->bflagx = SHORT(bflagpoint->x); - con->bflagy = SHORT(bflagpoint->y); - con->bflagz = SHORT(bflagpoint->z); - con->bflags2 = 0; - con->bfuse = 0; - } - } - else // player has flag - con->bflagloose = 2; -} - -/// \todo Remove this AWFUL consistency fixing packet and replace it with re-sending $$$.sav, or at least pause the game until it gets acked! -static void SV_SendConsistency(INT32 node) -{ - INT32 i; - - netbuffer->packettype = PT_CONSISTENCY; - - if (gametype == GT_CTF) - handlectfconstuff(&netbuffer->u.consistency); - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - writeconplayer(&netbuffer->u.consistency, i); - HSendPacket(node, true, 0, (sizeof(cons_pak))); - } -} - // used at txtcmds received to check packetsize bound static size_t TotalTextCmdPerTic(tic_t tic) { @@ -2910,6 +3080,10 @@ static void HandleConnect(SINT8 node) newnode = true; #endif SV_AddNode(node); + + // you get a free second before desynch checks. use it wisely. + SV_InitResynchVars(node); + if (cv_joinnextround.value && gameaction == ga_nothing) G_SetGamestate(GS_WAITINGPLAYERS); if (!SV_SendServerConfig(node)) @@ -2934,6 +3108,7 @@ static void HandleConnect(SINT8 node) DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(); + player_joining = true; } #endif } @@ -2982,6 +3157,9 @@ static void GetPackets(void) XBOXSTATIC tic_t realend,realstart; XBOXSTATIC UINT8 *pak, *txtpak, numtxtpak; FILESTAMP + + player_joining = false; + while (HGetPacket()) { node = (SINT8)doomcom->remotenode; @@ -3153,9 +3331,14 @@ FILESTAMP I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); #endif + txtpak = NULL; + switch (netbuffer->packettype) { // -------------------------------------------- SERVER RECEIVE ---------- + case PT_RESYNCHGET: + SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); + break; case PT_CLIENTCMD: case PT_CLIENT2CMD: case PT_CLIENTMIS: @@ -3165,6 +3348,10 @@ FILESTAMP if (!server) break; + // ignore tics from those not synched + if (resynch_inprogress[node]) + break; + // to save bytes, only the low byte of tic numbers are sent // Figure out what the rest of the bytes are realstart = ExpandTics(netbuffer->u.clientpak.client_tic); @@ -3213,42 +3400,30 @@ FILESTAMP G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], &netbuffer->u.client2pak.cmd2, 1); + // a delay before we check resynching + // used on join or just after a synch fail + if (resynch_delay[node]) + { + --resynch_delay[node]; + break; + } // check player consistancy during the level - // Careful: When a consistency packet is sent, it overwrites the incoming packet containing the ticcmd. - // Keep this in mind when changing the code that responds to these packets. - if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 - && gamestate == GS_LEVEL && playeringame[netconsole] - && players[netconsole].playerstate == PST_LIVE - && !players[netconsole].spectator - && players[netconsole].jointime > 10 + if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)) { - if (cv_consfailprotect.value && consfailcount[netconsole] < cv_consfailprotect.value) + SV_RequireResynch(node); + + if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) { - if (!consfailstatus[netconsole]) - { - if (cv_blamecfail.value) - CONS_Printf(M_GetText("Consistency failure for player %d (%s), restoring...\n"), netconsole+1, player_names[netconsole]); - - DEBFILE(va("Restoring player %d (consistency failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - - SV_SendConsistency(netconsole); - consfailstatus[netconsole] = 1; - consfailcount[netconsole]++; - break; // ticcmd packet is gone. - } - else - { - //We don't want to send any more packets than we have to. - //If the client doesn't resync in a certain time, - //assume they didn't get the packet. Send another. - if (consfailstatus[netconsole] < 10) - consfailstatus[netconsole]++; - else - consfailstatus[netconsole] = 0; - } + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy)); + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + break; } else { @@ -3257,19 +3432,14 @@ FILESTAMP buf[0] = (UINT8)netconsole; buf[1] = KICK_MSG_CON_FAIL; SendNetXCmd(XD_KICK, &buf, 2); - DEBFILE(va("player %d kicked (consistency failure) [%u] %d!=%d\n", + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", netconsole, realstart, consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy))); - consfailstatus[netconsole] = 0; - consfailcount[netconsole] = 0; break; } } - else - { - consfailstatus[netconsole] = 0; - consfailcount[netconsole] = 0; - } + else if (resynch_score[node]) + --resynch_score[node]; break; case PT_TEXTCMD2: // splitscreen special netconsole = nodetoplayer2[node]; @@ -3346,6 +3516,31 @@ FILESTAMP nodeingame[node] = false; break; // -------------------------------------------- CLIENT RECEIVE ---------- + case PT_RESYNCHEND: + // Only accept PT_RESYNCHEND from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHEND", node); + + if (server) + { + XBOXSTATIC UINT8 buf[2]; + buf[0] = (UINT8)node; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + + break; + } + resynch_local_inprogress = false; + + P_SetRandSeed(netbuffer->u.resynchend.randomseed); + + if (gametype == GT_CTF) + resynch_read_ctf(&netbuffer->u.resynchend); + resynch_read_others(&netbuffer->u.resynchend); + + break; case PT_SERVERTICS: // Only accept PT_SERVERTICS from the server. if (node != servernode) @@ -3366,8 +3561,9 @@ FILESTAMP realstart = ExpandTics(netbuffer->u.serverpak.starttic); realend = realstart + netbuffer->u.serverpak.numtics; - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots - * netbuffer->u.serverpak.numtics]; + if (!txtpak) + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots + * netbuffer->u.serverpak.numtics]; if (realend > gametic + BACKUPTICS) realend = gametic + BACKUPTICS; @@ -3404,11 +3600,11 @@ FILESTAMP else DEBFILE(va("frame not in bound: %u\n", neededtic)); break; - case PT_CONSISTENCY: - // Only accept PT_CONSISTENCY from the server. + case PT_RESYNCHING: + // Only accept PT_RESYNCHING from the server. if (node != servernode) { - CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_CONSISTENCY", node); + CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHING", node); if (server) { @@ -3420,8 +3616,8 @@ FILESTAMP break; } - - readconplayer(&netbuffer->u.consistency, netbuffer->u.consistency.playernum); + resynch_local_inprogress = true; + CL_AcknowledgeResynch(&netbuffer->u.resynchpak); break; #ifdef NEWPING case PT_PING: @@ -3470,25 +3666,35 @@ FILESTAMP // Builds ticcmds for console player, // sends out a packet // +// no more use random generator, because at very first tic isn't yet synchronized // Note: It is called consistAncy on purpose. // static INT16 Consistancy(void) { - INT16 ret = 0; INT32 i; + UINT32 ret = 0; DEBFILE(va("TIC %u ", gametic)); - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].playerstate == PST_LIVE && !players[i].spectator) - { - //DEBFILE(va("p[%d].x = %f ", i, (double)FIXED_TO_FLOAT(players[i].mo->x))); - ret = (INT16)((ret + (players[i].mo->x>>8)) & 0xFFFF); - ret = (INT16)((ret + players[i].powers[pw_shield]) & 0xFFFF); - } - DEBFILE(va("players = %d, rnd %d\n", ret, P_GetRandSeed())); - ret = (INT16)(ret + P_GetRandSeed()); - return ret; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + ret ^= 0xCCCC; + else if (!players[i].mo); + else + { + ret += players[i].mo->x; + ret -= players[i].mo->y; + ret += players[i].powers[pw_shield]; + ret *= i+1; + } + } + // I give up + // Coop desynching enemies is painful + if (!G_PlatformGametype()) + ret += P_GetRandSeed(); + + return (INT16)(ret & 0xFFFF); } // send the client packet to the server @@ -3776,6 +3982,9 @@ void TryRunTics(tic_t realtics) } #endif + if (player_joining) + return; + if (neededtic > gametic) { if (advancedemo) @@ -3911,13 +4120,19 @@ FILESTAMP MasterClient_Ticker(); // acking the master server if (!server) - CL_SendClientCmd(); // send tic cmd + { + if (!resynch_local_inprogress) + CL_SendClientCmd(); // send tic cmd + hu_resynching = resynch_local_inprogress; + } else { if (!demoplayback) { INT32 counts; + hu_resynching = false; + firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) if (nodeingame[i] && nettics[i] < firstticstosend) @@ -3926,18 +4141,31 @@ FILESTAMP // Don't erase tics not acknowledged counts = realtics; - if (maketic + counts >= firstticstosend + BACKUPTICS) - counts = firstticstosend+BACKUPTICS-maketic-1; + for (i = 0; i < MAXNETNODES; ++i) + if (resynch_inprogress[i]) + { + SV_SendResynch(i); + counts = -666; + } - for (i = 0; i < counts; i++) - SV_Maketic(); // create missed tics and increment maketic + // do not make tics while resynching + if (counts != -666) + { + if (maketic + counts >= firstticstosend + BACKUPTICS) + counts = firstticstosend+BACKUPTICS-maketic-1; - for (; tictoclear < firstticstosend; tictoclear++) // clear only when acknoledged - D_Clearticcmd(tictoclear); // clear the maketic the new tic + for (i = 0; i < counts; i++) + SV_Maketic(); // create missed tics and increment maketic - SV_SendTics(); + for (; tictoclear < firstticstosend; tictoclear++) // clear only when acknoledged + D_Clearticcmd(tictoclear); // clear the maketic the new tic - neededtic = maketic; // the server is a client too + SV_SendTics(); + + neededtic = maketic; // the server is a client too + } + else + hu_resynching = true; } } Net_AckTicker(); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index d35c5cb3..0086132e 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -53,6 +53,8 @@ typedef enum PT_REQUESTFILE, // Client requests a file transfer PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client. // If this ID changes, update masterserver definition. + PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic + PT_RESYNCHGET, // Player got resynch packet // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. @@ -66,7 +68,8 @@ typedef enum PT_TEXTCMD2, // Splitscreen text commands. PT_CLIENTJOIN, // Client wants to join; used in start game. PT_NODETIMEOUT, // Packet sent to self if the connection times out. - PT_CONSISTENCY, // Packet sent to resync players. + PT_RESYNCHING, // Packet sent to resync players. + // Blocks game advance until synched. #ifdef NEWPING PT_PING, // Packet sent to tell clients the other client's latency to server. #endif @@ -110,6 +113,147 @@ typedef struct ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large } ATTRPACK servertics_pak; +// sent to client when all consistency data +// for players has been restored +typedef struct +{ + UINT32 randomseed; + + //ctf flag stuff + SINT8 flagplayer[2]; + INT32 flagloose[2]; + INT32 flagflags[2]; + fixed_t flagx[2]; + fixed_t flagy[2]; + fixed_t flagz[2]; + + UINT32 ingame; // spectator bit for each player + UINT32 ctfteam; // if not spectator, then which team? + + // Resynch game scores and the like all at once + UINT32 score[MAXPLAYERS]; // Everyone's score. + INT16 numboxes[MAXPLAYERS]; + INT16 totalring[MAXPLAYERS]; + tic_t realtime[MAXPLAYERS]; + UINT8 laps[MAXPLAYERS]; +} ATTRPACK resynchend_pak; + +typedef struct +{ + //player stuff + UINT8 playernum; + + // Do not send anything visual related. + // Only send data that we need to know for physics. + UINT8 playerstate; //playerstate_t + UINT32 pflags; //pflags_t + UINT8 panim; //panim_t + + angle_t aiming; + INT32 currentweapon; + INT32 ringweapons; + UINT16 powers[NUMPOWERS]; + + // Score is resynched in the confirm resync packet + INT32 health; + SINT8 lives; + SINT8 continues; + UINT8 scoreadd; + SINT8 xtralife; + SINT8 pity; + + UINT8 skincolor; + INT32 skin; + // Just in case Lua does something like + // modify these at runtime + fixed_t normalspeed; + fixed_t runspeed; + UINT8 thrustfactor; + UINT8 accelstart; + UINT8 acceleration; + UINT8 charability; + UINT8 charability2; + UINT32 charflags; + UINT32 thokitem; //mobjtype_t + UINT32 spinitem; //mobjtype_t + UINT32 revitem; //mobjtype_t + INT32 actionspd; + INT32 mindash; + INT32 maxdash; + fixed_t jumpfactor; + + fixed_t speed; + UINT8 jumping; + UINT8 secondjump; + UINT8 fly1; + tic_t glidetime; + UINT8 climbing; + INT32 deadtimer; + tic_t exiting; + UINT8 homing; + fixed_t cmomx; + fixed_t cmomy; + fixed_t rmomx; + fixed_t rmomy; + + INT32 weapondelay; + INT32 tossdelay; + + INT16 starpostx; + INT16 starposty; + INT16 starpostz; + INT32 starpostnum; + tic_t starposttime; + angle_t starpostangle; + + INT32 maxlink; + fixed_t dashspeed; + INT32 dashtime; + angle_t angle_pos; + angle_t old_angle_pos; + tic_t bumpertime; + INT32 flyangle; + tic_t drilltimer; + INT32 linkcount; + tic_t linktimer; + INT32 anotherflyangle; + tic_t nightstime; + INT32 drillmeter; + UINT8 drilldelay; + UINT8 bonustime; + UINT8 mare; + INT16 lastsidehit, lastlinehit; + + tic_t losstime; + UINT8 timeshit; + INT32 onconveyor; + + //player->mo stuff + UINT8 hasmo; //boolean + + angle_t angle; + fixed_t x; + fixed_t y; + fixed_t z; + fixed_t momx; + fixed_t momy; + fixed_t momz; + fixed_t friction; + fixed_t movefactor; + + INT16 tics; + statenum_t statenum; + UINT32 flags; + UINT32 flags2; + UINT8 eflags; + + fixed_t radius; + fixed_t height; + fixed_t scale; + fixed_t destscale; + fixed_t scalespeed; +} ATTRPACK resynch_pak; + typedef struct { UINT8 version; // different versions don't work @@ -194,143 +338,6 @@ typedef struct tic_t time; // used for ping evaluation } ATTRPACK msaskinfo_pak; -typedef struct -{ - UINT32 randomseed; - - //ctf flag stuff - UINT8 rflagloose; - UINT8 bflagloose; - INT32 rfuse; - INT32 bfuse; - INT32 rflags2; - INT32 bflags2; - INT16 rflagx; - INT16 rflagy; - INT16 rflagz; - INT16 bflagx; - INT16 bflagy; - INT16 bflagz; - - //player stuff - UINT8 playernum; - - UINT8 playerstate; //playerstate_t - ticcmd_t cmd; - fixed_t viewz; - fixed_t viewheight; - fixed_t deltaviewheight; - fixed_t bob; - angle_t aiming; - angle_t awayviewaiming; - INT32 phealth; - SINT8 pity; - INT32 currentweapon; - INT32 ringweapons; - UINT16 powers[NUMPOWERS]; - UINT32 pflags; //pflags_t - UINT8 panim; //panim_t - INT32 flashcount; - UINT8 skincolor; - INT32 skin; - UINT32 score; - INT32 maxlink; - fixed_t dashspeed; - INT32 dashtime; - fixed_t normalspeed; - fixed_t runspeed; - UINT8 thrustfactor; - UINT8 accelstart; - UINT8 acceleration; - UINT8 charability; - UINT8 charability2; - UINT32 charflags; - UINT32 thokitem; //mobjtype_t - UINT32 spinitem; //mobjtype_t - UINT32 revitem; //mobjtype_t - INT32 actionspd; - INT32 mindash; - INT32 maxdash; - fixed_t jumpfactor; - INT32 lives; - INT32 continues; - INT32 xtralife; - fixed_t speed; - INT32 jumping; - UINT8 secondjump; - UINT8 fly1; - UINT8 scoreadd; - tic_t glidetime; - UINT8 climbing; - INT32 deadtimer; - tic_t exiting; - UINT8 homing; - tic_t skidtime; - fixed_t cmomx; - fixed_t cmomy; - fixed_t rmomx; - fixed_t rmomy; - INT32 numboxes; - INT32 totalring; - tic_t realtime; - UINT32 laps; - INT32 ctfteam; - UINT16 gotflag; - INT32 weapondelay; - INT32 tossdelay; - INT16 starpostx; - INT16 starposty; - INT16 starpostz; - INT32 starpostnum; - tic_t starposttime; - angle_t starpostangle; - angle_t angle_pos; - angle_t old_angle_pos; - tic_t bumpertime; - INT32 flyangle; - tic_t drilltimer; - INT32 linkcount; - tic_t linktimer; - INT32 anotherflyangle; - tic_t nightstime; - INT32 drillmeter; - UINT8 drilldelay; - UINT8 bonustime; - UINT8 mare; - INT16 lastsidehit, lastlinehit; - tic_t losstime; - UINT8 timeshit; - INT32 onconveyor; - UINT8 spectator; //boolean - tic_t jointime; - - //player->mo stuff - UINT8 hasmo; //boolean - - angle_t angle; - fixed_t x; - fixed_t y; - fixed_t z; - fixed_t momx; - fixed_t momy; - fixed_t momz; - fixed_t friction; - fixed_t movefactor; - - INT32 tics; - statenum_t statenum; - UINT32 flags; - UINT32 flags2; - UINT8 eflags; - INT32 health; - - fixed_t radius; - fixed_t height; - fixed_t scale; - fixed_t destscale; - fixed_t scalespeed; -} ATTRPACK cons_pak; - // Shorter player information for external use. typedef struct { @@ -372,6 +379,9 @@ typedef struct client2cmd_pak client2pak; // 200 bytes servertics_pak serverpak; // 132495 bytes serverconfig_pak servercfg; // 773 bytes + resynchend_pak resynchend; // + resynch_pak resynchpak; // + UINT8 resynchgot; // UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes filetx_pak filetxpak; // 139 bytes clientconfig_pak clientcfg; // 136 bytes @@ -379,7 +389,6 @@ typedef struct serverrefuse_pak serverrefuse; // 65025 bytes askinfo_pak askinfo; // 61 bytes msaskinfo_pak msaskinfo; // 22 bytes - cons_pak consistency; // 544 bytes plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes #ifdef NEWPING @@ -437,7 +446,7 @@ extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; #endif -extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_consfailprotect, cv_blamecfail, cv_maxsend; +extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend; // used in d_net, the only dependence tic_t ExpandTics(INT32 low); @@ -492,4 +501,5 @@ void D_ResetTiccmds(void); tic_t GetLag(INT32 node); UINT8 GetFreeXCmdSize(void); +extern UINT8 hu_resynching; #endif diff --git a/src/d_main.c b/src/d_main.c index 2492f622..bd8e12f2 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -401,7 +401,10 @@ static void D_Display(void) if (lastdraw) { if (rendermode == render_soft) + { VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); + usebuffer = true; + } lastdraw = false; } @@ -1087,14 +1090,14 @@ void D_SRB2Main(void) #endif D_CleanFile(); -#if 1 // md5s last updated 3/18/14 +#if 1 // md5s last updated 3/22/14 // Check MD5s of autoloaded files W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad W_VerifyFileMD5(1, "a894044b555dfcc71865cee16a996e88"); // zones.dta W_VerifyFileMD5(2, "4c410c1de6e0440cc5b2858dcca80c3e"); // player.dta W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.dta - W_VerifyFileMD5(4, "12c58561edf3be16a15505f1d5eacee0"); // patch.dta + W_VerifyFileMD5(4, "4d56695e194a6fd3bc5c87610a215186"); // patch.dta // don't check music.dta because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. diff --git a/src/d_net.c b/src/d_net.c index 3c2213fc..906c5389 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -129,10 +129,10 @@ boolean Net_GetNetStat(void) // ----------------------------------------------------------------- // Some structs and functions for acknowledgement of packets // ----------------------------------------------------------------- -#define MAXACKPACKETS 64 // minimum number of nodes -#define MAXACKTOSEND 64 -#define URGENTFREESLOTENUM 6 -#define ACKTOSENDTIMEOUT (TICRATE/17) +#define MAXACKPACKETS 96 // minimum number of nodes +#define MAXACKTOSEND 96 +#define URGENTFREESLOTENUM 10 +#define ACKTOSENDTIMEOUT (TICRATE/11) #ifndef NONET typedef struct @@ -784,18 +784,6 @@ static void DebugPrintpacket(const char *header) fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)( &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])); break; - case PT_CONSISTENCY: - fprintf(debugfile, " randomseed %d playernum %d hasmo %d\n", - netbuffer->u.consistency.randomseed, netbuffer->u.consistency.playernum, netbuffer->u.consistency.hasmo); - fprintf(debugfile, " x %d y %d z %d momx %d momy %d momz %d\n", - netbuffer->u.consistency.x, netbuffer->u.consistency.y, netbuffer->u.consistency.z, - netbuffer->u.consistency.momx, netbuffer->u.consistency.momy, netbuffer->u.consistency.momz); - fprintf(debugfile, " angle %d health %d eflags %d flags %d flags2 %d\n", - netbuffer->u.consistency.angle, netbuffer->u.consistency.health, netbuffer->u.consistency.eflags, - netbuffer->u.consistency.flags, netbuffer->u.consistency.flags2); - fprintf(debugfile, " friction %d movefactor %d tics %d statenum %d\n", - netbuffer->u.consistency.friction, netbuffer->u.consistency.movefactor, - netbuffer->u.consistency.tics, (INT32)netbuffer->u.consistency.statenum); case PT_CLIENTCMD: case PT_CLIENT2CMD: case PT_CLIENTMIS: diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 57445244..6b74e602 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1575,15 +1575,18 @@ static void Command_Playdemo_f(void) return; } - // disconnect from server here? - if (demoplayback || metalplayback) - G_StopDemo(); if (netgame) { CONS_Printf(M_GetText("You can't play a demo while in a netgame.\n")); return; } + // disconnect from server here? + if (demoplayback) + G_StopDemo(); + if (metalplayback) + G_StopMetalDemo(); + // open the demo file strcpy(name, COM_Argv(1)); // dont add .lmp so internal game demos can be played @@ -1603,15 +1606,18 @@ static void Command_Timedemo_f(void) return; } - // disconnect from server here? - if (demoplayback || metalplayback) - G_StopDemo(); if (netgame) { CONS_Printf(M_GetText("You can't play a demo while in a netgame.\n")); return; } + // disconnect from server here? + if (demoplayback) + G_StopDemo(); + if (metalplayback) + G_StopMetalDemo(); + // open the demo file strcpy (name, COM_Argv(1)); // dont add .lmp so internal game demos can be played @@ -1970,6 +1976,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (demorecording) // Okay, level loaded, character spawned and skinned, G_BeginRecording(); // I AM NOW READY TO RECORD. demo_start = true; + metal_start = true; } static void Command_Pause(void) @@ -3138,10 +3145,8 @@ static void Command_Addfile(void) p = fn+strlen(fn); while(--p >= fn) if (*p == '\\' || *p == '/' || *p == ':') - { - ++p; break; - } + ++p; WRITESTRINGN(buf_p,p,240); { @@ -4094,8 +4099,17 @@ static void Command_Isgamemodified_f(void) static void Command_Cheats_f(void) { + if (COM_CheckParm("off")) + { + CV_ResetCheatNetVars(); + return; + } + if (CV_CheatsEnabled()) + { CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed -- Cheats are enabled.\n")); + CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.")); + } else CONS_Printf(M_GetText("No CHEAT-marked variables are changed -- Cheats are disabled.\n")); } diff --git a/src/d_player.h b/src/d_player.h index 3abc6ddf..4b297854 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -147,7 +147,7 @@ typedef enum PF_TAGGED = 1<<27, // Player has been tagged and awaits the next round in hide and seek. PF_TAGIT = 1<<28, // The player is it! For Tag Mode - // free: 1<<29, 1<<31 + // free: 1<<29 through 1<<31 } pflags_t; typedef enum @@ -268,10 +268,9 @@ typedef struct player_s // It is updated with cmd->aiming. angle_t aiming; - angle_t awayviewaiming; // Used for cut-away view - // This is only used between levels, // mo->health is used during levels. + /// \todo Remove this. We don't need a second health definition for players. INT32 health; SINT8 pity; // i pity the fool. @@ -324,15 +323,14 @@ typedef struct player_s fixed_t jumpfactor; // How high can the player jump? - INT32 lives; - INT32 continues; // continues that player has acquired + SINT8 lives; + SINT8 continues; // continues that player has acquired - INT32 xtralife; // Ring Extra Life counter + SINT8 xtralife; // Ring Extra Life counter UINT8 gotcontinue; // Got continue from this stage? fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values) - INT32 jumping; // Jump counter - + UINT8 jumping; // Jump counter UINT8 secondjump; UINT8 fly1; // Tails flying @@ -357,10 +355,10 @@ typedef struct player_s ///////////////////// // Race Mode Stuff // ///////////////////// - INT32 numboxes; // Number of item boxes obtained for Race Mode - INT32 totalring; // Total number of rings obtained for Race Mode + INT16 numboxes; // Number of item boxes obtained for Race Mode + INT16 totalring; // Total number of rings obtained for Race Mode tic_t realtime; // integer replacement for leveltime - UINT32 laps; // Number of laps (optional) + UINT8 laps; // Number of laps (optional) //////////////////// // CTF Mode Stuff // @@ -421,6 +419,7 @@ typedef struct player_s mobj_t *awayviewmobj; INT32 awayviewtics; + angle_t awayviewaiming; // Used for cut-away view boolean spectator; UINT8 bot; diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index 41d25f2e..edbba552 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -36,8 +36,11 @@ typedef enum BT_CAMRIGHT = 1<<9, // turn camera right BT_TOSSFLAG = 1<<10, BT_JUMP = 1<<11, - BT_FIRENORMAL = 1<<12 // Fire a normal ring no matter what - // free: up to and including 1<<15 + BT_FIRENORMAL = 1<<12, // Fire a normal ring no matter what + + BT_CUSTOM1 = 1<<13, + BT_CUSTOM2 = 1<<14, + BT_CUSTOM3 = 1<<15, } buttoncode_t; // The data sampled per tick (single player) diff --git a/src/dehacked.c b/src/dehacked.c index e25f66e7..35e672eb 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1132,7 +1132,7 @@ static void readlevelheader(MYFILE *f, INT32 num) else if (fastcmp(word, "PALETTE")) mapheaderinfo[num-1]->palette = (UINT16)i; else if (fastcmp(word, "NUMLAPS")) - mapheaderinfo[num-1]->numlaps = (UINT32)i; + mapheaderinfo[num-1]->numlaps = (UINT8)i; else if (fastcmp(word, "UNLOCKABLE")) { if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something @@ -7101,6 +7101,7 @@ static const char *const MOBJFLAG_LIST[] = { "STICKY", "NIGHTSITEM", "NOCLIPTHING", + "GRENADEBOUNCE", "RUNSPAWNFUNC", NULL }; @@ -7325,24 +7326,29 @@ static const char *const HUDITEMS_LIST[] = { "LIVESPIC", "LIVESNUM", "LIVESX", - "RINGSSPLIT", - "RINGSNUMSPLIT", + "RINGS", + "RINGSSPLIT", "RINGSNUM", + "RINGSNUMSPLIT", + "SCORE", "SCORENUM", - "TIMESPLIT", - "SECONDSSPLIT", - "MINUTESSPLIT", - "TIMECOLONSPLIT", + "TIME", - "TICS", - "SECONDS", + "TIMESPLIT", "MINUTES", + "MINUTESSPLIT", "TIMECOLON", + "TIMECOLONSPLIT", + "SECONDS", + "SECONDSSPLIT", "TIMETICCOLON", - "SS_TOTALRINGS_SPLIT", + "TICS", + "SS_TOTALRINGS", + "SS_TOTALRINGS_SPLIT", + "GETRINGS", "GETRINGSNUM", "TIMELEFT", @@ -7643,6 +7649,9 @@ struct { {"BT_TOSSFLAG",BT_TOSSFLAG}, {"BT_JUMP",BT_JUMP}, {"BT_FIRENORMAL",BT_FIRENORMAL}, // Fire a normal ring no matter what + {"BT_CUSTOM1",BT_CUSTOM1}, // Lua customizable + {"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable + {"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable // cvflags_t {"CV_SAVE",CV_SAVE}, @@ -7683,6 +7692,9 @@ struct { {"V_70TRANS",V_70TRANS}, {"V_80TRANS",V_80TRANS}, {"V_90TRANS",V_90TRANS}, + {"V_HUDTRANSHALF",V_HUDTRANSHALF}, + {"V_HUDTRANS",V_HUDTRANS}, + {"V_HUDTRANSDOUBLE",V_HUDTRANSDOUBLE}, {"V_AUTOFADEOUT",V_AUTOFADEOUT}, {"V_RETURN8",V_RETURN8}, {"V_OFFSET",V_OFFSET}, diff --git a/src/doomdata.h b/src/doomdata.h index 4023c497..371decc2 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -131,6 +131,7 @@ typedef struct #define ML_NOSONIC 2048 #define ML_NOTAILS 4096 #define ML_NOKNUX 8192 +#define ML_NETONLY 14336 // all of the above // Bounce off walls! #define ML_BOUNCY 16384 diff --git a/src/doomdef.h b/src/doomdef.h index 3649db08..6c9d7ebe 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -144,8 +144,8 @@ extern FILE *logstream; #define VERSIONSTRING "Trunk" #else #define VERSION 201 // Game version -#define SUBVERSION 3 // more precise version number -#define VERSIONSTRING "v2.1.3" +#define SUBVERSION 5 // more precise version number +#define VERSIONSTRING "v2.1.5" #endif // Modification options @@ -201,7 +201,7 @@ extern FILE *logstream; // it's only for detection of the version the player is using so the MS can alert them of an update. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". -#define MODVERSION 7 +#define MODVERSION 10 @@ -469,7 +469,7 @@ extern const char *compdate, *comptime, *comprevision; #if !defined (_NDS) && !defined (_PSP) /// Shuffle's incomplete OpenGL sorting code. -//#define SHUFFLE +#define SHUFFLE // This has nothing to do with sorting, why was it disabled? #endif #if !defined (_NDS) && !defined (_PSP) diff --git a/src/doomstat.h b/src/doomstat.h index 576b7009..642e9bfc 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -227,7 +227,7 @@ typedef struct UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. INT16 countdown; ///< Countdown until level end? UINT16 palette; ///< PAL lump to use on this map - UINT32 numlaps; ///< Number of laps in circuit mode, unless overridden. + UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) diff --git a/src/g_game.c b/src/g_game.c index e3f2a281..8f0d5b91 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -231,14 +231,17 @@ boolean demorecording; boolean demoplayback; boolean titledemo; // Title Screen demo can be cancelled by any key static UINT8 *demobuffer = NULL; -static UINT8 *metalbuffer = NULL; -static UINT8 *demo_p, *metal_p, *demotime_p; +static UINT8 *demo_p, *demotime_p; static UINT8 *demoend; static UINT8 demoflags; boolean singledemo; // quit after playing a demo from cmdline +boolean demo_start; // don't start playing demo right away + boolean metalrecording; // recording as metal sonic mobj_t *metalplayback; -boolean demo_start; // don't start playing demo right away +static UINT8 *metalbuffer = NULL; +static UINT8 *metal_p; +boolean metal_start; // extra data stuff (events registered this frame while recording) static struct { @@ -1046,8 +1049,16 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) if (PLAYER1INPUTDOWN(gc_tossflag)) cmd->buttons |= BT_TOSSFLAG; + // Lua scriptable buttons + if (PLAYER1INPUTDOWN(gc_custom1)) + cmd->buttons |= BT_CUSTOM1; + if (PLAYER1INPUTDOWN(gc_custom2)) + cmd->buttons |= BT_CUSTOM2; + if (PLAYER1INPUTDOWN(gc_custom3)) + cmd->buttons |= BT_CUSTOM3; + // use with any button/key - if (PLAYER1INPUTDOWN(gc_use) && !(player->pflags & PF_MACESPIN)) + if (PLAYER1INPUTDOWN(gc_use)) cmd->buttons |= BT_USE; // Camera Controls @@ -1315,6 +1326,14 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) if (PLAYER2INPUTDOWN(gc_tossflag)) cmd->buttons |= BT_TOSSFLAG; + // Lua scriptable buttons + if (PLAYER2INPUTDOWN(gc_custom1)) + cmd->buttons |= BT_CUSTOM1; + if (PLAYER2INPUTDOWN(gc_custom2)) + cmd->buttons |= BT_CUSTOM2; + if (PLAYER2INPUTDOWN(gc_custom3)) + cmd->buttons |= BT_CUSTOM3; + // use with any button/key if (PLAYER2INPUTDOWN(gc_use)) cmd->buttons |= BT_USE; @@ -1467,10 +1486,12 @@ static void Analog_OnChange(void) { if (!cv_cam_dist.string) return; + + // cameras are not initialized at this point + if (leveltime > 1) CV_SetValue(&cv_cam_dist, 128); - - if (netgame || !camera.chase) + if (netgame) CV_StealthSetValue(&cv_analog, 0); else if (cv_analog.value || demoplayback) CV_SetValue(&cv_cam_dist, 192); @@ -1480,9 +1501,12 @@ static void Analog2_OnChange(void) { if (!splitscreen || !cv_cam2_dist.string) return; + + // cameras are not initialized at this point + if (leveltime > 1) CV_SetValue(&cv_cam2_dist, 128); - if (netgame || !camera2.chase) + if (netgame) CV_StealthSetValue(&cv_analog2, 0); else if (cv_analog2.value) CV_SetValue(&cv_cam2_dist, 192); @@ -1927,7 +1951,6 @@ void G_PlayerReborn(INT32 player) INT32 score; INT32 lives; INT32 continues; - INT32 xtralife; UINT8 charability; UINT8 charability2; fixed_t normalspeed; @@ -1952,9 +1975,9 @@ void G_PlayerReborn(INT32 player) INT32 starpostangle; fixed_t jumpfactor; INT32 exiting; - INT32 numboxes; - INT32 laps; - INT32 totalring; + INT16 numboxes; + INT16 totalring; + UINT8 laps; UINT8 mare; UINT8 skincolor; INT32 skin; @@ -1966,7 +1989,6 @@ void G_PlayerReborn(INT32 player) score = players[player].score; lives = players[player].lives; continues = players[player].continues; - xtralife = players[player].xtralife; ctfteam = players[player].ctfteam; exiting = players[player].exiting; jointime = players[player].jointime; @@ -2017,7 +2039,6 @@ void G_PlayerReborn(INT32 player) p->lives = lives; p->continues = continues; p->pflags = pflags; - p->xtralife = xtralife; p->ctfteam = ctfteam; p->jointime = jointime; p->spectator = spectator; @@ -2643,8 +2664,10 @@ static void G_DoCompleted(void) gameaction = ga_nothing; - if (metalrecording || metalplayback) - G_CheckDemoStatus(); + if (metalplayback) + G_StopMetalDemo(); + if (metalrecording) + G_StopMetalRecording(); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) @@ -4198,7 +4221,7 @@ void G_ReadMetalTic(mobj_t *metal) UINT16 speed; UINT8 statetype; - if (!metal_p || !demo_start) + if (!metal_p || !metal_start) return; ziptic = READUINT8(metal_p); @@ -4287,7 +4310,7 @@ void G_ReadMetalTic(mobj_t *metal) if (*metal_p == DEMOMARKER) { // end of demo data stream - G_CheckDemoStatus(); + G_StopMetalDemo(); return; } } @@ -4394,7 +4417,7 @@ void G_WriteMetalTic(mobj_t *metal) // latest demos with mouse aiming byte in ticcmd if (demo_p >= demoend - 32) { - G_CheckDemoStatus(); // no more space + G_StopMetalRecording(); // no more space return; } } @@ -4869,6 +4892,7 @@ void G_DoPlayDemo(char *defdemoname) // didn't start recording right away. demo_start = false; + metal_start = false; #ifdef HAVE_BLUA LUAh_MapChange(); @@ -4914,6 +4938,7 @@ void G_DoPlayDemo(char *defdemoname) players[0].jumpfactor = jumpfactor; demo_start = true; + metal_start = true; } void G_AddGhost(char *defdemoname) @@ -5166,6 +5191,7 @@ void G_DoPlayMetal(void) if (!mo) { CONS_Alert(CONS_ERROR, M_GetText("Failed to find bot entity.\n")); + Z_Free(metalbuffer); return; } @@ -5213,18 +5239,46 @@ void G_DoneLevelLoad(void) =================== */ +// Stops metal sonic's demo. Separate from other functions because metal + replays can coexist +void G_StopMetalDemo(void) +{ + + // Metal Sonic finishing doesn't end the game, dammit. + Z_Free(metalbuffer); + metalbuffer = NULL; + metalplayback = NULL; + metal_p = NULL; +} + +// Stops metal sonic recording. +ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void) +{ + boolean saved = false; + if (demo_p) + { + UINT8 *p = demobuffer+16; // checksum position +#ifdef NOMD5 + UINT8 i; + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + for (i = 0; i < 16; i++, p++) + *p = P_Random(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. +#else + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + md5_buffer((char *)p+16, demo_p - (p+16), (void *)p); // make a checksum of everything after the checksum in the file. +#endif + saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. + } + free(demobuffer); + metalrecording = false; + if (saved) + I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); + I_Error("Failed to save demo!"); +} + // reset engine variable set for the demos // called from stopdemo command, map command, and g_checkdemoStatus. void G_StopDemo(void) { - if (metalplayback) - { // Metal Sonic finishing doesn't end the game, dammit. - Z_Free(metalbuffer); - metalbuffer = NULL; - metalplayback = NULL; - if (!demoplayback) - return; - } Z_Free(demobuffer); demobuffer = NULL; demoplayback = false; @@ -5248,31 +5302,7 @@ boolean G_CheckDemoStatus(void) if(ghosts) // ... ... ... ghosts = NULL; // :) - if (metalrecording) - { - saved = false; - if (demo_p) - { - UINT8 *p = demobuffer+16; // checksum position -#ifdef NOMD5 - UINT8 i; - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - for (i = 0; i < 16; i++, p++) - *p = P_Random(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. -#else - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - md5_buffer((char *)p+16, demo_p - (p+16), (void *)p); // make a checksum of everything after the checksum in the file. -#endif - saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. - } - free(demobuffer); - metalrecording = false; - if (saved) - I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); - else - I_Error("Failed to save demo!"); - return true; - } + // DO NOT end metal sonic demos here if (timingdemo) { @@ -5332,12 +5362,6 @@ boolean G_CheckDemoStatus(void) return true; } - if (metalplayback) - { - G_StopDemo(); - return false; - } - return false; } diff --git a/src/g_game.h b/src/g_game.h index d57b6ebd..af37fc8a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -37,12 +37,14 @@ extern boolean playeringame[MAXPLAYERS]; // demoplaying back and demo recording extern boolean demoplayback, titledemo, demorecording, timingdemo; -extern mobj_t *metalplayback; // Quit after playing a demo from cmdline. extern boolean singledemo; extern boolean demo_start; +extern mobj_t *metalplayback; +extern boolean metal_start; + // gametic at level start extern tic_t levelstarttic; @@ -150,6 +152,8 @@ void G_TimeDemo(const char *name); void G_AddGhost(char *defdemoname); void G_DoPlayMetal(void); void G_DoneLevelLoad(void); +void G_StopMetalDemo(void); +ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void); void G_StopDemo(void); boolean G_CheckDemoStatus(void); diff --git a/src/g_input.c b/src/g_input.c index 29d13dce..f8170dd3 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -989,6 +989,9 @@ static const char *gamecontrolname[num_gamecontrols] = "jump", "console", "pause", + "custom1", + "custom2", + "custom3", }; #define NUMKEYNAMES (sizeof (keynames)/sizeof (keyname_t)) diff --git a/src/g_input.h b/src/g_input.h index 334b7ad9..699542a8 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -118,6 +118,9 @@ typedef enum gc_jump, gc_console, gc_pause, + gc_custom1, // Lua scriptable + gc_custom2, // Lua scriptable + gc_custom3, // Lua scriptable num_gamecontrols } gamecontrols_e; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 6dc0f0f7..168761a0 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -67,6 +67,10 @@ typedef UINT8 GLRGB[3]; #define BLENDMODE PF_Translucent +static UINT8 softwaretranstogl[11] = { 0, 25, 51, 76,102,127,153,178,204,229,255}; +static UINT8 softwaretranstogl_hi[11] = { 0, 51,102,153,204,255,255,255,255,255,255}; +static UINT8 softwaretranstogl_lo[11] = { 0, 12, 24, 36, 48, 60, 71, 83, 95,111,127}; + // // -----------------+ // HWR_DrawPatch : Draw a 'tile' graphic @@ -128,24 +132,16 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) flags |= PF_ForceWrapY; // clip it since it is used for bunny scroll in doom I - if (option & V_TRANSLUCENT) - { - FSurfaceInfo Surf; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.s.alpha = (UINT8)cv_grtranslucenthud.value; - flags |= PF_Modulated; - HWD.pfnDrawPolygon(&Surf, v, 4, flags); - } - else - HWD.pfnDrawPolygon(NULL, v, 4, flags); + HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, fixed_t scale) +void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, const UINT8 *colormap) { FOutVector v[4]; FBITFIELD flags; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); + UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); // 3--2 // | /| @@ -153,11 +149,17 @@ void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, // 0--1 float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(scale); - float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(scale); + float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); + float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); + + if (alphalevel >= 10 && alphalevel < 13) + return; // make patch ready in hardware cache - HWR_GetPatch(gpatch); + if (!colormap) + HWR_GetPatch(gpatch); + else + HWR_GetMappedPatch(gpatch, colormap); switch (option & V_SCALEPATCHMASK) { @@ -197,11 +199,14 @@ void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, flags |= PF_ForceWrapY; // clip it since it is used for bunny scroll in doom I - if (option & V_TRANSLUCENT) + if (alphalevel) { FSurfaceInfo Surf; Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.s.alpha = (UINT8)cv_grtranslucenthud.value; + 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]; + else Surf.FlatColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } @@ -209,19 +214,13 @@ void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawClippedPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) +void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) { - // hardware clips the patch quite nicely anyway :) - HWR_DrawPatch(gpatch, x, y, option); /// \todo do real cliping -} - -// Only supports one kind of translucent for now. Tails 06-12-2003 -// Boked -// Alam_GBC: Why? you could not get a FSurfaceInfo to set the alpha channel? -void HWR_DrawTranslucentPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) -{ - FOutVector v[4]; + FOutVector v[4]; FBITFIELD flags; + float cx = FIXED_TO_FLOAT(x); + float cy = FIXED_TO_FLOAT(y); + UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); // 3--2 // | /| @@ -229,12 +228,14 @@ void HWR_DrawTranslucentPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option // 0--1 float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; - float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - FSurfaceInfo Surf; + float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); + float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); + + if (alphalevel >= 10 && alphalevel < 13) + return; // make patch ready in hardware cache - HWR_GetPatch (gpatch); + HWR_GetPatch(gpatch); switch (option & V_SCALEPATCHMASK) { @@ -254,82 +255,19 @@ void HWR_DrawTranslucentPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option if (option & V_NOSCALESTART) sdupx = sdupy = 2.0f; - v[0].x = v[3].x = (x*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; - v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdupy-gpatch->topoffset*pdupy)/vid.height; - v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; + v[0].x = v[3].x = (cx*sdupx - gpatch->leftoffset * pdupx) / vid.width - 1; + v[2].x = v[1].x = (cx*sdupx + ((w-sx) - gpatch->leftoffset) * pdupx) / vid.width - 1; + v[0].y = v[1].y = 1 - (cy*sdupy - gpatch->topoffset * pdupy) / vid.height; + v[2].y = v[3].y = 1 - (cy*sdupy + ((h-sy) - gpatch->topoffset) * pdupy) / vid.height; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = gpatch->max_s; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; + v[0].sow = v[3].sow = ((sx)/(float)gpatch->width )*gpatch->max_s; + v[2].sow = v[1].sow = ((w )/(float)gpatch->width )*gpatch->max_s; + v[0].tow = v[1].tow = ((sy)/(float)gpatch->height)*gpatch->max_t; + v[2].tow = v[3].tow = ((h )/(float)gpatch->height)*gpatch->max_t; - flags = PF_Modulated | BLENDMODE | PF_Clip | PF_NoZClip | PF_NoDepthTest; - - if (option & V_WRAPX) - flags |= PF_ForceWrapX; - if (option & V_WRAPY) - flags |= PF_ForceWrapY; - - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - // Alam_GBC: There, you have translucent HW Draw, OK? - if ((option & V_TRANSLUCENT) && cv_grtranslucenthud.value != 255) - { - Surf.FlatColor.s.alpha = (UINT8)(cv_grtranslucenthud.value/2); - } - else - Surf.FlatColor.s.alpha = 127; - - HWD.pfnDrawPolygon(&Surf, v, 4, flags); -} - -// Draws a patch 2x as small SSNTails 06-10-2003 -void HWR_DrawSmallPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, const UINT8 *colormap) -{ - FOutVector v[4]; - FBITFIELD flags; - - float sdupx = FIXED_TO_FLOAT(vid.fdupx); - float sdupy = FIXED_TO_FLOAT(vid.fdupy); - float pdupx = FIXED_TO_FLOAT(vid.fdupx); - float pdupy = FIXED_TO_FLOAT(vid.fdupy); - - // make patch ready in hardware cache - HWR_GetMappedPatch (gpatch, colormap); - - switch (option & V_SCALEPATCHMASK) - { - case V_NOSCALEPATCH: - pdupx = pdupy = 2.0f; - break; - case V_SMALLSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy); - break; - case V_MEDSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy); - break; - } - - if (option & V_NOSCALESTART) - sdupx = sdupy = 2.0f; - - v[0].x = v[3].x = (x*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; - v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdupy-gpatch->topoffset*pdupy)/vid.height; - v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; - - v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = gpatch->max_s; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; - - flags = BLENDMODE | PF_Clip | PF_NoZClip | PF_NoDepthTest; + flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; if (option & V_WRAPX) flags |= PF_ForceWrapX; @@ -337,77 +275,14 @@ void HWR_DrawSmallPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, cons flags |= PF_ForceWrapY; // clip it since it is used for bunny scroll in doom I - if (option & V_TRANSLUCENT) + if (alphalevel) { FSurfaceInfo Surf; Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.s.alpha = (UINT8)cv_grtranslucenthud.value; - flags |= PF_Modulated; - HWD.pfnDrawPolygon(&Surf, v, 4, flags); - } - else - HWD.pfnDrawPolygon(NULL, v, 4, flags); -} - -// -// HWR_DrawMappedPatch(): Like HWR_DrawPatch but with translated color -// -void HWR_DrawMappedPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, const UINT8 *colormap) -{ - FOutVector v[4]; - FBITFIELD flags; - - float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; - float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; - float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - - // make patch ready in hardware cache - HWR_GetMappedPatch (gpatch, colormap); - - switch (option & V_SCALEPATCHMASK) - { - case V_NOSCALEPATCH: - pdupx = pdupy = 2.0f; - break; - case V_SMALLSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy); - break; - case V_MEDSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy); - break; - } - - if (option & V_NOSCALESTART) - sdupx = sdupy = 2.0f; - - v[0].x = v[3].x = (x*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; - v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdupy-gpatch->topoffset*pdupy)/vid.height; - v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; - - v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - - v[0].sow = v[3].sow = 0.0f; - v[2].sow = v[1].sow = gpatch->max_s; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; - - flags = BLENDMODE | PF_Clip | PF_NoZClip | PF_NoDepthTest; - - if (option & V_WRAPX) - flags |= PF_ForceWrapX; - if (option & V_WRAPY) - flags |= PF_ForceWrapY; - - // clip it since it is used for bunny scroll in doom I - if (option & V_TRANSLUCENT) - { - FSurfaceInfo Surf; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.s.alpha = (UINT8)cv_grtranslucenthud.value; + 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]; + else Surf.FlatColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } @@ -447,15 +322,7 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) // But then, the question is: why not 0 instead of PF_Masked ? // or maybe PF_Environment ??? (like what I said above) // BP: PF_Environment don't change anything ! and 0 is undifined - if (cv_grtranslucenthud.value != 255) - { - FSurfaceInfo Surf; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.s.alpha = (UINT8)cv_grtranslucenthud.value; - HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated | BLENDMODE | PF_NoDepthTest | PF_Clip | PF_NoZClip); - } - else - HWD.pfnDrawPolygon(NULL, v, 4, BLENDMODE | PF_NoDepthTest | PF_Clip | PF_NoZClip); + HWD.pfnDrawPolygon(NULL, v, 4, BLENDMODE | PF_NoDepthTest | PF_Clip | PF_NoZClip); } // ========================================================================== diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b2b51773..0e356269 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1212,23 +1212,17 @@ static void HWR_SplitFog(sector_t *sector, wallVert3D *wallVerts, FSurfaceInfo* if (list[i].caster) { - if (sector->lightlist[i].caster->flags & FF_SOLID && !(cutflag & FF_EXTRA)) - solid = true; - else if (sector->lightlist[i].caster->flags & FF_CUTEXTRA && cutflag & FF_EXTRA) + if (sector->lightlist[i].caster->flags & FF_FOG && cutflag & FF_FOG) // Only fog cuts fog { if (sector->lightlist[i].caster->flags & FF_EXTRA) { - if (sector->lightlist[i].caster->flags == cutflag) + if (sector->lightlist[i].caster->flags == cutflag) // only cut by the same solid = true; } else solid = true; } - else - solid = false; } - else - solid = false; height = FIXED_TO_FLOAT(list[i].height); @@ -1645,7 +1639,12 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) blendmode = PF_Environment; if (gr_frontsector->numlights) - HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS); + { + if (!(blendmode & PF_Masked)) + HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS|FF_TRANSLUCENT); + else + HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS); + } else if (!(blendmode & PF_Masked)) HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap); else @@ -3385,30 +3384,17 @@ noshadow: if (sector->numlights) { - INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false); + INT32 light; - if ((sector->lightlist[light].height > (spr->mobj->z + spr->mobj->height)) && !(sector->lightlist[light].flags & FF_NOSHADE)) - { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel); - else - lightlevel = LightLevelToLum(255); + light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } - else // If we can't use the light at its bottom, we'll use the light at its top - { - light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel); + else + lightlevel = LightLevelToLum(255); - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel); - else - lightlevel = LightLevelToLum(255); - - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } + if (sector->lightlist[light].extra_colormap) + colormap = sector->lightlist[light].extra_colormap; } else { @@ -3855,7 +3841,7 @@ static void HWR_DrawSprites(void) HWR_DrawPrecipitationSprite(spr); else #endif - if (spr->mobj->skin) + if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { if (!cv_grmd2.value || (cv_grmd2.value && md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == true)) HWR_DrawSprite(spr); @@ -3884,7 +3870,7 @@ static void HWR_DrawMD2S(void) if (!spr->precip) { #endif - if (spr->mobj && spr->mobj->skin) + if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { if ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false) && (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)) HWR_DrawMD2(spr); @@ -4323,6 +4309,8 @@ static void HWR_DrawSkyBackground(player_t *player) v[0].z = v[1].z = v[2].z = v[3].z = 4.0f; + // X + if (textures[skytexture]->width > 256) angle = (angle_t)((float)(dup_viewangle + gr_xtoviewangle[0]) /((float)textures[skytexture]->width/256.0f)) @@ -4337,9 +4325,19 @@ static void HWR_DrawSkyBackground(player_t *player) v[0].sow = v[3].sow = 0.22f+(f)/(textures[skytexture]->width/2); v[2].sow = v[1].sow = 0.22f+(f+(127))/(textures[skytexture]->width/2); + + // Y + + if (textures[skytexture]->height > 256) + angle = (angle_t)((float)(aimingangle) + *(256.0f/(float)textures[skytexture]->height)) + %(ANGLE_90-1); // Just so that looking up and down scales right + else + angle = (aimingangle); + f = (float)((textures[skytexture]->height/2) * FIXED_TO_FLOAT(FINETANGENT((2048 - - ((INT32)aimingangle>>(ANGLETOFINESHIFT + 1))) & FINEMASK))); + - ((INT32)angle>>(ANGLETOFINESHIFT + 1))) & FINEMASK))); v[3].tow = v[2].tow = 0.22f+(f)/(textures[skytexture]->height/2); v[0].tow = v[1].tow = 0.22f+(f+(127))/(textures[skytexture]->height/2); @@ -4406,9 +4404,9 @@ void HWR_SetViewSize(void) } // ========================================================================== -// +// Same as rendering the player view, but from the skybox object // ========================================================================== -void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) +void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) { const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd); FTransform stransform; @@ -4425,7 +4423,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) } // note: sets viewangle, viewx, viewy, viewz - R_SetupFrame(player, false); + R_SkyboxFrame(player); // copy view cam position for local use dup_viewx = viewx; @@ -4572,6 +4570,217 @@ if (0) HWR_DrawCoronas(); #endif +#ifdef SORTING + if (numplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything + { + HWR_CreateDrawNodes(); + } +#else + if (numfloors || numwalls) + { + HWD.pfnSetTransform(&atransform); + if (numfloors) + HWR_Render3DWater(); + if (numwalls) + HWR_RenderTransparentWalls(); + } +#endif + + HWD.pfnSetTransform(NULL); + + // put it off for menus etc + if (cv_grfog.value) + HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); + + // Check for new console commands. + NetUpdate(); + + // added by Hurdler for correct splitscreen + // moved here by hurdler so it works with the new near clipping plane + HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); +} + +// ========================================================================== +// +// ========================================================================== +void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) +{ + const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd); + FTransform stransform; + + const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on + + FRGBAFloat ClearColor; + + ClearColor.red = 0.0f; + ClearColor.green = 0.0f; + ClearColor.blue = 0.0f; + ClearColor.alpha = 1.0f; + + HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. + + if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox + HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind + + { + // do we really need to save player (is it not the same)? + player_t *saved_player = stplyr; + stplyr = player; + ST_doPaletteStuff(); + stplyr = saved_player; +#ifdef ALAM_LIGHTING + HWR_SetLights(viewnumber); +#endif + } + + // note: sets viewangle, viewx, viewy, viewz + R_SetupFrame(player, false); // This can stay false because it is only used to set viewsky in r_main.c, which isn't used here + + // copy view cam position for local use + dup_viewx = viewx; + dup_viewy = viewy; + dup_viewz = viewz; + dup_viewangle = viewangle; + + // set window position + gr_centery = gr_basecentery; + gr_viewwindowy = gr_baseviewwindowy; + gr_windowcentery = gr_basewindowcentery; + if (splitscreen && viewnumber == 1) + { + gr_viewwindowy += (vid.height/2); + gr_windowcentery += (vid.height/2); + } + + // check for new console commands. + NetUpdate(); + + gr_viewx = FIXED_TO_FLOAT(dup_viewx); + gr_viewy = FIXED_TO_FLOAT(dup_viewy); + gr_viewz = FIXED_TO_FLOAT(dup_viewz); + gr_viewsin = FIXED_TO_FLOAT(viewsin); + gr_viewcos = FIXED_TO_FLOAT(viewcos); + + gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(aimingangle>>ANGLETOFINESHIFT)); + gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(aimingangle>>ANGLETOFINESHIFT)); + + //04/01/2000: Hurdler: added for T&L + // It should replace all other gr_viewxxx when finished + atransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + atransform.x = gr_viewx; // FIXED_TO_FLOAT(viewx) + atransform.y = gr_viewy; // FIXED_TO_FLOAT(viewy) + atransform.z = gr_viewz; // FIXED_TO_FLOAT(viewz) + atransform.scalex = 1; + atransform.scaley = ORIGINAL_ASPECT; + atransform.scalez = 1; + atransform.fovxangle = fpov; // Tails + atransform.fovyangle = fpov; // Tails + atransform.splitscreen = splitscreen; + + // Transform for sprites + stransform.anglex = 0.0f; + stransform.angley = -270.0f; + stransform.x = 0.0f; + stransform.y = 0.0f; + stransform.z = 0.0f; + stransform.scalex = 1; + stransform.scaley = 1; + stransform.scalez = 1; + stransform.fovxangle = 90.0f; + stransform.fovyangle = 90.0f; + stransform.splitscreen = splitscreen; + + gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); + + //------------------------------------------------------------------------ + HWR_ClearView(); // Clears the depth buffer and resets the view I believe + +if (0) +{ // I don't think this is ever used. + if (cv_grfog.value) + HWR_FoggingOn(); // First of all, turn it on, set the default user settings too + else + HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); // Turn it off +} + +#ifndef _NDS + if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox + HWR_DrawSkyBackground(player); +#else + (void)HWR_DrawSkyBackground; +#endif + + //Hurdler: it doesn't work in splitscreen mode + drawsky = splitscreen; + + HWR_ClearSprites(); + +#ifdef SORTING + drawcount = 0; +#endif + HWR_ClearClipSegs(); + + //04/01/2000: Hurdler: added for T&L + // Actually it only works on Walls and Planes + HWD.pfnSetTransform(&atransform); + + validcount++; + + HWR_RenderBSPNode((INT32)numnodes-1); + + // Make a viewangle int so we can render things based on mouselook + if (player == &players[consoleplayer]) + viewangle = localaiming; + else if (splitscreen && player == &players[secondarydisplayplayer]) + viewangle = localaiming2; + + // Handle stuff when you are looking farther up or down. + if ((aimingangle || cv_grfov.value+player->fovadd > 90*FRACUNIT)) + { + dup_viewangle += ANGLE_90; + HWR_ClearClipSegs(); + HWR_RenderBSPNode((INT32)numnodes-1); //left + + dup_viewangle += ANGLE_90; + if (((INT32)aimingangle > ANGLE_45 || (INT32)aimingangle<-ANGLE_45)) + { + HWR_ClearClipSegs(); + HWR_RenderBSPNode((INT32)numnodes-1); //back + } + + dup_viewangle += ANGLE_90; + HWR_ClearClipSegs(); + HWR_RenderBSPNode((INT32)numnodes-1); //right + + dup_viewangle += ANGLE_90; + } + + // Check for new console commands. + NetUpdate(); + +#ifdef ALAM_LIGHTING + //14/11/99: Hurdler: moved here because it doesn't work with + // subsector, see other comments; + HWR_ResetLights(); +#endif + + // Draw MD2 and sprites +#ifdef SORTING + HWR_SortVisSprites(); +#endif + HWR_DrawMD2S(); + + // Draw the sprites with trivial transform + HWD.pfnSetTransform(&stransform); +#ifdef SORTING + HWR_DrawSprites(); +#endif +#ifdef NEWCORONAS + //Hurdler: they must be drawn before translucent planes, what about gl fog? + HWR_DrawCoronas(); +#endif + #ifdef SORTING if (numplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything { @@ -5022,11 +5231,19 @@ void HWR_DoPostProcessor(player_t *player) FOutVector v[4]; FSurfaceInfo Surf; - v[0].x = v[2].y = v[3].x = v[3].y = -1.0f; - v[0].y = v[1].x = v[1].y = v[2].x = 1.0f; - v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; + v[0].x = v[2].y = v[3].x = v[3].y = -4.0f; + v[0].y = v[1].x = v[1].y = v[2].x = 4.0f; + v[0].z = v[1].z = v[2].z = v[3].z = 4.0f; // 4.0 because of the same reason as with the sky, just after the screen is cleared so near clipping plane is 3.99 + + // This won't change if the flash palettes are changed unfortunately, but it works for its purpose + if (player->flashpal == PAL_NUKE) + { + Surf.FlatColor.s.red = 0xff; + Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0x7F; // The nuke palette is kind of pink-ish + } + else + Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; - Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff; Surf.FlatColor.s.alpha = 0xc0; // match software mode HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest|PF_Clip|PF_NoZClip); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index d3b3df66..c93d4ea6 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -35,6 +35,7 @@ void HWR_clearAutomap(void); void HWR_drawAMline(const fline_t *fl, INT32 color); void HWR_FadeScreenMenuBack(UINT32 color, INT32 height); void HWR_DrawConsoleBack(UINT32 color, INT32 height); +void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); void HWR_DrawViewBorder(INT32 clearlines); void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum); @@ -43,11 +44,9 @@ boolean HWR_Screenshot(const char *lbmname); void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); -void HWR_DrawClippedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); -void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, fixed_t scale); -void HWR_DrawTranslucentPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); -void HWR_DrawSmallPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, const UINT8 *colormap); -void HWR_DrawMappedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, const UINT8 *colormap); +void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, const UINT8 *colormap); +void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); +void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, fixed_t scale, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index fb012535..a173971c 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1087,30 +1087,17 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (sector->numlights) { - INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false); + INT32 light; - if (sector->lightlist[light].height > (spr->mobj->z + spr->mobj->height)) - { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel); - else - lightlevel = LightLevelToLum(255); + light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } - else // If we can't use the light at its bottom, we'll use the light at its top - { - light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel); + else + lightlevel = LightLevelToLum(255); - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel); - else - lightlevel = LightLevelToLum(255); - - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } + if (sector->lightlist[light].extra_colormap) + colormap = sector->lightlist[light].extra_colormap; } else { @@ -1136,7 +1123,6 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (cv_grmd2.value && ((md2_models[spr->mobj->sprite].scale > 0.0f) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)) && !spr->precip) { GLPatch_t *gpatch; - FBITFIELD blend = 0; INT32 *buff; UINT32 durs = spr->mobj->state->tics; UINT32 tics = spr->mobj->tics; @@ -1149,14 +1135,12 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (spr->mobj->flags2 & MF2_SHADOW) { Surf.FlatColor.s.alpha = 0x40; - blend = PF_Translucent; } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else { Surf.FlatColor.s.alpha = 0xFF; - blend = PF_Translucent; } // dont forget to enabled the depth test because we can't do this like @@ -1164,7 +1148,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) // 1. load model+texture if not already loaded // 2. draw model with correct position, rotation,... - if (spr->mobj->skin) + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites { md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins]; md2->skin = (skin_t*)spr->mobj->skin-skins; @@ -1188,13 +1172,14 @@ void HWR_DrawMD2(gr_vissprite_t *spr) return; } } - HWD.pfnSetBlend(blend); + //HWD.pfnSetBlend(blend); // This seems to actually break translucency? finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy gpatch = md2->grpatch; if (!gpatch || !gpatch->mipmap.grInfo.format || !gpatch->mipmap.downloaded) md2_loadTexture(md2); - else if (gpatch->mipmap.grInfo.format) + + if (gpatch && gpatch->mipmap.grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture { // This is safe, since we know the texture has been downloaded HWD.pfnSetTexture(&gpatch->mipmap); @@ -1211,7 +1196,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) buff = md2->model->glCommandBuffer; curr = &md2->model->frames[frame]; if (cv_grmd2.value == 1 - && spr->mobj->state->nextstate != S_NULL + && spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL && !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_TAP1 || spr->mobj->state->nextstate == S_PLAY_TAP2) && spr->mobj->state == &states[S_PLAY_STND])) { const INT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index c8f452a6..96902c73 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -903,7 +903,7 @@ static inline void HU_DrawCrosshair(void) #endif y = viewwindowy + (viewheight>>1); - V_DrawTranslucentPatch(vid.width>>1, y, V_NOSCALESTART|V_OFFSET, crosshair[i - 1]); + V_DrawScaledPatch(vid.width>>1, y, V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, crosshair[i - 1]); } static inline void HU_DrawCrosshair2(void) @@ -933,7 +933,7 @@ static inline void HU_DrawCrosshair2(void) #endif y += viewheight; - V_DrawTranslucentPatch(vid.width>>1, y, V_NOSCALESTART|V_OFFSET, crosshair[i - 1]); + V_DrawScaledPatch(vid.width>>1, y, V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, crosshair[i - 1]); } } @@ -1086,6 +1086,10 @@ void HU_Drawer(void) if (!automapactive && cv_crosshair2.value && !demoplayback && !camera2.chase && !players[secondarydisplayplayer].spectator) HU_DrawCrosshair2(); + + // draw desynch text + if (hu_resynching) + V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching..."); } //====================================================================== @@ -1619,7 +1623,7 @@ static void HU_DrawRankings(void) { if (circuitmap) { - if (players[i].laps+1 >= tab[scorelines].count && completed[i] == false) + if ((unsigned)players[i].laps+1 >= tab[scorelines].count && completed[i] == false) { tab[scorelines].count = players[i].laps+1; tab[scorelines].num = i; @@ -1710,19 +1714,19 @@ static void HU_DrawCoopOverlay(void) #endif if (emeralds & EMERALD1) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)-32, V_TRANSLUCENT, emeraldpics[0]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)-32, 0, emeraldpics[0]); if (emeralds & EMERALD2) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)-16, V_TRANSLUCENT, emeraldpics[1]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)-16, 0, emeraldpics[1]); if (emeralds & EMERALD3) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)+16, V_TRANSLUCENT, emeraldpics[2]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)+16, 0, emeraldpics[2]); if (emeralds & EMERALD4) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)+32, V_TRANSLUCENT, emeraldpics[3]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)+32, 0, emeraldpics[3]); if (emeralds & EMERALD5) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)+16, V_TRANSLUCENT, emeraldpics[4]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)+16, 0, emeraldpics[4]); if (emeralds & EMERALD6) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)-16, V_TRANSLUCENT, emeraldpics[5]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)-16, 0, emeraldpics[5]); if (emeralds & EMERALD7) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3) , V_TRANSLUCENT, emeraldpics[6]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3) , 0, emeraldpics[6]); } static void HU_DrawNetplayCoopOverlay(void) @@ -1737,7 +1741,7 @@ static void HU_DrawNetplayCoopOverlay(void) for (i = 0; i < 7; ++i) { if (emeralds & (1 << i)) - V_DrawScaledPatch(20 + (i * 20), 6, V_TRANSLUCENT, emeraldpics[i]); + V_DrawScaledPatch(20 + (i * 20), 6, 0, emeraldpics[i]); } } diff --git a/src/info.c b/src/info.c index e69d84f0..d0ba598b 100644 --- a/src/info.c +++ b/src/info.c @@ -4817,10 +4817,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 20*TICRATE, // mass 48*FRACUNIT, // damage sfx_s3k5d, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE, // flags + MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE|MF_GRENADEBOUNCE, // flags S_NULL // raisestate }, @@ -11936,7 +11936,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 6*TICRATE, // mass (<-- Looking for the Grenade Ring's fuse? It's right here!) 1, // damage sfx_s3k5d, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE, // flags + MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE|MF_GRENADEBOUNCE, // flags S_NULL // raisestate }, diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index f80d9809..38b06961 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -195,6 +195,15 @@ static int patch_set(lua_State *L) // lib_draw // +static int libd_patchExists(lua_State *L) +{ + if (!hud_running) + return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); + + lua_pushboolean(L, W_CheckNumForName(luaL_checkstring(L, 1)) != LUMPERROR); + return 1; +} + static int libd_cachePatch(lua_State *L) { if (!hud_running) @@ -222,21 +231,7 @@ static int libd_draw(lua_State *L) flags &= ~V_PARAMMASK; // Don't let crashes happen. - if (colormap) - { - if (flags & V_ALPHAMASK) - V_DrawTranslucentMappedPatch(x, y, flags, patch, colormap); - else - V_DrawMappedPatch(x, y, flags, patch, colormap); - } - else - { - if (flags & V_ALPHAMASK) - V_DrawTranslucentPatch(x, y, flags, patch); - else - V_DrawScaledPatch(x, y, flags, patch); - } - + V_DrawFixedPatch(x<bob); else if (fastcmp(field,"aiming")) lua_pushinteger(L, plr->aiming); - else if (fastcmp(field,"awayviewaiming")) - lua_pushinteger(L, plr->awayviewaiming); else if (fastcmp(field,"health")) lua_pushinteger(L, plr->health); else if (fastcmp(field,"pity")) @@ -187,7 +185,7 @@ static int player_get(lua_State *L) else if (fastcmp(field,"speed")) lua_pushinteger(L, plr->speed); else if (fastcmp(field,"jumping")) - lua_pushinteger(L, plr->jumping); + lua_pushboolean(L, plr->jumping); else if (fastcmp(field,"secondjump")) lua_pushinteger(L, plr->secondjump); else if (fastcmp(field,"fly1")) @@ -306,6 +304,8 @@ static int player_get(lua_State *L) LUA_PushUserdata(L, plr->awayviewmobj, META_MOBJ); else if (fastcmp(field,"awayviewtics")) lua_pushinteger(L, plr->awayviewtics); + else if (fastcmp(field,"awayviewaiming")) + lua_pushinteger(L, plr->awayviewaiming); else if (fastcmp(field,"spectator")) lua_pushinteger(L, plr->spectator); else if (fastcmp(field,"bot")) @@ -365,8 +365,6 @@ static int player_set(lua_State *L) else if (plr == &players[secondarydisplayplayer]) localaiming2 = plr->aiming; } - else if (fastcmp(field,"awayviewaiming")) - plr->awayviewaiming = (angle_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"health")) plr->health = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"pity")) @@ -424,17 +422,17 @@ static int player_set(lua_State *L) else if (fastcmp(field,"jumpfactor")) plr->jumpfactor = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"lives")) - plr->lives = (INT32)luaL_checkinteger(L, 3); + plr->lives = (SINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"continues")) - plr->continues = (INT32)luaL_checkinteger(L, 3); + plr->continues = (SINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"xtralife")) - plr->xtralife = (INT32)luaL_checkinteger(L, 3); + plr->xtralife = (SINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"gotcontinue")) plr->gotcontinue = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"speed")) plr->speed = (fixed_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"jumping")) - plr->jumping = (INT32)luaL_checkinteger(L, 3); + plr->jumping = luaL_checkboolean(L, 3); else if (fastcmp(field,"secondjump")) plr->secondjump = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"fly1")) @@ -462,13 +460,13 @@ static int player_set(lua_State *L) else if (fastcmp(field,"rmomy")) plr->rmomy = (fixed_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"numboxes")) - plr->numboxes = (INT32)luaL_checkinteger(L, 3); + plr->numboxes = (INT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"totalring")) - plr->totalring = (INT32)luaL_checkinteger(L, 3); + plr->totalring = (INT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"realtime")) plr->realtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"laps")) - plr->laps = (UINT32)luaL_checkinteger(L, 3); + plr->laps = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"ctfteam")) plr->ctfteam = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"gotflag")) @@ -567,6 +565,8 @@ static int player_set(lua_State *L) if (plr->awayviewtics && !plr->awayviewmobj) // awayviewtics must ALWAYS have an awayviewmobj set!! P_SetTarget(&plr->awayviewmobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now. } + else if (fastcmp(field,"awayviewaiming")) + plr->awayviewaiming = (angle_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"spectator")) plr->spectator = lua_toboolean(L, 3); else if (fastcmp(field,"bot")) diff --git a/src/m_cheat.c b/src/m_cheat.c index 44c6f03e..16bd88ad 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -464,9 +464,9 @@ void Command_Savecheckpoint_f(void) // Like M_GetAllEmeralds() but for console devmode junkies. void Command_Getallemeralds_f(void) { - REQUIRE_PANDORA; REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; + REQUIRE_PANDORA; emeralds = ((EMERALD7)*2)-1; @@ -475,8 +475,8 @@ void Command_Getallemeralds_f(void) void Command_Resetemeralds_f(void) { - REQUIRE_PANDORA; REQUIRE_SINGLEPLAYER; + REQUIRE_PANDORA; emeralds = 0; @@ -511,10 +511,10 @@ void Command_Devmode_f(void) void Command_Setrings_f(void) { - REQUIRE_PANDORA; REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; + REQUIRE_PANDORA; if (COM_Argc() > 1) { @@ -530,10 +530,10 @@ void Command_Setrings_f(void) void Command_Setlives_f(void) { - REQUIRE_PANDORA; REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; + REQUIRE_PANDORA; if (COM_Argc() > 1) { @@ -547,10 +547,10 @@ void Command_Setlives_f(void) void Command_Setcontinues_f(void) { - REQUIRE_PANDORA; REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; + REQUIRE_PANDORA; if (COM_Argc() > 1) { diff --git a/src/m_menu.c b/src/m_menu.c index 5aad4e77..30876cbc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1037,6 +1037,10 @@ static menuitem_t OP_CameraControlsMenu[] = static menuitem_t OP_MiscControlsMenu[] = { + {IT_CALL | IT_STRING2, NULL, "Custom Action 1", M_ChangeControl, gc_custom1 }, + {IT_CALL | IT_STRING2, NULL, "Custom Action 2", M_ChangeControl, gc_custom2 }, + {IT_CALL | IT_STRING2, NULL, "Custom Action 3", M_ChangeControl, gc_custom3 }, + {IT_CALL | IT_STRING2, NULL, "Pause", M_ChangeControl, gc_pause }, {IT_CALL | IT_STRING2, NULL, "Console", M_ChangeControl, gc_console }, }; @@ -1137,8 +1141,6 @@ static menuitem_t OP_OpenGLOptionsMenu[] = #ifdef _WINDOWS {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 50}, #endif - {IT_STRING|IT_CVAR|IT_CV_SLIDER, - NULL, "Translucent HUD", &cv_grtranslucenthud, 60}, #ifdef ALAM_LIGHTING {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 70}, #endif @@ -1245,17 +1247,19 @@ static menuitem_t OP_GameOptionsMenu[] = NULL, "Master server", &cv_masterserver, 10}, #endif {IT_STRING | IT_CVAR, NULL, "Show HUD", &cv_showhud, 40}, - {IT_STRING | IT_CVAR, NULL, "Timer Display", &cv_timetic, 50}, + {IT_STRING | IT_CVAR | IT_CV_SLIDER, + NULL, "HUD Visibility", &cv_translucenthud, 50}, + {IT_STRING | IT_CVAR, NULL, "Timer Display", &cv_timetic, 60}, #ifdef SEENAMES - {IT_STRING | IT_CVAR, NULL, "HUD Player Names", &cv_seenames, 60}, + {IT_STRING | IT_CVAR, NULL, "HUD Player Names", &cv_seenames, 80}, #endif - {IT_STRING | IT_CVAR, NULL, "Log Hazard Damage", &cv_hazardlog, 70}, + {IT_STRING | IT_CVAR, NULL, "Log Hazard Damage", &cv_hazardlog, 90}, - {IT_STRING | IT_CVAR, NULL, "Console Back Color", &cons_backcolor, 90}, - {IT_STRING | IT_CVAR, NULL, "Console Text Size", &cv_constextsize,100}, - {IT_STRING | IT_CVAR, NULL, "Uppercase Console", &cv_allcaps, 110}, + {IT_STRING | IT_CVAR, NULL, "Console Back Color", &cons_backcolor, 100}, + {IT_STRING | IT_CVAR, NULL, "Console Text Size", &cv_constextsize,110}, + {IT_STRING | IT_CVAR, NULL, "Uppercase Console", &cv_allcaps, 120}, - {IT_STRING | IT_CVAR, NULL, "Title Screen Demos", &cv_rollingdemos, 130}, + {IT_STRING | IT_CVAR, NULL, "Title Screen Demos", &cv_rollingdemos, 140}, }; static menuitem_t OP_ServerOptionsMenu[] = @@ -1276,7 +1280,7 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 110}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 120}, {IT_STRING | IT_CVAR, NULL, "Allow WAD Downloading", &cv_downloading, 130}, - {IT_STRING | IT_CVAR, NULL, "Consistency Protection", &cv_consfailprotect, 140}, + {IT_STRING | IT_CVAR, NULL, "Attempts to Resynch", &cv_resynchattempts, 140}, #endif }; @@ -3764,8 +3768,8 @@ static void M_Options(INT32 choice) // if the player is not admin or server, disable server options OP_MainMenu[5].status = (Playing() && !(server || adminplayer == consoleplayer)) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); - // if the player is playing _at all_, disable data options - OP_MainMenu[3].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + // if the player is playing _at all_, disable the erase data options + OP_DataOptionsMenu[1].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_MainDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_MainDef); @@ -4681,9 +4685,9 @@ static void M_DrawSetupChoosePlayerMenu(void) } patch = W_CachePatchName(picname, PU_CACHE); if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<height) - 64 + o*2, SHORT(patch->width), SHORT(patch->height)); + V_DrawCroppedPatch(8<height) - 64 + o*2, SHORT(patch->width), SHORT(patch->height)); else - V_DrawCroppedPatch(8<height) - 32 + o, SHORT(patch->width), SHORT(patch->height)); + V_DrawCroppedPatch(8<height) - 32 + o, SHORT(patch->width), SHORT(patch->height)); W_UnlockCachedPatch(patch); } @@ -4707,9 +4711,9 @@ static void M_DrawSetupChoosePlayerMenu(void) } patch = W_CachePatchName(picname, PU_CACHE); if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), o*2); + V_DrawCroppedPatch(8<width), o*2); else - V_DrawCroppedPatch(8<width), o); + V_DrawCroppedPatch(8<width), o); W_UnlockCachedPatch(patch); } @@ -4741,9 +4745,9 @@ static void M_DrawSetupChoosePlayerMenu(void) else { if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), SHORT(patch->height)); + V_DrawCroppedPatch(8<width), SHORT(patch->height)); else - V_DrawCroppedPatch(8<width), SHORT(patch->height)); + V_DrawCroppedPatch(8<width), SHORT(patch->height)); } W_UnlockCachedPatch(patch); } @@ -5709,7 +5713,7 @@ static void M_DrawConnectMenu(void) // Room name if (ms_RoomId < 0) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey, - V_YELLOWMAP, ""); + V_YELLOWMAP, (itemOn == mp_connect_room) ? "" : ""); else V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_YELLOWMAP, room_list[menuRoomIndex].name); @@ -6560,8 +6566,9 @@ static void M_Setup1PControlsMenu(INT32 choice) OP_MPControlsMenu[0].status = IT_CALL|IT_STRING2; OP_MPControlsMenu[1].status = IT_CALL|IT_STRING2; OP_MPControlsMenu[2].status = IT_CALL|IT_STRING2; - // Unhide the entire misc menu - OP_ControlListMenu[3].status = IT_SUBMENU | IT_STRING; + // Unide the pause/console controls too + OP_MiscControlsMenu[3].status = IT_CALL|IT_STRING2; + OP_MiscControlsMenu[4].status = IT_CALL|IT_STRING2; OP_ControlListDef.prevMenu = &OP_P1ControlsDef; M_SetupNextMenu(&OP_ControlListDef); @@ -6578,8 +6585,9 @@ static void M_Setup2PControlsMenu(INT32 choice) OP_MPControlsMenu[0].status = IT_GRAYEDOUT2; OP_MPControlsMenu[1].status = IT_GRAYEDOUT2; OP_MPControlsMenu[2].status = IT_GRAYEDOUT2; - // Hide the entire misc menu - OP_ControlListMenu[3].status = IT_GRAYEDOUT; + // Hide the pause/console controls too + OP_MiscControlsMenu[3].status = IT_GRAYEDOUT2; + OP_MiscControlsMenu[4].status = IT_GRAYEDOUT2; OP_ControlListDef.prevMenu = &OP_P2ControlsDef; M_SetupNextMenu(&OP_ControlListDef); diff --git a/src/p_inter.c b/src/p_inter.c index 03ad7c46..398ad493 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1861,7 +1861,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) if (target->player && !target->player->spectator) { if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording! - G_CheckDemoStatus(); + G_StopMetalRecording(); #ifdef CHAOSISNOTDEADYET if (gametype == GT_CHAOS) target->player->score /= 2; // Halve the player's score in Chaos Mode diff --git a/src/p_map.c b/src/p_map.c index 8b7869b8..eb7c6ad7 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2552,7 +2552,7 @@ static boolean PTR_SlideTraverse(intercept_t *in) // one-sided linedef if (!li->backsector) { - if (P_PointOnLineSide(mapcampointer->x, mapcampointer->y, li)) + if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) return true; // don't hit the back side goto isblocking; } diff --git a/src/p_mobj.c b/src/p_mobj.c index b973c6cc..a7dc363f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1669,16 +1669,21 @@ static boolean P_ZMovement(mobj_t *mo) // another to prevent them from turning into hockey pucks. // I'm sorry in advance. -SH // PS: Oh, and Brak's napalm bombs too, now. - if (mo->type == MT_THROWNGRENADE || mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE) + if (mo->flags & MF_GRENADEBOUNCE) { - if (mo->momz <= 0) + // Going down? (Or up in reverse gravity?) + if (mo->momz*P_MobjFlip(mo) < 0) { - if (mo->momz >= -FixedMul(FRACUNIT, mo->scale)) + // If going slower than a fracunit, just stop. + if (abs(mo->momz) < FixedMul(FRACUNIT, mo->scale)) { mo->momx = mo->momy = mo->momz = 0; - if (mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE) - P_SetMobjState(mo, mo->info->deathstate); + + // Napalm hack + if (mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE && mo->fuse) + mo->fuse = 1; } + // Otherwise bounce up at half speed. else mo->momz = -FixedMul(mo->momz, FRACUNIT/2); S_StartSound(mo, mo->info->activesound); @@ -4595,7 +4600,7 @@ static void P_Boss9Thinker(mobj_t *mobj) // This is below threshold because we don't want to bob while zipping around // Ohh you're in for it now.. - if (mobj->flags2 & MF2_FRET && mobj->health <= 3) + if (mobj->flags2 & MF2_FRET && mobj->health <= mobj->info->damage) mobj->fuse = 0; // reactiontime is used for delays. @@ -4657,11 +4662,13 @@ static void P_Boss9Thinker(mobj_t *mobj) case 1: { // Okay, we're up? Good, time to gather energy... - if (mobj->health > mobj->info->damage) { // No more bubble if we're broken (pinch phase) + if (mobj->health > mobj->info->damage) + { // No more bubble if we're broken (pinch phase) mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); P_SetTarget(&mobj->tracer, shield); P_SetTarget(&shield->target, mobj); - } else + } + else P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); mobj->fuse = 4*TICRATE; mobj->flags |= MF_PAIN; @@ -4673,8 +4680,12 @@ static void P_Boss9Thinker(mobj_t *mobj) case 2: // We're all charged and ready now! Unleash the fury!! - P_RemoveMobj(mobj->tracer); - P_SetTarget(&mobj->tracer, mobj->hnext); + if (mobj->health > mobj->info->damage) + { + mobj_t *removemobj = mobj->tracer; + P_SetTarget(&mobj->tracer, mobj->hnext); + P_RemoveMobj(removemobj); + } if (mobj->health <= mobj->info->damage) { // Attack 1: Pinball dash! if (mobj->health == 1) @@ -6483,6 +6494,7 @@ void P_MobjThinker(mobj_t *mobj) { // gargoyle and snowman handled in P_PushableThinker, not here case MT_THROWNGRENADE: + case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: P_SetMobjState(mobj, mobj->info->deathstate); break; case MT_BLUEFLAG: @@ -7231,6 +7243,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) #endif switch (mobj->type) { + case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: + mobj->fuse = mobj->info->mass; case MT_BLACKEGGMAN: { mobj_t *spawn = P_SpawnMobj(mobj->x, mobj->z, mobj->z+mobj->height-16*FRACUNIT, MT_BLACKEGGMAN_HELPER); @@ -9445,7 +9459,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) boolean P_CheckMissileSpawn(mobj_t *th) { // move a little forward so an angle can be computed if it immediately explodes - if (th->type != MT_THROWNGRENADE) // hack: bad! should be a flag. + if (th->flags & MF_GRENADEBOUNCE) // hack: bad! should be a flag. { th->x += th->momx>>1; th->y += th->momy>>1; diff --git a/src/p_mobj.h b/src/p_mobj.h index 84d22301..6d120c47 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -156,9 +156,11 @@ typedef enum // for chase camera, don't be blocked by things (partial clipping) // (need comma at end of this for SOC editor) MF_NOCLIPTHING = 1<<27, + // Missile bounces like a grenade. + MF_GRENADEBOUNCE = 1<<28, // Run the action thinker on spawn. - MF_RUNSPAWNFUNC = 1<<28, - // free: to and including 1<<31 + MF_RUNSPAWNFUNC = 1<<29, + // free: 1<<30 and 1<<31 } mobjflag_t; typedef enum diff --git a/src/p_saveg.c b/src/p_saveg.c index 17db0062..baa04211 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -120,6 +120,13 @@ static inline void P_NetArchivePlayers(void) flags = 0; + // ticcmd write + WRITESINT8(save_p, players[i].cmd.forwardmove); + WRITESINT8(save_p, players[i].cmd.sidemove); + WRITEINT16(save_p, players[i].cmd.angleturn); + WRITEINT16(save_p, players[i].cmd.aiming); + WRITEUINT16(save_p, players[i].cmd.buttons); + WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); WRITEANGLE(save_p, players[i].aiming); WRITEANGLE(save_p, players[i].awayviewaiming); @@ -146,12 +153,12 @@ static inline void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].score); WRITEINT32(save_p, players[i].dashspeed); WRITEINT32(save_p, players[i].dashtime); - WRITEINT32(save_p, players[i].lives); - WRITEINT32(save_p, players[i].continues); - WRITEINT32(save_p, players[i].xtralife); + WRITESINT8(save_p, players[i].lives); + WRITESINT8(save_p, players[i].continues); + WRITESINT8(save_p, players[i].xtralife); WRITEUINT8(save_p, players[i].gotcontinue); WRITEINT32(save_p, players[i].speed); - WRITEINT32(save_p, players[i].jumping); + WRITEUINT8(save_p, players[i].jumping); WRITEUINT8(save_p, players[i].secondjump); WRITEUINT8(save_p, players[i].fly1); WRITEUINT8(save_p, players[i].scoreadd); @@ -176,7 +183,7 @@ static inline void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].numboxes); WRITEINT32(save_p, players[i].totalring); WRITEUINT32(save_p, players[i].realtime); - WRITEUINT32(save_p, players[i].laps); + WRITEUINT8(save_p, players[i].laps); //////////////////// // CTF Mode Stuff // @@ -282,6 +289,7 @@ static inline void P_NetUnArchivePlayers(void) { INT32 i, j; UINT16 flags; + ticcmd_t tmptic; if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS) I_Error("Bad $$$.sav at archive block Players"); @@ -292,6 +300,14 @@ static inline void P_NetUnArchivePlayers(void) if (!playeringame[i]) continue; + memset(&tmptic, 0, sizeof(ticcmd_t)); + tmptic.forwardmove = READSINT8(save_p); + tmptic.sidemove = READSINT8(save_p); + tmptic.angleturn = READINT16(save_p); + tmptic.aiming = READINT16(save_p); + tmptic.buttons = READUINT16(save_p); + G_CopyTiccmd(&players[i].cmd, &tmptic, 1); + READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); players[i].aiming = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p); @@ -318,12 +334,12 @@ static inline void P_NetUnArchivePlayers(void) players[i].score = READUINT32(save_p); players[i].dashspeed = READINT32(save_p); // dashing speed players[i].dashtime = READINT32(save_p); // dashing speed - players[i].lives = READINT32(save_p); - players[i].continues = READINT32(save_p); // continues that player has acquired - players[i].xtralife = READINT32(save_p); // Ring Extra Life counter + players[i].lives = READSINT8(save_p); + players[i].continues = READSINT8(save_p); // continues that player has acquired + players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter players[i].gotcontinue = READUINT8(save_p); // got continue from stage players[i].speed = READINT32(save_p); // Player's speed (distance formula of MOMX and MOMY values) - players[i].jumping = READINT32(save_p); // Jump counter + players[i].jumping = READUINT8(save_p); // Jump counter players[i].secondjump = READUINT8(save_p); players[i].fly1 = READUINT8(save_p); // Tails flying players[i].scoreadd = READUINT8(save_p); // Used for multiple enemy attack bonus @@ -348,7 +364,7 @@ static inline void P_NetUnArchivePlayers(void) players[i].numboxes = READINT32(save_p); // Number of item boxes obtained for Race Mode players[i].totalring = READINT32(save_p); // Total number of rings obtained for Race Mode players[i].realtime = READUINT32(save_p); // integer replacement for leveltime - players[i].laps = READUINT32(save_p); // Number of laps (optional) + players[i].laps = READUINT8(save_p); // Number of laps (optional) //////////////////// // CTF Mode Stuff // diff --git a/src/p_setup.c b/src/p_setup.c index 25bcd0d5..9b32d4a0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2315,7 +2315,7 @@ boolean P_SetupLevel(boolean skipprecip) cv_debug = botskin = 0; if (metalplayback) - G_StopDemo(); + G_StopMetalDemo(); // Clear CECHO messages HU_ClearCEcho(); diff --git a/src/p_spec.c b/src/p_spec.c index 20d86176..fa6200cd 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3854,10 +3854,10 @@ DoneSection2: if (player->pflags & PF_NIGHTSMODE) player->drillmeter += 48*20; - if (player->laps >= (unsigned)cv_numlaps.value) + if (player->laps >= (UINT8)cv_numlaps.value) CONS_Printf(M_GetText("%s has finished the race.\n"), player_names[player-players]); else - CONS_Printf(M_GetText("%s started lap %d\n"), player_names[player-players],player->laps+1); + CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); // Reset starposts (checkpoints) info player->starpostangle = player->starposttime = player->starpostnum = 0; @@ -5342,10 +5342,14 @@ void P_SpawnSpecials(INT32 fromnetsave) if (lines[i].special == 6) { // Ability flags can disable disable linedefs now, lol - if ((netgame || multiplayer) - || (!(players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) - && !(players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) - && !(players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)))) + if (netgame || multiplayer) + { + // future: nonet flag? + } + else if (((lines[i].flags & ML_NETONLY) != ML_NETONLY) + && !(players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + && !(players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) + && !(players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX ))) { for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;) { @@ -5404,7 +5408,16 @@ void P_SpawnSpecials(INT32 fromnetsave) for (i = 0; i < numlines; i++) { // set line specials to 0 here too, same reason as above - if (!(netgame || multiplayer)) + if (netgame || multiplayer) + { + // future: nonet flag? + } + else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) + { + lines[i].special = 0; + continue; + } + else { if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) { diff --git a/src/p_user.c b/src/p_user.c index 5aa0d50a..d5c17e00 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3178,12 +3178,26 @@ static void P_DoSuperStuff(player_t *player) P_SetPlayerMobjState(player->mo, S_PLAY_STND); P_RestoreMusic(player); P_SpawnShieldOrb(player); + + // Restore color + if (player->powers[pw_shield] & SH_FIREFLOWER) + { + player->mo->color = SKINCOLOR_WHITE; + G_GhostAddColor(GHC_FIREFLOWER); + } + else + { + player->mo->color = player->skincolor; + G_GhostAddColor(GHC_NORMAL); + } + if (gametype != GT_COOP) { HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players])); } + return; } // Deplete one ring every second while super @@ -3200,7 +3214,7 @@ static void P_DoSuperStuff(player_t *player) G_GhostAddColor(GHC_SUPER); // Ran out of rings while super! - if ((player->powers[pw_super]) && (player->health <= 1 || player->exiting)) + if (player->powers[pw_super] && (player->health <= 1 || player->exiting)) { player->powers[pw_emeralds] = 0; // lost the power stones P_SpawnGhostMobj(player->mo); @@ -8113,19 +8127,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall + ((*rover->topheight - *rover->bottomheight)/2)); delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - if (*rover->topheight > tmfloorz && abs(delta1) < abs(delta2)) - { + if (*rover->topheight > myfloorz && abs(delta1) < abs(delta2)) myfloorz = *rover->topheight; - } - if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2)) - { + if (*rover->bottomheight < myceilingz && abs(delta1) >= abs(delta2)) myceilingz = *rover->bottomheight; - } } } #ifdef POLYOBJECTS - // Check polyobjects and see if tmfloorz/tmceilingz need to be altered + // Check polyobjects and see if floorz/ceilingz need to be altered { INT32 xl, xh, yl, yh, bx, by; validcount++; @@ -8191,10 +8201,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall delta1 = midz - (polybottom + ((polytop - polybottom)/2)); delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - if (polytop > tmfloorz && abs(delta1) < abs(delta2)) + if (polytop > myfloorz && abs(delta1) < abs(delta2)) myfloorz = polytop; - if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) + if (polybottom < myceilingz && abs(delta1) >= abs(delta2)) myceilingz = polybottom; } plink = (polymaplink_t *)(plink->link.next); @@ -8204,7 +8214,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall #endif // crushed camera - if (myceilingz <= myfloorz && !resetcalled && !cameranoclip) + if (myceilingz <= myfloorz + thiscam->height && !resetcalled && !cameranoclip) { P_ResetCamera(player, thiscam); return true; @@ -8645,7 +8655,7 @@ void P_PlayerThink(player_t *player) if (players[i].lives <= 0) continue; - if (!players[i].exiting) + if (!players[i].exiting || players[i].exiting > 3) break; } @@ -9198,7 +9208,7 @@ void P_PlayerAfterThink(player_t *player) } } } - else if ((player->pflags & PF_MACESPIN) && player->mo->tracer) + else if ((player->pflags & PF_MACESPIN) && player->mo->tracer && player->mo->tracer->target) { player->mo->height = P_GetPlayerSpinHeight(player); // tracer is what you're hanging onto.... @@ -9218,11 +9228,6 @@ void P_PlayerAfterThink(player_t *player) if (!(player->mo->tracer->target->flags & MF_SLIDEME) // Noclimb on chain parameters gives this && !(twodlevel || player->mo->flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode? { - if (cmd->buttons & BT_USE) // do we actually still want this? - { - player->mo->tracer->target->health += 50; - player->mo->angle += 50< ANGLE_MAX - } player->mo->tracer->target->health += cmd->sidemove; player->mo->angle += cmd->sidemove< ANGLE_MAX diff --git a/src/r_main.c b/src/r_main.c index 10228c29..6af1bf46 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -122,7 +122,7 @@ static CV_PossibleValue_t drawdist_cons_t[] = { {3072, "3072"}, {4096, "4096"}, {6144, "6144"}, {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; static CV_PossibleValue_t precipdensity_cons_t[] = {{0, "None"}, {1, "Light"}, {2, "Moderate"}, {4, "Heavy"}, {6, "Thick"}, {8, "V.Thick"}, {0, NULL}}; -static CV_PossibleValue_t grtranslucenthud_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}}; static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}}; static void ChaseCam_OnChange(void); @@ -141,7 +141,7 @@ consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0 consvar_t cv_soniccd = {"soniccd", "Off", CV_NETVAR, 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}; -consvar_t cv_grtranslucenthud = {"gr_translucenthud", "255", CV_SAVE|CV_CALL, grtranslucenthud_cons_t, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -732,7 +732,7 @@ static mobj_t *viewmobj; // WARNING: a should be unsigned but to add with 2048, it isn't! #define AIMINGTODY(a) ((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)>>FRACBITS) -static void R_SkyboxFrame(player_t *player) +void R_SkyboxFrame(player_t *player) { INT32 dy = 0; camera_t *thiscam; @@ -1237,11 +1237,11 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_cam2_rotspeed); CV_RegisterVar(&cv_showhud); + CV_RegisterVar(&cv_translucenthud); // Default viewheight is changeable, // initialized to standard viewheight CV_RegisterVar(&cv_viewheight); - CV_RegisterVar(&cv_grtranslucenthud); #ifdef HWRENDER // GL-specific Commands diff --git a/src/r_main.h b/src/r_main.h index a6387bbc..a367960c 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -81,9 +81,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y); // REFRESH - the actual rendering functions. // -extern consvar_t cv_showhud; +extern consvar_t cv_showhud, cv_translucenthud; extern consvar_t cv_homremoval; -extern consvar_t cv_grtranslucenthud; extern consvar_t cv_chasecam, cv_chasecam2; extern consvar_t cv_flipcam, cv_flipcam2; extern consvar_t cv_shadow, cv_shadowoffs; @@ -101,6 +100,8 @@ void R_SetViewSize(void); // do it (sometimes explicitly called) void R_ExecuteSetViewSize(void); +void R_SkyboxFrame(player_t *player); + void R_SetupFrame(player_t *player, boolean skybox); // Called by G_Drawer. void R_RenderPlayerView(player_t *player); diff --git a/src/screen.c b/src/screen.c index 666f2e1e..08505606 100644 --- a/src/screen.c +++ b/src/screen.c @@ -227,7 +227,11 @@ void SCR_Startup(void) vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); - vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); + +#ifdef HWRENDER + if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions, not sure if it does anything in software +#endif + vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; @@ -269,7 +273,12 @@ void SCR_Recalc(void) vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); - vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); + +#ifdef HWRENDER + if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions, not sure if it does anything in software +#endif + vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); + //vid.baseratio = FixedDiv(vid.height << FRACBITS, BASEVIDHEIGHT << FRACBITS); vid.baseratio = FRACUNIT; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 9c0f521f..1e03edd8 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2278,8 +2278,12 @@ void I_Quit(void) G_SaveGameData(); // Tails 12-08-2002 //added:16-02-98: when recording a demo, should exit using 'q' key, // but sometimes we forget and use 'F10'.. so save here too. - if (demorecording || metalrecording) + + if (demorecording) G_CheckDemoStatus(); + if (metalrecording) + G_StopMetalRecording(); + D_QuitNetGame(); I_ShutdownMusic(); I_ShutdownSound(); @@ -2431,8 +2435,10 @@ void I_Error(const char *error, ...) G_SaveGameData(); // Tails 12-08-2002 // Shutdown. Here might be other errors. - if (demorecording || metalrecording) + if (demorecording) G_CheckDemoStatus(); + if (metalrecording) + G_StopMetalRecording(); D_QuitNetGame(); I_ShutdownMusic(); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 71c81364..1a2305fe 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1577,6 +1577,7 @@ const char *VID_GetModeName(INT32 modeNum) INT32 VID_GetModeForSize(INT32 w, INT32 h) { INT32 matchMode = -1, i; + VID_PrepareModeList(); if (USE_FULLSCREEN && numVidModes != -1) { for (i=firstEntry; iwidth); - const UINT8 *colormap; - - if (colornum == 0) - colormap = colormaps; - else // Uses the player colors. - colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE); - - I_Assert(num >= 0); // this function does not draw negative numbers - - // draw the number - do - { - x -= (w * vid.dupx); - V_DrawMappedPatch(x, y, V_NOSCALESTART|V_TRANSLUCENT, numpat[num % 10], colormap); - num /= 10; - } while (num); - - // Sorry chum, this function only draws UNSIGNED values! -} - -// Draw a number, scaled, over the view, with set translucency -// Always draw the number completely since it's overlay -// -// Supports different colors! woo! -static void ST_DrawTranslucentNightsOverlayNum(INT32 x /* right border */, INT32 y, INT32 a, +static void ST_DrawNightsOverlayNum(INT32 x /* right border */, INT32 y, INT32 a, INT32 num, patch_t **numpat, skincolors_t colornum) { INT32 w = SHORT(numpat[0]->width); @@ -603,16 +590,16 @@ static void ST_drawDebugInfo(void) static void ST_drawScore(void) { // SCORE: - V_DrawScaledPatch(SCX(hudinfo[HUD_SCORE].x), SCY(hudinfo[HUD_SCORE].y), V_NOSCALESTART|V_TRANSLUCENT, sboscore); + ST_DrawPatchFromHud(HUD_SCORE, sboscore); if (objectplacing) { if (op_displayflags > UINT16_MAX) - V_DrawScaledPatch(SCX(hudinfo[HUD_SCORENUM].x-tallminus->width), SCY(hudinfo[HUD_SCORENUM].y), V_NOSCALESTART, tallminus); + ST_DrawOverlayPatch(SCX(hudinfo[HUD_SCORENUM].x-tallminus->width), SCY(hudinfo[HUD_SCORENUM].y), tallminus); else - ST_DrawOverlayNum(SCX(hudinfo[HUD_SCORENUM].x), SCY(hudinfo[HUD_SCORENUM].y), V_NOSCALESTART, op_displayflags); + ST_DrawNumFromHud(HUD_SCORENUM, op_displayflags); } else - ST_DrawOverlayNum(SCX(hudinfo[HUD_SCORENUM].x), SCY(hudinfo[HUD_SCORENUM].y), V_NOSCALESTART, stplyr->score); + ST_DrawNumFromHud(HUD_SCORENUM, stplyr->score); } static void ST_drawTime(void) @@ -620,8 +607,7 @@ static void ST_drawTime(void) INT32 seconds, minutes, tictrn, tics; // TIME: - V_DrawScaledPatch(SCX(hudinfo[(splitscreen) ? HUD_TIMESPLIT : HUD_TIME].x), - SCY(hudinfo[(splitscreen) ? HUD_TIMESPLIT : HUD_TIME].y), V_NOSCALESTART|V_TRANSLUCENT, sbotime); + ST_DrawPatchFromHudWS(HUD_TIME, sbotime); if (objectplacing) { @@ -633,61 +619,45 @@ static void ST_drawTime(void) else { tics = stplyr->realtime; - seconds = tics/TICRATE % 60; - minutes = tics/(60*TICRATE); + seconds = G_TicsToSeconds(tics); + minutes = G_TicsToMinutes(tics, true); tictrn = G_TicsToCentiseconds(tics); } if (cv_timetic.value == 1) // Tics only -- how simple is this? - ST_DrawOverlayNum(SCX(hudinfo[(splitscreen) ? HUD_SECONDSSPLIT : HUD_SECONDS].x), - SCY(hudinfo[(splitscreen) ? HUD_SECONDSSPLIT : HUD_SECONDS].y), V_NOSCALESTART, tics); + ST_DrawNumFromHudWS(HUD_SECONDS, tics); else { - // Minutes - ST_DrawOverlayNum(SCX(hudinfo[(splitscreen) ? HUD_MINUTESSPLIT : HUD_MINUTES].x), - SCY(hudinfo[(splitscreen) ? HUD_MINUTESSPLIT : HUD_MINUTES].y), V_NOSCALESTART, minutes); - // Colon - V_DrawScaledPatch(SCX(hudinfo[(splitscreen) ? HUD_TIMECOLONSPLIT : HUD_TIMECOLON].x), - SCY(hudinfo[(splitscreen) ? HUD_TIMECOLONSPLIT : HUD_TIMECOLON].y), V_NOSCALESTART|V_TRANSLUCENT, sbocolon); - // Seconds - ST_DrawPaddedOverlayNum(SCX(hudinfo[(splitscreen) ? HUD_SECONDSSPLIT : HUD_SECONDS].x), - SCY(hudinfo[(splitscreen) ? HUD_SECONDSSPLIT : HUD_SECONDS].y), seconds, 2); + ST_DrawNumFromHudWS(HUD_MINUTES, minutes); // Minutes + ST_DrawPatchFromHudWS(HUD_TIMECOLON, sbocolon); // Colon + ST_DrawPadNumFromHudWS(HUD_SECONDS, seconds, 2); // Seconds if (!splitscreen && (cv_timetic.value == 2 || modeattacking)) // there's not enough room for tics in splitscreen, don't even bother trying! { - // Colon - V_DrawScaledPatch(SCX(hudinfo[HUD_TIMETICCOLON].x), SCY(hudinfo[HUD_TIMETICCOLON].y), V_NOSCALESTART|V_TRANSLUCENT, sbocolon); - // Tics - ST_DrawPaddedOverlayNum(SCX(hudinfo[HUD_TICS].x), SCY(hudinfo[HUD_TICS].y), tictrn, 2); + ST_DrawPatchFromHud(HUD_TIMETICCOLON, sbocolon); // Colon + ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics } } } static inline void ST_drawRings(void) { - hudnum_t ringHUD = (splitscreen) ? HUD_RINGSSPLIT : HUD_RINGS; - hudnum_t ringnumHUD = (splitscreen) ? HUD_RINGSNUMSPLIT : HUD_RINGSNUM; + INT32 ringnum = max(stplyr->health-1, 0); - V_DrawScaledPatch(SCX(hudinfo[ringHUD].x), SCY(hudinfo[ringHUD].y), V_NOSCALESTART|V_TRANSLUCENT, - (stplyr->health <= 1 && leveltime/5 & 1) ? rrings : sborings); + ST_DrawPatchFromHudWS(HUD_RINGS, ((stplyr->health <= 1 && leveltime/5 & 1) ? rrings : sborings)); if (objectplacing) - { - ST_DrawOverlayNum(SCX(hudinfo[ringnumHUD].x), SCY(hudinfo[ringnumHUD].y), V_NOSCALESTART, op_currentdoomednum); - } + ringnum = op_currentdoomednum; else if (!useNightsSS && G_IsSpecialStage(gamemap)) { - INT32 ringscollected = 0; // Total # everyone has collected INT32 i; - + ringnum = 0; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && players[i].mo->health > 1) - ringscollected += players[i].mo->health - 1; - - ST_DrawOverlayNum(SCX(hudinfo[ringnumHUD].x), SCY(hudinfo[ringnumHUD].y), V_NOSCALESTART, ringscollected); + ringnum += players[i].mo->health - 1; } - else - ST_DrawOverlayNum(SCX(hudinfo[ringnumHUD].x), SCY(hudinfo[ringnumHUD].y), V_NOSCALESTART, stplyr->health > 0 ? stplyr->health-1 : 0); + + ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum); } static void ST_drawLives(void) @@ -699,7 +669,7 @@ static void ST_drawLives(void) // face background V_DrawSmallScaledPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT|v_splitflag, livesback); + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, livesback); // face if (stplyr->mo && stplyr->mo->color) @@ -710,25 +680,29 @@ static void ST_drawLives(void) if (stplyr->powers[pw_super] || stplyr->pflags & PF_NIGHTSMODE) face = superprefix[stplyr->skin]; V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT|v_splitflag,face, colormap); + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,face, colormap); } else if (stplyr->skincolor) { // skincolor face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT|v_splitflag,faceprefix[stplyr->skin], colormap); + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,faceprefix[stplyr->skin], colormap); } // name if (strlen(skins[stplyr->skin].hudname) > 8) - V_DrawThinString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); + V_DrawThinString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), + V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); else - V_DrawString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); + V_DrawString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), + V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); // x - V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, hudinfo[HUD_LIVESX].y + (v_splitflag ? -4 : 0), V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT|v_splitflag, stlivex); + V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, hudinfo[HUD_LIVESX].y + (v_splitflag ? -4 : 0), + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, stlivex); // lives - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), V_SNAPTOLEFT|V_SNAPTOBOTTOM|v_splitflag, va("%d",stplyr->lives)); + V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, va("%d",stplyr->lives)); } static void ST_drawLevelTitle(void) @@ -820,9 +794,9 @@ static void ST_drawFirstPersonHUD(void) if (p) { if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24), V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, p); + V_DrawSmallScaledPatch(312, STRINGY(24), V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); else - V_DrawScaledPatch(304, 24, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, p); + V_DrawScaledPatch(304, 24, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); } // pw_flashing just sets the icon to flash no matter what. @@ -830,17 +804,17 @@ static void ST_drawFirstPersonHUD(void) if (invulntime > 3*TICRATE || (invulntime && leveltime & 1)) { if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24) + 14, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, invincibility); + V_DrawSmallScaledPatch(312, STRINGY(24) + 14, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility); else - V_DrawScaledPatch(304, 24 + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, invincibility); + V_DrawScaledPatch(304, 24 + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility); } if (player->powers[pw_sneakers] > 3*TICRATE || (player->powers[pw_sneakers] && leveltime & 1)) { if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24) + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, sneakers); + V_DrawSmallScaledPatch(312, STRINGY(24) + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers); else - V_DrawScaledPatch(304, 24 + 56, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, sneakers); + V_DrawScaledPatch(304, 24 + 56, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers); } p = NULL; @@ -890,8 +864,8 @@ static void ST_drawFirstPersonHUD(void) } if (p) - V_DrawTranslucentPatch(SCX((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset)), SCY(60 - SHORT(p->topoffset)), - V_NOSCALESTART|V_OFFSET, p); + V_DrawScaledPatch(SCX((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset)), SCY(60 - SHORT(p->topoffset)), + V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, p); } // [21:42] <+Rob> Beige - Lavender - Steel Blue - Peach - Orange - Purple - Silver - Yellow - Pink - Red - Blue - Green - Cyan - Gold @@ -946,11 +920,7 @@ static void ST_drawNightsRecords(void) V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(148), aflag, "BONUS:"); V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(140), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings)); V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(148), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50)); - - if (aflag) - ST_DrawTranslucentNightsOverlayNum(SCX(BASEVIDWIDTH/2 + 48), SCY(160), aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_STEELBLUE); - else - ST_DrawNightsOverlayNum(SCX(BASEVIDWIDTH/2 + 48), SCY(160), stplyr->lastmarescore, nightsnum, SKINCOLOR_STEELBLUE); + ST_DrawNightsOverlayNum(SCX(BASEVIDWIDTH/2 + 48), SCY(160), aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_STEELBLUE); // If new record, say so! if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore) @@ -1012,15 +982,13 @@ static void ST_drawNiGHTSHUD(void) if (splitscreen) { - ST_DrawTranslucentNightsOverlayNum(SCX(256), SCY(160), linktrans, (stplyr->linkcount-1), - nightsnum, colornum); + ST_DrawNightsOverlayNum(SCX(256), SCY(160), linktrans, (stplyr->linkcount-1), nightsnum, colornum); V_DrawTranslucentMappedPatch(SCX(264), SCY(160), V_NOSCALESTART|linktrans, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } else { - ST_DrawTranslucentNightsOverlayNum(SCX(160), SCY(160), linktrans, (stplyr->linkcount-1), - nightsnum, colornum); + ST_DrawNightsOverlayNum(SCX(160), SCY(160), linktrans, (stplyr->linkcount-1), nightsnum, colornum); V_DrawTranslucentMappedPatch(SCX(168), SCY(160), V_NOSCALESTART|linktrans, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } @@ -1032,20 +1000,20 @@ static void ST_drawNiGHTSHUD(void) { INT32 offs = 10 - (stplyr->linktimer - (2*TICRATE - 9)); INT32 ghosttrans = offs << V_ALPHASHIFT; - ST_DrawTranslucentNightsOverlayNum(SCX(160), SCY(160)+(offs*2), ghosttrans, (stplyr->linkcount-2), + ST_DrawNightsOverlayNum(SCX(160), SCY(160)+(offs*2), ghosttrans, (stplyr->linkcount-2), nightsnum, colornum); } #endif if (splitscreen) { - ST_DrawNightsOverlayNum(SCX(256), SCY(160), (stplyr->linkcount-1), nightsnum, colornum); + ST_DrawNightsOverlayNum(SCX(256), SCY(160), 0, (stplyr->linkcount-1), nightsnum, colornum); V_DrawMappedPatch(SCX(264), SCY(160), V_NOSCALESTART, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } else { - ST_DrawNightsOverlayNum(SCX(160), SCY(160), (stplyr->linkcount-1), nightsnum, colornum); + ST_DrawNightsOverlayNum(SCX(160), SCY(160), 0, (stplyr->linkcount-1), nightsnum, colornum); V_DrawMappedPatch(SCX(168), SCY(160), V_NOSCALESTART, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } @@ -1086,32 +1054,32 @@ static void ST_drawNiGHTSHUD(void) if (splitscreen) { // Dirty hack because V_SNAPTOBOTTOM doesn't have a way to account for splitscreen, but better than overlapping bars. - V_DrawScaledPatch(SCX(locx), SCY(locy), V_NOSCALESTART|V_TRANSLUCENT, drillbar); + V_DrawScaledPatch(SCX(locx), SCY(locy), V_NOSCALESTART|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(SCX(locx + 2 + dfill), SCY(locy + 3), V_NOSCALESTART|V_TRANSLUCENT, drillfill[fillpatch]); + V_DrawScaledPatch(SCX(locx + 2 + dfill), SCY(locy + 3), V_NOSCALESTART|V_HUDTRANS, drillfill[fillpatch]); } else if (nosshack) { // Even dirtier hack-of-a-hack to draw seperate drill meters in splitscreen special stages but nothing else. splitscreen = true; - V_DrawScaledPatch(SCX(locx), SCY(locy), V_NOSCALESTART|V_TRANSLUCENT, drillbar); + V_DrawScaledPatch(SCX(locx), SCY(locy), V_NOSCALESTART|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(SCX(locx + 2 + dfill), SCY(locy + 3), V_NOSCALESTART|V_TRANSLUCENT, drillfill[fillpatch]); + V_DrawScaledPatch(SCX(locx + 2 + dfill), SCY(locy + 3), V_NOSCALESTART|V_HUDTRANS, drillfill[fillpatch]); stplyr = &players[secondarydisplayplayer]; if (stplyr->pflags & PF_DRILLING) fillpatch = (stplyr->drillmeter & 1) + 1; else fillpatch = 0; - V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT, drillbar); + V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT, drillfill[fillpatch]); + V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); stplyr = &players[displayplayer]; splitscreen = false; } else { // Draw normally. <:3 - V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT, drillbar); + V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT, drillfill[fillpatch]); + V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); } // Display actual drill amount and bumper time @@ -1136,11 +1104,11 @@ static void ST_drawNiGHTSHUD(void) if (LUA_HudEnabled(hud_nightsrings)) { #endif - V_DrawScaledPatch(SCX(16), SCY(8), V_NOSCALESTART|V_TRANSLUCENT, nbracket); + ST_DrawOverlayPatch(SCX(16), SCY(8), nbracket); if (G_IsSpecialStage(gamemap)) - V_DrawScaledPatch(SCX(24), SCY(8) + SCZ(8), V_NOSCALESTART|V_TRANSLUCENT, nsshud); + ST_DrawOverlayPatch(SCX(24), SCY(8) + SCZ(8), nsshud); else - V_DrawScaledPatch(SCX(24), SCY(8) + SCZ(8), V_NOSCALESTART|V_TRANSLUCENT, nhud[(leveltime/2)%12]); + ST_DrawOverlayPatch(SCX(24), SCY(8) + SCZ(8), nhud[(leveltime/2)%12]); if (G_IsSpecialStage(gamemap)) { @@ -1161,8 +1129,8 @@ static void ST_drawNiGHTSHUD(void) origamount = stplyr->capsule->spawnpoint->angle; I_Assert(origamount > 0); // should not happen now - V_DrawScaledPatch(SCX(72), SCY(8), V_NOSCALESTART|V_TRANSLUCENT, nbracket); - V_DrawScaledPatch(SCX(74), SCY(8) + SCZ(4), V_NOSCALESTART|V_TRANSLUCENT, minicaps); + ST_DrawOverlayPatch(SCX(72), SCY(8), nbracket); + ST_DrawOverlayPatch(SCX(74), SCY(8) + SCZ(4), minicaps); if (stplyr->capsule->reactiontime != 0) { @@ -1171,10 +1139,10 @@ static void ST_drawNiGHTSHUD(void) for (r = 0; r < 5; r++) { - V_DrawScaledPatch(SCX(230 - (7*r)), SCY(144), V_NOSCALESTART|V_TRANSLUCENT, redstat); - V_DrawScaledPatch(SCX(188 - (7*r)), SCY(144), V_NOSCALESTART|V_TRANSLUCENT, orngstat); - V_DrawScaledPatch(SCX(146 - (7*r)), SCY(144), V_NOSCALESTART|V_TRANSLUCENT, yelstat); - V_DrawScaledPatch(SCX(104 - (7*r)), SCY(144), V_NOSCALESTART|V_TRANSLUCENT, byelstat); + ST_DrawOverlayPatch(SCX(230 - (7*r)), SCY(144), redstat); + ST_DrawOverlayPatch(SCX(188 - (7*r)), SCY(144), orngstat); + ST_DrawOverlayPatch(SCX(146 - (7*r)), SCY(144), yelstat); + ST_DrawOverlayPatch(SCX(104 - (7*r)), SCY(144), byelstat); } amount = (origamount - stplyr->capsule->health); @@ -1193,7 +1161,7 @@ static void ST_drawNiGHTSHUD(void) if (r > 10) ++t; if (r > 5) ++t; - V_DrawScaledPatch(SCX(69 + (7*t)), SCY(144), V_NOSCALESTART|V_TRANSLUCENT, bluestat); + ST_DrawOverlayPatch(SCX(69 + (7*t)), SCY(144), bluestat); } } } @@ -1202,27 +1170,27 @@ static void ST_drawNiGHTSHUD(void) INT32 cfill; // Lil' white box! - V_DrawScaledPatch(15, STRINGY(8) + 34, V_SNAPTOLEFT|V_SNAPTOTOP|V_TRANSLUCENT, capsulebar); + V_DrawScaledPatch(15, STRINGY(8) + 34, V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulebar); amount = (origamount - stplyr->capsule->health); amount = (amount * length)/origamount; for (cfill = 0; cfill < amount && cfill < 88; ++cfill) - V_DrawScaledPatch(15 + cfill + 1, STRINGY(8) + 35, V_SNAPTOLEFT|V_SNAPTOTOP|V_TRANSLUCENT, capsulefill); + V_DrawScaledPatch(15 + cfill + 1, STRINGY(8) + 35, V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill); } if (total_ringcount >= stplyr->capsule->health) - V_DrawScaledPatch(SCX(40), SCY(8) + SCZ(5), V_NOSCALESTART|V_TRANSLUCENT, nredar[leveltime%8]); + ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), nredar[leveltime%8]); else - V_DrawScaledPatch(SCX(40), SCY(8) + SCZ(5), V_NOSCALESTART|V_TRANSLUCENT, narrow[(leveltime/2)%8]); + ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), narrow[(leveltime/2)%8]); } else - V_DrawScaledPatch(SCX(40), SCY(8) + SCZ(5), V_NOSCALESTART|V_TRANSLUCENT, narrow[8]); + ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), narrow[8]); if (total_ringcount >= 100) - ST_DrawOverlayNum((total_ringcount >= 1000) ? SCX(76) : SCX(72), SCY(8) + SCZ(11), V_NOSCALESTART, total_ringcount); + ST_DrawOverlayNum((total_ringcount >= 1000) ? SCX(76) : SCX(72), SCY(8) + SCZ(11), total_ringcount); else - ST_DrawOverlayNum(SCX(68), SCY(8) + SCZ(11), V_NOSCALESTART, total_ringcount); + ST_DrawOverlayNum(SCX(68), SCY(8) + SCZ(11), total_ringcount); #ifdef HAVE_BLUA } #endif @@ -1233,7 +1201,7 @@ static void ST_drawNiGHTSHUD(void) && LUA_HudEnabled(hud_nightsscore) #endif ) - ST_DrawNightsOverlayNum(SCX(304), SCY(16), stplyr->marescore, nightsnum, SKINCOLOR_STEELBLUE); + ST_DrawNightsOverlayNum(SCX(304), SCY(16), 0, stplyr->marescore, nightsnum, SKINCOLOR_STEELBLUE); // Ideya time remaining if (!stplyr->exiting && stplyr->nightstime > 0 @@ -1275,10 +1243,10 @@ static void ST_drawNiGHTSHUD(void) numbersize = SCX(48)/2; if (realnightstime < 10) - ST_DrawNightsOverlayNum(SCX(160) + numbersize, SCY(12), realnightstime, + ST_DrawNightsOverlayNum(SCX(160) + numbersize, SCY(12), 0, realnightstime, nightsnum, SKINCOLOR_RED); else - ST_DrawNightsOverlayNum(SCX(160) + numbersize, SCY(12), realnightstime, + ST_DrawNightsOverlayNum(SCX(160) + numbersize, SCY(12), 0, realnightstime, nightsnum, SKINCOLOR_SUPER4); // Show exact time in debug @@ -1325,31 +1293,34 @@ static void ST_drawNiGHTSHUD(void) static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, INT32 xoffs, patch_t *pat) { - INT32 yelflag = 0; + INT32 txtflags = 0, patflags = 0; if (stplyr->powers[weapon]) { if (stplyr->powers[weapon] >= rw_maximums[wepflag]) - yelflag = V_YELLOWMAP; + txtflags |= V_YELLOWMAP; if (weapon == pw_infinityring || (stplyr->ringweapons & rwflag && stplyr->health > 1)) - V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT, pat); + txtflags |= V_20TRANS; else - V_DrawTranslucentPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|V_80TRANS, pat); + { + txtflags |= V_TRANSLUCENT; + patflags = V_80TRANS; + } + + V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|patflags, pat); if (stplyr->powers[weapon] > 99) - V_DrawThinString(8 + xoffs + 1, STRINGY(162), V_TRANSLUCENT | V_SNAPTOLEFT | yelflag, - va("%d", stplyr->powers[weapon])); + V_DrawThinString(8 + xoffs + 1, STRINGY(162), V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); else - V_DrawString(8 + xoffs, STRINGY(162), V_TRANSLUCENT | V_SNAPTOLEFT | yelflag, - va("%d", stplyr->powers[weapon])); + V_DrawString(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); if (stplyr->currentweapon == wepflag) V_DrawScaledPatch(6 + xoffs, STRINGY(162 - (splitscreen ? 4 : 2)), V_SNAPTOLEFT, curweapon); } else if (stplyr->ringweapons & rwflag) - V_DrawTranslucentPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT, pat); + V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|V_TRANSLUCENT, pat); } static void ST_drawMatchHUD(void) @@ -1503,15 +1474,15 @@ static void ST_drawCTFHUD(void) UINT16 whichflag = 0; // Draw the flags - V_DrawSmallScaledPatch(256, (splitscreen) ? STRINGY(160) : STRINGY(176), 0, rflagico); - V_DrawSmallScaledPatch(288, (splitscreen) ? STRINGY(160) : STRINGY(176), 0, bflagico); + V_DrawSmallScaledPatch(256, (splitscreen) ? STRINGY(160) : STRINGY(176), V_HUDTRANS, rflagico); + V_DrawSmallScaledPatch(288, (splitscreen) ? STRINGY(160) : STRINGY(176), V_HUDTRANS, bflagico); for (i = 0; i < MAXPLAYERS; i++) { if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base - V_DrawScaledPatch(256, (splitscreen) ? STRINGY(156) : STRINGY(174), 0, nonicon); + V_DrawScaledPatch(256, (splitscreen) ? STRINGY(156) : STRINGY(174), V_HUDTRANS, nonicon); else if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base - V_DrawScaledPatch(288, (splitscreen) ? STRINGY(156) : STRINGY(174), 0, nonicon); + V_DrawScaledPatch(288, (splitscreen) ? STRINGY(156) : STRINGY(174), V_HUDTRANS, nonicon); whichflag |= players[i].gotflag; if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG)) @@ -1524,9 +1495,9 @@ static void ST_drawCTFHUD(void) patch_t *p = (stplyr->gotflag & GF_REDFLAG) ? gotrflag : gotbflag; if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24) + 42, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, p); + V_DrawSmallScaledPatch(312, STRINGY(24) + 42, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); else - V_DrawScaledPatch(304, 24 + 84, V_SNAPTORIGHT|V_SNAPTOTOP|V_TRANSLUCENT, p); + V_DrawScaledPatch(304, 24 + 84, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); } // Display a countdown timer showing how much time left until the flag your team dropped returns to base. @@ -1535,13 +1506,13 @@ static void ST_drawCTFHUD(void) if (redflag && redflag->fuse > 1) { sprintf(timeleft, "%u", (redflag->fuse / TICRATE)); - V_DrawCenteredString(268, STRINGY(184), V_YELLOWMAP, timeleft); + V_DrawCenteredString(268, STRINGY(184), V_YELLOWMAP|V_HUDTRANS, timeleft); } if (blueflag && blueflag->fuse > 1) { sprintf(timeleft, "%u", (blueflag->fuse / TICRATE)); - V_DrawCenteredString(300, STRINGY(184), V_YELLOWMAP, timeleft); + V_DrawCenteredString(300, STRINGY(184), V_YELLOWMAP|V_HUDTRANS, timeleft); } } } @@ -1550,11 +1521,11 @@ static void ST_drawCTFHUD(void) static inline void ST_drawTeamName(void) { if (stplyr->ctfteam == 1) - V_DrawString(256, (splitscreen) ? STRINGY(184) : STRINGY(192), V_TRANSLUCENT, "RED TEAM"); + V_DrawString(256, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "RED TEAM"); else if (stplyr->ctfteam == 2) - V_DrawString(248, (splitscreen) ? STRINGY(184) : STRINGY(192), V_TRANSLUCENT, "BLUE TEAM"); + V_DrawString(248, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "BLUE TEAM"); else - V_DrawString(244, (splitscreen) ? STRINGY(184) : STRINGY(192), V_TRANSLUCENT, "SPECTATOR"); + V_DrawString(244, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "SPECTATOR"); } #ifdef CHAOSISNOTDEADYET @@ -1562,33 +1533,28 @@ static inline void ST_drawChaosHUD(void) { char chains[33]; sprintf(chains, "CHAINS: %u", stplyr->scoreadd); - V_DrawString(8, STRINGY(184), V_TRANSLUCENT, chains); + V_DrawString(8, STRINGY(184), V_HUDTRANSHALF, chains); } #endif static void ST_drawSpecialStageHUD(void) { if (totalrings > 0) - { - if (splitscreen) - ST_DrawOverlayNum(hudinfo[HUD_SS_TOTALRINGS_SPLIT].x, hudinfo[HUD_SS_TOTALRINGS_SPLIT].y, V_SNAPTOTOP, totalrings); - else - ST_DrawOverlayNum(hudinfo[HUD_SS_TOTALRINGS].x, hudinfo[HUD_SS_TOTALRINGS].y, V_SNAPTOTOP, totalrings); - } + ST_DrawNumFromHudWS(HUD_SS_TOTALRINGS, totalrings); if (leveltime < 5*TICRATE && totalrings > 0) { - V_DrawScaledPatch(hudinfo[HUD_GETRINGS].x, SCR(hudinfo[HUD_GETRINGS].y), V_TRANSLUCENT, getall); - ST_DrawOverlayNum(hudinfo[HUD_GETRINGSNUM].x, SCR(hudinfo[HUD_GETRINGSNUM].y), 0, totalrings); + ST_DrawPatchFromHud(HUD_GETRINGS, getall); + ST_DrawNumFromHud(HUD_GETRINGSNUM, totalrings); } if (sstimer) { - V_DrawString(hudinfo[HUD_TIMELEFT].x, STRINGY(hudinfo[HUD_TIMELEFT].y), 0, M_GetText("TIME LEFT")); - ST_DrawNightsOverlayNum(SCX(hudinfo[HUD_TIMELEFTNUM].x), SCY(hudinfo[HUD_TIMELEFTNUM].y), sstimer/TICRATE, tallnum, SKINCOLOR_WHITE); + V_DrawString(hudinfo[HUD_TIMELEFT].x, STRINGY(hudinfo[HUD_TIMELEFT].y), V_HUDTRANS, M_GetText("TIME LEFT")); + ST_DrawNightsOverlayNum(SCX(hudinfo[HUD_TIMELEFTNUM].x), SCY(hudinfo[HUD_TIMELEFTNUM].y), V_HUDTRANS, sstimer/TICRATE, tallnum, SKINCOLOR_WHITE); } else - V_DrawScaledPatch(hudinfo[HUD_TIMEUP].x, hudinfo[HUD_TIMEUP].y, V_TRANSLUCENT, timeup); + ST_DrawPatchFromHud(HUD_TIMEUP, timeup); } static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offset) @@ -1627,7 +1593,7 @@ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offse interval = 0; } - V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, STRINGY(hudinfo[HUD_HUNTPICS].y), V_TRANSLUCENT, patches[i]); + V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, STRINGY(hudinfo[HUD_HUNTPICS].y), V_HUDTRANS, patches[i]); return interval; } @@ -1895,9 +1861,9 @@ static void ST_overlayDrawer(void) { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; if (respawntime > 0 && !stplyr->spectator) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_TRANSLUCENT, va(M_GetText("Respawn in: %d second%s."), respawntime, respawntime == 1 ? "" : "s")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, va(M_GetText("Respawn in: %d second%s."), respawntime, respawntime == 1 ? "" : "s")); else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_TRANSLUCENT, M_GetText("Press Jump to respawn.")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Jump to respawn.")); } else if (stplyr->spectator #ifdef HAVE_BLUA @@ -1905,13 +1871,13 @@ static void ST_overlayDrawer(void) #endif ) { - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), V_TRANSLUCENT, M_GetText("You are a spectator.")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), V_HUDTRANSHALF, M_GetText("You are a spectator.")); if (G_GametypeHasTeams()) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_TRANSLUCENT, M_GetText("Press Fire to be assigned to a team.")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_TRANSLUCENT, M_GetText("Press Fire to enter the game.")); - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(148), V_TRANSLUCENT, M_GetText("Press F12 to watch another player.")); - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(164), V_TRANSLUCENT, M_GetText("Press Jump to float and Spin to sink.")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(148), V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(164), V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink.")); } } @@ -1924,12 +1890,12 @@ void ST_Drawer(boolean refresh) if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo) { if (cv_seenames.value == 1) - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_TRANSLUCENT, player_names[seenplayer-players]); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, player_names[seenplayer-players]); else if (cv_seenames.value == 2) - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_TRANSLUCENT, + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, va("%s%s", G_GametypeHasTeams() ? ((seenplayer->ctfteam == 1) ? "\x85" : "\x84") : "", player_names[seenplayer-players])); else //if (cv_seenames.value == 3) - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_TRANSLUCENT, + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, va("%s%s", !G_RingSlingerGametype() || (G_GametypeHasTeams() && players[consoleplayer].ctfteam == seenplayer->ctfteam) ? "\x83" : "\x85", player_names[seenplayer-players])); } diff --git a/src/st_stuff.h b/src/st_stuff.h index 5b5df5c1..d303bc80 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -83,24 +83,29 @@ typedef enum HUD_LIVESPIC, HUD_LIVESNUM, HUD_LIVESX, - HUD_RINGSSPLIT, - HUD_RINGSNUMSPLIT, + HUD_RINGS, + HUD_RINGSSPLIT, HUD_RINGSNUM, + HUD_RINGSNUMSPLIT, + HUD_SCORE, HUD_SCORENUM, - HUD_TIMESPLIT, - HUD_SECONDSSPLIT, - HUD_MINUTESSPLIT, - HUD_TIMECOLONSPLIT, + HUD_TIME, - HUD_TICS, - HUD_SECONDS, + HUD_TIMESPLIT, HUD_MINUTES, + HUD_MINUTESSPLIT, HUD_TIMECOLON, + HUD_TIMECOLONSPLIT, + HUD_SECONDS, + HUD_SECONDSSPLIT, HUD_TIMETICCOLON, - HUD_SS_TOTALRINGS_SPLIT, + HUD_TICS, + HUD_SS_TOTALRINGS, + HUD_SS_TOTALRINGS_SPLIT, + HUD_GETRINGS, HUD_GETRINGSNUM, HUD_TIMELEFT, diff --git a/src/v_video.c b/src/v_video.c index 17cd4362..032a4ec9 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -297,657 +297,127 @@ void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT3 #endif } -// -// V_DrawTranslucentMappedPatch: like V_DrawMappedPatch, but with translucency. -// -void V_DrawTranslucentMappedPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch, const UINT8 *colormap) +static UINT8 hudplusalpha[11] = { 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0}; +static UINT8 hudminusalpha[11] = { 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5}; + +static const UINT8 *v_colormap = NULL; +static const UINT8 *v_translevel = NULL; + +static inline UINT8 standardpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - size_t count; - INT32 col, w, dupx, dupy, ofs, colfrac, rowfrac; - const column_t *column; - UINT8 *desttop, *dest; - const UINT8 *source, *translevel, *deststop; - - if (rendermode == render_none) - return; -#ifdef HWRENDER - // draw a hardware converted patch - else if (rendermode != render_soft) - { - HWR_DrawMappedPatch((GLPatch_t *)patch, x, y, scrn, colormap); - return; - } -#endif - - if (scrn & V_ALPHAMASK) - { - INT32 alphalevel = (scrn & V_ALPHAMASK) >> V_ALPHASHIFT; - if (alphalevel >= NUMTRANSMAPS) - return; // fully translucent - translevel = ((alphalevel)<topoffset); - x -= SHORT(patch->leftoffset); - - if (scrn & V_NOSCALESTART) - { - desttop = screens[scrn&V_PARAMMASK] + (y*vid.width) + x; - deststop = screens[scrn&V_PARAMMASK] + vid.rowbytes * vid.height; - } - else - { - desttop = screens[scrn&V_PARAMMASK] + (y*vid.dupy*vid.width) + (x*vid.dupx); - deststop = screens[scrn&V_PARAMMASK] + vid.rowbytes * vid.height; - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - } - } - scrn &= V_PARAMMASK; - - col = 0; - colfrac = FixedDiv(FRACUNIT, dupx<width)<columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)column + 3; - dest = desttop + topdelta*dupy*vid.width; - count = column->length*dupy; - - ofs = 0; - while (count--) - { - if (dest < deststop) - *dest = *(translevel + (((*(colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); - else - count = 0; - dest += vid.width; - ofs += rowfrac; - } - - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } + (void)dest; return source[ofs>>FRACBITS]; } - -// -// V_DrawMappedPatch: like V_DrawScaledPatch, but with a colormap. -// -void V_DrawMappedPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch, const UINT8 *colormap) +static inline UINT8 mappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - size_t count; - INT32 col, w, dupx, dupy, ofs, colfrac, rowfrac; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - boolean flip = false; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - HWR_DrawMappedPatch((GLPatch_t *)patch, x, y, scrn, colormap); - return; - } -#endif - - switch (scrn & V_SCALEPATCHMASK) - { - case V_NOSCALEPATCH: - dupx = dupy = 1; - break; - case V_SMALLSCALEPATCH: - dupx = vid.smalldupx; - dupy = vid.smalldupy; - break; - case V_MEDSCALEPATCH: - dupx = vid.meddupx; - dupy = vid.meddupy; - break; - default: - dupx = vid.dupx; - dupy = vid.dupy; - break; - } - - // Only use one dup, to avoid stretching. - if (dupx < dupy) - dupy = dupx; - else - dupx = dupy; - - y -= SHORT(patch->topoffset); - if (scrn & V_FLIP) - { - flip = true; - x -= SHORT(patch->width) - SHORT(patch->leftoffset); - } - else - x -= SHORT(patch->leftoffset); - - if (scrn & V_SPLITSCREEN) - y /= 2; - - if (scrn & V_NOSCALESTART) - { - desttop = screens[scrn&V_PARAMMASK] + (y*vid.width) + x; - deststop = screens[scrn&V_PARAMMASK] + vid.rowbytes * vid.height; - } - else - { - desttop = screens[scrn&V_PARAMMASK] + (y*dupy*vid.width) + (x*dupx); - deststop = screens[scrn&V_PARAMMASK] + vid.rowbytes * vid.height; - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SPLITSCREEN && scrn & V_SNAPTOBOTTOM) - desttop += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)) * vid.width; - else if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - // if it's meant to cover the whole screen, black out the rest - if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : *(colormap + source[0]))); - } - } - } - scrn &= V_PARAMMASK; - - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx; - - col = 0; - colfrac = FixedDiv(FRACUNIT, dupx<width)<columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)column + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += topdelta*dupy*vid.width; - count = column->length*dupy; - - ofs = 0; - while (count--) - { - if (dest < deststop) - *dest = *(colormap + source[ofs>>FRACBITS]); - else - count = 0; - dest += vid.width; - ofs += rowfrac; - } - - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } + (void)dest; return *(v_colormap + source[ofs>>FRACBITS]); } - -// -// V_DrawScaledPatch -// -// Like V_DrawPatch, but scaled 2, 3, 4 times the original size and position. -// This is used for menu and title screens, with high resolutions. -// -void V_DrawScaledPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch) +static inline UINT8 translucentpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - size_t count; - INT32 col, dupx, dupy, ofs, colfrac, rowfrac; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - boolean flip = false; - -#ifdef PARANOIA - if (!patch) - CONS_Alert(CONS_ERROR, "NULL patch passed to V_DrawScaledPatch?! Crashing!\n"); -#endif - - if (rendermode == render_none) - return; -#ifdef HWRENDER - // draw a hardware converted patch - else if (rendermode != render_soft && !con_startup) - { - HWR_DrawPatch((GLPatch_t *)patch, x, y, scrn); - return; - } -#endif - - switch (scrn & V_SCALEPATCHMASK) - { - case V_NOSCALEPATCH: - dupx = dupy = 1; - break; - case V_SMALLSCALEPATCH: - dupx = vid.smalldupx; - dupy = vid.smalldupy; - break; - case V_MEDSCALEPATCH: - dupx = vid.meddupx; - dupy = vid.meddupy; - break; - default: - dupx = vid.dupx; - dupy = vid.dupy; - break; - } - - // Only use one dup, to avoid stretching. - if (dupx < dupy) - dupy = dupx; - else - dupx = dupy; - - y -= SHORT(patch->topoffset); - if (scrn & V_FLIP) - { - flip = true; - x -= SHORT(patch->width) - SHORT(patch->leftoffset); - } - else - x -= SHORT(patch->leftoffset); - - if (scrn & V_SPLITSCREEN) - y /= 2; - - colfrac = FixedDiv(FRACUNIT, dupx<width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - } - } - } - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx; - - if (destend + (SHORT(patch->height) * dupy) * vid.width < screens[scrn&V_PARAMMASK]) - return; - - for (col = 0; desttop < destend; col += colfrac, desttop++) - { - register INT32 heightmask; - INT32 topdelta, prevdelta = -1; - - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += topdelta*dupy*vid.width; - count = column->length*dupy; - - ofs = 0; - - heightmask = column->length - 1; - - while (dest < screens[scrn&V_PARAMMASK] && count) - { - dest += vid.width; - ofs += rowfrac; - --count; - } - - if (count && column->length & heightmask) - { - heightmask++; - heightmask <<= FRACBITS; - - if (rowfrac < 0) - while ((rowfrac += heightmask) < 0) - ; - else - while (rowfrac >= heightmask) - rowfrac -= heightmask; - - do - { - if (dest < deststop) - *dest = source[ofs>>FRACBITS]; - else - count = 0; - dest += vid.width; - ofs += rowfrac; - if ((ofs + rowfrac) > heightmask) - goto donedrawing; - } while (count--); - } - else - { - while (count--) - { - if (dest < deststop) - *dest = source[ofs>>FRACBITS]; - else - count = 0; - dest += vid.width; - ofs += rowfrac; - } - } -donedrawing: - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } + return *(v_translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); } - -/** Draws a patch to the screen, being careful not to go off the right - * side or bottom of the screen. This is slower than a normal draw, so - * it gets a separate function. - * - * With hardware rendering, the patch is clipped anyway, so this is - * just the same as V_DrawScaledPatch(). - * - * \param x X coordinate for left side, based on 320x200 screen. - * \param y Y coordinate for top, based on 320x200 screen. - * \param scrn Any of several flags to change the drawing behavior. - * \param patch Patch to draw. - * \sa V_DrawScaledPatch - * \author Graue - */ -static void V_DrawClippedScaledPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch) +static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - size_t count; - INT32 col, dupx, dupy, ofs, colfrac, rowfrac; - const column_t *column; - UINT8 *desttop, *dest, *destend; - const UINT8 *source, *deststop; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - // V_NOSCALESTART might be impled for software, but not for hardware! - HWR_DrawClippedPatch((GLPatch_t *)patch, x, y, V_NOSCALESTART); - return; - } -#endif - - switch (scrn & V_SCALEPATCHMASK) - { - case V_NOSCALEPATCH: - dupx = dupy = 1; - break; - case V_SMALLSCALEPATCH: - dupx = vid.smalldupx; - dupy = vid.smalldupy; - break; - case V_MEDSCALEPATCH: - dupx = vid.meddupx; - dupy = vid.meddupy; - break; - default: - dupx = vid.dupx; - dupy = vid.dupy; - break; - } - - // Only use one dup, to avoid stretching. - if (dupx < dupy) - dupy = dupx; - else - dupx = dupy; - - y -= SHORT(patch->topoffset); - x -= SHORT(patch->leftoffset); - - if (x < 0 || y < 0 || x >= vid.width || y >= vid.height) - return; - - colfrac = FixedDiv(FRACUNIT, dupx<width)*dupx <= vid.width) - destend = desttop + SHORT(patch->width) * dupx; - else - destend = desttop + vid.width - x; - - for (col = 0; desttop < destend; col += colfrac, desttop++) - { - register INT32 heightmask; - INT32 topdelta, prevdelta = -1; - - column = (const column_t *)((const UINT8 *)patch + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)column + 3; - dest = desttop + topdelta*dupy*vid.width; - count = column->length*dupy; - if ((dest-screens[scrn&V_PARAMMASK])/vid.width + count > (unsigned)vid.height - 1) - count = vid.height - 1 - (dest-screens[scrn&V_PARAMMASK])/vid.width; - if (count <= 0) - break; - - ofs = 0; - - heightmask = column->length - 1; - - if (column->length & heightmask) - { - // length is not a power of two - heightmask++; - heightmask <<= FRACBITS; - - if (rowfrac < 0) - while ((rowfrac += heightmask) < 0) - ; - else - while (rowfrac >= heightmask) - rowfrac -= heightmask; - - do - { - if (dest < deststop) - *dest = source[ofs>>FRACBITS]; - else - count = 0; - dest += vid.width; - ofs += rowfrac; - if ((ofs + rowfrac) > heightmask) - goto doneclipping; - } while (count--); - } - else - { - // length is a power of two - while (count--) - { - if (dest < deststop) - *dest = source[ofs>>FRACBITS]; - else - count = 0; - dest += vid.width; - ofs += rowfrac; - } - } -doneclipping: - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } + return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); } // Draws a patch scaled to arbitrary size. -void V_DrawSciencePatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_t science) +void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, const UINT8 *colormap) { + UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); + UINT32 alphalevel = 0; + boolean flip = false; + fixed_t col, ofs, colfrac, rowfrac, fdup; INT32 dupx, dupy; const column_t *column; - UINT8 *desttop, *dest; + UINT8 *desttop, *dest, *deststart, *destend; const UINT8 *source, *deststop; + if (rendermode == render_none) + return; + #ifdef HWRENDER // oh please - if (rendermode != render_soft && rendermode != render_none) + if (rendermode != render_soft && !con_startup) { - HWR_DrawSciencePatch((GLPatch_t *)patch, x, y, scrn, science); + HWR_DrawFixedPatch((GLPatch_t *)patch, x, y, pscale, scrn, colormap); return; } #endif + patchdrawfunc = standardpdraw; + + v_translevel = NULL; + if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT))) + { + if (alphalevel == 13) + alphalevel = hudminusalpha[cv_translucenthud.value]; + else if (alphalevel == 14) + alphalevel = 10 - cv_translucenthud.value; + else if (alphalevel == 15) + alphalevel = hudplusalpha[cv_translucenthud.value]; + + if (alphalevel >= 10) + return; // invis + } + if (alphalevel) + { + v_translevel = ((alphalevel)<> V_SCALEPATCHSHIFT) + { + case 1: // V_NOSCALEPATCH + dupx = dupy = 1; + break; + case 2: // V_SMALLSCALEPATCH + dupx = vid.smalldupx; + dupy = vid.smalldupy; + break; + case 3: // V_MEDSCALEPATCH + dupx = vid.meddupx; + dupy = vid.meddupy; + break; + default: + break; + } + // only use one dup, to avoid stretching (har har) - dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - fdup = FixedMul(dupx<topoffset)<leftoffset)<topoffset)*dupy)<leftoffset)*dupx)<topoffset)<width) - SHORT(patch->leftoffset))<leftoffset)<>=1; desttop = screens[scrn&V_PARAMMASK]; @@ -956,11 +426,13 @@ void V_DrawSciencePatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_ deststop = desttop + vid.rowbytes * vid.height; - if (scrn & V_NOSCALESTART) { + if (scrn & V_NOSCALESTART) + { x >>= FRACBITS; y >>= FRACBITS; desttop += (y*vid.width) + x; - } else + } + else { x = FixedMul(x,dupx<width) * dupx; + for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) { INT32 topdelta, prevdelta = -1; - if (x < 0) { // don't draw off the left of the screen (WRAP PREVENTION) + if (x < 0) + { // don't draw off the left of the screen (WRAP PREVENTION) x++; continue; } @@ -1017,12 +495,14 @@ void V_DrawSciencePatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_ prevdelta = topdelta; source = (const UINT8 *)(column) + 3; dest = desttop; + if (flip) + dest = deststart + (destend - desttop); dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) { if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) - *dest = source[ofs>>FRACBITS]; + *dest = patchdrawfunc(dest, source, ofs); dest += vid.width; } column = (const column_t *)((const UINT8 *)column + column->length + 4); @@ -1031,7 +511,7 @@ void V_DrawSciencePatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_ } // Draws a patch cropped and scaled to arbitrary size. -void V_DrawCroppedPatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_t science, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) { fixed_t col, ofs, colfrac, rowfrac, fdup; INT32 dupx, dupy; @@ -1039,20 +519,26 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_ UINT8 *desttop, *dest; const UINT8 *source, *deststop; -#ifdef HWRENDER - // fuck off - if (rendermode != render_soft && rendermode != render_none) + if (rendermode == render_none) return; + +#ifdef HWRENDER + // Done + if (rendermode != render_soft && !con_startup) + { + HWR_DrawCroppedPatch((GLPatch_t*)patch,x,y,pscale,scrn,sx,sy,w,h); + return; + } #endif // only use one dup, to avoid stretching (har har) dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - fdup = FixedMul(dupx<topoffset)<leftoffset)<topoffset)<leftoffset)<>= FRACBITS; y >>= FRACBITS; desttop += (y*vid.width) + x; - } else + } + else { x = FixedMul(x,dupx<topoffset)/2; - if (scrn & V_FLIP) - { - flip = true; - x -= (SHORT(patch->width) - SHORT(patch->leftoffset))/2; - } - else - x -= SHORT(patch->leftoffset)/2; - - if (scrn & V_SPLITSCREEN) - y /= 2; - - desttop = screens[scrn&V_PARAMMASK]; - - if (!desttop) - return; - - deststop = desttop + vid.rowbytes * vid.height; - - if (scrn & V_NOSCALESTART) - desttop += (y*vid.width) + x; - else - { - x = x*dupx; - y = y*dupy; - desttop += (y*vid.width) + x; - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SPLITSCREEN && scrn & V_SNAPTOBOTTOM) - desttop += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)) * vid.width; - else if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - // if it's meant to cover the whole screen, black out the rest - if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - } - } - } - - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx / 2; - - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) - { - INT32 topdelta, prevdelta = -1; - if (x < 0) { // don't draw off the left of the screen (WRAP PREVENTION) - x++; - continue; - } - if (x > vid.width) // don't draw off the right of the screen (WRAP PREVENTION) - break; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) - *dest = source[ofs>>FRACBITS]; - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// Draws a patch 2x as small, translucent, and colormapped. -void V_DrawSmallTranslucentMappedPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch, const UINT8 *colormap) -{ - fixed_t col, ofs, colfrac, rowfrac, fdup; - INT32 dupx, dupy; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - UINT8 *translevel; - boolean flip = false; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - if (!(scrn & V_NOSCALESTART)) // Graue 07-08-2004: I have no idea why this works - { - x = FixedInt(FixedMul(vid.fdupx, x*FRACUNIT)); - y = FixedInt(FixedMul(vid.fdupy, y*FRACUNIT)); - scrn |= V_NOSCALESTART; - } - HWR_DrawSmallPatch((GLPatch_t *)patch, x, y, scrn, colormap); - return; - } -#endif - - if (scrn & V_ALPHAMASK) - { - INT32 alphalevel = (scrn & V_ALPHAMASK) >> V_ALPHASHIFT; - if (alphalevel >= NUMTRANSMAPS) - return; // fully translucent - translevel = ((alphalevel)<topoffset)/2; - if (scrn & V_FLIP) - { - flip = true; - x -= (SHORT(patch->width) - SHORT(patch->leftoffset))/2; - } - else - x -= SHORT(patch->leftoffset)/2; - - desttop = screens[scrn&V_PARAMMASK]; - - if (!desttop) - return; - - deststop = desttop + vid.rowbytes * vid.height; - - if (scrn & V_NOSCALESTART) - desttop += (y*vid.width) + x; - else - { - desttop += (y*dupy*vid.width) + (x*dupx); - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - } - } - - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx / 2; - - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - *dest = *(translevel + (colormap[source[ofs>>FRACBITS]]<<8) + (*dest)); - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// Draws a patch 2x as small, and translucent. -void V_DrawSmallTranslucentPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch) -{ - fixed_t col, ofs, colfrac, rowfrac, fdup; - INT32 dupx, dupy; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - UINT8 *translevel; - boolean flip = false; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - if (!(scrn & V_NOSCALESTART)) // Graue 07-08-2004: I have no idea why this works - { - x = FixedInt(FixedMul(vid.fdupx, x*FRACUNIT)); - y = FixedInt(FixedMul(vid.fdupy, y*FRACUNIT)); - scrn |= V_NOSCALESTART; - } - HWR_DrawSmallPatch((GLPatch_t *)patch, x, y, scrn, colormaps); - return; - } -#endif - - if (scrn & V_ALPHAMASK) - { - INT32 alphalevel = (scrn & V_ALPHAMASK) >> V_ALPHASHIFT; - if (alphalevel >= NUMTRANSMAPS) - return; // fully translucent - translevel = ((alphalevel)<topoffset)/2; - if (scrn & V_FLIP) - { - flip = true; - x -= (SHORT(patch->width) - SHORT(patch->leftoffset))/2; - } - else - x -= SHORT(patch->leftoffset)/2; - - desttop = screens[scrn&V_PARAMMASK]; - - if (!desttop) - return; - - deststop = desttop + vid.rowbytes * vid.height; - - if (scrn & V_NOSCALESTART) - desttop += (y*vid.width) + x; - else - { - desttop += (y*dupy*vid.width) + (x*dupx); - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - } - } - - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx / 2; - - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - *dest = *(translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// Draws a patch 2x as small, and colormapped. -void V_DrawSmallMappedPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch, const UINT8 *colormap) -{ - fixed_t col, ofs, colfrac, rowfrac, fdup; - INT32 dupx, dupy; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - boolean flip = false; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - if (!(scrn & V_NOSCALESTART)) // Graue 07-08-2004: I have no idea why this works - { - x = FixedInt(FixedMul(vid.fdupx, x*FRACUNIT)); - y = FixedInt(FixedMul(vid.fdupy, y*FRACUNIT)); - scrn |= V_NOSCALESTART; - } - HWR_DrawSmallPatch((GLPatch_t *)patch, x, y, scrn, colormap); - return; - } -#endif - - // only use one dup, to avoid stretching. - dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - fdup = dupx<<(FRACBITS-1); - colfrac = FixedDiv(FRACUNIT, fdup); - rowfrac = FixedDiv(FRACUNIT, fdup); - - y -= SHORT(patch->topoffset)/2; - if (scrn & V_FLIP) - { - flip = true; - x -= (SHORT(patch->width) - SHORT(patch->leftoffset))/2; - } - else - x -= SHORT(patch->leftoffset)/2; - - if (scrn & V_SPLITSCREEN) - y /= 2; - - desttop = screens[scrn&V_PARAMMASK]; - - if (!desttop) - return; - - deststop = desttop + vid.rowbytes * vid.height; - - if (scrn & V_NOSCALESTART) - desttop += (y*vid.width) + x; - else - { - desttop += (y*dupy*vid.width) + (x*dupx); - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SPLITSCREEN && scrn & V_SNAPTOBOTTOM) - desttop += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)) * vid.width; - else if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - // if it's meant to cover the whole screen, black out the rest - if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : *(colormap + source[0]))); - } - } - } - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx / 2; - - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - *dest = *(colormap + source[ofs>>FRACBITS]); - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// Draws a patch 4x as small. -void V_DrawTinyScaledPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch) -{ - fixed_t col, ofs, colfrac, rowfrac, fdup; - INT32 dupx, dupy; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - boolean flip = false; - -#ifdef HWRENDER - // No. - if (rendermode != render_soft && rendermode != render_none) - return; -#endif - - // only use one dup, to avoid stretching. - fdup = (vid.dupx < vid.dupy ? vid.dupx<topoffset)/4; - if (scrn & V_FLIP) - { - flip = true; - x -= (SHORT(patch->width) - SHORT(patch->leftoffset))/4; - } - else - x -= SHORT(patch->leftoffset)/4; - - desttop = screens[scrn&V_PARAMMASK]; - - if (!desttop) - return; - - deststop = desttop + vid.rowbytes * vid.height; - - if (scrn & V_NOSCALESTART) - desttop += (y*vid.width) + x; - else - { - desttop += (y*dupy*vid.width) + (x*dupx); - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - // if it's meant to cover the whole screen, black out the rest - if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - } - } - } - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx / 4; - - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - *dest = source[ofs>>FRACBITS]; - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// Draws a patch 4x as small, and colormapped. -void V_DrawTinyMappedPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch, const UINT8 *colormap) -{ - fixed_t col, ofs, colfrac, rowfrac, fdup; - INT32 dupx, dupy; - const column_t *column; - UINT8 *desttop, *dest, *deststart, *destend; - const UINT8 *source, *deststop; - boolean flip = false; - -#ifdef HWRENDER - // No. - if (rendermode != render_soft && rendermode != render_none) - return; -#endif - - // only use one dup, to avoid stretching. - dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - fdup = dupx<<(FRACBITS-2); - colfrac = FixedDiv(FRACUNIT, fdup); - rowfrac = FixedDiv(FRACUNIT, fdup); - - y -= SHORT(patch->topoffset)/4; - if (scrn & V_FLIP) - { - flip = true; - x -= (SHORT(patch->width) - SHORT(patch->leftoffset))/4; - } - else - x -= SHORT(patch->leftoffset)/4; - - desttop = screens[scrn&V_PARAMMASK]; - - if (!desttop) - return; - - deststop = desttop + vid.rowbytes * vid.height; - - if (scrn & V_NOSCALESTART) - desttop += (y*vid.width) + x; - else - { - desttop += (y*dupy*vid.width) + (x*dupx); - - // Center it if necessary - if (!(scrn & V_SCALEPATCHMASK)) - { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } - // if it's meant to cover the whole screen, black out the rest - if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : *(colormap + source[0]))); - } - } - } - deststart = desttop; - destend = desttop + SHORT(patch->width) * dupx / 4; - - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)(column) + 3; - dest = desttop; - if (flip) - dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) - { - *dest = *(colormap + source[ofs>>FRACBITS]); - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// This draws a patch over a background with translucency...SCALED. -// SCALE THE STARTING COORDS! -// Used for crosshair. -// -void V_DrawTranslucentPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch) -{ - size_t count; - INT32 col, w, dupx, dupy, ofs, colfrac, rowfrac; - const column_t *column; - UINT8 *desttop, *dest; - const UINT8 *source, *translevel, *deststop; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - HWR_DrawTranslucentPatch((GLPatch_t *)patch, x, y, scrn); - return; - } -#endif - - if (scrn & V_ALPHAMASK) - { - INT32 alphalevel = (scrn & V_ALPHAMASK) >> V_ALPHASHIFT; - if (alphalevel >= NUMTRANSMAPS) - return; // fully translucent - translevel = ((alphalevel)<topoffset)*dupy; - x -= SHORT(patch->leftoffset)*dupx; - } - else - { - y -= SHORT(patch->topoffset); - x -= SHORT(patch->leftoffset); - } - - colfrac = FixedDiv(FRACUNIT, dupx<width)<columnofs[col>>FRACBITS])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)column + 3; - dest = desttop + topdelta*dupy*vid.width; - count = column->length*dupy; - - ofs = 0; - while (count--) - { - if (dest < deststop) - *dest = *(translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); - else - count = 0; - dest += vid.width; - ofs += rowfrac; - } - - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - -// -// V_DrawPatch -// Masks a column based masked pic to the screen. NO SCALING! -// -void V_DrawPatch(INT32 x, INT32 y, INT32 scrn, patch_t *patch) -{ - size_t count; - INT32 col, w; - const column_t *column; - UINT8 *desttop, *dest; - const UINT8 *source, *deststop; - -#ifdef HWRENDER - // draw a hardware converted patch - if (rendermode != render_soft && rendermode != render_none) - { - HWR_DrawPatch((GLPatch_t *)patch, x, y, V_NOSCALESTART|V_NOSCALEPATCH); - return; - } -#endif - - y -= SHORT(patch->topoffset); - x -= SHORT(patch->leftoffset); -#ifdef RANGECHECK - if (x < 0 || x + SHORT(patch->width) > vid.width || y < 0 - || y + SHORT(patch->height) > vid.height || (unsigned)scrn > 4) - { - fprintf(stderr, "Patch at %d, %d exceeds LFB\n", x, y); - // No I_Error abort - what is up with TNT.WAD? - fprintf(stderr, "V_DrawPatch: bad patch (ignored)\n"); - return; - } -#endif - - desttop = screens[scrn] + y*vid.width + x; - deststop = screens[scrn&V_PARAMMASK] + vid.rowbytes * vid.height; - w = SHORT(patch->width); - - for (col = 0; col < w; x++, col++, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (const column_t *)((const UINT8 *)patch + LONG(patch->columnofs[col])); - - // step through the posts in a column - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)column + 3; - dest = desttop + topdelta*vid.width; - count = column->length; - - while (count--) - { - if (dest < deststop) - *dest = *source++; - else - count = 0; - dest += vid.width; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - } -} - // // V_DrawContinueIcon // Draw a mini player! If we can, that is. Otherwise we draw a star. @@ -2032,7 +630,7 @@ void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skin { if (skins[skinnum].flags & SF_HIRES #ifdef HWRENDER - || (rendermode != render_soft && rendermode != render_none) +// || (rendermode != render_soft && rendermode != render_none) #endif ) V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); @@ -2310,12 +908,7 @@ void V_DrawPatchFill(patch_t *pat) for (x = 0; x < vid.width; x += pw) { for (y = 0; y < vid.height; y += ph) - { - if (x + pw >= vid.width || y + ph >= vid.height) - V_DrawClippedScaledPatch(x, y, 0, pat); // V_NOSCALESTART is implied - else - V_DrawScaledPatch(x, y, V_NOSCALESTART, pat); - } + V_DrawScaledPatch(x, y, V_NOSCALESTART, pat); } } @@ -2678,15 +1271,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) } colormap = V_GetStringColormap(charflags); - - if (colormap != NULL && (option & V_ALPHAMASK)) - V_DrawTranslucentMappedPatch(cx + center, cy, option, hu_font[c], colormap); - else if (colormap != NULL) - V_DrawMappedPatch(cx + center, cy, option, hu_font[c], colormap); - else if (option & V_ALPHAMASK) - V_DrawTranslucentPatch(cx + center, cy, option, hu_font[c]); - else - V_DrawScaledPatch(cx + center, cy, option, hu_font[c]); + V_DrawFixedPatch((cx + center)<