Exemplo n.º 1
0
void
EV_SlidingDoor
( line_t*		line,
  mobj_t*		thing )
{
	sector_t*			sec;
	slidedoor_t*		door;

	// DOOM II ONLY...
	if (gamemode != commercial)
		return;

	// Make sure door isn't already being animated
	sec = line->frontsector;
	door = NULL;
	if (sec->specialdata)
	{
		if (!thing->player)
			return;

		door = sec->specialdata;
		if (door->type == sdt_openAndClose)
		{
			if (door->status == sd_waiting)
				door->status = sd_closing;
		}
		else
			return;
	}

	// Init sliding door vars
	if (!door)
	{
		door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
		P_AddThinker (&door->thinker);
		sec->specialdata = door;

		door->type = sdt_openAndClose;
		door->status = sd_opening;
		door->whichDoorIndex = P_FindSlidingDoorType(line);

		if (door->whichDoorIndex < 0)
			I_Error("EV_SlidingDoor: Can't use texture for sliding door!");

		door->frontsector = sec;
		door->backsector = line->backsector;
		door->thinker.function = T_SlidingDoor;
		door->timer = SWAITTICS;
		door->frame = 0;
		door->line = line;
	}
}
Exemplo n.º 2
0
void P_SpawnGlowingLight(sector_t * sector)
{
    glow_t *g;

    g = Z_Malloc(sizeof(*g), PU_LEVSPEC, 0);
    P_AddThinker(&g->thinker);
    g->sector = sector;
    g->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
    g->maxlight = sector->lightlevel;
    g->thinker.function = T_Glow;
    g->direction = -1;

    sector->special = 0;
}
Exemplo n.º 3
0
boolean P_StartACS(int number, int map, byte * args, mobj_t * activator,
                   line_t * line, int side)
{
    int i;
    acs_t *script;
    int infoIndex;
    aste_t *statePtr;

    NewScript = NULL;
    if (map && map != gamemap)
    {                           // Add to the script store
        return AddToACSStore(map, number, args);
    }
    infoIndex = GetACSIndex(number);
    if (infoIndex == -1)
    {                           // Script not found
        //I_Error("P_StartACS: Unknown script number %d", number);
        snprintf(ErrorMsg, sizeof(ErrorMsg),
                 "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number);
        P_SetMessage(&players[consoleplayer], ErrorMsg, true);
    }
    statePtr = &ACSInfo[infoIndex].state;
    if (*statePtr == ASTE_SUSPENDED)
    {                           // Resume a suspended script
        *statePtr = ASTE_RUNNING;
        return true;
    }
    if (*statePtr != ASTE_INACTIVE)
    {                           // Script is already executing
        return false;
    }
    script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
    memset(script, 0, sizeof(acs_t));
    script->number = number;
    script->infoIndex = infoIndex;
    script->activator = activator;
    script->line = line;
    script->side = side;
    script->ip = ACSInfo[infoIndex].address;
    script->thinker.function = T_InterpretACS;
    for (i = 0; i < ACSInfo[infoIndex].argCount; i++)
    {
        script->vars[i] = args[i];
    }
    *statePtr = ASTE_RUNNING;
    P_AddThinker(&script->thinker);
    NewScript = script;
    return true;
}
Exemplo n.º 4
0
void P_UnArchiveThinkers(void)
{
    byte tclass;
    thinker_t *currentthinker, *next;
    mobj_t *mobj;

    //
    // remove all the current thinkers
    //
    currentthinker = thinkercap.next;
    while (currentthinker != &thinkercap)
    {
        next = currentthinker->next;
        if (currentthinker->function == P_MobjThinker)
            P_RemoveMobj((mobj_t *) currentthinker);
        else
            Z_Free(currentthinker);
        currentthinker = next;
    }
    P_InitThinkers();

    // read in saved thinkers
    while (1)
    {
        tclass = SV_ReadByte();
        switch (tclass)
        {
            case tc_end:
                return;         // end of list

            case tc_mobj:
                mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
                saveg_read_mobj_t(mobj);
                mobj->target = NULL;
                P_SetThingPosition(mobj);
                mobj->info = &mobjinfo[mobj->type];
                mobj->floorz = mobj->subsector->sector->floorheight;
                mobj->ceilingz = mobj->subsector->sector->ceilingheight;
                mobj->thinker.function = P_MobjThinker;
                P_AddThinker(&mobj->thinker);
                break;

            default:
                I_Error("Unknown tclass %i in savegame", tclass);
        }

    }

}
Exemplo n.º 5
0
static vldoor_t* get_door_block (sector_t* sec)
{
  vldoor_t*	door;

  door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
  P_AddThinker (&door->thinker, (actionf_p1) T_VerticalDoor);
  sec->ceilingdata = door;

  door->sector = sec;
  door->topwait = VDOORWAIT;
  door->speed = VDOORSPEED;
  door->direction = 1;
  door->line = NULL;
  return (door);
}
Exemplo n.º 6
0
//==================================================================
//
//      Spawn a door that closes after 30 seconds
//
//==================================================================
void P_SpawnDoorCloseIn30(sector_t * sec)
{
    vldoor_t *door;

    door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
    P_AddThinker(&door->thinker);
    sec->specialdata = door;
    sec->special = 0;
    door->thinker.function = T_VerticalDoor;
    door->sector = sec;
    door->direction = 0;
    door->type = normal;
    door->speed = VDOORSPEED;
    door->topcountdown = 30 * 35;
}
Exemplo n.º 7
0
void P_SpawnStrobeAltFlash(sector_t* sector, int speed) {      // 0x80015C44
    strobe_t* flash;

    flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);

    P_AddThinker(&flash->thinker);

    flash->sector = sector;
    flash->darktime = speed;
    flash->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
    flash->special = sector->special;
    flash->maxlight = 127;
    flash->brighttime = 1;
    flash->count = 1;
}
Exemplo n.º 8
0
void P_SpawnStrobeFlash(sector_t* sector, int speed) {
    strobe_t* flash;

    flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);

    P_AddThinker(&flash->thinker);

    flash->sector = sector;
    flash->darktime = speed;
    flash->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
    flash->special = sector->special;
    flash->maxlight = 16;
    flash->brighttime = 3;
    flash->count = (P_Random(pr_lights) & 7) + 1;
}
Exemplo n.º 9
0
void P_CombineLightSpecials(sector_t *sector) {
    actionf_p1 func;
    thinker_t *thinker;
    combine_t *combine;

    switch(sector->special) {
    case 1:
        func = T_LightFlash;
        break;
    case 2:
    case 3:
    case 202:
    case 203:
    case 204:
    case 205:
    case 206:
    case 208:
        func = T_StrobeFlash;
        break;
    case 8:
    case 9:
    case 11:
        func = T_Glow;
        break;
    case 17:
        func = T_FireFlicker;
        break;
    default:
        return;
    }

    for(thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) {
        if((actionf_p1)func != (actionf_p1)thinker->function.acp1) {
            continue;
        }

        combine = Z_Malloc(sizeof(*combine), PU_LEVSPEC, 0);

        P_AddThinker(&combine->thinker);

        combine->sector = sector;
        combine->special = sector->special;
        combine->combiner = thinker;
        combine->func = func;
        combine->thinker.function.acp1 = (actionf_p1)T_Combine;
        return;
    }
}
Exemplo n.º 10
0
//
// P_SpawnGlowingLight()
//
// Spawns a glowing light (smooth oscillation from min to max) thinker
//
// Passed the sector that spawned the thinker
// Returns nothing
//
void P_SpawnGlowingLight(sector_t*  sector)
{
  glow_t* g;

  g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0);

  P_AddThinker(&g->thinker);

  g->sector = sector;
  g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
  g->maxlight = sector->lightlevel;
  g->thinker.function.acp1 = (actionf_p1) T_Glow;
  g->direction = -1;

  sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type
}
Exemplo n.º 11
0
static void StartOpenACS(int number, int infoIndex, int *address)
{
    acs_t *script;

    script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
    memset(script, 0, sizeof(acs_t));
    script->number = number;

    // World objects are allotted 1 second for initialization
    script->delayCount = 35;

    script->infoIndex = infoIndex;
    script->ip = address;
    script->thinker.function = T_InterpretACS;
    P_AddThinker(&script->thinker);
}
Exemplo n.º 12
0
//==================================================================
//
//      P_SpawnLightFlash
//
//      After the map has been loaded, scan each sector for specials that spawn thinkers
//
//==================================================================
void P_SpawnLightFlash(sector_t * sector)
{
    lightflash_t *flash;

    sector->special = 0;        // nothing special about it during gameplay

    flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);
    P_AddThinker(&flash->thinker);
    flash->thinker.function = T_LightFlash;
    flash->sector = sector;
    flash->maxlight = sector->lightlevel;

    flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
    flash->maxtime = 64;
    flash->mintime = 7;
    flash->count = (P_Random() & flash->maxtime) + 1;
}
Exemplo n.º 13
0
//
// P_SpawnFireFlicker
//
void P_SpawnFireFlicker(sector_t *sector)
{
    fireflicker_t       *flick = Z_Malloc(sizeof(*flick), PU_LEVSPEC, 0);

    // Note that we are resetting sector attributes.
    // Nothing special about it during gameplay.
    sector->special = 0;

    memset(flick, 0, sizeof(*flick));
    P_AddThinker(&flick->thinker);

    flick->thinker.function = T_FireFlicker;
    flick->sector = sector;
    flick->maxlight = sector->lightlevel;
    flick->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel) + 16;
    flick->count = 4;
}
Exemplo n.º 14
0
//
// P_SpawnFireFlicker
//
// [STRIFE] 
// haleyjd 2011023: Changes to minimum light level and initial duration
//
void P_SpawnFireFlicker (sector_t*      sector)
{
    fireflicker_t*      flick;

    // Note that we are resetting sector attributes.
    // Nothing special about it during gameplay.
    sector->special = 0; 

    flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0);

    P_AddThinker (&flick->thinker);

    flick->thinker.function.acp1 = (actionf_p1) T_FireFlicker;
    flick->sector = sector;
    flick->maxlight = sector->lightlevel;
    flick->minlight = sector->lightlevel - 32; // [STRIFE] changed from min surrounding+16
    flick->count = 2;                          // [STRIFE]: Initial count 4 -> 2
}
Exemplo n.º 15
0
//==================================================================
//
//      Spawn a door that opens after 5 minutes
//
//==================================================================
void P_SpawnDoorRaiseIn5Mins(sector_t * sec, int secnum)
{
    vldoor_t *door;

    door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
    P_AddThinker(&door->thinker);
    sec->specialdata = door;
    sec->special = 0;
    door->thinker.function = T_VerticalDoor;
    door->sector = sec;
    door->direction = 2;
    door->type = raiseIn5Mins;
    door->speed = VDOORSPEED;
    door->topheight = P_FindLowestCeilingSurrounding(sec);
    door->topheight -= 4 * FRACUNIT;
    door->topwait = VDOORWAIT;
    door->topcountdown = 5 * 60 * 35;
}
Exemplo n.º 16
0
//
// P_SpawnFireFlicker()
//
// Spawns a fire flicker lighting thinker
//
// Passed the sector that spawned the thinker
// Returns nothing
//
void P_SpawnFireFlicker (sector_t*  sector)
{
  fireflicker_t*  flick;

  // Note that we are resetting sector attributes.
  // Nothing special about it during gameplay.
  sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type

  flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0);

  P_AddThinker (&flick->thinker);

  flick->thinker.function.acp1 = (actionf_p1) T_FireFlicker;
  flick->sector = sector;
  flick->maxlight = sector->lightlevel;
  flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16;
  flick->count = 4;
}
Exemplo n.º 17
0
void P_SpawnFireFlicker(sector_t *sector)
{

    fireflicker_t *flick;
    sector->special &= ~31;

    flick = Z_Malloc(sizeof(*flick), PU_LEVSPEC, 0);

    memset(flick, 0, sizeof(*flick));
    P_AddThinker (&flick->thinker);

    flick->thinker.function = T_FireFlicker;
    flick->sector = sector;
    flick->maxlight = sector->lightlevel;
    flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel) + 16;
    flick->count = 4;

}
Exemplo n.º 18
0
//
// Spawn a door that closes after 30 seconds
//
void P_SpawnDoorCloseIn30(sector_t *sec)
{
    vldoor_t	*door;

    door = Z_Malloc(sizeof(*door), PU_LEVSPEC, (void *)0);

    P_AddThinker(&door->thinker);

    sec->ceilingdata = door;
    sec->special = 0;

    door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
    door->sector = sec;
    door->direction = 0;
    door->type = normal;
    door->speed = VDOORSPEED;
    door->topcountdown = 30 * 35;
    door->line = (line_t *)0;	// no line triggered us
}
Exemplo n.º 19
0
void P_SpawnLightFlash(sector_t *sector)
{

    lightflash_t *flash;
    sector->special &= ~31;

    flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);

    memset(flash, 0, sizeof(*flash));
    P_AddThinker(&flash->thinker);

    flash->thinker.function = T_LightFlash;
    flash->sector = sector;
    flash->maxlight = sector->lightlevel;
    flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
    flash->maxtime = 64;
    flash->mintime = 7;
    flash->count = (P_Random(pr_lights)&flash->maxtime) + 1;

}
Exemplo n.º 20
0
//
// P_SpawnLightFlash()
//
// Spawns a broken light flash lighting thinker
//
// Passed the sector that spawned the thinker
// Returns nothing
//
void P_SpawnLightFlash (sector_t* sector)
{
  lightflash_t* flash;

  // nothing special about it during gameplay
  sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type

  flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);

  P_AddThinker (&flash->thinker);

  flash->thinker.function.acp1 = (actionf_p1) T_LightFlash;
  flash->sector = sector;
  flash->maxlight = sector->lightlevel;

  flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel);
  flash->maxtime = 64;
  flash->mintime = 7;
  flash->count = (P_Random(pr_lights)&flash->maxtime)+1;
}
Exemplo n.º 21
0
void P_UpdateLightThinker(light_t* destlight, light_t* srclight) {
    lightmorph_t* lt;

    lt = Z_Malloc(sizeof(*lt), PU_LEVSPEC, 0);
    P_AddThinker(&lt->thinker);
    lt->thinker.function.acp1 = (actionf_p1)T_LightMorph;

    if(destlight) {
        destlight->r = srclight->r;
        destlight->g = srclight->g;
        destlight->b = srclight->b;
    }

    lt->inc = 0;
    lt->src = srclight; // the light to morph to
    lt->dest = destlight == NULL ? srclight : destlight; // the light to morph from
    lt->r = destlight == NULL ? 0 : destlight->base_r;
    lt->g = destlight == NULL ? 0 : destlight->base_g;
    lt->b = destlight == NULL ? 0 : destlight->base_b;
}
Exemplo n.º 22
0
//
// P_SpawnDoorCloseIn30()
//
// Spawn a door that closes after 30 seconds (called at level init)
//
// Passed the sector of the door, whose type specified the door action
// Returns nothing
//
void P_SpawnDoorCloseIn30(sector_t *sec) {
  vldoor_t *door;

  door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);

  memset(door, 0, sizeof(*door));
  P_AddThinker(&door->thinker);

  sec->ceilingdata = door; //jff 2/22/98
  sec->special = 0;

  door->thinker.function = T_VerticalDoor;
  door->sector = sec;
  door->direction = 0;
  door->type = normal;
  door->speed = VDOORSPEED;
  door->topcountdown = 30 * 35;
  door->line = NULL; // jff 1/31/98 remember line that triggered us
  door->lighttag = 0; /* killough 10/98: no lighting changes */
}
Exemplo n.º 23
0
void P_SpawnPhasedLight(sector_t * sector, int base, int index)
{
    phase_t *phase;

    phase = Z_Malloc(sizeof(*phase), PU_LEVSPEC, 0);
    P_AddThinker(&phase->thinker);
    phase->sector = sector;
    if (index == -1)
    {                           // sector->lightlevel as the index
        phase->index = sector->lightlevel & 63;
    }
    else
    {
        phase->index = index & 63;
    }
    phase->base = base & 255;
    sector->lightlevel = phase->base + PhaseTable[phase->index];
    phase->thinker.function = T_Phase;

    sector->special = 0;
}
Exemplo n.º 24
0
void EV_ForceField (line_t *line, int flag)
{
    register int	i;
    forcefield_t	*field;

    // find all 2s lines with same tag but force field special
    for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;)
    {
	// force field must be 2s line
	if (!lines[i].flags & ML_TWOSIDED)
	    continue;

	// make sure force field isn't open already
	if (sides[lines[i].sidenum[0]].midtexture == 0)
	    continue;

	// force field special?
	if (lines[i].special == 320)
	{
	    field = Z_Malloc(sizeof(*field), PU_LEVSPEC, (void *)0);
	    field->frontsector = lines[i].frontsector;
	    field->backsector = lines[i].backsector;
	    field->line = &lines[i];
	    field->oldflags = lines[i].flags;
	    // used a switch?
	    if (!flag)
	    {
		field->status = ff_open;
		field->timer = FFWAITTICS;
	    }
	    // no, damaged with gun shot or deactivated with comm gadget
	    else
	    {
		field->status = ff_damaged;
	    }
	    P_AddThinker(&field->thinker);
	    field->thinker.function.acv = T_ForceField;
	}
    }
}
Exemplo n.º 25
0
void P_SpawnGlowingLight(sector_t*    sector, byte type) {
    glow_t*    g;

    g = Z_Malloc(sizeof(*g), PU_LEVSPEC, 0);

    P_AddThinker(&g->thinker);
    g->count = 2;
    g->direction = 1;
    g->sector = sector;
    g->type = type;
    g->special = sector->special;
    g->thinker.function.acp1 = (actionf_p1)T_Glow;
    g->minlight = 0;

    if(g->type == PULSENORMAL) {
        g->maxlight = 32;
    }
    else if(g->type == PULSERANDOM || g->type == PULSESLOW) {
        g->maxlight = 48;
    }

}
Exemplo n.º 26
0
//
// P_SpawnStrobeFlash
// After the map has been loaded, scan each sector
// for specials that spawn thinkers
//
void P_SpawnStrobeFlash(sector_t *sector, int fastOrSlow, int inSync)
{
    strobe_t    *flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);

    memset(flash, 0, sizeof(*flash));
    P_AddThinker(&flash->thinker);

    flash->sector = sector;
    flash->darktime = fastOrSlow;
    flash->brighttime = STROBEBRIGHT;
    flash->thinker.function = T_StrobeFlash;
    flash->maxlight = sector->lightlevel;
    flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);

    if (flash->minlight == flash->maxlight)
        flash->minlight = 0;

    // nothing special about it during gameplay
    sector->special = 0;

    flash->count = (inSync ? 1 : (P_Random() & 7) + 1);
}
Exemplo n.º 27
0
/** Spawns an adjustable glowing light effect in a sector.
  *
  * \param minsector Sector whose light level is used as the darkest.
  * \param maxsector Sector whose light level is used as the brightest,
  *                  and also the target sector for the effect.
  * \param length    The speed of the effect.
  * \sa T_Glow
  */
glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, INT32 length)
{
	glow_t *g;

	P_RemoveLighting(maxsector); // out with the old, in with the new
	g = Z_Calloc(sizeof (*g), PU_LEVSPEC, NULL);

	P_AddThinker(&g->thinker);

	g->sector = maxsector;
	g->minlight = minsector->lightlevel;
	g->maxlight = maxsector->lightlevel;
	if (g->minlight > g->maxlight)
	{
		// You mixed them up, you dummy.
		INT32 oops = g->minlight;
		g->minlight = g->maxlight;
		g->maxlight = oops;
	}
	g->thinker.function.acp1 = (actionf_p1)T_Glow;
	g->direction = 1;
	g->speed = length/4;
	if (g->speed > (g->maxlight - g->minlight)/2) // don't make it ridiculous speed
		g->speed = (g->maxlight - g->minlight)/2;

	while (g->speed < 1)
	{
		if (g->minlight > 0)
			g->minlight--;
		if (g->maxlight < 255)
			g->maxlight++;

		g->speed = (g->maxlight - g->minlight)/2;
	}

	maxsector->lightingdata = g;

	return g;
}
Exemplo n.º 28
0
//
// Switch force fields with id off
//
void EV_PlusForceField(int id, line_t *ln, mobj_t *thing, int flag)
{
	register int	line = -1;
	forcefield_t	*field;

	// find all lines with id
	while ((line = P_FindLineFromTag(id, line)) >= 0)
	{
		// force field must be 2s line
		if (!lines[line].flags & ML_TWOSIDED)
			continue;

		// make sure force field isn't open already
		if (sides[lines[line].sidenum[0]].midtexture == 0)
			continue;

		field = Z_Malloc(sizeof(*field), PU_LEVSPEC, (void *)0);
		field->frontsector = lines[line].frontsector;
		field->backsector = lines[line].backsector;
		field->line = &lines[line];
		field->oldflags = lines[line].flags;

		// used a switch?
		if (!flag)
		{
			field->status = ff_open;
			field->timer = FFWAITTICS;
		}
		// no, damaged with gun shot or deactivated with comm gadget or button
		else
		{
			field->status = ff_damaged;
			P_ChangeSwitchTexture(ln, 0);
		}
		P_AddThinker(&field->thinker);
		field->thinker.function.acv = T_ForceField;
	}
}
Exemplo n.º 29
0
void P_SpawnSequenceLight(sector_t* sector, dboolean first) {
    sequenceGlow_t* seq;
    sector_t *headsector = NULL;
    int i = 0;

    if(!sector->linecount) {
        return;
    }

    if(first) {
        for(i = 0; i < sector->linecount; i++) {
            headsector = sector->lines[i]->frontsector;
            if(!headsector) {  // this should never happen
                return;
            }

            if(headsector == sector) {
                continue;
            }

            if(headsector->tag == sector->tag) {
                break;
            }
        }
    }

    seq = Z_Malloc(sizeof(*seq), PU_LEVSPEC, 0);

    P_AddThinker(&seq->thinker);

    seq->thinker.function.acp1 = (actionf_p1)T_Sequence;
    seq->sector = sector;
    seq->special = sector->special;
    seq->count = 1;
    seq->index = sector->tag;
    seq->start = (headsector == NULL ? 1 : 0);
    seq->headsector = headsector;
}
Exemplo n.º 30
0
/** Fades all the lights in sectors with a particular tag to a new
  * value.
  *
  * \param tag       Tag to look for sectors by.
  * \param destvalue The final light value in these sectors.
  * \param speed     Speed of the fade; the change to the ligh
  *                  level in each sector per tic.
  * \todo Calculate speed better so that it is possible to specify
  *       the time for completion of the fade, and all lights fade
  *       in this time regardless of initial values.
  * \sa T_LightFade
  */
void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed)
{
	INT32 i;
	lightlevel_t *ll;
	sector_t *sector;

	// search all sectors for ones with tag
	for (i = -1; (i = P_FindSectorFromTag(tag, i)) >= 0 ;)
	{
		sector = &sectors[i];

		P_RemoveLighting(sector); // remove the old lighting effect first
		ll = Z_Calloc(sizeof (*ll), PU_LEVSPEC, NULL);
		ll->thinker.function.acp1 = (actionf_p1)T_LightFade;
		sector->lightingdata = ll; // set it to the lightlevel_t

		P_AddThinker(&ll->thinker); // add thinker

		ll->sector = sector;
		ll->destlevel = destvalue;
		ll->speed = speed;
	}
}