doom

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

f_finale.c (8910B)


      1 #include <ctype.h>
      2 
      3 #include "doomdef.h"
      4 #include "i_system.h"
      5 #include "z_zone.h"
      6 #include "v_video.h"
      7 #include "w_wad.h"
      8 #include "s_sound.h"
      9 #include "sounds.h"
     10 #include "doomstat.h"
     11 #include "r_state.h"
     12 #include "hu_stuff.h"
     13 
     14 #define	TEXTSPEED	3
     15 #define	TEXTWAIT	250
     16 
     17 typedef struct {
     18 	int        name;
     19 	mobjtype_t type;
     20 } castinfo_t;
     21 
     22 void    F_CastTicker ();
     23 boolean F_CastResponder (event_t *ev);
     24 void    F_CastDrawer ();
     25 void    V_DrawPatchFlipped(int x, int y, int scrn, patch_t *patch);
     26 
     27 extern	patch_t *hu_font[HU_FONTSIZE];
     28 int		finalestage;
     29 int		finalecount;
     30 char*	finaletext;
     31 char*	finaleflat;
     32 int		castnum;
     33 int		casttics;
     34 state_t*	caststate;
     35 boolean		castdeath;
     36 int		castframes;
     37 int		castonmelee;
     38 boolean		castattacking;
     39 extern	gamestate_t     wipegamestate;
     40 
     41 castinfo_t castorder[] = {
     42 	{CC_ZOMBIE,  MT_POSSESSED},
     43 	{CC_SHOTGUN, MT_SHOTGUY},
     44 	{CC_HEAVY,   MT_CHAINGUY},
     45 	{CC_IMP,     MT_TROOP},
     46 	{CC_DEMON,   MT_SERGEANT},
     47 	{CC_LOST,    MT_SKULL},
     48 	{CC_CACO,    MT_HEAD},
     49 	{CC_HELL,    MT_KNIGHT},
     50 	{CC_BARON,   MT_BRUISER},
     51 	{CC_ARACH,   MT_BABY},
     52 	{CC_PAIN,    MT_PAIN},
     53 	{CC_REVEN,   MT_UNDEAD},
     54 	{CC_MANCU,   MT_FATSO},
     55 	{CC_ARCH,    MT_VILE},
     56 	{CC_SPIDER,  MT_SPIDER},
     57 	{CC_CYBER,   MT_CYBORG},
     58 	{CC_HERO,    MT_PLAYER},
     59 	{0,          0}
     60 };
     61 
     62 void
     63 F_StartFinale()
     64 {
     65 	gameaction = ga_nothing;
     66 	gamestate = GS_FINALE;
     67 	viewactive = false;
     68 	automapactive = false;
     69 	S_ChangeMusic(mus_victor, true);
     70 	switch (gameepisode) {
     71 		case 1:
     72 			finaleflat = "FLOOR4_8";
     73 			finaletext = lang[E1TEXT];
     74 			break;
     75 		case 2:
     76 			finaleflat = "SFLR6_1";
     77 			finaletext = lang[E2TEXT];
     78 			break;
     79 		case 3:
     80 			finaleflat = "MFLR8_4";
     81 			finaletext = lang[E3TEXT];
     82 			break;
     83 		case 4:
     84 			finaleflat = "MFLR8_3";
     85 			finaletext = lang[E4TEXT];
     86 			break;
     87 	}
     88 	finalestage = 0;
     89 	finalecount = 0;
     90 }
     91 
     92 boolean
     93 F_Responder(event_t* event)
     94 {
     95 	if (finalestage == 2) return F_CastResponder(event);
     96 	return false;
     97 }
     98 
     99 void
    100 F_Ticker()
    101 {
    102 	finalecount++;
    103 	if (finalestage == 2) {
    104 		F_CastTicker ();
    105 		return;
    106 	}
    107 	if (!finalestage && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT) {
    108 		finalecount = 0;
    109 		finalestage = 1;
    110 		wipegamestate = -1;
    111 		if (gameepisode == 3) S_StartMusic(mus_bunny);
    112 	}
    113 }
    114 
    115 void
    116 F_TextWrite()
    117 {
    118 	byte*	src, *dest;
    119 	char*	ch;
    120 	int		x, y, w, count, c, cx, cy;
    121 
    122 	src = W_CacheLumpName(finaleflat, PU_CACHE);
    123 	dest = screens[0];
    124 	for (y = 0; y < SCREENHEIGHT; ++y) {
    125 		for (x = 0; x < SCREENWIDTH/64; ++x) {
    126 			memcpy (dest, src+((y&63)<<6), 64);
    127 			dest += 64;
    128 		}
    129 		if (SCREENWIDTH&63) {
    130 			memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
    131 			dest += (SCREENWIDTH&63);
    132 		}
    133 	}
    134 	V_MarkRect(0, 0, SCREENWIDTH, SCREENHEIGHT);
    135 	cx = cy = 10;
    136 	ch = finaletext;
    137 	count = (finalecount - 10)/TEXTSPEED;
    138 	if (count < 0) count = 0;
    139 	for (; count; --count) {
    140 		c = *ch++;
    141 		if (!c) break;
    142 		if (c == '\n') {
    143 			cx = 10;
    144 			cy += 11;
    145 			continue;
    146 		}
    147 		c = toupper(c) - HU_FONTSTART;
    148 		if (c < 0 || c> HU_FONTSIZE) {
    149 			cx += 4;
    150 			continue;
    151 		}
    152 		w = hu_font[c]->width;
    153 		if (cx+w > SCREENWIDTH) break;
    154 		V_DrawPatch(cx, cy, 0, hu_font[c]);
    155 		cx+=w;
    156 	}
    157 }
    158 
    159 
    160 void
    161 F_CastTicker()
    162 {
    163 	int st, sfx;
    164 
    165 	if (--casttics > 0) return;
    166 	if (caststate->tics == -1 || caststate->nextstate == S_NULL) {
    167 		castnum++;
    168 		castdeath = false;
    169 		if (lang[castorder[castnum].name] == NULL)
    170 			castnum = 0;
    171 		if (mobjinfo[castorder[castnum].type].seesound)
    172 			S_StartSound(NULL, mobjinfo[castorder[castnum].type].seesound);
    173 		caststate = &states[mobjinfo[castorder[castnum].type].seestate];
    174 		castframes = 0;
    175 	} else {
    176 		if (caststate == &states[S_PLAY_ATK1]) goto stopattack;
    177 		st = caststate->nextstate;
    178 		caststate = &states[st];
    179 		castframes++;
    180 		switch (st) {
    181 			case S_PLAY_ATK1: sfx = sfx_dshtgn; break;
    182 			case S_POSS_ATK2: sfx = sfx_pistol; break;
    183 			case S_SPOS_ATK2: sfx = sfx_shotgn; break;
    184 			case S_VILE_ATK2: sfx = sfx_vilatk; break;
    185 			case S_SKEL_FIST2: sfx = sfx_skeswg; break;
    186 			case S_SKEL_FIST4: sfx = sfx_skepch; break;
    187 			case S_SKEL_MISS2: sfx = sfx_skeatk; break;
    188 			case S_FATT_ATK8:
    189 			case S_FATT_ATK5:
    190 			case S_FATT_ATK2: sfx = sfx_firsht; break;
    191 			case S_CPOS_ATK2:
    192 			case S_CPOS_ATK3:
    193 			case S_CPOS_ATK4: sfx = sfx_shotgn; break;
    194 			case S_TROO_ATK3: sfx = sfx_claw; break;
    195 			case S_SARG_ATK2: sfx = sfx_sgtatk; break;
    196 			case S_BOSS_ATK2:
    197 			case S_BOS2_ATK2:
    198 			case S_HEAD_ATK2: sfx = sfx_firsht; break;
    199 			case S_SKULL_ATK2: sfx = sfx_sklatk; break;
    200 			case S_SPID_ATK2:
    201 			case S_SPID_ATK3: sfx = sfx_shotgn; break;
    202 			case S_BSPI_ATK2: sfx = sfx_plasma; break;
    203 			case S_CYBER_ATK2:
    204 			case S_CYBER_ATK4:
    205 			case S_CYBER_ATK6: sfx = sfx_rlaunc; break;
    206 			case S_PAIN_ATK3: sfx = sfx_sklatk; break;
    207 			default: sfx = 0; break;
    208 		}
    209 		if (sfx) S_StartSound(NULL, sfx);
    210 	}
    211 	if (castframes == 12) {
    212 		castattacking = true;
    213 		if (castonmelee) caststate=&states[mobjinfo[castorder[castnum].type].meleestate];
    214 		else caststate=&states[mobjinfo[castorder[castnum].type].missilestate];
    215 		castonmelee ^= 1;
    216 		if (caststate == &states[S_NULL]) {
    217 			if (castonmelee) caststate = &states[mobjinfo[castorder[castnum].type].meleestate];
    218 			else caststate = &states[mobjinfo[castorder[castnum].type].missilestate];
    219 		}
    220 	}
    221 	if (castattacking) {
    222 		if (castframes == 24 || caststate == &states[mobjinfo[castorder[castnum].type].seestate] ) {
    223 			stopattack:
    224 			castattacking = false;
    225 			castframes = 0;
    226 			caststate = &states[mobjinfo[castorder[castnum].type].seestate];
    227 		}
    228 	}
    229 	casttics = caststate->tics;
    230 	if (casttics == -1) casttics = 15;
    231 }
    232 
    233 boolean
    234 F_CastResponder(event_t* ev)
    235 {
    236 	if (ev->type != ev_keydown) return false;
    237 	if (castdeath) return true;
    238 	castdeath = true;
    239 	caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
    240 	casttics = caststate->tics;
    241 	castframes = 0;
    242 	castattacking = false;
    243 	if (mobjinfo[castorder[castnum].type].deathsound) S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
    244 	return true;
    245 }
    246 
    247 void
    248 F_CastPrint(char* text)
    249 {
    250 	char*	ch;
    251 	int		c, cx, w, width;
    252 
    253 	width = 0;
    254 	ch = text;
    255 	while (ch) {
    256 		c = *ch++;
    257 		if (!c) break;
    258 		c = toupper(c) - HU_FONTSTART;
    259 		if (c < 0 || c> HU_FONTSIZE) {
    260 			width += 4;
    261 			continue;
    262 		}
    263 		w =  (hu_font[c]->width);
    264 		width += w;
    265 	}
    266 	cx = 160-width/2;
    267 	ch = text;
    268 	while (ch) {
    269 		c = *ch++;
    270 		if (!c) break;
    271 		c = toupper(c) - HU_FONTSTART;
    272 		if (c < 0 || c > HU_FONTSIZE) {
    273 			cx += 4;
    274 			continue;
    275 		}
    276 		w =  (hu_font[c]->width);
    277 		V_DrawPatch(cx, 180, 0, hu_font[c]);
    278 		cx += w;
    279 	}
    280 }
    281 
    282 
    283 void
    284 F_CastDrawer()
    285 {
    286 	spriteframe_t* sprframe;
    287 	spritedef_t*   sprdef;
    288 	patch_t*       patch;
    289 	int            lump;
    290 	boolean        flip;
    291 
    292 	V_DrawPatch (0, 0, 0,  W_CacheLumpName ("BOSSBACK",  PU_CACHE));
    293 	F_CastPrint(lang[castorder[castnum].name]);
    294 	sprdef = &sprites[caststate->sprite];
    295 	sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK];
    296 	lump = sprframe->lump[0];
    297 	flip = (boolean)sprframe->flip[0];
    298 	patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
    299 	if (flip) V_DrawPatchFlipped(160, 170, 0, patch);
    300 	else V_DrawPatch (160, 170, 0, patch);
    301 }
    302 
    303 void
    304 F_DrawPatchCol(int x, patch_t* patch, int col)
    305 {
    306 	column_t* column;
    307 	byte*     source, *dest , *desttop;
    308 	int       count;
    309 
    310 	column = (column_t *)((byte *)patch + patch->columnofs[col]);
    311 	desttop = screens[0] + x;
    312 	while (column->topdelta != 0xff ) {
    313 		source = (byte *)column + 3;
    314 		dest = desttop + column->topdelta*SCREENWIDTH;
    315 		for (count = column->length; count; --count) {
    316 			*dest = *source++;
    317 			dest += SCREENWIDTH;
    318 		}
    319 		column = (column_t*)((byte*)column + column->length + 4);
    320 	}
    321 }
    322 
    323 void
    324 F_BunnyScroll()
    325 {
    326 	static int laststage;
    327 	patch_t*   p1;
    328 	patch_t*   p2;
    329 	int        scrolled;
    330 	int        x;
    331 	int        stage;
    332 	char       name[10];
    333 
    334 	p1 = W_CacheLumpName ("PFUB2", PU_LEVEL);
    335 	p2 = W_CacheLumpName ("PFUB1", PU_LEVEL);
    336 	V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
    337 	scrolled = 320 - (finalecount-230)/2;
    338 	if (scrolled > 320) scrolled = 320;
    339 	if (scrolled < 0) scrolled = 0;
    340 	for (x = 0; x < SCREENWIDTH; ++x) {
    341 		if (x+scrolled < 320) F_DrawPatchCol(x, p1, x+scrolled);
    342 		else F_DrawPatchCol(x, p2, x+scrolled - 320);
    343 	}
    344 	if (finalecount < 1130) return;
    345 	if (finalecount < 1180) {
    346 		V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2, 0, W_CacheLumpName("END0", PU_CACHE));
    347 		laststage = 0;
    348 		return;
    349 	}
    350 	stage = (finalecount-1180) / 5;
    351 	if (stage > 6) stage = 6;
    352 	if (stage > laststage) {
    353 		S_StartSound (NULL, sfx_pistol);
    354 		laststage = stage;
    355 	}
    356 	sprintf (name, "END%i", stage);
    357 	V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2, 0, W_CacheLumpName(name, PU_CACHE));
    358 }
    359 
    360 void
    361 F_Drawer()
    362 {
    363 	if (finalestage == 2) {
    364 		F_CastDrawer ();
    365 		return;
    366 	}
    367 	if (!finalestage) F_TextWrite();
    368 	else {
    369 		switch (gameepisode) {
    370 			case 1:
    371 				V_DrawPatch (0, 0, 0, W_CacheLumpName("HELP2", PU_CACHE));
    372 				break;
    373 			case 2:
    374 				V_DrawPatch(0, 0, 0, W_CacheLumpName("VICTORY2", PU_CACHE));
    375 				break;
    376 			case 3:
    377 				F_BunnyScroll();
    378 				break;
    379 			case 4:
    380 				V_DrawPatch (0, 0, 0, W_CacheLumpName("ENDPIC", PU_CACHE));
    381 				break;
    382 		}
    383 	}
    384 }