// p_lnspec.c: Code to handle line specials.
//
// Each function returns true if it caused something to happen
// or false if it couldn't perform the desired action.

#include <string.h>
#include "doomstat.h"
#include "p_local.h"
#include "p_lnspec.h"
#include "g_level.h"
#include "v_palette.h"
#include "tables.h"
#include "i_system.h"
#include "i_sound.h" // [BC] New #includes
#include "p_inter.h"
#include "st_stuff.h"
#include "dstrings.h"
#include "t_info.h"
#include "sv_main.h"
#include "p_local.h"
#include "v_text.h"

#define FUNC(a) static BOOL a (line_t *ln, AActor *it, int arg0, int arg1, \
							   int arg2, int arg3, int arg4, int arg5) // [BC]

#define SPEED(a)		((a)*(FRACUNIT/8))
#define TICS(a)			(((a)*TICRATE)/35)
#define OCTICS(a)		(((a)*TICRATE)/8)
#define	BYTEANGLE(a)	((angle_t)((a)<<24))

// [BC] Also for evil grin
extern BOOL		evilgrin;
BOOL lockspvars;

// Used by the teleporters to know if they were
// activated by walking across the backside of a line.
int TeleportSide;

// Set true if this special was activated from inside a script.
BOOL InScript;

FUNC(LS_NOP)
{
	return false;
}

FUNC(LS_Polyobj_RotateLeft)
// Polyobj_RotateLeft (po, speed, angle)
{
	return EV_RotatePoly (ln, arg0, arg1, arg2, 1, false);
}

FUNC(LS_Polyobj_RotateRight)
// Polyobj_rotateRight (po, speed, angle)
{
	return EV_RotatePoly (ln, arg0, arg1, arg2, -1, false);
}

FUNC(LS_Polyobj_Move)
// Polyobj_Move (po, speed, angle, distance)
{
	return EV_MovePoly (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg3 * FRACUNIT, false);
}

FUNC(LS_Polyobj_MoveTimes8)
// Polyobj_MoveTimes8 (po, speed, angle, distance)
{
	return EV_MovePoly (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg3 * FRACUNIT * 8, false);
}

FUNC(LS_Polyobj_DoorSwing)
// Polyobj_DoorSwing (po, speed, angle, delay)
{
	return EV_OpenPolyDoor (ln, arg0, arg1, BYTEANGLE(arg2), arg3, 0, PODOOR_SWING);
}

FUNC(LS_Polyobj_DoorSlide)
// Polyobj_DoorSlide (po, speed, angle, distance, delay)
{
	return EV_OpenPolyDoor (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg4, arg3*FRACUNIT, PODOOR_SLIDE);
}

FUNC(LS_Polyobj_OR_RotateLeft)
// Polyobj_OR_RotateLeft (po, speed, angle)
{
	return EV_RotatePoly (ln, arg0, arg1, arg2, 1, true);
}

FUNC(LS_Polyobj_OR_RotateRight)
// Polyobj_OR_RotateRight (po, speed, angle)
{
	return EV_RotatePoly (ln, arg0, arg1, arg2, -1, true);
}

FUNC(LS_Polyobj_OR_Move)
// Polyobj_OR_Move (po, speed, angle, distance)
{
	return EV_MovePoly (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg3 * FRACUNIT, true);
}

FUNC(LS_Polyobj_OR_MoveTimes8)
// Polyobj_OR_MoveTimes8 (po, speed, angle, distance)
{
	return EV_MovePoly (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg3 * FRACUNIT * 8, true);
}

FUNC(LS_Door_Close)
// Door_Close (tag, speed)
{
	return EV_DoDoor (DDoor::doorClose, ln, it, arg0, SPEED(arg1), 0, NoKey);
}

FUNC(LS_Door_Open)
// Door_Open (tag, speed)
{
	return EV_DoDoor (DDoor::doorOpen, ln, it, arg0, SPEED(arg1), 0, NoKey);
}

FUNC(LS_Door_Raise)
// Door_Raise (tag, speed, delay)
{
	return EV_DoDoor (DDoor::doorRaise, ln, it, arg0, SPEED(arg1), TICS(arg2), NoKey);
}

FUNC(LS_Door_LockedRaise)
// Door_LockedRaise (tag, speed, delay, lock)
{
	return EV_DoDoor (arg2 ? DDoor::doorRaise : DDoor::doorOpen, ln, it,
					  arg0, SPEED(arg1), TICS(arg2), (keytype_t)arg3);
}

FUNC(LS_Door_CloseWaitOpen)
// Door_CloseWaitOpen (tag, speed, delay)
{
	return EV_DoDoor (DDoor::doorCloseWaitOpen, ln, it, arg0, SPEED(arg1), OCTICS(arg2), NoKey);
}

FUNC(LS_Generic_Door)
// Generic_Door (tag, speed, kind, delay, lock)
{
	DDoor::EVlDoor type;

	switch (arg2)
	{
		case 0: type = DDoor::doorRaise;			break;
		case 1: type = DDoor::doorOpen;				break;
		case 2: type = DDoor::doorCloseWaitOpen;	break;
		case 3: type = DDoor::doorClose;			break;
		default: return false;
	}
	return EV_DoDoor (type, ln, it, arg0, SPEED(arg1), OCTICS(arg3), (keytype_t)arg4);
}

FUNC(LS_Floor_LowerByValue)
// Floor_LowerByValue (tag, speed, height)
{
	return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, 0, 0);
}

FUNC(LS_Floor_LowerToLowest)
// Floor_LowerToLowest (tag, speed)
{
	return EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Floor_LowerToHighest)
// Floor_LowerToHighest (tag, speed, adjust)
{
	return EV_DoFloor (DFloor::floorLowerToHighest, ln, arg0, SPEED(arg1), (arg2-128)*FRACUNIT, 0, 0);
}

FUNC(LS_Floor_LowerToNearest)
// Floor_LowerToNearest (tag, speed)
{
	return EV_DoFloor (DFloor::floorLowerToNearest, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Floor_RaiseByValue)
// Floor_RaiseByValue (tag, speed, height)
{
	return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, 0, 0);
}

FUNC(LS_Floor_RaiseToHighest)
// Floor_RaiseToHighest (tag, speed)
{
	return EV_DoFloor (DFloor::floorRaiseToHighest, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Floor_RaiseToNearest)
// Floor_RaiseToNearest (tag, speed)
{
	return EV_DoFloor (DFloor::floorRaiseToNearest, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Floor_RaiseAndCrush)
// Floor_RaiseAndCrush (tag, speed, crush)
{
	return EV_DoFloor (DFloor::floorRaiseAndCrush, ln, arg0, SPEED(arg1), 0, arg2, 0);
}

FUNC(LS_Floor_RaiseByValueTimes8)
// FLoor_RaiseByValueTimes8 (tag, speed, height)
{
	return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, 0, 0);
}

FUNC(LS_Floor_LowerByValueTimes8)
// Floor_LowerByValueTimes8 (tag, speed, height)
{
	return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, 0, 0);
}

FUNC(LS_Floor_CrushStop)
// Floor_CrushStop (tag)
{
	return EV_FloorCrushStop (arg0);
}

FUNC(LS_Floor_LowerInstant)
// Floor_LowerInstant (tag, unused, height)
{
	return EV_DoFloor (DFloor::floorLowerInstant, ln, arg0, 0, arg2*FRACUNIT*8, 0, 0);
}

FUNC(LS_Floor_RaiseInstant)
// Floor_RaiseInstant (tag, unused, height)
{
	return EV_DoFloor (DFloor::floorRaiseInstant, ln, arg0, 0, arg2*FRACUNIT*8, 0, 0);
}

FUNC(LS_Floor_MoveToValueTimes8)
// Floor_MoveToValueTimes8 (tag, speed, height, negative)
{
	return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1),
					   arg2*FRACUNIT*8*(arg3?-1:1), 0, 0);
}

FUNC(LS_Floor_RaiseToLowestCeiling)
// Floor_RaiseToLowestCeiling (tag, speed)
{
	return EV_DoFloor (DFloor::floorRaiseToLowestCeiling, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Floor_RaiseByTexture)
// Floor_RaiseByTexture (tag, speed)
{
	return EV_DoFloor (DFloor::floorRaiseByTexture, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Floor_RaiseByValueTxTy)
// Floor_RaiseByValueTxTy (tag, speed, height)
{
	return EV_DoFloor (DFloor::floorRaiseAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, 0);
}

FUNC(LS_Floor_LowerToLowestTxTy)
// Floor_LowerToLowestTxTy (tag, speed)
{
	return EV_DoFloor (DFloor::floorLowerAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, 0);
}

FUNC(LS_Floor_Waggle)
// Floor_Waggle (tag, amplitude, frequency, delay, time)
{
	return EV_StartFloorWaggle (arg0, arg1, arg2, arg3, arg4);
}

FUNC(LS_Floor_TransferTrigger)
// Floor_TransferTrigger (tag)
{
	return EV_DoChange (ln, trigChangeOnly, arg0);
}

FUNC(LS_Floor_TransferNumeric)
// Floor_TransferNumeric (tag)
{
	return EV_DoChange (ln, numChangeOnly, arg0);
}

FUNC(LS_Floor_Donut)
// Floor_Donut (pillartag, pillarspeed, slimespeed)
{
	return EV_DoDonut (arg0, SPEED(arg1), SPEED(arg2));
}

FUNC(LS_Generic_Floor)
// Generic_Floor (tag, speed, height, target, change/model/direct/crush)
{
	DFloor::EFloor type;

	if (arg4 & 8)
	{
		switch (arg3)
		{
			case 1: type = DFloor::floorRaiseToHighest;			break;
			case 2: type = DFloor::floorRaiseToLowest;			break;
			case 3: type = DFloor::floorRaiseToNearest;			break;
			case 4: type = DFloor::floorRaiseToLowestCeiling;	break;
			case 5: type = DFloor::floorRaiseToCeiling;			break;
			case 6: type = DFloor::floorRaiseByTexture;			break;
			default:type = DFloor::floorRaiseByValue;			break;
		}
	}
	else
	{
		switch (arg3)
		{
			case 1: type = DFloor::floorLowerToHighest;			break;
			case 2: type = DFloor::floorLowerToLowest;			break;
			case 3: type = DFloor::floorLowerToNearest;			break;
			case 4: type = DFloor::floorLowerToLowestCeiling;	break;
			case 5: type = DFloor::floorLowerToCeiling;			break;
			case 6: type = DFloor::floorLowerByTexture;			break;
			default:type = DFloor::floorLowerByValue;			break;
		}
	}

	return EV_DoFloor (type, ln, arg0, SPEED(arg1), arg2*FRACUNIT,
					   (arg4 & 16) ? 20 : -1, arg4 & 7);
					   
}

FUNC(LS_Stairs_BuildDown)
// Stair_BuildDown (tag, speed, height, delay, reset)
{
	return EV_BuildStairs (arg0, DFloor::buildDown, ln,
						   arg2 * FRACUNIT, SPEED(arg1), TICS(arg3), arg4, 0, 1);
}

FUNC(LS_Stairs_BuildUp)
// Stairs_BuildUp (tag, speed, height, delay, reset)
{
	return EV_BuildStairs (arg0, DFloor::buildUp, ln,
						   arg2 * FRACUNIT, SPEED(arg1), TICS(arg3), arg4, 0, 1);
}

FUNC(LS_Stairs_BuildDownSync)
// Stairs_BuildDownSync (tag, speed, height, reset)
{
	return EV_BuildStairs (arg0, DFloor::buildDown, ln,
						   arg2 * FRACUNIT, SPEED(arg1), 0, arg3, 0, 2);
}

FUNC(LS_Stairs_BuildUpSync)
// Stairs_BuildUpSync (tag, speed, height, reset)
{
	return EV_BuildStairs (arg0, DFloor::buildUp, ln,
						   arg2 * FRACUNIT, SPEED(arg1), 0, arg3, 0, 2);
}

FUNC(LS_Stairs_BuildUpDoom)
// Stairs_BuildUpDoom (tag, speed, height, delay, reset)
{
	return EV_BuildStairs (arg0, DFloor::buildUp, ln,
						   arg2 * FRACUNIT, SPEED(arg1), TICS(arg3), arg4, 0, 0);
}

FUNC(LS_Generic_Stairs)
// Generic_Stairs (tag, speed, step, dir/igntxt, reset)
{
	DFloor::EStair type = (arg3 & 1) ? DFloor::buildUp : DFloor::buildDown;
	BOOL res = EV_BuildStairs (arg0, type, ln,
							   arg2 * FRACUNIT, SPEED(arg1), 0, arg4, arg3 & 2, 0);

	if (res && ln && (ln->flags & ML_REPEAT_SPECIAL) && ln->special == Generic_Stairs)
		// Toggle direction of next activation of repeatable stairs
		ln->args[3] ^= 1;

	return res;
}

FUNC(LS_Pillar_Build)
// Pillar_Build (tag, speed, height)
{
	return EV_DoPillar (DPillar::pillarBuild, arg0, SPEED(arg1), arg2*FRACUNIT, 0, -1);
}

FUNC(LS_Pillar_BuildAndCrush)
// Pillar_BuildAndCrush (tag, speed, height, crush)
{
	return EV_DoPillar (DPillar::pillarBuild, arg0, SPEED(arg1), arg2*FRACUNIT, 0, arg3);
}

FUNC(LS_Pillar_Open)
// Pillar_Open (tag, speed, f_height, c_height)
{
	return EV_DoPillar (DPillar::pillarOpen, arg0, SPEED(arg1), arg2*FRACUNIT, arg3*FRACUNIT, -1);
}

FUNC(LS_Ceiling_LowerByValue)
// Ceiling_LowerByValue (tag, speed, height)
{
	return EV_DoCeiling (DCeiling::ceilLowerByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT, 0, 0, 0);
}

FUNC(LS_Ceiling_RaiseByValue)
// Ceiling_RaiseByValue (tag, speed, height)
{
	return EV_DoCeiling (DCeiling::ceilRaiseByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT, 0, 0, 0);
}

FUNC(LS_Ceiling_LowerByValueTimes8)
// Ceiling_LowerByValueTimes8 (tag, speed, height)
{
	return EV_DoCeiling (DCeiling::ceilLowerByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT*8, 0, 0, 0);
}

FUNC(LS_Ceiling_RaiseByValueTimes8)
// Ceiling_RaiseByValueTimes8 (tag, speed, height)
{
	return EV_DoCeiling (DCeiling::ceilRaiseByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT*8, 0, 0, 0);
}

FUNC(LS_Ceiling_CrushAndRaise)
// Ceiling_CrushAndRaise (tag, speed, crush)
{
	return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0);
}

FUNC(LS_Ceiling_LowerAndCrush)
// Ceiling_LowerAndCrush (tag, speed, crush)
{
	return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0);
}

FUNC(LS_Ceiling_CrushStop)
// Ceiling_CrushStop (tag)
{
	return EV_CeilingCrushStop (arg0);
}

FUNC(LS_Ceiling_CrushRaiseAndStay)
// Ceiling_CrushRaiseAndStay (tag, speed, crush)
{
	return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0);
}

FUNC(LS_Ceiling_MoveToValueTimes8)
// Ceiling_MoveToValueTimes8 (tag, speed, height, negative)
{
	return EV_DoCeiling (DCeiling::ceilMoveToValue, ln, arg0, SPEED(arg1), 0,
						 arg2*FRACUNIT*8*((arg3) ? -1 : 1), 0, 0, 0);
}

FUNC(LS_Ceiling_LowerToHighestFloor)
// Ceiling_LowerToHighestFloor (tag, speed)
{
	return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, 0, 0, 0, 0);
}

FUNC(LS_Ceiling_LowerInstant)
// Ceiling_LowerInstant (tag, unused, height)
{
	return EV_DoCeiling (DCeiling::ceilLowerInstant, ln, arg0, 0, 0, arg2*FRACUNIT*8, 0, 0, 0);
}

FUNC(LS_Ceiling_RaiseInstant)
// Ceiling_RaiseInstant (tag, unused, height)
{
	return EV_DoCeiling (DCeiling::ceilRaiseInstant, ln, arg0, 0, 0, arg2*FRACUNIT*8, 0, 0, 0);
}

FUNC(LS_Ceiling_CrushRaiseAndStayA)
// Ceiling_CrushRaiseAndStayA (tag, dnspeed, upspeed, damage)
{
	return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 0, 0);
}

FUNC(LS_Ceiling_CrushRaiseAndStaySilA)
// Ceiling_CrushRaiseAndStaySilA (tag, dnspeed, upspeed, damage)
{
	return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 1, 0);
}

FUNC(LS_Ceiling_CrushAndRaiseA)
// Ceiling_CrushAndRaiseA (tag, dnspeed, upspeed, damage)
{
	return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 0, 0);
}

FUNC(LS_Ceiling_CrushAndRaiseSilentA)
// Ceiling_CrushAndRaiseSilentA (tag, dnspeed, upspeed, damage)
{
	return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 1, 0);
}

FUNC(LS_Ceiling_RaiseToNearest)
// Ceiling_RaiseToNearest (tag, speed)
{
	return EV_DoCeiling (DCeiling::ceilRaiseToNearest, ln, arg0, SPEED(arg1), 0, 0, 0, 0, 0);
}

FUNC(LS_Ceiling_LowerToLowest)
// Ceiling_LowerToLowest (tag, speed)
{
	return EV_DoCeiling (DCeiling::ceilLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, 0, 0);
}

FUNC(LS_Ceiling_LowerToFloor)
// Ceiling_LowerToFloor (tag, speed)
{
	return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, 0, 0, 0, 0);
}

FUNC(LS_Generic_Ceiling)
// Generic_Ceiling (tag, speed, height, target, change/model/direct/crush)
{
	DCeiling::ECeiling type;

	if (arg4 & 8) {
		switch (arg3) {
			case 1:  type = DCeiling::ceilRaiseToHighest;		break;
			case 2:  type = DCeiling::ceilRaiseToLowest;		break;
			case 3:  type = DCeiling::ceilRaiseToNearest;		break;
			case 4:  type = DCeiling::ceilRaiseToHighestFloor;	break;
			case 5:  type = DCeiling::ceilRaiseToFloor;			break;
			case 6:  type = DCeiling::ceilRaiseByTexture;		break;
			default: type = DCeiling::ceilRaiseByValue;			break;
		}
	} else {
		switch (arg3) {
			case 1:  type = DCeiling::ceilLowerToHighest;		break;
			case 2:  type = DCeiling::ceilLowerToLowest;		break;
			case 3:  type = DCeiling::ceilLowerToNearest;		break;
			case 4:  type = DCeiling::ceilLowerToHighestFloor;	break;
			case 5:  type = DCeiling::ceilLowerToFloor;			break;
			case 6:  type = DCeiling::ceilLowerByTexture;		break;
			default: type = DCeiling::ceilLowerByValue;			break;
		}
	}

	return EV_DoCeiling (type, ln, arg0, SPEED(arg1), SPEED(arg1), arg2*FRACUNIT,
						 (arg4 & 16) ? 20 : -1, 0, arg4 & 7);
	return false;
}

FUNC(LS_Generic_Crusher)
// Generic_Crusher (tag, dnspeed, upspeed, silent, damage)
{
	return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1),
						 SPEED(arg2), 0, arg4, arg3 ? 2 : 0, 0);
}

FUNC(LS_Plat_PerpetualRaise)
// Plat_PerpetualRaise (tag, speed, delay)
{
	return EV_DoPlat (arg0, ln, DPlat::platPerpetualRaise, 0, SPEED(arg1), TICS(arg2), 8, 0);
}

FUNC(LS_Plat_PerpetualRaiseLip)
// Plat_PerpetualRaiseLip (tag, speed, delay, lip)
{
	return EV_DoPlat (arg0, ln, DPlat::platPerpetualRaise, 0, SPEED(arg1), TICS(arg2), arg3, 0);
}

FUNC(LS_Plat_Stop)
// Plat_Stop (tag)
{
	EV_StopPlat (arg0);
	return true;
}

FUNC(LS_Plat_DownWaitUpStay)
// Plat_DownWaitUpStay (tag, speed, delay)
{
	return EV_DoPlat (arg0, ln, DPlat::platDownWaitUpStay, 0, SPEED(arg1), TICS(arg2), 8, 0);
}

FUNC(LS_Plat_DownWaitUpStayLip)
// Plat_DownWaitUpStayLip (tag, speed, delay, lip)
{
	return EV_DoPlat (arg0, ln, DPlat::platDownWaitUpStay, 0, SPEED(arg1), TICS(arg2), arg3, 0);
}

FUNC(LS_Plat_DownByValue)
// Plat_DownByValue (tag, speed, delay, height)
{
	return EV_DoPlat (arg0, ln, DPlat::platDownByValue, FRACUNIT*arg3*8, SPEED(arg1), TICS(arg2), 0, 0);
}

FUNC(LS_Plat_UpByValue)
// Plat_UpByValue (tag, speed, delay, height)
{
	return EV_DoPlat (arg0, ln, DPlat::platUpByValue, FRACUNIT*arg3*8, SPEED(arg1), TICS(arg2), 0, 0);
}

FUNC(LS_Plat_UpWaitDownStay)
// Plat_UpWaitDownStay (tag, speed, delay)
{
	return EV_DoPlat (arg0, ln, DPlat::platUpWaitDownStay, 0, SPEED(arg1), TICS(arg2), 0, 0);
}

FUNC(LS_Plat_RaiseAndStayTx0)
// Plat_RaiseAndStayTx0 (tag, speed)
{
	return EV_DoPlat (arg0, ln, DPlat::platRaiseAndStay, 0, SPEED(arg1), 0, 0, 1);
}

FUNC(LS_Plat_UpByValueStayTx)
// Plat_UpByValueStayTx (tag, speed, height)
{
	return EV_DoPlat (arg0, ln, DPlat::platUpByValueStay, FRACUNIT*arg2*8, SPEED(arg1), 0, 0, 2);
}

FUNC(LS_Plat_ToggleCeiling)
// Plat_ToggleCeiling (tag)
{
	return EV_DoPlat (arg0, ln, DPlat::platToggle, 0, 0, 0, 0, 0);
}

FUNC(LS_Generic_Lift)
// Generic_Lift (tag, speed, delay, target, height)
{
	DPlat::EPlatType type;

	switch (arg3)
	{
		case 1:
			type = DPlat::platDownWaitUpStay;
			break;
		case 2:
			type = DPlat::platDownToNearestFloor;
			break;
		case 3:
			type = DPlat::platDownToLowestCeiling;
			break;
		case 4:
			type = DPlat::platPerpetualRaise;
			break;
		default:
			type = DPlat::platUpByValue;
			break;
	}

	return EV_DoPlat (arg0, ln, type, arg4*8*FRACUNIT, SPEED(arg1), OCTICS(arg2), 0, 0);
}

FUNC(LS_Exit_Normal)
// Exit_Normal (position)
{
	if (netstate == NS_CLIENT)
		return false;

	if (CheckIfExitIsGood (it))
	{
		G_ExitLevel (0);
		return true;
	}
	return false;
}

FUNC(LS_Exit_Secret)
// Exit_Secret (position)
{
	if (netstate == NS_CLIENT)
		return false;

	if (CheckIfExitIsGood (it))
	{
		G_SecretExitLevel (0);
		return true;
	}
	return false;
}

FUNC(LS_Teleport_NewMap)
// Teleport_NewMap (map, position)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!TeleportSide)
	{
		level_info_t *info = FindLevelByNum (arg0);

		if (info && CheckIfExitIsGood (it))
		{
			strncpy (level.nextmap, info->mapname, 8);
			G_ExitLevel (arg1);
			return true;
		}
	}
	return false;
}

FUNC(LS_Teleport)
// Teleport (tid)
{
	return EV_Teleport (arg0, TeleportSide, it);
}

FUNC(LS_TeleportAll)	// [BC]
// TeleportAll (tid)
{
	return EV_TeleportAll (arg0, TeleportSide, it);
}

FUNC(LS_Teleport_NoFog)
// Teleport_NoFog (tid)
{
	return EV_SilentTeleport (arg0, ln, TeleportSide, it);
}

FUNC(LS_TeleportAll_NoFog)	// [BC]
// TeleportAll_NoFog (tid)
{
	return EV_SilentTeleportAll (arg0, ln, TeleportSide, it);
}

FUNC(LS_Teleport_EndGame)
// Teleport_EndGame ()
{
	if (netstate == NS_CLIENT)
		return false;

	if (!TeleportSide && CheckIfExitIsGood (it))
	{
		strncpy (level.nextmap, "EndGameC", 8);
		G_ExitLevel (0);
		return true;
	}
	return false;
}

FUNC(LS_Teleport_Line)
// Teleport_Line (thisid, destid, reversed)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_SilentLineTeleport (ln, TeleportSide, it, arg1, arg2);
}

// [BC] Now you can thrust things with tid's
FUNC(LS_ThrustThing)
// ThrustThing (angle, force, tid)
{
	if (netstate == NS_CLIENT)
		return false;

	AActor *mobj = AActor::FindByTID (NULL, arg2);

	if (arg2)
	{
		while (mobj)
		{
			angle_t angle = BYTEANGLE(arg0) >> ANGLETOFINESHIFT;

			mobj->momx = arg1 * finecosine[angle];
			mobj->momy = arg1 * finesine[angle];
	
			mobj = mobj->FindByTID(arg2);
		}
		return true;
	}
	else if (it)
	{
		angle_t angle = BYTEANGLE(arg0) >> ANGLETOFINESHIFT;

		it->momx = arg1 * finecosine[angle];
		it->momy = arg1 * finesine[angle];
		return true;
	}
	return false;
}

FUNC(LS_DamageThing)
// DamageThing (damage)
{
	if (netstate == NS_CLIENT)
		return false;

	if (it)
	{
		if (arg0)
			P_DamageMobj (it, NULL, NULL, arg0, MOD_UNKNOWN);
		else
			P_DamageMobj (it, NULL, NULL, it->health+it->info->spawnhealth, MOD_UNKNOWN, DMG_NO_INVUL|DMG_NO_ARMOR);
	}

	return it ? true : false;
}

BOOL P_GiveBody (player_t *, int);

FUNC(LS_HealThing)
// HealThing (amount)
{
	if (netstate == NS_CLIENT)
		return false;

	if (it)
	{
		if (it->player)
		{
			P_GiveBody (it->player, arg0);
		}
		else
		{
			it->health += arg0;
			if (mobjinfo[it->type].spawnhealth > it->health)
				it->health = mobjinfo[it->type].spawnhealth;
		}
	}

	return it ? true : false;
}

FUNC(LS_Thing_Activate)
// Thing_Activate (tid)
{
	if (netstate == NS_CLIENT)
		return false;

	AActor *mobj = AActor::FindByTID (NULL, arg0);

	while (mobj)
	{
		AActor *temp = mobj->FindByTID (arg0);
		P_ActivateMobj (mobj, it);
		mobj = temp;
	}

	return true;
}

FUNC(LS_Thing_Deactivate)
// Thing_Deactivate (tid)
{
	if (netstate == NS_CLIENT)
		return false;

	AActor *mobj = AActor::FindByTID (NULL, arg0);

	while (mobj)
	{
		AActor *temp = mobj->FindByTID (arg0);
		P_DeactivateMobj (mobj);
		mobj = temp;
	}

	return true;
}

FUNC(LS_Thing_Remove)
// Thing_Remove (tid)
{
	if (netstate == NS_CLIENT)
		return false;

	AActor *mobj = AActor::FindByTID (NULL, arg0);

	while (mobj)
	{
		AActor *temp = mobj->FindByTID (arg0);
		mobj->Destroy ();
		mobj = temp;
	}

	return true;
}

FUNC(LS_Thing_Destroy)
// Thing_Destroy (tid)
{
	if (netstate == NS_CLIENT)
		return false;

	AActor *mobj = AActor::FindByTID (NULL, arg0);

	while (mobj)
	{
		AActor *temp = mobj->FindByTID (arg0);

		if (mobj->flags & MF_SHOOTABLE)
			P_DamageMobj (mobj, NULL, it, mobj->health, MOD_UNKNOWN);

		mobj = temp;
	}

	return true;
}

FUNC(LS_Thing_Projectile)
// Thing_Projectile (tid, type, angle, speed, vspeed)
{
	if (netstate == NS_CLIENT)
		return false;

	return P_Thing_Projectile (arg0, arg1, BYTEANGLE(arg2), arg3<<(FRACBITS-3),
		arg4<<(FRACBITS-3), false);
}

FUNC(LS_Thing_ProjectileGravity)
// Thing_ProjectileGravity (tid, type, angle, speed, vspeed)
{
	if (netstate == NS_CLIENT)
		return false;

	return P_Thing_Projectile (arg0, arg1, BYTEANGLE(arg2), arg3<<(FRACBITS-3),
		arg4<<(FRACBITS-3), true);
}

FUNC(LS_Thing_Spawn)	// [BC]
// Thing_Spawn (tid, type, angle, fog, newtid)
{
	if (netstate == NS_CLIENT)
		return false;

	return P_Thing_Spawn (arg0, arg1, BYTEANGLE(arg2), true, arg3);
}

FUNC(LS_Thing_SpawnNoFog)	// [BC]
// Thing_SpawnNoFog (tid, type, angle, newtid)
{
	if (netstate == NS_CLIENT)
		return false;

	return P_Thing_Spawn (arg0, arg1, BYTEANGLE(arg2), false, arg3);
}

FUNC(LS_Thing_SetGoal)
// Thing_SetGoal (tid, goal, delay)
{
	if (netstate == NS_CLIENT)
		return false;

	AActor *self = AActor::FindByTID (NULL, arg0);
	AActor *goal = AActor::FindGoal (NULL, arg1, MT_PATHNODE);

	while (self)
	{
		if (self->flags & MF_SHOOTABLE)
		{
			self->goal = goal;
			if (!self->target)
				self->reactiontime = arg2 * TICRATE;
		}
		self = self->FindByTID (arg0);
	}

	return true;
}

FUNC(LS_ACS_Execute)
// ACS_Execute (script, map, s_arg1, s_arg2, s_arg3)
{
	level_info_t *info;

	if ( (arg1 == 0) || !(info = FindLevelByNum (arg1)) )
		return P_StartScript (it, ln, arg0, level.mapname, TeleportSide, arg2, arg3, arg4, 0);
	else
		return P_StartScript (it, ln, arg0, info->mapname, TeleportSide, arg2, arg3, arg4, 0);
}

FUNC(LS_ACS_ExecuteAlways)
// ACS_ExecuteAlways (script, map, s_arg1, s_arg2, s_arg3)
{
	level_info_t *info;

	if ( (arg1 == 0) || !(info = FindLevelByNum (arg1)) )
		return P_StartScript (it, ln, arg0, level.mapname, TeleportSide, arg2, arg3, arg4, 1);
	else
		return P_StartScript (it, ln, arg0, info->mapname, TeleportSide, arg2, arg3, arg4, 1);
}

FUNC(LS_ACS_LockedExecute)
// ACS_LockedExecute (script, map, s_arg1, s_arg2, lock)
{
	if (arg4 && !P_CheckKeys (it->player, (keytype_t)arg4, 1))
		return false;
	else
		return LS_ACS_Execute (ln, it, arg0, arg1, arg2, arg3, 0, 0);	// [BC]
}

FUNC(LS_ACS_Suspend)
// ACS_Suspend (script, map)
{
	level_info_t *info;

	if ( (arg1 == 0) || !(info = FindLevelByNum (arg1)) )
		P_SuspendScript (arg0, level.mapname);
	else
		P_SuspendScript (arg0, info->mapname);

	return true;
}

FUNC(LS_ACS_Terminate)
// ACS_Terminate (script, map)
{
	level_info_t *info;

	if ( (arg1 == 0) || !(info = FindLevelByNum (arg1)) )
		P_TerminateScript (arg0, level.mapname);
	else
		P_TerminateScript (arg0, info->mapname);

	return true;
}

FUNC(LS_FloorAndCeiling_LowerByValue)
// FloorAndCeiling_LowerByValue (tag, speed, height)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_DoElevator (ln, DElevator::elevateLower, SPEED(arg1), arg2*FRACUNIT, arg0);
}

FUNC(LS_FloorAndCeiling_RaiseByValue)
// FloorAndCeiling_RaiseByValue (tag, speed, height)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_DoElevator (ln, DElevator::elevateRaise, SPEED(arg1), arg2*FRACUNIT, arg0);
}

FUNC(LS_FloorAndCeiling_LowerRaise)
// FloorAndCeiling_LowerRaise (tag, fspeed, cspeed)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_DoCeiling (DCeiling::ceilRaiseToHighest, ln, arg0, SPEED(arg2), 0, 0, 0, 0, 0) ||
		EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0);
}

FUNC(LS_Elevator_MoveToFloor)
// Elevator_MoveToFloor (tag, speed)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_DoElevator (ln, DElevator::elevateCurrent, SPEED(arg1), 0, arg0);
}

FUNC(LS_Elevator_RaiseToNearest)
// Elevator_RaiseToNearest (tag, speed)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_DoElevator (ln, DElevator::elevateUp, SPEED(arg1), 0, arg0);
}

FUNC(LS_Elevator_LowerToNearest)
// Elevator_LowerToNearest (tag, speed)
{
	if (netstate == NS_CLIENT)
		return false;

	return EV_DoElevator (ln, DElevator::elevateDown, SPEED(arg1), 0, arg0);
}

FUNC(LS_Light_ForceLightning)
// Light_ForceLightning (tag)
{
	return false;
}

FUNC(LS_Light_RaiseByValue)
// Light_RaiseByValue (tag, value)
{
	EV_LightChange (arg0, arg1);
	return true;
}

FUNC(LS_Light_LowerByValue)
// Light_LowerByValue (tag, value)
{
	EV_LightChange (arg0, -arg1);
	return true;
}

FUNC(LS_Light_ChangeToValue)
// Light_ChangeToValue (tag, value)
{
	EV_LightTurnOn (arg0, arg1);
	return true;
}

FUNC(LS_Light_Fade)
// Light_Fade (tag, value, tics);
{
	EV_StartLightFading (arg0, arg1, TICS(arg2));
	return true;
}

FUNC(LS_Light_Glow)
// Light_Glow (tag, upper, lower, tics)
{
	EV_StartLightGlowing (arg0, arg1, arg2, TICS(arg3));
	return true;
}

FUNC(LS_Light_Flicker)
// Light_Flicker (tag, upper, lower)
{
	EV_StartLightFlickering (arg0, arg1, arg2);
	return true;
}

FUNC(LS_Light_Strobe)
// Light_Strobe (tag, upper, lower, u-tics, l-tics)
{
	EV_StartLightStrobing (arg0, arg1, arg2, TICS(arg3), TICS(arg4));
	return true;
}

FUNC(LS_Light_StrobeDoom)
// Light_StrobeDoom (tag, u-tics, l-tics)
{
	EV_StartLightStrobing (arg0, TICS(arg1), TICS(arg2));
	return true;
}

FUNC(LS_Light_MinNeighbor)
// Light_MinNeighbor (tag)
{
	EV_TurnTagLightsOff (arg0);
	return true;
}

FUNC(LS_Light_MaxNeighbor)
// Light_MaxNeighbor (tag)
{
	EV_LightTurnOn (arg0, -1);
	return true;
}

FUNC(LS_Radius_Quake)
// Radius_Quake (intensity, duration, damrad, tremrad, tid)
{
	return P_StartQuake (arg4, arg0, arg1, arg2, arg3);
}

FUNC(LS_UsePuzzleItem)
// UsePuzzleItem (item, script)
{
	return false;
}

FUNC(LS_Sector_ChangeSound)
// Sector_ChangeSound (tag, sound)
{
	int secNum;
	BOOL rtn;

	if (!arg0)
		return false;

	secNum = -1;
	rtn = false;
	while ((secNum = P_FindSectorFromTag (arg0,	secNum)) >= 0)
	{
		sectors[secNum].seqType = arg1;
		rtn = true;
	}
	return rtn;
}

struct FThinkerCollection
{
	int RefNum;
	DThinker *Obj;
};

static TArray<FThinkerCollection> Collection;

void AdjustPusher (int tag, int magnitude, int angle, DPusher::EPusher type)
{
	// Find pushers already attached to the sector, and change their parameters.
	{
		TThinkerIterator<DPusher> iterator;
		FThinkerCollection collect;

		while ( (collect.Obj = iterator.Next ()) )
		{
			if ((collect.RefNum = ((DPusher *)collect.Obj)->CheckForSectorMatch (type, tag)) >= 0)
			{
				((DPusher *)collect.Obj)->ChangeValues (magnitude, angle);
				Collection.Push (collect);
			}
		}
	}

	int numcollected = Collection.Size ();
	int secnum = -1;

	// Now create pushers for any sectors that don't already have them.
	while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
	{
		int i;
		for (i = 0; i < numcollected; i++)
		{
			if (Collection[i].RefNum == sectors[secnum].tag)
				break;
		}
		if (i == numcollected)
		{
			new DPusher (type, NULL, magnitude, angle, NULL, secnum);
		}
	}
	Collection.Clear ();
}

FUNC(LS_Sector_SetWind)
// Sector_SetWind (tag, amount, angle)
{
	if (ln || arg3)
		return false;

	AdjustPusher (arg0, arg1, arg2, DPusher::p_wind);
	return true;
}

FUNC(LS_Sector_SetCurrent)
// Sector_SetCurrent (tag, amount, angle)
{
	if (ln || arg3)
		return false;

	AdjustPusher (arg0, arg1, arg2, DPusher::p_current);
	return true;
}

FUNC(LS_Sector_SetFriction)
// Sector_SetFriction ()
{
	return false;
}

FUNC(LS_Scroll_Texture_Both)
// Scroll_Texture_Both (id, left, right, up, down)
{
	if (arg0 == 0)
		return false;

	fixed_t dx = (arg1 - arg2) * (FRACUNIT/64);
	fixed_t dy = (arg4 - arg3) * (FRACUNIT/64);
	int sidechoice;

	if (arg0 < 0)
	{
		sidechoice = 1;
		arg0 = -arg0;
	}
	else
	{
		sidechoice = 0;
	}

	if (dx == 0 && dy == 0)
	{
		// Special case: Remove the scroller, because the deltas are both 0.
		TThinkerIterator<DScroller> iterator;
		DScroller *scroller;

		while ( (scroller = iterator.Next ()) )
		{
			int wallnum = scroller->GetWallNum ();

			if (wallnum >= 0 && lines[sides[wallnum].linenum].id == arg0 &&
				lines[sides[wallnum].linenum].sidenum[sidechoice] == wallnum)
			{
				scroller->Destroy ();
			}
		}
	}
	else
	{
		// Find scrollers already attached to the matching walls, and change
		// their rates.
		{
			TThinkerIterator<DScroller> iterator;
			FThinkerCollection collect;

			while ( (collect.Obj = iterator.Next ()) )
			{
				if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 &&
					lines[sides[collect.RefNum].linenum].id == arg0 &&
					lines[sides[collect.RefNum].linenum].sidenum[sidechoice] == collect.RefNum)
				{
					((DScroller *)collect.Obj)->SetRate (dx, dy);
					Collection.Push (collect);
				}
			}
		}

		int numcollected = Collection.Size ();
		int linenum = -1;

		// Now create scrollers for any walls that don't already have them.
		while ((linenum = P_FindLineFromID (arg0, linenum)) >= 0)
		{
			int i;
			for (i = 0; i < numcollected; i++)
			{
				if (Collection[i].RefNum == lines[linenum].sidenum[sidechoice])
					break;
			}
			if (i == numcollected)
			{
				new DScroller (DScroller::sc_side, dx, dy, -1, lines[linenum].sidenum[sidechoice], 0);
			}
		}
		Collection.Clear ();
	}

	return true;
}

FUNC(LS_Scroll_Floor)
{
	return false;
}

FUNC(LS_Scroll_Ceiling)
{
	return false;
}

FUNC(LS_PointPush_SetForce)
// PointPush_SetForce ()
{
	return false;
}

FUNC(LS_Sector_SetDamage)
// Sector_SetDamage (tag, amount, mod)
{
	int secnum = -1;
	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) {
		sectors[secnum].damage = arg1;
		sectors[secnum].mod = arg2;
	}
	return true;
}

FUNC(LS_Sector_SetGravity)
// Sector_SetGravity (tag, intpart, fracpart)
{
	int secnum = -1;
	float gravity;

	if (arg2 > 99)
		arg2 = 99;
	gravity = (float)arg1 + (float)arg2 * 0.01f;

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
		sectors[secnum].gravity = gravity;

	return true;
}

FUNC(LS_Sector_SetColor)
// Sector_SetColor (tag, r, g, b)
{
	int secnum = -1;
	
	if (netstate == NS_SERVER)
		return false;

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		sectors[secnum].floorcolormap = GetSpecialLights (arg1, arg2, arg3,
			RPART(sectors[secnum].floorcolormap->fade),
			GPART(sectors[secnum].floorcolormap->fade),
			BPART(sectors[secnum].floorcolormap->fade));
		sectors[secnum].ceilingcolormap = GetSpecialLights (arg1, arg2, arg3,
			RPART(sectors[secnum].ceilingcolormap->fade),
			GPART(sectors[secnum].ceilingcolormap->fade),
			BPART(sectors[secnum].ceilingcolormap->fade));
	}

	return true;
}

FUNC(LS_Sector_SetFade)
// Sector_SetFade (tag, r, g, b)
{
	if (netstate == NS_SERVER)
		return false;

	int secnum = -1;
	
	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		sectors[secnum].floorcolormap = GetSpecialLights (
			RPART(sectors[secnum].floorcolormap->color),
			GPART(sectors[secnum].floorcolormap->color),
			BPART(sectors[secnum].floorcolormap->color),
			arg1, arg2, arg3);
		sectors[secnum].ceilingcolormap = GetSpecialLights (
			RPART(sectors[secnum].ceilingcolormap->color),
			GPART(sectors[secnum].ceilingcolormap->color),
			BPART(sectors[secnum].ceilingcolormap->color),
			arg1, arg2, arg3);
	}
	return true;
}

FUNC(LS_Sector_SetCeilingPanning)
// Sector_SetCeilingPanning (tag, x-int, x-frac, y-int, y-frac)
{
	int secnum = -1;
	fixed_t xofs = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
	fixed_t yofs = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		sectors[secnum].ceiling_xoffs = xofs;
		sectors[secnum].ceiling_yoffs = yofs;
	}
	return true;
}

FUNC(LS_Sector_SetFloorPanning)
// Sector_SetFloorPanning (tag, x-int, x-frac, y-int, y-frac)
{
	int secnum = -1;
	fixed_t xofs = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
	fixed_t yofs = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		sectors[secnum].floor_xoffs = xofs;
		sectors[secnum].floor_yoffs = yofs;
	}
	return true;
}

FUNC(LS_Sector_SetCeilingScale)
// Sector_SetCeilingScale (tag, x-int, x-frac, y-int, y-frac)
{
	int secnum = -1;
	fixed_t xscale = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
	fixed_t yscale = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);

	if (xscale)
		xscale = FixedDiv (FRACUNIT, xscale);
	if (yscale)
		yscale = FixedDiv (FRACUNIT, yscale);

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		if (xscale)
			sectors[secnum].ceiling_xscale = xscale;
		if (yscale)
			sectors[secnum].ceiling_yscale = yscale;
	}
	return true;
}

FUNC(LS_Sector_SetFloorScale)
// Sector_SetFloorScale (tag, x-int, x-frac, y-int, y-frac)
{
	int secnum = -1;
	fixed_t xscale = arg1 * FRACUNIT + arg2 * (FRACUNIT/100);
	fixed_t yscale = arg3 * FRACUNIT + arg4 * (FRACUNIT/100);

	if (xscale)
		xscale = FixedDiv (FRACUNIT, xscale);
	if (yscale)
		yscale = FixedDiv (FRACUNIT, yscale);

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		if (xscale)
			sectors[secnum].floor_xscale = xscale;
		if (yscale)
			sectors[secnum].floor_yscale = yscale;
	}
	return true;
}

FUNC(LS_Sector_SetRotation)
// Sector_SetRotation (tag, floor-angle, ceiling-angle)
{
	int secnum = -1;
	angle_t ceiling = arg2 * ANGLE_1;
	angle_t floor = arg1 * ANGLE_1;

	while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
	{
		sectors[secnum].floor_angle = floor;
		sectors[secnum].ceiling_angle = ceiling;
	}
	return true;
}

FUNC(LS_Line_AlignCeiling)
// Line_AlignCeiling (lineid, side)
{
	int line = P_FindLineFromID (arg0, -1);
	BOOL ret = 0;

	if (line < 0)
		I_Error ("Sector_AlignCeiling: Lineid %d is undefined", arg0);
	do
	{
		ret |= R_AlignFlat (line, !!arg1, 1);
	} while ( (line = P_FindLineFromID (arg0, line)) >= 0);
	return ret;
}

FUNC(LS_Line_AlignFloor)
// Line_AlignFloor (lineid, side)
{
	int line = P_FindLineFromID (arg0, -1);
	BOOL ret = 0;

	if (line < 0)
		I_Error ("Sector_AlignFloor: Lineid %d is undefined", arg0);
	do
	{
		ret |= R_AlignFlat (line, !!arg1, 0);
	} while ( (line = P_FindLineFromID (arg0, line)) >= 0);
	return ret;
}

FUNC(LS_ChangeCamera)
// ChangeCamera (tid, who, revert?)
{
	AActor *camera = AActor::FindGoal (NULL, arg0, MT_CAMERA);

	if (!it || !it->player || arg1) {
		int i;

		for (i = 0; i < MAXPLAYERS; i++) {
			if (!playeringame[i])
				continue;

			if (camera) {
				players[i].camera = camera;
				if (arg2)
					players[i].cheats |= CF_REVERTPLEASE;
			} else {
				players[i].camera = players[i].mo;
				players[i].cheats &= ~CF_REVERTPLEASE;
			}
		}
	} else {
		if (camera) {
			it->player->camera = camera;
			if (arg2)
				it->player->cheats |= CF_REVERTPLEASE;
		} else {
			it->player->camera = it;
			it->player->cheats &= ~CF_REVERTPLEASE;
		}
	}

	return true;
}

FUNC(LS_SetPlayerProperty)
// SetPlayerProperty (who, set, which)
{
#define PROP_FROZEN		0
#define PROP_NOTARGET	1

	int mask = 0;

	if (!it->player && !arg0)
		return false;

	switch (arg2)
	{
		case PROP_FROZEN:
			mask = CF_FROZEN;
			break;
		case PROP_NOTARGET:
			mask = CF_NOTARGET;
			break;
	}

	if (arg1 == 0)
	{
		if (arg1)
			it->player->cheats |= mask;
		else
			it->player->cheats &= ~mask;
	}
	else
	{
		int i;

		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;

			if (arg1)
				players[i].cheats |= mask;
			else
				players[i].cheats &= ~mask;
		}
	}

	return !!mask;
}

FUNC(LS_TranslucentLine)
// TranslucentLine (id, amount)
{
	if (ln)
		return false;

	int linenum = -1;
	while ((linenum = P_FindLineFromID (arg0, linenum)) >= 0)
	{
		lines[linenum].lucency = arg1 & 255;
	}

	return true;
}

// [BC] Start of new ACS functions
FUNC(LS_Player_RemoveItem)
// Player_RemoveItem (which, BOOL display message)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!it || !it->player || !arg0)
		return false;

	P_LostSpecialThing ((mobjtype_t)SpawnableThings[arg0], it->player, !!arg1);
	ST_Start ();
	return true;
}

FUNC(LS_Player_GiveItem)
// Player_GiveItem (which, BOOL display message)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!it || !it->player || !arg0)
		return false;

	P_GiveSpecialThing ((mobjtype_t)SpawnableThings[arg0], it->player, !!arg1, false);
	ST_Start ();
	return true;
}

