2006-02-24 04:48:15 +00:00
|
|
|
/*
|
|
|
|
** p_lnspec.cpp
|
|
|
|
** Handles line specials
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
2007-01-30 20:05:39 +00:00
|
|
|
** Copyright 1998-2007 Randy Heit
|
2006-02-24 04:48:15 +00:00
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
** Each function returns true if it caused something to happen
|
|
|
|
** or false if it could not perform the desired action.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_lnspec.h"
|
|
|
|
#include "p_enemy.h"
|
|
|
|
#include "g_level.h"
|
|
|
|
#include "v_palette.h"
|
|
|
|
#include "tables.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "a_sharedglobal.h"
|
|
|
|
#include "a_lightning.h"
|
|
|
|
#include "statnums.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "a_keys.h"
|
|
|
|
#include "gi.h"
|
|
|
|
#include "m_random.h"
|
2006-06-03 12:30:11 +00:00
|
|
|
#include "p_conversation.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "a_strifeglobal.h"
|
2007-12-26 16:06:03 +00:00
|
|
|
#include "r_translate.h"
|
2008-03-20 21:12:03 +00:00
|
|
|
#include "p_3dmidtex.h"
|
2008-09-14 23:54:38 +00:00
|
|
|
#include "d_net.h"
|
|
|
|
#include "d_event.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
#define FUNC(a) static int a (line_t *ln, AActor *it, bool backSide, \
|
|
|
|
int arg0, int arg1, int arg2, int arg3, int arg4)
|
|
|
|
|
|
|
|
#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))
|
2008-03-19 22:47:04 +00:00
|
|
|
#define CRUSHTYPE(a) ((a)==1? false : (a)==2? true : gameinfo.gametype == GAME_Hexen)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
static FRandom pr_glass ("GlassBreak");
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
FName MODtoDamageType (int mod)
|
|
|
|
{
|
|
|
|
switch (mod)
|
|
|
|
{
|
|
|
|
default: return NAME_None; break;
|
|
|
|
case 9: return NAME_BFGSplash; break;
|
2007-01-28 04:59:04 +00:00
|
|
|
case 12: return NAME_Drowning; break;
|
2006-10-31 14:53:21 +00:00
|
|
|
case 13: return NAME_Slime; break;
|
|
|
|
case 14: return NAME_Fire; break;
|
|
|
|
case 15: return NAME_Crush; break;
|
|
|
|
case 16: return NAME_Telefrag; break;
|
|
|
|
case 17: return NAME_Falling; break;
|
|
|
|
case 18: return NAME_Suicide; break;
|
|
|
|
case 20: return NAME_Exit; break;
|
|
|
|
case 22: return NAME_Melee; break;
|
|
|
|
case 23: return NAME_Railgun; break;
|
|
|
|
case 24: return NAME_Ice; break;
|
|
|
|
case 25: return NAME_Disintegrate; break;
|
|
|
|
case 26: return NAME_Poison; break;
|
|
|
|
case 27: return NAME_Electric; break;
|
|
|
|
case 1000: return NAME_Massacre; break;
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-08-01 19:14:10 +00:00
|
|
|
FUNC(LS_Polyobj_MoveTo)
|
|
|
|
// Polyobj_MoveTo (po, speed, x, y)
|
|
|
|
{
|
2010-08-10 19:06:33 +00:00
|
|
|
return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2 << FRACBITS, arg3 << FRACBITS, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Polyobj_MoveToSpot)
|
|
|
|
// Polyobj_MoveToSpot (po, speed, tid)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg2);
|
|
|
|
AActor *spot = iterator.Next();
|
|
|
|
if (spot == NULL) return false;
|
|
|
|
return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, false);
|
2010-08-01 19:14:10 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-08-01 19:14:10 +00:00
|
|
|
FUNC(LS_Polyobj_OR_MoveTo)
|
|
|
|
// Polyobj_OR_MoveTo (po, speed, x, y)
|
|
|
|
{
|
2010-08-10 19:06:33 +00:00
|
|
|
return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2 << FRACBITS, arg3 << FRACBITS, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Polyobj_OR_MoveToSpot)
|
|
|
|
// Polyobj_OR_MoveToSpot (po, speed, tid)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg2);
|
|
|
|
AActor *spot = iterator.Next();
|
|
|
|
if (spot == NULL) return false;
|
|
|
|
return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, true);
|
2010-08-01 19:14:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Polyobj_Stop)
|
|
|
|
// Polyobj_Stop (po)
|
|
|
|
{
|
|
|
|
return EV_StopPoly (arg0);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Door_Close)
|
|
|
|
// Door_Close (tag, speed, lighttag)
|
|
|
|
{
|
|
|
|
return EV_DoDoor (DDoor::doorClose, ln, it, arg0, SPEED(arg1), 0, 0, arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Door_Open)
|
|
|
|
// Door_Open (tag, speed, lighttag)
|
|
|
|
{
|
|
|
|
return EV_DoDoor (DDoor::doorOpen, ln, it, arg0, SPEED(arg1), 0, 0, arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Door_Raise)
|
|
|
|
// Door_Raise (tag, speed, delay, lighttag)
|
|
|
|
{
|
|
|
|
return EV_DoDoor (DDoor::doorRaise, ln, it, arg0, SPEED(arg1), TICS(arg2), 0, arg3);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Door_LockedRaise)
|
|
|
|
// Door_LockedRaise (tag, speed, delay, lock, lighttag)
|
|
|
|
{
|
|
|
|
return EV_DoDoor (arg2 ? DDoor::doorRaise : DDoor::doorOpen, ln, it,
|
|
|
|
arg0, SPEED(arg1), TICS(arg2), arg3, arg4);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Door_CloseWaitOpen)
|
|
|
|
// Door_CloseWaitOpen (tag, speed, delay, lighttag)
|
|
|
|
{
|
|
|
|
return EV_DoDoor (DDoor::doorCloseWaitOpen, ln, it, arg0, SPEED(arg1), OCTICS(arg2), 0, arg3);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Door_Animated)
|
2010-02-17 22:25:48 +00:00
|
|
|
// Door_Animated (tag, speed, delay, lock)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-02-17 22:25:48 +00:00
|
|
|
if (arg3 != 0 && !P_CheckKeys (it, arg3, arg0 != 0))
|
|
|
|
return false;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
return EV_SlidingDoor (ln, it, arg0, arg1, arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Generic_Door)
|
|
|
|
// Generic_Door (tag, speed, kind, delay, lock)
|
|
|
|
{
|
|
|
|
int tag, lightTag;
|
|
|
|
DDoor::EVlDoor type;
|
|
|
|
|
|
|
|
switch (arg2 & 127)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (arg2 & 128)
|
|
|
|
{
|
|
|
|
// New for 2.0.58: Finally support BOOM's local door light effect
|
|
|
|
tag = 0;
|
|
|
|
lightTag = arg0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tag = arg0;
|
|
|
|
lightTag = 0;
|
|
|
|
}
|
|
|
|
return EV_DoDoor (type, ln, it, tag, SPEED(arg1), OCTICS(arg3), arg4, lightTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerByValue)
|
|
|
|
// Floor_LowerByValue (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerToLowest)
|
|
|
|
// Floor_LowerToLowest (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerToHighest)
|
|
|
|
// Floor_LowerToHighest (tag, speed, adjust)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerToHighest, ln, arg0, SPEED(arg1), (arg2-128)*FRACUNIT, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerToNearest)
|
|
|
|
// Floor_LowerToNearest (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerToNearest, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseByValue)
|
|
|
|
// Floor_RaiseByValue (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseToHighest)
|
|
|
|
// Floor_RaiseToHighest (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseToHighest, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseToNearest)
|
|
|
|
// Floor_RaiseToNearest (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseToNearest, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseAndCrush)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Floor_RaiseAndCrush (tag, speed, crush, crushmode)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseAndCrush, ln, arg0, SPEED(arg1), 0, arg2, 0, CRUSHTYPE(arg3));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseByValueTimes8)
|
|
|
|
// FLoor_RaiseByValueTimes8 (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerByValueTimes8)
|
|
|
|
// Floor_LowerByValueTimes8 (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_CrushStop)
|
|
|
|
// Floor_CrushStop (tag)
|
|
|
|
{
|
|
|
|
return EV_FloorCrushStop (arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerInstant)
|
|
|
|
// Floor_LowerInstant (tag, unused, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerInstant, ln, arg0, 0, arg2*FRACUNIT*8, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseInstant)
|
|
|
|
// Floor_RaiseInstant (tag, unused, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseInstant, ln, arg0, 0, arg2*FRACUNIT*8, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_MoveToValueTimes8)
|
|
|
|
// Floor_MoveToValueTimes8 (tag, speed, height, negative)
|
|
|
|
{
|
|
|
|
return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1),
|
2008-03-19 22:47:04 +00:00
|
|
|
arg2*FRACUNIT*8*(arg3?-1:1), 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2007-11-28 09:11:35 +00:00
|
|
|
FUNC(LS_Floor_MoveToValue)
|
|
|
|
// Floor_MoveToValue (tag, speed, height, negative)
|
|
|
|
{
|
|
|
|
return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1),
|
2008-03-19 22:47:04 +00:00
|
|
|
arg2*FRACUNIT*(arg3?-1:1), 0, 0, false);
|
2007-11-28 09:11:35 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Floor_RaiseToLowestCeiling)
|
|
|
|
// Floor_RaiseToLowestCeiling (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseToLowestCeiling, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseByTexture)
|
|
|
|
// Floor_RaiseByTexture (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseByTexture, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_RaiseByValueTxTy)
|
|
|
|
// Floor_RaiseByValueTxTy (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorRaiseAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_LowerToLowestTxTy)
|
|
|
|
// Floor_LowerToLowestTxTy (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoFloor (DFloor::floorLowerAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Floor_Waggle)
|
|
|
|
// Floor_Waggle (tag, amplitude, frequency, delay, time)
|
|
|
|
{
|
2009-11-24 07:38:11 +00:00
|
|
|
return EV_StartWaggle (arg0, ln, arg1, arg2, arg3, arg4, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_Waggle)
|
|
|
|
// Ceiling_Waggle (tag, amplitude, frequency, delay, time)
|
|
|
|
{
|
2009-11-24 07:38:11 +00:00
|
|
|
return EV_StartWaggle (arg0, ln, arg1, arg2, arg3, arg4, true);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2009-11-24 07:38:11 +00:00
|
|
|
return EV_DoDonut (arg0, ln, SPEED(arg1), SPEED(arg2));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2008-03-19 22:47:04 +00:00
|
|
|
(arg4 & 16) ? 20 : -1, arg4 & 7, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoPillar (DPillar::pillarBuild, arg0, SPEED(arg1), arg2*FRACUNIT, 0, -1, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Pillar_BuildAndCrush)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Pillar_BuildAndCrush (tag, speed, height, crush, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoPillar (DPillar::pillarBuild, arg0, SPEED(arg1), arg2*FRACUNIT, 0, arg3, CRUSHTYPE(arg4));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Pillar_Open)
|
|
|
|
// Pillar_Open (tag, speed, f_height, c_height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoPillar (DPillar::pillarOpen, arg0, SPEED(arg1), arg2*FRACUNIT, arg3*FRACUNIT, -1, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_LowerByValue)
|
|
|
|
// Ceiling_LowerByValue (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_RaiseByValue)
|
|
|
|
// Ceiling_RaiseByValue (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilRaiseByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_LowerByValueTimes8)
|
|
|
|
// Ceiling_LowerByValueTimes8 (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT*8, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_RaiseByValueTimes8)
|
|
|
|
// Ceiling_RaiseByValueTimes8 (tag, speed, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilRaiseByValue, ln, arg0, SPEED(arg1), 0, arg2*FRACUNIT*8, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_CrushAndRaise)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_CrushAndRaise (tag, speed, crush, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0, CRUSHTYPE(arg3));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_LowerAndCrush)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_LowerAndCrush (tag, speed, crush, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), 0, arg2, 0, 0, CRUSHTYPE(arg3));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 16:26:10 +00:00
|
|
|
FUNC(LS_Ceiling_LowerAndCrushDist)
|
|
|
|
// Ceiling_LowerAndCrush (tag, speed, crush, dist, crushtype)
|
|
|
|
{
|
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerAndCrushDist, ln, arg0, SPEED(arg1), SPEED(arg1), arg3*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg4));
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Ceiling_CrushStop)
|
|
|
|
// Ceiling_CrushStop (tag)
|
|
|
|
{
|
|
|
|
return EV_CeilingCrushStop (arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_CrushRaiseAndStay)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_CrushRaiseAndStay (tag, speed, crush, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0, CRUSHTYPE(arg3));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_MoveToValueTimes8)
|
|
|
|
// Ceiling_MoveToValueTimes8 (tag, speed, height, negative)
|
|
|
|
{
|
|
|
|
return EV_DoCeiling (DCeiling::ceilMoveToValue, ln, arg0, SPEED(arg1), 0,
|
2008-03-19 22:47:04 +00:00
|
|
|
arg2*FRACUNIT*8*((arg3) ? -1 : 1), -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2007-11-28 09:11:35 +00:00
|
|
|
FUNC(LS_Ceiling_MoveToValue)
|
|
|
|
// Ceiling_MoveToValue (tag, speed, height, negative)
|
|
|
|
{
|
|
|
|
return EV_DoCeiling (DCeiling::ceilMoveToValue, ln, arg0, SPEED(arg1), 0,
|
2008-03-19 22:47:04 +00:00
|
|
|
arg2*FRACUNIT*((arg3) ? -1 : 1), -1, 0, 0, false);
|
2007-11-28 09:11:35 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Ceiling_LowerToHighestFloor)
|
|
|
|
// Ceiling_LowerToHighestFloor (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, 0, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_LowerInstant)
|
|
|
|
// Ceiling_LowerInstant (tag, unused, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerInstant, ln, arg0, 0, 0, arg2*FRACUNIT*8, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_RaiseInstant)
|
|
|
|
// Ceiling_RaiseInstant (tag, unused, height)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilRaiseInstant, ln, arg0, 0, 0, arg2*FRACUNIT*8, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_CrushRaiseAndStayA)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_CrushRaiseAndStayA (tag, dnspeed, upspeed, damage, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 0, 0, CRUSHTYPE(arg4));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_CrushRaiseAndStaySilA)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_CrushRaiseAndStaySilA (tag, dnspeed, upspeed, damage, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 1, 0, CRUSHTYPE(arg4));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_CrushAndRaiseA)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_CrushAndRaiseA (tag, dnspeed, upspeed, damage, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 0, 0, CRUSHTYPE(arg4));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_CrushAndRaiseSilentA)
|
2008-03-19 22:47:04 +00:00
|
|
|
// Ceiling_CrushAndRaiseSilentA (tag, dnspeed, upspeed, damage, crushtype)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg2), 0, arg3, 1, 0, CRUSHTYPE(arg4));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_RaiseToNearest)
|
|
|
|
// Ceiling_RaiseToNearest (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilRaiseToNearest, ln, arg0, SPEED(arg1), 0, 0, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_LowerToLowest)
|
|
|
|
// Ceiling_LowerToLowest (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Ceiling_LowerToFloor)
|
|
|
|
// Ceiling_LowerToFloor (tag, speed)
|
|
|
|
{
|
2008-03-19 22:47:04 +00:00
|
|
|
return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, 0, -1, 0, 0, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2008-03-19 22:47:04 +00:00
|
|
|
(arg4 & 16) ? 20 : -1, 0, arg4 & 7, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Generic_Crusher)
|
|
|
|
// Generic_Crusher (tag, dnspeed, upspeed, silent, damage)
|
|
|
|
{
|
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1),
|
2008-03-19 22:47:04 +00:00
|
|
|
SPEED(arg2), 0, arg4, arg3 ? 2 : 0, 0, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Generic_Crusher2)
|
|
|
|
// Generic_Crusher2 (tag, dnspeed, upspeed, silent, damage)
|
|
|
|
{
|
|
|
|
// same as above but uses Hexen's crushing method.
|
|
|
|
return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1),
|
|
|
|
SPEED(arg2), 0, arg4, arg3 ? 2 : 0, 0, true);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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, floor-sound?)
|
|
|
|
{
|
|
|
|
return EV_DoPlat (arg0, ln,
|
|
|
|
arg4 ? DPlat::platDownWaitUpStayStone : 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_UpNearestWaitDownStay)
|
|
|
|
// Plat_UpNearestWaitDownStay (tag, speed, delay)
|
|
|
|
{
|
|
|
|
return EV_DoPlat (arg0, ln, DPlat::platUpNearestWaitDownStay, 0, SPEED(arg1), TICS(arg2), 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Plat_RaiseAndStayTx0)
|
2009-09-08 21:01:24 +00:00
|
|
|
// Plat_RaiseAndStayTx0 (tag, speed, lockout)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-09-08 21:01:24 +00:00
|
|
|
DPlat::EPlatType type;
|
|
|
|
|
|
|
|
switch (arg3)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
type = DPlat::platRaiseAndStay;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
type = DPlat::platRaiseAndStayLockout;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
type = gameinfo.gametype == GAME_Heretic? DPlat::platRaiseAndStayLockout : DPlat::platRaiseAndStay;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return EV_DoPlat (arg0, ln, type, 0, SPEED(arg1), 0, 0, 1);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2008-02-12 05:54:03 +00:00
|
|
|
if (CheckIfExitIsGood (it, FindLevelInfo(G_GetExitMap())))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
G_ExitLevel (arg0, false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Exit_Secret)
|
|
|
|
// Exit_Secret (position)
|
|
|
|
{
|
2008-02-12 05:54:03 +00:00
|
|
|
if (CheckIfExitIsGood (it, FindLevelInfo(G_GetSecretExitMap())))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
G_SecretExitLevel (arg0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Teleport_NewMap)
|
|
|
|
// Teleport_NewMap (map, position, keepFacing?)
|
|
|
|
{
|
|
|
|
if (backSide == 0 || gameinfo.gametype == GAME_Strife)
|
|
|
|
{
|
|
|
|
level_info_t *info = FindLevelByNum (arg0);
|
|
|
|
|
2008-02-12 05:54:03 +00:00
|
|
|
if (info && CheckIfExitIsGood (it, info))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-06-18 03:35:41 +00:00
|
|
|
G_ChangeLevel(info->mapname, arg1, arg2 ? CHANGELEVEL_KEEPFACING : 0);
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Teleport)
|
|
|
|
// Teleport (tid, sectortag, bNoSourceFog)
|
2009-01-18 09:31:49 +00:00
|
|
|
{
|
2006-02-24 04:48:15 +00:00
|
|
|
return EV_Teleport (arg0, arg1, ln, backSide, it, true, !arg2, false);
|
|
|
|
}
|
|
|
|
|
2008-07-19 12:40:10 +00:00
|
|
|
FUNC( LS_Teleport_NoStop )
|
|
|
|
// Teleport_NoStop (tid, sectortag, bNoSourceFog)
|
|
|
|
{
|
|
|
|
return EV_Teleport( arg0, arg1, ln, backSide, it, true, !arg2, false, false );
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Teleport_NoFog)
|
|
|
|
// Teleport_NoFog (tid, useang, sectortag)
|
|
|
|
{
|
|
|
|
return EV_Teleport (arg0, arg2, ln, backSide, it, false, false, !arg1);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Teleport_ZombieChanger)
|
|
|
|
// Teleport_ZombieChanger (tid, sectortag)
|
|
|
|
{
|
|
|
|
// This is practically useless outside of Strife, but oh well.
|
|
|
|
if (it != NULL)
|
|
|
|
{
|
|
|
|
EV_Teleport (arg0, arg1, ln, backSide, it, false, false, false);
|
2007-07-12 15:15:57 +00:00
|
|
|
if (it->health >= 0) it->SetState (it->FindState(NAME_Pain));
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_TeleportOther)
|
|
|
|
// TeleportOther (other_tid, dest_tid, fog?)
|
|
|
|
{
|
|
|
|
return EV_TeleportOther (arg0, arg1, arg2?true:false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_TeleportGroup)
|
|
|
|
// TeleportGroup (group_tid, source_tid, dest_tid, move_source?, fog?)
|
|
|
|
{
|
|
|
|
return EV_TeleportGroup (arg0, it, arg1, arg2, arg3?true:false, arg4?true:false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_TeleportInSector)
|
|
|
|
// TeleportInSector (tag, source_tid, dest_tid, bFog, group_tid)
|
|
|
|
{
|
|
|
|
return EV_TeleportSector (arg0, arg1, arg2, arg3?true:false, arg4);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Teleport_EndGame)
|
|
|
|
// Teleport_EndGame ()
|
|
|
|
{
|
2008-02-12 05:54:03 +00:00
|
|
|
if (!backSide && CheckIfExitIsGood (it, NULL))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-10-06 10:44:03 +00:00
|
|
|
G_ChangeLevel(NULL, 0, 0);
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Teleport_Line)
|
|
|
|
// Teleport_Line (thisid, destid, reversed)
|
|
|
|
{
|
|
|
|
return EV_SilentLineTeleport (ln, backSide, it, arg1, arg2);
|
|
|
|
}
|
|
|
|
|
2006-09-14 00:02:31 +00:00
|
|
|
static void ThrustThingHelper (AActor *it, angle_t angle, int force, INTBOOL nolimit);
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_ThrustThing)
|
|
|
|
// ThrustThing (angle, force, nolimit, tid)
|
|
|
|
{
|
|
|
|
if (arg3 != 0)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg3);
|
|
|
|
while ((it = iterator.Next()) != NULL)
|
|
|
|
{
|
|
|
|
ThrustThingHelper (it, BYTEANGLE(arg0), arg1, arg2);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (it)
|
|
|
|
{
|
|
|
|
ThrustThingHelper (it, BYTEANGLE(arg0), arg1, arg2);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-09-14 00:02:31 +00:00
|
|
|
static void ThrustThingHelper (AActor *it, angle_t angle, int force, INTBOOL nolimit)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
angle >>= ANGLETOFINESHIFT;
|
2009-06-30 20:57:51 +00:00
|
|
|
it->velx += force * finecosine[angle];
|
|
|
|
it->vely += force * finesine[angle];
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!nolimit)
|
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
it->velx = clamp<fixed_t> (it->velx, -MAXMOVE, MAXMOVE);
|
|
|
|
it->vely = clamp<fixed_t> (it->vely, -MAXMOVE, MAXMOVE);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ThrustThingZ) // [BC]
|
|
|
|
// ThrustThingZ (tid, zthrust, down/up, set)
|
|
|
|
{
|
|
|
|
AActor *victim;
|
|
|
|
fixed_t thrust = arg1*FRACUNIT/4;
|
|
|
|
|
|
|
|
// [BC] Up is default
|
|
|
|
if (arg2)
|
|
|
|
thrust = -thrust;
|
|
|
|
|
|
|
|
if (arg0 != 0)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
|
|
|
|
while ( (victim = iterator.Next ()) )
|
|
|
|
{
|
|
|
|
if (!arg3)
|
2009-06-30 20:57:51 +00:00
|
|
|
victim->velz = thrust;
|
2006-02-24 04:48:15 +00:00
|
|
|
else
|
2009-06-30 20:57:51 +00:00
|
|
|
victim->velz += thrust;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (it)
|
|
|
|
{
|
|
|
|
if (!arg3)
|
2009-06-30 20:57:51 +00:00
|
|
|
it->velz = thrust;
|
2006-02-24 04:48:15 +00:00
|
|
|
else
|
2009-06-30 20:57:51 +00:00
|
|
|
it->velz += thrust;
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_SetSpecial) // [BC]
|
|
|
|
// Thing_SetSpecial (tid, special, arg1, arg2, arg3)
|
|
|
|
// [RH] Use the SetThingSpecial ACS command instead.
|
|
|
|
// It can set all args and not just the first three.
|
|
|
|
{
|
2008-02-14 15:40:46 +00:00
|
|
|
if (arg0 == 0)
|
|
|
|
{
|
2008-02-14 15:48:31 +00:00
|
|
|
if (it != NULL)
|
|
|
|
{
|
|
|
|
it->special = arg1;
|
|
|
|
it->args[0] = arg2;
|
|
|
|
it->args[1] = arg3;
|
|
|
|
it->args[2] = arg4;
|
|
|
|
}
|
2008-02-14 15:40:46 +00:00
|
|
|
}
|
|
|
|
else
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *actor;
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
|
|
|
|
while ( (actor = iterator.Next ()) )
|
|
|
|
{
|
|
|
|
actor->special = arg1;
|
|
|
|
actor->args[0] = arg2;
|
|
|
|
actor->args[1] = arg3;
|
|
|
|
actor->args[2] = arg4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_ChangeTID)
|
|
|
|
// Thing_ChangeTID (oldtid, newtid)
|
|
|
|
{
|
|
|
|
if (arg0 == 0)
|
|
|
|
{
|
2008-03-12 02:56:11 +00:00
|
|
|
if (it != NULL && !(it->ObjectFlags & OF_EuthanizeMe))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
it->RemoveFromHash ();
|
|
|
|
it->tid = arg1;
|
|
|
|
it->AddToHash ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
AActor *actor, *next;
|
|
|
|
|
|
|
|
next = iterator.Next ();
|
|
|
|
while (next != NULL)
|
|
|
|
{
|
2006-05-22 22:02:13 +00:00
|
|
|
actor = next;
|
|
|
|
next = iterator.Next ();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-12 02:56:11 +00:00
|
|
|
if (!(actor->ObjectFlags & OF_EuthanizeMe))
|
2006-05-22 22:02:13 +00:00
|
|
|
{
|
2006-05-22 09:53:09 +00:00
|
|
|
actor->RemoveFromHash ();
|
|
|
|
actor->tid = arg1;
|
|
|
|
actor->AddToHash ();
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_DamageThing)
|
2006-10-05 20:32:16 +00:00
|
|
|
// DamageThing (damage, mod)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (it)
|
|
|
|
{
|
|
|
|
if (arg0 < 0)
|
|
|
|
{ // Negative damages mean healing
|
|
|
|
if (it->player)
|
|
|
|
{
|
|
|
|
P_GiveBody (it, -arg0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
it->health -= arg0;
|
2009-07-04 18:17:44 +00:00
|
|
|
if (it->SpawnHealth() < it->health)
|
|
|
|
it->health = it->SpawnHealth();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (arg0 > 0)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (it, NULL, NULL, arg0, MODtoDamageType (arg1));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // If zero damage, guarantee a kill
|
2009-08-07 03:57:03 +00:00
|
|
|
P_DamageMobj (it, NULL, NULL, TELEFRAG_DAMAGE, MODtoDamageType (arg1));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return it ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_HealThing)
|
|
|
|
// HealThing (amount, max)
|
|
|
|
{
|
|
|
|
if (it)
|
|
|
|
{
|
|
|
|
int max = arg1;
|
|
|
|
|
|
|
|
if (max == 0 || it->player == NULL)
|
|
|
|
{
|
2006-11-04 13:06:42 +00:00
|
|
|
P_GiveBody(it, arg0);
|
|
|
|
return true;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (max == 1)
|
|
|
|
{
|
|
|
|
max = deh.MaxSoulsphere;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If health is already above max, do nothing
|
|
|
|
if (it->health < max)
|
|
|
|
{
|
|
|
|
it->health += arg0;
|
|
|
|
if (it->health > max && max > 0)
|
|
|
|
{
|
|
|
|
it->health = max;
|
|
|
|
}
|
|
|
|
if (it->player)
|
|
|
|
{
|
|
|
|
it->player->health = it->health;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return it ? true : false;
|
|
|
|
}
|
|
|
|
|
2009-10-09 20:35:07 +00:00
|
|
|
// So that things activated/deactivated by ACS or DECORATE *and* by
|
|
|
|
// the BUMPSPECIAL or USESPECIAL flags work correctly both ways.
|
|
|
|
void DoActivateThing(AActor * thing, AActor * activator)
|
|
|
|
{
|
|
|
|
if (thing->activationtype & THINGSPEC_Activate)
|
|
|
|
{
|
|
|
|
thing->activationtype &= ~THINGSPEC_Activate; // Clear flag
|
|
|
|
if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching
|
|
|
|
thing->activationtype |= THINGSPEC_Deactivate;
|
|
|
|
}
|
|
|
|
thing->Activate (activator);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DoDeactivateThing(AActor * thing, AActor * activator)
|
|
|
|
{
|
|
|
|
if (thing->activationtype & THINGSPEC_Deactivate)
|
|
|
|
{
|
|
|
|
thing->activationtype &= ~THINGSPEC_Deactivate; // Clear flag
|
|
|
|
if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching
|
|
|
|
thing->activationtype |= THINGSPEC_Activate;
|
|
|
|
}
|
|
|
|
thing->Deactivate (activator);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Thing_Activate)
|
|
|
|
// Thing_Activate (tid)
|
|
|
|
{
|
2006-08-10 15:28:12 +00:00
|
|
|
if (arg0 != 0)
|
|
|
|
{
|
|
|
|
AActor *actor;
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
int count = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-08-10 15:28:12 +00:00
|
|
|
actor = iterator.Next ();
|
|
|
|
while (actor)
|
|
|
|
{
|
|
|
|
// Actor might remove itself as part of activation, so get next
|
|
|
|
// one before activating it.
|
|
|
|
AActor *temp = iterator.Next ();
|
2009-10-09 20:35:07 +00:00
|
|
|
DoActivateThing(actor, it);
|
2006-08-10 15:28:12 +00:00
|
|
|
actor = temp;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count != 0;
|
|
|
|
}
|
|
|
|
else if (it != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-10-09 20:35:07 +00:00
|
|
|
DoActivateThing(it, it);
|
2006-08-10 15:28:12 +00:00
|
|
|
return true;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-08-10 15:28:12 +00:00
|
|
|
return false;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Deactivate)
|
|
|
|
// Thing_Deactivate (tid)
|
|
|
|
{
|
2006-10-05 20:32:16 +00:00
|
|
|
if (arg0 != 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-05 20:32:16 +00:00
|
|
|
AActor *actor;
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
actor = iterator.Next ();
|
|
|
|
while (actor)
|
|
|
|
{
|
|
|
|
// Actor might removes itself as part of deactivation, so get next
|
|
|
|
// one before we activate it.
|
|
|
|
AActor *temp = iterator.Next ();
|
2009-10-09 20:35:07 +00:00
|
|
|
DoDeactivateThing(actor, it);
|
2006-10-05 20:32:16 +00:00
|
|
|
actor = temp;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count != 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-05 20:32:16 +00:00
|
|
|
else if (it != NULL)
|
|
|
|
{
|
2009-10-09 20:35:07 +00:00
|
|
|
DoDeactivateThing(it, it);
|
2006-10-05 20:32:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Remove)
|
|
|
|
// Thing_Remove (tid)
|
|
|
|
{
|
2006-08-10 15:28:12 +00:00
|
|
|
if (arg0 != 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-08-10 15:28:12 +00:00
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
AActor *actor;
|
2006-04-13 22:40:43 +00:00
|
|
|
|
2006-08-10 15:28:12 +00:00
|
|
|
actor = iterator.Next ();
|
|
|
|
while (actor)
|
2006-04-13 22:40:43 +00:00
|
|
|
{
|
2006-08-10 15:28:12 +00:00
|
|
|
AActor *temp = iterator.Next ();
|
|
|
|
|
2008-12-06 10:22:37 +00:00
|
|
|
P_RemoveThing(actor);
|
2006-08-10 15:28:12 +00:00
|
|
|
actor = temp;
|
2006-04-13 22:40:43 +00:00
|
|
|
}
|
2006-08-10 15:28:12 +00:00
|
|
|
}
|
|
|
|
else if (it != NULL)
|
|
|
|
{
|
2008-12-06 10:22:37 +00:00
|
|
|
P_RemoveThing(it);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Destroy)
|
2010-09-18 22:39:27 +00:00
|
|
|
// Thing_Destroy (tid, extreme, tag)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-09-18 22:39:27 +00:00
|
|
|
AActor *actor;
|
|
|
|
|
|
|
|
if (arg0 == 0 && arg2 == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
P_Massacre ();
|
|
|
|
}
|
2010-09-18 22:39:27 +00:00
|
|
|
else if (arg0 == 0)
|
|
|
|
{
|
|
|
|
TThinkerIterator<AActor> iterator;
|
|
|
|
|
|
|
|
actor = iterator.Next ();
|
|
|
|
while (actor)
|
|
|
|
{
|
|
|
|
AActor *temp = iterator.Next ();
|
|
|
|
if (actor->flags & MF_SHOOTABLE && actor->Sector->tag == arg2)
|
|
|
|
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
|
|
|
|
actor = temp;
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
|
|
|
|
actor = iterator.Next ();
|
|
|
|
while (actor)
|
|
|
|
{
|
|
|
|
AActor *temp = iterator.Next ();
|
2010-09-18 22:39:27 +00:00
|
|
|
if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || actor->Sector->tag == arg2))
|
2009-08-07 03:57:03 +00:00
|
|
|
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
|
2006-02-24 04:48:15 +00:00
|
|
|
actor = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Damage)
|
|
|
|
// Thing_Damage (tid, amount, MOD)
|
|
|
|
{
|
- Moved the implementation for the Thing_Damage special into another function
so that I can create the ACS function Thing_Damage2. It's exactly the same as
Thing_Damage, except the damage type is specified by name. When I did this,
I noticed that it didn't do anything useful for a TID of 0, so I made it
affect the activator in that case.
- Added a new SetActorState ACS function:
int SetActorState (int tid, str statename, optional bool exact);
If tid is 0, it affects the script activator, otherwise it affects all the
matching actors. Statename is the name of the state you want to put the
actor in. The final parameter, exact, specifies whether or not partial
state name matches are accepted. If you don't specify it or set it to
false, if you try to do something like:
SetActorState (0, "Foo.Bar");
And the actor has a Foo state but no Foo.Bar state, it will enter the Foo
state. If you set exact to true:
SetActorState (0, "Foo.Bar", true);
Then the actor must have a Foo.Bar state, or it will not change state at
all, even if it has a Foo state.
The return value for this function is the number of actors that successfully
changed state. Note that you should refrain from using this function to
enter special states such as Death, or unpredictable results could occur.
SVN r505 (trunk)
2007-03-23 22:26:14 +00:00
|
|
|
P_Thing_Damage (arg0, it, arg1, MODtoDamageType (arg2));
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Projectile)
|
|
|
|
// Thing_Projectile (tid, type, angle, speed, vspeed)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Projectile (arg0, it, arg1, NULL, BYTEANGLE(arg2), arg3<<(FRACBITS-3),
|
2006-02-24 04:48:15 +00:00
|
|
|
arg4<<(FRACBITS-3), 0, NULL, 0, 0, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_ProjectileGravity)
|
|
|
|
// Thing_ProjectileGravity (tid, type, angle, speed, vspeed)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Projectile (arg0, it, arg1, NULL, BYTEANGLE(arg2), arg3<<(FRACBITS-3),
|
2006-02-24 04:48:15 +00:00
|
|
|
arg4<<(FRACBITS-3), 0, NULL, 1, 0, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Hate)
|
|
|
|
// Thing_Hate (hater, hatee, group/"xray"?)
|
|
|
|
{
|
|
|
|
FActorIterator haterIt (arg0);
|
|
|
|
AActor *hater, *hatee = NULL;
|
|
|
|
FActorIterator hateeIt (arg1);
|
|
|
|
bool nothingToHate = false;
|
|
|
|
|
|
|
|
if (arg1 != 0)
|
|
|
|
{
|
|
|
|
while ((hatee = hateeIt.Next ()))
|
|
|
|
{
|
|
|
|
if (hatee->flags & MF_SHOOTABLE && // can't hate nonshootable things
|
|
|
|
hatee->health > 0 && // can't hate dead things
|
|
|
|
!(hatee->flags2 & MF2_DORMANT)) // can't target dormant things
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hatee == NULL)
|
|
|
|
{ // Nothing to hate
|
|
|
|
nothingToHate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg0 == 0)
|
|
|
|
{
|
2006-04-12 01:50:09 +00:00
|
|
|
if (it != NULL && it->player != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
// Players cannot have their attitudes set
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hater = it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while ((hater = haterIt.Next ()))
|
|
|
|
{
|
|
|
|
if (hater->health > 0 && hater->flags & MF_SHOOTABLE)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (hater != NULL)
|
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
// Can't hate if can't attack.
|
|
|
|
if (hater->SeeState != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
// If hating a group of things, record the TID and NULL
|
|
|
|
// the target (if its TID doesn't match). A_Look will
|
|
|
|
// find an appropriate thing to go chase after.
|
|
|
|
if (arg2 != 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
hater->TIDtoHate = arg1;
|
2008-03-12 02:56:11 +00:00
|
|
|
hater->LastLookActor = NULL;
|
2006-04-13 03:13:07 +00:00
|
|
|
|
|
|
|
// If the TID to hate is 0, then don't forget the target and
|
|
|
|
// lastenemy fields.
|
|
|
|
if (arg1 != 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
if (hater->target != NULL && hater->target->tid != arg1)
|
|
|
|
{
|
|
|
|
hater->target = NULL;
|
|
|
|
}
|
|
|
|
if (hater->lastenemy != NULL && hater->lastenemy->tid != arg1)
|
|
|
|
{
|
|
|
|
hater->lastenemy = NULL;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2006-04-13 03:13:07 +00:00
|
|
|
// Hate types for arg2:
|
|
|
|
//
|
|
|
|
// 0 - Just hate one specific actor
|
|
|
|
// 1 - Hate actors with given TID and attack players when shot
|
|
|
|
// 2 - Same as 1, but will go after enemies without seeing them first
|
|
|
|
// 3 - Hunt actors with given TID and also players
|
|
|
|
// 4 - Same as 3, but will go after monsters without seeing them first
|
|
|
|
// 5 - Hate actors with given TID and ignore player attacks
|
|
|
|
// 6 - Same as 5, but will go after enemies without seeing them first
|
|
|
|
|
|
|
|
// Note here: If you use Thing_Hate (tid, 0, 2), you can make
|
|
|
|
// a monster go after a player without seeing him first.
|
|
|
|
if (arg2 == 2 || arg2 == 4 || arg2 == 6)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
hater->flags3 |= MF3_NOSIGHTCHECK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hater->flags3 &= ~MF3_NOSIGHTCHECK;
|
|
|
|
}
|
|
|
|
if (arg2 == 3 || arg2 == 4)
|
|
|
|
{
|
|
|
|
hater->flags3 |= MF3_HUNTPLAYERS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hater->flags3 &= ~MF3_HUNTPLAYERS;
|
|
|
|
}
|
|
|
|
if (arg2 == 5 || arg2 == 6)
|
|
|
|
{
|
|
|
|
hater->flags4 |= MF4_NOHATEPLAYERS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hater->flags4 &= ~MF4_NOHATEPLAYERS;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-04-13 03:13:07 +00:00
|
|
|
if (arg1 == 0)
|
|
|
|
{
|
|
|
|
hatee = it;
|
|
|
|
}
|
|
|
|
else if (nothingToHate)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
hatee = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-04-13 03:13:07 +00:00
|
|
|
else if (arg2 != 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-13 03:13:07 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
hatee = hateeIt.Next ();
|
|
|
|
}
|
|
|
|
while ( hatee == NULL ||
|
|
|
|
hatee == hater || // can't hate self
|
|
|
|
!(hatee->flags & MF_SHOOTABLE) || // can't hate nonshootable things
|
|
|
|
hatee->health <= 0 || // can't hate dead things
|
2007-10-19 08:49:02 +00:00
|
|
|
(hatee->flags2 & MF2_DORMANT));
|
2006-04-13 03:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hatee != NULL && hatee != hater && (arg2 == 0 || (hater->goal != NULL && hater->target != hater->goal)))
|
|
|
|
{
|
|
|
|
if (hater->target)
|
|
|
|
{
|
|
|
|
hater->lastenemy = hater->target;
|
|
|
|
}
|
|
|
|
hater->target = hatee;
|
|
|
|
if (!(hater->flags2 & MF2_DORMANT))
|
|
|
|
{
|
2007-07-12 15:15:57 +00:00
|
|
|
if (hater->health > 0) hater->SetState (hater->SeeState);
|
2006-04-13 03:13:07 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (arg0 != 0)
|
|
|
|
{
|
|
|
|
while ((hater = haterIt.Next ()))
|
|
|
|
{
|
|
|
|
if (hater->health > 0 && hater->flags & MF_SHOOTABLE)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hater = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_ProjectileAimed)
|
|
|
|
// Thing_ProjectileAimed (tid, type, speed, target, newtid)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Projectile (arg0, it, arg1, NULL, 0, arg2<<(FRACBITS-3), 0, arg3, it, 0, arg4, false);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_ProjectileIntercept)
|
|
|
|
// Thing_ProjectileIntercept (tid, type, speed, target, newtid)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Projectile (arg0, it, arg1, NULL, 0, arg2<<(FRACBITS-3), 0, arg3, it, 0, arg4, true);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// [BC] added newtid for next two
|
|
|
|
FUNC(LS_Thing_Spawn)
|
|
|
|
// Thing_Spawn (tid, type, angle, newtid)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Spawn (arg0, it, arg1, BYTEANGLE(arg2), true, arg3);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_SpawnNoFog)
|
|
|
|
// Thing_SpawnNoFog (tid, type, angle, newtid)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Spawn (arg0, it, arg1, BYTEANGLE(arg2), false, arg3);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_SpawnFacing)
|
|
|
|
// Thing_SpawnFacing (tid, type, nofog, newtid)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Spawn (arg0, it, arg1, ANGLE_MAX, arg2 ? false : true, arg3);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-06-03 12:30:11 +00:00
|
|
|
FUNC(LS_Thing_Raise)
|
|
|
|
// Thing_Raise(tid)
|
|
|
|
{
|
|
|
|
AActor * target;
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
if (arg0==0)
|
|
|
|
{
|
2009-07-13 22:07:18 +00:00
|
|
|
ok = P_Thing_Raise (it);
|
2006-06-03 12:30:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TActorIterator<AActor> iterator (arg0);
|
|
|
|
|
|
|
|
while ( (target = iterator.Next ()) )
|
|
|
|
{
|
2009-07-13 22:07:18 +00:00
|
|
|
ok |= P_Thing_Raise(target);
|
2006-06-03 12:30:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2007-04-22 21:01:35 +00:00
|
|
|
FUNC(LS_Thing_Stop)
|
|
|
|
// Thing_Stop(tid)
|
|
|
|
{
|
|
|
|
AActor * target;
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
if (arg0==0)
|
|
|
|
{
|
|
|
|
if (it != NULL)
|
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
it->velx = it->vely = it->velz = 0;
|
|
|
|
if (it->player != NULL) it->player->velx = it->player->vely = 0;
|
2007-04-22 21:01:35 +00:00
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TActorIterator<AActor> iterator (arg0);
|
|
|
|
|
|
|
|
while ( (target = iterator.Next ()) )
|
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
target->velx = target->vely = target->velz = 0;
|
|
|
|
if (target->player != NULL) target->player->velx = target->player->vely = 0;
|
2007-04-22 21:01:35 +00:00
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_Thing_SetGoal)
|
2006-05-13 12:41:15 +00:00
|
|
|
// Thing_SetGoal (tid, goal, delay, chasegoal)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
TActorIterator<AActor> selfiterator (arg0);
|
2006-12-02 15:38:50 +00:00
|
|
|
NActorIterator goaliterator (NAME_PatrolPoint, arg1);
|
2006-02-24 04:48:15 +00:00
|
|
|
AActor *self;
|
2006-12-02 15:38:50 +00:00
|
|
|
AActor *goal = goaliterator.Next ();
|
2006-02-24 04:48:15 +00:00
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
while ( (self = selfiterator.Next ()) )
|
|
|
|
{
|
|
|
|
ok = true;
|
|
|
|
if (self->flags & MF_SHOOTABLE)
|
|
|
|
{
|
|
|
|
self->goal = goal;
|
2006-05-13 12:41:15 +00:00
|
|
|
if (arg3 == 0) self->flags5 &=~ MF5_CHASEGOAL;
|
2006-05-18 15:03:35 +00:00
|
|
|
else self->flags5 |= MF5_CHASEGOAL;
|
2006-05-13 12:41:15 +00:00
|
|
|
if (self->target == NULL)
|
|
|
|
{
|
2006-02-24 04:48:15 +00:00
|
|
|
self->reactiontime = arg2 * TICRATE;
|
2006-05-13 12:41:15 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_Move) // [BC]
|
2006-04-11 08:36:23 +00:00
|
|
|
// Thing_Move (tid, mapspot, nofog)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
return P_Thing_Move (arg0, it, arg1, arg2 ? false : true);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Thing_SetTranslation)
|
|
|
|
// Thing_SetTranslation (tid, range)
|
|
|
|
{
|
|
|
|
TActorIterator<AActor> iterator (arg0);
|
2008-01-08 01:08:27 +00:00
|
|
|
int range;
|
2006-02-24 04:48:15 +00:00
|
|
|
AActor *target;
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
if (arg1 == -1 && it != NULL)
|
|
|
|
{
|
|
|
|
range = it->Translation;
|
|
|
|
}
|
|
|
|
else if (arg1 >= 1 && arg1 < MAX_ACS_TRANSLATIONS)
|
|
|
|
{
|
2007-12-26 16:06:03 +00:00
|
|
|
range = TRANSLATION(TRANSLATION_LevelScripted, (arg1-1));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
range = 0;
|
|
|
|
}
|
|
|
|
|
2008-02-14 15:40:46 +00:00
|
|
|
if (arg0 == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-02-14 15:48:31 +00:00
|
|
|
if (it != NULL)
|
|
|
|
{
|
|
|
|
ok = true;
|
|
|
|
it->Translation = range==0? it->GetDefault()->Translation : range;
|
|
|
|
}
|
2008-02-14 15:40:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while ( (target = iterator.Next ()) )
|
|
|
|
{
|
|
|
|
ok = true;
|
|
|
|
target->Translation = range==0? target->GetDefault()->Translation : range;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_Execute)
|
|
|
|
// ACS_Execute (script, map, s_arg1, s_arg2, s_arg3)
|
|
|
|
{
|
|
|
|
level_info_t *info;
|
|
|
|
|
2008-06-10 09:16:01 +00:00
|
|
|
if (arg1 == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
return P_StartScript (it, ln, arg0, level.mapname, backSide, arg2, arg3, arg4, false, false);
|
2008-06-10 09:16:01 +00:00
|
|
|
else if ((info = FindLevelByNum (arg1)) )
|
2006-02-24 04:48:15 +00:00
|
|
|
return P_StartScript (it, ln, arg0, info->mapname, backSide, arg2, arg3, arg4, false, false);
|
2008-06-10 09:16:01 +00:00
|
|
|
else return false;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_ExecuteAlways)
|
|
|
|
// ACS_ExecuteAlways (script, map, s_arg1, s_arg2, s_arg3)
|
|
|
|
{
|
|
|
|
level_info_t *info;
|
|
|
|
|
2008-06-10 09:16:01 +00:00
|
|
|
if (arg1 == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
return P_StartScript (it, ln, arg0, level.mapname, backSide, arg2, arg3, arg4, true, false);
|
2008-06-10 09:16:01 +00:00
|
|
|
else if ((info = FindLevelByNum (arg1)) )
|
2006-02-24 04:48:15 +00:00
|
|
|
return P_StartScript (it, ln, arg0, info->mapname, backSide, arg2, arg3, arg4, true, false);
|
2008-06-10 09:16:01 +00:00
|
|
|
else return false;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_LockedExecute)
|
|
|
|
// ACS_LockedExecute (script, map, s_arg1, s_arg2, lock)
|
|
|
|
{
|
2006-05-07 00:27:22 +00:00
|
|
|
if (arg4 && !P_CheckKeys (it, arg4, true))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return LS_ACS_Execute (ln, it, backSide, arg0, arg1, arg2, arg3, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_LockedExecuteDoor)
|
|
|
|
// ACS_LockedExecuteDoor (script, map, s_arg1, s_arg2, lock)
|
|
|
|
{
|
|
|
|
if (arg4 && !P_CheckKeys (it, arg4, false))
|
2006-02-24 04:48:15 +00:00
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return LS_ACS_Execute (ln, it, backSide, arg0, arg1, arg2, arg3, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_ExecuteWithResult)
|
|
|
|
// ACS_ExecuteWithResult (script, s_arg1, s_arg2, s_arg3)
|
|
|
|
{
|
|
|
|
// This is like ACS_ExecuteAlways, except the script is always run on
|
|
|
|
// the current map, and the return value is whatever the script sets
|
|
|
|
// with SetResultValue.
|
|
|
|
return P_StartScript (it, ln, arg0, level.mapname, backSide, arg1, arg2, arg3, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_Suspend)
|
|
|
|
// ACS_Suspend (script, map)
|
|
|
|
{
|
|
|
|
level_info_t *info;
|
|
|
|
|
2008-06-10 09:16:01 +00:00
|
|
|
if (arg1 == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
P_SuspendScript (arg0, level.mapname);
|
2008-06-10 09:16:01 +00:00
|
|
|
else if ((info = FindLevelByNum (arg1)) )
|
2006-02-24 04:48:15 +00:00
|
|
|
P_SuspendScript (arg0, info->mapname);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ACS_Terminate)
|
|
|
|
// ACS_Terminate (script, map)
|
|
|
|
{
|
|
|
|
level_info_t *info;
|
|
|
|
|
2008-06-10 09:16:01 +00:00
|
|
|
if (arg1 == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
P_TerminateScript (arg0, level.mapname);
|
2008-06-10 09:16:01 +00:00
|
|
|
else if ((info = FindLevelByNum (arg1)) )
|
2006-02-24 04:48:15 +00:00
|
|
|
P_TerminateScript (arg0, info->mapname);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_FloorAndCeiling_LowerByValue)
|
|
|
|
// FloorAndCeiling_LowerByValue (tag, speed, height)
|
|
|
|
{
|
|
|
|
return EV_DoElevator (ln, DElevator::elevateLower, SPEED(arg1), arg2*FRACUNIT, arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_FloorAndCeiling_RaiseByValue)
|
|
|
|
// FloorAndCeiling_RaiseByValue (tag, speed, height)
|
|
|
|
{
|
|
|
|
return EV_DoElevator (ln, DElevator::elevateRaise, SPEED(arg1), arg2*FRACUNIT, arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_FloorAndCeiling_LowerRaise)
|
2010-11-10 11:25:34 +00:00
|
|
|
// FloorAndCeiling_LowerRaise (tag, fspeed, cspeed, boomemu)
|
|
|
|
{
|
|
|
|
bool res = EV_DoCeiling (DCeiling::ceilRaiseToHighest, ln, arg0, SPEED(arg2), 0, 0, 0, 0, 0, false);
|
|
|
|
// The switch based Boom equivalents of FloorandCeiling_LowerRaise do incorrect checks
|
|
|
|
// which cause the floor only to move when the ceiling fails to do so.
|
|
|
|
// To avoid problems with maps that have incorrect args this only uses a
|
|
|
|
// more or less unintuitive value for the fourth arg to trigger Boom's broken behavior
|
|
|
|
if (arg3 != 1998 || !res) // (1998 for the year in which Boom was released... :P)
|
|
|
|
{
|
|
|
|
res |= EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, false);
|
|
|
|
}
|
|
|
|
return res;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Elevator_MoveToFloor)
|
|
|
|
// Elevator_MoveToFloor (tag, speed)
|
|
|
|
{
|
|
|
|
return EV_DoElevator (ln, DElevator::elevateCurrent, SPEED(arg1), 0, arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Elevator_RaiseToNearest)
|
|
|
|
// Elevator_RaiseToNearest (tag, speed)
|
|
|
|
{
|
|
|
|
return EV_DoElevator (ln, DElevator::elevateUp, SPEED(arg1), 0, arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Elevator_LowerToNearest)
|
|
|
|
// Elevator_LowerToNearest (tag, speed)
|
|
|
|
{
|
|
|
|
return EV_DoElevator (ln, DElevator::elevateDown, SPEED(arg1), 0, arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Light_ForceLightning)
|
2008-03-22 12:41:36 +00:00
|
|
|
// Light_ForceLightning (mode)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-22 12:41:36 +00:00
|
|
|
P_ForceLightning (arg0);
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_Light_Stop)
|
|
|
|
// Light_Stop (tag)
|
|
|
|
{
|
|
|
|
EV_StopLightEffect (arg0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Radius_Quake)
|
|
|
|
// Radius_Quake (intensity, duration, damrad, tremrad, tid)
|
|
|
|
{
|
2009-10-15 08:25:07 +00:00
|
|
|
return P_StartQuake (it, arg4, arg0, arg1, arg2*64, arg3*64, "world/quake");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_UsePuzzleItem)
|
|
|
|
// UsePuzzleItem (item, script)
|
|
|
|
{
|
|
|
|
AInventory *item;
|
|
|
|
|
|
|
|
if (!it) return false;
|
|
|
|
|
|
|
|
// Check player's inventory for puzzle item
|
|
|
|
for (item = it->Inventory; item != NULL; item = item->Inventory)
|
|
|
|
{
|
|
|
|
if (item->IsKindOf (RUNTIME_CLASS(APuzzleItem)))
|
|
|
|
{
|
|
|
|
if (static_cast<APuzzleItem*>(item)->PuzzleItemNumber == arg0)
|
|
|
|
{
|
|
|
|
if (it->UseInventory (item))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// [RH] Say "hmm" if you don't have the puzzle item
|
|
|
|
S_Sound (it, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-05-11 21:16:32 +00:00
|
|
|
FUNC(LS_Sector_ChangeFlags)
|
|
|
|
// Sector_ChangeFlags (tag, set, clear)
|
|
|
|
{
|
|
|
|
int secNum;
|
|
|
|
bool rtn;
|
|
|
|
|
|
|
|
if (!arg0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
secNum = -1;
|
|
|
|
rtn = false;
|
|
|
|
while ((secNum = P_FindSectorFromTag (arg0, secNum)) >= 0)
|
|
|
|
{
|
|
|
|
sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2;
|
|
|
|
rtn = true;
|
|
|
|
}
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t 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)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < numcollected; i++)
|
|
|
|
{
|
2010-11-03 23:27:31 +00:00
|
|
|
if (Collection[i].RefNum == sectors[secnum].sectornum)
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == numcollected)
|
|
|
|
{
|
|
|
|
new DPusher (type, NULL, magnitude, angle, NULL, secnum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Collection.Clear ();
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Sector_SetWind)
|
|
|
|
// Sector_SetWind (tag, amount, angle)
|
|
|
|
{
|
2010-01-30 14:35:52 +00:00
|
|
|
if (arg3)
|
2006-02-24 04:48:15 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
AdjustPusher (arg0, arg1, arg2, DPusher::p_wind);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Sector_SetCurrent)
|
|
|
|
// Sector_SetCurrent (tag, amount, angle)
|
|
|
|
{
|
2010-01-30 14:35:52 +00:00
|
|
|
if (arg3)
|
2006-02-24 04:48:15 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
AdjustPusher (arg0, arg1, arg2, DPusher::p_current);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Sector_SetFriction)
|
|
|
|
// Sector_SetFriction (tag, amount)
|
|
|
|
{
|
|
|
|
P_SetSectorFriction (arg0, arg1, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-03-20 21:12:03 +00:00
|
|
|
FUNC(LS_Sector_SetLink)
|
|
|
|
// Sector_SetLink (controltag, linktag, floor/ceiling, movetype)
|
|
|
|
{
|
|
|
|
if (arg0 != 0) // control tag == 0 is for static initialization and must not be handled here
|
|
|
|
{
|
|
|
|
int control = P_FindSectorFromTag(arg0, -1);
|
|
|
|
if (control != 0)
|
|
|
|
{
|
|
|
|
return P_AddSectorLinks(§ors[control], arg1, arg2, arg3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-21 17:35:49 +00:00
|
|
|
static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int Where)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-21 17:35:49 +00:00
|
|
|
Where &=7;
|
|
|
|
if (Where == 0) return;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
if ((dx | dy) == 0)
|
|
|
|
{
|
|
|
|
// Special case: Remove the scroller, because the deltas are both 0.
|
|
|
|
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
|
|
|
|
DScroller *scroller;
|
|
|
|
|
|
|
|
while ( (scroller = iterator.Next ()) )
|
|
|
|
{
|
|
|
|
int wallnum = scroller->GetWallNum ();
|
|
|
|
|
2009-09-06 18:19:28 +00:00
|
|
|
if (wallnum >= 0 && sides[wallnum].linedef->id == id &&
|
2009-09-06 20:45:56 +00:00
|
|
|
int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum &&
|
2008-03-21 17:35:49 +00:00
|
|
|
Where == scroller->GetScrollParts())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
scroller->Destroy ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Find scrollers already attached to the matching walls, and change
|
|
|
|
// their rates.
|
|
|
|
{
|
|
|
|
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
|
|
|
|
FThinkerCollection collect;
|
|
|
|
|
|
|
|
while ( (collect.Obj = iterator.Next ()) )
|
|
|
|
{
|
|
|
|
if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 &&
|
2009-09-06 18:19:28 +00:00
|
|
|
sides[collect.RefNum].linedef->id == id &&
|
2009-09-06 20:45:56 +00:00
|
|
|
int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum &&
|
2008-03-21 17:35:49 +00:00
|
|
|
Where == ((DScroller *)collect.Obj)->GetScrollParts())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
((DScroller *)collect.Obj)->SetRate (dx, dy);
|
|
|
|
Collection.Push (collect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t numcollected = Collection.Size ();
|
|
|
|
int linenum = -1;
|
|
|
|
|
|
|
|
// Now create scrollers for any walls that don't already have them.
|
|
|
|
while ((linenum = P_FindLineFromID (id, linenum)) >= 0)
|
|
|
|
{
|
2009-09-06 20:45:56 +00:00
|
|
|
if (lines[linenum].sidedef[sidechoice] != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-09-06 20:45:56 +00:00
|
|
|
int sidenum = int(lines[linenum].sidedef[sidechoice] - sides);
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < numcollected; i++)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-09-06 20:45:56 +00:00
|
|
|
if (Collection[i].RefNum == sidenum)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == numcollected)
|
|
|
|
{
|
|
|
|
new DScroller (DScroller::sc_side, dx, dy, -1, sidenum, 0, Where);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Collection.Clear ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-03-21 17:35:49 +00:00
|
|
|
SetWallScroller (arg0, sidechoice, dx, dy, 7);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Scroll_Wall)
|
|
|
|
// Scroll_Wall (id, x, y, side, flags)
|
|
|
|
{
|
|
|
|
if (arg0 == 0)
|
|
|
|
return false;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-21 17:35:49 +00:00
|
|
|
SetWallScroller (arg0, !!arg3, arg1, arg2, arg4);
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed_t dy)
|
|
|
|
{
|
|
|
|
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
|
|
|
|
DScroller *scroller;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Check if there is already a scroller for this tag
|
|
|
|
// If at least one sector with this tag is scrolling, then they all are.
|
|
|
|
// If the deltas are both 0, we don't remove the scroller, because a
|
|
|
|
// displacement/accelerative scroller might have been set up, and there's
|
|
|
|
// no way to create one after the level is fully loaded.
|
|
|
|
i = 0;
|
|
|
|
while ( (scroller = iterator.Next ()) )
|
|
|
|
{
|
|
|
|
if (scroller->IsType (type))
|
|
|
|
{
|
|
|
|
if (sectors[scroller->GetAffectee ()].tag == tag)
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
scroller->SetRate (dx, dy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0 || (dx|dy) == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to create scrollers for the sector(s)
|
|
|
|
for (i = -1; (i = P_FindSectorFromTag (tag, i)) >= 0; )
|
|
|
|
{
|
|
|
|
new DScroller (type, dx, dy, -1, i, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: For the next two functions, x-move and y-move are
|
|
|
|
// 0-based, not 128-based as they are if they appear on lines.
|
|
|
|
// Note also that parameter ordering is different.
|
|
|
|
|
|
|
|
FUNC(LS_Scroll_Floor)
|
|
|
|
// Scroll_Floor (tag, x-move, y-move, s/c)
|
|
|
|
{
|
|
|
|
fixed_t dx = arg1 * FRACUNIT/32;
|
|
|
|
fixed_t dy = arg2 * FRACUNIT/32;
|
|
|
|
|
|
|
|
if (arg3 == 0 || arg3 == 2)
|
|
|
|
{
|
|
|
|
SetScroller (arg0, DScroller::sc_floor, -dx, dy);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetScroller (arg0, DScroller::sc_floor, 0, 0);
|
|
|
|
}
|
|
|
|
if (arg3 > 0)
|
|
|
|
{
|
|
|
|
SetScroller (arg0, DScroller::sc_carry, dx, dy);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetScroller (arg0, DScroller::sc_carry, 0, 0);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Scroll_Ceiling)
|
|
|
|
// Scroll_Ceiling (tag, x-move, y-move, 0)
|
|
|
|
{
|
|
|
|
fixed_t dx = arg1 * FRACUNIT/32;
|
|
|
|
fixed_t dy = arg2 * FRACUNIT/32;
|
|
|
|
|
|
|
|
SetScroller (arg0, DScroller::sc_ceiling, -dx, dy);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_PointPush_SetForce)
|
|
|
|
// PointPush_SetForce ()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Sector_SetDamage)
|
|
|
|
// Sector_SetDamage (tag, amount, mod)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
// The sector still stores the mod in its old format because
|
|
|
|
// adding an FName to the sector_t structure might cause
|
|
|
|
// problems by adding an unwanted constructor.
|
|
|
|
// Since it doesn't really matter whether the type is translated
|
|
|
|
// here or in P_PlayerInSpecialSector I think it's the best solution.
|
2006-02-24 04:48:15 +00:00
|
|
|
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, desaturate)
|
|
|
|
{
|
|
|
|
int secnum = -1;
|
|
|
|
|
|
|
|
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
|
|
|
|
{
|
2007-10-29 22:15:46 +00:00
|
|
|
sectors[secnum].SetColor(arg1, arg2, arg3, arg4);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Sector_SetFade)
|
|
|
|
// Sector_SetFade (tag, r, g, b)
|
|
|
|
{
|
|
|
|
int secnum = -1;
|
|
|
|
|
|
|
|
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
|
|
|
|
{
|
2007-10-29 22:15:46 +00:00
|
|
|
sectors[secnum].SetFade(arg1, arg2, arg3);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2008-06-14 15:26:16 +00:00
|
|
|
sectors[secnum].SetXOffset(sector_t::ceiling, xofs);
|
|
|
|
sectors[secnum].SetYOffset(sector_t::ceiling, yofs);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2008-06-14 15:26:16 +00:00
|
|
|
sectors[secnum].SetXOffset(sector_t::floor, xofs);
|
|
|
|
sectors[secnum].SetYOffset(sector_t::floor, yofs);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:42:07 +00:00
|
|
|
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].SetXScale(sector_t::floor, xscale);
|
|
|
|
if (yscale)
|
|
|
|
sectors[secnum].SetYScale(sector_t::floor, yscale);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
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)
|
2008-06-29 08:42:07 +00:00
|
|
|
sectors[secnum].SetXScale(sector_t::ceiling, xscale);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (yscale)
|
2008-06-29 08:42:07 +00:00
|
|
|
sectors[secnum].SetYScale(sector_t::ceiling, yscale);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-10-05 20:32:16 +00:00
|
|
|
FUNC(LS_Sector_SetFloorScale2)
|
|
|
|
// Sector_SetFloorScale2 (tag, x-factor, y-factor)
|
|
|
|
{
|
|
|
|
int secnum = -1;
|
|
|
|
|
|
|
|
if (arg1)
|
|
|
|
arg1 = FixedDiv (FRACUNIT, arg1);
|
|
|
|
if (arg2)
|
|
|
|
arg2 = FixedDiv (FRACUNIT, arg2);
|
|
|
|
|
|
|
|
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
|
|
|
|
{
|
|
|
|
if (arg1)
|
2008-06-14 15:26:16 +00:00
|
|
|
sectors[secnum].SetXScale(sector_t::floor, arg1);
|
2006-10-05 20:32:16 +00:00
|
|
|
if (arg2)
|
2008-06-29 08:42:07 +00:00
|
|
|
sectors[secnum].SetYScale(sector_t::floor, arg2);
|
2006-10-05 20:32:16 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Sector_SetCeilingScale2)
|
|
|
|
// Sector_SetFloorScale2 (tag, x-factor, y-factor)
|
|
|
|
{
|
|
|
|
int secnum = -1;
|
|
|
|
|
|
|
|
if (arg1)
|
|
|
|
arg1 = FixedDiv (FRACUNIT, arg1);
|
|
|
|
if (arg2)
|
|
|
|
arg2 = FixedDiv (FRACUNIT, arg2);
|
|
|
|
|
|
|
|
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
|
|
|
|
{
|
|
|
|
if (arg1)
|
2008-06-14 15:26:16 +00:00
|
|
|
sectors[secnum].SetXScale(sector_t::ceiling, arg1);
|
2006-10-05 20:32:16 +00:00
|
|
|
if (arg2)
|
2008-06-29 08:42:07 +00:00
|
|
|
sectors[secnum].SetYScale(sector_t::ceiling, arg2);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2008-06-14 15:26:16 +00:00
|
|
|
sectors[secnum].SetAngle(sector_t::floor, floor);
|
|
|
|
sectors[secnum].SetAngle(sector_t::ceiling, ceiling);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-03-22 17:20:54 +00:00
|
|
|
FUNC(LS_Line_SetTextureOffset)
|
|
|
|
// Line_SetTextureOffset (id, x, y, side, flags)
|
|
|
|
{
|
|
|
|
const fixed_t NO_CHANGE = 32767<<FRACBITS;
|
|
|
|
|
|
|
|
if (arg0 == 0 || arg3 < 0 || arg3 > 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for(int line = -1; (line = P_FindLineFromID (arg0, line)) >= 0; )
|
|
|
|
{
|
2009-09-06 20:45:56 +00:00
|
|
|
side_t *side = lines[line].sidedef[arg3];
|
|
|
|
if (side != NULL)
|
2008-03-22 17:20:54 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if ((arg4&8)==0)
|
|
|
|
{
|
|
|
|
// set
|
|
|
|
if (arg1 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->SetTextureXOffset(side_t::top, arg1);
|
|
|
|
if (arg4&2) side->SetTextureXOffset(side_t::mid, arg1);
|
|
|
|
if (arg4&4) side->SetTextureXOffset(side_t::bottom, arg1);
|
|
|
|
}
|
|
|
|
if (arg2 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->SetTextureYOffset(side_t::top, arg2);
|
|
|
|
if (arg4&2) side->SetTextureYOffset(side_t::mid, arg2);
|
|
|
|
if (arg4&4) side->SetTextureYOffset(side_t::bottom, arg2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// add
|
|
|
|
if (arg1 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->AddTextureXOffset(side_t::top, arg1);
|
|
|
|
if (arg4&2) side->AddTextureXOffset(side_t::mid, arg1);
|
|
|
|
if (arg4&4) side->AddTextureXOffset(side_t::bottom, arg1);
|
|
|
|
}
|
|
|
|
if (arg2 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->AddTextureYOffset(side_t::top, arg2);
|
|
|
|
if (arg4&2) side->AddTextureYOffset(side_t::mid, arg2);
|
|
|
|
if (arg4&4) side->AddTextureYOffset(side_t::bottom, arg2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-06-08 23:49:27 +00:00
|
|
|
FUNC(LS_Line_SetTextureScale)
|
|
|
|
// Line_SetTextureScale (id, x, y, side, flags)
|
|
|
|
{
|
|
|
|
const fixed_t NO_CHANGE = 32767<<FRACBITS;
|
|
|
|
|
|
|
|
if (arg0 == 0 || arg3 < 0 || arg3 > 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for(int line = -1; (line = P_FindLineFromID (arg0, line)) >= 0; )
|
|
|
|
{
|
2009-09-06 20:45:56 +00:00
|
|
|
side_t *side = lines[line].sidedef[arg3];
|
|
|
|
if (side != NULL)
|
2009-06-08 23:49:27 +00:00
|
|
|
{
|
|
|
|
if ((arg4&8)==0)
|
|
|
|
{
|
|
|
|
// set
|
|
|
|
if (arg1 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->SetTextureXScale(side_t::top, arg1);
|
|
|
|
if (arg4&2) side->SetTextureXScale(side_t::mid, arg1);
|
|
|
|
if (arg4&4) side->SetTextureXScale(side_t::bottom, arg1);
|
|
|
|
}
|
|
|
|
if (arg2 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->SetTextureYScale(side_t::top, arg2);
|
|
|
|
if (arg4&2) side->SetTextureYScale(side_t::mid, arg2);
|
|
|
|
if (arg4&4) side->SetTextureYScale(side_t::bottom, arg2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// add
|
|
|
|
if (arg1 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->MultiplyTextureXScale(side_t::top, arg1);
|
|
|
|
if (arg4&2) side->MultiplyTextureXScale(side_t::mid, arg1);
|
|
|
|
if (arg4&4) side->MultiplyTextureXScale(side_t::bottom, arg1);
|
|
|
|
}
|
|
|
|
if (arg2 != NO_CHANGE)
|
|
|
|
{
|
|
|
|
if (arg4&1) side->MultiplyTextureYScale(side_t::top, arg2);
|
|
|
|
if (arg4&2) side->MultiplyTextureYScale(side_t::mid, arg2);
|
|
|
|
if (arg4&4) side->MultiplyTextureYScale(side_t::bottom, arg2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-02-22 15:39:42 +00:00
|
|
|
FUNC(LS_Line_SetBlocking)
|
|
|
|
// Line_SetBlocking (id, setflags, clearflags)
|
|
|
|
{
|
|
|
|
static const int flagtrans[] =
|
|
|
|
{
|
|
|
|
ML_BLOCKING,
|
|
|
|
ML_BLOCKMONSTERS,
|
|
|
|
ML_BLOCK_PLAYERS,
|
|
|
|
ML_BLOCK_FLOATERS,
|
|
|
|
ML_BLOCKPROJECTILE,
|
|
|
|
ML_BLOCKEVERYTHING,
|
|
|
|
ML_RAILING,
|
2009-04-28 20:53:07 +00:00
|
|
|
ML_BLOCKUSE,
|
2011-01-23 10:52:18 +00:00
|
|
|
ML_BLOCKSIGHT,
|
2009-02-22 15:39:42 +00:00
|
|
|
-1
|
|
|
|
};
|
|
|
|
|
|
|
|
if (arg0 == 0) return false;
|
|
|
|
|
|
|
|
int setflags = 0;
|
|
|
|
int clearflags = 0;
|
|
|
|
|
|
|
|
for(int i = 0; flagtrans[i] != -1; i++, arg1 >>= 1, arg2 >>= 1)
|
|
|
|
{
|
|
|
|
if (arg1 & 1) setflags |= flagtrans[i];
|
|
|
|
if (arg2 & 1) clearflags |= flagtrans[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int line = -1; (line = P_FindLineFromID (arg0, line)) >= 0; )
|
|
|
|
{
|
|
|
|
lines[line].flags = (lines[line].flags & ~clearflags) | setflags;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-03-22 17:20:54 +00:00
|
|
|
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
FUNC(LS_ChangeCamera)
|
|
|
|
// ChangeCamera (tid, who, revert?)
|
|
|
|
{
|
|
|
|
AActor *camera;
|
|
|
|
if (arg0 != 0)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
camera = iterator.Next ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
camera = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!it || !it->player || arg1)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
|
|
{
|
|
|
|
if (!playeringame[i])
|
|
|
|
continue;
|
|
|
|
|
2007-02-04 01:12:50 +00:00
|
|
|
AActor *oldcamera = players[i].camera;
|
2006-02-24 04:48:15 +00:00
|
|
|
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;
|
|
|
|
}
|
2007-02-04 01:12:50 +00:00
|
|
|
if (oldcamera != players[i].camera)
|
|
|
|
{
|
|
|
|
R_ClearPastViewer (players[i].camera);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-02-04 01:12:50 +00:00
|
|
|
AActor *oldcamera = it->player->camera;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (camera)
|
|
|
|
{
|
|
|
|
it->player->camera = camera;
|
|
|
|
if (arg2)
|
|
|
|
it->player->cheats |= CF_REVERTPLEASE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
it->player->camera = it;
|
|
|
|
it->player->cheats &= ~CF_REVERTPLEASE;
|
|
|
|
}
|
2007-02-04 01:12:50 +00:00
|
|
|
if (oldcamera != it->player->camera)
|
|
|
|
{
|
|
|
|
R_ClearPastViewer (it->player->camera);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_FROZEN,
|
|
|
|
PROP_NOTARGET,
|
|
|
|
PROP_INSTANTWEAPONSWITCH,
|
|
|
|
PROP_FLY,
|
|
|
|
PROP_TOTALLYFROZEN,
|
|
|
|
|
|
|
|
PROP_INVULNERABILITY,
|
|
|
|
PROP_STRENGTH,
|
|
|
|
PROP_INVISIBILITY,
|
|
|
|
PROP_RADIATIONSUIT,
|
|
|
|
PROP_ALLMAP,
|
|
|
|
PROP_INFRARED,
|
|
|
|
PROP_WEAPONLEVEL2,
|
|
|
|
PROP_FLIGHT,
|
|
|
|
PROP_UNUSED1,
|
|
|
|
PROP_UNUSED2,
|
|
|
|
PROP_SPEED,
|
2010-01-24 08:41:40 +00:00
|
|
|
PROP_BUDDHA,
|
2006-02-24 04:48:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
FUNC(LS_SetPlayerProperty)
|
2008-09-13 02:55:45 +00:00
|
|
|
// SetPlayerProperty (who, value, which)
|
|
|
|
// who == 0: set activator's property
|
|
|
|
// who == 1: set every player's property
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
int mask = 0;
|
|
|
|
|
|
|
|
if ((!it || !it->player) && !arg0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Add or remove a power
|
|
|
|
if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
static const PClass *powers[11] =
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
RUNTIME_CLASS(APowerInvulnerable),
|
|
|
|
RUNTIME_CLASS(APowerStrength),
|
|
|
|
RUNTIME_CLASS(APowerInvisibility),
|
|
|
|
RUNTIME_CLASS(APowerIronFeet),
|
|
|
|
NULL, // MapRevealer
|
|
|
|
RUNTIME_CLASS(APowerLightAmp),
|
|
|
|
RUNTIME_CLASS(APowerWeaponLevel2),
|
|
|
|
RUNTIME_CLASS(APowerFlight),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
RUNTIME_CLASS(APowerSpeed)
|
|
|
|
};
|
|
|
|
int power = arg2 - PROP_INVULNERABILITY;
|
|
|
|
|
|
|
|
if (power > 4 && powers[power] == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg0 == 0)
|
|
|
|
{
|
|
|
|
if (arg1)
|
|
|
|
{ // Give power to activator
|
|
|
|
if (power != 4)
|
|
|
|
{
|
2008-08-06 19:25:59 +00:00
|
|
|
APowerup *item = static_cast<APowerup*>(it->GiveInventoryType (powers[power]));
|
2009-09-21 13:15:36 +00:00
|
|
|
if (item != NULL && power == 0 && arg1 == 1)
|
|
|
|
{
|
|
|
|
item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (it->player - players == consoleplayer)
|
|
|
|
{
|
2009-02-03 19:11:43 +00:00
|
|
|
level.flags2 |= LEVEL2_ALLMAP;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Take power from activator
|
|
|
|
if (power != 4)
|
|
|
|
{
|
|
|
|
AInventory *item = it->FindInventory (powers[power]);
|
|
|
|
if (item != NULL)
|
|
|
|
{
|
|
|
|
item->Destroy ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (it->player - players == consoleplayer)
|
|
|
|
{
|
2009-02-03 19:11:43 +00:00
|
|
|
level.flags2 &= ~LEVEL2_ALLMAP;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
|
|
{
|
|
|
|
if (!playeringame[i] || players[i].mo == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (arg1)
|
|
|
|
{ // Give power
|
|
|
|
if (power != 4)
|
|
|
|
{
|
2009-09-21 13:15:36 +00:00
|
|
|
APowerup *item = static_cast<APowerup*>(players[i].mo->GiveInventoryType (powers[power]));
|
|
|
|
if (item != NULL && power == 0 && arg1 == 1)
|
|
|
|
{
|
|
|
|
item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (i == consoleplayer)
|
|
|
|
{
|
2009-02-03 19:11:43 +00:00
|
|
|
level.flags2 |= LEVEL2_ALLMAP;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Take power
|
|
|
|
if (power != 4)
|
|
|
|
{
|
|
|
|
AInventory *item = players[i].mo->FindInventory (powers[power]);
|
|
|
|
if (item != NULL)
|
|
|
|
{
|
|
|
|
item->Destroy ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (i == consoleplayer)
|
|
|
|
{
|
2009-02-03 19:11:43 +00:00
|
|
|
level.flags2 &= ~LEVEL2_ALLMAP;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set or clear a flag
|
|
|
|
switch (arg2)
|
|
|
|
{
|
2010-01-24 08:41:40 +00:00
|
|
|
case PROP_BUDDHA:
|
|
|
|
mask = CF_BUDDHA;
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
case PROP_FROZEN:
|
|
|
|
mask = CF_FROZEN;
|
|
|
|
break;
|
|
|
|
case PROP_NOTARGET:
|
|
|
|
mask = CF_NOTARGET;
|
|
|
|
break;
|
|
|
|
case PROP_INSTANTWEAPONSWITCH:
|
|
|
|
mask = CF_INSTANTWEAPSWITCH;
|
|
|
|
break;
|
|
|
|
case PROP_FLY:
|
|
|
|
mask = CF_FLY;
|
|
|
|
break;
|
|
|
|
case PROP_TOTALLYFROZEN:
|
|
|
|
mask = CF_TOTALLYFROZEN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg0 == 0)
|
|
|
|
{
|
|
|
|
if (arg1)
|
|
|
|
{
|
|
|
|
it->player->cheats |= mask;
|
|
|
|
if (arg2 == PROP_FLY)
|
|
|
|
{
|
|
|
|
it->flags2 |= MF2_FLY;
|
|
|
|
it->flags |= MF_NOGRAVITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
it->player->cheats &= ~mask;
|
|
|
|
if (arg2 == PROP_FLY)
|
|
|
|
{
|
|
|
|
it->flags2 &= ~MF2_FLY;
|
|
|
|
it->flags &= ~MF_NOGRAVITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
|
|
{
|
|
|
|
if (!playeringame[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (arg1)
|
|
|
|
{
|
|
|
|
players[i].cheats |= mask;
|
|
|
|
if (arg2 == PROP_FLY)
|
|
|
|
{
|
|
|
|
players[i].mo->flags2 |= MF2_FLY;
|
|
|
|
players[i].mo->flags |= MF_NOGRAVITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
players[i].cheats &= ~mask;
|
|
|
|
if (arg2 == PROP_FLY)
|
|
|
|
{
|
|
|
|
players[i].mo->flags2 &= ~MF2_FLY;
|
|
|
|
players[i].mo->flags &= ~MF_NOGRAVITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return !!mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_TranslucentLine)
|
|
|
|
// TranslucentLine (id, amount, type)
|
|
|
|
{
|
|
|
|
int linenum = -1;
|
|
|
|
while ((linenum = P_FindLineFromID (arg0, linenum)) >= 0)
|
|
|
|
{
|
2008-05-02 10:55:48 +00:00
|
|
|
lines[linenum].Alpha = Scale(clamp(arg1, 0, 255), FRACUNIT, 255);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (arg2 == 0)
|
|
|
|
{
|
2008-05-30 06:56:50 +00:00
|
|
|
lines[linenum].flags &= ~ML_ADDTRANS;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (arg2 == 1)
|
|
|
|
{
|
2008-05-30 06:56:50 +00:00
|
|
|
lines[linenum].flags |= ML_ADDTRANS;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Printf ("Unknown translucency type used with TranslucentLine\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_Autosave)
|
|
|
|
{
|
|
|
|
if (gameaction != ga_savegame)
|
|
|
|
{
|
2010-12-16 09:13:06 +00:00
|
|
|
level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT;
|
2006-10-19 20:20:56 +00:00
|
|
|
Net_WriteByte (DEM_CHECKAUTOSAVE);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ChangeSkill)
|
|
|
|
{
|
2007-11-03 15:08:06 +00:00
|
|
|
if ((unsigned)arg0 >= AllSkills.Size())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
NextSkill = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NextSkill = arg0;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_NoiseAlert)
|
|
|
|
// NoiseAlert (TID of target, TID of emitter)
|
|
|
|
{
|
|
|
|
AActor *target, *emitter;
|
|
|
|
|
|
|
|
if (arg0 == 0)
|
|
|
|
{
|
|
|
|
target = it;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FActorIterator iter (arg0);
|
|
|
|
target = iter.Next();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 == 0)
|
|
|
|
{
|
|
|
|
emitter = it;
|
|
|
|
}
|
|
|
|
else if (arg1 == arg0)
|
|
|
|
{
|
|
|
|
emitter = target;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FActorIterator iter (arg1);
|
|
|
|
emitter = iter.Next();
|
|
|
|
}
|
|
|
|
|
|
|
|
P_NoiseAlert (target, emitter);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_SendToCommunicator)
|
|
|
|
// SendToCommunicator (voc #, front-only, identify, nolog)
|
|
|
|
{
|
|
|
|
// This obviously isn't going to work for co-op.
|
|
|
|
if (arg1 && backSide)
|
|
|
|
return false;
|
|
|
|
|
2006-12-25 13:43:11 +00:00
|
|
|
if (it != NULL && it->player != NULL && it->FindInventory(NAME_Communicator))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-12-25 13:43:11 +00:00
|
|
|
char name[32];
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf (name, countof(name), "svox/voc%d", arg0);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (!arg3)
|
|
|
|
{
|
|
|
|
it->player->SetLogNumber (arg0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (it->CheckLocalView (consoleplayer))
|
|
|
|
{
|
2008-07-01 04:06:56 +00:00
|
|
|
S_StopSound (CHAN_VOICE);
|
2006-02-24 04:48:15 +00:00
|
|
|
S_Sound (CHAN_VOICE, name, 1, ATTN_NORM);
|
|
|
|
if (arg2 == 0)
|
|
|
|
{
|
|
|
|
Printf (PRINT_CHAT, "Incoming Message\n");
|
|
|
|
}
|
|
|
|
else if (arg2 == 1)
|
|
|
|
{
|
|
|
|
Printf (PRINT_CHAT, "Incoming Message from BlackBird\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ForceField)
|
|
|
|
// ForceField ()
|
|
|
|
{
|
|
|
|
if (it != NULL)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (it, NULL, NULL, 16, NAME_None);
|
2009-09-25 03:07:20 +00:00
|
|
|
P_ThrustMobj (it, it->angle + ANGLE_180, 0x7D000);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_ClearForceField)
|
|
|
|
// ClearForceField (tag)
|
|
|
|
{
|
|
|
|
int secnum = -1;
|
|
|
|
bool rtn = false;
|
|
|
|
|
|
|
|
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
|
|
|
|
{
|
|
|
|
sector_t *sec = §ors[secnum];
|
|
|
|
rtn = true;
|
|
|
|
|
|
|
|
for (int i = 0; i < sec->linecount; ++i)
|
|
|
|
{
|
|
|
|
line_t *line = sec->lines[i];
|
|
|
|
if (line->backsector != NULL && line->special == ForceField)
|
|
|
|
{
|
|
|
|
line->flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING);
|
|
|
|
line->special = 0;
|
2009-09-06 20:45:56 +00:00
|
|
|
line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID());
|
|
|
|
line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC(LS_GlassBreak)
|
|
|
|
// GlassBreak (bNoJunk)
|
|
|
|
{
|
|
|
|
bool switched;
|
|
|
|
bool quest1, quest2;
|
|
|
|
|
|
|
|
ln->flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING);
|
2009-09-06 20:45:56 +00:00
|
|
|
switched = P_ChangeSwitchTexture (ln->sidedef[0], false, 0, &quest1);
|
2006-02-24 04:48:15 +00:00
|
|
|
ln->special = 0;
|
2009-09-06 20:45:56 +00:00
|
|
|
if (ln->sidedef[1] != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-09-06 20:45:56 +00:00
|
|
|
switched |= P_ChangeSwitchTexture (ln->sidedef[1], false, 0, &quest2);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
quest2 = quest1;
|
|
|
|
}
|
|
|
|
if (switched)
|
|
|
|
{
|
|
|
|
if (!arg0)
|
|
|
|
{ // Break some glass
|
|
|
|
fixed_t x, y;
|
|
|
|
AActor *glass;
|
|
|
|
angle_t an;
|
|
|
|
int speed;
|
|
|
|
|
|
|
|
x = ln->v1->x + ln->dx/2;
|
|
|
|
y = ln->v1->y + ln->dy/2;
|
|
|
|
x += (ln->frontsector->soundorg[0] - x) / 5;
|
|
|
|
y += (ln->frontsector->soundorg[1] - y) / 5;
|
|
|
|
|
|
|
|
for (int i = 0; i < 7; ++i)
|
|
|
|
{
|
2006-07-31 10:22:53 +00:00
|
|
|
glass = Spawn("GlassJunk", x, y, ONFLOORZ, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
glass->z += 24 * FRACUNIT;
|
2006-07-31 10:22:53 +00:00
|
|
|
glass->SetState (glass->SpawnState + (pr_glass() % glass->health));
|
2006-02-24 04:48:15 +00:00
|
|
|
an = pr_glass() << (32-8);
|
|
|
|
glass->angle = an;
|
|
|
|
an >>= ANGLETOFINESHIFT;
|
|
|
|
speed = pr_glass() & 3;
|
2009-06-30 20:57:51 +00:00
|
|
|
glass->velx = finecosine[an] * speed;
|
|
|
|
glass->vely = finesine[an] * speed;
|
|
|
|
glass->velz = (pr_glass() & 7) << FRACBITS;
|
2006-02-24 04:48:15 +00:00
|
|
|
// [RH] Let the shards stick around longer than they did in Strife.
|
|
|
|
glass->tics += pr_glass();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (quest1 || quest2)
|
|
|
|
{ // Up stats and signal this mission is complete
|
|
|
|
if (it == NULL)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
|
|
|
{
|
|
|
|
if (playeringame[i])
|
|
|
|
{
|
|
|
|
it = players[i].mo;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (it != NULL)
|
|
|
|
{
|
|
|
|
it->GiveInventoryType (QuestItemClasses[28]);
|
|
|
|
it->GiveInventoryType (RUNTIME_CLASS(AUpgradeAccuracy));
|
|
|
|
it->GiveInventoryType (RUNTIME_CLASS(AUpgradeStamina));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We already changed the switch texture, so don't make the main code switch it back.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-06-03 12:30:11 +00:00
|
|
|
FUNC(LS_StartConversation)
|
|
|
|
// StartConversation (tid, facetalker)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
|
|
|
|
AActor *target = iterator.Next();
|
|
|
|
|
2006-06-04 14:49:17 +00:00
|
|
|
// Nothing to talk to
|
|
|
|
if (target == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-06-03 12:30:11 +00:00
|
|
|
// Only living players are allowed to start conversations
|
|
|
|
if (it == NULL || it->player == NULL || it->player->mo != it || it->health<=0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dead things can't talk.
|
|
|
|
if (target->health <= 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Fighting things don't talk either.
|
|
|
|
if (target->flags4 & MF4_INCOMBAT)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (target->Conversation != NULL)
|
|
|
|
{
|
|
|
|
// Give the NPC a chance to play a brief animation
|
|
|
|
target->ConversationAnimation (0);
|
2006-07-29 01:26:24 +00:00
|
|
|
P_StartConversation (target, it, !!arg1, true);
|
2006-06-03 12:30:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-20 12:20:51 +00:00
|
|
|
FUNC(LS_Thing_SetConversation)
|
|
|
|
// Thing_SetConversation (tid, dlg_id)
|
|
|
|
{
|
|
|
|
int dlg_index = -1;
|
|
|
|
FStrifeDialogueNode *node = NULL;
|
|
|
|
|
|
|
|
if (arg1 != 0)
|
|
|
|
{
|
|
|
|
dlg_index = GetConversation(arg1);
|
|
|
|
if (dlg_index == -1) return false;
|
|
|
|
node = StrifeDialogues[dlg_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg0 != 0)
|
|
|
|
{
|
|
|
|
FActorIterator iterator (arg0);
|
|
|
|
while ((it = iterator.Next()) != NULL)
|
|
|
|
{
|
|
|
|
it->ConversationRoot = dlg_index;
|
|
|
|
it->Conversation = node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (it)
|
|
|
|
{
|
|
|
|
it->ConversationRoot = dlg_index;
|
|
|
|
it->Conversation = node;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-06-03 12:30:11 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
lnSpecFunc LineSpecials[256] =
|
|
|
|
{
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 0 */ LS_NOP,
|
|
|
|
/* 1 */ LS_NOP, // Polyobj_StartLine,
|
|
|
|
/* 2 */ LS_Polyobj_RotateLeft,
|
|
|
|
/* 3 */ LS_Polyobj_RotateRight,
|
|
|
|
/* 4 */ LS_Polyobj_Move,
|
|
|
|
/* 5 */ LS_NOP, // Polyobj_ExplicitLine
|
|
|
|
/* 6 */ LS_Polyobj_MoveTimes8,
|
|
|
|
/* 7 */ LS_Polyobj_DoorSwing,
|
|
|
|
/* 8 */ LS_Polyobj_DoorSlide,
|
|
|
|
/* 9 */ LS_NOP, // Line_Horizon
|
|
|
|
/* 10 */ LS_Door_Close,
|
|
|
|
/* 11 */ LS_Door_Open,
|
|
|
|
/* 12 */ LS_Door_Raise,
|
|
|
|
/* 13 */ LS_Door_LockedRaise,
|
|
|
|
/* 14 */ LS_Door_Animated,
|
|
|
|
/* 15 */ LS_Autosave,
|
|
|
|
/* 16 */ LS_NOP, // Transfer_WallLight
|
|
|
|
/* 17 */ LS_Thing_Raise,
|
|
|
|
/* 18 */ LS_StartConversation,
|
|
|
|
/* 19 */ LS_Thing_Stop,
|
|
|
|
/* 20 */ LS_Floor_LowerByValue,
|
|
|
|
/* 21 */ LS_Floor_LowerToLowest,
|
|
|
|
/* 22 */ LS_Floor_LowerToNearest,
|
|
|
|
/* 23 */ LS_Floor_RaiseByValue,
|
|
|
|
/* 24 */ LS_Floor_RaiseToHighest,
|
|
|
|
/* 25 */ LS_Floor_RaiseToNearest,
|
|
|
|
/* 26 */ LS_Stairs_BuildDown,
|
|
|
|
/* 27 */ LS_Stairs_BuildUp,
|
|
|
|
/* 28 */ LS_Floor_RaiseAndCrush,
|
|
|
|
/* 29 */ LS_Pillar_Build,
|
|
|
|
/* 30 */ LS_Pillar_Open,
|
|
|
|
/* 31 */ LS_Stairs_BuildDownSync,
|
|
|
|
/* 32 */ LS_Stairs_BuildUpSync,
|
|
|
|
/* 33 */ LS_ForceField,
|
|
|
|
/* 34 */ LS_ClearForceField,
|
|
|
|
/* 35 */ LS_Floor_RaiseByValueTimes8,
|
|
|
|
/* 36 */ LS_Floor_LowerByValueTimes8,
|
|
|
|
/* 37 */ LS_Floor_MoveToValue,
|
|
|
|
/* 38 */ LS_Ceiling_Waggle,
|
|
|
|
/* 39 */ LS_Teleport_ZombieChanger,
|
|
|
|
/* 40 */ LS_Ceiling_LowerByValue,
|
|
|
|
/* 41 */ LS_Ceiling_RaiseByValue,
|
|
|
|
/* 42 */ LS_Ceiling_CrushAndRaise,
|
|
|
|
/* 43 */ LS_Ceiling_LowerAndCrush,
|
|
|
|
/* 44 */ LS_Ceiling_CrushStop,
|
|
|
|
/* 45 */ LS_Ceiling_CrushRaiseAndStay,
|
|
|
|
/* 46 */ LS_Floor_CrushStop,
|
|
|
|
/* 47 */ LS_Ceiling_MoveToValue,
|
|
|
|
/* 48 */ LS_NOP, // Sector_Attach3dMidtex
|
|
|
|
/* 49 */ LS_GlassBreak,
|
|
|
|
/* 50 */ LS_NOP, // ExtraFloor_LightOnly
|
|
|
|
/* 51 */ LS_Sector_SetLink,
|
|
|
|
/* 52 */ LS_Scroll_Wall,
|
|
|
|
/* 53 */ LS_Line_SetTextureOffset,
|
|
|
|
/* 54 */ LS_Sector_ChangeFlags,
|
|
|
|
/* 55 */ LS_Line_SetBlocking,
|
|
|
|
/* 56 */ LS_Line_SetTextureScale,
|
|
|
|
/* 57 */ LS_NOP, // Sector_SetPortal
|
2010-08-10 19:06:33 +00:00
|
|
|
/* 58 */ LS_NOP, // Sector_CopyScroller
|
|
|
|
/* 59 */ LS_Polyobj_OR_MoveToSpot,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 60 */ LS_Plat_PerpetualRaise,
|
|
|
|
/* 61 */ LS_Plat_Stop,
|
|
|
|
/* 62 */ LS_Plat_DownWaitUpStay,
|
|
|
|
/* 63 */ LS_Plat_DownByValue,
|
|
|
|
/* 64 */ LS_Plat_UpWaitDownStay,
|
|
|
|
/* 65 */ LS_Plat_UpByValue,
|
|
|
|
/* 66 */ LS_Floor_LowerInstant,
|
|
|
|
/* 67 */ LS_Floor_RaiseInstant,
|
|
|
|
/* 68 */ LS_Floor_MoveToValueTimes8,
|
|
|
|
/* 69 */ LS_Ceiling_MoveToValueTimes8,
|
|
|
|
/* 70 */ LS_Teleport,
|
|
|
|
/* 71 */ LS_Teleport_NoFog,
|
|
|
|
/* 72 */ LS_ThrustThing,
|
|
|
|
/* 73 */ LS_DamageThing,
|
|
|
|
/* 74 */ LS_Teleport_NewMap,
|
|
|
|
/* 75 */ LS_Teleport_EndGame,
|
|
|
|
/* 76 */ LS_TeleportOther,
|
|
|
|
/* 77 */ LS_TeleportGroup,
|
|
|
|
/* 78 */ LS_TeleportInSector,
|
2010-08-20 12:20:51 +00:00
|
|
|
/* 79 */ LS_Thing_SetConversation,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 80 */ LS_ACS_Execute,
|
|
|
|
/* 81 */ LS_ACS_Suspend,
|
|
|
|
/* 82 */ LS_ACS_Terminate,
|
|
|
|
/* 83 */ LS_ACS_LockedExecute,
|
|
|
|
/* 84 */ LS_ACS_ExecuteWithResult,
|
|
|
|
/* 85 */ LS_ACS_LockedExecuteDoor,
|
2010-08-10 19:06:33 +00:00
|
|
|
/* 86 */ LS_Polyobj_MoveToSpot,
|
2010-08-01 19:14:10 +00:00
|
|
|
/* 87 */ LS_Polyobj_Stop,
|
|
|
|
/* 88 */ LS_Polyobj_MoveTo,
|
|
|
|
/* 89 */ LS_Polyobj_OR_MoveTo,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 90 */ LS_Polyobj_OR_RotateLeft,
|
|
|
|
/* 91 */ LS_Polyobj_OR_RotateRight,
|
|
|
|
/* 92 */ LS_Polyobj_OR_Move,
|
|
|
|
/* 93 */ LS_Polyobj_OR_MoveTimes8,
|
|
|
|
/* 94 */ LS_Pillar_BuildAndCrush,
|
|
|
|
/* 95 */ LS_FloorAndCeiling_LowerByValue,
|
|
|
|
/* 96 */ LS_FloorAndCeiling_RaiseByValue,
|
2010-10-02 16:26:10 +00:00
|
|
|
/* 97 */ LS_Ceiling_LowerAndCrushDist,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 98 */ LS_NOP,
|
|
|
|
/* 99 */ LS_NOP,
|
|
|
|
/* 100 */ LS_NOP, // Scroll_Texture_Left
|
|
|
|
/* 101 */ LS_NOP, // Scroll_Texture_Right
|
|
|
|
/* 102 */ LS_NOP, // Scroll_Texture_Up
|
|
|
|
/* 103 */ LS_NOP, // Scroll_Texture_Down
|
|
|
|
/* 104 */ LS_NOP,
|
|
|
|
/* 105 */ LS_NOP,
|
|
|
|
/* 106 */ LS_NOP,
|
|
|
|
/* 107 */ LS_NOP,
|
|
|
|
/* 108 */ LS_NOP,
|
|
|
|
/* 109 */ LS_Light_ForceLightning,
|
|
|
|
/* 110 */ LS_Light_RaiseByValue,
|
|
|
|
/* 111 */ LS_Light_LowerByValue,
|
|
|
|
/* 112 */ LS_Light_ChangeToValue,
|
|
|
|
/* 113 */ LS_Light_Fade,
|
|
|
|
/* 114 */ LS_Light_Glow,
|
|
|
|
/* 115 */ LS_Light_Flicker,
|
|
|
|
/* 116 */ LS_Light_Strobe,
|
|
|
|
/* 117 */ LS_Light_Stop,
|
2010-01-30 22:53:37 +00:00
|
|
|
/* 118 */ LS_NOP, // Plane_Copy
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 119 */ LS_Thing_Damage,
|
|
|
|
/* 120 */ LS_Radius_Quake,
|
|
|
|
/* 121 */ LS_NOP, // Line_SetIdentification
|
|
|
|
/* 122 */ LS_NOP,
|
|
|
|
/* 123 */ LS_NOP,
|
|
|
|
/* 124 */ LS_NOP,
|
|
|
|
/* 125 */ LS_Thing_Move,
|
|
|
|
/* 126 */ LS_NOP,
|
|
|
|
/* 127 */ LS_Thing_SetSpecial,
|
|
|
|
/* 128 */ LS_ThrustThingZ,
|
|
|
|
/* 129 */ LS_UsePuzzleItem,
|
|
|
|
/* 130 */ LS_Thing_Activate,
|
|
|
|
/* 131 */ LS_Thing_Deactivate,
|
|
|
|
/* 132 */ LS_Thing_Remove,
|
|
|
|
/* 133 */ LS_Thing_Destroy,
|
|
|
|
/* 134 */ LS_Thing_Projectile,
|
|
|
|
/* 135 */ LS_Thing_Spawn,
|
|
|
|
/* 136 */ LS_Thing_ProjectileGravity,
|
|
|
|
/* 137 */ LS_Thing_SpawnNoFog,
|
|
|
|
/* 138 */ LS_Floor_Waggle,
|
|
|
|
/* 139 */ LS_Thing_SpawnFacing,
|
|
|
|
/* 140 */ LS_Sector_ChangeSound,
|
2010-01-30 22:53:37 +00:00
|
|
|
/* 141 */ LS_NOP,
|
|
|
|
/* 142 */ LS_NOP,
|
|
|
|
/* 143 */ LS_NOP,
|
|
|
|
/* 144 */ LS_NOP,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 145 */ LS_NOP, // 145 Player_SetTeam
|
2010-01-30 22:53:37 +00:00
|
|
|
/* 146 */ LS_NOP,
|
|
|
|
/* 147 */ LS_NOP,
|
|
|
|
/* 148 */ LS_NOP,
|
|
|
|
/* 149 */ LS_NOP,
|
|
|
|
/* 150 */ LS_NOP,
|
|
|
|
/* 151 */ LS_NOP,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 152 */ LS_NOP, // 152 Team_Score
|
2010-01-30 22:53:37 +00:00
|
|
|
/* 153 */ LS_NOP, // 153 Team_GivePoints
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 154 */ LS_Teleport_NoStop,
|
2010-01-30 22:53:37 +00:00
|
|
|
/* 155 */ LS_NOP,
|
|
|
|
/* 156 */ LS_NOP,
|
2010-01-16 07:51:50 +00:00
|
|
|
/* 157 */ LS_NOP, // SetGlobalFogParameter // in GZDoom
|
|
|
|
/* 158 */ LS_NOP, // FS_Execute in GZDoom
|
|
|
|
/* 159 */ LS_NOP, // Sector_SetPlaneReflection in GZDoom
|
|
|
|
/* 160 */ LS_NOP, // Sector_Set3DFloor in GZDoom and Vavoom
|
|
|
|
/* 161 */ LS_NOP, // Sector_SetContents in GZDoom and Vavoom
|
|
|
|
/* 162 */ LS_NOP,
|
|
|
|
/* 163 */ LS_NOP,
|
|
|
|
/* 164 */ LS_NOP,
|
|
|
|
/* 165 */ LS_NOP,
|
|
|
|
/* 166 */ LS_NOP,
|
|
|
|
/* 167 */ LS_NOP,
|
|
|
|
/* 168 */ LS_NOP,
|
|
|
|
/* 169 */ LS_Generic_Crusher2,
|
|
|
|
/* 170 */ LS_Sector_SetCeilingScale2,
|
|
|
|
/* 171 */ LS_Sector_SetFloorScale2,
|
|
|
|
/* 172 */ LS_Plat_UpNearestWaitDownStay,
|
|
|
|
/* 173 */ LS_NoiseAlert,
|
|
|
|
/* 174 */ LS_SendToCommunicator,
|
|
|
|
/* 175 */ LS_Thing_ProjectileIntercept,
|
|
|
|
/* 176 */ LS_Thing_ChangeTID,
|
|
|
|
/* 177 */ LS_Thing_Hate,
|
|
|
|
/* 178 */ LS_Thing_ProjectileAimed,
|
|
|
|
/* 179 */ LS_ChangeSkill,
|
|
|
|
/* 180 */ LS_Thing_SetTranslation,
|
|
|
|
/* 181 */ LS_NOP, // Plane_Align
|
|
|
|
/* 182 */ LS_NOP, // Line_Mirror
|
|
|
|
/* 183 */ LS_Line_AlignCeiling,
|
|
|
|
/* 184 */ LS_Line_AlignFloor,
|
|
|
|
/* 185 */ LS_Sector_SetRotation,
|
|
|
|
/* 186 */ LS_Sector_SetCeilingPanning,
|
|
|
|
/* 187 */ LS_Sector_SetFloorPanning,
|
|
|
|
/* 188 */ LS_Sector_SetCeilingScale,
|
|
|
|
/* 189 */ LS_Sector_SetFloorScale,
|
|
|
|
/* 190 */ LS_NOP, // Static_Init
|
|
|
|
/* 191 */ LS_SetPlayerProperty,
|
|
|
|
/* 192 */ LS_Ceiling_LowerToHighestFloor,
|
|
|
|
/* 193 */ LS_Ceiling_LowerInstant,
|
|
|
|
/* 194 */ LS_Ceiling_RaiseInstant,
|
|
|
|
/* 195 */ LS_Ceiling_CrushRaiseAndStayA,
|
|
|
|
/* 196 */ LS_Ceiling_CrushAndRaiseA,
|
|
|
|
/* 197 */ LS_Ceiling_CrushAndRaiseSilentA,
|
|
|
|
/* 198 */ LS_Ceiling_RaiseByValueTimes8,
|
|
|
|
/* 199 */ LS_Ceiling_LowerByValueTimes8,
|
|
|
|
/* 200 */ LS_Generic_Floor,
|
|
|
|
/* 201 */ LS_Generic_Ceiling,
|
|
|
|
/* 202 */ LS_Generic_Door,
|
|
|
|
/* 203 */ LS_Generic_Lift,
|
|
|
|
/* 204 */ LS_Generic_Stairs,
|
|
|
|
/* 205 */ LS_Generic_Crusher,
|
|
|
|
/* 206 */ LS_Plat_DownWaitUpStayLip,
|
|
|
|
/* 207 */ LS_Plat_PerpetualRaiseLip,
|
|
|
|
/* 208 */ LS_TranslucentLine,
|
|
|
|
/* 209 */ LS_NOP, // Transfer_Heights
|
|
|
|
/* 210 */ LS_NOP, // Transfer_FloorLight
|
|
|
|
/* 211 */ LS_NOP, // Transfer_CeilingLight
|
|
|
|
/* 212 */ LS_Sector_SetColor,
|
|
|
|
/* 213 */ LS_Sector_SetFade,
|
|
|
|
/* 214 */ LS_Sector_SetDamage,
|
|
|
|
/* 215 */ LS_Teleport_Line,
|
|
|
|
/* 216 */ LS_Sector_SetGravity,
|
|
|
|
/* 217 */ LS_Stairs_BuildUpDoom,
|
|
|
|
/* 218 */ LS_Sector_SetWind,
|
|
|
|
/* 219 */ LS_Sector_SetFriction,
|
|
|
|
/* 220 */ LS_Sector_SetCurrent,
|
|
|
|
/* 221 */ LS_Scroll_Texture_Both,
|
|
|
|
/* 222 */ LS_NOP, // Scroll_Texture_Model
|
|
|
|
/* 223 */ LS_Scroll_Floor,
|
|
|
|
/* 224 */ LS_Scroll_Ceiling,
|
|
|
|
/* 225 */ LS_NOP, // Scroll_Texture_Offsets
|
|
|
|
/* 226 */ LS_ACS_ExecuteAlways,
|
|
|
|
/* 227 */ LS_PointPush_SetForce,
|
|
|
|
/* 228 */ LS_Plat_RaiseAndStayTx0,
|
|
|
|
/* 229 */ LS_Thing_SetGoal,
|
|
|
|
/* 230 */ LS_Plat_UpByValueStayTx,
|
|
|
|
/* 231 */ LS_Plat_ToggleCeiling,
|
|
|
|
/* 232 */ LS_Light_StrobeDoom,
|
|
|
|
/* 233 */ LS_Light_MinNeighbor,
|
|
|
|
/* 234 */ LS_Light_MaxNeighbor,
|
|
|
|
/* 235 */ LS_Floor_TransferTrigger,
|
|
|
|
/* 236 */ LS_Floor_TransferNumeric,
|
|
|
|
/* 237 */ LS_ChangeCamera,
|
|
|
|
/* 238 */ LS_Floor_RaiseToLowestCeiling,
|
|
|
|
/* 239 */ LS_Floor_RaiseByValueTxTy,
|
|
|
|
/* 240 */ LS_Floor_RaiseByTexture,
|
|
|
|
/* 241 */ LS_Floor_LowerToLowestTxTy,
|
|
|
|
/* 242 */ LS_Floor_LowerToHighest,
|
|
|
|
/* 243 */ LS_Exit_Normal,
|
|
|
|
/* 244 */ LS_Exit_Secret,
|
|
|
|
/* 245 */ LS_Elevator_RaiseToNearest,
|
|
|
|
/* 246 */ LS_Elevator_MoveToFloor,
|
|
|
|
/* 247 */ LS_Elevator_LowerToNearest,
|
|
|
|
/* 248 */ LS_HealThing,
|
|
|
|
/* 249 */ LS_Door_CloseWaitOpen,
|
|
|
|
/* 250 */ LS_Floor_Donut,
|
|
|
|
/* 251 */ LS_FloorAndCeiling_LowerRaise,
|
|
|
|
/* 252 */ LS_Ceiling_RaiseToNearest,
|
|
|
|
/* 253 */ LS_Ceiling_LowerToLowest,
|
|
|
|
/* 254 */ LS_Ceiling_LowerToFloor,
|
|
|
|
/* 255 */ LS_Ceiling_CrushRaiseAndStaySilA
|
2006-02-24 04:48:15 +00:00
|
|
|
};
|
2008-03-19 12:48:02 +00:00
|
|
|
|
2009-09-12 04:08:31 +00:00
|
|
|
#define DEFINE_SPECIAL(name, num, min, max, mmax) {#name, num, min, max, mmax},
|
|
|
|
static FLineSpecial LineSpecialNames[] = {
|
2008-03-19 12:48:02 +00:00
|
|
|
#include "actionspecials.h"
|
|
|
|
};
|
2009-09-12 04:08:31 +00:00
|
|
|
const FLineSpecial *LineSpecialsInfo[256];
|
2008-03-19 12:48:02 +00:00
|
|
|
|
|
|
|
static int STACK_ARGS lscmp (const void * a, const void * b)
|
|
|
|
{
|
|
|
|
return stricmp( ((FLineSpecial*)a)->name, ((FLineSpecial*)b)->name);
|
|
|
|
}
|
|
|
|
|
2009-09-12 04:08:31 +00:00
|
|
|
static struct InitLineSpecials
|
2008-03-19 12:48:02 +00:00
|
|
|
{
|
2009-09-12 04:08:31 +00:00
|
|
|
InitLineSpecials()
|
2008-03-19 12:48:02 +00:00
|
|
|
{
|
|
|
|
qsort(LineSpecialNames, countof(LineSpecialNames), sizeof(FLineSpecial), lscmp);
|
2009-09-12 04:08:31 +00:00
|
|
|
for (size_t i = 0; i < countof(LineSpecialNames); ++i)
|
|
|
|
{
|
|
|
|
assert(LineSpecialsInfo[LineSpecialNames[i].number] == NULL);
|
|
|
|
LineSpecialsInfo[LineSpecialNames[i].number] = &LineSpecialNames[i];
|
|
|
|
}
|
2008-03-19 12:48:02 +00:00
|
|
|
}
|
2009-09-12 04:08:31 +00:00
|
|
|
} DoInit;
|
2008-03-19 12:48:02 +00:00
|
|
|
|
2009-09-12 04:08:31 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// P_FindLineSpecial
|
|
|
|
//
|
|
|
|
// Finds a line special and also returns the min and max argument count.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
int P_FindLineSpecial (const char *string, int *min_args, int *max_args)
|
|
|
|
{
|
2008-03-19 12:48:02 +00:00
|
|
|
int min = 0, max = countof(LineSpecialNames) - 1;
|
|
|
|
|
|
|
|
while (min <= max)
|
|
|
|
{
|
|
|
|
int mid = (min + max) / 2;
|
|
|
|
int lexval = stricmp (string, LineSpecialNames[mid].name);
|
|
|
|
if (lexval == 0)
|
|
|
|
{
|
|
|
|
if (min_args != NULL) *min_args = LineSpecialNames[mid].min_args;
|
|
|
|
if (max_args != NULL) *max_args = LineSpecialNames[mid].max_args;
|
|
|
|
return LineSpecialNames[mid].number;
|
|
|
|
}
|
|
|
|
else if (lexval > 0)
|
|
|
|
{
|
|
|
|
min = mid + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = mid - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|