Details | 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 | // Implements special effects: |
||
21 | // Texture animation, height or lighting changes |
||
22 | // according to adjacent sectors, respective |
||
23 | // utility functions, etc. |
||
24 | // Line Tag handling. Line and Sector triggers. |
||
25 | // |
||
26 | //----------------------------------------------------------------------------- |
||
27 | |||
28 | static const char |
||
29 | rcsid[] = "$Id: p_spec.c,v 1.6 1997/02/03 22:45:12 b1 Exp $"; |
||
30 | |||
31 | #include |
||
32 | |||
33 | #include "doomdef.h" |
||
34 | #include "doomstat.h" |
||
35 | |||
36 | #include "i_system.h" |
||
37 | #include "z_zone.h" |
||
38 | #include "m_argv.h" |
||
39 | #include "m_random.h" |
||
40 | #include "w_wad.h" |
||
41 | |||
42 | #include "r_local.h" |
||
43 | #include "p_local.h" |
||
44 | |||
45 | #include "g_game.h" |
||
46 | |||
47 | #include "s_sound.h" |
||
48 | |||
49 | // State. |
||
50 | #include "r_state.h" |
||
51 | |||
52 | // Data. |
||
53 | #include "sounds.h" |
||
54 | |||
55 | |||
56 | // |
||
57 | // Animating textures and planes |
||
58 | // There is another anim_t used in wi_stuff, unrelated. |
||
59 | // |
||
60 | typedef struct |
||
61 | { |
||
62 | boolean istexture; |
||
63 | int picnum; |
||
64 | int basepic; |
||
65 | int numpics; |
||
66 | int speed; |
||
67 | |||
68 | } anim_t; |
||
69 | |||
70 | // |
||
71 | // source animation definition |
||
72 | // |
||
73 | typedef struct |
||
74 | { |
||
75 | boolean istexture; // if false, it is a flat |
||
76 | char endname[9]; |
||
77 | char startname[9]; |
||
78 | int speed; |
||
79 | } animdef_t; |
||
80 | |||
81 | |||
82 | |||
83 | #define MAXANIMS 32 |
||
84 | |||
85 | extern anim_t anims[MAXANIMS]; |
||
86 | extern anim_t* lastanim; |
||
87 | |||
88 | // |
||
89 | // P_InitPicAnims |
||
90 | // |
||
91 | |||
92 | // Floor/ceiling animation sequences, |
||
93 | // defined by first and last frame, |
||
94 | // i.e. the flat (64x64 tile) name to |
||
95 | // be used. |
||
96 | // The full animation sequence is given |
||
97 | // using all the flats between the start |
||
98 | // and end entry, in the order found in |
||
99 | // the WAD file. |
||
100 | // |
||
101 | animdef_t animdefs[] = |
||
102 | { |
||
103 | {false, "NUKAGE3", "NUKAGE1", 8}, |
||
104 | {false, "FWATER4", "FWATER1", 8}, |
||
105 | {false, "SWATER4", "SWATER1", 8}, |
||
106 | {false, "LAVA4", "LAVA1", 8}, |
||
107 | {false, "BLOOD3", "BLOOD1", 8}, |
||
108 | |||
109 | // DOOM II flat animations. |
||
110 | {false, "RROCK08", "RROCK05", 8}, |
||
111 | {false, "SLIME04", "SLIME01", 8}, |
||
112 | {false, "SLIME08", "SLIME05", 8}, |
||
113 | {false, "SLIME12", "SLIME09", 8}, |
||
114 | |||
115 | {true, "BLODGR4", "BLODGR1", 8}, |
||
116 | {true, "SLADRIP3", "SLADRIP1", 8}, |
||
117 | |||
118 | {true, "BLODRIP4", "BLODRIP1", 8}, |
||
119 | {true, "FIREWALL", "FIREWALA", 8}, |
||
120 | {true, "GSTFONT3", "GSTFONT1", 8}, |
||
121 | {true, "FIRELAVA", "FIRELAV3", 8}, |
||
122 | {true, "FIREMAG3", "FIREMAG1", 8}, |
||
123 | {true, "FIREBLU2", "FIREBLU1", 8}, |
||
124 | {true, "ROCKRED3", "ROCKRED1", 8}, |
||
125 | |||
126 | {true, "BFALL4", "BFALL1", 8}, |
||
127 | {true, "SFALL4", "SFALL1", 8}, |
||
128 | {true, "WFALL4", "WFALL1", 8}, |
||
129 | {true, "DBRAIN4", "DBRAIN1", 8}, |
||
130 | |||
131 | {-1} |
||
132 | }; |
||
133 | |||
134 | anim_t anims[MAXANIMS]; |
||
135 | anim_t* lastanim; |
||
136 | |||
137 | |||
138 | // |
||
139 | // Animating line specials |
||
140 | // |
||
141 | #define MAXLINEANIMS 64 |
||
142 | |||
143 | extern short numlinespecials; |
||
144 | extern line_t* linespeciallist[MAXLINEANIMS]; |
||
145 | |||
146 | |||
147 | |||
148 | void P_InitPicAnims (void) |
||
149 | { |
||
150 | int i; |
||
151 | |||
152 | |||
153 | // Init animation |
||
154 | lastanim = anims; |
||
155 | for (i=0 ; animdefs[i].istexture != -1 ; i++) |
||
156 | { |
||
157 | if (animdefs[i].istexture) |
||
158 | { |
||
159 | // different episode ? |
||
160 | if (R_CheckTextureNumForName(animdefs[i].startname) == -1) |
||
161 | continue; |
||
162 | |||
163 | lastanim->picnum = R_TextureNumForName (animdefs[i].endname); |
||
164 | lastanim->basepic = R_TextureNumForName (animdefs[i].startname); |
||
165 | } |
||
166 | else |
||
167 | { |
||
168 | if (W_CheckNumForName(animdefs[i].startname) == -1) |
||
169 | continue; |
||
170 | |||
171 | lastanim->picnum = R_FlatNumForName (animdefs[i].endname); |
||
172 | lastanim->basepic = R_FlatNumForName (animdefs[i].startname); |
||
173 | } |
||
174 | |||
175 | lastanim->istexture = animdefs[i].istexture; |
||
176 | lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; |
||
177 | |||
178 | if (lastanim->numpics < 2) |
||
179 | I_Error ("P_InitPicAnims: bad cycle from %s to %s", |
||
180 | animdefs[i].startname, |
||
181 | animdefs[i].endname); |
||
182 | |||
183 | lastanim->speed = animdefs[i].speed; |
||
184 | lastanim++; |
||
185 | } |
||
186 | |||
187 | } |
||
188 | |||
189 | |||
190 | |||
191 | // |
||
192 | // UTILITIES |
||
193 | // |
||
194 | |||
195 | |||
196 | |||
197 | // |
||
198 | // getSide() |
||
199 | // Will return a side_t* |
||
200 | // given the number of the current sector, |
||
201 | // the line number, and the side (0/1) that you want. |
||
202 | // |
||
203 | side_t* |
||
204 | getSide |
||
205 | ( int currentSector, |
||
206 | int line, |
||
207 | int side ) |
||
208 | { |
||
209 | return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; |
||
210 | } |
||
211 | |||
212 | |||
213 | // |
||
214 | // getSector() |
||
215 | // Will return a sector_t* |
||
216 | // given the number of the current sector, |
||
217 | // the line number and the side (0/1) that you want. |
||
218 | // |
||
219 | sector_t* |
||
220 | getSector |
||
221 | ( int currentSector, |
||
222 | int line, |
||
223 | int side ) |
||
224 | { |
||
225 | return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; |
||
226 | } |
||
227 | |||
228 | |||
229 | // |
||
230 | // twoSided() |
||
231 | // Given the sector number and the line number, |
||
232 | // it will tell you whether the line is two-sided or not. |
||
233 | // |
||
234 | int |
||
235 | twoSided |
||
236 | ( int sector, |
||
237 | int line ) |
||
238 | { |
||
239 | return (sectors[sector].lines[line])->flags & ML_TWOSIDED; |
||
240 | } |
||
241 | |||
242 | |||
243 | |||
244 | |||
245 | // |
||
246 | // getNextSector() |
||
247 | // Return sector_t * of sector next to current. |
||
248 | // NULL if not two-sided line |
||
249 | // |
||
250 | sector_t* |
||
251 | getNextSector |
||
252 | ( line_t* line, |
||
253 | sector_t* sec ) |
||
254 | { |
||
255 | if (!(line->flags & ML_TWOSIDED)) |
||
256 | return NULL; |
||
257 | |||
258 | if (line->frontsector == sec) |
||
259 | return line->backsector; |
||
260 | |||
261 | return line->frontsector; |
||
262 | } |
||
263 | |||
264 | |||
265 | |||
266 | // |
||
267 | // P_FindLowestFloorSurrounding() |
||
268 | // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS |
||
269 | // |
||
270 | fixed_t P_FindLowestFloorSurrounding(sector_t* sec) |
||
271 | { |
||
272 | int i; |
||
273 | line_t* check; |
||
274 | sector_t* other; |
||
275 | fixed_t floor = sec->floorheight; |
||
276 | |||
277 | for (i=0 ;i < sec->linecount ; i++) |
||
278 | { |
||
279 | check = sec->lines[i]; |
||
280 | other = getNextSector(check,sec); |
||
281 | |||
282 | if (!other) |
||
283 | continue; |
||
284 | |||
285 | if (other->floorheight < floor) |
||
286 | floor = other->floorheight; |
||
287 | } |
||
288 | return floor; |
||
289 | } |
||
290 | |||
291 | |||
292 | |||
293 | // |
||
294 | // P_FindHighestFloorSurrounding() |
||
295 | // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS |
||
296 | // |
||
297 | fixed_t P_FindHighestFloorSurrounding(sector_t *sec) |
||
298 | { |
||
299 | int i; |
||
300 | line_t* check; |
||
301 | sector_t* other; |
||
302 | fixed_t floor = -500*FRACUNIT; |
||
303 | |||
304 | for (i=0 ;i < sec->linecount ; i++) |
||
305 | { |
||
306 | check = sec->lines[i]; |
||
307 | other = getNextSector(check,sec); |
||
308 | |||
309 | if (!other) |
||
310 | continue; |
||
311 | |||
312 | if (other->floorheight > floor) |
||
313 | floor = other->floorheight; |
||
314 | } |
||
315 | return floor; |
||
316 | } |
||
317 | |||
318 | |||
319 | |||
320 | // |
||
321 | // P_FindNextHighestFloor |
||
322 | // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS |
||
323 | // Note: this should be doable w/o a fixed array. |
||
324 | |||
325 | // 20 adjoining sectors max! |
||
326 | #define MAX_ADJOINING_SECTORS 20 |
||
327 | |||
328 | fixed_t |
||
329 | P_FindNextHighestFloor |
||
330 | ( sector_t* sec, |
||
331 | int currentheight ) |
||
332 | { |
||
333 | int i; |
||
334 | int h; |
||
335 | int min; |
||
336 | line_t* check; |
||
337 | sector_t* other; |
||
338 | fixed_t height = currentheight; |
||
339 | |||
340 | |||
341 | fixed_t heightlist[MAX_ADJOINING_SECTORS]; |
||
342 | |||
343 | for (i=0, h=0 ;i < sec->linecount ; i++) |
||
344 | { |
||
345 | check = sec->lines[i]; |
||
346 | other = getNextSector(check,sec); |
||
347 | |||
348 | if (!other) |
||
349 | continue; |
||
350 | |||
351 | if (other->floorheight > height) |
||
352 | heightlist[h++] = other->floorheight; |
||
353 | |||
354 | // Check for overflow. Exit. |
||
355 | if ( h >= MAX_ADJOINING_SECTORS ) |
||
356 | { |
||
357 | // __libclog_printf("Sector with more than 20 adjoining sectors\n" ); |
||
358 | break; |
||
359 | } |
||
360 | } |
||
361 | |||
362 | // Find lowest height in list |
||
363 | if (!h) |
||
364 | return currentheight; |
||
365 | |||
366 | min = heightlist[0]; |
||
367 | |||
368 | // Range checking? |
||
369 | for (i = 1;i < h;i++) |
||
370 | if (heightlist[i] < min) |
||
371 | min = heightlist[i]; |
||
372 | |||
373 | return min; |
||
374 | } |
||
375 | |||
376 | |||
377 | // |
||
378 | // FIND LOWEST CEILING IN THE SURROUNDING SECTORS |
||
379 | // |
||
380 | fixed_t |
||
381 | P_FindLowestCeilingSurrounding(sector_t* sec) |
||
382 | { |
||
383 | int i; |
||
384 | line_t* check; |
||
385 | sector_t* other; |
||
386 | fixed_t height = MAXINT; |
||
387 | |||
388 | for (i=0 ;i < sec->linecount ; i++) |
||
389 | { |
||
390 | check = sec->lines[i]; |
||
391 | other = getNextSector(check,sec); |
||
392 | |||
393 | if (!other) |
||
394 | continue; |
||
395 | |||
396 | if (other->ceilingheight < height) |
||
397 | height = other->ceilingheight; |
||
398 | } |
||
399 | return height; |
||
400 | } |
||
401 | |||
402 | |||
403 | // |
||
404 | // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS |
||
405 | // |
||
406 | fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) |
||
407 | { |
||
408 | int i; |
||
409 | line_t* check; |
||
410 | sector_t* other; |
||
411 | fixed_t height = 0; |
||
412 | |||
413 | for (i=0 ;i < sec->linecount ; i++) |
||
414 | { |
||
415 | check = sec->lines[i]; |
||
416 | other = getNextSector(check,sec); |
||
417 | |||
418 | if (!other) |
||
419 | continue; |
||
420 | |||
421 | if (other->ceilingheight > height) |
||
422 | height = other->ceilingheight; |
||
423 | } |
||
424 | return height; |
||
425 | } |
||
426 | |||
427 | |||
428 | |||
429 | // |
||
430 | // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO |
||
431 | // |
||
432 | int |
||
433 | P_FindSectorFromLineTag |
||
434 | ( line_t* line, |
||
435 | int start ) |
||
436 | { |
||
437 | int i; |
||
438 | |||
439 | for (i=start+1;i |
||
440 | if (sectors[i].tag == line->tag) |
||
441 | return i; |
||
442 | |||
443 | return -1; |
||
444 | } |
||
445 | |||
446 | |||
447 | |||
448 | |||
449 | // |
||
450 | // Find minimum light from an adjacent sector |
||
451 | // |
||
452 | int |
||
453 | P_FindMinSurroundingLight |
||
454 | ( sector_t* sector, |
||
455 | int max ) |
||
456 | { |
||
457 | int i; |
||
458 | int min; |
||
459 | line_t* line; |
||
460 | sector_t* check; |
||
461 | |||
462 | min = max; |
||
463 | for (i=0 ; i < sector->linecount ; i++) |
||
464 | { |
||
465 | line = sector->lines[i]; |
||
466 | check = getNextSector(line,sector); |
||
467 | |||
468 | if (!check) |
||
469 | continue; |
||
470 | |||
471 | if (check->lightlevel < min) |
||
472 | min = check->lightlevel; |
||
473 | } |
||
474 | return min; |
||
475 | } |
||
476 | |||
477 | |||
478 | |||
479 | // |
||
480 | // EVENTS |
||
481 | // Events are operations triggered by using, crossing, |
||
482 | // or shooting special lines, or by timed thinkers. |
||
483 | // |
||
484 | |||
485 | // |
||
486 | // P_CrossSpecialLine - TRIGGER |
||
487 | // Called every time a thing origin is about |
||
488 | // to cross a line with a non 0 special. |
||
489 | // |
||
490 | void |
||
491 | P_CrossSpecialLine |
||
492 | ( int linenum, |
||
493 | int side, |
||
494 | mobj_t* thing ) |
||
495 | { |
||
496 | line_t* line; |
||
497 | int ok; |
||
498 | |||
499 | line = &lines[linenum]; |
||
500 | |||
501 | // Triggers that other things can activate |
||
502 | if (!thing->player) |
||
503 | { |
||
504 | // Things that should NOT trigger specials... |
||
505 | switch(thing->type) |
||
506 | { |
||
507 | case MT_ROCKET: |
||
508 | case MT_PLASMA: |
||
509 | case MT_BFG: |
||
510 | case MT_TROOPSHOT: |
||
511 | case MT_HEADSHOT: |
||
512 | case MT_BRUISERSHOT: |
||
513 | return; |
||
514 | break; |
||
515 | |||
516 | default: break; |
||
517 | } |
||
518 | |||
519 | ok = 0; |
||
520 | switch(line->special) |
||
521 | { |
||
522 | case 39: // TELEPORT TRIGGER |
||
523 | case 97: // TELEPORT RETRIGGER |
||
524 | case 125: // TELEPORT MONSTERONLY TRIGGER |
||
525 | case 126: // TELEPORT MONSTERONLY RETRIGGER |
||
526 | case 4: // RAISE DOOR |
||
527 | case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER |
||
528 | case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER |
||
529 | ok = 1; |
||
530 | break; |
||
531 | } |
||
532 | if (!ok) |
||
533 | return; |
||
534 | } |
||
535 | |||
536 | |||
537 | // Note: could use some const's here. |
||
538 | switch (line->special) |
||
539 | { |
||
540 | // TRIGGERS. |
||
541 | // All from here to RETRIGGERS. |
||
542 | case 2: |
||
543 | // Open Door |
||
544 | EV_DoDoor(line,open); |
||
545 | line->special = 0; |
||
546 | break; |
||
547 | |||
548 | case 3: |
||
549 | // Close Door |
||
550 | EV_DoDoor(line,close); |
||
551 | line->special = 0; |
||
552 | break; |
||
553 | |||
554 | case 4: |
||
555 | // Raise Door |
||
556 | EV_DoDoor(line,normal); |
||
557 | line->special = 0; |
||
558 | break; |
||
559 | |||
560 | case 5: |
||
561 | // Raise Floor |
||
562 | EV_DoFloor(line,raiseFloor); |
||
563 | line->special = 0; |
||
564 | break; |
||
565 | |||
566 | case 6: |
||
567 | // Fast Ceiling Crush & Raise |
||
568 | EV_DoCeiling(line,fastCrushAndRaise); |
||
569 | line->special = 0; |
||
570 | break; |
||
571 | |||
572 | case 8: |
||
573 | // Build Stairs |
||
574 | EV_BuildStairs(line,build8); |
||
575 | line->special = 0; |
||
576 | break; |
||
577 | |||
578 | case 10: |
||
579 | // PlatDownWaitUp |
||
580 | EV_DoPlat(line,downWaitUpStay,0); |
||
581 | line->special = 0; |
||
582 | break; |
||
583 | |||
584 | case 12: |
||
585 | // Light Turn On - brightest near |
||
586 | EV_LightTurnOn(line,0); |
||
587 | line->special = 0; |
||
588 | break; |
||
589 | |||
590 | case 13: |
||
591 | // Light Turn On 255 |
||
592 | EV_LightTurnOn(line,255); |
||
593 | line->special = 0; |
||
594 | break; |
||
595 | |||
596 | case 16: |
||
597 | // Close Door 30 |
||
598 | EV_DoDoor(line,close30ThenOpen); |
||
599 | line->special = 0; |
||
600 | break; |
||
601 | |||
602 | case 17: |
||
603 | // Start Light Strobing |
||
604 | EV_StartLightStrobing(line); |
||
605 | line->special = 0; |
||
606 | break; |
||
607 | |||
608 | case 19: |
||
609 | // Lower Floor |
||
610 | EV_DoFloor(line,lowerFloor); |
||
611 | line->special = 0; |
||
612 | break; |
||
613 | |||
614 | case 22: |
||
615 | // Raise floor to nearest height and change texture |
||
616 | EV_DoPlat(line,raiseToNearestAndChange,0); |
||
617 | line->special = 0; |
||
618 | break; |
||
619 | |||
620 | case 25: |
||
621 | // Ceiling Crush and Raise |
||
622 | EV_DoCeiling(line,crushAndRaise); |
||
623 | line->special = 0; |
||
624 | break; |
||
625 | |||
626 | case 30: |
||
627 | // Raise floor to shortest texture height |
||
628 | // on either side of lines. |
||
629 | EV_DoFloor(line,raiseToTexture); |
||
630 | line->special = 0; |
||
631 | break; |
||
632 | |||
633 | case 35: |
||
634 | // Lights Very Dark |
||
635 | EV_LightTurnOn(line,35); |
||
636 | line->special = 0; |
||
637 | break; |
||
638 | |||
639 | case 36: |
||
640 | // Lower Floor (TURBO) |
||
641 | EV_DoFloor(line,turboLower); |
||
642 | line->special = 0; |
||
643 | break; |
||
644 | |||
645 | case 37: |
||
646 | // LowerAndChange |
||
647 | EV_DoFloor(line,lowerAndChange); |
||
648 | line->special = 0; |
||
649 | break; |
||
650 | |||
651 | case 38: |
||
652 | // Lower Floor To Lowest |
||
653 | EV_DoFloor( line, lowerFloorToLowest ); |
||
654 | line->special = 0; |
||
655 | break; |
||
656 | |||
657 | case 39: |
||
658 | // TELEPORT! |
||
659 | EV_Teleport( line, side, thing ); |
||
660 | line->special = 0; |
||
661 | break; |
||
662 | |||
663 | case 40: |
||
664 | // RaiseCeilingLowerFloor |
||
665 | EV_DoCeiling( line, raiseToHighest ); |
||
666 | EV_DoFloor( line, lowerFloorToLowest ); |
||
667 | line->special = 0; |
||
668 | break; |
||
669 | |||
670 | case 44: |
||
671 | // Ceiling Crush |
||
672 | EV_DoCeiling( line, lowerAndCrush ); |
||
673 | line->special = 0; |
||
674 | break; |
||
675 | |||
676 | case 52: |
||
677 | // EXIT! |
||
678 | G_ExitLevel (); |
||
679 | break; |
||
680 | |||
681 | case 53: |
||
682 | // Perpetual Platform Raise |
||
683 | EV_DoPlat(line,perpetualRaise,0); |
||
684 | line->special = 0; |
||
685 | break; |
||
686 | |||
687 | case 54: |
||
688 | // Platform Stop |
||
689 | EV_StopPlat(line); |
||
690 | line->special = 0; |
||
691 | break; |
||
692 | |||
693 | case 56: |
||
694 | // Raise Floor Crush |
||
695 | EV_DoFloor(line,raiseFloorCrush); |
||
696 | line->special = 0; |
||
697 | break; |
||
698 | |||
699 | case 57: |
||
700 | // Ceiling Crush Stop |
||
701 | EV_CeilingCrushStop(line); |
||
702 | line->special = 0; |
||
703 | break; |
||
704 | |||
705 | case 58: |
||
706 | // Raise Floor 24 |
||
707 | EV_DoFloor(line,raiseFloor24); |
||
708 | line->special = 0; |
||
709 | break; |
||
710 | |||
711 | case 59: |
||
712 | // Raise Floor 24 And Change |
||
713 | EV_DoFloor(line,raiseFloor24AndChange); |
||
714 | line->special = 0; |
||
715 | break; |
||
716 | |||
717 | case 104: |
||
718 | // Turn lights off in sector(tag) |
||
719 | EV_TurnTagLightsOff(line); |
||
720 | line->special = 0; |
||
721 | break; |
||
722 | |||
723 | case 108: |
||
724 | // Blazing Door Raise (faster than TURBO!) |
||
725 | EV_DoDoor (line,blazeRaise); |
||
726 | line->special = 0; |
||
727 | break; |
||
728 | |||
729 | case 109: |
||
730 | // Blazing Door Open (faster than TURBO!) |
||
731 | EV_DoDoor (line,blazeOpen); |
||
732 | line->special = 0; |
||
733 | break; |
||
734 | |||
735 | case 100: |
||
736 | // Build Stairs Turbo 16 |
||
737 | EV_BuildStairs(line,turbo16); |
||
738 | line->special = 0; |
||
739 | break; |
||
740 | |||
741 | case 110: |
||
742 | // Blazing Door Close (faster than TURBO!) |
||
743 | EV_DoDoor (line,blazeClose); |
||
744 | line->special = 0; |
||
745 | break; |
||
746 | |||
747 | case 119: |
||
748 | // Raise floor to nearest surr. floor |
||
749 | EV_DoFloor(line,raiseFloorToNearest); |
||
750 | line->special = 0; |
||
751 | break; |
||
752 | |||
753 | case 121: |
||
754 | // Blazing PlatDownWaitUpStay |
||
755 | EV_DoPlat(line,blazeDWUS,0); |
||
756 | line->special = 0; |
||
757 | break; |
||
758 | |||
759 | case 124: |
||
760 | // Secret EXIT |
||
761 | G_SecretExitLevel (); |
||
762 | break; |
||
763 | |||
764 | case 125: |
||
765 | // TELEPORT MonsterONLY |
||
766 | if (!thing->player) |
||
767 | { |
||
768 | EV_Teleport( line, side, thing ); |
||
769 | line->special = 0; |
||
770 | } |
||
771 | break; |
||
772 | |||
773 | case 130: |
||
774 | // Raise Floor Turbo |
||
775 | EV_DoFloor(line,raiseFloorTurbo); |
||
776 | line->special = 0; |
||
777 | break; |
||
778 | |||
779 | case 141: |
||
780 | // Silent Ceiling Crush & Raise |
||
781 | EV_DoCeiling(line,silentCrushAndRaise); |
||
782 | line->special = 0; |
||
783 | break; |
||
784 | |||
785 | // RETRIGGERS. All from here till end. |
||
786 | case 72: |
||
787 | // Ceiling Crush |
||
788 | EV_DoCeiling( line, lowerAndCrush ); |
||
789 | break; |
||
790 | |||
791 | case 73: |
||
792 | // Ceiling Crush and Raise |
||
793 | EV_DoCeiling(line,crushAndRaise); |
||
794 | break; |
||
795 | |||
796 | case 74: |
||
797 | // Ceiling Crush Stop |
||
798 | EV_CeilingCrushStop(line); |
||
799 | break; |
||
800 | |||
801 | case 75: |
||
802 | // Close Door |
||
803 | EV_DoDoor(line,close); |
||
804 | break; |
||
805 | |||
806 | case 76: |
||
807 | // Close Door 30 |
||
808 | EV_DoDoor(line,close30ThenOpen); |
||
809 | break; |
||
810 | |||
811 | case 77: |
||
812 | // Fast Ceiling Crush & Raise |
||
813 | EV_DoCeiling(line,fastCrushAndRaise); |
||
814 | break; |
||
815 | |||
816 | case 79: |
||
817 | // Lights Very Dark |
||
818 | EV_LightTurnOn(line,35); |
||
819 | break; |
||
820 | |||
821 | case 80: |
||
822 | // Light Turn On - brightest near |
||
823 | EV_LightTurnOn(line,0); |
||
824 | break; |
||
825 | |||
826 | case 81: |
||
827 | // Light Turn On 255 |
||
828 | EV_LightTurnOn(line,255); |
||
829 | break; |
||
830 | |||
831 | case 82: |
||
832 | // Lower Floor To Lowest |
||
833 | EV_DoFloor( line, lowerFloorToLowest ); |
||
834 | break; |
||
835 | |||
836 | case 83: |
||
837 | // Lower Floor |
||
838 | EV_DoFloor(line,lowerFloor); |
||
839 | break; |
||
840 | |||
841 | case 84: |
||
842 | // LowerAndChange |
||
843 | EV_DoFloor(line,lowerAndChange); |
||
844 | break; |
||
845 | |||
846 | case 86: |
||
847 | // Open Door |
||
848 | EV_DoDoor(line,open); |
||
849 | break; |
||
850 | |||
851 | case 87: |
||
852 | // Perpetual Platform Raise |
||
853 | EV_DoPlat(line,perpetualRaise,0); |
||
854 | break; |
||
855 | |||
856 | case 88: |
||
857 | // PlatDownWaitUp |
||
858 | EV_DoPlat(line,downWaitUpStay,0); |
||
859 | break; |
||
860 | |||
861 | case 89: |
||
862 | // Platform Stop |
||
863 | EV_StopPlat(line); |
||
864 | break; |
||
865 | |||
866 | case 90: |
||
867 | // Raise Door |
||
868 | EV_DoDoor(line,normal); |
||
869 | break; |
||
870 | |||
871 | case 91: |
||
872 | // Raise Floor |
||
873 | EV_DoFloor(line,raiseFloor); |
||
874 | break; |
||
875 | |||
876 | case 92: |
||
877 | // Raise Floor 24 |
||
878 | EV_DoFloor(line,raiseFloor24); |
||
879 | break; |
||
880 | |||
881 | case 93: |
||
882 | // Raise Floor 24 And Change |
||
883 | EV_DoFloor(line,raiseFloor24AndChange); |
||
884 | break; |
||
885 | |||
886 | case 94: |
||
887 | // Raise Floor Crush |
||
888 | EV_DoFloor(line,raiseFloorCrush); |
||
889 | break; |
||
890 | |||
891 | case 95: |
||
892 | // Raise floor to nearest height |
||
893 | // and change texture. |
||
894 | EV_DoPlat(line,raiseToNearestAndChange,0); |
||
895 | break; |
||
896 | |||
897 | case 96: |
||
898 | // Raise floor to shortest texture height |
||
899 | // on either side of lines. |
||
900 | EV_DoFloor(line,raiseToTexture); |
||
901 | break; |
||
902 | |||
903 | case 97: |
||
904 | // TELEPORT! |
||
905 | EV_Teleport( line, side, thing ); |
||
906 | break; |
||
907 | |||
908 | case 98: |
||
909 | // Lower Floor (TURBO) |
||
910 | EV_DoFloor(line,turboLower); |
||
911 | break; |
||
912 | |||
913 | case 105: |
||
914 | // Blazing Door Raise (faster than TURBO!) |
||
915 | EV_DoDoor (line,blazeRaise); |
||
916 | break; |
||
917 | |||
918 | case 106: |
||
919 | // Blazing Door Open (faster than TURBO!) |
||
920 | EV_DoDoor (line,blazeOpen); |
||
921 | break; |
||
922 | |||
923 | case 107: |
||
924 | // Blazing Door Close (faster than TURBO!) |
||
925 | EV_DoDoor (line,blazeClose); |
||
926 | break; |
||
927 | |||
928 | case 120: |
||
929 | // Blazing PlatDownWaitUpStay. |
||
930 | EV_DoPlat(line,blazeDWUS,0); |
||
931 | break; |
||
932 | |||
933 | case 126: |
||
934 | // TELEPORT MonsterONLY. |
||
935 | if (!thing->player) |
||
936 | EV_Teleport( line, side, thing ); |
||
937 | break; |
||
938 | |||
939 | case 128: |
||
940 | // Raise To Nearest Floor |
||
941 | EV_DoFloor(line,raiseFloorToNearest); |
||
942 | break; |
||
943 | |||
944 | case 129: |
||
945 | // Raise Floor Turbo |
||
946 | EV_DoFloor(line,raiseFloorTurbo); |
||
947 | break; |
||
948 | } |
||
949 | } |
||
950 | |||
951 | |||
952 | |||
953 | // |
||
954 | // P_ShootSpecialLine - IMPACT SPECIALS |
||
955 | // Called when a thing shoots a special line. |
||
956 | // |
||
957 | void |
||
958 | P_ShootSpecialLine |
||
959 | ( mobj_t* thing, |
||
960 | line_t* line ) |
||
961 | { |
||
962 | int ok; |
||
963 | |||
964 | // Impacts that other things can activate. |
||
965 | if (!thing->player) |
||
966 | { |
||
967 | ok = 0; |
||
968 | switch(line->special) |
||
969 | { |
||
970 | case 46: |
||
971 | // OPEN DOOR IMPACT |
||
972 | ok = 1; |
||
973 | break; |
||
974 | } |
||
975 | if (!ok) |
||
976 | return; |
||
977 | } |
||
978 | |||
979 | switch(line->special) |
||
980 | { |
||
981 | case 24: |
||
982 | // RAISE FLOOR |
||
983 | EV_DoFloor(line,raiseFloor); |
||
984 | P_ChangeSwitchTexture(line,0); |
||
985 | break; |
||
986 | |||
987 | case 46: |
||
988 | // OPEN DOOR |
||
989 | EV_DoDoor(line,open); |
||
990 | P_ChangeSwitchTexture(line,1); |
||
991 | break; |
||
992 | |||
993 | case 47: |
||
994 | // RAISE FLOOR NEAR AND CHANGE |
||
995 | EV_DoPlat(line,raiseToNearestAndChange,0); |
||
996 | P_ChangeSwitchTexture(line,0); |
||
997 | break; |
||
998 | } |
||
999 | } |
||
1000 | |||
1001 | |||
1002 | |||
1003 | // |
||
1004 | // P_PlayerInSpecialSector |
||
1005 | // Called every tic frame |
||
1006 | // that the player origin is in a special sector |
||
1007 | // |
||
1008 | void P_PlayerInSpecialSector (player_t* player) |
||
1009 | { |
||
1010 | sector_t* sector; |
||
1011 | |||
1012 | sector = player->mo->subsector->sector; |
||
1013 | |||
1014 | // Falling, not all the way down yet? |
||
1015 | if (player->mo->z != sector->floorheight) |
||
1016 | return; |
||
1017 | |||
1018 | // Has hitten ground. |
||
1019 | switch (sector->special) |
||
1020 | { |
||
1021 | case 5: |
||
1022 | // HELLSLIME DAMAGE |
||
1023 | if (!player->powers[pw_ironfeet]) |
||
1024 | if (!(leveltime&0x1f)) |
||
1025 | P_DamageMobj (player->mo, NULL, NULL, 10); |
||
1026 | break; |
||
1027 | |||
1028 | case 7: |
||
1029 | // NUKAGE DAMAGE |
||
1030 | if (!player->powers[pw_ironfeet]) |
||
1031 | if (!(leveltime&0x1f)) |
||
1032 | P_DamageMobj (player->mo, NULL, NULL, 5); |
||
1033 | break; |
||
1034 | |||
1035 | case 16: |
||
1036 | // SUPER HELLSLIME DAMAGE |
||
1037 | case 4: |
||
1038 | // STROBE HURT |
||
1039 | if (!player->powers[pw_ironfeet] |
||
1040 | || (P_Random()<5) ) |
||
1041 | { |
||
1042 | if (!(leveltime&0x1f)) |
||
1043 | P_DamageMobj (player->mo, NULL, NULL, 20); |
||
1044 | } |
||
1045 | break; |
||
1046 | |||
1047 | case 9: |
||
1048 | // SECRET SECTOR |
||
1049 | player->secretcount++; |
||
1050 | sector->special = 0; |
||
1051 | break; |
||
1052 | |||
1053 | case 11: |
||
1054 | // EXIT SUPER DAMAGE! (for E1M8 finale) |
||
1055 | player->cheats &= ~CF_GODMODE; |
||
1056 | |||
1057 | if (!(leveltime&0x1f)) |
||
1058 | P_DamageMobj (player->mo, NULL, NULL, 20); |
||
1059 | |||
1060 | if (player->health <= 10) |
||
1061 | G_ExitLevel(); |
||
1062 | break; |
||
1063 | |||
1064 | default: |
||
1065 | I_Error ("P_PlayerInSpecialSector: " |
||
1066 | "unknown special %i", |
||
1067 | sector->special); |
||
1068 | break; |
||
1069 | }; |
||
1070 | } |
||
1071 | |||
1072 | |||
1073 | |||
1074 | |||
1075 | // |
||
1076 | // P_UpdateSpecials |
||
1077 | // Animate planes, scroll walls, etc. |
||
1078 | // |
||
1079 | boolean levelTimer; |
||
1080 | int levelTimeCount; |
||
1081 | |||
1082 | void P_UpdateSpecials (void) |
||
1083 | { |
||
1084 | anim_t* anim; |
||
1085 | int pic; |
||
1086 | int i; |
||
1087 | line_t* line; |
||
1088 | |||
1089 | |||
1090 | // LEVEL TIMER |
||
1091 | if (levelTimer == true) |
||
1092 | { |
||
1093 | levelTimeCount--; |
||
1094 | if (!levelTimeCount) |
||
1095 | G_ExitLevel(); |
||
1096 | } |
||
1097 | |||
1098 | // ANIMATE FLATS AND TEXTURES GLOBALLY |
||
1099 | for (anim = anims ; anim < lastanim ; anim++) |
||
1100 | { |
||
1101 | for (i=anim->basepic ; i |
||
1102 | { |
||
1103 | pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); |
||
1104 | if (anim->istexture) |
||
1105 | texturetranslation[i] = pic; |
||
1106 | else |
||
1107 | flattranslation[i] = pic; |
||
1108 | } |
||
1109 | } |
||
1110 | |||
1111 | |||
1112 | // ANIMATE LINE SPECIALS |
||
1113 | for (i = 0; i < numlinespecials; i++) |
||
1114 | { |
||
1115 | line = linespeciallist[i]; |
||
1116 | switch(line->special) |
||
1117 | { |
||
1118 | case 48: |
||
1119 | // EFFECT FIRSTCOL SCROLL + |
||
1120 | sides[line->sidenum[0]].textureoffset += FRACUNIT; |
||
1121 | break; |
||
1122 | } |
||
1123 | } |
||
1124 | |||
1125 | |||
1126 | // DO BUTTONS |
||
1127 | for (i = 0; i < MAXBUTTONS; i++) |
||
1128 | if (buttonlist[i].btimer) |
||
1129 | { |
||
1130 | buttonlist[i].btimer--; |
||
1131 | if (!buttonlist[i].btimer) |
||
1132 | { |
||
1133 | switch(buttonlist[i].where) |
||
1134 | { |
||
1135 | case top: |
||
1136 | sides[buttonlist[i].line->sidenum[0]].toptexture = |
||
1137 | buttonlist[i].btexture; |
||
1138 | break; |
||
1139 | |||
1140 | case middle: |
||
1141 | sides[buttonlist[i].line->sidenum[0]].midtexture = |
||
1142 | buttonlist[i].btexture; |
||
1143 | break; |
||
1144 | |||
1145 | case bottom: |
||
1146 | sides[buttonlist[i].line->sidenum[0]].bottomtexture = |
||
1147 | buttonlist[i].btexture; |
||
1148 | break; |
||
1149 | } |
||
1150 | S_StartSound((mobj_t *)&buttonlist[i].soundorg,sfx_swtchn); |
||
1151 | memset(&buttonlist[i],0,sizeof(button_t)); |
||
1152 | } |
||
1153 | } |
||
1154 | |||
1155 | } |
||
1156 | |||
1157 | |||
1158 | |||
1159 | // |
||
1160 | // Special Stuff that can not be categorized |
||
1161 | // |
||
1162 | int EV_DoDonut(line_t* line) |
||
1163 | { |
||
1164 | sector_t* s1; |
||
1165 | sector_t* s2; |
||
1166 | sector_t* s3; |
||
1167 | int secnum; |
||
1168 | int rtn; |
||
1169 | int i; |
||
1170 | floormove_t* floor; |
||
1171 | |||
1172 | secnum = -1; |
||
1173 | rtn = 0; |
||
1174 | while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) |
||
1175 | { |
||
1176 | s1 = §ors[secnum]; |
||
1177 | |||
1178 | // ALREADY MOVING? IF SO, KEEP GOING... |
||
1179 | if (s1->specialdata) |
||
1180 | continue; |
||
1181 | |||
1182 | rtn = 1; |
||
1183 | s2 = getNextSector(s1->lines[0],s1); |
||
1184 | for (i = 0;i < s2->linecount;i++) |
||
1185 | { |
||
1186 | if ((!s2->lines[i]->flags & ML_TWOSIDED) || |
||
1187 | (s2->lines[i]->backsector == s1)) |
||
1188 | continue; |
||
1189 | s3 = s2->lines[i]->backsector; |
||
1190 | |||
1191 | // Spawn rising slime |
||
1192 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); |
||
1193 | P_AddThinker (&floor->thinker); |
||
1194 | s2->specialdata = floor; |
||
1195 | floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; |
||
1196 | floor->type = donutRaise; |
||
1197 | floor->crush = false; |
||
1198 | floor->direction = 1; |
||
1199 | floor->sector = s2; |
||
1200 | floor->speed = FLOORSPEED / 2; |
||
1201 | floor->texture = s3->floorpic; |
||
1202 | floor->newspecial = 0; |
||
1203 | floor->floordestheight = s3->floorheight; |
||
1204 | |||
1205 | // Spawn lowering donut-hole |
||
1206 | floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); |
||
1207 | P_AddThinker (&floor->thinker); |
||
1208 | s1->specialdata = floor; |
||
1209 | floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; |
||
1210 | floor->type = lowerFloor; |
||
1211 | floor->crush = false; |
||
1212 | floor->direction = -1; |
||
1213 | floor->sector = s1; |
||
1214 | floor->speed = FLOORSPEED / 2; |
||
1215 | floor->floordestheight = s3->floorheight; |
||
1216 | break; |
||
1217 | } |
||
1218 | } |
||
1219 | return rtn; |
||
1220 | } |
||
1221 | |||
1222 | |||
1223 | |||
1224 | // |
||
1225 | // SPECIAL SPAWNING |
||
1226 | // |
||
1227 | |||
1228 | // |
||
1229 | // P_SpawnSpecials |
||
1230 | // After the map has been loaded, scan for specials |
||
1231 | // that spawn thinkers |
||
1232 | // |
||
1233 | short numlinespecials; |
||
1234 | line_t* linespeciallist[MAXLINEANIMS]; |
||
1235 | |||
1236 | |||
1237 | // Parses command line parameters. |
||
1238 | void P_SpawnSpecials (void) |
||
1239 | { |
||
1240 | sector_t* sector; |
||
1241 | int i; |
||
1242 | int episode; |
||
1243 | |||
1244 | episode = 1; |
||
1245 | if (W_CheckNumForName("texture2") >= 0) |
||
1246 | episode = 2; |
||
1247 | |||
1248 | |||
1249 | // See if -TIMER needs to be used. |
||
1250 | levelTimer = false; |
||
1251 | |||
1252 | i = M_CheckParm("-avg"); |
||
1253 | if (i && deathmatch) |
||
1254 | { |
||
1255 | levelTimer = true; |
||
1256 | levelTimeCount = 20 * 60 * 35; |
||
1257 | } |
||
1258 | |||
1259 | i = M_CheckParm("-timer"); |
||
1260 | if (i && deathmatch) |
||
1261 | { |
||
1262 | int time; |
||
1263 | time = atoi(myargv[i+1]) * 60 * 35; |
||
1264 | levelTimer = true; |
||
1265 | levelTimeCount = time; |
||
1266 | } |
||
1267 | |||
1268 | // Init special SECTORs. |
||
1269 | sector = sectors; |
||
1270 | for (i=0 ; i |
||
1271 | { |
||
1272 | if (!sector->special) |
||
1273 | continue; |
||
1274 | |||
1275 | switch (sector->special) |
||
1276 | { |
||
1277 | case 1: |
||
1278 | // FLICKERING LIGHTS |
||
1279 | P_SpawnLightFlash (sector); |
||
1280 | break; |
||
1281 | |||
1282 | case 2: |
||
1283 | // STROBE FAST |
||
1284 | P_SpawnStrobeFlash(sector,FASTDARK,0); |
||
1285 | break; |
||
1286 | |||
1287 | case 3: |
||
1288 | // STROBE SLOW |
||
1289 | P_SpawnStrobeFlash(sector,SLOWDARK,0); |
||
1290 | break; |
||
1291 | |||
1292 | case 4: |
||
1293 | // STROBE FAST/DEATH SLIME |
||
1294 | P_SpawnStrobeFlash(sector,FASTDARK,0); |
||
1295 | sector->special = 4; |
||
1296 | break; |
||
1297 | |||
1298 | case 8: |
||
1299 | // GLOWING LIGHT |
||
1300 | P_SpawnGlowingLight(sector); |
||
1301 | break; |
||
1302 | case 9: |
||
1303 | // SECRET SECTOR |
||
1304 | totalsecret++; |
||
1305 | break; |
||
1306 | |||
1307 | case 10: |
||
1308 | // DOOR CLOSE IN 30 SECONDS |
||
1309 | P_SpawnDoorCloseIn30 (sector); |
||
1310 | break; |
||
1311 | |||
1312 | case 12: |
||
1313 | // SYNC STROBE SLOW |
||
1314 | P_SpawnStrobeFlash (sector, SLOWDARK, 1); |
||
1315 | break; |
||
1316 | |||
1317 | case 13: |
||
1318 | // SYNC STROBE FAST |
||
1319 | P_SpawnStrobeFlash (sector, FASTDARK, 1); |
||
1320 | break; |
||
1321 | |||
1322 | case 14: |
||
1323 | // DOOR RAISE IN 5 MINUTES |
||
1324 | P_SpawnDoorRaiseIn5Mins (sector, i); |
||
1325 | break; |
||
1326 | |||
1327 | case 17: |
||
1328 | P_SpawnFireFlicker(sector); |
||
1329 | break; |
||
1330 | } |
||
1331 | } |
||
1332 | |||
1333 | |||
1334 | // Init line EFFECTs |
||
1335 | numlinespecials = 0; |
||
1336 | for (i = 0;i < numlines; i++) |
||
1337 | { |
||
1338 | switch(lines[i].special) |
||
1339 | { |
||
1340 | case 48: |
||
1341 | // EFFECT FIRSTCOL SCROLL+ |
||
1342 | linespeciallist[numlinespecials] = &lines[i]; |
||
1343 | numlinespecials++; |
||
1344 | break; |
||
1345 | } |
||
1346 | } |
||
1347 | |||
1348 | |||
1349 | // Init other misc stuff |
||
1350 | for (i = 0;i < MAXCEILINGS;i++) |
||
1351 | activeceilings[i] = NULL; |
||
1352 | |||
1353 | for (i = 0;i < MAXPLATS;i++) |
||
1354 | activeplats[i] = NULL; |
||
1355 | |||
1356 | for (i = 0;i < MAXBUTTONS;i++) |
||
1357 | memset(&buttonlist[i],0,sizeof(button_t)); |
||
1358 | |||
1359 | // UNUSED: no horizonal sliders. |
||
1360 | // P_InitSlidingDoorFrames(); |
||
1361 | }>>>>>>>>=>5)>>> |