// [BC] Note: I did this cause I don't
// want the function to be able to crash
// if they tried to say change an item's
// sprite to the one of a player carrying
// the BFG or something, since it'd crash.
// So all the ones like that have been removed
// from this list.
int SwitchableSprites[] = {
	0,
	S_NULL,
	S_BLOOD1,
	S_BLOOD2,
	S_BLOOD3,
	S_PUFF1,
	S_PUFF2,
	S_PUFF3,
	S_PUFF4,
	S_TBALL1,	// 10
	S_TBALL2,
	S_TBALLX1,
	S_TBALLX2,
	S_TBALLX3,
	S_RBALL1,
	S_RBALL2,
	S_RBALLX1,
	S_RBALLX2,
	S_RBALLX3,
	S_PLASBALL,
	S_PLASBALL2,
	S_PLASEXP,
	S_PLASEXP2,
	S_PLASEXP3,
	S_PLASEXP4,
	S_PLASEXP5,
	S_ROCKET,
	S_BFGSHOT,
	S_BFGSHOT2,
	S_BFGLAND,
	S_BFGLAND2,
	S_BFGLAND3,
	S_BFGLAND4,
	S_BFGLAND5,
	S_BFGLAND6,
	S_BFGEXP,
	S_BFGEXP2,
	S_BFGEXP3,
	S_BFGEXP4,
	S_EXPLODE1,
	S_EXPLODE2,
	S_EXPLODE3,
	S_TFOG,
	S_TFOG01,
	S_TFOG02,
	S_TFOG2,
	S_TFOG3,
	S_TFOG4,
	S_TFOG5,
	S_TFOG6,
	S_TFOG7,
	S_TFOG8,
	S_TFOG9,
	S_TFOG10,
	S_IFOG,
	S_IFOG01,
	S_IFOG02,
	S_IFOG2,
	S_IFOG3,
	S_IFOG4,
	S_IFOG5,
	S_PLAY,
	S_PLAY_RUN1,
	S_PLAY_RUN2,
	S_PLAY_RUN3,
	S_PLAY_RUN4,
	S_PLAY_ATK1,
	S_PLAY_ATK2,
	S_PLAY_PAIN,
	S_PLAY_PAIN2,
	S_PLAY_DIE1,
	S_PLAY_DIE2,
	S_PLAY_DIE3,
	S_PLAY_DIE4,
	S_PLAY_DIE5,
	S_PLAY_DIE6,
	S_PLAY_DIE7,
	S_PLAY_XDIE1,
	S_PLAY_XDIE2,
	S_PLAY_XDIE3,
	S_PLAY_XDIE4,
	S_PLAY_XDIE5,
	S_PLAY_XDIE6,
	S_PLAY_XDIE7,
	S_PLAY_XDIE8,
	S_PLAY_XDIE9,
	S_POSS_STND,
	S_POSS_STND2,
	S_POSS_RUN1,
	S_POSS_RUN2,
	S_POSS_RUN3,
	S_POSS_RUN4,
	S_POSS_RUN5,
	S_POSS_RUN6,
	S_POSS_RUN7,
	S_POSS_RUN8,
	S_POSS_ATK1,
	S_POSS_ATK2,
	S_POSS_ATK3,
	S_POSS_PAIN,
	S_POSS_PAIN2,
	S_POSS_DIE1,
	S_POSS_DIE2,
	S_POSS_DIE3,
	S_POSS_DIE4,
	S_POSS_DIE5,
	S_POSS_XDIE1,
	S_POSS_XDIE2,
	S_POSS_XDIE3,
	S_POSS_XDIE4,
	S_POSS_XDIE5,
	S_POSS_XDIE6,
	S_POSS_XDIE7,
	S_POSS_XDIE8,
	S_POSS_XDIE9,
	S_POSS_RAISE1,
	S_POSS_RAISE2,
	S_POSS_RAISE3,
	S_POSS_RAISE4,
	S_SPOS_STND,
	S_SPOS_STND2,
	S_SPOS_RUN1,
	S_SPOS_RUN2,
	S_SPOS_RUN3,
	S_SPOS_RUN4,
	S_SPOS_RUN5,
	S_SPOS_RUN6,
	S_SPOS_RUN7,
	S_SPOS_RUN8,
	S_SPOS_ATK1,
	S_SPOS_ATK2,
	S_SPOS_ATK3,
	S_SPOS_PAIN,
	S_SPOS_PAIN2,
	S_SPOS_DIE1,
	S_SPOS_DIE2,
	S_SPOS_DIE3,
	S_SPOS_DIE4,
	S_SPOS_DIE5,
	S_SPOS_XDIE1,
	S_SPOS_XDIE2,
	S_SPOS_XDIE3,
	S_SPOS_XDIE4,
	S_SPOS_XDIE5,
	S_SPOS_XDIE6,
	S_SPOS_XDIE7,
	S_SPOS_XDIE8,
	S_SPOS_XDIE9,
	S_SPOS_RAISE1,
	S_SPOS_RAISE2,
	S_SPOS_RAISE3,
	S_SPOS_RAISE4,
	S_SPOS_RAISE5,
	S_VILE_STND,
	S_VILE_STND2,
	S_VILE_RUN1,
	S_VILE_RUN2,
	S_VILE_RUN3,
	S_VILE_RUN4,
	S_VILE_RUN5,
	S_VILE_RUN6,
	S_VILE_RUN7,
	S_VILE_RUN8,
	S_VILE_RUN9,
	S_VILE_RUN10,
	S_VILE_RUN11,
	S_VILE_RUN12,
	S_VILE_ATK1,
	S_VILE_ATK2,
	S_VILE_ATK3,
	S_VILE_ATK4,
	S_VILE_ATK5,
	S_VILE_ATK6,
	S_VILE_ATK7,
	S_VILE_ATK8,
	S_VILE_ATK9,
	S_VILE_ATK10,
	S_VILE_ATK11,
	S_VILE_HEAL1,
	S_VILE_HEAL2,
	S_VILE_HEAL3,
	S_VILE_PAIN,
	S_VILE_PAIN2,
	S_VILE_DIE1,
	S_VILE_DIE2,
	S_VILE_DIE3,
	S_VILE_DIE4,
	S_VILE_DIE5,
	S_VILE_DIE6,
	S_VILE_DIE7,
	S_VILE_DIE8,
	S_VILE_DIE9,
	S_VILE_DIE10,
	S_FIRE1,
	S_FIRE2,
	S_FIRE3,
	S_FIRE4,
	S_FIRE5,
	S_FIRE6,
	S_FIRE7,
	S_FIRE8,
	S_FIRE9,
	S_FIRE10,
	S_FIRE11,
	S_FIRE12,
	S_FIRE13,
	S_FIRE14,
	S_FIRE15,
	S_FIRE16,
	S_FIRE17,
	S_FIRE18,
	S_FIRE19,
	S_FIRE20,
	S_FIRE21,
	S_FIRE22,
	S_FIRE23,
	S_FIRE24,
	S_FIRE25,
	S_FIRE26,
	S_FIRE27,
	S_FIRE28,
	S_FIRE29,
	S_FIRE30,
	S_SMOKE1,
	S_SMOKE2,
	S_SMOKE3,
	S_SMOKE4,
	S_SMOKE5,
	S_TRACER,
	S_TRACER2,
	S_TRACEEXP1,
	S_TRACEEXP2,
	S_TRACEEXP3,
	S_SKEL_STND,
	S_SKEL_STND2,
	S_SKEL_RUN1,
	S_SKEL_RUN2,
	S_SKEL_RUN3,
	S_SKEL_RUN4,
	S_SKEL_RUN5,
	S_SKEL_RUN6,
	S_SKEL_RUN7,
	S_SKEL_RUN8,
	S_SKEL_RUN9,
	S_SKEL_RUN10,
	S_SKEL_RUN11,
	S_SKEL_RUN12,
	S_SKEL_FIST1,
	S_SKEL_FIST2,
	S_SKEL_FIST3,
	S_SKEL_FIST4,
	S_SKEL_MISS1,
	S_SKEL_MISS2,
	S_SKEL_MISS3,
	S_SKEL_MISS4,
	S_SKEL_PAIN,
	S_SKEL_PAIN2,
	S_SKEL_DIE1,
	S_SKEL_DIE2,
	S_SKEL_DIE3,
	S_SKEL_DIE4,
	S_SKEL_DIE5,
	S_SKEL_DIE6,
	S_SKEL_RAISE1,
	S_SKEL_RAISE2,
	S_SKEL_RAISE3,
	S_SKEL_RAISE4,
	S_SKEL_RAISE5,
	S_SKEL_RAISE6,
	S_FATSHOT1,
	S_FATSHOT2,
	S_FATSHOTX1,
	S_FATSHOTX2,
	S_FATSHOTX3,
	S_FATT_STND,
	S_FATT_STND2,
	S_FATT_RUN1,
	S_FATT_RUN2,
	S_FATT_RUN3,
	S_FATT_RUN4,
	S_FATT_RUN5,
	S_FATT_RUN6,
	S_FATT_RUN7,
	S_FATT_RUN8,
	S_FATT_RUN9,
	S_FATT_RUN10,
	S_FATT_RUN11,
	S_FATT_RUN12,
	S_FATT_ATK1,
	S_FATT_ATK2,
	S_FATT_ATK3,
	S_FATT_ATK4,
	S_FATT_ATK5,
	S_FATT_ATK6,
	S_FATT_ATK7,
	S_FATT_ATK8,
	S_FATT_ATK9,
	S_FATT_ATK10,
	S_FATT_PAIN,
	S_FATT_PAIN2,
	S_FATT_DIE1,
	S_FATT_DIE2,
	S_FATT_DIE3,
	S_FATT_DIE4,
	S_FATT_DIE5,
	S_FATT_DIE6,
	S_FATT_DIE7,
	S_FATT_DIE8,
	S_FATT_DIE9,
	S_FATT_DIE10,
	S_FATT_RAISE1,
	S_FATT_RAISE2,
	S_FATT_RAISE3,
	S_FATT_RAISE4,
	S_FATT_RAISE5,
	S_FATT_RAISE6,
	S_FATT_RAISE7,
	S_FATT_RAISE8,
	S_CPOS_STND,
	S_CPOS_STND2,
	S_CPOS_RUN1,
	S_CPOS_RUN2,
	S_CPOS_RUN3,
	S_CPOS_RUN4,
	S_CPOS_RUN5,
	S_CPOS_RUN6,
	S_CPOS_RUN7,
	S_CPOS_RUN8,
	S_CPOS_ATK1,
	S_CPOS_ATK2,
	S_CPOS_ATK3,
	S_CPOS_ATK4,
	S_CPOS_PAIN,
	S_CPOS_PAIN2,
	S_CPOS_DIE1,
	S_CPOS_DIE2,
	S_CPOS_DIE3,
	S_CPOS_DIE4,
	S_CPOS_DIE5,
	S_CPOS_DIE6,
	S_CPOS_DIE7,
	S_CPOS_XDIE1,
	S_CPOS_XDIE2,
	S_CPOS_XDIE3,
	S_CPOS_XDIE4,
	S_CPOS_XDIE5,
	S_CPOS_XDIE6,
	S_CPOS_RAISE1,
	S_CPOS_RAISE2,
	S_CPOS_RAISE3,
	S_CPOS_RAISE4,
	S_CPOS_RAISE5,
	S_CPOS_RAISE6,
	S_CPOS_RAISE7,
	S_TROO_STND,
	S_TROO_STND2,
	S_TROO_RUN1,
	S_TROO_RUN2,
	S_TROO_RUN3,
	S_TROO_RUN4,
	S_TROO_RUN5,
	S_TROO_RUN6,
	S_TROO_RUN7,
	S_TROO_RUN8,
	S_TROO_ATK1,
	S_TROO_ATK2,
	S_TROO_ATK3,
	S_TROO_PAIN,
	S_TROO_PAIN2,
	S_TROO_DIE1,
	S_TROO_DIE2,
	S_TROO_DIE3,
	S_TROO_DIE4,
	S_TROO_DIE5,
	S_TROO_XDIE1,
	S_TROO_XDIE2,
	S_TROO_XDIE3,
	S_TROO_XDIE4,
	S_TROO_XDIE5,
	S_TROO_XDIE6,
	S_TROO_XDIE7,
	S_TROO_XDIE8,
	S_TROO_RAISE1,
	S_TROO_RAISE2,
	S_TROO_RAISE3,
	S_TROO_RAISE4,
	S_TROO_RAISE5,
	S_SARG_STND,
	S_SARG_STND2,
	S_SARG_RUN1,
	S_SARG_RUN2,
	S_SARG_RUN3,
	S_SARG_RUN4,
	S_SARG_RUN5,
	S_SARG_RUN6,
	S_SARG_RUN7,
	S_SARG_RUN8,
	S_SARG_ATK1,
	S_SARG_ATK2,
	S_SARG_ATK3,
	S_SARG_PAIN,
	S_SARG_PAIN2,
	S_SARG_DIE1,
	S_SARG_DIE2,
	S_SARG_DIE3,
	S_SARG_DIE4,
	S_SARG_DIE5,
	S_SARG_DIE6,
	S_SARG_RAISE1,
	S_SARG_RAISE2,
	S_SARG_RAISE3,
	S_SARG_RAISE4,
	S_SARG_RAISE5,
	S_SARG_RAISE6,
	S_HEAD_STND,
	S_HEAD_RUN1,
	S_HEAD_ATK1,
	S_HEAD_ATK2,
	S_HEAD_ATK3,
	S_HEAD_PAIN,
	S_HEAD_PAIN2,
	S_HEAD_PAIN3,
	S_HEAD_DIE1,
	S_HEAD_DIE2,
	S_HEAD_DIE3,
	S_HEAD_DIE4,
	S_HEAD_DIE5,
	S_HEAD_DIE6,
	S_HEAD_RAISE1,
	S_HEAD_RAISE2,
	S_HEAD_RAISE3,
	S_HEAD_RAISE4,
	S_HEAD_RAISE5,
	S_HEAD_RAISE6,
	S_BRBALL1,
	S_BRBALL2,
	S_BRBALLX1,
	S_BRBALLX2,
	S_BRBALLX3,
	S_BOSS_STND,
	S_BOSS_STND2,
	S_BOSS_RUN1,
	S_BOSS_RUN2,
	S_BOSS_RUN3,
	S_BOSS_RUN4,
	S_BOSS_RUN5,
	S_BOSS_RUN6,
	S_BOSS_RUN7,
	S_BOSS_RUN8,
	S_BOSS_ATK1,
	S_BOSS_ATK2,
	S_BOSS_ATK3,
	S_BOSS_PAIN,
	S_BOSS_PAIN2,
	S_BOSS_DIE1,
	S_BOSS_DIE2,
	S_BOSS_DIE3,
	S_BOSS_DIE4,
	S_BOSS_DIE5,
	S_BOSS_DIE6,
	S_BOSS_DIE7,
	S_BOSS_RAISE1,
	S_BOSS_RAISE2,
	S_BOSS_RAISE3,
	S_BOSS_RAISE4,
	S_BOSS_RAISE5,
	S_BOSS_RAISE6,
	S_BOSS_RAISE7,
	S_BOS2_STND,
	S_BOS2_STND2,
	S_BOS2_RUN1,
	S_BOS2_RUN2,
	S_BOS2_RUN3,
	S_BOS2_RUN4,
	S_BOS2_RUN5,
	S_BOS2_RUN6,
	S_BOS2_RUN7,
	S_BOS2_RUN8,
	S_BOS2_ATK1,
	S_BOS2_ATK2,
	S_BOS2_ATK3,
	S_BOS2_PAIN,
	S_BOS2_PAIN2,
	S_BOS2_DIE1,
	S_BOS2_DIE2,
	S_BOS2_DIE3,
	S_BOS2_DIE4,
	S_BOS2_DIE5,
	S_BOS2_DIE6,
	S_BOS2_DIE7,
	S_BOS2_RAISE1,
	S_BOS2_RAISE2,
	S_BOS2_RAISE3,
	S_BOS2_RAISE4,
	S_BOS2_RAISE5,
	S_BOS2_RAISE6,
	S_BOS2_RAISE7,
	S_SKULL_STND,
	S_SKULL_STND2,
	S_SKULL_RUN1,
	S_SKULL_RUN2,
	S_SKULL_ATK1,
	S_SKULL_ATK2,
	S_SKULL_ATK3,
	S_SKULL_ATK4,
	S_SKULL_PAIN,
	S_SKULL_PAIN2,
	S_SKULL_DIE1,
	S_SKULL_DIE2,
	S_SKULL_DIE3,
	S_SKULL_DIE4,
	S_SKULL_DIE5,
	S_SKULL_DIE6,
	S_SPID_STND,
	S_SPID_STND2,
	S_SPID_RUN1,
	S_SPID_RUN2,
	S_SPID_RUN3,
	S_SPID_RUN4,
	S_SPID_RUN5,
	S_SPID_RUN6,
	S_SPID_RUN7,
	S_SPID_RUN8,
	S_SPID_RUN9,
	S_SPID_RUN10,
	S_SPID_RUN11,
	S_SPID_RUN12,
	S_SPID_ATK1,
	S_SPID_ATK2,
	S_SPID_ATK3,
	S_SPID_ATK4,
	S_SPID_PAIN,
	S_SPID_PAIN2,
	S_SPID_DIE1,
	S_SPID_DIE2,
	S_SPID_DIE3,
	S_SPID_DIE4,
	S_SPID_DIE5,
	S_SPID_DIE6,
	S_SPID_DIE7,
	S_SPID_DIE8,
	S_SPID_DIE9,
	S_SPID_DIE10,
	S_SPID_DIE11,
	S_BSPI_STND,
	S_BSPI_STND2,
	S_BSPI_SIGHT,
	S_BSPI_RUN1,
	S_BSPI_RUN2,
	S_BSPI_RUN3,
	S_BSPI_RUN4,
	S_BSPI_RUN5,
	S_BSPI_RUN6,
	S_BSPI_RUN7,
	S_BSPI_RUN8,
	S_BSPI_RUN9,
	S_BSPI_RUN10,
	S_BSPI_RUN11,
	S_BSPI_RUN12,
	S_BSPI_ATK1,
	S_BSPI_ATK2,
	S_BSPI_ATK3,
	S_BSPI_ATK4,
	S_BSPI_PAIN,
	S_BSPI_PAIN2,
	S_BSPI_DIE1,
	S_BSPI_DIE2,
	S_BSPI_DIE3,
	S_BSPI_DIE4,
	S_BSPI_DIE5,
	S_BSPI_DIE6,
	S_BSPI_DIE7,
	S_BSPI_RAISE1,
	S_BSPI_RAISE2,
	S_BSPI_RAISE3,
	S_BSPI_RAISE4,
	S_BSPI_RAISE5,
	S_BSPI_RAISE6,
	S_BSPI_RAISE7,
	S_ARACH_PLAZ,
	S_ARACH_PLAZ2,
	S_ARACH_PLEX,
	S_ARACH_PLEX2,
	S_ARACH_PLEX3,
	S_ARACH_PLEX4,
	S_ARACH_PLEX5,
	S_CYBER_STND,
	S_CYBER_STND2,
	S_CYBER_RUN1,
	S_CYBER_RUN2,
	S_CYBER_RUN3,
	S_CYBER_RUN4,
	S_CYBER_RUN5,
	S_CYBER_RUN6,
	S_CYBER_RUN7,
	S_CYBER_RUN8,
	S_CYBER_ATK1,
	S_CYBER_ATK2,
	S_CYBER_ATK3,
	S_CYBER_ATK4,
	S_CYBER_ATK5,
	S_CYBER_ATK6,
	S_CYBER_PAIN,
	S_CYBER_DIE1,
	S_CYBER_DIE2,
	S_CYBER_DIE3,
	S_CYBER_DIE4,
	S_CYBER_DIE5,
	S_CYBER_DIE6,
	S_CYBER_DIE7,
	S_CYBER_DIE8,
	S_CYBER_DIE9,
	S_CYBER_DIE10,
	S_PAIN_STND,
	S_PAIN_RUN1,
	S_PAIN_RUN2,
	S_PAIN_RUN3,
	S_PAIN_RUN4,
	S_PAIN_RUN5,
	S_PAIN_RUN6,
	S_PAIN_ATK1,
	S_PAIN_ATK2,
	S_PAIN_ATK3,
	S_PAIN_ATK4,
	S_PAIN_PAIN,
	S_PAIN_PAIN2,
	S_PAIN_DIE1,
	S_PAIN_DIE2,
	S_PAIN_DIE3,
	S_PAIN_DIE4,
	S_PAIN_DIE5,
	S_PAIN_DIE6,
	S_PAIN_RAISE1,
	S_PAIN_RAISE2,
	S_PAIN_RAISE3,
	S_PAIN_RAISE4,
	S_PAIN_RAISE5,
	S_PAIN_RAISE6,
	S_SSWV_STND,
	S_SSWV_STND2,
	S_SSWV_RUN1,
	S_SSWV_RUN2,
	S_SSWV_RUN3,
	S_SSWV_RUN4,
	S_SSWV_RUN5,
	S_SSWV_RUN6,
	S_SSWV_RUN7,
	S_SSWV_RUN8,
	S_SSWV_ATK1,
	S_SSWV_ATK2,
	S_SSWV_ATK3,
	S_SSWV_ATK4,
	S_SSWV_ATK5,
	S_SSWV_ATK6,
	S_SSWV_PAIN,
	S_SSWV_PAIN2,
	S_SSWV_DIE1,
	S_SSWV_DIE2,
	S_SSWV_DIE3,
	S_SSWV_DIE4,
	S_SSWV_DIE5,
	S_SSWV_XDIE1,
	S_SSWV_XDIE2,
	S_SSWV_XDIE3,
	S_SSWV_XDIE4,
	S_SSWV_XDIE5,
	S_SSWV_XDIE6,
	S_SSWV_XDIE7,
	S_SSWV_XDIE8,
	S_SSWV_XDIE9,
	S_SSWV_RAISE1,
	S_SSWV_RAISE2,
	S_SSWV_RAISE3,
	S_SSWV_RAISE4,
	S_SSWV_RAISE5,
	S_KEENSTND,
	S_COMMKEEN,
	S_COMMKEEN2,
	S_COMMKEEN3,
	S_COMMKEEN4,
	S_COMMKEEN5,
	S_COMMKEEN6,
	S_COMMKEEN7,
	S_COMMKEEN8,
	S_COMMKEEN9,
	S_COMMKEEN10,
	S_COMMKEEN11,
	S_COMMKEEN12,
	S_KEENPAIN,
	S_KEENPAIN2,
	S_BRAIN,
	S_BRAIN_PAIN,
	S_BRAIN_DIE1,
	S_BRAIN_DIE2,
	S_BRAIN_DIE3,
	S_BRAIN_DIE4,
	S_BRAINEYE,
	S_BRAINEYESEE,
	S_BRAINEYE1,
	S_SPAWN1,
	S_SPAWN2,
	S_SPAWN3,
	S_SPAWN4,
	S_SPAWNFIRE1,
	S_SPAWNFIRE2,
	S_SPAWNFIRE3,
	S_SPAWNFIRE4,
	S_SPAWNFIRE5,
	S_SPAWNFIRE6,
	S_SPAWNFIRE7,
	S_SPAWNFIRE8,
	S_BRAINEXPLODE1,
	S_BRAINEXPLODE2,
	S_BRAINEXPLODE3,
	S_ARM1,
	S_ARM1A,
	S_ARM2,
	S_ARM2A,
	S_BAR1,
	S_BAR2,
	S_BEXP,
	S_BEXP2,
	S_BEXP3,
	S_BEXP4,
	S_BEXP5,
	S_BBAR1,
	S_BBAR2,
	S_BBAR3,
	S_BON1,
	S_BON1A,
	S_BON1B,
	S_BON1C,
	S_BON1D,
	S_BON1E,
	S_BON2,
	S_BON2A,
	S_BON2B,
	S_BON2C,
	S_BON2D,
	S_BON2E,
	S_BKEY,
	S_BKEY2,
	S_RKEY,
	S_RKEY2,
	S_YKEY,
	S_YKEY2,
	S_BSKULL,
	S_BSKULL2,
	S_RSKULL,
	S_RSKULL2,
	S_YSKULL,
	S_YSKULL2,
	S_STIM,
	S_MEDI,
	S_SOUL,
	S_SOUL2,
	S_SOUL3,
	S_SOUL4,
	S_SOUL5,
	S_SOUL6,
	S_PINV,
	S_PINV2,
	S_PINV3,
	S_PINV4,
	S_PSTR,
	S_PINS,
	S_PINS2,
	S_PINS3,
	S_PINS4,
	S_MEGA,
	S_MEGA2,
	S_MEGA3,
	S_MEGA4,
	S_SUIT,
	S_PMAP,
	S_PMAP2,
	S_PMAP3,
	S_PMAP4,
	S_PMAP5,
	S_PMAP6,
	S_PVIS,
	S_PVIS2,
	S_CLIP,
	S_AMMO,
	S_ROCK,
	S_BROK,
	S_CELL,
	S_CELP,
	S_SHEL,
	S_SBOX,
	S_BPAK,
	S_BFUG,
	S_MGUN,
	S_CSAW,
	S_LAUN,
	S_PLAS,
	S_SHOT,
	S_SHOT2,
	S_COLU,
	S_BLOODYTWITCH,
	S_BLOODYTWITCH2,
	S_BLOODYTWITCH3,
	S_BLOODYTWITCH4,
	S_DEADTORSO,
	S_DEADBOTTOM,
	S_HEADSONSTICK,
	S_GIBS,
	S_HEADONASTICK,
	S_HEADCANDLES,
	S_HEADCANDLES2,
	S_DEADSTICK,
	S_LIVESTICK,
	S_LIVESTICK2,
	S_MEAT2,
	S_MEAT3,
	S_MEAT4,
	S_MEAT5,
	S_STALAGTITE,
	S_TALLGRNCOL,
	S_SHRTGRNCOL,
	S_TALLREDCOL,
	S_SHRTREDCOL,
	S_CANDLESTIK,
	S_CANDELABRA,
	S_SKULLCOL,
	S_TORCHTREE,
	S_BIGTREE,
	S_TECHPILLAR,
	S_EVILEYE,
	S_EVILEYE2,
	S_EVILEYE3,
	S_EVILEYE4,
	S_FLOATSKULL,
	S_FLOATSKULL2,
	S_FLOATSKULL3,
	S_HEARTCOL,
	S_HEARTCOL2,
	S_BLUETORCH,
	S_BLUETORCH2,
	S_BLUETORCH3,
	S_BLUETORCH4,
	S_GREENTORCH,
	S_GREENTORCH2,
	S_GREENTORCH3,
	S_GREENTORCH4,
	S_REDTORCH,
	S_REDTORCH2,
	S_REDTORCH3,
	S_REDTORCH4,
	S_BTORCHSHRT,
	S_BTORCHSHRT2,
	S_BTORCHSHRT3,
	S_BTORCHSHRT4,
	S_GTORCHSHRT,
	S_GTORCHSHRT2,
	S_GTORCHSHRT3,
	S_GTORCHSHRT4,
	S_RTORCHSHRT,
	S_RTORCHSHRT2,
	S_RTORCHSHRT3,
	S_RTORCHSHRT4,
	S_HANGNOGUTS,
	S_HANGBNOBRAIN,
	S_HANGTLOOKDN,
	S_HANGTSKULL,
	S_HANGTLOOKUP,
	S_HANGTNOBRAIN,
	S_COLONGIBS,
	S_SMALLPOOL,
	S_BRAINSTEM,
	S_TECHLAMP,
	S_TECHLAMP2,
	S_TECHLAMP3,
	S_TECHLAMP4,
	S_TECH2LAMP,
	S_TECH2LAMP2,
	S_TECH2LAMP3,
	S_TECH2LAMP4,
	S_TNT1,
	S_GIB0,
	S_GIB1,
	S_GIB2,
	S_GIB3,
	S_GIB4,
	S_GIB5,
	S_GIB6,
	S_GIB7,
	S_AMBIENTSOUND,
	S_UNKNOWNTHING,
	S_BRIDGE1,
	S_BRIDGE2,
	S_BRIDGE3,
	S_BRIDGE4,
	S_BRIDGE5,
	S_SMT2,
	S_TURB,
	S_TURB2,
	S_TURB3,
	S_TURB4,
	S_ARM3,
	S_ARM3A,
	S_COL7,
	S_COL8,
	S_COL9,
	S_COL9A,
	S_ANTI,
	S_ANTI2,
	S_ANTI3,
	S_ANTI4,
	S_LSKU,
	S_LSKU2,
	S_SSKU,
	S_SSKU2,
	S_GSKU,
	S_GSKU2,
	S_LKEY,
	S_LKEY2,
	S_SKEY,
	S_SKEY2,
	S_GKEY,
	S_GKEY2,
	S_GLAU,
	S_RAIL,
	S_GLAUNCHER,
	S_GLAUNCHERDOWN,
	S_GLAUNCHERUP,
	S_GLAUNCHER1,
	S_GLAUNCHER2,
	S_GLAUNCHER3,
	S_GLAUNCHERFLASH1,
	S_GLAUNCHERFLASH2,
	S_GLAUNCHERFLASH3,
	S_GLAUNCHERFLASH4,
	S_GRENADE,
	S_FREEZE,
	S_FREEZE2,
	S_FREEZE3,
	S_FREEZE4,
	S_RAILGUN,
	S_RAILGUNDOWN,
	S_RAILGUNUP,
	S_RAILGUN1,
	S_RAILGUN2,
	S_RAILGUN3,
	S_RAILGUNFLASH,
	S_BARONSTATUE,
	S_DEATHSTICK,
	S_CHAINSTICK,
	S_TROOPSTICK,
	S_GRABBER,
	S_GRABBER2,
	S_GRABBER3,
	S_GRABBER4,
	S_HOVER,
	S_HOVER2,
	S_HOVER3,
	S_HOVER4,
	S_IMPHEAD,
	S_MCARD,
	S_MCARD2,
	S_MSKU,
	S_MSKU2,
	S_INFRA,
	S_INFRA2,
	S_RUN1,
	S_RUN1A,
	S_RUN2,
	S_RUN2A,
	S_RUN3,
	S_RUN3A,
	S_RUN4,
	S_RUN4A,
	S_RUN5,
	S_RUN5A,
	S_RUN6,
	S_RUN6A,
	S_RUN6B,
	S_RUN6C,
	S_RUN6D,
	S_RUN7,
	S_RUN7A,
	S_RUN7B,
	S_RUN7C,
	S_RUN8,
	S_RUN8A,
	S_RUN9,
	S_RUN9A,
	S_RUNA,
	S_RUNA2,
	S_RUNB,
	S_RUNB2,
	S_RUNC,
	S_RUNC2,
	S_BON3,
	S_BON3A,
	S_BON3B,
	S_BON3C,
	S_BON3D,
	S_BON3E,
	S_BON4,
	S_BON4A,
	S_BON4B,
	S_BON4C,
	S_BON4D,
	S_BON4E,
	S_RFOG,
	S_RFOG01,
	S_RFOG02,
	S_RFOG2,
	S_RFOG3,
	S_RFOG4,
	S_RFOG5,
	S_BHOVER,
	S_BHOVER2,
	S_BHOVER3,
	S_BHOVER4,
	S_GHOVER,
	S_GHOVER2,
	S_GHOVER3,
	S_GHOVER4,
	S_PIST,
	S_TRAK,
	S_TRAK2,
	S_TRAK3,
	S_TRAK4,
	S_TRAK5,
	S_TRAK6,
	S_INVS,
	S_INVS2,
	S_INVS3,
	S_INVS4
};

