?? p_spec.c
字號:
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Implements special effects:
// Texture animation, height or lighting changes
// according to adjacent sectors, respective
// utility functions, etc.
// Line Tag handling. Line and Sector triggers.
//
//-----------------------------------------------------------------------------
static const char
rcsid[] = "$Id: p_spec.c,v 1.6 1997/02/03 22:45:12 b1 Exp $";
#include <stdlib.h>
#include "doomdef.h"
#include "doomstat.h"
#include "i_system.h"
#include "z_zone.h"
#include "m_argv.h"
#include "m_random.h"
#include "w_wad.h"
#include "r_local.h"
#include "p_local.h"
#include "g_game.h"
#include "s_sound.h"
// State.
#include "r_state.h"
// Data.
#include "sounds.h"
//
// Animating textures and planes
// There is another anim_t used in wi_stuff, unrelated.
//
typedef struct
{
boolean istexture;
int picnum;
int basepic;
int numpics;
int speed;
} anim_t;
//
// source animation definition
//
typedef struct
{
boolean istexture; // if false, it is a flat
char endname[9];
char startname[9];
int speed;
} animdef_t;
#define MAXANIMS 32
extern anim_t anims[MAXANIMS];
extern anim_t* lastanim;
//
// P_InitPicAnims
//
// Floor/ceiling animation sequences,
// defined by first and last frame,
// i.e. the flat (64x64 tile) name to
// be used.
// The full animation sequence is given
// using all the flats between the start
// and end entry, in the order found in
// the WAD file.
//
animdef_t animdefs[] =
{
{false, "NUKAGE3", "NUKAGE1", 8},
{false, "FWATER4", "FWATER1", 8},
{false, "SWATER4", "SWATER1", 8},
{false, "LAVA4", "LAVA1", 8},
{false, "BLOOD3", "BLOOD1", 8},
// DOOM II flat animations.
{false, "RROCK08", "RROCK05", 8},
{false, "SLIME04", "SLIME01", 8},
{false, "SLIME08", "SLIME05", 8},
{false, "SLIME12", "SLIME09", 8},
{true, "BLODGR4", "BLODGR1", 8},
{true, "SLADRIP3", "SLADRIP1", 8},
{true, "BLODRIP4", "BLODRIP1", 8},
{true, "FIREWALL", "FIREWALA", 8},
{true, "GSTFONT3", "GSTFONT1", 8},
{true, "FIRELAVA", "FIRELAV3", 8},
{true, "FIREMAG3", "FIREMAG1", 8},
{true, "FIREBLU2", "FIREBLU1", 8},
{true, "ROCKRED3", "ROCKRED1", 8},
{true, "BFALL4", "BFALL1", 8},
{true, "SFALL4", "SFALL1", 8},
{true, "WFALL4", "WFALL1", 8},
{true, "DBRAIN4", "DBRAIN1", 8},
{-1}
};
anim_t anims[MAXANIMS];
anim_t* lastanim;
//
// Animating line specials
//
#define MAXLINEANIMS 64
extern short numlinespecials;
extern line_t* linespeciallist[MAXLINEANIMS];
void P_InitPicAnims (void)
{
int i;
// Init animation
lastanim = anims;
for (i=0 ; animdefs[i].istexture != -1 ; i++)
{
if (animdefs[i].istexture)
{
// different episode ?
if (R_CheckTextureNumForName(animdefs[i].startname) == -1)
continue;
lastanim->picnum = R_TextureNumForName (animdefs[i].endname);
lastanim->basepic = R_TextureNumForName (animdefs[i].startname);
}
else
{
if (W_CheckNumForName(animdefs[i].startname) == -1)
continue;
lastanim->picnum = R_FlatNumForName (animdefs[i].endname);
lastanim->basepic = R_FlatNumForName (animdefs[i].startname);
}
lastanim->istexture = animdefs[i].istexture;
lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
if (lastanim->numpics < 2)
I_Error ("P_InitPicAnims: bad cycle from %s to %s",
animdefs[i].startname,
animdefs[i].endname);
lastanim->speed = animdefs[i].speed;
lastanim++;
}
}
//
// UTILITIES
//
//
// getSide()
// Will return a side_t*
// given the number of the current sector,
// the line number, and the side (0/1) that you want.
//
side_t*
getSide
( int currentSector,
int line,
int side )
{
return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
}
//
// getSector()
// Will return a sector_t*
// given the number of the current sector,
// the line number and the side (0/1) that you want.
//
sector_t*
getSector
( int currentSector,
int line,
int side )
{
return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
}
//
// twoSided()
// Given the sector number and the line number,
// it will tell you whether the line is two-sided or not.
//
int
twoSided
( int sector,
int line )
{
return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
}
//
// getNextSector()
// Return sector_t * of sector next to current.
// NULL if not two-sided line
//
sector_t*
getNextSector
( line_t* line,
sector_t* sec )
{
if (!(line->flags & ML_TWOSIDED))
return NULL;
if (line->frontsector == sec)
return line->backsector;
return line->frontsector;
}
//
// P_FindLowestFloorSurrounding()
// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
//
fixed_t P_FindLowestFloorSurrounding(sector_t* sec)
{
int i;
line_t* check;
sector_t* other;
fixed_t floor = sec->floorheight;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->floorheight < floor)
floor = other->floorheight;
}
return floor;
}
//
// P_FindHighestFloorSurrounding()
// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
//
fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
{
int i;
line_t* check;
sector_t* other;
fixed_t floor = -500*FRACUNIT;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->floorheight > floor)
floor = other->floorheight;
}
return floor;
}
//
// P_FindNextHighestFloor
// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
// Note: this should be doable w/o a fixed array.
// 20 adjoining sectors max!
#define MAX_ADJOINING_SECTORS 20
fixed_t
P_FindNextHighestFloor
( sector_t* sec,
int currentheight )
{
int i;
int h;
int min;
line_t* check;
sector_t* other;
fixed_t height = currentheight;
fixed_t heightlist[MAX_ADJOINING_SECTORS];
for (i=0, h=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->floorheight > height)
heightlist[h++] = other->floorheight;
// Check for overflow. Exit.
if ( h >= MAX_ADJOINING_SECTORS )
{
fprintf( stderr,
"Sector with more than 20 adjoining sectors\n" );
break;
}
}
// Find lowest height in list
if (!h)
return currentheight;
min = heightlist[0];
// Range checking?
for (i = 1;i < h;i++)
if (heightlist[i] < min)
min = heightlist[i];
return min;
}
//
// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
//
fixed_t
P_FindLowestCeilingSurrounding(sector_t* sec)
{
int i;
line_t* check;
sector_t* other;
fixed_t height = MAXINT;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->ceilingheight < height)
height = other->ceilingheight;
}
return height;
}
//
// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
//
fixed_t P_FindHighestCeilingSurrounding(sector_t* sec)
{
int i;
line_t* check;
sector_t* other;
fixed_t height = 0;
for (i=0 ;i < sec->linecount ; i++)
{
check = sec->lines[i];
other = getNextSector(check,sec);
if (!other)
continue;
if (other->ceilingheight > height)
height = other->ceilingheight;
}
return height;
}
//
// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
//
int
P_FindSectorFromLineTag
( line_t* line,
int start )
{
int i;
for (i=start+1;i<numsectors;i++)
if (sectors[i].tag == line->tag)
return i;
return -1;
}
//
// Find minimum light from an adjacent sector
//
int
P_FindMinSurroundingLight
( sector_t* sector,
int max )
{
int i;
int min;
line_t* line;
sector_t* check;
min = max;
for (i=0 ; i < sector->linecount ; i++)
{
line = sector->lines[i];
check = getNextSector(line,sector);
if (!check)
continue;
if (check->lightlevel < min)
min = check->lightlevel;
}
return min;
}
//
// EVENTS
// Events are operations triggered by using, crossing,
// or shooting special lines, or by timed thinkers.
//
//
// P_CrossSpecialLine - TRIGGER
// Called every time a thing origin is about
// to cross a line with a non 0 special.
//
void
P_CrossSpecialLine
( int linenum,
int side,
mobj_t* thing )
{
line_t* line;
int ok;
line = &lines[linenum];
// Triggers that other things can activate
if (!thing->player)
{
// Things that should NOT trigger specials...
switch(thing->type)
{
case MT_ROCKET:
case MT_PLASMA:
case MT_BFG:
case MT_TROOPSHOT:
case MT_HEADSHOT:
case MT_BRUISERSHOT:
return;
break;
default: break;
}
ok = 0;
switch(line->special)
{
case 39: // TELEPORT TRIGGER
case 97: // TELEPORT RETRIGGER
case 125: // TELEPORT MONSTERONLY TRIGGER
case 126: // TELEPORT MONSTERONLY RETRIGGER
case 4: // RAISE DOOR
case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER
case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER
ok = 1;
break;
}
if (!ok)
return;
}
// Note: could use some const's here.
switch (line->special)
{
// TRIGGERS.
// All from here to RETRIGGERS.
case 2:
// Open Door
EV_DoDoor(line,open);
line->special = 0;
break;
case 3:
// Close Door
EV_DoDoor(line,close);
line->special = 0;
break;
case 4:
// Raise Door
EV_DoDoor(line,normal);
line->special = 0;
break;
case 5:
// Raise Floor
EV_DoFloor(line,raiseFloor);
line->special = 0;
break;
case 6:
// Fast Ceiling Crush & Raise
EV_DoCeiling(line,fastCrushAndRaise);
line->special = 0;
break;
case 8:
// Build Stairs
EV_BuildStairs(line,build8);
line->special = 0;
break;
case 10:
// PlatDownWaitUp
EV_DoPlat(line,downWaitUpStay,0);
line->special = 0;
break;
case 12:
// Light Turn On - brightest near
EV_LightTurnOn(line,0);
line->special = 0;
break;
case 13:
// Light Turn On 255
EV_LightTurnOn(line,255);
line->special = 0;
break;
case 16:
// Close Door 30
EV_DoDoor(line,close30ThenOpen);
line->special = 0;
break;
case 17:
// Start Light Strobing
EV_StartLightStrobing(line);
line->special = 0;
break;
case 19:
// Lower Floor
EV_DoFloor(line,lowerFloor);
line->special = 0;
break;
case 22:
// Raise floor to nearest height and change texture
EV_DoPlat(line,raiseToNearestAndChange,0);
line->special = 0;
break;
case 25:
// Ceiling Crush and Raise
EV_DoCeiling(line,crushAndRaise);
line->special = 0;
break;
case 30:
// Raise floor to shortest texture height
// on either side of lines.
EV_DoFloor(line,raiseToTexture);
line->special = 0;
break;
case 35:
// Lights Very Dark
EV_LightTurnOn(line,35);
line->special = 0;
break;
case 36:
// Lower Floor (TURBO)
EV_DoFloor(line,turboLower);
line->special = 0;
break;
case 37:
// LowerAndChange
EV_DoFloor(line,lowerAndChange);
line->special = 0;
break;
case 38:
// Lower Floor To Lowest
EV_DoFloor( line, lowerFloorToLowest );
line->special = 0;
break;
case 39:
// TELEPORT!
EV_Teleport( line, side, thing );
line->special = 0;
break;
case 40:
// RaiseCeilingLowerFloor
EV_DoCeiling( line, raiseToHighest );
EV_DoFloor( line, lowerFloorToLowest );
line->special = 0;
break;
case 44:
// Ceiling Crush
EV_DoCeiling( line, lowerAndCrush );
line->special = 0;
break;
case 52:
// EXIT!
G_ExitLevel ();
break;
case 53:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -