diff options
Diffstat (limited to 'src/strife/wi_stuff.c')
-rw-r--r-- | src/strife/wi_stuff.c | 1841 |
1 files changed, 1841 insertions, 0 deletions
diff --git a/src/strife/wi_stuff.c b/src/strife/wi_stuff.c new file mode 100644 index 00000000..83f5052f --- /dev/null +++ b/src/strife/wi_stuff.c @@ -0,0 +1,1841 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// Intermission screens. +// +//----------------------------------------------------------------------------- + + +#include <stdio.h> + +#include "z_zone.h" + +#include "m_random.h" + +#include "deh_main.h" +#include "i_swap.h" +#include "i_system.h" + +#include "w_wad.h" + +#include "g_game.h" + +#include "r_local.h" +#include "s_sound.h" + +#include "doomstat.h" + +// Data. +#include "sounds.h" + +// Needs access to LFB. +#include "v_video.h" + +#include "wi_stuff.h" + +// +// Data needed to add patches to full screen intermission pics. +// Patches are statistics messages, and animations. +// Loads of by-pixel layout and placement, offsets etc. +// + + +// +// Different vetween registered DOOM (1994) and +// Ultimate DOOM - Final edition (retail, 1995?). +// This is supposedly ignored for commercial +// release (aka DOOM II), which had 34 maps +// in one episode. So there. +#define NUMEPISODES 4 +#define NUMMAPS 9 + + +// in tics +//U #define PAUSELEN (TICRATE*2) +//U #define SCORESTEP 100 +//U #define ANIMPERIOD 32 +// pixel distance from "(YOU)" to "PLAYER N" +//U #define STARDIST 10 +//U #define WK 1 + + +// GLOBAL LOCATIONS +#define WI_TITLEY 2 +#define WI_SPACINGY 33 + +// SINGPLE-PLAYER STUFF +#define SP_STATSX 50 +#define SP_STATSY 50 + +#define SP_TIMEX 16 +#define SP_TIMEY (SCREENHEIGHT-32) + + +// NET GAME STUFF +#define NG_STATSY 50 +#define NG_STATSX (32 + SHORT(star->width)/2 + 32*!dofrags) + +#define NG_SPACINGX 64 + + +// DEATHMATCH STUFF +#define DM_MATRIXX 42 +#define DM_MATRIXY 68 + +#define DM_SPACINGX 40 + +#define DM_TOTALSX 269 + +#define DM_KILLERSX 10 +#define DM_KILLERSY 100 +#define DM_VICTIMSX 5 +#define DM_VICTIMSY 50 + + + + +typedef enum +{ + ANIM_ALWAYS, + ANIM_RANDOM, + ANIM_LEVEL + +} animenum_t; + +typedef struct +{ + int x; + int y; + +} point_t; + + +// +// Animation. +// There is another anim_t used in p_spec. +// +typedef struct +{ + animenum_t type; + + // period in tics between animations + int period; + + // number of animation frames + int nanims; + + // location of animation + point_t loc; + + // ALWAYS: n/a, + // RANDOM: period deviation (<256), + // LEVEL: level + int data1; + + // ALWAYS: n/a, + // RANDOM: random base period, + // LEVEL: n/a + int data2; + + // actual graphics for frames of animations + patch_t* p[3]; + + // following must be initialized to zero before use! + + // next value of bcnt (used in conjunction with period) + int nexttic; + + // last drawn animation frame + int lastdrawn; + + // next frame number to animate + int ctr; + + // used by RANDOM and LEVEL when animating + int state; + +} anim_t; + + +static point_t lnodes[NUMEPISODES][NUMMAPS] = +{ + // Episode 0 World Map + { + { 185, 164 }, // location of level 0 (CJ) + { 148, 143 }, // location of level 1 (CJ) + { 69, 122 }, // location of level 2 (CJ) + { 209, 102 }, // location of level 3 (CJ) + { 116, 89 }, // location of level 4 (CJ) + { 166, 55 }, // location of level 5 (CJ) + { 71, 56 }, // location of level 6 (CJ) + { 135, 29 }, // location of level 7 (CJ) + { 71, 24 } // location of level 8 (CJ) + }, + + // Episode 1 World Map should go here + { + { 254, 25 }, // location of level 0 (CJ) + { 97, 50 }, // location of level 1 (CJ) + { 188, 64 }, // location of level 2 (CJ) + { 128, 78 }, // location of level 3 (CJ) + { 214, 92 }, // location of level 4 (CJ) + { 133, 130 }, // location of level 5 (CJ) + { 208, 136 }, // location of level 6 (CJ) + { 148, 140 }, // location of level 7 (CJ) + { 235, 158 } // location of level 8 (CJ) + }, + + // Episode 2 World Map should go here + { + { 156, 168 }, // location of level 0 (CJ) + { 48, 154 }, // location of level 1 (CJ) + { 174, 95 }, // location of level 2 (CJ) + { 265, 75 }, // location of level 3 (CJ) + { 130, 48 }, // location of level 4 (CJ) + { 279, 23 }, // location of level 5 (CJ) + { 198, 48 }, // location of level 6 (CJ) + { 140, 25 }, // location of level 7 (CJ) + { 281, 136 } // location of level 8 (CJ) + } + +}; + + +// +// Animation locations for episode 0 (1). +// Using patches saves a lot of space, +// as they replace 320x200 full screen frames. +// + +#define ANIM(type, period, nanims, x, y, nexttic) \ + { (type), (period), (nanims), { (x), (y) }, (nexttic), \ + 0, { NULL, NULL, NULL }, 0, 0, 0, 0 } + + +static anim_t epsd0animinfo[] = +{ + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0), +}; + +static anim_t epsd1animinfo[] = +{ + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7), + ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8), +}; + +static anim_t epsd2animinfo[] = +{ + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0), + ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0), +}; + +static int NUMANIMS[NUMEPISODES] = +{ + arrlen(epsd0animinfo), + arrlen(epsd1animinfo), + arrlen(epsd2animinfo), +}; + +static anim_t *anims[NUMEPISODES] = +{ + epsd0animinfo, + epsd1animinfo, + epsd2animinfo +}; + + +// +// GENERAL DATA +// + +// +// Locally used stuff. +// + +// States for single-player +#define SP_KILLS 0 +#define SP_ITEMS 2 +#define SP_SECRET 4 +#define SP_FRAGS 6 +#define SP_TIME 8 +#define SP_PAR ST_TIME + +#define SP_PAUSE 1 + +// in seconds +#define SHOWNEXTLOCDELAY 4 +//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY + + +// used to accelerate or skip a stage +static int acceleratestage; + +// wbs->pnum +static int me; + + // specifies current state +static stateenum_t state; + +// contains information passed into intermission +static wbstartstruct_t* wbs; + +static wbplayerstruct_t* plrs; // wbs->plyr[] + +// used for general timing +static int cnt; + +// used for timing of background animation +static int bcnt; + +// signals to refresh everything for one frame +static int firstrefresh; + +static int cnt_kills[MAXPLAYERS]; +static int cnt_items[MAXPLAYERS]; +static int cnt_secret[MAXPLAYERS]; +static int cnt_time; +static int cnt_par; +static int cnt_pause; + +// # of commercial levels +static int NUMCMAPS; + + +// +// GRAPHICS +// + +// You Are Here graphic +static patch_t* yah[3] = { NULL, NULL, NULL }; + +// splat +static patch_t* splat[2] = { NULL, NULL }; + +// %, : graphics +static patch_t* percent; +static patch_t* colon; + +// 0-9 graphic +static patch_t* num[10]; + +// minus sign +static patch_t* wiminus; + +// "Finished!" graphics +static patch_t* finished; + +// "Entering" graphic +static patch_t* entering; + +// "secret" +static patch_t* sp_secret; + + // "Kills", "Scrt", "Items", "Frags" +static patch_t* kills; +static patch_t* secret; +static patch_t* items; +static patch_t* frags; + +// Time sucks. +static patch_t* timepatch; +static patch_t* par; +static patch_t* sucks; + +// "killers", "victims" +static patch_t* killers; +static patch_t* victims; + +// "Total", your face, your dead face +static patch_t* total; +static patch_t* star; +static patch_t* bstar; + +// "red P[1..MAXPLAYERS]" +static patch_t* p[MAXPLAYERS]; + +// "gray P[1..MAXPLAYERS]" +static patch_t* bp[MAXPLAYERS]; + + // Name graphics of each level (centered) +static patch_t** lnames; + +// Buffer storing the backdrop +static patch_t *background; + +// +// CODE +// + +// slam background +void WI_slamBackground(void) +{ + V_DrawPatch(0, 0, background); +} + +// The ticker is used to detect keys +// because of timing issues in netgames. +boolean WI_Responder(event_t* ev) +{ + return false; +} + + +// Draws "<Levelname> Finished!" +void WI_drawLF(void) +{ + int y = WI_TITLEY; + + if (gamemode != commercial || wbs->last < NUMCMAPS) + { + // draw <LevelName> + V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2, + y, lnames[wbs->last]); + + // draw "Finished!" + y += (5*SHORT(lnames[wbs->last]->height))/4; + + V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished); + } + else if (wbs->last == NUMCMAPS) + { + // MAP33 - nothing is displayed! + } + else if (wbs->last > NUMCMAPS) + { + // > MAP33. Doom bombs out here with a Bad V_DrawPatch error. + // I'm pretty sure that doom2.exe is just reading into random + // bits of memory at this point, but let's try to be accurate + // anyway. This deliberately triggers a V_DrawPatch error. + + patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1, + { 0, 0, 0, 0, 0, 0, 0, 0 } }; + + V_DrawPatch(0, y, &tmp); + } +} + + + +// Draws "Entering <LevelName>" +void WI_drawEL(void) +{ + int y = WI_TITLEY; + + // draw "Entering" + V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2, + y, + entering); + + // draw level + y += (5*SHORT(lnames[wbs->next]->height))/4; + + V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2, + y, + lnames[wbs->next]); + +} + +void +WI_drawOnLnode +( int n, + patch_t* c[] ) +{ + + int i; + int left; + int top; + int right; + int bottom; + boolean fits = false; + + i = 0; + do + { + left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset); + top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset); + right = left + SHORT(c[i]->width); + bottom = top + SHORT(c[i]->height); + + if (left >= 0 + && right < SCREENWIDTH + && top >= 0 + && bottom < SCREENHEIGHT) + { + fits = true; + } + else + { + i++; + } + } while (!fits && i!=2 && c[i] != NULL); + + if (fits && i<2) + { + V_DrawPatch(lnodes[wbs->epsd][n].x, + lnodes[wbs->epsd][n].y, + c[i]); + } + else + { + // DEBUG + printf("Could not place patch on level %d", n+1); + } +} + + + +void WI_initAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) + return; + + if (wbs->epsd > 2) + return; + + for (i=0;i<NUMANIMS[wbs->epsd];i++) + { + a = &anims[wbs->epsd][i]; + + // init variables + a->ctr = -1; + + // specify the next time to draw it + if (a->type == ANIM_ALWAYS) + a->nexttic = bcnt + 1 + (M_Random()%a->period); + else if (a->type == ANIM_RANDOM) + a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); + else if (a->type == ANIM_LEVEL) + a->nexttic = bcnt + 1; + } + +} + +void WI_updateAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) + return; + + if (wbs->epsd > 2) + return; + + for (i=0;i<NUMANIMS[wbs->epsd];i++) + { + a = &anims[wbs->epsd][i]; + + if (bcnt == a->nexttic) + { + switch (a->type) + { + case ANIM_ALWAYS: + if (++a->ctr >= a->nanims) a->ctr = 0; + a->nexttic = bcnt + a->period; + break; + + case ANIM_RANDOM: + a->ctr++; + if (a->ctr == a->nanims) + { + a->ctr = -1; + a->nexttic = bcnt+a->data2+(M_Random()%a->data1); + } + else a->nexttic = bcnt + a->period; + break; + + case ANIM_LEVEL: + // gawd-awful hack for level anims + if (!(state == StatCount && i == 7) + && wbs->next == a->data1) + { + a->ctr++; + if (a->ctr == a->nanims) a->ctr--; + a->nexttic = bcnt + a->period; + } + break; + } + } + + } + +} + +void WI_drawAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) + return; + + if (wbs->epsd > 2) + return; + + for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++) + { + a = &anims[wbs->epsd][i]; + + if (a->ctr >= 0) + V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]); + } + +} + +// +// Draws a number. +// If digits > 0, then use that many digits minimum, +// otherwise only use as many as necessary. +// Returns new x position. +// + +int +WI_drawNum +( int x, + int y, + int n, + int digits ) +{ + + int fontwidth = SHORT(num[0]->width); + int neg; + int temp; + + if (digits < 0) + { + if (!n) + { + // make variable-length zeros 1 digit long + digits = 1; + } + else + { + // figure out # of digits in # + digits = 0; + temp = n; + + while (temp) + { + temp /= 10; + digits++; + } + } + } + + neg = n < 0; + if (neg) + n = -n; + + // if non-number, do not draw it + if (n == 1994) + return 0; + + // draw the new number + while (digits--) + { + x -= fontwidth; + V_DrawPatch(x, y, num[ n % 10 ]); + n /= 10; + } + + // draw a minus sign if necessary + if (neg) + V_DrawPatch(x-=8, y, wiminus); + + return x; + +} + +void +WI_drawPercent +( int x, + int y, + int p ) +{ + if (p < 0) + return; + + V_DrawPatch(x, y, percent); + WI_drawNum(x, y, p, -1); +} + + + +// +// Display level completion time and par, +// or "sucks" message if overflow. +// +void +WI_drawTime +( int x, + int y, + int t ) +{ + + int div; + int n; + + if (t<0) + return; + + if (t <= 61*59) + { + div = 1; + + do + { + n = (t / div) % 60; + x = WI_drawNum(x, y, n, 2) - SHORT(colon->width); + div *= 60; + + // draw + if (div==60 || t / div) + V_DrawPatch(x, y, colon); + + } while (t / div); + } + else + { + // "sucks" + V_DrawPatch(x - SHORT(sucks->width), y, sucks); + } +} + + +void WI_End(void) +{ + void WI_unloadData(void); + WI_unloadData(); +} + +void WI_initNoState(void) +{ + state = NoState; + acceleratestage = 0; + cnt = 10; +} + +void WI_updateNoState(void) { + + WI_updateAnimatedBack(); + + if (!--cnt) + { + // Don't call WI_End yet. G_WorldDone doesnt immediately + // change gamestate, so WI_Drawer is still going to get + // run until that happens. If we do that after WI_End + // (which unloads all the graphics), we're in trouble. + //WI_End(); + G_WorldDone(); + } + +} + +static boolean snl_pointeron = false; + + +void WI_initShowNextLoc(void) +{ + state = ShowNextLoc; + acceleratestage = 0; + cnt = SHOWNEXTLOCDELAY * TICRATE; + + WI_initAnimatedBack(); +} + +void WI_updateShowNextLoc(void) +{ + WI_updateAnimatedBack(); + + if (!--cnt || acceleratestage) + WI_initNoState(); + else + snl_pointeron = (cnt & 31) < 20; +} + +void WI_drawShowNextLoc(void) +{ + + int i; + int last; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + if ( gamemode != commercial) + { + if (wbs->epsd > 2) + { + WI_drawEL(); + return; + } + + last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; + + // draw a splat on taken cities. + for (i=0 ; i<=last ; i++) + WI_drawOnLnode(i, splat); + + // splat the secret level? + if (wbs->didsecret) + WI_drawOnLnode(8, splat); + + // draw flashing ptr + if (snl_pointeron) + WI_drawOnLnode(wbs->next, yah); + } + + // draws which level you are entering.. + if ( (gamemode != commercial) + || wbs->next != 30) + WI_drawEL(); + +} + +void WI_drawNoState(void) +{ + snl_pointeron = true; + WI_drawShowNextLoc(); +} + +int WI_fragSum(int playernum) +{ + int i; + int frags = 0; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (playeringame[i] + && i!=playernum) + { + frags += plrs[playernum].frags[i]; + } + } + + + // JDC hack - negative frags. + frags -= plrs[playernum].frags[playernum]; + // UNUSED if (frags < 0) + // frags = 0; + + return frags; +} + + + +static int dm_state; +static int dm_frags[MAXPLAYERS][MAXPLAYERS]; +static int dm_totals[MAXPLAYERS]; + + + +void WI_initDeathmatchStats(void) +{ + + int i; + int j; + + state = StatCount; + acceleratestage = 0; + dm_state = 1; + + cnt_pause = TICRATE; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (playeringame[i]) + { + for (j=0 ; j<MAXPLAYERS ; j++) + if (playeringame[j]) + dm_frags[i][j] = 0; + + dm_totals[i] = 0; + } + } + + WI_initAnimatedBack(); +} + + + +void WI_updateDeathmatchStats(void) +{ + + int i; + int j; + + boolean stillticking; + + WI_updateAnimatedBack(); + + if (acceleratestage && dm_state != 4) + { + acceleratestage = 0; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (playeringame[i]) + { + for (j=0 ; j<MAXPLAYERS ; j++) + if (playeringame[j]) + dm_frags[i][j] = plrs[i].frags[j]; + + dm_totals[i] = WI_fragSum(i); + } + } + + + S_StartSound(0, sfx_barexp); + dm_state = 4; + } + + + if (dm_state == 2) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (playeringame[i]) + { + for (j=0 ; j<MAXPLAYERS ; j++) + { + if (playeringame[j] + && dm_frags[i][j] != plrs[i].frags[j]) + { + if (plrs[i].frags[j] < 0) + dm_frags[i][j]--; + else + dm_frags[i][j]++; + + if (dm_frags[i][j] > 99) + dm_frags[i][j] = 99; + + if (dm_frags[i][j] < -99) + dm_frags[i][j] = -99; + + stillticking = true; + } + } + dm_totals[i] = WI_fragSum(i); + + if (dm_totals[i] > 99) + dm_totals[i] = 99; + + if (dm_totals[i] < -99) + dm_totals[i] = -99; + } + + } + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + dm_state++; + } + + } + else if (dm_state == 4) + { + if (acceleratestage) + { + S_StartSound(0, sfx_slop); + + if ( gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (dm_state & 1) + { + if (!--cnt_pause) + { + dm_state++; + cnt_pause = TICRATE; + } + } +} + + + +void WI_drawDeathmatchStats(void) +{ + + int i; + int j; + int x; + int y; + int w; + + int lh; // line height + + lh = WI_SPACINGY; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + WI_drawLF(); + + // draw stat titles (top line) + V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2, + DM_MATRIXY-WI_SPACINGY+10, + total); + + V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers); + V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims); + + // draw P? + x = DM_MATRIXX + DM_SPACINGX; + y = DM_MATRIXY; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (playeringame[i]) + { + V_DrawPatch(x-SHORT(p[i]->width)/2, + DM_MATRIXY - WI_SPACINGY, + p[i]); + + V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, + y, + p[i]); + + if (i == me) + { + V_DrawPatch(x-SHORT(p[i]->width)/2, + DM_MATRIXY - WI_SPACINGY, + bstar); + + V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, + y, + star); + } + } + else + { + // V_DrawPatch(x-SHORT(bp[i]->width)/2, + // DM_MATRIXY - WI_SPACINGY, bp[i]); + // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2, + // y, bp[i]); + } + x += DM_SPACINGX; + y += WI_SPACINGY; + } + + // draw stats + y = DM_MATRIXY+10; + w = SHORT(num[0]->width); + + for (i=0 ; i<MAXPLAYERS ; i++) + { + x = DM_MATRIXX + DM_SPACINGX; + + if (playeringame[i]) + { + for (j=0 ; j<MAXPLAYERS ; j++) + { + if (playeringame[j]) + WI_drawNum(x+w, y, dm_frags[i][j], 2); + + x += DM_SPACINGX; + } + WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2); + } + y += WI_SPACINGY; + } +} + +static int cnt_frags[MAXPLAYERS]; +static int dofrags; +static int ng_state; + +void WI_initNetgameStats(void) +{ + + int i; + + state = StatCount; + acceleratestage = 0; + ng_state = 1; + + cnt_pause = TICRATE; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0; + + dofrags += WI_fragSum(i); + } + + dofrags = !!dofrags; + + WI_initAnimatedBack(); +} + + + +void WI_updateNetgameStats(void) +{ + + int i; + int fsum; + + boolean stillticking; + + WI_updateAnimatedBack(); + + if (acceleratestage && ng_state != 10) + { + acceleratestage = 0; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret; + + if (dofrags) + cnt_frags[i] = WI_fragSum(i); + } + S_StartSound(0, sfx_barexp); + ng_state = 10; + } + + if (ng_state == 2) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + cnt_kills[i] += 2; + + if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills) + cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 4) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + cnt_items[i] += 2; + if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems) + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + else + stillticking = true; + } + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 6) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + cnt_secret[i] += 2; + + if (cnt_secret[i] >= (plrs[i].ssecret * 100) / wbs->maxsecret) + cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + cnt_frags[i] += 1; + + if (cnt_frags[i] >= (fsum = WI_fragSum(i))) + cnt_frags[i] = fsum; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_pldeth); + ng_state++; + } + } + else if (ng_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + if ( gamemode == commercial ) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } + } +} + + + +void WI_drawNetgameStats(void) +{ + int i; + int x; + int y; + int pwidth = SHORT(percent->width); + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + // draw stat titles (top line) + V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width), + NG_STATSY, kills); + + V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width), + NG_STATSY, items); + + V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width), + NG_STATSY, secret); + + if (dofrags) + V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width), + NG_STATSY, frags); + + // draw stats + y = NG_STATSY + SHORT(kills->height); + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (!playeringame[i]) + continue; + + x = NG_STATSX; + V_DrawPatch(x-SHORT(p[i]->width), y, p[i]); + + if (i == me) + V_DrawPatch(x-SHORT(p[i]->width), y, star); + + x += NG_SPACINGX; + WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX; + WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX; + WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX; + + if (dofrags) + WI_drawNum(x, y+10, cnt_frags[i], -1); + + y += WI_SPACINGY; + } + +} + +static int sp_state; + +void WI_initStats(void) +{ + state = StatCount; + acceleratestage = 0; + sp_state = 1; + cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; + cnt_time = cnt_par = -1; + cnt_pause = TICRATE; + + WI_initAnimatedBack(); +} + +void WI_updateStats(void) +{ + + WI_updateAnimatedBack(); + + if (acceleratestage && sp_state != 10) + { + acceleratestage = 0; + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret; + cnt_time = plrs[me].stime / TICRATE; + cnt_par = wbs->partime / TICRATE; + S_StartSound(0, sfx_barexp); + sp_state = 10; + } + + if (sp_state == 2) + { + cnt_kills[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) + { + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 4) + { + cnt_items[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) + { + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 6) + { + cnt_secret[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret) + { + cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + + else if (sp_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + cnt_time += 3; + + if (cnt_time >= plrs[me].stime / TICRATE) + cnt_time = plrs[me].stime / TICRATE; + + cnt_par += 3; + + if (cnt_par >= wbs->partime / TICRATE) + { + cnt_par = wbs->partime / TICRATE; + + if (cnt_time >= plrs[me].stime / TICRATE) + { + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + } + else if (sp_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + + if (gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (sp_state & 1) + { + if (!--cnt_pause) + { + sp_state++; + cnt_pause = TICRATE; + } + } + +} + +void WI_drawStats(void) +{ + // line height + int lh; + + lh = (3*SHORT(num[0]->height))/2; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + V_DrawPatch(SP_STATSX, SP_STATSY, kills); + WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]); + + V_DrawPatch(SP_STATSX, SP_STATSY+lh, items); + WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]); + + V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret); + WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); + + V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch); + WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time); + + if (wbs->epsd < 3) + { + V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par); + WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par); + } + +} + +void WI_checkForAccelerate(void) +{ + int i; + player_t *player; + + // check for button presses to skip delays + for (i=0, player = players ; i<MAXPLAYERS ; i++, player++) + { + if (playeringame[i]) + { + if (player->cmd.buttons & BT_ATTACK) + { + if (!player->attackdown) + acceleratestage = 1; + player->attackdown = true; + } + else + player->attackdown = false; + if (player->cmd.buttons & BT_USE) + { + if (!player->usedown) + acceleratestage = 1; + player->usedown = true; + } + else + player->usedown = false; + } + } +} + + + +// Updates stuff each tick +void WI_Ticker(void) +{ + // counter for general background animation + bcnt++; + + if (bcnt == 1) + { + // intermission music + if ( gamemode == commercial ) + S_ChangeMusic(mus_dm2int, true); + else + S_ChangeMusic(mus_inter, true); + } + + WI_checkForAccelerate(); + + switch (state) + { + case StatCount: + if (deathmatch) WI_updateDeathmatchStats(); + else if (netgame) WI_updateNetgameStats(); + else WI_updateStats(); + break; + + case ShowNextLoc: + WI_updateShowNextLoc(); + break; + + case NoState: + WI_updateNoState(); + break; + } + +} + +typedef void (*load_callback_t)(char *lumpname, patch_t **variable); + +// Common load/unload function. Iterates over all the graphics +// lumps to be loaded/unloaded into memory. + +static void WI_loadUnloadData(load_callback_t callback) +{ + int i, j; + char name[9]; + anim_t *a; + + if (gamemode == commercial) + { + for (i=0 ; i<NUMCMAPS ; i++) + { + sprintf(name, DEH_String("CWILV%2.2d"), i); + callback(name, &lnames[i]); + } + } + else + { + for (i=0 ; i<NUMMAPS ; i++) + { + sprintf(name, DEH_String("WILV%d%d"), wbs->epsd, i); + callback(name, &lnames[i]); + } + + // you are here + callback(DEH_String("WIURH0"), &yah[0]); + + // you are here (alt.) + callback(DEH_String("WIURH1"), &yah[1]); + + // splat + callback(DEH_String("WISPLAT"), &splat[0]); + + if (wbs->epsd < 3) + { + for (j=0;j<NUMANIMS[wbs->epsd];j++) + { + a = &anims[wbs->epsd][j]; + for (i=0;i<a->nanims;i++) + { + // MONDO HACK! + if (wbs->epsd != 1 || j != 8) + { + // animations + sprintf(name, DEH_String("WIA%d%.2d%.2d"), + wbs->epsd, j, i); + callback(name, &a->p[i]); + } + else + { + // HACK ALERT! + a->p[i] = anims[1][4].p[i]; + } + } + } + } + } + + // More hacks on minus sign. + callback(DEH_String("WIMINUS"), &wiminus); + + for (i=0;i<10;i++) + { + // numbers 0-9 + sprintf(name, DEH_String("WINUM%d"), i); + callback(name, &num[i]); + } + + // percent sign + callback(DEH_String("WIPCNT"), &percent); + + // "finished" + callback(DEH_String("WIF"), &finished); + + // "entering" + callback(DEH_String("WIENTER"), &entering); + + // "kills" + callback(DEH_String("WIOSTK"), &kills); + + // "scrt" + callback(DEH_String("WIOSTS"), &secret); + + // "secret" + callback(DEH_String("WISCRT2"), &sp_secret); + + // french wad uses WIOBJ (?) + if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0) + { + // "items" + if (netgame && !deathmatch) + callback(DEH_String("WIOBJ"), &items); + else + callback(DEH_String("WIOSTI"), &items); + } else { + callback(DEH_String("WIOSTI"), &items); + } + + // "frgs" + callback(DEH_String("WIFRGS"), &frags); + + // ":" + callback(DEH_String("WICOLON"), &colon); + + // "time" + callback(DEH_String("WITIME"), &timepatch); + + // "sucks" + callback(DEH_String("WISUCKS"), &sucks); + + // "par" + callback(DEH_String("WIPAR"), &par); + + // "killers" (vertical) + callback(DEH_String("WIKILRS"), &killers); + + // "victims" (horiz) + callback(DEH_String("WIVCTMS"), &victims); + + // "total" + callback(DEH_String("WIMSTT"), &total); + + for (i=0 ; i<MAXPLAYERS ; i++) + { + // "1,2,3,4" + sprintf(name, DEH_String("STPB%d"), i); + callback(name, &p[i]); + + // "1,2,3,4" + sprintf(name, DEH_String("WIBP%d"), i+1); + callback(name, &bp[i]); + } + + // Background image + + if (gamemode == commercial) + { + strcpy(name, DEH_String("INTERPIC")); + } + else if (gamemode == retail && wbs->epsd == 3) + { + strcpy(name, DEH_String("INTERPIC")); + } + else + { + sprintf(name, DEH_String("WIMAP%d"), wbs->epsd); + } + + // Draw backdrop and save to a temporary buffer + + callback(name, &background); +} + +static void WI_loadCallback(char *name, patch_t **variable) +{ + *variable = W_CacheLumpName(name, PU_STATIC); +} + +void WI_loadData(void) +{ + if (gamemode == commercial) + { + NUMCMAPS = 32; + lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS, + PU_STATIC, NULL); + } + else + { + lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS, + PU_STATIC, NULL); + } + + WI_loadUnloadData(WI_loadCallback); + + // These two graphics are special cased because we're sharing + // them with the status bar code + + // your face + star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC); + + // dead face + bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC); +} + +static void WI_unloadCallback(char *name, patch_t **variable) +{ + W_ReleaseLumpName(name); + *variable = NULL; +} + +void WI_unloadData(void) +{ + WI_loadUnloadData(WI_unloadCallback); + + // We do not free these lumps as they are shared with the status + // bar code. + + // W_ReleaseLumpName("STFST01"); + // W_ReleaseLumpName("STFDEAD0"); +} + +void WI_Drawer (void) +{ + switch (state) + { + case StatCount: + if (deathmatch) + WI_drawDeathmatchStats(); + else if (netgame) + WI_drawNetgameStats(); + else + WI_drawStats(); + break; + + case ShowNextLoc: + WI_drawShowNextLoc(); + break; + + case NoState: + WI_drawNoState(); + break; + } +} + + +void WI_initVariables(wbstartstruct_t* wbstartstruct) +{ + + wbs = wbstartstruct; + +#ifdef RANGECHECKING + if (gamemode != commercial) + { + if ( gamemode == retail ) + RNGCHECK(wbs->epsd, 0, 3); + else + RNGCHECK(wbs->epsd, 0, 2); + } + else + { + RNGCHECK(wbs->last, 0, 8); + RNGCHECK(wbs->next, 0, 8); + } + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); +#endif + + acceleratestage = 0; + cnt = bcnt = 0; + firstrefresh = 1; + me = wbs->pnum; + plrs = wbs->plyr; + + if (!wbs->maxkills) + wbs->maxkills = 1; + + if (!wbs->maxitems) + wbs->maxitems = 1; + + if (!wbs->maxsecret) + wbs->maxsecret = 1; + + if ( gamemode != retail ) + if (wbs->epsd > 2) + wbs->epsd -= 3; +} + +void WI_Start(wbstartstruct_t* wbstartstruct) +{ + WI_initVariables(wbstartstruct); + WI_loadData(); + + if (deathmatch) + WI_initDeathmatchStats(); + else if (netgame) + WI_initNetgameStats(); + else + WI_initStats(); +} |