diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f4b262bac..46a711aac 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,541 @@ 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) + { + if (!playeringame[j] || players[j].gotflag != i) + 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 +3071,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 +3099,7 @@ static void HandleConnect(SINT8 node) DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(); + player_joining = true; } #endif } @@ -2982,6 +3148,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 +3322,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 +3339,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 +3391,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 +3423,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 +3507,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 +3552,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 +3591,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 +3607,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 +3657,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 +3973,9 @@ void TryRunTics(tic_t realtics) } #endif + if (player_joining) + return; + if (neededtic > gametic) { if (advancedemo) @@ -3911,13 +4111,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 +4132,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 d35c5cb3c..0086132e6 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 2492f622c..025903904 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; } @@ -1094,7 +1097,7 @@ void D_SRB2Main(void) 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, "e868046d2d2da1d8c706c900edfb03f8"); // 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 3c2213fca..d93b80c95 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -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 57445244d..06c6fcb0e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3138,10 +3138,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 +4092,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 3abc6ddf3..4b2978546 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/dehacked.c b/src/dehacked.c index e25f66e72..6eae1ce23 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 @@ -7325,24 +7325,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", @@ -7683,6 +7688,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 4023c4979..371decc2d 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 d4ad4a68a..a5454851f 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 4 // more precise version number +#define VERSIONSTRING "v2.1.4" #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 9 diff --git a/src/doomstat.h b/src/doomstat.h index 576b70099..642e9bfc3 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 e3f2a2813..dfd9aacd0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1467,10 +1467,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 +1482,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 +1932,6 @@ void G_PlayerReborn(INT32 player) INT32 score; INT32 lives; INT32 continues; - INT32 xtralife; UINT8 charability; UINT8 charability2; fixed_t normalspeed; @@ -1952,9 +1956,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 +1970,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 +2020,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; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 43d4537fd..168761a07 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,13 +214,13 @@ void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawCroppedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, fixed_t scale, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +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) { 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 // | /| @@ -223,8 +228,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, fix // 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); @@ -247,17 +255,17 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, fix if (option & V_NOSCALESTART) sdupx = sdupy = 2.0f; - v[0].x = v[3].x = (cx*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; - v[2].x = v[1].x = ((cx-sx)*sdupx+(w-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-sy)*sdupy+(h-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 = ((float)sx/(float)gpatch->height); - v[2].sow = v[1].sow = gpatch->max_s*((float)w/(float)gpatch->width); - v[0].tow = v[1].tow = ((float)sy/(float)gpatch->height); - v[2].tow = v[3].tow = gpatch->max_t*((float)h/(float)gpatch->height); + 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 = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; @@ -267,217 +275,14 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, fix 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); -} - -void HWR_DrawClippedPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) -{ - // 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]; - FBITFIELD flags; - -// 3--2 -// | /| -// |/ | -// 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; - - // make patch ready in hardware cache - HWR_GetPatch (gpatch); - - 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 = 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; - - 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; - 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); } @@ -517,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.h b/src/hardware/hw_main.h index a6cf3fb7f..c93d4ea6b 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -44,12 +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_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_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_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/hu_stuff.c b/src/hu_stuff.c index c8f452a69..14f6d54ad 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; diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index f80d9809e..47bd4370f 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -222,21 +222,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 44c6f03e3..16bd88ad8 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 5aad4e77d..0676bb522 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1137,8 +1137,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 +1243,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 +1276,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 }; @@ -4681,9 +4681,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 +4707,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 +4741,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); } diff --git a/src/p_map.c b/src/p_map.c index 8b7869b83..eb7c6ad75 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_saveg.c b/src/p_saveg.c index 17db00625..baa042112 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_spec.c b/src/p_spec.c index 20d86176f..fa6200cd5 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 5aa0d50a1..ac026a11a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8113,19 +8113,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 +8187,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 +8200,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 +8641,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; } diff --git a/src/r_main.c b/src/r_main.c index c55de3940..6af1bf468 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}; @@ -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 8a39b7d30..a367960c7 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; diff --git a/src/st_stuff.c b/src/st_stuff.c index 56ce8e4e9..9f5a691ee 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -129,27 +129,29 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 16, 176}, // HUD_LIVESPIC { 74, 184}, // HUD_LIVESNUM { 38, 186}, // HUD_LIVESX - { 220, 10}, // HUD_RINGSSPLIT - { 288, 10}, // HUD_RINGSNUMSPLIT + { 16, 42}, // HUD_RINGS + { 220, 10}, // HUD_RINGSSPLIT { 112, 42}, // HUD_RINGSNUM + { 288, 10}, // HUD_RINGSNUMSPLIT + { 16, 10}, // HUD_SCORE { 128, 10}, // HUD_SCORENUM - { 136, 10}, // HUD_TIMESPLIT - { 212, 10}, // HUD_SECONDSSPLIT - { 188, 10}, // HUD_MINUTESSPLIT - { 188, 10}, // HUD_TIMECOLONSPLIT { 17, 26}, // HUD_TIME - + { 136, 10}, // HUD_TIMESPLIT + { 88, 26}, // HUD_MINUTES + { 188, 10}, // HUD_MINUTESSPLIT + { 88, 26}, // HUD_TIMECOLON + { 188, 10}, // HUD_TIMECOLONSPLIT + { 112, 26}, // HUD_SECONDS + { 212, 10}, // HUD_SECONDSSPLIT + { 112, 26}, // HUD_TIMETICCOLON { 136, 26}, // HUD_TICS - { 112, 26}, // HUD_SECONDS - { 88, 26}, // HUD_MINUTES - { 88, 26}, // HUD_TIMECOLON - { 112, 26}, // HUD_TIMETICCOLON - { 288, 40}, // HUD_SS_TOTALRINGS_SPLIT { 112, 56}, // HUD_SS_TOTALRINGS + { 288, 40}, // HUD_SS_TOTALRINGS_SPLIT + { 110, 93}, // HUD_GETRINGS { 160, 93}, // HUD_GETRINGSNUM { 124, 160}, // HUD_TIMELEFT @@ -160,9 +162,6 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 240, 160}, // HUD_LAP }; -#define ST_DrawOverlayNum(x,y,f,n) V_DrawTallNum(x, y, f|V_TRANSLUCENT, n) -#define ST_DrawPaddedOverlayNum(x,y,n,d) V_DrawPaddedTallNum(x, y, V_NOSCALESTART|V_TRANSLUCENT, n, d) - // // STATUS BAR CODE // @@ -463,6 +462,7 @@ static INT32 SCX(INT32 x) return FixedInt(FixedMul(x<width); - 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 5b5df5c12..d303bc804 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 76728a35d..032a4ec94 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,23 +519,26 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_ UINT8 *desttop, *dest; const UINT8 *source, *deststop; + if (rendermode == render_none) + return; + #ifdef HWRENDER // Done - if (rendermode != render_soft && rendermode != render_none) + if (rendermode != render_soft && !con_startup) { - HWR_DrawCroppedPatch((GLPatch_t *)patch, x, y, scrn, science, sx, sy, w, h); + 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. @@ -2035,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)); @@ -2313,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); } } @@ -2681,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)<