Subversion Repositories Kolibri OS

Rev

Rev 298 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
298 serge 1
// Emacs style mode select   -*- C++ -*-
2
//-----------------------------------------------------------------------------
3
//
4
// $Id:$
5
//
6
// Copyright (C) 1993-1996 by id Software, Inc.
7
//
8
// This source is available for distribution and/or modification
9
// only under the terms of the DOOM Source Code License as
10
// published by id Software. All rights reserved.
11
//
12
// The source is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15
// for more details.
16
//
17
// $Log:$
18
//
19
// DESCRIPTION:
20
//	Game completion, final screen animation.
21
//
22
//-----------------------------------------------------------------------------
23
 
24
 
25
static const char
26
rcsid[] = "$Id: f_finale.c,v 1.5 1997/02/03 21:26:34 b1 Exp $";
27
 
28
#include 
29
 
30
// Functions.
333 serge 31
#include "i_system.h"
298 serge 32
#include "m_swap.h"
33
#include "z_zone.h"
34
#include "v_video.h"
35
#include "w_wad.h"
36
#include "s_sound.h"
37
 
38
// Data.
39
#include "dstrings.h"
40
#include "sounds.h"
41
 
42
#include "doomstat.h"
43
#include "r_state.h"
44
 
45
// ?
46
//#include "doomstat.h"
47
//#include "r_local.h"
48
//#include "f_finale.h"
49
 
50
// Stage of animation:
51
//  0 = text, 1 = art screen, 2 = character cast
52
int		finalestage;
53
 
54
int		finalecount;
55
 
56
#define	TEXTSPEED	3
57
#define	TEXTWAIT	250
58
 
59
char*	e1text = E1TEXT;
60
char*	e2text = E2TEXT;
61
char*	e3text = E3TEXT;
62
char*	e4text = E4TEXT;
63
 
64
char*	c1text = C1TEXT;
65
char*	c2text = C2TEXT;
66
char*	c3text = C3TEXT;
67
char*	c4text = C4TEXT;
68
char*	c5text = C5TEXT;
69
char*	c6text = C6TEXT;
70
 
71
char*	p1text = P1TEXT;
72
char*	p2text = P2TEXT;
73
char*	p3text = P3TEXT;
74
char*	p4text = P4TEXT;
75
char*	p5text = P5TEXT;
76
char*	p6text = P6TEXT;
77
 
78
char*	t1text = T1TEXT;
79
char*	t2text = T2TEXT;
80
char*	t3text = T3TEXT;
81
char*	t4text = T4TEXT;
82
char*	t5text = T5TEXT;
83
char*	t6text = T6TEXT;
84
 
85
char*	finaletext;
86
char*	finaleflat;
87
 
88
void	F_StartCast (void);
89
void	F_CastTicker (void);
90
boolean F_CastResponder (event_t *ev);
91
void	F_CastDrawer (void);
92
 
93
//
94
// F_StartFinale
95
//
96
void F_StartFinale (void)
97
{
98
    gameaction = ga_nothing;
99
    gamestate = GS_FINALE;
100
    viewactive = false;
101
    automapactive = false;
102
 
103
    // Okay - IWAD dependend stuff.
104
    // This has been changed severly, and
105
    //  some stuff might have changed in the process.
106
    switch ( gamemode )
107
    {
108
 
109
      // DOOM 1 - E1, E3 or E4, but each nine missions
110
      case shareware:
111
      case registered:
112
      case retail:
113
      {
114
	S_ChangeMusic(mus_victor, true);
115
 
116
	switch (gameepisode)
117
	{
118
	  case 1:
119
	    finaleflat = "FLOOR4_8";
120
	    finaletext = e1text;
121
	    break;
122
	  case 2:
123
	    finaleflat = "SFLR6_1";
124
	    finaletext = e2text;
125
	    break;
126
	  case 3:
127
	    finaleflat = "MFLR8_4";
128
	    finaletext = e3text;
129
	    break;
130
	  case 4:
131
	    finaleflat = "MFLR8_3";
132
	    finaletext = e4text;
133
	    break;
134
	  default:
135
	    // Ouch.
136
	    break;
137
	}
138
	break;
139
      }
140
 
141
      // DOOM II and missions packs with E1, M34
142
      case commercial:
143
      {
144
	  S_ChangeMusic(mus_read_m, true);
145
 
146
	  switch (gamemap)
147
	  {
148
	    case 6:
149
	      finaleflat = "SLIME16";
150
	      finaletext = c1text;
151
	      break;
152
	    case 11:
153
	      finaleflat = "RROCK14";
154
	      finaletext = c2text;
155
	      break;
156
	    case 20:
157
	      finaleflat = "RROCK07";
158
	      finaletext = c3text;
159
	      break;
160
	    case 30:
161
	      finaleflat = "RROCK17";
162
	      finaletext = c4text;
163
	      break;
164
	    case 15:
165
	      finaleflat = "RROCK13";
166
	      finaletext = c5text;
167
	      break;
168
	    case 31:
169
	      finaleflat = "RROCK19";
170
	      finaletext = c6text;
171
	      break;
172
	    default:
173
	      // Ouch.
174
	      break;
175
	  }
176
	  break;
177
      }
178
 
179
 
180
      // Indeterminate.
181
      default:
182
	S_ChangeMusic(mus_read_m, true);
183
	finaleflat = "F_SKY1"; // Not used anywhere else.
184
	finaletext = c1text;  // FIXME - other text, music?
185
	break;
186
    }
187
 
188
    finalestage = 0;
189
    finalecount = 0;
190
 
191
}
192
 