const int NumSwitchableSprites = sizeof(SwitchableSprites);

FUNC(LS_Thing_SetSprite)
// Thing_SetSprite (tid, sprite)
{
	int spr;
	AActor *thing = AActor::FindByTID (NULL, arg0);

	if (arg1 >= NumSwitchableSprites)
		return false;

	if ((spr = SwitchableSprites[arg1]) == 0)
		return false;

	while (thing)
	{
		P_SetMobjState (thing, (statenum_t)spr);
		thing = thing->FindByTID(arg0);
	}
	return true;
}

FUNC(LS_Music_Pause)
// Music_Pause (BOOL)
{
	if (arg0)
		S_PauseSound();
	else
		S_ResumeSound();
	return true;
}

FUNC(LS_Music_Change)
// Music_Change (lump)
{
	return true;
}


FUNC(LS_ThrustThingZ)
// ThrustThingZ (tid, zthrust, down/up, set)
{
	AActor *thing = AActor::FindByTID(NULL, arg0);

	fixed_t thrust = arg1*FRACUNIT/4;

	// [BC] Up is default
	if (arg2)
		thrust = -thrust;

	if (arg0)
	{
		while (thing)
		{
			if (!arg3)
				thing->momz = thrust;
			else
				thing->momz += thrust;

			thing = thing->FindByTID(arg0);
		}
		return true;
	}
	else if (it)
	{
		if (!arg3)
			it->momz = thrust;
		else
			it->momz += thrust;
		return true;
	}
	return false;
}

