DOOM64-RE

DOOM 64 Reverse Engineering
Log | Files | Refs | README | LICENSE

p_spec.c (36278B)


      1 /* P_Spec.c */
      2 #include "doomdef.h"
      3 #include "r_local.h"
      4 #include "p_local.h"
      5 #include "st_main.h"
      6 
      7 extern mapthing_t  *spawnlist;     // 800A5D74
      8 extern int         spawncount;     // 800A5D78
      9 
     10 line_t	    **linespeciallist;  // 800A5F60
     11 int		    numlinespecials;    // 800A5F64
     12 
     13 sector_t    **sectorspeciallist;// 800A5F68
     14 int         numsectorspecials;  // 800A5F6C
     15 
     16 animdef_t		animdefs[MAXANIMS] = // 8005AE80
     17 {
     18 	{ 15, "SMONAA", 4, 7, false, false },
     19 	{  0, "SMONBA", 4, 1, false, false },
     20 	{  0, "SMONCA", 4, 7, false, false },
     21 	{ 90, "CFACEA", 3, 3,  true, false },
     22 	{  0, "SMONDA", 4, 3, false, false },
     23 	{ 10, "SMONEA", 4, 7, false, false },
     24 	{  0, "SPORTA", 9, 3, false,  true },
     25 	{ 10,  "SMONF", 5, 1,  true,  true },
     26 	{ 10, "STRAKR", 5, 1,  true,  true },
     27 	{ 10, "STRAKB", 5, 1,  true,  true },
     28 	{ 10, "STRAKY", 5, 1,  true,  true },
     29 	{ 50,  "C307B", 5, 1,  true,  true },
     30 	{  0,   "CTEL", 8, 3, false,  true },
     31 	{  0,"CASFL98", 5, 7,  true,  true },
     32 	{  0,  "HTELA", 4, 1,  true, false }
     33 };
     34 
     35 /*----------
     36 / anims[8] -> anims[MAXANIMS = 15]
     37 / For some reason Doom 64 is 8,
     38 / I will leave it at 15 to avoid problems loading data into this pointer.
     39 /---------*/
     40 anim_t	anims[MAXANIMS], *lastanim; // 800A5F70, 800A6090
     41 
     42 card_t      MapBlueKeyType;     //0x80077E9C
     43 card_t      MapRedKeyType;      //0x8007821C
     44 card_t      MapYellowKeyType;   //0x800780A0
     45 
     46 void P_AddSectorSpecial(sector_t *sec);
     47 
     48 /*
     49 =================
     50 =
     51 = P_Init
     52 =
     53 =================
     54 */
     55 
     56 void P_Init (void) // 8001F340
     57 {
     58 	int i;
     59 	sector_t    *sector;
     60 	side_t      *side;
     61 
     62 	side = sides;
     63 	for (i = 0; i < numsides; i++, side++)
     64 	{
     65         W_CacheLumpNum(side->toptexture + firsttex    , PU_LEVEL, dec_d64);
     66         W_CacheLumpNum(side->bottomtexture + firsttex , PU_LEVEL, dec_d64);
     67         W_CacheLumpNum(side->midtexture + firsttex    , PU_LEVEL, dec_d64);
     68 	}
     69 
     70 	sector = sectors;
     71 	for (i = 0; i < numsectors; i++, sector++)
     72 	{
     73 		if (sector->ceilingpic >= 0)
     74             W_CacheLumpNum(sector->ceilingpic + firsttex, PU_LEVEL, dec_d64);
     75 
     76         if (sector->floorpic >= 0)
     77             W_CacheLumpNum(sector->floorpic + firsttex, PU_LEVEL, dec_d64);
     78 
     79         if (sector->flags & MS_LIQUIDFLOOR)
     80             W_CacheLumpNum(sector->floorpic + firsttex + 1, PU_LEVEL,dec_d64);
     81 	}
     82 }
     83 
     84 /*
     85 ==============================================================================
     86 
     87 							SPECIAL SPAWNING
     88 
     89 ==============================================================================
     90 */
     91 /*
     92 ================================================================================
     93 = P_SpawnSpecials
     94 =
     95 = After the map has been loaded, scan for specials that
     96 = spawn thinkers
     97 =
     98 ===============================================================================
     99 */
    100 
    101 void P_SpawnSpecials (void) // 8001F490
    102 {
    103     mobj_t      *mo;
    104 	sector_t    *sector;
    105 	line_t      *line;
    106 	int         i, j;
    107 	int         lump;
    108 
    109 	/* */
    110 	/*	Init animation aka (P_InitPicAnims) */
    111 	/* */
    112 	lastanim = anims;
    113 	for (i=0 ; i < MAXANIMS ; i++)
    114 	{
    115 	    lump = W_GetNumForName(animdefs[i].startname);
    116 
    117         lastanim->basepic   = (lump - firsttex);
    118         lastanim->tics      = animdefs[i].speed;
    119         lastanim->delay     = animdefs[i].delay;
    120         lastanim->delaycnt  = lastanim->delay;
    121         lastanim->isreverse = animdefs[i].isreverse;
    122 
    123 	    if (animdefs[i].ispalcycle == false)
    124 	    {
    125             lastanim->current   = (lump << 4);
    126             lastanim->picstart  = (lump << 4);
    127             lastanim->picend    = (animdefs[i].frames + lump - 1) << 4;
    128             lastanim->frame     = 16;
    129 
    130             /* Load the following graphics for animation */
    131             for (j=0 ; j < animdefs[i].frames ; j++)
    132             {
    133                 W_CacheLumpNum(lump, PU_LEVEL, dec_d64);
    134                 lump++;
    135             }
    136 	    }
    137 	    else
    138         {
    139             lastanim->current   = (lump << 4);
    140             lastanim->picstart  = (lump << 4);
    141             lastanim->picend    = (lump << 4) | (animdefs[i].frames - 1);
    142             lastanim->frame     = 1;
    143         }
    144 
    145 		lastanim++;
    146 	}
    147 
    148 	/* */
    149 	/*	Init Macro Variables */
    150 	/* */
    151     activemacro = NULL;
    152     macrocounter = 0;
    153     macroidx1 = 0;
    154     macroidx2 = 0;
    155 
    156 	/* */
    157 	/*	Init special SECTORs */
    158 	/* */
    159 	scrollfrac = 0;
    160 	numsectorspecials = 0; // Restart count
    161 	sector = sectors;
    162 	for(i = 0; i < numsectors; i++, sector++)
    163     {
    164         P_AddSectorSpecial(sector);
    165         if(sector->flags & MS_SECRET)
    166         {
    167             totalsecret++;
    168         }
    169 
    170         if(sector->flags & (MS_SCROLLCEILING | MS_SCROLLFLOOR|
    171         MS_SCROLLLEFT | MS_SCROLLRIGHT| MS_SCROLLUP| MS_SCROLLDOWN))
    172         {
    173             numsectorspecials++;
    174         }
    175     }
    176 
    177     sectorspeciallist = (sector_t**)Z_Malloc(numsectorspecials*sizeof(void*), PU_LEVEL, NULL);
    178     sector = sectors;
    179 	for(i = 0, j = 0; i < numsectors; i++, sector++)
    180     {
    181         if(sector->flags & (MS_SCROLLCEILING | MS_SCROLLFLOOR|
    182         MS_SCROLLLEFT | MS_SCROLLRIGHT| MS_SCROLLUP| MS_SCROLLDOWN))
    183         {
    184             sectorspeciallist[j] = sector;
    185             j++;
    186         }
    187     }
    188 
    189 	/* */
    190 	/*	Init line EFFECTs */
    191 	/* */
    192 	numlinespecials = 0;
    193 	line = lines;
    194 	for (i = 0;i < numlines; i++, line++)
    195     {
    196         if(line->flags & (ML_SCROLLRIGHT|ML_SCROLLLEFT|ML_SCROLLUP|ML_SCROLLDOWN))
    197         {
    198             numlinespecials++;
    199         }
    200     }
    201 
    202     linespeciallist = (line_t**)Z_Malloc(numlinespecials*sizeof(void*), PU_LEVEL, NULL);
    203     line = lines;
    204 	for (i = 0, j = 0; i < numlines; i++, line++)
    205     {
    206         if(line->flags & (ML_SCROLLRIGHT|ML_SCROLLLEFT|ML_SCROLLUP|ML_SCROLLDOWN))
    207         {
    208             linespeciallist[j] = line;
    209             j++;
    210         }
    211     }
    212 
    213     /* */
    214 	/*	Init Keys */
    215 	/* */
    216 
    217     MapBlueKeyType   = it_bluecard;
    218     MapYellowKeyType = it_yellowcard;
    219     MapRedKeyType    = it_redcard;
    220     for (mo = mobjhead.next ; mo != &mobjhead ; mo = mo->next)
    221     {
    222         if((mo->type == MT_ITEM_BLUESKULLKEY) ||
    223            (mo->type == MT_ITEM_YELLOWSKULLKEY) ||
    224            (mo->type == MT_ITEM_REDSKULLKEY))
    225         {
    226             MapBlueKeyType   = it_blueskull;
    227             MapYellowKeyType = it_yellowskull;
    228             MapRedKeyType    = it_redskull;
    229             break;
    230         }
    231 
    232         /*switch (mo->type)
    233         {
    234             case MT_ITEM_BLUESKULLKEY:   MapBlueKeyType   = it_blueskull;     break;
    235             case MT_ITEM_YELLOWSKULLKEY: MapYellowKeyType = it_yellowskull;   break;
    236             case MT_ITEM_REDSKULLKEY:    MapRedKeyType    = it_redskull;      break;
    237         }*/
    238     }
    239 
    240     for (i = 0; i < spawncount; i++)
    241     {
    242         if((spawnlist[i].type == 40) ||
    243            (spawnlist[i].type == 39) ||
    244            (spawnlist[i].type == 38))
    245         {
    246             MapBlueKeyType   = it_blueskull;
    247             MapYellowKeyType = it_yellowskull;
    248             MapRedKeyType    = it_redskull;
    249             break;
    250         }
    251 
    252         /*if(spawnlist[i].type == 40)//mobjinfo[MT_ITEM_BLUESKULLKEY].doomednum
    253             MapBlueKeyType   = it_blueskull;
    254         if(spawnlist[i].type == 39)//mobjinfo[MT_ITEM_YELLOWSKULLKEY].doomednum
    255             MapYellowKeyType   = it_yellowskull;
    256         if(spawnlist[i].type == 38)//mobjinfo[MT_ITEM_REDSKULLKEY].doomednum
    257             MapRedKeyType   = it_redskull;*/
    258     }
    259 
    260 	/* */
    261 	/*	Init other misc stuff */
    262 	/* */
    263 	D_memset(activeceilings, 0, MAXCEILINGS * sizeof(ceiling_t*));
    264 	D_memset(activeplats, 0, MAXPLATS * sizeof(plat_t*));
    265 	D_memset(buttonlist, 0, MAXBUTTONS * sizeof(button_t));
    266 }
    267 
    268 /*
    269 ==============================================================================
    270 
    271 							UTILITIES
    272 
    273 ==============================================================================
    274 */
    275 
    276 /*================================================================== */
    277 /* */
    278 /*	Return sector_t * of sector next to current. NULL if not two-sided line */
    279 /* */
    280 /*================================================================== */
    281 sector_t *getNextSector(line_t *line,sector_t *sec) // 8001F96C
    282 {
    283 	if (!(line->flags & ML_TWOSIDED))
    284 		return NULL;
    285 
    286 	if (line->frontsector == sec)
    287 		return line->backsector;
    288 
    289 	return line->frontsector;
    290 }
    291 
    292 /*================================================================== */
    293 /* */
    294 /*	FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS */
    295 /* */
    296 /*================================================================== */
    297 fixed_t	P_FindLowestFloorSurrounding(sector_t *sec) // 8001F9AC
    298 {
    299 	int			i;
    300 	line_t		*check;
    301 	sector_t	*other;
    302 	fixed_t		floor = sec->floorheight;
    303 
    304 	for (i=0 ;i < sec->linecount ; i++)
    305 	{
    306 		check = sec->lines[i];
    307 		other = getNextSector(check,sec);
    308 		if (!other)
    309 			continue;
    310 		if (other->floorheight < floor)
    311 			floor = other->floorheight;
    312 	}
    313 	return floor;
    314 }
    315 
    316 /*================================================================== */
    317 /* */
    318 /*	FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS */
    319 /* */
    320 /*================================================================== */
    321 fixed_t	P_FindHighestFloorSurrounding(sector_t *sec) // 8001FA48
    322 {
    323 	int			i;
    324 	line_t		*check;
    325 	sector_t	*other;
    326 	fixed_t		floor = -500*FRACUNIT;
    327 
    328 	for (i=0 ;i < sec->linecount ; i++)
    329 	{
    330 		check = sec->lines[i];
    331 		other = getNextSector(check,sec);
    332 		if (!other)
    333 			continue;
    334 		if (other->floorheight > floor)
    335 			floor = other->floorheight;
    336 	}
    337 	return floor;
    338 }
    339 
    340 /*================================================================== */
    341 /* */
    342 /*	FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS */
    343 /* */
    344 /*================================================================== */
    345 fixed_t	P_FindNextHighestFloor(sector_t *sec,int currentheight) // 8001FAE4
    346 {
    347 	int			i;
    348 	int			h;
    349 	int			min;
    350 	line_t		*check;
    351 	sector_t	*other;
    352 	fixed_t		height = currentheight;
    353 	fixed_t		heightlist[20];		/* 20 adjoining sectors max! */
    354 
    355 	for (i =0,h = 0 ;i < sec->linecount ; i++)
    356 	{
    357 		check = sec->lines[i];
    358 		other = getNextSector(check,sec);
    359 		if (!other)
    360 			continue;
    361 		if (other->floorheight > height)
    362 			heightlist[h++] = other->floorheight;
    363 	}
    364 
    365 	/* */
    366 	/* Find lowest height in list */
    367 	/* */
    368 	min = heightlist[0];
    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 /*================================================================== */
    381 fixed_t	P_FindLowestCeilingSurrounding(sector_t *sec) // 8001FC68
    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 		if (!other)
    393 			continue;
    394 		if (other->ceilingheight < height)
    395 			height = other->ceilingheight;
    396 	}
    397 	return height;
    398 }
    399 
    400 /*================================================================== */
    401 /* */
    402 /*	FIND HIGHEST CEILING IN THE SURROUNDING SECTORS */
    403 /* */
    404 /*================================================================== */
    405 fixed_t	P_FindHighestCeilingSurrounding(sector_t *sec) // 8001FD08
    406 {
    407 	int	i;
    408 	line_t	*check;
    409 	sector_t	*other;
    410 	fixed_t	height = 0;
    411 
    412 	for (i=0 ;i < sec->linecount ; i++)
    413 	{
    414 		check = sec->lines[i];
    415 		other = getNextSector(check,sec);
    416 		if (!other)
    417 			continue;
    418 		if (other->ceilingheight > height)
    419 			height = other->ceilingheight;
    420 	}
    421 	return height;
    422 }
    423 
    424 /*================================================================== */
    425 /* */
    426 /*	RETURN NEXT SECTOR # THAT LINE TAG REFERS TO */
    427 /* */
    428 /*================================================================== */
    429 int	P_FindSectorFromLineTag(int tag,int start) // 8001FDA4
    430 {
    431 	int	i;
    432 
    433 	for (i=start+1;i<numsectors;i++)
    434 		if (sectors[i].tag == tag)
    435 			return i;
    436 	return -1;
    437 }
    438 
    439 /*================================================================== */
    440 /* */
    441 /*	RETURN NEXT LIGHT # THAT LINE TAG REFERS TO */
    442 /*	Exclusive Doom 64 */
    443 /* */
    444 /*================================================================== */
    445 int P_FindLightFromLightTag(int tag,int start) // 8001FE08
    446 {
    447 	int	i;
    448 
    449 	for (i=(start+256+1);i<numlights;i++)
    450 		if (lights[i].tag == tag)
    451 			return i;
    452 	return -1;
    453 }
    454 
    455 /*================================================================== */
    456 /* */
    457 /*	RETURN TRUE OR FALSE */
    458 /*	Exclusive Doom 64 */
    459 /* */
    460 /*================================================================== */
    461 boolean P_ActivateLineByTag(int tag,mobj_t *thing) // 8001FE64
    462 {
    463 	int	i;
    464 	line_t *li;
    465 
    466 	li = lines;
    467 	for (i=0;i<numlines;i++,li++)
    468     {
    469 		if (li->tag == tag)
    470 			return P_UseSpecialLine(li, thing);
    471     }
    472 	return false;
    473 }
    474 
    475 #if 0
    476 /*================================================================== */
    477 /* */
    478 /*	Find minimum light from an adjacent sector */
    479 /* */
    480 /*================================================================== */
    481 int	P_FindMinSurroundingLight(sector_t *sector,int max)//L80026C10()
    482 {
    483 	int			i;
    484 	int			min;
    485 	line_t		*line;
    486 	sector_t	*check;
    487 
    488 	min = max;
    489 	for (i=0 ; i < sector->linecount ; i++)
    490 	{
    491 		line = sector->lines[i];
    492 		check = getNextSector(line,sector);
    493 		if (!check)
    494 			continue;
    495 		if (check->lightlevel < min)
    496 			min = check->lightlevel;
    497 	}
    498 	return min;
    499 }
    500 #endif // 0
    501 
    502 /*
    503 ==============================================================================
    504 
    505 							EVENTS
    506 
    507 Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
    508 
    509 ==============================================================================
    510 */
    511 
    512 /*
    513 ===============================================================================
    514 =
    515 = P_UpdateSpecials
    516 =
    517 = Animate planes, scroll walls, etc
    518 ===============================================================================
    519 */
    520 
    521 #define SCROLLLIMIT (FRACUNIT*127)
    522 
    523 void P_UpdateSpecials (void) // 8001FEC0
    524 {
    525 	anim_t		*anim;
    526 	line_t		*line;
    527 	sector_t	*sector;
    528 	fixed_t     speed;
    529 	int			i;
    530 	int         neg;
    531 
    532 	/* */
    533 	/*	ANIMATE FLATS AND TEXTURES GLOBALY */
    534 	/* */
    535 	for (anim = anims ; anim < lastanim ; anim++)
    536 	{
    537 	    anim->delaycnt--;
    538 		if ((anim->delaycnt <= 0) && !(gametic & anim->tics))
    539 		{
    540 		    anim->current += anim->frame;
    541 
    542 		    if ((anim->current < anim->picstart) || (anim->picend < anim->current))
    543             {
    544                 neg = -anim->frame;
    545 
    546                 if (anim->isreverse)
    547                 {
    548                     anim->frame = neg;
    549                     anim->current += neg;
    550 
    551                     if (anim->delay == 0)
    552                         anim->current += neg + neg;
    553                 }
    554                 else
    555                 {
    556                     anim->current = anim->picstart;
    557                 }
    558 
    559                 anim->delaycnt = anim->delay;
    560             }
    561 
    562             textures[anim->basepic] = anim->current;
    563 		}
    564 	}
    565 
    566 	/* */
    567 	/*	ANIMATE LINE SPECIALS */
    568 	/* */
    569 	for (i = 0; i < numlinespecials; i++)
    570 	{
    571 		line = linespeciallist[i];
    572 
    573 		if(line->flags & ML_SCROLLRIGHT)
    574         {
    575             sides[line->sidenum[0]].textureoffset += FRACUNIT;
    576             sides[line->sidenum[0]].textureoffset &= SCROLLLIMIT;
    577         }
    578         else if(line->flags & ML_SCROLLLEFT)
    579         {
    580             sides[line->sidenum[0]].textureoffset -= FRACUNIT;
    581             sides[line->sidenum[0]].textureoffset &= SCROLLLIMIT;
    582         }
    583 
    584         if(line->flags & ML_SCROLLUP)
    585         {
    586             sides[line->sidenum[0]].rowoffset += FRACUNIT;
    587             sides[line->sidenum[0]].rowoffset &= SCROLLLIMIT;
    588         }
    589         else if(line->flags & ML_SCROLLDOWN)
    590         {
    591             sides[line->sidenum[0]].rowoffset -= FRACUNIT;
    592             sides[line->sidenum[0]].rowoffset &= SCROLLLIMIT;
    593         }
    594 	}
    595 
    596 	/* */
    597 	/*	ANIMATE SECTOR SPECIALS */
    598 	/* */
    599 
    600     scrollfrac = (scrollfrac + (FRACUNIT / 2));
    601 
    602     for (i = 0; i < numsectorspecials; i++)
    603 	{
    604 		sector = sectorspeciallist[i];
    605 
    606 		if(sector->flags & MS_SCROLLFAST)
    607             speed = 3*FRACUNIT;
    608         else
    609             speed = FRACUNIT;
    610 
    611         if(sector->flags & MS_SCROLLLEFT)
    612         {
    613             sector->xoffset += speed;
    614         }
    615         else if(sector->flags & MS_SCROLLRIGHT)
    616         {
    617             sector->xoffset -= speed;
    618         }
    619 
    620         if(sector->flags & MS_SCROLLUP)
    621         {
    622             sector->yoffset -= speed;
    623         }
    624         else if(sector->flags & MS_SCROLLDOWN)
    625         {
    626             sector->yoffset += speed;
    627         }
    628 	}
    629 
    630 	/* */
    631 	/*	DO BUTTONS */
    632 	/* */
    633 	for (i = 0; i < MAXBUTTONS; i++)
    634 	{
    635 		if (buttonlist[i].btimer > 0)
    636 		{
    637 			buttonlist[i].btimer -= vblsinframe[0];
    638 
    639 			if (buttonlist[i].btimer <= 0)
    640 			{
    641 				switch (buttonlist[i].where)
    642 				{
    643 				case top:
    644 					buttonlist[i].side->toptexture = buttonlist[i].btexture;
    645 					break;
    646 				case middle:
    647 					buttonlist[i].side->midtexture = buttonlist[i].btexture;
    648 					break;
    649 				case bottom:
    650 					buttonlist[i].side->bottomtexture = buttonlist[i].btexture;
    651 					break;
    652 				}
    653 				S_StartSound((mobj_t *)buttonlist[i].soundorg, sfx_switch1);
    654 				D_memset(&buttonlist[i], 0, sizeof(button_t)); // ? Doom 64 elimina esta linea
    655 			}
    656 		}
    657 	}
    658 }
    659 
    660 /*
    661 ==============================================================================
    662 
    663 							UTILITIES
    664 
    665 ==============================================================================
    666 */
    667 
    668 /* */
    669 /*	Will return a side_t* given the number of the current sector, */
    670 /*		the line number, and the side (0/1) that you want. */
    671 /* */
    672 side_t *getSide(int currentSector,int line, int side) // 8002026C
    673 {
    674 	return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
    675 }
    676 
    677 /* */
    678 /*	Will return a sector_t* given the number of the current sector, */
    679 /*		the line number and the side (0/1) that you want. */
    680 /* */
    681 sector_t *getSector(int currentSector,int line,int side) // 800202BC
    682 {
    683 	return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
    684 }
    685 
    686 /* */
    687 /*	Given the sector number and the line number, will tell you whether */
    688 /*		the line is two-sided or not. */
    689 /* */
    690 int	twoSided(int sector,int line) // 80020314
    691 {
    692 	return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
    693 }
    694 
    695 /*
    696 ==============================================================================
    697 
    698 							EVENTS
    699 
    700 Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
    701 
    702 ==============================================================================
    703 */
    704 
    705 void P_AddSectorSpecial(sector_t* sector) // 80020354
    706 {
    707 
    708     if((sector->flags & MS_SYNCSPECIALS) && (sector->special))
    709     {
    710         P_CombineLightSpecials(sector);
    711         return;
    712     }
    713 
    714     switch(sector->special)
    715     {
    716     case 0:
    717         sector->lightlevel = 0;
    718         break;
    719 
    720     case 1:
    721         /* FLICKERING LIGHTS */
    722         P_SpawnLightFlash(sector);
    723         break;
    724 
    725     case 2:
    726         /* STROBE FAST */
    727         P_SpawnStrobeFlash(sector, FASTDARK);
    728         break;
    729 
    730     case 3:
    731         /* STROBE SLOW */
    732         P_SpawnStrobeFlash(sector, SLOWDARK);
    733         break;
    734 
    735     case 8:
    736         /* GLOWING LIGHT */
    737         P_SpawnGlowingLight(sector, PULSENORMAL);
    738         break;
    739 
    740     case 9:
    741         P_SpawnGlowingLight(sector, PULSESLOW);
    742         break;
    743 
    744     case 11:
    745         P_SpawnGlowingLight(sector, PULSERANDOM);
    746         break;
    747 
    748     case 17:
    749         P_SpawnFireFlicker(sector);
    750         break;
    751 
    752     case 202:
    753         P_SpawnStrobeAltFlash(sector, 3);
    754         break;
    755 
    756     case 204:
    757         P_SpawnStrobeFlash(sector, 7);
    758         break;
    759 
    760     case 205:
    761         P_SpawnSequenceLight(sector, true);
    762         break;
    763 
    764     case 206:
    765         P_SpawnStrobeFlash(sector, 90);
    766         break;
    767 
    768     case 208:
    769         P_SpawnStrobeAltFlash(sector, 6);
    770         break;
    771 
    772     case 666:
    773         break;
    774     }
    775 }
    776 
    777 /*
    778 ==============================================================================
    779 =
    780 = P_UseSpecialLine
    781 =
    782 = Called when a thing uses a special line
    783 = Only the front sides of lines are usable
    784 ===============================================================================
    785 */
    786 
    787 boolean P_UseSpecialLine (line_t *line, mobj_t *thing) // 800204BC
    788 {
    789     player_t    *player;
    790     boolean     ok;
    791     int         actionType;
    792 
    793     actionType = SPECIALMASK(line->special);
    794 
    795     if(actionType == 0)
    796         return false;
    797 
    798 
    799     player = thing->player;
    800 
    801 	/* */
    802 	/*	Switches that other things can activate */
    803 	/* */
    804 	if (!player)
    805 	{
    806 	    /* Missiles should NOT trigger specials... */
    807         if(thing->flags & MF_MISSILE)
    808             return false;
    809 
    810         if(!(line->flags & ML_THINGTRIGGER))
    811         {
    812             /* never open secret doors */
    813             if (line->flags & ML_SECRET)
    814                 return false;
    815 
    816             /* never allow a non-player mobj to use lines with these useflags */
    817             if (line->special & (MLU_BLUE|MLU_YELLOW|MLU_RED))
    818                 return false;
    819 
    820             /*
    821                 actionType == 1 // MANUAL DOOR RAISE
    822                 actionType == 2 // OPEN DOOR IMPACT
    823                 actionType == 4 // RAISE DOOR
    824                 actionType == 10 // PLAT DOWN-WAIT-UP-STAY TRIGGER
    825                 actionType == 39 // TELEPORT TRIGGER
    826                 actionType == 125 // TELEPORT MONSTERONLY TRIGGER
    827             */
    828 
    829             if (!((line->special & MLU_USE   && actionType == 1) ||
    830                   (line->special & MLU_CROSS &&(actionType == 4 || actionType == 10 || actionType == 39 || actionType == 125)) ||
    831                   (line->special & MLU_SHOOT && actionType == 2)))
    832                 return false;
    833         }
    834 	}
    835     else
    836     {
    837         if(line->special & MLU_BLUE) /* Blue Card Lock */
    838         {
    839             if(!player->cards[it_bluecard] && !player->cards[it_blueskull])
    840             {
    841                 player->message = "You need a blue key.";
    842                 player->messagetic = MSGTICS;
    843                 S_StartSound(thing, sfx_oof);
    844 
    845                 if (player == &players[0])
    846                     tryopen[MapBlueKeyType] = true;
    847 
    848                 return true;
    849             }
    850         }
    851 
    852         if(line->special & MLU_YELLOW) /* Yellow Card Lock */
    853         {
    854             if(!player->cards[it_yellowcard] && !player->cards[it_yellowskull])
    855             {
    856                 player->message = "You need a yellow key.";
    857                 player->messagetic = MSGTICS;
    858                 S_StartSound(thing, sfx_oof);
    859 
    860                 if (player == &players[0])
    861                     tryopen[MapYellowKeyType] = true;
    862 
    863                 return true;
    864             }
    865         }
    866 
    867         if(line->special & MLU_RED) /* Red Card Lock */
    868         {
    869             if(!player->cards[it_redcard] && !player->cards[it_redskull])
    870             {
    871                 player->message = "You need a red key.";
    872                 player->messagetic = MSGTICS;
    873                 S_StartSound(thing, sfx_oof);   // ?? line missing on Doom64
    874 
    875                 if (player == &players[0])
    876                     tryopen[MapRedKeyType] = true;
    877 
    878                 return true;
    879             }
    880         }
    881 
    882         /*
    883             actionType == 90 // ARTIFACT SWITCH 1
    884             actionType == 91 // ARTIFACT SWITCH 2
    885             actionType == 92 // ARTIFACT SWITCH 3
    886         */
    887 
    888         if ((actionType == 90 || actionType == 91 || actionType == 92) &&
    889            !((player->artifacts & 1) << ((actionType + 6) & 0x1f)))
    890         {
    891             player->message = "You lack the ability to activate it.";
    892             player->messagetic = MSGTICS;
    893             S_StartSound(thing, sfx_oof);
    894 
    895             return false;
    896         }
    897     }
    898 
    899     if(actionType >= 256)
    900         return P_StartMacro(actionType, line, thing);
    901 
    902     ok = false;
    903 
    904 	/* */
    905 	/* do something */
    906 	/*	*/
    907 	switch(SPECIALMASK(line->special))
    908 	{
    909         case 1:			/* Vertical Door */
    910 		case 31:		/* Manual Door Open */
    911 		case 117:		/* Blazing Door Raise */
    912 		case 118:		/* Blazing Door Open */
    913             EV_VerticalDoor(line, thing);
    914             ok = true;
    915 			break;
    916         case 2:			/* Open Door */
    917 			ok = EV_DoDoor(line, DoorOpen);
    918 			break;
    919 		case 3:			/* Close Door */
    920 			ok = EV_DoDoor(line, DoorClose);
    921 			break;
    922 		case 4:			/* Raise Door */
    923 			ok = EV_DoDoor(line, Normal);
    924 			break;
    925 		case 5:			/* Raise Floor */
    926 			ok = EV_DoFloor(line, raiseFloor, FLOORSPEED);
    927 			break;
    928 		case 6:			/* Fast Ceiling Crush & Raise */
    929 			ok = EV_DoCeiling(line, fastCrushAndRaise, CEILSPEED*2);
    930 			break;
    931 		case 8:			/* Build Stairs */
    932 			ok = EV_BuildStairs(line, build8);
    933 			break;
    934 		case 10:		/* PlatDownWaitUp */
    935 			ok = EV_DoPlat(line, downWaitUpStay, 0);
    936 			break;
    937         case 16:		/* Close Door 30 */
    938 			ok = EV_DoDoor(line, Close30ThenOpen);
    939 			break;
    940 		case 17:		/* Start Light Strobing */
    941 			ok = EV_StartLightStrobing(line);
    942 			break;
    943 		case 19:		/* Lower Floor */
    944 			ok = EV_DoFloor(line, lowerFloor, FLOORSPEED);
    945 			break;
    946 		case 22:		/* Raise floor to nearest height and change texture */
    947 			ok = EV_DoPlat(line, raiseToNearestAndChange, 0);
    948 			break;
    949 		case 25:		/* Ceiling Crush and Raise */
    950 			ok = EV_DoCeiling(line, crushAndRaise, CEILSPEED);
    951 			break;
    952 		case 30:		/* Raise floor to shortest texture height on either side of lines */
    953 			ok = EV_DoFloor(line, raiseToTexture, FLOORSPEED);
    954 			break;
    955 		case 36:		/* Lower Floor (TURBO) */
    956 			ok = EV_DoFloor(line, turboLower, FLOORSPEED * 4);
    957 			break;
    958 		case 37:		/* LowerAndChange */
    959 			ok = EV_DoFloor(line, lowerAndChange, FLOORSPEED);
    960 			break;
    961 		case 38:		/* Lower Floor To Lowest */
    962 			ok = EV_DoFloor(line, lowerFloorToLowest, FLOORSPEED);
    963 			break;
    964 		case 39:		/* TELEPORT! */
    965 			EV_Teleport(line, thing);
    966 			ok = false;
    967 			break;
    968         case 43:		/* Lower Ceiling to Floor */
    969 			ok = EV_DoCeiling(line, lowerToFloor, CEILSPEED);
    970 			break;
    971         case 44:		/* Ceiling Crush */
    972 			ok = EV_DoCeiling(line, lowerAndCrush, CEILSPEED);
    973 			break;
    974         case 52:		/* EXIT! */
    975 			P_ExitLevel();//G_ExitLevel
    976 			ok = true;
    977 			break;
    978         case 53:		/* Perpetual Platform Raise */
    979 			ok = EV_DoPlat(line, perpetualRaise, 0);
    980 			break;
    981         case 54:		/* Platform Stop */
    982 			ok = EV_StopPlat(line);
    983 			break;
    984         case 56:		/* Raise Floor Crush */
    985 			ok = EV_DoFloor(line, raiseFloorCrush, FLOORSPEED);
    986 			break;
    987         case 57:		/* Ceiling Crush Stop */
    988 			ok = EV_CeilingCrushStop(line);
    989 			break;
    990         case 58:		/* Raise Floor 24 */
    991 			ok = EV_DoFloor(line, raiseFloor24, FLOORSPEED);
    992 			break;
    993 		case 59:		/* Raise Floor 24 And Change */
    994 			ok = EV_DoFloor(line, raiseFloor24AndChange, FLOORSPEED);
    995 			break;
    996         case 66:		/* Raise Floor 24 and change texture */
    997 			ok = EV_DoPlat(line, raiseAndChange, 24);
    998 			break;
    999         case 67:		/* Raise Floor 32 and change texture */
   1000 			ok = EV_DoPlat(line, raiseAndChange, 32);
   1001 			break;
   1002         case 90:        /* Artifact Switch 1 */
   1003         case 91:        /* Artifact Switch 2 */
   1004         case 92:        /* Artifact Switch 3 */
   1005             ok = P_ActivateLineByTag(line->tag + 1, thing);
   1006             break;
   1007         case 93:        /* Modify mobj flags */
   1008             ok = P_ModifyMobjFlags(line->tag, MF_NOINFIGHTING);
   1009             break;
   1010         case 94:        /* Noise Alert */
   1011             ok = P_AlertTaggedMobj(line->tag, thing);
   1012             break;
   1013         case 100:		/* Build Stairs Turbo 16 */
   1014 			ok = EV_BuildStairs(line, turbo16);
   1015 			break;
   1016         case 108:		/* Blazing Door Raise (faster than TURBO!) */
   1017 			ok = EV_DoDoor(line, BlazeRaise);
   1018 			break;
   1019         case 109:		/* Blazing Door Open (faster than TURBO!) */
   1020 			ok = EV_DoDoor(line, BlazeOpen);
   1021 			break;
   1022         case 110:		/* Blazing Door Close (faster than TURBO!) */
   1023 			ok = EV_DoDoor(line, BlazeClose);
   1024 			break;
   1025         case 119:		/* Raise floor to nearest surr. floor */
   1026 			ok = EV_DoFloor(line, raiseFloorToNearest, FLOORSPEED);
   1027 			break;
   1028         case 121:		/* Blazing PlatDownWaitUpStay */
   1029 			ok = EV_DoPlat(line, blazeDWUS, 0);
   1030 			break;
   1031         case 122:		/* PlatDownWaitUpStay */
   1032 			ok = EV_DoPlat(line, upWaitDownStay, 0);
   1033 			break;
   1034         case 123:		/* Blazing PlatUpWaitDownStay */
   1035 			ok = EV_DoPlat(line, blazeUWDS, 0);
   1036 			break;
   1037         case 124:		/* Secret EXIT */
   1038 			P_SecretExitLevel(line->tag);//(G_SecretExitLevel)
   1039 			ok = true;
   1040 			break;
   1041         case 125:		/* TELEPORT MonsterONLY */
   1042 			if (!thing->player)
   1043 			{
   1044 				EV_Teleport(line, thing);
   1045 				ok = false;
   1046 			}
   1047 			break;
   1048         case 141:		/* Silent Ceiling Crush & Raise (Demon Disposer)*/
   1049 			ok = EV_DoCeiling(line, silentCrushAndRaise, CEILSPEED*2);
   1050 			break;
   1051         case 200:       /* Set Lookat Camera */
   1052             ok = P_SetAimCamera(line, true);
   1053             break;
   1054         case 201:       /* Set Camera */
   1055             ok = P_SetAimCamera(line, false);
   1056             break;
   1057         case 202:       /* Invoke Dart */
   1058             ok = EV_SpawnTrapMissile(line, thing, MT_PROJ_DART);
   1059             break;
   1060         case 203:       /* Delay Thinker */
   1061             P_SpawnDelayTimer(line->tag, NULL);
   1062             ok = true;
   1063             break;
   1064         case 204:       /* Set global integer */
   1065             macrointeger = line->tag;
   1066             ok = true;
   1067             break;
   1068         case 205:       /* Modify sector color */
   1069             P_ModifySectorColor(line, LIGHT_FLOOR, macrointeger);
   1070             ok = true;
   1071             break;
   1072         case 206:       /* Modify sector color */
   1073             ok = P_ModifySectorColor(line, LIGHT_CEILING, macrointeger);
   1074             break;
   1075         case 207:       /* Modify sector color */
   1076             ok = P_ModifySectorColor(line, LIGHT_THING, macrointeger);
   1077             break;
   1078         case 208:       /* Modify sector color */
   1079             ok = P_ModifySectorColor(line, LIGHT_UPRWALL, macrointeger);
   1080             break;
   1081         case 209:       /* Modify sector color */
   1082             ok = P_ModifySectorColor(line, LIGHT_LWRWALL, macrointeger);
   1083             break;
   1084         case 210:       /* Modify sector ceiling height */
   1085             ok = EV_DoCeiling(line, customCeiling, CEILSPEED);
   1086             break;
   1087         case 212:       /* Modify sector floor height */
   1088             ok = EV_DoFloor(line, customFloor, FLOORSPEED);
   1089             break;
   1090         case 214:       /* Elevator Sector */
   1091             ok = EV_SplitSector(line, true);
   1092             break;
   1093         case 218:       /* Modify Line Flags */
   1094             ok = P_ModifyLineFlags(line, macrointeger);
   1095             break;
   1096         case 219:       /* Modify Line Texture */
   1097             ok = P_ModifyLineTexture(line, macrointeger);
   1098             break;
   1099         case 220:       /* Modify Sector Flags */
   1100             ok = P_ModifySector(line, macrointeger, mods_flags);
   1101             break;
   1102         case 221:       /* Modify Sector Specials */
   1103             ok = P_ModifySector(line, macrointeger, mods_special);
   1104             break;
   1105         case 222:       /* Modify Sector Lights */
   1106             ok = P_ModifySector(line, macrointeger, mods_lights);
   1107             break;
   1108         case 223:       /* Modify Sector Flats */
   1109             ok = P_ModifySector(line, macrointeger, mods_flats);
   1110             break;
   1111         case 224:       /* Spawn Thing */
   1112             ok = EV_SpawnMobjTemplate(line->tag);
   1113             break;
   1114         case 225:       /* Quake Effect */
   1115             P_SpawnQuake(line->tag);
   1116             ok = true;
   1117             break;
   1118         case 226:       /* Modify sector ceiling height */
   1119             ok = EV_DoCeiling(line, customCeiling, CEILSPEED * 4);
   1120             break;
   1121         case 227:       /* Modify sector ceiling height */
   1122             ok = EV_DoCeiling(line, customCeiling, 4096 * FRACUNIT);
   1123             break;
   1124         case 228:       /* Modify sector floor height */
   1125             ok = EV_DoFloor(line, customFloor, FLOORSPEED * 4);
   1126             break;
   1127         case 229:       /* Modify sector floor height */
   1128             ok = EV_DoFloor(line, customFloor, 4096 * FRACUNIT);
   1129             break;
   1130         case 230:       /* Modify Line Special */
   1131             ok = P_ModifyLineData(line, macrointeger);
   1132             break;
   1133         case 231:       /* Invoke Revenant Missile */
   1134             ok = EV_SpawnTrapMissile(line, thing, MT_PROJ_TRACER);
   1135             break;
   1136         case 232:       /* Fast Ceiling Crush & Raise */
   1137             ok = EV_DoCeiling(line, crushAndRaiseOnce, CEILSPEED * 4);
   1138             break;
   1139         case 233:       /* Freeze Player */
   1140             thing->reactiontime = line->tag;
   1141             ok = true;
   1142             break;
   1143         case 234:      /* Change light by light tag */
   1144             ok = P_ChangeLightByTag(macrointeger, line->tag);
   1145             break;
   1146         case 235:       /* Modify Light Data */
   1147             ok = P_DoSectorLightChange(macrointeger, line->tag);
   1148             break;
   1149         case 236:       /* Modify platform */
   1150             ok = EV_DoPlat(line, customDownUp, 0);
   1151             break;
   1152         case 237:       /* Modify platform */
   1153             ok = EV_DoPlat(line, customDownUpFast,0);
   1154             break;
   1155         case 238:       /* Modify platform */
   1156             ok = EV_DoPlat(line,customUpDown,0);
   1157             break;
   1158         case 239:       /* Modify platform */
   1159             ok = EV_DoPlat(line,customUpDownFast,0);
   1160             break;
   1161         case 240:       /* Execute random line trigger */
   1162             ok = P_RandomLineTrigger(line, thing);
   1163             break;
   1164         case 241:       /* Split Open Sector */
   1165             ok = EV_SplitSector(line, false);
   1166             break;
   1167         case 242:       /* Fade Out Thing */
   1168             ok = EV_FadeOutMobj(line->tag);
   1169             break;
   1170         case 243:       /* Move and Aim Camera */
   1171             P_SetMovingCamera(line);
   1172             ok = false;
   1173             break;
   1174         case 244:       /* Modify Sector Floor */
   1175             ok = EV_DoFloor(line, customFloorToHeight, 4096 * FRACUNIT);
   1176             break;
   1177         case 245:       /* Modify Sector Ceiling */
   1178             ok = EV_DoCeiling(line, customCeilingToHeight, 4096 * FRACUNIT);
   1179             break;
   1180         case 246:       /* Restart Macro at ID */
   1181             P_RestartMacro(line, macrointeger);
   1182             ok = false;
   1183             break;
   1184         case 247:       /* Modify Sector Floor */
   1185             ok = EV_DoFloor(line, customFloorToHeight, FLOORSPEED);
   1186             break;
   1187         case 248:       /* Suspend a macro script */
   1188             ok = P_SuspendMacro();
   1189             break;
   1190         case 249:       /* Silent Teleport */
   1191             ok = EV_SilentTeleport(line, thing);
   1192             break;
   1193         case 250:       /* Toggle macros on */
   1194             P_ToggleMacros(line->tag, true);
   1195             ok = true;
   1196             break;
   1197         case 251:       /* Toggle macros off */
   1198             P_ToggleMacros(line->tag, false);
   1199             ok = true;
   1200             break;
   1201         case 252:       /* Modify Sector Ceiling */
   1202             ok = EV_DoCeiling(line, customCeilingToHeight, CEILSPEED);
   1203             break;
   1204         case 253:       /* Unlock Cheat Menu */
   1205             if(!demoplayback) {
   1206                 FeaturesUnlocked = true;
   1207             }
   1208             ok = true;
   1209             break;
   1210         case 254:       /* D64 Map33 Logo */
   1211             Skyfadeback = true;
   1212             break;
   1213 
   1214         default:
   1215             return false;
   1216 	}
   1217 
   1218 	if (ok)
   1219     {
   1220         if (line == &macrotempline)
   1221             return true;
   1222 
   1223         P_ChangeSwitchTexture(line, line->special & MLU_REPEAT);
   1224 
   1225         if (line->special & MLU_REPEAT)
   1226             return true;
   1227 
   1228         line->special = 0;
   1229     }
   1230 
   1231     return true;
   1232 }
   1233 
   1234 #if 0
   1235 
   1236 /*============================================================ */
   1237 /* */
   1238 /*	Special Stuff that can't be categorized */
   1239 /* */
   1240 /*============================================================ */
   1241 int EV_DoDonut(line_t *line)//L8002796C()
   1242 {
   1243 	sector_t	*s1;
   1244 	sector_t	*s2;
   1245 	sector_t	*s3;
   1246 	int			secnum;
   1247 	int			rtn;
   1248 	int			i;
   1249 	floormove_t		*floor;
   1250 
   1251 	secnum = -1;
   1252 	rtn = 0;
   1253 	while ((secnum = P_FindSectorFromLineTag(line->tag,secnum)) >= 0)
   1254 	{
   1255 		s1 = &sectors[secnum];
   1256 
   1257 		/*	ALREADY MOVING?  IF SO, KEEP GOING... */
   1258 		if (s1->specialdata)
   1259 			continue;
   1260 
   1261 		rtn = 1;
   1262 		s2 = getNextSector(s1->lines[0],s1);
   1263 		for (i = 0;i < s2->linecount;i++)
   1264 		{
   1265 			if (//(!s2->lines[i]->flags & ML_TWOSIDED) ||
   1266 				(s2->lines[i]->backsector == s1))
   1267 				continue;
   1268 			s3 = s2->lines[i]->backsector;
   1269 
   1270 			/* */
   1271 			/*	Spawn rising slime */
   1272 			/* */
   1273 			floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
   1274 			P_AddThinker (&floor->thinker);
   1275 			s2->specialdata = floor;
   1276 			floor->thinker.function = T_MoveFloor;
   1277 			floor->type = donutRaise;
   1278 			floor->crush = false;
   1279 			floor->direction = 1;
   1280 			floor->sector = s2;
   1281 			floor->speed = FLOORSPEED / 2;
   1282 			floor->texture = s3->floorpic;
   1283 			floor->newspecial = 0;
   1284 			floor->floordestheight = s3->floorheight;
   1285 
   1286 			/* */
   1287 			/*	Spawn lowering donut-hole */
   1288 			/* */
   1289 			floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
   1290 			P_AddThinker (&floor->thinker);
   1291 			s1->specialdata = floor;
   1292 			floor->thinker.function = T_MoveFloor;
   1293 			floor->type = lowerFloor;
   1294 			floor->crush = false;
   1295 			floor->direction = -1;
   1296 			floor->sector = s1;
   1297 			floor->speed = FLOORSPEED / 2;
   1298 			floor->floordestheight = s3->floorheight;
   1299 			break;
   1300 		}
   1301 	}
   1302 	return rtn;
   1303 }
   1304 
   1305 #endif // 0