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 }