doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

wi_stuff.c (23496B)


      1 #include <stdio.h>
      2 
      3 #include "m_swap.h"
      4 #include "z_zone.h"
      5 #include "m_random.h"
      6 #include "i_system.h"
      7 #include "w_wad.h"
      8 #include "g_game.h"
      9 #include "r_local.h"
     10 #include "s_sound.h"
     11 #include "doomstat.h"
     12 #include "sounds.h"
     13 #include "v_video.h"
     14 #include "wi_stuff.h"
     15 
     16 #define NUMEPISODES	4
     17 #define NUMMAPS		9
     18 #define WI_TITLEY		2
     19 #define WI_SPACINGY    		33
     20 #define SP_STATSX		50
     21 #define SP_STATSY		50
     22 #define SP_TIMEX		16
     23 #define SP_TIMEY		(SCREENHEIGHT-32)
     24 #define NG_STATSY		50
     25 #define NG_STATSX		(32 + SHORT(star->width)/2 + 32*!dofrags)
     26 #define NG_SPACINGX    		64
     27 #define DM_MATRIXX		42
     28 #define DM_MATRIXY		68
     29 #define DM_SPACINGX		40
     30 #define DM_TOTALSX		269
     31 #define DM_KILLERSX		10
     32 #define DM_KILLERSY		100
     33 #define DM_VICTIMSX    		5
     34 #define DM_VICTIMSY		50
     35 #define FB 0
     36 #define SP_KILLS		0
     37 #define SP_ITEMS		2
     38 #define SP_SECRET		4
     39 #define SP_FRAGS		6
     40 #define SP_TIME			8
     41 #define SP_PAR			ST_TIME
     42 #define SP_PAUSE		1
     43 #define SHOWNEXTLOCDELAY	4
     44 
     45 
     46 typedef enum {
     47 	ANIM_ALWAYS,
     48 	ANIM_RANDOM,
     49 	ANIM_LEVEL
     50 } animenum_t;
     51 
     52 typedef struct {
     53 	int x;
     54 	int y;
     55 } point_t;
     56 
     57 typedef struct {
     58 	animenum_t type;
     59 	int		period;
     60 	int		nanims;
     61 	point_t	loc;
     62 	int		data1;
     63 	int		data2;
     64 	patch_t*	p[3];
     65 	int		nexttic;
     66 	int		lastdrawn;
     67 	int		ctr;
     68 	int		state;
     69 } anim_t;
     70 
     71 static point_t lnodes[NUMEPISODES][NUMMAPS] = {
     72 	{
     73 		{ 185, 164 },	
     74 		{ 148, 143 },	
     75 		{ 69, 122 },	
     76 		{ 209, 102 },	
     77 		{ 116, 89 },	
     78 		{ 166, 55 },	
     79 		{ 71, 56 },	
     80 		{ 135, 29 },	
     81 		{ 71, 24 }	
     82 	},
     83 	{
     84 		{ 254, 25 },	
     85 		{ 97, 50 },	
     86 		{ 188, 64 },	
     87 		{ 128, 78 },	
     88 		{ 214, 92 },	
     89 		{ 133, 130 },	
     90 		{ 208, 136 },	
     91 		{ 148, 140 },	
     92 		{ 235, 158 }	
     93 	},
     94 	{
     95 		{ 156, 168 },	
     96 		{ 48, 154 },	
     97 		{ 174, 95 },	
     98 		{ 265, 75 },	
     99 		{ 130, 48 },	
    100 		{ 279, 23 },	
    101 		{ 198, 48 },	
    102 		{ 140, 25 },	
    103 		{ 281, 136 }	
    104 	}
    105 };
    106 
    107 static anim_t epsd0animinfo[] = {
    108 	{ ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 } },
    109 	{ ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 } },
    110 	{ ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 } },
    111 	{ ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 } },
    112 	{ ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 } },
    113 	{ ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 } },
    114 	{ ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 } },
    115 	{ ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 } },
    116 	{ ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 } },
    117 	{ ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 } }
    118 };
    119 
    120 static anim_t epsd1animinfo[] = {
    121 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1 },
    122 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2 },
    123 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3 },
    124 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4 },
    125 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5 },
    126 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6 },
    127 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7 },
    128 	{ ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8 },
    129 	{ ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8 }
    130 };
    131 
    132 static anim_t epsd2animinfo[] = {
    133 	{ ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 } },
    134 	{ ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 } },
    135 	{ ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 } },
    136 	{ ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 } },
    137 	{ ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 } },
    138 	{ ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 } }
    139 };
    140 
    141 static int NUMANIMS[NUMEPISODES] = {
    142 	sizeof(epsd0animinfo)/sizeof(anim_t),
    143 	sizeof(epsd1animinfo)/sizeof(anim_t),
    144 	sizeof(epsd2animinfo)/sizeof(anim_t)
    145 };
    146 
    147 static anim_t *anims[NUMEPISODES] = {
    148 	epsd0animinfo,
    149 	epsd1animinfo,
    150 	epsd2animinfo
    151 };
    152 
    153 static int		acceleratestage;
    154 static int		me;
    155 static stateenum_t	state;
    156 static wbstartstruct_t*	wbs;
    157 static wbplayerstruct_t* plrs;
    158 static int 		cnt;
    159 static int 		bcnt;
    160 static int 		firstrefresh;
    161 static int		cnt_kills[MAXPLAYERS];
    162 static int		cnt_items[MAXPLAYERS];
    163 static int		cnt_secret[MAXPLAYERS];
    164 static int		cnt_time;
    165 static int		cnt_par;
    166 static int		cnt_pause;
    167 static patch_t*		bg;
    168 static patch_t*		yah[2];
    169 static patch_t*		splat;
    170 static patch_t*		percent;
    171 static patch_t*		colon;
    172 static patch_t*		num[10];
    173 static patch_t*		wiminus;
    174 static patch_t*		finished;
    175 static patch_t*		entering;
    176 static patch_t*		sp_secret;
    177 static patch_t*		kills;
    178 static patch_t*		secret;
    179 static patch_t*		items;
    180 static patch_t*		frags;
    181 static patch_t*		time;
    182 static patch_t*		par;
    183 static patch_t*		sucks;
    184 static patch_t*		killers;
    185 static patch_t*		victims;
    186 static patch_t*		total;
    187 static patch_t*		star;
    188 static patch_t*		bstar;
    189 static patch_t*		p[MAXPLAYERS];
    190 static patch_t*		bp[MAXPLAYERS];
    191 static patch_t**	lnames;
    192 static boolean		snl_pointeron = false;
    193 static int		dm_state;
    194 static int		dm_frags[MAXPLAYERS][MAXPLAYERS];
    195 static int		dm_totals[MAXPLAYERS];
    196 static int	cnt_frags[MAXPLAYERS];
    197 static int	dofrags;
    198 static int	ng_state;
    199 static int	sp_state;
    200 
    201 void
    202 WI_slamBackground()
    203 {
    204 	memcpy(screens[0], screens[1], SCREENWIDTH * SCREENHEIGHT);
    205 	V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
    206 }
    207 
    208 boolean
    209 WI_Responder(event_t* ev)
    210 {
    211 	return false;
    212 }
    213 
    214 void
    215 WI_drawLF()
    216 {
    217 	int y;
    218 
    219 	y = WI_TITLEY;
    220 	V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2, y, FB, lnames[wbs->last]);
    221 	y += (5*SHORT(lnames[wbs->last]->height))/4;
    222 	V_DrawPatch((SCREENWIDTH - SHORT(finished->width))/2, y, FB, finished);
    223 }
    224 
    225 void
    226 WI_drawEL()
    227 {
    228 	int y;
    229 
    230 	y = WI_TITLEY;
    231 	V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2, y, FB, entering);
    232 	y += (5*SHORT(lnames[wbs->next]->height))/4;
    233 	V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2, y, FB, lnames[wbs->next]);
    234 }
    235 
    236 void
    237 WI_drawOnLnode(int n, patch_t* c[])
    238 {
    239 	int		i, left, top, right, bottom;
    240 	boolean	fits;
    241 
    242 	fits = false;
    243 	i = 0;
    244 	do {
    245 		left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset);
    246 		top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset);
    247 		right = left + SHORT(c[i]->width);
    248 		bottom = top + SHORT(c[i]->height);
    249 		if (left >= 0 && right < SCREENWIDTH && top >= 0 && bottom < SCREENHEIGHT)
    250 			fits = true;
    251 		else
    252 			++i;
    253 	} while (!fits && i!=2);
    254 	if (fits && i<2)
    255 		V_DrawPatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, FB, c[i]);
    256 	else
    257 		printf("Could not place patch on level %d", n+1);
    258 }
    259 
    260 void
    261 WI_initAnimatedBack()
    262 {
    263 	anim_t*	a;
    264 	int		i;
    265 
    266 	if (wbs->epsd > 2) return;
    267 	for (i = 0; i < NUMANIMS[wbs->epsd]; ++i) {
    268 		a = &anims[wbs->epsd][i];
    269 		a->ctr = -1;
    270 		if (a->type == ANIM_ALWAYS) a->nexttic = bcnt + 1 + (M_Random()%a->period);
    271 		if (a->type == ANIM_RANDOM) a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1);
    272 		if (a->type == ANIM_LEVEL) a->nexttic = bcnt + 1;
    273 	}
    274 }
    275 
    276 void
    277 WI_updateAnimatedBack()
    278 {
    279 	anim_t*	a;
    280 	int		i;
    281 
    282 	if (wbs->epsd > 2)
    283 		return;
    284 	for (i = 0; i < NUMANIMS[wbs->epsd]; ++i) {
    285 		a = &anims[wbs->epsd][i];
    286 		if (bcnt == a->nexttic) {
    287 			switch (a->type) {
    288 				case ANIM_ALWAYS:
    289 					if (++a->ctr >= a->nanims)
    290 						a->ctr = 0;
    291 					a->nexttic = bcnt + a->period;
    292 					break;
    293 				case ANIM_RANDOM:
    294 					a->ctr++;
    295 					if (a->ctr == a->nanims) {
    296 						a->ctr = -1;
    297 						a->nexttic = bcnt+a->data2+(M_Random()%a->data1);
    298 					} else a->nexttic = bcnt + a->period;
    299 					break;
    300 				case ANIM_LEVEL:
    301 					if (!(state == StatCount && i == 7) && wbs->next == a->data1) {
    302 						if (++a->ctr == a->nanims)
    303 							a->ctr--;
    304 						a->nexttic = bcnt + a->period;
    305 					}
    306 			}
    307 		}
    308 	}
    309 }
    310 
    311 void
    312 WI_drawAnimatedBack()
    313 {
    314 	anim_t*		a;
    315 	int			i;
    316 
    317 	if (wbs->epsd > 2) return;
    318 	for (i = 0; i < NUMANIMS[wbs->epsd]; ++i) {
    319 		a = &anims[wbs->epsd][i];
    320 		if (a->ctr >= 0)
    321 			V_DrawPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr]);
    322 	}
    323 }
    324 
    325 int
    326 WI_drawNum(int x, int y, int n, int digits)
    327 {
    328 	int		fontwidth, neg, temp;
    329 
    330 	fontwidth = SHORT(num[0]->width);
    331 	if (digits < 0) {
    332 		if (!n)
    333 			digits = 1;
    334 		else {
    335 			digits = 0;
    336 			for (temp = n; temp; temp /= 10) ++digits;
    337 		}
    338 	}
    339 	neg = n < 0;
    340 	if (neg)
    341 		n = -n;
    342 	if (n == 1994)
    343 		return 0;
    344 	while (digits--) {
    345 		x -= fontwidth;
    346 		V_DrawPatch(x, y, FB, num[ n % 10 ]);
    347 		n /= 10;
    348 	}
    349 	if (neg)
    350 		V_DrawPatch(x-=8, y, FB, wiminus);
    351 	return x;
    352 }
    353 
    354 void
    355 WI_drawPercent(int x, int y, int p)
    356 {
    357 	if (p < 0)
    358 		return;
    359 	V_DrawPatch(x, y, FB, percent);
    360 	WI_drawNum(x, y, p, -1);
    361 }
    362 
    363 void
    364 WI_drawTime(int x, int y, int t)
    365 {
    366 	int div, n;
    367 
    368 	if (t < 0)
    369 		return;
    370 	if (t <= 61*59) {
    371 		div = 1;
    372 		do {
    373 			n = (t / div) % 60;
    374 			x = WI_drawNum(x, y, n, 2) - SHORT(colon->width);
    375 			div *= 60;
    376 			if (div==60 || t / div)
    377 				V_DrawPatch(x, y, FB, colon);
    378 			
    379 		} while (t / div);
    380 	} else V_DrawPatch(x - SHORT(sucks->width), y, FB, sucks);
    381 }
    382 
    383 void
    384 WI_initShowNextLoc()
    385 {
    386 	state = ShowNextLoc;
    387 	acceleratestage = 0;
    388 	cnt = SHOWNEXTLOCDELAY * TICRATE;
    389 	WI_initAnimatedBack();
    390 }
    391 
    392 void
    393 WI_drawShowNextLoc()
    394 {
    395 	int i, last;
    396 
    397 	WI_slamBackground();
    398 	WI_drawAnimatedBack();
    399   	if (wbs->epsd > 2) {
    400 	    WI_drawEL();
    401 	    return;
    402 	}
    403 	last = (wbs->last == 8) ? wbs->next - 1 : wbs->last;
    404 	for (i = 0; i <= last; ++i)
    405 	    WI_drawOnLnode(i, &splat);
    406 	if (wbs->didsecret) WI_drawOnLnode(8, &splat);
    407 	if (snl_pointeron) WI_drawOnLnode(wbs->next, yah);
    408 	if (wbs->next != 30) WI_drawEL();
    409 }
    410 
    411 void
    412 WI_drawNoState()
    413 {
    414 	snl_pointeron = true;
    415 	WI_drawShowNextLoc();
    416 }
    417 
    418 int
    419 WI_fragSum(int playernum)
    420 {
    421 	int i, frags;
    422 
    423 	frags = 0;
    424 	for (i = 0; i < MAXPLAYERS; ++i)
    425 		if (playeringame[i] && i!=playernum)
    426 			frags += plrs[playernum].frags[i];
    427 	frags -= plrs[playernum].frags[playernum];
    428 	return frags;
    429 }
    430 
    431 void
    432 WI_initDeathmatchStats()
    433 {
    434 	int i, j;
    435 
    436 	state = StatCount;
    437 	acceleratestage = 0;
    438 	dm_state = 1;
    439 	cnt_pause = TICRATE;
    440 	for (i = 0; i < MAXPLAYERS; ++i) {
    441 		if (playeringame[i]) {
    442 			for (j = 0; j < MAXPLAYERS; ++j)
    443 			if (playeringame[j])
    444 				dm_frags[i][j] = 0;
    445 			dm_totals[i] = 0;
    446 		}
    447 	}
    448 	WI_initAnimatedBack();
    449 }
    450 
    451 void
    452 WI_updateDeathmatchStats()
    453 {
    454 	boolean	stillticking;
    455 	int i, j;
    456 
    457 	WI_updateAnimatedBack();
    458 	if (acceleratestage && dm_state != 4) {
    459 		acceleratestage = 0;
    460 		for (i = 0; i < MAXPLAYERS; ++i) {
    461 			if (playeringame[i]) {
    462 				for (j = 0; j < MAXPLAYERS; ++j)
    463 					if (playeringame[j])
    464 						dm_frags[i][j] = plrs[i].frags[j];
    465 				dm_totals[i] = WI_fragSum(i);
    466 			}
    467 		}
    468 		S_StartSound(0, sfx_barexp);
    469 		dm_state = 4;
    470 	}
    471 	if (dm_state == 2) {
    472 		if (!(bcnt&3))
    473 			S_StartSound(0, sfx_pistol);
    474 		stillticking = false;
    475 		for (i = 0; i < MAXPLAYERS; ++i) {
    476 			if (playeringame[i]) {
    477 				for (j = 0; j < MAXPLAYERS; ++j) {
    478 					if (playeringame[j] && dm_frags[i][j] != plrs[i].frags[j]) {
    479 						if (plrs[i].frags[j] < 0) dm_frags[i][j]--;
    480 						else dm_frags[i][j]++;
    481 						if (dm_frags[i][j] > 99) dm_frags[i][j] = 99;
    482 						if (dm_frags[i][j] < -99) dm_frags[i][j] = -99;
    483 						stillticking = true;
    484 					}
    485 				}
    486 				dm_totals[i] = WI_fragSum(i);
    487 				if (dm_totals[i] > 99) dm_totals[i] = 99;
    488 				if (dm_totals[i] < -99) dm_totals[i] = -99;
    489 			}
    490 		}
    491 		if (!stillticking) {
    492 			S_StartSound(0, sfx_barexp);
    493 			dm_state++;
    494 		}
    495 	}
    496 	if (dm_state == 4) {
    497 		if (acceleratestage) {
    498 			S_StartSound(0, sfx_slop);
    499 			WI_initShowNextLoc();
    500 		}
    501 	}
    502 	if (dm_state & 1) {
    503 		if (!--cnt_pause) {
    504 			dm_state++;
    505 			cnt_pause = TICRATE;
    506 		}
    507 	}
    508 }
    509 
    510 void
    511 WI_drawDeathmatchStats()
    512 {
    513 
    514 	int		i, j, x, y, w;
    515 	
    516 	WI_slamBackground();
    517 	WI_drawAnimatedBack();
    518 	WI_drawLF();
    519 	V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2, DM_MATRIXY-WI_SPACINGY+10, FB, total);
    520 	V_DrawPatch(DM_KILLERSX, DM_KILLERSY, FB, killers);
    521 	V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims);
    522 	x = DM_MATRIXX + DM_SPACINGX;
    523 	y = DM_MATRIXY;
    524 	for (i = 0; i < MAXPLAYERS; ++i) {
    525 		if (playeringame[i]) {
    526 			V_DrawPatch(x-SHORT(p[i]->width)/2, DM_MATRIXY - WI_SPACINGY, FB, p[i]);
    527 			V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, FB, p[i]);
    528 			if (i == me) {
    529 				V_DrawPatch(x-SHORT(p[i]->width)/2, DM_MATRIXY - WI_SPACINGY, FB, bstar);
    530 				V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, FB, star);
    531 			}
    532 		}
    533 		x += DM_SPACINGX;
    534 		y += WI_SPACINGY;
    535 	}
    536 	y = DM_MATRIXY+10;
    537 	w = SHORT(num[0]->width);
    538 	for (i = 0; i < MAXPLAYERS; ++i) {
    539 		x = DM_MATRIXX + DM_SPACINGX;
    540 		if (playeringame[i]) {
    541 			for (j = 0; j < MAXPLAYERS; ++j) {
    542 				if (playeringame[j])
    543 					WI_drawNum(x+w, y, dm_frags[i][j], 2);
    544 				x += DM_SPACINGX;
    545 			}
    546 			WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
    547 		}
    548 		y += WI_SPACINGY;
    549 	}
    550 }
    551 
    552 void
    553 WI_initNetgameStats()
    554 {
    555 	int i;
    556 
    557 	state = StatCount;
    558 	acceleratestage = 0;
    559 	ng_state = 1;
    560 	cnt_pause = TICRATE;
    561 	for (i = 0; i < MAXPLAYERS; ++i) {
    562 		if (!playeringame[i])
    563 			continue;
    564 		cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
    565 		dofrags += WI_fragSum(i);
    566 	}
    567 	dofrags = !!dofrags;
    568 	WI_initAnimatedBack();
    569 }
    570 
    571 void
    572 WI_updateNetgameStats()
    573 {
    574 	int i, fsum;
    575 	boolean	stillticking;
    576 
    577 	WI_updateAnimatedBack();
    578 	if (acceleratestage && ng_state != 10) {
    579 		acceleratestage = 0;
    580 		for (i = 0; i < MAXPLAYERS; ++i) {
    581 			if (!playeringame[i]) 
    582 				continue;
    583 			cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
    584 			cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
    585 			cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
    586 			if (dofrags)
    587 				cnt_frags[i] = WI_fragSum(i);
    588 		}
    589 		S_StartSound(0, sfx_barexp);
    590 		ng_state = 10;
    591 	}
    592 	switch (ng_state) {
    593 		case 2:
    594 			if (!(bcnt&3))
    595 				S_StartSound(0, sfx_pistol);
    596 			stillticking = false;
    597 			for (i = 0; i < MAXPLAYERS; ++i) {
    598 				if (!playeringame[i])
    599 					continue;
    600 				cnt_kills[i] += 2;
    601 				if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills)
    602 					cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
    603 				else stillticking = true;
    604 			}
    605 			if (!stillticking) {
    606 				S_StartSound(0, sfx_barexp);
    607 				++ng_state;
    608 			}
    609 			break;
    610 		case 4:
    611 			if (!(bcnt&3))
    612 				S_StartSound(0, sfx_pistol);
    613 			stillticking = false;
    614 			for (i = 0; i < MAXPLAYERS; ++i) {
    615 				if (!playeringame[i])
    616 					continue;
    617 				cnt_items[i] += 2;
    618 				if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems)
    619 					cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
    620 				else stillticking = true;
    621 			}
    622 			if (!stillticking) {
    623 				S_StartSound(0, sfx_barexp);
    624 				++ng_state;
    625 			}
    626 			break;
    627 		case 6:
    628 			if (!(bcnt&3))
    629 				S_StartSound(0, sfx_pistol);
    630 			stillticking = false;
    631 			for (i = 0; i < MAXPLAYERS; ++i) {
    632 				if (!playeringame[i])
    633 					continue;
    634 				cnt_secret[i] += 2;
    635 				if (cnt_secret[i] >= (plrs[i].ssecret * 100) / wbs->maxsecret)
    636 					cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
    637 				else stillticking = true;
    638 			}
    639 			if (!stillticking) {
    640 				S_StartSound(0, sfx_barexp);
    641 				ng_state += 1 + 2*!dofrags;
    642 			}
    643 			break;
    644 		case 8:
    645 			if (!(bcnt&3))
    646 				S_StartSound(0, sfx_pistol);
    647 			stillticking = false;
    648 			for (i = 0; i < MAXPLAYERS; ++i) {
    649 				if (!playeringame[i])
    650 					continue;
    651 				cnt_frags[i] += 1;
    652 				if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
    653 					cnt_frags[i] = fsum;
    654 				else stillticking = true;
    655 			}
    656 			if (!stillticking) {
    657 				S_StartSound(0, sfx_pldeth);
    658 				++ng_state;
    659 			}
    660 			break;
    661 		case 10:
    662 			if (acceleratestage) {
    663 				S_StartSound(0, sfx_sgcock);
    664 				WI_initShowNextLoc();
    665 			}
    666 	}
    667 	if (ng_state & 1) {
    668 		if (!--cnt_pause) {
    669 			++ng_state;
    670 			cnt_pause = TICRATE;
    671 		}
    672 	}
    673 }
    674 
    675 void
    676 WI_drawNetgameStats()
    677 {
    678 	int		i, x, y, pwidth;
    679 
    680 	pwidth = SHORT(percent->width);
    681 	WI_slamBackground();
    682 	WI_drawAnimatedBack();
    683 	WI_drawLF();
    684 	V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width), NG_STATSY, FB, kills);
    685 	V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width), NG_STATSY, FB, items);
    686 	V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width), NG_STATSY, FB, secret);
    687 	if (dofrags)
    688 		V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width), NG_STATSY, FB, frags);
    689 	y = NG_STATSY + SHORT(kills->height);
    690 	for (i = 0; i < MAXPLAYERS; ++i) {
    691 		if (!playeringame[i])
    692 			continue;
    693 		x = NG_STATSX;
    694 		V_DrawPatch(x-SHORT(p[i]->width), y, FB, p[i]);
    695 		if (i == me)
    696 			V_DrawPatch(x-SHORT(p[i]->width), y, FB, star);
    697 		x += NG_SPACINGX;
    698 		WI_drawPercent(x-pwidth, y+10, cnt_kills[i]);	x += NG_SPACINGX;
    699 		WI_drawPercent(x-pwidth, y+10, cnt_items[i]);	x += NG_SPACINGX;
    700 		WI_drawPercent(x-pwidth, y+10, cnt_secret[i]);	x += NG_SPACINGX;
    701 		if (dofrags)
    702 			WI_drawNum(x, y+10, cnt_frags[i], -1);
    703 		y += WI_SPACINGY;
    704 	}
    705 }
    706 
    707 void
    708 WI_initStats()
    709 {
    710 	state = StatCount;
    711 	acceleratestage = 0;
    712 	sp_state = 1;
    713 	cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
    714 	cnt_time = cnt_par = -1;
    715 	cnt_pause = TICRATE;
    716 	WI_initAnimatedBack();
    717 }
    718 
    719 void
    720 WI_updateStats()
    721 {
    722 	WI_updateAnimatedBack();
    723 	if (acceleratestage && sp_state != 10) {
    724 		acceleratestage = 0;
    725 		cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
    726 		cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
    727 		cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
    728 		cnt_time = plrs[me].stime / TICRATE;
    729 		cnt_par = wbs->partime / TICRATE;
    730 		S_StartSound(0, sfx_barexp);
    731 		sp_state = 10;
    732 	}
    733 	switch (sp_state) {
    734 		case 2:
    735 			cnt_kills[0] += 2;
    736 			if (!(bcnt&3))
    737 				S_StartSound(0, sfx_pistol);
    738 			if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) {
    739 				cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
    740 				S_StartSound(0, sfx_barexp);
    741 				++sp_state;
    742 			}
    743 			break;
    744 		case 4:
    745 			cnt_items[0] += 2;
    746 			if (!(bcnt&3))
    747 				S_StartSound(0, sfx_pistol);
    748 			if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) {
    749 				cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
    750 				S_StartSound(0, sfx_barexp);
    751 				++sp_state;
    752 			}
    753 			break;
    754 		case 6:
    755 			cnt_secret[0] += 2;
    756 			if (!(bcnt&3))
    757 				S_StartSound(0, sfx_pistol);
    758 			if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret) {
    759 				cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
    760 				S_StartSound(0, sfx_barexp);
    761 				++sp_state;
    762 			}
    763 			break;
    764 		case 8:
    765 			if (!(bcnt&3))
    766 				S_StartSound(0, sfx_pistol);
    767 			cnt_time += 3;
    768 			if (cnt_time >= plrs[me].stime / TICRATE)
    769 				cnt_time = plrs[me].stime / TICRATE;
    770 			cnt_par += 3;
    771 			if (cnt_par >= wbs->partime / TICRATE) {
    772 				cnt_par = wbs->partime / TICRATE;
    773 				if (cnt_time >= plrs[me].stime / TICRATE) {
    774 					S_StartSound(0, sfx_barexp);
    775 					++sp_state;
    776 				}
    777 			}
    778 			break;
    779 		case 10:
    780 			if (acceleratestage) {
    781 				S_StartSound(0, sfx_sgcock);
    782 				WI_initShowNextLoc();
    783 			}
    784 	}
    785 	if (sp_state & 1) {
    786 		if (!--cnt_pause) {
    787 			++sp_state;
    788 			cnt_pause = TICRATE;
    789 		}
    790 	}
    791 }
    792 
    793 void
    794 WI_drawStats()
    795 {
    796 	int lh;	
    797 
    798 	lh = (3*SHORT(num[0]->height))/2;
    799 	WI_slamBackground();
    800 	WI_drawAnimatedBack();
    801 	WI_drawLF();
    802 	V_DrawPatch(SP_STATSX, SP_STATSY, FB, kills);
    803 	WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]);
    804 	V_DrawPatch(SP_STATSX, SP_STATSY+lh, FB, items);
    805 	WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
    806 	V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret);
    807 	WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
    808 	V_DrawPatch(SP_TIMEX, SP_TIMEY, FB, time);
    809 	WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time);
    810 	if (wbs->epsd < 3) {
    811 		V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, FB, par);
    812 		WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par);
    813 	}
    814 }
    815 
    816 void
    817 WI_checkForAccelerate()
    818 {
    819 	player_t* player;
    820 	int       i;
    821 	
    822 	for (i = 0, player = players; i < MAXPLAYERS; ++i, ++player) {
    823 		if (playeringame[i]) {
    824 			if (player->cmd.buttons & BT_ATTACK) {
    825 				if (!player->attackdown)
    826 					acceleratestage = 1;
    827 				player->attackdown = true;
    828 			} else player->attackdown = false;
    829 			if (player->cmd.buttons & BT_USE) {
    830 				if (!player->usedown)
    831 					acceleratestage = 1;
    832 				player->usedown = true;
    833 			} else player->usedown = false;
    834 		}
    835 	}
    836 }
    837 
    838 void
    839 WI_initNoState()
    840 {
    841 	state = NoState;
    842 	acceleratestage = 0;
    843 	cnt = 10;
    844 }
    845 
    846 void
    847 WI_updateShowNextLoc()
    848 {
    849 	WI_updateAnimatedBack();
    850 	if (!--cnt || acceleratestage)
    851 		WI_initNoState();
    852 	else
    853 		snl_pointeron = (cnt & 31) < 20;
    854 }
    855 
    856 
    857 void
    858 WI_updateNoState()
    859 {
    860 	WI_updateAnimatedBack();
    861 	if (!--cnt)
    862 		G_WorldDone();
    863 }
    864 
    865 void
    866 WI_Ticker()
    867 {
    868 	bcnt++;
    869 
    870 	if (bcnt == 1)
    871 		S_ChangeMusic(mus_inter, true);
    872 	WI_checkForAccelerate();
    873 	switch (state) {
    874 		case StatCount:
    875 			if (deathmatch) WI_updateDeathmatchStats();
    876 			else if (netgame) WI_updateNetgameStats();
    877 			else WI_updateStats();
    878 			break;
    879 		case ShowNextLoc:
    880 			WI_updateShowNextLoc();
    881 			break;
    882 		case NoState:
    883 			WI_updateNoState();
    884 	}
    885 }
    886 
    887 void
    888 WI_loadData()
    889 {
    890 	char	name[10];
    891 	anim_t*	a;
    892 	int		i, j;
    893 
    894 	sprintf(name, "WIMAP%d", wbs->epsd);
    895 	bg = W_CacheLumpName(name, PU_CACHE);
    896 	V_DrawPatch(0, 0, 1, bg);
    897 	lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS, PU_STATIC, 0);
    898 	for (i = 0; i < NUMMAPS; ++i) {
    899 	    sprintf(name, "WILV%d%d", wbs->epsd, i);
    900 	    lnames[i] = W_CacheLumpName(name, PU_STATIC);
    901 	}
    902 	yah[0] = W_CacheLumpName("WIURH0", PU_STATIC);
    903 	yah[1] = W_CacheLumpName("WIURH1", PU_STATIC);
    904 	splat = W_CacheLumpName("WISPLAT", PU_STATIC);
    905 	if (wbs->epsd < 3) {
    906 	    for (j = 0; j < NUMANIMS[wbs->epsd]; ++j) {
    907 			a = &anims[wbs->epsd][j];
    908 			for (i = 0; i < a->nanims; ++i) {
    909 				if (wbs->epsd != 1 || j != 8) {
    910 					sprintf(name, "WIA%d%02d%02d", wbs->epsd % 10, j % 100, i % 100);
    911 					a->p[i] = W_CacheLumpName(name, PU_STATIC);
    912 				} else a->p[i] = anims[1][4].p[i];
    913 			}
    914 		}
    915 	}
    916 	wiminus = W_CacheLumpName("WIMINUS", PU_STATIC);
    917 	for (i = 0; i < 10; ++i) {
    918 		sprintf(name, "WINUM%d", i);
    919 		num[i] = W_CacheLumpName(name, PU_STATIC);
    920 	}
    921 	percent = W_CacheLumpName("WIPCNT", PU_STATIC);
    922 	finished = W_CacheLumpName("WIF", PU_STATIC);
    923 	entering = W_CacheLumpName("WIENTER", PU_STATIC);
    924 	kills = W_CacheLumpName("WIOSTK", PU_STATIC);
    925 	secret = W_CacheLumpName("WIOSTS", PU_STATIC);
    926 	sp_secret = W_CacheLumpName("WISCRT2", PU_STATIC);
    927 	items = W_CacheLumpName("WIOSTI", PU_STATIC);
    928 	frags = W_CacheLumpName("WIFRGS", PU_STATIC);
    929 	colon = W_CacheLumpName("WICOLON", PU_STATIC);
    930 	time = W_CacheLumpName("WITIME", PU_STATIC);
    931 	sucks = W_CacheLumpName("WISUCKS", PU_STATIC);
    932 	par = W_CacheLumpName("WIPAR", PU_STATIC);
    933 	killers = W_CacheLumpName("WIKILRS", PU_STATIC);
    934 	victims = W_CacheLumpName("WIVCTMS", PU_STATIC);
    935 	total = W_CacheLumpName("WIMSTT", PU_STATIC);
    936 	star = W_CacheLumpName("STFST01", PU_STATIC);
    937 	bstar = W_CacheLumpName("STFDEAD0", PU_STATIC);
    938 	for (i = 0; i < MAXPLAYERS; ++i) {
    939 		sprintf(name, "STPB%d", i);
    940 		p[i] = W_CacheLumpName(name, PU_STATIC);
    941 		sprintf(name, "WIBP%d", i+1);
    942 		bp[i] = W_CacheLumpName(name, PU_STATIC);
    943 	}
    944 }
    945 
    946 void
    947 WI_unloadData()
    948 {
    949 	int i, j;
    950 
    951 	Z_ChangeTag(wiminus, PU_CACHE);
    952 	for (i = 0; i < 10; ++i)
    953 		Z_ChangeTag(num[i], PU_CACHE);
    954 	Z_ChangeTag(yah[0], PU_CACHE);
    955 	Z_ChangeTag(yah[1], PU_CACHE);
    956 	Z_ChangeTag(splat, PU_CACHE);
    957 	for (i = 0; i < NUMMAPS; ++i)
    958 	    Z_ChangeTag(lnames[i], PU_CACHE);
    959 	if (wbs->epsd < 3) {
    960 	    for (j = 0; j < NUMANIMS[wbs->epsd]; ++j) {
    961 			if (wbs->epsd != 1 || j != 8)
    962 				for (i = 0; i < anims[wbs->epsd][j].nanims; ++i)
    963 					Z_ChangeTag(anims[wbs->epsd][j].p[i], PU_CACHE);
    964 	    }
    965 	}
    966 	Z_Free(lnames);
    967 	Z_ChangeTag(percent, PU_CACHE);
    968 	Z_ChangeTag(colon, PU_CACHE);
    969 	Z_ChangeTag(finished, PU_CACHE);
    970 	Z_ChangeTag(entering, PU_CACHE);
    971 	Z_ChangeTag(kills, PU_CACHE);
    972 	Z_ChangeTag(secret, PU_CACHE);
    973 	Z_ChangeTag(sp_secret, PU_CACHE);
    974 	Z_ChangeTag(items, PU_CACHE);
    975 	Z_ChangeTag(frags, PU_CACHE);
    976 	Z_ChangeTag(time, PU_CACHE);
    977 	Z_ChangeTag(sucks, PU_CACHE);
    978 	Z_ChangeTag(par, PU_CACHE);
    979 	Z_ChangeTag(victims, PU_CACHE);
    980 	Z_ChangeTag(killers, PU_CACHE);
    981 	Z_ChangeTag(total, PU_CACHE);
    982 	for (i = 0; i < MAXPLAYERS; ++i)
    983 		Z_ChangeTag(p[i], PU_CACHE);
    984 	for (i = 0; i < MAXPLAYERS; ++i)
    985 		Z_ChangeTag(bp[i], PU_CACHE);
    986 }
    987 
    988 void
    989 WI_End()
    990 {
    991 	WI_unloadData();
    992 }
    993 
    994 void
    995 WI_Drawer()
    996 {
    997 	switch (state) {
    998 		case StatCount:
    999 			if (deathmatch) WI_drawDeathmatchStats();
   1000 			else if (netgame) WI_drawNetgameStats();
   1001 			else WI_drawStats();
   1002 			break;
   1003 		case ShowNextLoc:
   1004 			WI_drawShowNextLoc();
   1005 			break;
   1006 		case NoState:
   1007 			WI_drawNoState();
   1008 		}
   1009 }
   1010 
   1011 void
   1012 WI_initVariables(wbstartstruct_t* wbstartstruct)
   1013 {
   1014 	wbs = wbstartstruct;
   1015 	acceleratestage = cnt = bcnt = 0;
   1016 	firstrefresh = 1;
   1017 	me = wbs->pnum;
   1018 	plrs = wbs->plyr;
   1019 	if (!wbs->maxkills) wbs->maxkills = 1;
   1020 	if (!wbs->maxitems) wbs->maxitems = 1;
   1021 	if (!wbs->maxsecret) wbs->maxsecret = 1;
   1022 	if (wbs->epsd > 2) wbs->epsd -= 3;
   1023 }
   1024 
   1025 void
   1026 WI_Start(wbstartstruct_t* wbstartstruct)
   1027 {
   1028 
   1029 	WI_initVariables(wbstartstruct);
   1030 	WI_loadData();
   1031 	if (deathmatch) WI_initDeathmatchStats();
   1032 	else if (netgame) WI_initNetgameStats();
   1033 	else WI_initStats();
   1034 }