FUNC(LS_Thing_SetSpecial)
// Thing_SetSpecial (tid, special, arg1, arg2, arg3, arg4)
{
	AActor *thing = AActor::FindByTID (NULL, arg0);

	while (thing)
	{
		thing->special = arg1;
		thing->args[0] = arg2;
		thing->args[1] = arg3;
		thing->args[2] = arg4;
		thing = thing->FindByTID(arg0);
	}
	return true;
}

FUNC(LS_Player_SetTeam)
// Player_SetTeam (team1/team2)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!it || !it->player)
		return false;

	if (arg0)
	{
		if (arg0 == TEAM_BLUE)
			it->player->team = TM_BLUE;
		else if (arg0 == TEAM_RED)
			it->player->team = TM_RED;
		else
			it->player->team = TM_NONE;
	}
	else
		it->player->team = TM_NONE;

	if (netstate == NS_SERVER)
	{
		for (int i=0; i<MAXPLAYERS; i++)
		{
			client_t *cl = &clients[i];

			if (cl->cls < cs_spawned)
				continue;

			MSG_WriteByte(&cl->reliablebuf, svc_playerteam);
			MSG_WriteByte(&cl->reliablebuf, it->player - players);
			MSG_WriteByte(&cl->reliablebuf, (byte)it->player->team);
		}

		if (it->player->team == TM_BLUE)
			SV_BroadcastPrintf (PRINT_HIGH, TEXTCOLOR_NORMAL "%s joined the " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " team\n", it->player->userinfo.netname, teams[TM_BLUE].name);
		else
			SV_BroadcastPrintf (PRINT_HIGH, TEXTCOLOR_NORMAL "%s joined the " TEXTCOLOR_RED "%s" TEXTCOLOR_NORMAL " team\n", it->player->userinfo.netname, teams[TM_RED].name);

	}

	P_BuildColor (it->player - players);
	return true;
}

FUNC(LS_Team_GiveFP)
// Team_GiveFP (int howmuch)
{
	if (netstate == NS_CLIENT)
		return false;

	if (it && it->player && it->player->team != TM_NONE)
	{
		teams[it->player->team].fragpoints += arg0;
		return true;
	}
	return false;
}

FUNC(LS_Team_UseFP)
// Team_UseFP (int howmuch)
{
	if (netstate == NS_CLIENT)
		return false;

	if (it && it->player && it->player->team != TM_NONE)
	{
		teams[it->player->team].fragpoints -= arg0;
		return true;
	}
	return false;
}


FUNC(LS_Team_Score)
// Team_Score (int howmuch, bool nogrin)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!it || !it->player || it->player->team == TM_NONE)
		return false;

	if (teamgame.value)
	{
		if (!(arg0))
			I_Error ("Team_Score: No value specified");
		else
		{
			teams[it->player->team].points += arg0;

			// Update scores
			if (netstate == NS_SERVER)
			{
				for (int i=0; i<MAXPLAYERS; i++)
				{
					client_t *cl = &clients[i];

					if (cl->cls < cs_spawned)
						continue;

					MSG_WriteByte(&cl->reliablebuf, svc_updatescores);
					MSG_WriteByte(&cl->reliablebuf, it->player->team);
					MSG_WriteShort(&cl->reliablebuf, teams[it->player->team].points);
				}
			}

			if (!arg1)
				it->player->scored = true;
			it->player->pointcount += arg0;

			// Update scores
			if (netstate == NS_SERVER)
			{
				for (int i=0; i<MAXPLAYERS; i++)
				{
					client_t *cl = &clients[i];

					if (cl->cls < cs_spawned)
						continue;

					MSG_WriteByte(&cl->reliablebuf, svc_updateplayerscores);
					MSG_WriteByte(&cl->reliablebuf, it->player - players);
					MSG_WriteByte(&cl->reliablebuf, it->player->pointcount);
				}
			}

			if (it->player->skullb)
				it->player->skullb->state = BST_NOTHING;

			if (!(pointlimit.value) || netstate == NS_CLIENT)
				return true;
			else
			{
				if (!(level.flags & LEVEL_DONTENDONPOINTLIMIT))
				{
					if (teams[it->player->team].points >= pointlimit.value)
					{
						if (netstate == NS_SERVER)
							SV_BroadcastPrintf (PRINT_HIGH, "%s has won the game!\n", teams[it->player->team].name);
						else
							Printf (PRINT_HIGH, "%s has won the game!\n", teams[it->player->team].name);
						levelTics = 1*TICRATE;
					}
				}
			}
		}
	}
	return false;
}

FUNC(LS_Thing_SetGravity)
// Thing_SetGravity (intpart, fracpart, tid)
{
	if (arg1 > 99)
		arg1 = 99;

	if (arg2)
	{
		AActor *thing = AActor::FindByTID(NULL, arg2);
		while (thing)
		{
			thing->flags2 |= MF2_ALTGRAV;
			thing->gravity = (float)arg0 + (float)arg1 * 0.01f;
			thing = thing->FindByTID(arg2);
		}
		return true;
	}
	else
	{
		if (!it)
			return false;
		it->flags2 |= MF2_ALTGRAV;
		it->gravity = (float)arg0 + (float)arg1 * 0.01f;
		return true;
	}
}

FUNC(LS_Thing_ReverseGravity)
// Thing_ReverseGravity (on/off, tid)
{
	if (arg1)
	{
		AActor *thing = AActor::FindByTID(NULL, arg1);
		while (thing)
		{
			if (arg0)
				thing->flags2 |= MF2_REVERSEGRAV;
			else
				thing->flags2 &= ~MF2_REVERSEGRAV;
			thing = thing->FindByTID(arg1);
		}
		return true;
	}
	else
	{
		if (!it)
			return false;
		if (arg0)
			it->flags2 |= MF2_REVERSEGRAV;
		else
			it->flags2 &= ~MF2_REVERSEGRAV;
		return true;
	}
}

FUNC(LS_Thing_RevertGravity)
// Thing_RevertGravity (tid)
{
	if (arg0)
	{
		AActor *thing = AActor::FindByTID(NULL, arg0);
		while (thing)
		{
			thing->flags2 &= ~MF2_ALTGRAV;
			thing = thing->FindByTID(arg0);
		}
		return true;
	}
	else
	{
		if (it)
		{
			it->flags2 &= ~MF2_ALTGRAV;
			return true;
		}
		else
			return false;
	}
}

FUNC(LS_Team_Init)
// Team_Init (team1/team2)
{
	if (netstate == NS_CLIENT)
		return false;

	if (teamgame.value)
	{
		for (int i=0; i<NUMTEAMS; i++)
		{
			if (arg0)
				teams[i].points = arg0;
			else
				teams[i].points = 0;
		}
		return true;
	}
	return false;
}

FUNC(LS_Team_InitFP)
// Team_InitFP (true/false)
{
	if (netstate == NS_CLIENT)
		return false;

	if (arg0)
	{
		for (int i=0; i<NUMTEAMS; i++)
			teams[i].fragpoints = 0;
	}
	return false;
}

FUNC(LS_Player_SetLeader)
// Player_SetLeader (true/false)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!it || !it->player || it->player->team == TM_NONE)
		return false;

	if (arg0)
		teams[it->player->team].leader = it->player;
	else
		teams[it->player->team].leader = NULL;
	
	return true;
}

FUNC(LS_Thing_Move)
// Thing_Move (tid, mapspot)
{
	return P_Thing_Move (arg0, arg1);
}

FUNC(LS_Var_Lock)
// Var_Lock (on/off)
{
	if (arg0)
		lockspvars = true;
	else
		lockspvars = false;
	return true;
}

FUNC(LS_Team_RemoveItem)
// Team_RemoveItem (which, red/blue)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!arg0 || !arg1)
		return false;

	for (int i=0; i<MAXPLAYERS; i++)
	{
		if (!playeringame[i] || !players[i].team)
			continue;

		if ((arg1 == TEAM_BLUE && players[i].team != TM_BLUE) ||
			(arg1 == TEAM_RED && players[i].team != TM_RED))
			continue;

		if (arg0 >= NumSpawnableThings)
			return false;

		switch (SpawnableThings[arg0]) 
		{
		case MT_BSKU:
			players[i].cards[it_blueskull] = false;
			break;
		case MT_YSKU:
			players[i].cards[it_yellowskull] = false;
			break;
		case MT_RSKU:
			players[i].cards[it_redskull] = false;
			break;
		case MT_YKEY:
			players[i].cards[it_yellowcard] = false;
			break;
		case MT_BKEY:
			players[i].cards[it_bluecard] = false;
			break;
		case MT_RKEY:
			players[i].cards[it_redcard] = false;
			break;
		case MT_LSKU:
			players[i].cards[it_blackskull] = false;
			break;
		case MT_SSKU:
			players[i].cards[it_silverskull] = false;
			break;
		case MT_GSKU:
			players[i].cards[it_goldskull] = false;
			break;
		case MT_LKEY:
			players[i].cards[it_blackcard] = false;
			break;
		case MT_SKEY:
			players[i].cards[it_silvercard] = false;
			break;
		case MT_GKEY:
			players[i].cards[it_goldcard] = false;
			break;
		case MT_BACKPACK:
			players[i].backpack = false;
			break;
		case MT_PISTOL:
			players[i].weaponowned[wp_pistol] = false;
			break;		
		case MT_CHAINSAW:
			players[i].weaponowned[wp_chainsaw] = false;
			break;
		case MT_SHOTGUN:
			players[i].weaponowned[wp_shotgun] = false;
			break;
		case MT_SUPERSHOTGUN:
			players[i].weaponowned[wp_supershotgun] = false;
			break;
		case MT_CHAINGUN:
			players[i].weaponowned[wp_chaingun] = false;
			break;
		case MT_ROCKETLAUNCHER:
			players[i].weaponowned[wp_missile] = false;
			break;
		case MT_GRENADELAUNCHER:
			players[i].weaponowned[wp_grenlauncher] = false;
			break;
		case MT_PLASMAGUN:
			players[i].weaponowned[wp_plasma] = false;
			break;
		case MT_RAILGUN:
			players[i].weaponowned[wp_railgun] = false;
			break;
		case MT_BFG9000:
			players[i].weaponowned[wp_bfg] = false;
			break;
		case MT_INV:
			players[i].powers[pw_invulnerability] = false;
			break;
		case MT_INS:
			players[i].powers[pw_invisibility] = false;
			break;
		case MT_TURBOSPHERE:
			players[i].powers[pw_turbosphere] = false;
			break;
		case MT_LIGHTAMP:
			players[i].powers[pw_infrared] = false;
			break;
		case MT_RADSUIT:
			players[i].powers[pw_ironfeet] = false;
			break;
		case MT_COMPMAP:
			players[i].powers[pw_allmap] = false;
			break;
		case MT_BERSERK:
			players[i].powers[pw_strength] = false;
			break;
		case MT_FLOATINGFEET:
			players[i].powers[pw_floatingfeet] = false;
			break;
		case MT_ARMOR:
			if (players[i].armortype = 1)
			{
				players[i].armortype = 0;
				players[i].armorpoints = 0;
			}
			break;
		case MT_MEGAARMOR:
			if (players[i].armortype = 2)
			{
				players[i].armortype = 0;
				players[i].armorpoints = 0;
			}
			break;
		case MT_REDARMOR:
			if (players[i].armortype = 3)
			{
				players[i].armortype = 0;
				players[i].armorpoints = 0;
			}
			break;
		default:
			I_Error("Team_RemoveItem: Unknown item %d.", arg0);
		}
	}
	ST_Start ();
	return true;
}

