468 lines
11 KiB
Plaintext
468 lines
11 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
|
|
// _elevator_v2: used in mp_mines.gsc (original was used in mp_fahrenheit).
|
|
// Making adjustments to allow for multiple types of elevators
|
|
|
|
// ELEVATOR TEST
|
|
ELEVATOR_DOOR_TIME = 2;
|
|
ELEVATOR_FLOOR_MOVE_TIME = 5;
|
|
ELEVATOR_AUTOCLOSE_TIMEOUT = 10;
|
|
|
|
ELEVATOR_DOOR_STATE_CLOSED = 0;
|
|
ELEVATOR_DOOR_STATE_OPENING = 1;
|
|
ELEVATOR_DOOR_STATE_OPEN = 2;
|
|
ELEVATOR_DOOR_STATE_CLOSING = 3;
|
|
|
|
// should scale elevator door speed based on the actual distance moved
|
|
// in case of interrupts
|
|
|
|
init_elevator( config )
|
|
{
|
|
elevator = GetEnt( config.name, "targetname" );
|
|
AssertEx( IsDefined( elevator ), "Could not find an elevator entity named " + config.name );
|
|
elevator.unresolved_collision_func = ::handleUnreslovedCollision;
|
|
|
|
elevator.doors = [];
|
|
if ( IsDefined( config.doors ) )
|
|
{
|
|
foreach ( floorname, doorset in config.doors )
|
|
{
|
|
list = [];
|
|
foreach ( doorname in doorset )
|
|
{
|
|
list[ list.size ] = setupDoor( doorName + "left", false, config.doorMoveDist );
|
|
list[ list.size ] = setupDoor( doorName + "right", true, config.doorMoveDist );
|
|
}
|
|
|
|
elevator.doors[ floorname ] = list;
|
|
}
|
|
|
|
if ( IsDefined( config.doorOpenTime ) )
|
|
elevator.doorOpenTime = config.doorOpenTime;
|
|
else
|
|
elevator.doorOpenTime = ELEVATOR_DOOR_TIME;
|
|
|
|
elevator.doorSpeed = config.doorMoveDist / elevator.doorOpenTime;
|
|
|
|
if ( IsDefined( config.autoCloseTimeout ) )
|
|
elevator.autoCloseTimeout = config.autoCloseTimeout;
|
|
else
|
|
elevator.autoCloseTimeout = ELEVATOR_AUTOCLOSE_TIMEOUT;
|
|
|
|
elevator.trigBlock = GetEnt( config.trigBlockName, "targetname" );
|
|
AssertEx( IsDefined( elevator.trigBlock ), "Could not find an elevator trigger named " + config.trigBlockName );
|
|
|
|
if ( IsDefined( config.autoCloseTimeout ) )
|
|
elevator.autoCloseTimeout = config.autoCloseTimeout;
|
|
else
|
|
elevator.autoCloseTimeout = ELEVATOR_AUTOCLOSE_TIMEOUT;
|
|
|
|
elevator.doorOpenSfx = config.doorOpenSfx; // scn_elevator_doors_opening
|
|
elevator.doorCloseSfx = config.doorCloseSfx; // scn_elevator_doors_closing
|
|
}
|
|
|
|
if ( IsDefined( config.moveTime ) )
|
|
elevator.moveTime = config.moveTime;
|
|
else
|
|
elevator.moveTime = ELEVATOR_FLOOR_MOVE_TIME;
|
|
|
|
elevator.destinations = [];
|
|
elevator.pathBlockers = [];
|
|
elevator.buttons = GetEntArray( config.buttons, "targetname" );
|
|
foreach ( button in elevator.buttons )
|
|
{
|
|
button setupButton( elevator );
|
|
}
|
|
|
|
// set up destinations
|
|
destinationStructs = getstructarray( config.destinations, "targetname" );
|
|
foreach ( destination in destinationStructs )
|
|
{
|
|
elevator setupDestination( destination );
|
|
}
|
|
elevator.destinationNames = config.destinationNames;
|
|
|
|
elevator.curFloor = config.destinationNames[0]; // "floor1"; should this be determined from destinations?
|
|
elevator.requestedFloor = elevator.curFloor;
|
|
elevator.doorState = ELEVATOR_DOOR_STATE_CLOSED;
|
|
|
|
if ( IsDefined( config.models ) )
|
|
{
|
|
elevatorModels = GetEntArray( config.models, "targetname" );
|
|
if ( IsDefined( elevatorModels ) )
|
|
{
|
|
foreach ( eleModel in elevatorModels )
|
|
{
|
|
eleModel LinkTo( elevator );
|
|
}
|
|
}
|
|
}
|
|
|
|
elevator thread elevatorThink();
|
|
|
|
if (elevator.doors.size > 0)
|
|
{
|
|
elevator thread openElevatorDoors( elevator.curFloor, false );
|
|
}
|
|
|
|
// sounds
|
|
elevator.startSfx = config.startSfx; // "scn_elevator_startup"
|
|
elevator.stopSfx = config.stopSfx; // "scn_elevator_stopping"
|
|
elevator.loopSfx = config.loopSfx; // "scn_elevator_moving_lp"
|
|
elevator.beepSfx = config.beepSfx; // "scn_elevator_beep"
|
|
|
|
|
|
// callback on init
|
|
elevator.onMoveCallback = config.onMoveCallback;
|
|
elevator.onArrivedCallback = config.onArrivedCallback;
|
|
|
|
return elevator;
|
|
}
|
|
|
|
setupDoor( doorName, isRightSide, moveDistance )
|
|
{
|
|
door = GetEnt( doorName, "targetname" );
|
|
if (IsDefined(door))
|
|
{
|
|
door.closePos = door.origin;
|
|
if (IsDefined(door.target))
|
|
{
|
|
targetStruct = getstruct( door.target, "targetname" );
|
|
door.openPos = targetStruct.origin;
|
|
}
|
|
else
|
|
{
|
|
offset = AnglesToForward( door.angles ) * moveDistance;
|
|
/*
|
|
if (isRightSide)
|
|
{
|
|
offset *= -1;
|
|
}
|
|
*/
|
|
door.openPos = door.origin + offset;
|
|
}
|
|
|
|
// door.unresolved_collision_func = ::handleUnreslovedCollision;
|
|
|
|
return door;
|
|
}
|
|
else
|
|
{
|
|
AssertEx( IsDefined( door ), "Could not find an elevator door entity named " + doorName );
|
|
return;
|
|
}
|
|
}
|
|
|
|
setupButton( elevator ) // self == button
|
|
{
|
|
self.owner = elevator;
|
|
|
|
if ( IsDefined( self.target ) )
|
|
{
|
|
destination = getstruct( self.target, "targetname" );
|
|
self setupDestination( destination );
|
|
}
|
|
|
|
self enableButton();
|
|
}
|
|
|
|
setupDestination( destination ) // self == elevator
|
|
{
|
|
|
|
if ( IsDefined( destination ) )
|
|
{
|
|
self.destinations[ destination.script_label ] = destination.origin;
|
|
if ( IsDefined( destination.target ) )
|
|
{
|
|
blocker = GetEnt( destination.target, "targetname" );
|
|
if ( IsDefined( blocker ) )
|
|
{
|
|
self.pathBlockers[ destination.script_label ] = blocker;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enableButton() // self == button
|
|
{
|
|
self SetHintString( &"MP_ELEVATOR_USE" );
|
|
self MakeUsable();
|
|
|
|
self thread buttonThink();
|
|
}
|
|
|
|
disableButton()
|
|
{
|
|
self MakeUnusable();
|
|
}
|
|
|
|
buttonThink()
|
|
{
|
|
elevator = self.owner;
|
|
elevator endon( "elevator_busy" );
|
|
|
|
while ( true )
|
|
{
|
|
self waittill( "trigger" );
|
|
|
|
if ( !IsDefined( self.script_label ) || self.script_label == "elevator" )
|
|
{
|
|
// do some stuff
|
|
if ( elevator.curFloor == elevator.destinationNames[0] )
|
|
{
|
|
elevator.requestedFloor = elevator.destinationNames[1];
|
|
}
|
|
else
|
|
{
|
|
elevator.requestedFloor = elevator.destinationNames[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
elevator.requestedFloor = self.script_label;
|
|
}
|
|
|
|
elevator notify( "elevator_called" );
|
|
}
|
|
}
|
|
|
|
elevatorThink()
|
|
{
|
|
hasDoors = self.doors.size > 0;
|
|
|
|
while ( true )
|
|
{
|
|
self waittill( "elevator_called" );
|
|
|
|
foreach ( button in self.buttons )
|
|
{
|
|
button disableButton();
|
|
}
|
|
|
|
if ( self.curFloor != self.requestedFloor )
|
|
{
|
|
if ( self.doorState != ELEVATOR_DOOR_STATE_CLOSED )
|
|
{
|
|
self notify ("elevator_stop_autoclose");
|
|
self thread closeElevatorDoors( self.curFloor );
|
|
self waittill( "elevator_doors_closed" );
|
|
}
|
|
else if ( !hasDoors )
|
|
{
|
|
self elevatorBlockPath( self.curFloor );
|
|
}
|
|
|
|
self elevatorMoveToFloor( self.requestedFloor );
|
|
wait (0.25);
|
|
}
|
|
|
|
if ( hasDoors )
|
|
{
|
|
self thread openElevatorDoors( self.curFloor, false );
|
|
self waittill ( "elevator_doors_open" );
|
|
}
|
|
else
|
|
{
|
|
self elevatorClearPath( self.curFloor );
|
|
}
|
|
|
|
foreach ( button in self.buttons )
|
|
{
|
|
button enableButton();
|
|
}
|
|
}
|
|
}
|
|
|
|
elevatorMoveToFloor( targetFloor )
|
|
{
|
|
//self PlaySound( self.startSfx );
|
|
//self PlayLoopSound( self.loopSfx );
|
|
|
|
destinationPos = self.destinations[ targetFloor ];
|
|
deltaZ = destinationPos[2] - self.origin[2]; // may need to change this to full vector later
|
|
|
|
if ( IsDefined( self.doors[ "elevator" ] ) )
|
|
{
|
|
// move doors
|
|
foreach ( door in self.doors[ "elevator" ] )
|
|
{
|
|
door MoveZ( deltaZ, self.moveTime );
|
|
}
|
|
}
|
|
|
|
// move the floor
|
|
self MoveZ( deltaZ, self.moveTime );
|
|
|
|
if ( IsDefined( self.onMoveCallback ) )
|
|
{
|
|
self thread [[ self.onMoveCallback ]]( targetFloor );
|
|
}
|
|
|
|
wait ( self.moveTime );
|
|
|
|
//self StopLoopSound ( self.loopSfx );
|
|
//self PlaySound ( self.stopSfx );
|
|
if ( IsDefined( self.beepSfx ) )
|
|
self PlaySound ( self.beepSfx );
|
|
|
|
self.curFloor = self.requestedFloor;
|
|
|
|
if ( IsDefined( self.onArrivedCallback ) )
|
|
{
|
|
self thread [[ self.onArrivedCallback ]]( self.curFloor );
|
|
}
|
|
}
|
|
|
|
openElevatorDoors( floorName, autoClose ) // elevator
|
|
{
|
|
doorset = self.doors[ floorName ];
|
|
|
|
self.doorState = ELEVATOR_DOOR_STATE_OPENING;
|
|
|
|
// figre out the time it takes to move 1 door, assume it's the same fo rall
|
|
door = doorset[0];
|
|
doorDest = (door.openPos[0], door.openPos[1], door.origin[2]);
|
|
moveDelta = doorDest - door.origin;
|
|
moveDist = Length( moveDelta );
|
|
|
|
// this might move 0 time / 0 dist
|
|
// but we need it to counteract the closing elevator
|
|
// wish I could just tell it to stop, instead
|
|
movetime = moveDist / self.doorSpeed;
|
|
accelTime = 0.25;
|
|
if (moveTime == 0.0)
|
|
{
|
|
moveTime = 0.05;
|
|
accelTime = 0.0;
|
|
}
|
|
else
|
|
{
|
|
self PlaySound( self.doorOpenSfx );
|
|
accelTime = min(accelTime, moveTime);
|
|
}
|
|
|
|
foreach ( door in doorset )
|
|
{
|
|
door MoveTo( (door.openPos[0], door.openPos[1], door.origin[2]), movetime, 0.0, accelTime );
|
|
}
|
|
wait ( movetime );
|
|
|
|
self.doorState = ELEVATOR_DOOR_STATE_OPEN;
|
|
|
|
self notify ( "elevator_doors_open" );
|
|
|
|
self elevatorClearPath( floorName );
|
|
|
|
if ( autoClose )
|
|
{
|
|
self thread elevatorDoorsAutoClose();
|
|
}
|
|
}
|
|
|
|
closeElevatorDoors( floorName )
|
|
{
|
|
self endon( "elevator_close_interrupted" );
|
|
|
|
self thread watchCloseInterrupted( floorName );
|
|
|
|
doorset = self.doors[ floorName ];
|
|
|
|
self.doorState = ELEVATOR_DOOR_STATE_CLOSING;
|
|
|
|
// figre out the time it takes to move 1 door, assume it's the same fo rall
|
|
door = doorset[0];
|
|
doorDest = (door.closePos[0], door.closePos[1], door.origin[2]);
|
|
moveDelta = doorDest - door.origin;
|
|
moveDist = Length( moveDelta );
|
|
|
|
if ( moveDist != 0.0 )
|
|
{
|
|
movetime = moveDist / self.doorSpeed;
|
|
foreach ( door in doorset )
|
|
{
|
|
// we assume the doors all begin closed,
|
|
// so door.closePos should eventually be defined by the time we need it
|
|
door MoveTo( (door.closePos[0], door.closePos[1], door.origin[2]), movetime, 0.0, 0.25 );
|
|
}
|
|
self PlaySound( self.doorCloseSfx );
|
|
wait ( movetime );
|
|
}
|
|
|
|
self.doorState = ELEVATOR_DOOR_STATE_CLOSED;
|
|
|
|
self elevatorBlockPath( floorName );
|
|
|
|
self notify( "elevator_doors_closed" );
|
|
}
|
|
|
|
watchCloseInterrupted( floorName )
|
|
{
|
|
// if the doors have closed successfully, we don't care any more
|
|
self endon( "elevator_doors_closed" );
|
|
|
|
// make sure there is nothing in the way now
|
|
nothingBlocking = true;
|
|
foreach ( character in level.characters )
|
|
{
|
|
if ( character isTouchingTrigger( self.trigBlock ) )
|
|
{
|
|
nothingBlocking = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( nothingBlocking )
|
|
{
|
|
self.trigBlock waittill( "trigger" );
|
|
}
|
|
|
|
self notify( "elevator_close_interrupted" );
|
|
|
|
self openElevatorDoors( floorName, true );
|
|
}
|
|
|
|
isTouchingTrigger( trigger ) // self == player
|
|
{
|
|
return ( IsAlive( self ) && self IsTouching( trigger ) );
|
|
}
|
|
|
|
elevatorDoorsAutoClose() // self == elevator
|
|
{
|
|
self endon( "elevator_doors_closed" );
|
|
self endon( "elevator_stop_autoclose" );
|
|
|
|
wait ( self.autoCloseTimeout );
|
|
|
|
self closeElevatorDoors( self.curFloor);
|
|
}
|
|
|
|
handleUnreslovedCollision( hitEnt ) // self == mover, hitEnt == player (usually)
|
|
{
|
|
if ( !IsPlayer( hitEnt ) )
|
|
{
|
|
hitEnt DoDamage( 1000, hitEnt.origin, self, self, "MOD_CRUSH" );
|
|
}
|
|
}
|
|
|
|
elevatorClearPath( floorName ) // self == elevator
|
|
{
|
|
blocker = self.pathBlockers[ floorName ];
|
|
if ( IsDefined( blocker ) )
|
|
{
|
|
blocker ConnectPaths();
|
|
blocker Hide();
|
|
blocker NotSolid();
|
|
}
|
|
}
|
|
|
|
elevatorBlockPath( floorName )
|
|
{
|
|
blocker = self.pathBlockers[ floorName ];
|
|
if ( IsDefined( blocker ) )
|
|
{
|
|
blocker Show();
|
|
blocker Solid();
|
|
blocker DisconnectPaths();
|
|
}
|
|
} |