1124 lines
26 KiB
C++
1124 lines
26 KiB
C++
/* rotate quickc program
|
|
by jim dose' 10/17/96
|
|
copyright (c)1996 hipnotic interactive, inc.
|
|
all rights reserved.
|
|
do not distribute.
|
|
*/
|
|
|
|
float state_active = 0;
|
|
float state_inactive = 1;
|
|
float state_speedingup = 2;
|
|
float state_slowingdown = 3;
|
|
|
|
float state_closed = 4;
|
|
float state_open = 5;
|
|
float state_opening = 6;
|
|
float state_closing = 7;
|
|
|
|
float state_wait = 0;
|
|
float state_move = 1;
|
|
float state_stop = 2;
|
|
float state_find = 3;
|
|
float state_next = 4;
|
|
|
|
float object_rotate = 0;
|
|
float object_movewall = 1;
|
|
float object_setorigin = 2;
|
|
|
|
float toggle = 1;
|
|
float start_on = 2;
|
|
|
|
float rotation = 1;
|
|
float angles = 2;
|
|
float stop = 4;
|
|
float no_rotate = 8;
|
|
float damage = 16;
|
|
float movetime = 32;
|
|
float set_damage = 64;
|
|
|
|
float visible = 1;
|
|
float touch = 2;
|
|
float nonblocking = 4;
|
|
|
|
float stayopen = 1;
|
|
|
|
/*quaked info_rotate (0 0.5 0) (-4 -4 -4) (4 4 4)
|
|
used as the point of rotation for rotatable objects.
|
|
*/
|
|
void() info_rotate =
|
|
{
|
|
// remove self after a little while, to make sure that entities that
|
|
// have targeted it have had a chance to spawn
|
|
self.nextthink = time + 2;
|
|
self.think = sub_remove;
|
|
};
|
|
|
|
void() rotatetargets =
|
|
{
|
|
local entity ent;
|
|
local vector vx;
|
|
local vector vy;
|
|
local vector vz;
|
|
local vector org;
|
|
|
|
makevectors (self.angles);
|
|
|
|
ent = find( world, targetname, self.target);
|
|
while( ent )
|
|
{
|
|
if ( ent.rotate_type == object_setorigin )
|
|
{
|
|
org = ent.oldorigin;
|
|
vx = ( v_forward * org_x );
|
|
vy = ( v_right * org_y );
|
|
vy = vy * -1;
|
|
vz = ( v_up * org_z );
|
|
ent.neworigin = vx + vy + vz;
|
|
setorigin( ent, ent.neworigin + self.origin );
|
|
}
|
|
else if ( ent.rotate_type == object_rotate )
|
|
{
|
|
ent.angles = self.angles;
|
|
org = ent.oldorigin;
|
|
vx = ( v_forward * org_x );
|
|
vy = ( v_right * org_y );
|
|
vy = vy * -1;
|
|
vz = ( v_up * org_z );
|
|
ent.neworigin = vx + vy + vz;
|
|
setorigin( ent, ent.neworigin + self.origin );
|
|
}
|
|
else
|
|
{
|
|
org = ent.oldorigin;
|
|
vx = ( v_forward * org_x );
|
|
vy = ( v_right * org_y );
|
|
vy = vy * -1;
|
|
vz = ( v_up * org_z );
|
|
ent.neworigin = vx + vy + vz;
|
|
ent.neworigin = self.origin - self.oldorigin + (ent.neworigin - ent.oldorigin);
|
|
ent.velocity = (ent.neworigin-ent.origin)*25;
|
|
}
|
|
ent = find( ent, targetname, self.target);
|
|
}
|
|
};
|
|
|
|
void() rotatetargetsfinal =
|
|
{
|
|
local entity ent;
|
|
|
|
ent = find( world, targetname, self.target);
|
|
while( ent )
|
|
{
|
|
ent.velocity = '0 0 0';
|
|
if ( ent.rotate_type == object_rotate )
|
|
{
|
|
ent.angles = self.angles;
|
|
}
|
|
ent = find( ent, targetname, self.target);
|
|
}
|
|
};
|
|
|
|
void() settargetorigin =
|
|
{
|
|
local entity ent;
|
|
|
|
ent = find( world, targetname, self.target);
|
|
while( ent )
|
|
{
|
|
if ( ent.rotate_type == object_movewall )
|
|
{
|
|
setorigin( ent, self.origin - self.oldorigin +
|
|
(ent.neworigin - ent.oldorigin) );
|
|
}
|
|
else
|
|
{
|
|
setorigin( ent, ent.neworigin + self.origin );
|
|
}
|
|
ent = find( ent, targetname, self.target);
|
|
}
|
|
};
|
|
|
|
void() linkrotatetargets =
|
|
{
|
|
local entity ent;
|
|
local vector tempvec;
|
|
|
|
self.oldorigin = self.origin;
|
|
ent = find( world, targetname, self.target);
|
|
while( ent )
|
|
{
|
|
if ( ent.classname == "rotate_object" )
|
|
{
|
|
ent.rotate_type = object_rotate;
|
|
ent.oldorigin = ent.origin - self.oldorigin;
|
|
ent.neworigin = ent.origin - self.oldorigin;
|
|
ent.owner = self;
|
|
}
|
|
else if ( ent.classname == "func_movewall" )
|
|
{
|
|
ent.rotate_type = object_movewall;
|
|
tempvec = ( ent.absmin + ent.absmax ) * 0.5;
|
|
ent.oldorigin = tempvec - self.oldorigin;
|
|
ent.neworigin = ent.oldorigin;
|
|
ent.owner = self;
|
|
}
|
|
else
|
|
{
|
|
ent.rotate_type = object_setorigin;
|
|
ent.oldorigin = ent.origin - self.oldorigin;
|
|
ent.neworigin = ent.origin - self.oldorigin;
|
|
}
|
|
ent = find (ent, targetname, self.target);
|
|
}
|
|
};
|
|
|
|
void( float amount ) setdamageontargets =
|
|
{
|
|
local entity ent;
|
|
|
|
ent = find( world, targetname, self.target);
|
|
while( ent )
|
|
{
|
|
if ( ent.classname == "trigger_hurt" )
|
|
{
|
|
hurt_setdamage( ent, amount );
|
|
}
|
|
else if ( ent.classname == "func_movewall" )
|
|
{
|
|
ent.dmg = amount;
|
|
}
|
|
ent = find( ent, targetname, self.target);
|
|
}
|
|
};
|
|
|
|
|
|
//************************************************
|
|
//
|
|
// simple continual rotatation
|
|
//
|
|
//************************************************
|
|
|
|
void() rotate_entity_think =
|
|
{
|
|
local float t;
|
|
|
|
t = time - self.ltime;
|
|
self.ltime = time;
|
|
|
|
if ( self.state == state_speedingup )
|
|
{
|
|
self.count = self.count + self.cnt * t;
|
|
if ( self.count > 1 )
|
|
{
|
|
self.count = 1;
|
|
}
|
|
|
|
// get rate of rotation
|
|
t = t * self.count;
|
|
}
|
|
else if ( self.state == state_slowingdown )
|
|
{
|
|
self.count = self.count - self.cnt * t;
|
|
if ( self.count < 0 )
|
|
{
|
|
rotatetargetsfinal();
|
|
self.state = state_inactive;
|
|
self.think = sub_null;
|
|
return;
|
|
}
|
|
|
|
// get rate of rotation
|
|
t = t * self.count;
|
|
}
|
|
|
|
self.angles = self.angles + ( self.rotate * t );
|
|
self.angles = sub_normalizeangles( self.angles );
|
|
rotatetargets();
|
|
self.nextthink = time + 0.02;
|
|
};
|
|
|
|
void() rotate_entity_use =
|
|
{
|
|
// change to alternate textures
|
|
self.frame = 1 - self.frame;
|
|
|
|
if ( self.state == state_active )
|
|
{
|
|
if ( self.spawnflags & toggle )
|
|
{
|
|
if ( self.speed )
|
|
{
|
|
self.count = 1;
|
|
self.state = state_slowingdown;
|
|
}
|
|
else
|
|
{
|
|
self.state = state_inactive;
|
|
self.think = sub_null;
|
|
}
|
|
}
|
|
}
|
|
else if ( self.state == state_inactive )
|
|
{
|
|
self.think = rotate_entity_think;
|
|
self.nextthink = time + 0.02;
|
|
self.ltime = time;
|
|
if ( self.speed )
|
|
{
|
|
self.count = 0;
|
|
self.state = state_speedingup;
|
|
}
|
|
else
|
|
{
|
|
self.state = state_active;
|
|
}
|
|
}
|
|
else if ( self.state == state_speedingup )
|
|
{
|
|
if ( self.spawnflags & toggle )
|
|
{
|
|
self.state = state_slowingdown;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.state = state_speedingup;
|
|
}
|
|
};
|
|
|
|
void() rotate_entity_firstthink =
|
|
{
|
|
linkrotatetargets();
|
|
if ( self.spawnflags & start_on )
|
|
{
|
|
self.state = state_active;
|
|
self.think = rotate_entity_think;
|
|
self.nextthink = time + 0.02;
|
|
self.ltime = time;
|
|
}
|
|
else
|
|
{
|
|
self.state = state_inactive;
|
|
self.think = sub_null;
|
|
}
|
|
self.use = rotate_entity_use;
|
|
};
|
|
|
|
/*quaked func_rotate_entity (0 .5 .8) (-8 -8 -8) (8 8 8) toggle start_on
|
|
creates an entity that continually rotates. can be toggled on and
|
|
off if targeted.
|
|
|
|
toggle = allows the rotation to be toggled on/off
|
|
|
|
start_on = wether the entity is spinning when spawned. if toggle is 0, entity can be turned on, but not off.
|
|
|
|
if "deathtype" is set with a string, this is the message that will appear when a player is killed by the train.
|
|
|
|
"rotate" is the rate to rotate.
|
|
"target" is the center of rotation.
|
|
"speed" is how long the entity takes to go from standing still to full speed and vice-versa.
|
|
*/
|
|
|
|
void() func_rotate_entity =
|
|
{
|
|
self.solid = solid_not;
|
|
self.movetype = movetype_none;
|
|
|
|
setmodel (self, self.model);
|
|
setsize( self, self.mins, self.maxs );
|
|
|
|
if ( self.speed != 0 )
|
|
{
|
|
self.cnt = 1 / self.speed;
|
|
}
|
|
|
|
self.think = rotate_entity_firstthink;
|
|
self.nextthink = time + 0.1;
|
|
self.ltime = time;
|
|
};
|
|
|
|
//************************************************
|
|
//
|
|
// train with rotation functionality
|
|
//
|
|
//************************************************
|
|
|
|
/*quaked path_rotate (0.5 0.3 0) (-8 -8 -8) (8 8 8) rotation angles stop no_rotate damage movetime set_damage
|
|
path for rotate_train.
|
|
|
|
rotation tells train to rotate at rate specified by "rotate". use '0 0 0' to stop rotation.
|
|
|
|
angles tells train to rotate to the angles specified by "angles" while traveling to this path_rotate. use values < 0 or > 360 to guarantee that it turns in a certain direction. having this flag set automatically clears any rotation.
|
|
|
|
stop tells the train to stop and wait to be retriggered.
|
|
|
|
no_rotate tells the train to stop rotating when waiting to be triggered.
|
|
|
|
damage tells the train to cause damage based on "dmg".
|
|
|
|
movetime tells the train to interpret "speed" as the length of time to take moving from one corner to another.
|
|
|
|
set_damage tells the train to set all targets damage to "dmg"
|
|
|
|
"noise" contains the name of the sound to play when train stops.
|
|
"noise1" contains the name of the sound to play when train moves.
|
|
"event" is a target to trigger when train arrives at path_rotate.
|
|
*/
|
|
void() path_rotate =
|
|
{
|
|
if ( self.noise )
|
|
{
|
|
precache_sound( self.noise );
|
|
}
|
|
if ( self.noise1 )
|
|
{
|
|
precache_sound( self.noise1 );
|
|
}
|
|
};
|
|
|
|
|
|
void() rotate_train;
|
|
void() rotate_train_next;
|
|
void() rotate_train_find;
|
|
|
|
void() rotate_train_think =
|
|
{
|
|
local float t;
|
|
local float timeelapsed;
|
|
|
|
t = time - self.ltime;
|
|
self.ltime = time;
|
|
|
|
if ( ( self.endtime ) && ( time >= self.endtime ) )
|
|
{
|
|
self.endtime = 0;
|
|
if ( self.state == state_move )
|
|
{
|
|
setorigin(self, self.finaldest);
|
|
self.velocity = '0 0 0';
|
|
}
|
|
|
|
if (self.think1)
|
|
self.think1();
|
|
}
|
|
else
|
|
{
|
|
timeelapsed = (time - self.cnt) * self.duration;
|
|
if ( timeelapsed > 1 )
|
|
timeelapsed = 1;
|
|
setorigin( self, self.dest1 + ( self.dest2 * timeelapsed ) );
|
|
}
|
|
|
|
self.angles = self.angles + ( self.rotate * t );
|
|
self.angles = sub_normalizeangles( self.angles );
|
|
rotatetargets();
|
|
|
|
self.nextthink = time + 0.02;
|
|
};
|
|
|
|
void() rotate_train_use =
|
|
{
|
|
if (self.think1 != rotate_train_find)
|
|
{
|
|
if ( self.velocity != '0 0 0' )
|
|
return; // already activated
|
|
if ( self.think1 )
|
|
{
|
|
self.think1();
|
|
}
|
|
}
|
|
};
|
|
|
|
void() rotate_train_wait =
|
|
{
|
|
self.state = state_wait;
|
|
|
|
if ( self.goalentity.noise )
|
|
{
|
|
sound (self, chan_voice, self.goalentity.noise, 1, attn_norm);
|
|
}
|
|
else
|
|
{
|
|
sound (self, chan_voice, self.noise, 1, attn_norm);
|
|
}
|
|
if ( self.goalentity.spawnflags & angles )
|
|
{
|
|
self.rotate = '0 0 0';
|
|
self.angles = self.finalangle;
|
|
}
|
|
if ( self.goalentity.spawnflags & no_rotate )
|
|
{
|
|
self.rotate = '0 0 0';
|
|
}
|
|
self.endtime = self.ltime + self.goalentity.wait;
|
|
self.think1 = rotate_train_next;
|
|
};
|
|
|
|
void() rotate_train_stop =
|
|
{
|
|
self.state = state_stop;
|
|
|
|
if ( self.goalentity.noise )
|
|
{
|
|
sound (self, chan_voice, self.goalentity.noise, 1, attn_norm);
|
|
}
|
|
else
|
|
{
|
|
sound (self, chan_voice, self.noise, 1, attn_norm);
|
|
}
|
|
if ( self.goalentity.spawnflags & angles )
|
|
{
|
|
self.rotate = '0 0 0';
|
|
self.angles = self.finalangle;
|
|
}
|
|
if ( self.goalentity.spawnflags & no_rotate )
|
|
{
|
|
self.rotate = '0 0 0';
|
|
}
|
|
|
|
self.dmg = 0;
|
|
self.think1 = rotate_train_next;
|
|
};
|
|
|
|
void() rotate_train_next =
|
|
{
|
|
local entity targ;
|
|
local entity current;
|
|
local vector vdestdelta;
|
|
local float len, traveltime, div;
|
|
local string temp;
|
|
|
|
self.state = state_next;
|
|
|
|
current = self.goalentity;
|
|
targ = find (world, targetname, self.path );
|
|
if ( targ.classname != "path_rotate" )
|
|
objerror( "next target is not path_rotate" );
|
|
|
|
if ( self.goalentity.noise1 )
|
|
{
|
|
self.noise1 = self.goalentity.noise1;
|
|
}
|
|
sound (self, chan_voice, self.noise1, 1, attn_norm);
|
|
|
|
self.goalentity = targ;
|
|
self.path = targ.target;
|
|
if (!self.path )
|
|
objerror ("rotate_train_next: no next target");
|
|
|
|
if ( targ.spawnflags & stop )
|
|
{
|
|
self.think1 = rotate_train_stop;
|
|
}
|
|
else if (targ.wait)
|
|
{
|
|
self.think1 = rotate_train_wait;
|
|
}
|
|
else
|
|
{
|
|
self.think1 = rotate_train_next;
|
|
}
|
|
|
|
if ( current.event )
|
|
{
|
|
// trigger any events that should happen at the corner.
|
|
temp = self.target;
|
|
self.target = current.event;
|
|
self.message = current.message;
|
|
sub_usetargets();
|
|
self.target = temp;
|
|
self.message = string_null;
|
|
}
|
|
|
|
if ( current.spawnflags & angles )
|
|
{
|
|
self.rotate = '0 0 0';
|
|
self.angles = self.finalangle;
|
|
}
|
|
|
|
if ( current.spawnflags & rotation )
|
|
{
|
|
self.rotate = current.rotate;
|
|
}
|
|
|
|
if ( current.spawnflags & damage )
|
|
{
|
|
self.dmg = current.dmg;
|
|
}
|
|
|
|
if ( current.spawnflags & set_damage )
|
|
{
|
|
setdamageontargets( current.dmg );
|
|
}
|
|
|
|
if ( current.speed == -1 )
|
|
{
|
|
// warp to the next path_corner
|
|
setorigin( self, targ.origin );
|
|
self.endtime = self.ltime + 0.01;
|
|
settargetorigin();
|
|
|
|
if ( targ.spawnflags & angles )
|
|
{
|
|
self.angles = targ.angles;
|
|
}
|
|
|
|
self.duration = 1; // 1 / duration
|
|
self.cnt = time; // start time
|
|
self.dest2 = '0 0 0'; // delta
|
|
self.dest1 = self.origin; // original position
|
|
self.finaldest = self.origin;
|
|
}
|
|
else
|
|
{
|
|
self.state = state_move;
|
|
|
|
self.finaldest = targ.origin;
|
|
if (self.finaldest == self.origin)
|
|
{
|
|
self.velocity = '0 0 0';
|
|
self.endtime = self.ltime + 0.1;
|
|
|
|
self.duration = 1; // 1 / duration
|
|
self.cnt = time; // start time
|
|
self.dest2 = '0 0 0'; // delta
|
|
self.dest1 = self.origin; // original position
|
|
self.finaldest = self.origin;
|
|
return;
|
|
}
|
|
// set destdelta to the vector needed to move
|
|
vdestdelta = self.finaldest - self.origin;
|
|
|
|
// calculate length of vector
|
|
len = vlen (vdestdelta);
|
|
|
|
if ( current.spawnflags & movetime )
|
|
{
|
|
traveltime = current.speed;
|
|
}
|
|
else
|
|
{
|
|
// check if there's a speed change
|
|
if (current.speed>0)
|
|
self.speed = current.speed;
|
|
|
|
if (!self.speed)
|
|
objerror("no speed is defined!");
|
|
|
|
// divide by speed to get time to reach dest
|
|
traveltime = len / self.speed;
|
|
}
|
|
|
|
if (traveltime < 0.1)
|
|
{
|
|
self.velocity = '0 0 0';
|
|
self.endtime = self.ltime + 0.1;
|
|
if ( targ.spawnflags & angles )
|
|
{
|
|
self.angles = targ.angles;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// qcc won't take vec/float
|
|
div = 1 / traveltime;
|
|
|
|
if ( targ.spawnflags & angles )
|
|
{
|
|
self.finalangle = sub_normalizeangles( targ.angles );
|
|
self.rotate = ( targ.angles - self.angles ) * div;
|
|
}
|
|
|
|
// set endtime to trigger a think when dest is reached
|
|
self.endtime = self.ltime + traveltime;
|
|
|
|
// scale the destdelta vector by the time spent traveling to get velocity
|
|
self.velocity = vdestdelta * div;
|
|
|
|
self.duration = div; // 1 / duration
|
|
self.cnt = time; // start time
|
|
self.dest2 = vdestdelta; // delta
|
|
self.dest1 = self.origin; // original position
|
|
}
|
|
};
|
|
|
|
void() rotate_train_find =
|
|
{
|
|
local entity targ;
|
|
|
|
self.state = state_find;
|
|
|
|
linkrotatetargets();
|
|
|
|
// the first target is the point of rotation.
|
|
// the second target is the path.
|
|
targ = find ( world, targetname, self.path);
|
|
if ( targ.classname != "path_rotate" )
|
|
objerror( "next target is not path_rotate" );
|
|
|
|
// save the current entity
|
|
self.goalentity = targ;
|
|
|
|
if ( targ.spawnflags & angles )
|
|
{
|
|
self.angles = targ.angles;
|
|
self.finalangle = sub_normalizeangles( targ.angles );
|
|
}
|
|
|
|
self.path = targ.target;
|
|
setorigin (self, targ.origin );
|
|
settargetorigin();
|
|
rotatetargetsfinal();
|
|
self.think1 = rotate_train_next;
|
|
if (!self.targetname)
|
|
{
|
|
// not triggered, so start immediately
|
|
self.endtime = self.ltime + 0.1;
|
|
}
|
|
else
|
|
{
|
|
self.endtime = 0;
|
|
}
|
|
|
|
self.duration = 1; // 1 / duration
|
|
self.cnt = time; // start time
|
|
self.dest2 = '0 0 0'; // delta
|
|
self.dest1 = self.origin; // original position
|
|
};
|
|
|
|
/*quaked func_rotate_train (0 .5 .8) (-8 -8 -8) (8 8 8)
|
|
in path_rotate, set speed to be the new speed of the train after it reaches
|
|
the path change. if speed is -1, the train will warp directly to the next
|
|
path change after the specified wait time. if movetime is set on the
|
|
path_rotate, the train to interprets "speed" as the length of time to
|
|
take moving from one corner to another.
|
|
|
|
"noise" contains the name of the sound to play when train stops.
|
|
"noise1" contains the name of the sound to play when train moves.
|
|
both "noise" and "noise1" defaults depend upon "sounds" variable and
|
|
can be overridden by the "noise" and "noise1" variable in path_rotate.
|
|
|
|
also in path_rotate, if stop is set, the train will wait until it is
|
|
retriggered before moving on to the next goal.
|
|
|
|
trains are moving platforms that players can ride.
|
|
"path" specifies the first path_rotate and is the starting position.
|
|
if the train is the target of a button or trigger, it will not begin moving until activated.
|
|
the func_rotate_train entity is the center of rotation of all objects targeted by it.
|
|
|
|
if "deathtype" is set with a string, this is the message that will appear when a player is killed by the train.
|
|
|
|
speed default 100
|
|
dmg default 0
|
|
sounds
|
|
1) ratchet metal
|
|
*/
|
|
|
|
void() rotate_train =
|
|
{
|
|
objerror ("rotate_train entities should be changed to rotate_object with\nfunc_rotate_train controllers\n");
|
|
};
|
|
|
|
void() func_rotate_train =
|
|
{
|
|
if (!self.speed)
|
|
self.speed = 100;
|
|
if (!self.target)
|
|
objerror ("rotate_train without a target");
|
|
|
|
if ( !self.noise )
|
|
{
|
|
if (self.sounds == 0)
|
|
{
|
|
self.noise = ("misc/null.wav");
|
|
}
|
|
|
|
if (self.sounds == 1)
|
|
{
|
|
self.noise = ("plats/train2.wav");
|
|
}
|
|
}
|
|
if ( !self.noise1 )
|
|
{
|
|
if (self.sounds == 0)
|
|
{
|
|
self.noise1 = ("misc/null.wav");
|
|
}
|
|
if (self.sounds == 1)
|
|
{
|
|
self.noise1 = ("plats/train1.wav");
|
|
}
|
|
}
|
|
|
|
precache_sound( self.noise );
|
|
precache_sound( self.noise1 );
|
|
|
|
self.cnt = 1;
|
|
self.solid = solid_not;
|
|
self.movetype = movetype_step;
|
|
self.use = rotate_train_use;
|
|
|
|
setmodel (self, self.model);
|
|
setsize (self, self.mins, self.maxs);
|
|
setorigin (self, self.origin);
|
|
|
|
// start trains on the second frame, to make sure their targets have had
|
|
// a chance to spawn
|
|
self.ltime = time;
|
|
self.nextthink = self.ltime + 0.1;
|
|
self.endtime = self.ltime + 0.1;
|
|
self.think = rotate_train_think;
|
|
self.think1 = rotate_train_find;
|
|
self.state = state_find;
|
|
|
|
self.duration = 1; // 1 / duration
|
|
self.cnt = 0.1; // start time
|
|
self.dest2 = '0 0 0'; // delta
|
|
self.dest1 = self.origin; // original position
|
|
|
|
|
|
self.flags = self.flags | fl_onground;
|
|
};
|
|
|
|
//************************************************
|
|
//
|
|
// moving clip walls
|
|
//
|
|
//************************************************
|
|
|
|
void() rotate_door_reversedirection;
|
|
void() rotate_door_group_reversedirection;
|
|
|
|
void() movewall_touch =
|
|
{
|
|
if (time < self.owner.attack_finished)
|
|
return;
|
|
|
|
if ( self.dmg )
|
|
{
|
|
t_damage (other, self, self.owner, self.dmg);
|
|
self.owner.attack_finished = time + 0.5;
|
|
}
|
|
else if ( self.owner.dmg )
|
|
{
|
|
t_damage (other, self, self.owner, self.owner.dmg);
|
|
self.owner.attack_finished = time + 0.5;
|
|
}
|
|
};
|
|
|
|
void() movewall_blocked =
|
|
{
|
|
local entity temp;
|
|
|
|
if (time < self.owner.attack_finished)
|
|
return;
|
|
|
|
self.owner.attack_finished = time + 0.5;
|
|
|
|
if ( self.owner.classname == "func_rotate_door" )
|
|
{
|
|
temp = self;
|
|
self = self.owner;
|
|
rotate_door_group_reversedirection();
|
|
self = temp;
|
|
}
|
|
|
|
if ( self.dmg )
|
|
{
|
|
t_damage (other, self, self.owner, self.dmg);
|
|
self.owner.attack_finished = time + 0.5;
|
|
}
|
|
else if ( self.owner.dmg )
|
|
{
|
|
t_damage (other, self, self.owner, self.owner.dmg);
|
|
self.owner.attack_finished = time + 0.5;
|
|
}
|
|
};
|
|
|
|
void() movewall_think =
|
|
{
|
|
self.ltime = time;
|
|
self.nextthink = time + 0.02;
|
|
};
|
|
|
|
/*quaked func_movewall (0 .5 .8) ? visible touch nonblocking
|
|
used to emulate collision on rotating objects.
|
|
|
|
visible causes brush to be displayed.
|
|
|
|
touch specifies whether to cause damage when touched by player.
|
|
|
|
nonblocking makes the brush non-solid. this is useless if visible is set.
|
|
|
|
"dmg" specifies the damage to cause when touched or blocked.
|
|
*/
|
|
void() func_movewall =
|
|
{
|
|
self.angles = '0 0 0';
|
|
self.movetype = movetype_push;
|
|
if ( self.spawnflags & nonblocking )
|
|
{
|
|
self.solid = solid_not;
|
|
}
|
|
else
|
|
{
|
|
self.solid = solid_bsp;
|
|
self.blocked = movewall_blocked;
|
|
}
|
|
if ( self.spawnflags & touch )
|
|
{
|
|
self.touch = movewall_touch;
|
|
}
|
|
setmodel (self,self.model);
|
|
if ( !( self.spawnflags & visible ) )
|
|
{
|
|
self.model = string_null;
|
|
}
|
|
self.think = movewall_think;
|
|
self.nextthink = time + 0.02;
|
|
self.ltime = time;
|
|
};
|
|
|
|
/*quaked rotate_object (0 .5 .8) ?
|
|
this defines an object to be rotated. used as the target of func_rotate_door.
|
|
*/
|
|
void() rotate_object =
|
|
{
|
|
self.classname = "rotate_object";
|
|
self.solid = solid_not;
|
|
self.movetype = movetype_none;
|
|
setmodel (self,self.model);
|
|
setsize( self, self.mins, self.maxs );
|
|
self.think = sub_null;
|
|
};
|
|
|
|
//************************************************
|
|
//
|
|
// rotating doors
|
|
//
|
|
//************************************************
|
|
|
|
void() rotate_door_think2 =
|
|
{
|
|
local float t;
|
|
|
|
t = time - self.ltime;
|
|
self.ltime = time;
|
|
|
|
// change to alternate textures
|
|
self.frame = 1 - self.frame;
|
|
|
|
self.angles = self.dest;
|
|
|
|
if ( self.state == state_opening )
|
|
{
|
|
self.state = state_open;
|
|
}
|
|
else
|
|
{
|
|
if ( self.spawnflags & stayopen )
|
|
{
|
|
rotate_door_group_reversedirection();
|
|
return;
|
|
}
|
|
self.state = state_closed;
|
|
}
|
|
|
|
sound(self, chan_voice, self.noise3, 1, attn_norm);
|
|
self.think = sub_null;
|
|
|
|
rotatetargetsfinal();
|
|
};
|
|
|
|
void() rotate_door_think =
|
|
{
|
|
local float t;
|
|
|
|
t = time - self.ltime;
|
|
self.ltime = time;
|
|
|
|
if ( time < self.endtime )
|
|
{
|
|
self.angles = self.angles + ( self.rotate * t );
|
|
rotatetargets();
|
|
}
|
|
else
|
|
{
|
|
self.angles = self.dest;
|
|
rotatetargets();
|
|
self.think = rotate_door_think2;
|
|
}
|
|
|
|
self.nextthink = time + 0.01;
|
|
};
|
|
|
|
void() rotate_door_reversedirection =
|
|
{
|
|
local vector start;
|
|
|
|
// change to alternate textures
|
|
self.frame = 1 - self.frame;
|
|
|
|
if ( self.state == state_closing )
|
|
{
|
|
start = self.dest1;
|
|
self.dest = self.dest2;
|
|
self.state = state_opening;
|
|
}
|
|
else
|
|
{
|
|
start = self.dest2;
|
|
self.dest = self.dest1;
|
|
self.state = state_closing;
|
|
}
|
|
|
|
sound(self, chan_voice, self.noise2, 1, attn_norm);
|
|
|
|
self.rotate = ( self.dest - start ) * ( 1 / self.speed );
|
|
self.think = rotate_door_think;
|
|
self.nextthink = time + 0.02;
|
|
self.endtime = time + self.speed - ( self.endtime - time );
|
|
self.ltime = time;
|
|
};
|
|
|
|
void() rotate_door_group_reversedirection =
|
|
{
|
|
local string name;
|
|
|
|
// tell all associated rotaters to reverse direction
|
|
if ( self.group )
|
|
{
|
|
name = self.group;
|
|
self = find( world, group, name);
|
|
while( self )
|
|
{
|
|
rotate_door_reversedirection();
|
|
self = find( self, group, name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rotate_door_reversedirection();
|
|
}
|
|
};
|
|
|
|
void() rotate_door_use =
|
|
{
|
|
local entity t;
|
|
local vector start;
|
|
|
|
if ( ( self.state != state_open ) && ( self.state != state_closed ) )
|
|
return;
|
|
|
|
if ( !self.cnt )
|
|
{
|
|
self.cnt = 1;
|
|
linkrotatetargets();
|
|
}
|
|
|
|
// change to alternate textures
|
|
self.frame = 1 - self.frame;
|
|
|
|
if ( self.state == state_closed )
|
|
{
|
|
start = self.dest1;
|
|
self.dest = self.dest2;
|
|
self.state = state_opening;
|
|
}
|
|
else
|
|
{
|
|
start = self.dest2;
|
|
self.dest = self.dest1;
|
|
self.state = state_closing;
|
|
}
|
|
|
|
sound(self, chan_voice, self.noise2, 1, attn_norm);
|
|
|
|
self.rotate = ( self.dest - start ) * ( 1 / self.speed );
|
|
self.think = rotate_door_think;
|
|
self.nextthink = time + 0.01;
|
|
self.endtime = time + self.speed;
|
|
self.ltime = time;
|
|
};
|
|
|
|
|
|
/*quaked func_rotate_door (0 .5 .8) (-8 -8 -8) (8 8 8) stayopen
|
|
creates a door that rotates between two positions around a point of
|
|
rotation each time it's triggered.
|
|
|
|
stayopen tells the door to reopen after closing. this prevents a trigger-
|
|
once door from closing again when it's blocked.
|
|
|
|
"dmg" specifies the damage to cause when blocked. defaults to 2. negative numbers indicate no damage.
|
|
"speed" specifies how the time it takes to rotate
|
|
|
|
"sounds"
|
|
1) medieval (default)
|
|
2) metal
|
|
3) base
|
|
*/
|
|
|
|
void() func_rotate_door =
|
|
{
|
|
if (!self.target)
|
|
{
|
|
objerror( "rotate_door without target." );
|
|
}
|
|
|
|
self.dest1 = '0 0 0';
|
|
self.dest2 = self.angles;
|
|
self.angles = self.dest1;
|
|
|
|
// default to 2 seconds
|
|
if ( !self.speed )
|
|
{
|
|
self.speed = 2;
|
|
}
|
|
|
|
self.cnt = 0;
|
|
|
|
if (!self.dmg)
|
|
self.dmg = 2;
|
|
else if ( self.dmg < 0 )
|
|
{
|
|
self.dmg = 0;
|
|
}
|
|
|
|
if (self.sounds == 0)
|
|
self.sounds = 1;
|
|
if (self.sounds == 1)
|
|
{
|
|
precache_sound ("doors/latch2.wav");
|
|
precache_sound ("doors/winch2.wav");
|
|
precache_sound ("doors/drclos4.wav");
|
|
self.noise1 = "doors/latch2.wav";
|
|
self.noise2 = "doors/winch2.wav";
|
|
self.noise3 = "doors/drclos4.wav";
|
|
}
|
|
if (self.sounds == 2)
|
|
{
|
|
precache_sound ("doors/airdoor1.wav");
|
|
precache_sound ("doors/airdoor2.wav");
|
|
self.noise2 = "doors/airdoor1.wav";
|
|
self.noise1 = "doors/airdoor2.wav";
|
|
self.noise3 = "doors/airdoor2.wav";
|
|
}
|
|
if (self.sounds == 3)
|
|
{
|
|
precache_sound ("doors/basesec1.wav");
|
|
precache_sound ("doors/basesec2.wav");
|
|
self.noise2 = "doors/basesec1.wav";
|
|
self.noise1 = "doors/basesec2.wav";
|
|
self.noise3 = "doors/basesec2.wav";
|
|
}
|
|
|
|
self.solid = solid_not;
|
|
self.movetype = movetype_none;
|
|
setmodel (self, self.model);
|
|
setorigin( self, self.origin );
|
|
setsize( self, self.mins, self.maxs );
|
|
self.state = state_closed;
|
|
self.use = rotate_door_use;
|
|
self.think = sub_null;
|
|
};
|