FUNC(LS_Team_GiveItem)
// Team_GiveItem (which, red/blue)
{
	if (netstate == NS_CLIENT)
		return false;

	if (!arg0 || !arg1)
		return false;

	for (int i=0; i<MAXPLAYERS; i++)
	{
		if (!playeringame[i] || !players[i].team)
			continue;

		if ((arg1 == TEAM_BLUE && players[i].team != TM_BLUE) ||
			(arg1 == TEAM_RED && players[i].team != TM_RED))
			continue;

		if (arg0 >= NumSpawnableThings)
			return false;

		switch (SpawnableThings[arg0]) 
		{
		case MT_BSKU:
			players[i].cards[it_blueskull] = true;
			break;
		case MT_YSKU:
			players[i].cards[it_yellowskull] = true;
			break;
		case MT_RSKU:
			players[i].cards[it_redskull] = true;
			break;
		case MT_BKEY:
			players[i].cards[it_bluecard] = true;
			break;
		case MT_YKEY:
			players[i].cards[it_yellowcard] = true;
			break;
		case MT_RKEY:
			players[i].cards[it_redcard] = true;
			break;
		case MT_LSKU:
			players[i].cards[it_blackskull] = true;
			break;
		case MT_SSKU:
			players[i].cards[it_silverskull] = true;
			break;
		case MT_GSKU:
			players[i].cards[it_goldskull] = true;
			break;
		case MT_LKEY:
			players[i].cards[it_blackcard] = true;
			break;
		case MT_SKEY:
			players[i].cards[it_silvercard] = true;
			break;
		case MT_GKEY:
			players[i].cards[it_goldcard] = true;
			break;
		case MT_BACKPACK:
			players[i].backpack = true;
			break;
		case MT_PISTOL:
			players[i].weaponowned[wp_pistol] = true;
			break;
		case MT_CHAINSAW:
			players[i].weaponowned[wp_chainsaw] = true;
			break;
		case MT_SHOTGUN:
			players[i].weaponowned[wp_shotgun] = true;
			break;
		case MT_SUPERSHOTGUN:
			players[i].weaponowned[wp_supershotgun] = true;
			break;
		case MT_CHAINGUN:
			players[i].weaponowned[wp_chaingun] = true;
			break;
		case MT_ROCKETLAUNCHER:
			players[i].weaponowned[wp_missile] = true;
			break;
		case MT_GRENADELAUNCHER:
			players[i].weaponowned[wp_grenlauncher] = true;
			break;
		case MT_PLASMAGUN:
			players[i].weaponowned[wp_plasma] = true;
			break;
		case MT_RAILGUN:
			players[i].weaponowned[wp_railgun] = true;
			break;
		case MT_BFG9000:
			players[i].weaponowned[wp_bfg] = true;
			break;
		case MT_CLIP:
			P_GiveAmmo (&players[i], am_clip, 1);
			break;
		case MT_AMMOBOX:
			P_GiveAmmo (&players[i], am_clip, 5);
			break;
		case MT_SHELLS:
			P_GiveAmmo (&players[i], am_shell, 1);
			break;
		case MT_SHELLBOX:
			P_GiveAmmo (&players[i], am_shell, 5);
			break;
		case MT_MISSILE:
			P_GiveAmmo (&players[i], am_misl, 1);
			break;
		case MT_MISSILEBOX:
			P_GiveAmmo (&players[i], am_misl, 5);
			break;
		case MT_CELL:
			P_GiveAmmo (&players[i], am_cell, 1);
			break;
		case MT_CELLPACK:
			P_GiveAmmo (&players[i], am_cell, 5);
			break;
		case MT_INV:
			players[i].powers[pw_invulnerability] = INVULNTICS;
			break;
		case MT_INS:
			players[i].powers[pw_invisibility] = INVISTICS;
			break;
		case MT_MEGA:
			players[i].health = 200;
			players[i].armortype = 2;
			players[i].armorpoints = 200;
			break;
		case MT_TURBOSPHERE:
			players[i].powers[pw_turbosphere] = TURBOTICS;
			break;
		case MT_LIGHTAMP:
			players[i].powers[pw_infrared] = LIGHTTICS;
			break;
		case MT_RADSUIT:
			players[i].powers[pw_ironfeet] = IRONTICS;
			break;
		case MT_COMPMAP:
			players[i].powers[pw_allmap] = true;
			break;
		case MT_BERSERK:
			players[i].powers[pw_strength] = true;
			break;
		case MT_FLOATINGFEET:
			players[i].powers[pw_floatingfeet] = ANTITICS;
			break;
		case MT_TIMEFREEZER:
			players[i].powers[pw_freezer] = FREEZETICS;
			break;
		case MT_ARMOR:
			if (players[i].armorpoints <= 100)
			{
				players[i].armorpoints = 100;
				players[i].armortype = 1;
			}
			break;
		case MT_MEGAARMOR:
			if (players[i].armorpoints <= 200)
			{
				players[i].armortype = 2;
				players[i].armorpoints = 200;
			}
			break;
		case MT_REDARMOR:
			if (players[i].armortype < 3 || players[i].armorpoints <= 200)
			{
				players[i].armortype = 3;
				players[i].armorpoints = 2;
			}
			break;
		default:
			I_Error("Team_GiveItem: Unknown item %d.", arg0);
			return false;
		}
	}
	ST_Start ();
	return true;
}

lnSpecFunc LineSpecials[256] =
{
	LS_NOP,
	LS_NOP,		// Polyobj_StartLine,
	LS_Polyobj_RotateLeft,
	LS_Polyobj_RotateRight,
	LS_Polyobj_Move,
	LS_NOP,		// Polyobj_ExplicitLine
	LS_Polyobj_MoveTimes8,
	LS_Polyobj_DoorSwing,
	LS_Polyobj_DoorSlide,
	LS_NOP,		// 9
	LS_Door_Close,
	LS_Door_Open,
	LS_Door_Raise,
	LS_Door_LockedRaise,
	LS_NOP,		// 14
	LS_NOP,		// 15
	LS_NOP,		// 16
	LS_NOP,		// 17
	LS_NOP,		// 18
	LS_NOP,		// 19
	LS_Floor_LowerByValue,
	LS_Floor_LowerToLowest,
	LS_Floor_LowerToNearest,
	LS_Floor_RaiseByValue,
	LS_Floor_RaiseToHighest,
	LS_Floor_RaiseToNearest,
	LS_Stairs_BuildDown,
	LS_Stairs_BuildUp,
	LS_Floor_RaiseAndCrush,
	LS_Pillar_Build,
	LS_Pillar_Open,
	LS_Stairs_BuildDownSync,
	LS_Stairs_BuildUpSync,
	LS_NOP,		// 33
	LS_NOP,		// 34
	LS_Floor_RaiseByValueTimes8,
	LS_Floor_LowerByValueTimes8,
	LS_NOP,		// 37
	LS_NOP,		// 38
	LS_NOP,		// 39
	LS_Ceiling_LowerByValue,
	LS_Ceiling_RaiseByValue,
	LS_Ceiling_CrushAndRaise,
	LS_Ceiling_LowerAndCrush,
	LS_Ceiling_CrushStop,
	LS_Ceiling_CrushRaiseAndStay,
	LS_Floor_CrushStop,
	LS_NOP,		// 47
	LS_NOP,		// 48
	LS_NOP,		// 49
	LS_NOP,		// 50
	LS_NOP,		// 51
	LS_NOP,		// 52
	LS_NOP,		// 53
	LS_NOP,		// 54
	LS_NOP,		// 55
	LS_NOP,		// 56
	LS_NOP,		// 57
	LS_NOP,		// 58
	LS_NOP,		// 59
	LS_Plat_PerpetualRaise,
	LS_Plat_Stop,
	LS_Plat_DownWaitUpStay,
	LS_Plat_DownByValue,
	LS_Plat_UpWaitDownStay,
	LS_Plat_UpByValue,
	LS_Floor_LowerInstant,
	LS_Floor_RaiseInstant,
	LS_Floor_MoveToValueTimes8,
	LS_Ceiling_MoveToValueTimes8,
	LS_Teleport,
	LS_Teleport_NoFog,
	LS_ThrustThing,
	LS_DamageThing,
	LS_Teleport_NewMap,
	LS_Teleport_EndGame,
	LS_NOP,		// 76
	LS_NOP,		// 77
	LS_NOP,		// 78
	LS_NOP,		// 79
	LS_ACS_Execute,
	LS_ACS_Suspend,
	LS_ACS_Terminate,
	LS_ACS_LockedExecute,
	LS_NOP,		// 84
	LS_NOP,		// 85
	LS_NOP,		// 86
	LS_NOP,		// 87
	LS_NOP,		// 88
	LS_NOP,		// 89
	LS_Polyobj_OR_RotateLeft,
	LS_Polyobj_OR_RotateRight,
	LS_Polyobj_OR_Move,
	LS_Polyobj_OR_MoveTimes8,
	LS_Pillar_BuildAndCrush,
	LS_FloorAndCeiling_LowerByValue,
	LS_FloorAndCeiling_RaiseByValue,
	LS_NOP,		// 97
	LS_NOP,		// 98
	LS_NOP,		// 99
	LS_NOP,		// Scroll_Texture_Left
	LS_NOP,		// Scroll_Texture_Right
	LS_NOP,		// Scroll_Texture_Up
	LS_NOP,		// Scroll_Texture_Down
	LS_NOP,		// 104
	LS_NOP,		// 105
	LS_NOP,		// 106
	LS_NOP,		// 107
	LS_NOP,		// 108
	LS_Light_ForceLightning,
	LS_Light_RaiseByValue,
	LS_Light_LowerByValue,
	LS_Light_ChangeToValue,
	LS_Light_Fade,
	LS_Light_Glow,
	LS_Light_Flicker,
	LS_Light_Strobe,
	LS_NOP,		// 117
	LS_NOP,		// 118
	LS_NOP,		// 119
	LS_Radius_Quake,
	LS_NOP,		// Line_SetIdentification
	LS_Thing_SetGravity,	// [BC] Start
	LS_Thing_ReverseGravity,
	LS_Thing_RevertGravity,
	LS_Thing_Move,
	LS_Thing_SetSprite,
	LS_Thing_SetSpecial,
	LS_ThrustThingZ,		// End
	LS_UsePuzzleItem,
	LS_Thing_Activate,
	LS_Thing_Deactivate,
	LS_Thing_Remove,
	LS_Thing_Destroy,
	LS_Thing_Projectile,
	LS_Thing_Spawn,
	LS_Thing_ProjectileGravity,
	LS_Thing_SpawnNoFog,
	LS_Floor_Waggle,
	LS_NOP,		// 139
	LS_Sector_ChangeSound,
	LS_Music_Pause,			// [BC] Start
	LS_Music_Change,
	LS_Player_RemoveItem,
	LS_Player_GiveItem,
	LS_Player_SetTeam,
	LS_Player_SetLeader,
	LS_Team_InitFP,
	LS_TeleportAll,
	LS_TeleportAll_NoFog,
	LS_Team_GiveFP,
	LS_Team_UseFP,
	LS_Team_Score,
	LS_Team_Init,
	LS_Var_Lock,
	LS_Team_RemoveItem,
	LS_Team_GiveItem,		// [BC] End
	LS_NOP,		// 157
	LS_NOP,		// 158
	LS_NOP,		// 159
	LS_NOP,		// 160
	LS_NOP,		// 161
	LS_NOP,		// 162
	LS_NOP,		// 163
	LS_NOP,		// 164
	LS_NOP,		// 165
	LS_NOP,		// 166
	LS_NOP,		// 167
	LS_NOP,		// 168
	LS_NOP,		// 169
	LS_NOP,		// 170
	LS_NOP,		// 171
	LS_NOP,		// 172
	LS_NOP,		// 173
	LS_NOP,		// 174
	LS_NOP,		// 175
	LS_NOP,		// 176
	LS_NOP,		// 177
	LS_NOP,		// 178
	LS_NOP,		// 179
	LS_NOP,		// 180
	LS_NOP,		// 181
	LS_NOP,		// 182
	LS_Line_AlignCeiling,
	LS_Line_AlignFloor,
	LS_Sector_SetRotation,
	LS_Sector_SetCeilingPanning,
	LS_Sector_SetFloorPanning,
	LS_Sector_SetCeilingScale,
	LS_Sector_SetFloorScale,
	LS_NOP,		// Static_Init
	LS_SetPlayerProperty,
	LS_Ceiling_LowerToHighestFloor,
	LS_Ceiling_LowerInstant,
	LS_Ceiling_RaiseInstant,
	LS_Ceiling_CrushRaiseAndStayA,
	LS_Ceiling_CrushAndRaiseA,
	LS_Ceiling_CrushAndRaiseSilentA,
	LS_Ceiling_RaiseByValueTimes8,
	LS_Ceiling_LowerByValueTimes8,
	LS_Generic_Floor,
	LS_Generic_Ceiling,
	LS_Generic_Door,
	LS_Generic_Lift,
	LS_Generic_Stairs,
	LS_Generic_Crusher,
	LS_Plat_DownWaitUpStayLip,
	LS_Plat_PerpetualRaiseLip,
	LS_TranslucentLine,
	LS_NOP,		// Transfer_Heights
	LS_NOP,		// Transfer_FloorLight
	LS_NOP,		// Transfer_CeilingLight
	LS_Sector_SetColor,
	LS_Sector_SetFade,
	LS_Sector_SetDamage,
	LS_Teleport_Line,
	LS_Sector_SetGravity,
	LS_Stairs_BuildUpDoom,
	LS_Sector_SetWind,
	LS_Sector_SetFriction,
	LS_Sector_SetCurrent,
	LS_Scroll_Texture_Both,
	LS_NOP,		// Scroll_Texture_Model
	LS_Scroll_Floor,
	LS_Scroll_Ceiling,
	LS_NOP,		// Scroll_Texture_Offsets
	LS_ACS_ExecuteAlways,
	LS_PointPush_SetForce,
	LS_Plat_RaiseAndStayTx0,
	LS_Thing_SetGoal,
	LS_Plat_UpByValueStayTx,
	LS_Plat_ToggleCeiling,
	LS_Light_StrobeDoom,
	LS_Light_MinNeighbor,
	LS_Light_MaxNeighbor,
	LS_Floor_TransferTrigger,
	LS_Floor_TransferNumeric,
	LS_ChangeCamera,
	LS_Floor_RaiseToLowestCeiling,
	LS_Floor_RaiseByValueTxTy,
	LS_Floor_RaiseByTexture,
	LS_Floor_LowerToLowestTxTy,
	LS_Floor_LowerToHighest,
	LS_Exit_Normal,
	LS_Exit_Secret,
	LS_Elevator_RaiseToNearest,
	LS_Elevator_MoveToFloor,
	LS_Elevator_LowerToNearest,
	LS_HealThing,
	LS_Door_CloseWaitOpen,
	LS_Floor_Donut,
	LS_FloorAndCeiling_LowerRaise,
	LS_Ceiling_RaiseToNearest,
	LS_Ceiling_LowerToLowest,
	LS_Ceiling_LowerToFloor,
	LS_Ceiling_CrushRaiseAndStaySilA
/*	LS_Player_RemoveItem,	// [BC]
	LS_Player_GiveItem,
	LS_Thing_SetSprite,
	LS_Music_Pause,
	LS_Music_Change,
	LS_TeleportAll,
	LS_TeleportAll_NoFog,
	LS_ThrustThingZ,
	LS_Thing_SetSpecial,
	LS_Player_SetTeam,
	LS_Team_GiveFP,
	LS_Team_UseFP,
	LS_Thing_SetGravity,
	LS_Thing_ReverseGravity,
	LS_Thing_RevertGravity,
	LS_Team_Score,
	LS_Team_Init,
	LS_Player_InitFP,
	LS_Player_SetLeader,
	LS_Thing_Move,
	LS_Var_Lock*/
};