193
 
194
 
195
boolean F_Responder (event_t *event)
196
{
197
    if (finalestage == 2)
198
	return F_CastResponder (event);
199
 
200
    return false;
201
}
202
 
203
 
204
//
205
// F_Ticker
206
//
207
void F_Ticker (void)
208
{
209
    int		i;
210
 
211
    // check for skipping
212
    if ( (gamemode == commercial)
213
      && ( finalecount > 50) )
214
    {
215
      // go on to the next level
216
      for (i=0 ; i
217
	if (players[i].cmd.buttons)
218
	  break;
219
 
220
      if (i < MAXPLAYERS)
221
      {
222
	if (gamemap == 30)
223
	  F_StartCast ();
224
	else
225
	  gameaction = ga_worlddone;
226
      }
227
    }
228
 
229
    // advance animation
230
    finalecount++;
231
 
232
    if (finalestage == 2)
233
    {
234
	F_CastTicker ();
235
	return;
236
    }
237
 
238
    if ( gamemode == commercial)
239
	return;
240
 
241
    if (!finalestage && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
242
    {
243
	finalecount = 0;
244
	finalestage = 1;
245
	wipegamestate = -1;		// force a wipe
246
	if (gameepisode == 3)
247
	    S_StartMusic (mus_bunny);
248
    }
249
}
250
 
251
 
252
 
253
//
254
// F_TextWrite
255
//
256
 
257
#include "hu_stuff.h"
258
extern	patch_t *hu_font[HU_FONTSIZE];
259
 
260
 
261
void F_TextWrite (void)
262
{
263
    byte*	src;
264
    byte*	dest;
265
 
266
    int		x,y,w;
267
    int		count;
268
    char*	ch;
269
    int		c;
270
    int		cx;
271
    int		cy;
272
 
273
    // erase the entire screen to a tiled background
274
    src = W_CacheLumpName ( finaleflat , PU_CACHE);
275
    dest = screens[0];
276
 
277
    for (y=0 ; y
278
    {
279
	for (x=0 ; x
280
	{
281
	    memcpy (dest, src+((y&63)<<6), 64);
282
	    dest += 64;
283
	}
284
	if (SCREENWIDTH&63)
285
	{
286
	    memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
287
	    dest += (SCREENWIDTH&63);
288
	}
289
    }
290
 
291
    V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
292
 
293
    // draw some of the text onto the screen
294
    cx = 10;
295
    cy = 10;
296
    ch = finaletext;
297
 
298
    count = (finalecount - 10)/TEXTSPEED;
299
    if (count < 0)
300
	count = 0;
301
    for ( ; count ; count-- )
302
    {
303
	c = *ch++;
304
	if (!c)
305
	    break;
306
	if (c == '\n')
307
	{
308
	    cx = 10;
309
	    cy += 11;
310
	    continue;
311
	}
312
 
313
	c = toupper(c) - HU_FONTSTART;
314
	if (c < 0 || c> HU_FONTSIZE)
315
	{
316
	    cx += 4;
317
	    continue;
318
	}
319
 
320
	w = SHORT (hu_font[c]->width);
321
	if (cx+w > SCREENWIDTH)
322
	    break;
323
	V_DrawPatch(cx, cy, 0, hu_font[c]);
324
	cx+=w;
325
    }
326
 
327
}
328
 
329
//
330
// Final DOOM 2 animation
331
// Casting by id Software.
332
//   in order of appearance
333
//
334
typedef struct
335
{
336
    char		*name;
337
    mobjtype_t	type;
338
} castinfo_t;
339
 
340
castinfo_t	castorder[] = {
341
    {CC_ZOMBIE, MT_POSSESSED},
342
    {CC_SHOTGUN, MT_SHOTGUY},
343
    {CC_HEAVY, MT_CHAINGUY},
344
    {CC_IMP, MT_TROOP},
345
    {CC_DEMON, MT_SERGEANT},
346
    {CC_LOST, MT_SKULL},
347
    {CC_CACO, MT_HEAD},
348
    {CC_HELL, MT_KNIGHT},
349
    {CC_BARON, MT_BRUISER},
350
    {CC_ARACH, MT_BABY},
351
    {CC_PAIN, MT_PAIN},
352
    {CC_REVEN, MT_UNDEAD},
353
    {CC_MANCU, MT_FATSO},
354
    {CC_ARCH, MT_VILE},
355
    {CC_SPIDER, MT_SPIDER},
356
    {CC_CYBER, MT_CYBORG},
357
    {CC_HERO, MT_PLAYER},
358
 
359
    {NULL,0}
360
};
361
 
362
int		castnum;
363
int		casttics;
364
state_t*	caststate;
365
boolean		castdeath;
366
int		castframes;
367
int		castonmelee;
368
boolean		castattacking;
369
 
370
 
371
//
372
// F_StartCast
373
//
374
extern	gamestate_t     wipegamestate;
375
 
376
 
377
void F_StartCast (void)
378
{
379
    wipegamestate = -1;		// force a screen wipe
380
    castnum = 0;
381
    caststate = &states[mobjinfo[castorder[castnum].type].seestate];
382
    casttics = caststate->tics;
383
    castdeath = false;
384
    finalestage = 2;
385
    castframes = 0;
386
    castonmelee = 0;
387
    castattacking = false;
388
    S_ChangeMusic(mus_evil, true);
389
}
390
 
391
 
392
//
393
// F_CastTicker
394
//
395
void F_CastTicker (void)
396
{
397
    int		st;
398
    int		sfx;
399
 
400
    if (--casttics > 0)
401
	return;			// not time to change state yet
402
 
403
    if (caststate->tics == -1 || caststate->nextstate == S_NULL)
404
    {
405
	// switch from deathstate to next monster
406
	castnum++;
407
	castdeath = false;
408
	if (castorder[castnum].name == NULL)
409
	    castnum = 0;
410
	if (mobjinfo[castorder[castnum].type].seesound)
411
	    S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound);
412
	caststate = &states[mobjinfo[castorder[castnum].type].seestate];
413
	castframes = 0;
414
    }
415
    else
416
    {
417
	// just advance to next state in animation
418
	if (caststate == &states[S_PLAY_ATK1])
419
	    goto stopattack;	// Oh, gross hack!
420
	st = caststate->nextstate;
421
	caststate = &states[st];
422
	castframes++;
423
 
424
	// sound hacks....
425
	switch (st)
426
	{
427
	  case S_PLAY_ATK1:	sfx = sfx_dshtgn; break;
428
	  case S_POSS_ATK2:	sfx = sfx_pistol; break;
429
	  case S_SPOS_ATK2:	sfx = sfx_shotgn; break;
430
	  case S_VILE_ATK2:	sfx = sfx_vilatk; break;
431
	  case S_SKEL_FIST2:	sfx = sfx_skeswg; break;
432
	  case S_SKEL_FIST4:	sfx = sfx_skepch; break;
433
	  case S_SKEL_MISS2:	sfx = sfx_skeatk; break;
434
	  case S_FATT_ATK8:
435
	  case S_FATT_ATK5:
436
	  case S_FATT_ATK2:	sfx = sfx_firsht; break;
437
	  case S_CPOS_ATK2:
438
	  case S_CPOS_ATK3:
439
	  case S_CPOS_ATK4:	sfx = sfx_shotgn; break;
440
	  case S_TROO_ATK3:	sfx = sfx_claw; break;
441
	  case S_SARG_ATK2:	sfx = sfx_sgtatk; break;
442
	  case S_BOSS_ATK2:
443
	  case S_BOS2_ATK2:
444
	  case S_HEAD_ATK2:	sfx = sfx_firsht; break;
445
	  case S_SKULL_ATK2:	sfx = sfx_sklatk; break;
446
	  case S_SPID_ATK2:
447
	  case S_SPID_ATK3:	sfx = sfx_shotgn; break;
448
	  case S_BSPI_ATK2:	sfx = sfx_plasma; break;
449
	  case S_CYBER_ATK2:
450
	  case S_CYBER_ATK4:
451
	  case S_CYBER_ATK6:	sfx = sfx_rlaunc; break;
452
	  case S_PAIN_ATK3:	sfx = sfx_sklatk; break;
453
	  default: sfx = 0; break;
454
	}
455
 
456
	if (sfx)
457
	    S_StartSound (NULL, sfx);
458
    }
459
 
460
    if (castframes == 12)
461
    {
462
	// go into attack frame
463
	castattacking = true;
464
	if (castonmelee)
465
	    caststate=&states[mobjinfo[castorder[castnum].type].meleestate];
466
	else
467
	    caststate=&states[mobjinfo[castorder[castnum].type].missilestate];
468
	castonmelee ^= 1;
469
	if (caststate == &states[S_NULL])
470
	{
471
	    if (castonmelee)
472
		caststate=
473
		    &states[mobjinfo[castorder[castnum].type].meleestate];
474
	    else
475
		caststate=
476
		    &states[mobjinfo[castorder[castnum].type].missilestate];
477
	}
478
    }
479
 
480
    if (castattacking)
481
    {
482
	if (castframes == 24
483
	    ||	caststate == &states[mobjinfo[castorder[castnum].type].seestate] )
484
	{
485
	  stopattack:
486
	    castattacking = false;
487
	    castframes = 0;
488
	    caststate = &states[mobjinfo[castorder[castnum].type].seestate];
489
	}
490
    }
491
 
492
    casttics = caststate->tics;
493
    if (casttics == -1)
494
	casttics = 15;
495
}
496
 
497
 
498
//
499
// F_CastResponder
500
//
501
 
502
boolean F_CastResponder (event_t* ev)
503
{
504
    if (ev->type != ev_keydown)
505
	return false;
506
 
507
    if (castdeath)
508
	return true;			// already in dying frames
509
 
510
    // go into death frame
511
    castdeath = true;
512
    caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
513
    casttics = caststate->tics;
514
    castframes = 0;
515
    castattacking = false;
516
    if (mobjinfo[castorder[castnum].type].deathsound)
517
	S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
518
 
519
    return true;
520
}
521
 
522
 
523
void F_CastPrint (char* text)
524
{
525
    char*	ch;
526
    int		c;
527
    int		cx;
528
    int		w;
529
    int		width;
530
 
531
    // find width
532
    ch = text;
533
    width = 0;
534
 
535
    while (ch)
536
    {
537
	c = *ch++;
538
	if (!c)
539
	    break;
540
	c = toupper(c) - HU_FONTSTART;
541
	if (c < 0 || c> HU_FONTSIZE)
542
	{
543
	    width += 4;
544
	    continue;
545
	}
546
 
547
	w = SHORT (hu_font[c]->width);
548
	width += w;
549
    }
550
 
551
    // draw it
552
    cx = 160-width/2;
553
    ch = text;
554
    while (ch)
555
    {
556
	c = *ch++;
557
	if (!c)
558
	    break;
559
	c = toupper(c) - HU_FONTSTART;
560
	if (c < 0 || c> HU_FONTSIZE)
561
	{
562
	    cx += 4;
563
	    continue;
564
	}
565
 
566
	w = SHORT (hu_font[c]->width);
567
	V_DrawPatch(cx, 180, 0, hu_font[c]);
568
	cx+=w;
569
    }
570
 
571
}
572
 
573
 
574
//
575
// F_CastDrawer
576
//
577
void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch);
578
 
579
void F_CastDrawer (void)
580
{
581
    spritedef_t*	sprdef;
582
    spriteframe_t*	sprframe;
583
    int			lump;
584
    boolean		flip;
585
    patch_t*		patch;
586
 
587
    // erase the entire screen to a background
588
    V_DrawPatch (0,0,0, W_CacheLumpName ("BOSSBACK", PU_CACHE));
589
 
590
    F_CastPrint (castorder[castnum].name);
591
 
592
    // draw the current frame in the middle of the screen
593
    sprdef = &sprites[caststate->sprite];
594
    sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK];
595
    lump = sprframe->lump[0];
596
    flip = (boolean)sprframe->flip[0];
597
 
598
    patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
599
    if (flip)
600
	V_DrawPatchFlipped (160,170,0,patch);
601
    else
602
	V_DrawPatch (160,170,0,patch);
603
}
604
 
605
 
606
//
607
// F_DrawPatchCol
608
//
609
void
610
F_DrawPatchCol
611
( int		x,
612
  patch_t*	patch,
613
  int		col )
614
{
615
    column_t*	column;
616
    byte*	source;
617
    byte*	dest;
618
    byte*	desttop;
619
    int		count;
620
 
621
    column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
622
    desttop = screens[0]+x;
623
 
624
    // step through the posts in a column
625
    while (column->topdelta != 0xff )
626
    {
627
	source = (byte *)column + 3;
628
	dest = desttop + column->topdelta*SCREENWIDTH;
629
	count = column->length;
630
 
631
	while (count--)
632
	{
633
	    *dest = *source++;
634
	    dest += SCREENWIDTH;
635
	}
636
	column = (column_t *)(  (byte *)column + column->length + 4 );
637
    }
638
}
639
 
640
 
641
//
642
// F_BunnyScroll
643
//
644
void F_BunnyScroll (void)
645
{
646
    int		scrolled;
647
    int		x;
648
    patch_t*	p1;
649
    patch_t*	p2;
650
    char	name[10];
651
    int		stage;
652
    static int	laststage;
653
 
654
    p1 = W_CacheLumpName ("PFUB2", PU_LEVEL);
655
    p2 = W_CacheLumpName ("PFUB1", PU_LEVEL);
656
 
657
    V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
658
 
659
    scrolled = 320 - (finalecount-230)/2;
660
    if (scrolled > 320)
661
	scrolled = 320;
662
    if (scrolled < 0)
663
	scrolled = 0;
664
 
665
    for ( x=0 ; x
666
    {
667
	if (x+scrolled < 320)
668
	    F_DrawPatchCol (x, p1, x+scrolled);
669
	else
670
	    F_DrawPatchCol (x, p2, x+scrolled - 320);
671
    }
672
 
673
    if (finalecount < 1130)
674
	return;
675
    if (finalecount < 1180)
676
    {
677
	V_DrawPatch ((SCREENWIDTH-13*8)/2,
678
		     (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName ("END0",PU_CACHE));
679
	laststage = 0;
680
	return;
681
    }
682
 
683
    stage = (finalecount-1180) / 5;
684
    if (stage > 6)
685
	stage = 6;
686
    if (stage > laststage)
687
    {
688
	S_StartSound (NULL, sfx_pistol);
689
	laststage = stage;
690
    }
691
 
692
    sprintf (name,"END%i",stage);
693
    V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName (name,PU_CACHE));
694
}
695
 
696
 
697
//
698
// F_Drawer
699
//
700
void F_Drawer (void)
701
{
702
    if (finalestage == 2)
703
    {
704
	F_CastDrawer ();
705
	return;
706
    }
707
 
708
    if (!finalestage)
709
	F_TextWrite ();
710
    else
711
    {
712
	switch (gameepisode)
713
	{
714
	  case 1:
715
	    if ( gamemode == retail )
716
	      V_DrawPatch (0,0,0,
717
			 W_CacheLumpName("CREDIT",PU_CACHE));
718
	    else
719
	      V_DrawPatch (0,0,0,
720
			 W_CacheLumpName("HELP2",PU_CACHE));
721
	    break;
722
	  case 2:
723
	    V_DrawPatch(0,0,0,
724
			W_CacheLumpName("VICTORY2",PU_CACHE));
725
	    break;
726
	  case 3:
727
	    F_BunnyScroll ();
728
	    break;
729
	  case 4:
730
	    V_DrawPatch (0,0,0,
731
			 W_CacheLumpName("ENDPIC",PU_CACHE));
732
	    break;
733
	}
734
    }
735
 
736
}
737