2010 lines
48 KiB
C++
2010 lines
48 KiB
C++
/*
|
|
* $Header: /H2 Mission Pack/HCode/Doors.hc 26 3/19/98 2:26p Mgummelt $
|
|
*/
|
|
|
|
float DOOR_START_OPEN = 1;
|
|
float REVERSE = 2;
|
|
float DOOR_DONT_LINK = 4;
|
|
float DOOR_TOGGLE = 8;
|
|
float DOOR_SLIDE = 16;
|
|
float DOOR_NORMAL = 32;
|
|
float DOOR_REMOVE_PP = 64;
|
|
float DOOR_NO_PP = 128;
|
|
|
|
/*
|
|
Doors are similar to buttons, but can spawn a fat trigger field around them
|
|
to open without a touch, and they link together to form simultanious
|
|
double/quad doors.
|
|
|
|
Door.owner is the master door. If there is only one door, it points to itself.
|
|
If multiple doors, all will point to a single one.
|
|
|
|
Door.enemy chains from the master door through all doors linked in the chain.
|
|
*/
|
|
|
|
void door_hit_bottom();
|
|
void door_hit_top();
|
|
|
|
/*
|
|
===========================================================================
|
|
door_slide
|
|
===========================================================================
|
|
*/
|
|
|
|
void door_slide_next()
|
|
{
|
|
local vector vdestdelta, odelta;
|
|
local float len, tspeed;//, len2;
|
|
|
|
tspeed = self.speed;
|
|
|
|
if(!tspeed)
|
|
objerror("No speed is defined!");
|
|
|
|
// Make sure we're not already at the destination
|
|
if(self.finaldest == self.origin)
|
|
{
|
|
self.velocity = '0 0 0';
|
|
if(self.state == STATE_DOWN)
|
|
self.think = door_hit_bottom;
|
|
else if(self.state == STATE_UP)
|
|
self.think = door_hit_top;
|
|
self.nextthink = self.ltime + 0.1;
|
|
return;
|
|
}
|
|
|
|
vdestdelta = self.finaldest - self.origin; // Set destdelta to the vector needed to move
|
|
odelta = self.origin - self.pos1;
|
|
len = vlen(odelta); // Get the length of the vector
|
|
|
|
// If the length is this small, just stop
|
|
if(vlen(vdestdelta) < 0.1)
|
|
{
|
|
if(self.state == STATE_DOWN)
|
|
door_hit_bottom();
|
|
else if(self.state == STATE_UP)
|
|
door_hit_top();
|
|
else
|
|
dprint("Bad door state!\n");
|
|
return;
|
|
}
|
|
|
|
self.nextthink = self.ltime + 0.1;
|
|
self.think = door_slide_next;
|
|
|
|
tspeed = ((self.speed - (len / 10)) / 20);
|
|
|
|
if(tspeed < 2)
|
|
{
|
|
if(self.state == STATE_DOWN)
|
|
SUB_CalcMove(self.finaldest, self.speed, door_hit_bottom);
|
|
else if(self.state == STATE_UP)
|
|
SUB_CalcMove(self.finaldest, self.speed, door_hit_top);
|
|
else
|
|
dprint("Bad door state!\n");
|
|
return;
|
|
}
|
|
|
|
self.velocity = vdestdelta * tspeed;
|
|
}
|
|
|
|
|
|
void door_slide(vector tdest)
|
|
{
|
|
self.finaldest = tdest;
|
|
door_slide_next();
|
|
}
|
|
|
|
|
|
/*
|
|
===========================================================================
|
|
door_crash
|
|
===========================================================================
|
|
*/
|
|
|
|
void door_crash_next()
|
|
{
|
|
local vector vdestdelta, nextvect, testvect;
|
|
local vector tdest;
|
|
local float len, nextlen, testlen;
|
|
local float tspeed;
|
|
|
|
tdest = self.finaldest;
|
|
tspeed = self.speed;
|
|
|
|
if(!tspeed)
|
|
objerror("No speed is defined!");
|
|
|
|
if(tdest == self.origin)
|
|
{
|
|
self.velocity = '0 0 0';
|
|
if(self.state == STATE_DOWN)
|
|
self.think = door_hit_bottom;
|
|
else if(self.state == STATE_UP)
|
|
self.think = door_hit_top;
|
|
else
|
|
dprint("Bad door state!\n");
|
|
self.nextthink = self.ltime + 0.1;
|
|
return;
|
|
}
|
|
|
|
// set destdelta to the vector needed to move
|
|
vdestdelta = self.finaldest - self.origin;
|
|
nextvect = self.pos2 - self.origin;
|
|
testvect = self.pos2 - self.finaldest;
|
|
|
|
// calculate length of vector
|
|
len = vlen (vdestdelta);
|
|
nextlen = vlen(nextvect) + 1;
|
|
testlen = vlen(testvect);
|
|
|
|
if(len < 0.1 || nextlen > testlen)
|
|
{
|
|
door_hit_bottom;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
self.velocity = vdestdelta * (nextlen / len) * 4;
|
|
nextvect = self.origin + self.velocity;
|
|
nextlen = vlen(nextvect);
|
|
if(nextlen >= testlen * 2)
|
|
{
|
|
SUB_CalcMove(self.finaldest, self.speed * (len / (len / 3)), door_hit_bottom);
|
|
return;
|
|
}
|
|
}
|
|
|
|
self.nextthink = self.ltime + 0.1;
|
|
self.think = door_crash_next;
|
|
}
|
|
|
|
|
|
void door_crash(vector tdest)
|
|
{
|
|
self.finaldest = tdest;
|
|
door_crash_next();
|
|
}
|
|
|
|
/*
|
|
=============================================================================
|
|
THINK FUNCTIONS
|
|
=============================================================================
|
|
*/
|
|
|
|
void door_go_down();
|
|
void door_go_up();
|
|
|
|
void door_damage()
|
|
{
|
|
T_Damage (other, self, self, self.dmg);
|
|
}
|
|
|
|
void door_blocked()
|
|
{
|
|
//FIXME: Rotating doors sem to think they're being blocked
|
|
// even if they're rotating down and the object is above them
|
|
if(self.wait>-2&&self.strength<=0)
|
|
if(self.dmg==666)
|
|
{
|
|
if(other.classname=="player"&&other.flags2&FL_ALIVE)
|
|
{
|
|
other.decap=TRUE;
|
|
T_Damage (other, self, self, other.health+300);
|
|
}
|
|
else
|
|
T_Damage (other, self, self, other.health+50);
|
|
}
|
|
else
|
|
{
|
|
T_Damage (other, self, self, self.dmg);
|
|
}
|
|
|
|
|
|
//Rotating doors rotating around a x or z axis push you up and in the direction they're turning
|
|
/* if(self.strength==2)
|
|
{
|
|
other.flags(-)FL_ONGROUND;
|
|
other.velocity=normalize(self.origin-(other.absmin+other.absmax)*0.5)*100;
|
|
}
|
|
else*/ if(other.flags&FL_ONGROUND&&(self.movedir_x||self.movedir_z)&&self.strength==1)//&&other.origin_z>self.origin_z
|
|
{
|
|
other.flags(-)FL_ONGROUND;
|
|
other.velocity_z+=self.speed*2;
|
|
other.velocity_x-=self.speed*self.movedir_x;
|
|
other.velocity_y-=self.speed*self.movedir_z;
|
|
}
|
|
else
|
|
{
|
|
other.flags(-)FL_ONGROUND;
|
|
other.velocity_z+=10;
|
|
}
|
|
|
|
// if a door has a negative wait, it would never come back if blocked,
|
|
// so let it just squash the object to death real fast
|
|
if (other.health>0)
|
|
if (self.wait >= 0)
|
|
{
|
|
if (self.state == STATE_DOWN)
|
|
door_go_up ();
|
|
else
|
|
door_go_down ();
|
|
}
|
|
}
|
|
|
|
void door_blocked_mp()
|
|
{
|
|
float do_dmg;
|
|
|
|
/*
|
|
dprint("Blocked Door: \n");
|
|
dprint(other.classname);
|
|
dprint("\n");
|
|
dprintv("Velocity: %s\n",self.velocity);
|
|
dprintv("Avelocity: %s\n",self.avelocity);
|
|
*/
|
|
//FIXME: Rotating doors seem to think they're being blocked
|
|
// even if they're rotating down and the object is above them
|
|
// if(self.classname=="door_rotating")
|
|
// self.nextthink+=HX_FRAME_TIME;//self.wait?
|
|
|
|
/* dprint("door blocked\n");
|
|
dprintf("dmg = %s\n",self.dmg);
|
|
dprintf("strength = %s\n",self.strength);
|
|
dprintf("wait = %s\n",self.wait);
|
|
dprint("other = ");
|
|
dprint(other.classname);
|
|
dprint("\n");*/
|
|
if(self.dmg==-1)
|
|
{
|
|
if(other.classname=="player" && other.flags2&FL_ALIVE)
|
|
{
|
|
if (self.wait >= 0)
|
|
{
|
|
if (self.state == STATE_DOWN)
|
|
door_go_up ();
|
|
else
|
|
door_go_down ();
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
do_dmg=2;
|
|
}
|
|
else
|
|
do_dmg=self.dmg;
|
|
|
|
// dprintf("Door dmg = %s\n",do_dmg);
|
|
if(self.wait>-2)//&&self.strength<=0)
|
|
{
|
|
if(do_dmg==666)
|
|
{
|
|
if(other.classname=="player"&&other.flags2&FL_ALIVE)
|
|
{
|
|
other.decap=TRUE;
|
|
T_Damage (other, self, self, other.health+300);
|
|
}
|
|
else
|
|
T_Damage (other, self, self, other.health+50);
|
|
}
|
|
else
|
|
{
|
|
// dprintf("crushing- %s\n",do_dmg);
|
|
T_Damage (other, self, self, do_dmg);//FIXME: Rotating doors get stuck open and never try to return
|
|
}
|
|
}
|
|
// else
|
|
// dprint("Door wait <= -2\n");
|
|
|
|
//Rotating doors rotating around a x or z axis push you up and in the direction they're turning
|
|
/* if(self.strength==2)
|
|
{
|
|
other.flags(-)FL_ONGROUND;
|
|
other.velocity=normalize(self.origin-(other.absmin+other.absmax)*0.5)*100;
|
|
}
|
|
else*/
|
|
|
|
/*NOT in MP maps?
|
|
if(other.flags&FL_ONGROUND&&(self.movedir_x||self.movedir_z)&&self.strength==1)//&&other.origin_z>self.origin_z
|
|
{//This is not neccessary anymore
|
|
other.flags(-)FL_ONGROUND;
|
|
other.velocity_z+=self.speed*2;
|
|
other.velocity_x-=self.speed*self.movedir_x;
|
|
other.velocity_y-=self.speed*self.movedir_z;
|
|
}
|
|
else
|
|
{
|
|
other.flags(-)FL_ONGROUND;
|
|
other.velocity_z+=10;
|
|
}
|
|
*/
|
|
// if a door has a negative wait, it would never come back if blocked,
|
|
// so let it just squash the object to death real fast
|
|
if (other.health>0)
|
|
if (self.wait >= 0)//&&self.wait!=1.5)
|
|
{
|
|
if (self.state == STATE_DOWN)
|
|
{
|
|
// dprint("Going up...\n");
|
|
door_go_up ();
|
|
}
|
|
else
|
|
{
|
|
// dprint("Going down...\n");
|
|
door_go_down ();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void door_hit_top()
|
|
{
|
|
self.velocity = '0 0 0';
|
|
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
|
|
self.state = STATE_TOP;
|
|
|
|
if (self.spawnflags & DOOR_TOGGLE)
|
|
return; // don't come down automatically
|
|
|
|
if(self.wait== -2)
|
|
self.th_die();
|
|
else if(self.wait== -1)
|
|
self.nextthink = -1;
|
|
else
|
|
{
|
|
self.think = door_go_down;
|
|
self.nextthink = self.ltime + self.wait;
|
|
}
|
|
}
|
|
|
|
void door_hit_bottom()
|
|
{
|
|
self.velocity = '0 0 0';
|
|
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
|
|
self.state = STATE_BOTTOM;
|
|
}
|
|
|
|
void door_go_down()
|
|
{
|
|
string hold_target;
|
|
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
if(!self.thingtype && self.max_health)
|
|
{
|
|
self.takedamage = DAMAGE_YES;
|
|
self.health = self.max_health;
|
|
}
|
|
|
|
self.state = STATE_DOWN;
|
|
|
|
if(self.classname == "door")
|
|
{
|
|
// dprintv("rotation: %s\n",self.v_angle);
|
|
if(self.spawnflags & DOOR_SLIDE)
|
|
door_slide(self.pos1);
|
|
else if(self.spawnflags & DOOR_NORMAL)
|
|
if(self.v_angle!='0 0 0')
|
|
if(self.speed)
|
|
if(self.anglespeed)
|
|
SUB_CalcMoveAndAngleInit (self.pos1, self.speed, self.o_angle, self.anglespeed, door_hit_bottom,FALSE);
|
|
else
|
|
SUB_CalcMoveAndAngleInit (self.pos1, self.speed, self.o_angle, self.anglespeed, door_hit_bottom,TRUE);
|
|
else
|
|
SUB_CalcAngleMove(self.o_angle, self.anglespeed, door_hit_bottom);
|
|
else
|
|
SUB_CalcMove(self.pos1, self.speed, door_hit_bottom);
|
|
else
|
|
door_crash(self.pos1);
|
|
}
|
|
else if (self.classname == "door_rotating")
|
|
SUB_CalcAngleMove(self.pos1, self.speed, door_hit_bottom);
|
|
|
|
if(self.close_target!="")
|
|
{//Use second target when closing
|
|
hold_target=self.target;
|
|
self.target=self.close_target;
|
|
SUB_UseTargets();
|
|
self.target=hold_target;
|
|
}
|
|
}
|
|
|
|
|
|
void new_movedir (vector movin,float dir)
|
|
{
|
|
self.movedir = movin;
|
|
|
|
// check for clockwise rotation
|
|
if (dir<0)
|
|
self.movedir = self.movedir * -1;
|
|
|
|
self.pos1 = self.angles;
|
|
self.pos2 = self.angles + self.movedir * self.dflags;
|
|
}
|
|
|
|
void door_go_up()
|
|
{
|
|
if(self.state == STATE_UP) /* Already going up */
|
|
{
|
|
// dprint("UP: Tried to go up while already going up\n");
|
|
return;
|
|
}
|
|
|
|
if(self.state == STATE_TOP) /* Reset top wait time */
|
|
{
|
|
self.nextthink = self.ltime + self.wait;
|
|
// dprint("TOP: Tried to go up while already at top\n");
|
|
return;
|
|
}
|
|
|
|
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
self.state = STATE_UP;
|
|
|
|
if(self.classname == "door")
|
|
{
|
|
if(self.spawnflags & DOOR_NORMAL)
|
|
{
|
|
if(self.v_angle!='0 0 0')
|
|
{
|
|
if(self.speed)
|
|
{
|
|
if(self.anglespeed)
|
|
SUB_CalcMoveAndAngleInit (self.pos2, self.speed, self.v_angle, self.anglespeed, door_hit_top,FALSE);
|
|
else
|
|
SUB_CalcMoveAndAngleInit (self.pos2, self.speed, self.v_angle, self.anglespeed, door_hit_top,TRUE);
|
|
}
|
|
else
|
|
SUB_CalcAngleMove(self.v_angle, self.anglespeed, door_hit_top);
|
|
}
|
|
else
|
|
SUB_CalcMove(self.pos2, self.speed, door_hit_top);
|
|
}
|
|
else
|
|
door_slide(self.pos2);
|
|
}
|
|
else if(self.classname == "door_rotating")
|
|
SUB_CalcAngleMove(self.pos2, self.speed, door_hit_top);
|
|
|
|
SUB_UseTargets();
|
|
}
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
ACTIVATION FUNCTIONS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
void door_fire()
|
|
{
|
|
entity oself;
|
|
entity starte;
|
|
|
|
// if(self.wait<=-1 || self.wait==1.5)//not supposed to return
|
|
// if(self.velocity!='0 0 0'||self.avelocity!='0 0 0')//Moving
|
|
// return;
|
|
|
|
if (self.owner != self)
|
|
objerror ("door_fire: self.owner != self");
|
|
|
|
self.no_puzzle_msg = 0;
|
|
|
|
// play use key sound
|
|
|
|
self.message = 0; // no more message
|
|
oself = self;
|
|
|
|
if (self.spawnflags & DOOR_TOGGLE)
|
|
{
|
|
if (self.state == STATE_UP || self.state == STATE_TOP)
|
|
{
|
|
starte = self;
|
|
do
|
|
{
|
|
door_go_down ();
|
|
self = self.enemy;
|
|
} while ( (self != starte) && (self != world) );
|
|
self = oself;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// trigger all paired doors
|
|
starte = self;
|
|
do
|
|
{
|
|
door_go_up ();
|
|
self = self.enemy;
|
|
} while ( (self != starte) && (self != world) );
|
|
self = oself;
|
|
}
|
|
|
|
|
|
/*
|
|
* door_use() -- Called whenever a door is opened.
|
|
*/
|
|
|
|
void door_use()
|
|
{
|
|
entity oself;
|
|
|
|
|
|
/*
|
|
dprint("Door Used by: ");
|
|
dprint(other.classname);
|
|
dprint("\n");
|
|
dprint("Door's Activator: ");
|
|
dprint(activator.classname);
|
|
dprint("\n");
|
|
*/
|
|
|
|
if(self.inactive)
|
|
{
|
|
// dprint("Door not active\n");
|
|
return;
|
|
}
|
|
|
|
self.message = 0; // door messages are for touch only
|
|
self.owner.message = 0;
|
|
self.enemy.message = 0;
|
|
oself = self;
|
|
self = self.owner;
|
|
door_fire ();
|
|
self = oself;
|
|
}
|
|
|
|
|
|
// defined in triggers.hc
|
|
float check_puzzle_pieces(entity client, float remove_pieces, float inverse);
|
|
|
|
/*
|
|
* door_trigger_touch() -- Called when someone touches a door.
|
|
*/
|
|
|
|
void door_trigger_touch()
|
|
{
|
|
entity door;
|
|
string temp;
|
|
float removepp, inversepp;
|
|
|
|
// if(!other.flags2&FL_ALIVE)
|
|
// return;
|
|
|
|
if(!other.flags&FL_CLIENT&&!other.flags&FL_MONSTER)
|
|
return;
|
|
|
|
if(other.flags&FL_MONSTER&&world.spawnflags&MISSIONPACK)
|
|
return;
|
|
|
|
if(time < self.attack_finished)
|
|
return;
|
|
|
|
door = self;
|
|
self = self.owner;
|
|
if(!deathmatch)
|
|
{
|
|
removepp = (self.spawnflags & DOOR_REMOVE_PP);
|
|
inversepp = (self.spawnflags & DOOR_NO_PP);
|
|
|
|
if (!check_puzzle_pieces(other,removepp,inversepp))
|
|
{
|
|
if (self.no_puzzle_msg && !deathmatch)
|
|
{
|
|
temp = getstring(self.no_puzzle_msg);
|
|
centerprint (other, temp);
|
|
door.attack_finished = time + 2;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
self.attack_finished = time + 1;
|
|
|
|
activator = other;
|
|
door_use();
|
|
}
|
|
|
|
|
|
/*
|
|
* door_killed() -- Used to open doors that open when shot.
|
|
*/
|
|
|
|
void door_killed()
|
|
{
|
|
local entity oself;
|
|
|
|
oself = self;
|
|
self = self.owner;
|
|
self.health = self.max_health;
|
|
self.takedamage = DAMAGE_NO; // wil be reset upon return
|
|
door_use();
|
|
self = oself;
|
|
}
|
|
|
|
|
|
/*
|
|
* door_touch() -- Prints messages and opens key doors.
|
|
*/
|
|
|
|
void door_touch()
|
|
{
|
|
string temp;
|
|
float removepp, inversepp;
|
|
|
|
// dprint("Door hit!\n");
|
|
// if(!other.flags2&FL_ALIVE)
|
|
// return;
|
|
|
|
if(!other.flags&FL_CLIENT&&!other.flags&FL_MONSTER)
|
|
return;
|
|
|
|
if(other.flags&FL_MONSTER&&world.spawnflags&MISSIONPACK)
|
|
return;
|
|
|
|
if(self.dmg==666&&(self.velocity!='0 0 0'||self.avelocity!='0 0 0'))
|
|
{
|
|
if(other.classname=="player"&&other.flags2&FL_ALIVE)
|
|
{
|
|
other.decap=TRUE;
|
|
T_Damage (other, self, self, other.health+300);
|
|
}
|
|
else
|
|
T_Damage (other, self, self, other.health+50);
|
|
}
|
|
|
|
if(self.owner.attack_finished > time)
|
|
return;
|
|
|
|
if (self.owner)
|
|
self.owner.attack_finished = time + 2;
|
|
|
|
if(self.owner.message != 0 && !deathmatch && self.owner != world)
|
|
{
|
|
temp = getstring(self.owner.message);
|
|
centerprint (other, temp);
|
|
sound (other, CHAN_VOICE, "misc/comm.wav", 1, ATTN_NORM);
|
|
}
|
|
|
|
// key door stuff
|
|
|
|
if (!self.puzzle_piece_1 && !self.puzzle_piece_2 && !self.puzzle_piece_3 && !self.puzzle_piece_4)
|
|
return;
|
|
|
|
// FIXME: blink key on player's status bar
|
|
|
|
removepp = (self.spawnflags & DOOR_REMOVE_PP);
|
|
inversepp = (self.spawnflags & DOOR_NO_PP);
|
|
|
|
if (!check_puzzle_pieces(other,removepp,inversepp))
|
|
{
|
|
if (self.no_puzzle_msg && !deathmatch)
|
|
{
|
|
temp = getstring(self.no_puzzle_msg);
|
|
centerprint (other, temp);
|
|
}
|
|
return;
|
|
}
|
|
self.touch = SUB_Null;
|
|
if (self.enemy)
|
|
self.enemy.touch = SUB_Null; // get paired door
|
|
door_use ();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
SPAWNING FUNCTIONS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
entity spawn_field(vector fmins, vector fmaxs, entity door)
|
|
{//FIXME: THIS ENTITY NEEDS TO REMOVE ITSELF IF IT'S OWNER IS
|
|
//REMOVED!
|
|
entity trigger;
|
|
vector t1, t2;
|
|
|
|
trigger = spawn();
|
|
trigger.movetype = MOVETYPE_NONE;
|
|
trigger.solid = SOLID_TRIGGER;
|
|
trigger.owner = door;
|
|
trigger.touch = door_trigger_touch;
|
|
|
|
t1 = fmins;
|
|
t2 = fmaxs;
|
|
// if (door.classname == "door")
|
|
// {
|
|
// if(self.v_angle!='0 0 0')
|
|
// {
|
|
t1 += door.origin;
|
|
t2 += door.origin;
|
|
setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
|
|
/* }
|
|
else
|
|
setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
|
|
}
|
|
else if (door.classname == "door_rotating")
|
|
{
|
|
t1 += door.origin;
|
|
t2 += door.origin;
|
|
setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
|
|
}
|
|
*/ return (trigger);
|
|
}
|
|
|
|
float EntitiesTouching(entity e1, entity e2)
|
|
{
|
|
local vector e1max, e1min, e2max, e2min;
|
|
|
|
//Rotating door's mins and maxs aren't based on their world positions,
|
|
//so the origin needs to be applied to make sure they are checking their
|
|
//real positions
|
|
|
|
if (e1.classname == "door_rotating"||(e1.classname=="door"&&e1.v_angle!='0 0 0'))
|
|
{
|
|
e1max = e1.maxs + e1.origin;
|
|
e1min = e1.mins + e1.origin;
|
|
e2max = e2.maxs + e2.origin;
|
|
e2min = e2.mins + e2.origin;
|
|
}
|
|
else
|
|
{
|
|
e1max = e1.maxs;
|
|
e1min = e1.mins;
|
|
e2max = e2.maxs;
|
|
e2min = e2.mins;
|
|
}
|
|
|
|
if (e1min_x > e2max_x)
|
|
return FALSE;
|
|
if (e1min_y > e2max_y)
|
|
return FALSE;
|
|
if (e1min_z > e2max_z)
|
|
return FALSE;
|
|
if (e1max_x < e2min_x)
|
|
return FALSE;
|
|
if (e1max_y < e2min_y)
|
|
return FALSE;
|
|
if (e1max_z < e2min_z)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* LinkDoors()
|
|
*/
|
|
|
|
void LinkDoors()
|
|
{
|
|
entity t, starte;
|
|
vector cmins, cmaxs;
|
|
|
|
if (self.enemy)
|
|
return; // already linked by another door
|
|
|
|
if (self.spawnflags & 4)
|
|
{
|
|
self.owner = self.enemy = self;
|
|
return; // don't want to link this door
|
|
}
|
|
|
|
cmins = self.mins;
|
|
cmaxs = self.maxs;
|
|
|
|
starte = self;
|
|
t = self;
|
|
|
|
do
|
|
{
|
|
self.owner = starte; // master door
|
|
|
|
if (!self.thingtype && self.health)
|
|
starte.health = self.health;
|
|
if (self.targetname)
|
|
starte.targetname = self.targetname;
|
|
if (self.message != 0)
|
|
starte.message = self.message;
|
|
|
|
t = find (t, classname, self.classname);
|
|
if (!t)
|
|
{
|
|
self.enemy = starte; // make the chain a loop
|
|
|
|
// shootable, fired, or key doors just needed the owner/enemy links,
|
|
// they don't spawn a field
|
|
|
|
self = self.owner;
|
|
|
|
if (!self.thingtype && self.health)
|
|
return;
|
|
if (self.targetname)
|
|
return;
|
|
if (self.puzzle_piece_1 != string_null ||
|
|
self.puzzle_piece_2 != string_null ||
|
|
self.puzzle_piece_3 != string_null ||
|
|
self.puzzle_piece_4 != string_null)
|
|
return;
|
|
|
|
self.owner.trigger_field = spawn_field(cmins, cmaxs, self.owner);
|
|
|
|
return;
|
|
}
|
|
|
|
if (EntitiesTouching(self,t))
|
|
{
|
|
if (t.enemy)
|
|
objerror ("cross connected doors");
|
|
|
|
self.enemy = t;
|
|
self = t;
|
|
|
|
if (t.mins_x < cmins_x)
|
|
cmins_x = t.mins_x;
|
|
if (t.mins_y < cmins_y)
|
|
cmins_y = t.mins_y;
|
|
if (t.mins_z < cmins_z)
|
|
cmins_z = t.mins_z;
|
|
if (t.maxs_x > cmaxs_x)
|
|
cmaxs_x = t.maxs_x;
|
|
if (t.maxs_y > cmaxs_y)
|
|
cmaxs_y = t.maxs_y;
|
|
if (t.maxs_z > cmaxs_z)
|
|
cmaxs_z = t.maxs_z;
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
void door_sounds(void)
|
|
{
|
|
self.noise3 = "doors/baddoor.wav";
|
|
|
|
if (self.soundtype == 0) // No sound
|
|
{
|
|
self.noise1 = "misc/null.wav";
|
|
self.noise2 = "misc/null.wav";
|
|
self.noise4 = "misc/null.wav";
|
|
}
|
|
else if (self.soundtype == 1) // Big Metal door, swinging
|
|
{
|
|
precache_sound ("doors/gatestop.wav");
|
|
precache_sound ("doors/gateswng.wav");
|
|
precache_sound ("doors/gatestrt.wav");
|
|
|
|
self.noise1 = "doors/gatestop.wav";
|
|
self.noise2 = "doors/gateswng.wav";
|
|
self.noise4 = "doors/gatestrt.wav";
|
|
}
|
|
else if (self.soundtype == 2) // Big Stone Door, sliding
|
|
{
|
|
precache_sound ("doors/doorstop.wav");
|
|
precache_sound ("doors/stonslid.wav");
|
|
precache_sound ("doors/dorstart.wav");
|
|
|
|
self.noise1 = "doors/doorstop.wav";
|
|
self.noise2 = "doors/stonslid.wav";
|
|
self.noise4 = "doors/dorstart.wav";
|
|
}
|
|
else if (self.soundtype == 3) // Big Wood Door, Swinging
|
|
{
|
|
precache_sound ("doors/swngstop.wav");
|
|
precache_sound ("doors/wdswngbg.wav");
|
|
precache_sound ("doors/dorstart.wav");
|
|
|
|
self.noise1 = "doors/swngstop.wav";
|
|
self.noise2 = "doors/wdswngbg.wav";
|
|
self.noise4 = "doors/dorstart.wav";
|
|
}
|
|
else if (self.soundtype == 4) // Normal Wood Door, Swinging
|
|
{
|
|
precache_sound ("doors/swngstop.wav");
|
|
precache_sound ("doors/wdswngsm.wav");
|
|
precache_sound ("doors/dorstart.wav");
|
|
|
|
self.noise1 = "doors/swngstop.wav";
|
|
self.noise2 = "doors/wdswngsm.wav";
|
|
self.noise4 = "doors/dorstart.wav";
|
|
}
|
|
else if (self.soundtype == 5) // Big Wood Door, Sliding
|
|
{
|
|
precache_sound ("doors/swngstop.wav");
|
|
precache_sound ("doors/woodslid.wav");
|
|
precache_sound ("doors/dorstart.wav");
|
|
|
|
self.noise1 = "doors/swngstop.wav";
|
|
self.noise2 = "doors/woodslid.wav";
|
|
self.noise4 = "doors/dorstart.wav";
|
|
}
|
|
else if (self.soundtype == 6) // Drawbridge, Falling and crushing innocent peasants who are
|
|
// basically slave labor, who toil away their lives so that the rich upperclass
|
|
// can keep busy inbreeding with each other. Damn the aristocracy! Freedom to
|
|
// the common man! Burn the castle! Death to the tyrants!
|
|
{
|
|
precache_sound ("doors/doorstop.wav");
|
|
precache_sound ("doors/drawmove.wav");
|
|
precache_sound ("doors/drawstrt.wav");
|
|
|
|
self.noise1 = "doors/doorstop.wav";
|
|
self.noise2 = "doors/drawmove.wav";
|
|
self.noise4 = "doors/dorstart.wav";
|
|
}
|
|
else if (self.soundtype == 7) // Rotating Walkway
|
|
{
|
|
precache_sound ("doors/doorstop.wav");
|
|
precache_sound ("doors/stonslid.wav");
|
|
precache_sound ("doors/dorstart.wav");
|
|
|
|
self.noise1 = "doors/doorstop.wav";
|
|
self.noise2 = "doors/stonslid.wav";
|
|
self.noise4 = "doors/dorstart.wav";
|
|
}
|
|
else if (self.soundtype == 8) // Big Metal door, sliding
|
|
{
|
|
precache_sound ("doors/mtlstop.wav");
|
|
precache_sound ("doors/mtlslide.wav");
|
|
precache_sound ("doors/mtlstart.wav");
|
|
|
|
self.noise1 = "doors/mtlstop.wav";
|
|
self.noise2 = "doors/mtlslide.wav";
|
|
self.noise4 = "doors/mtlstart.wav";
|
|
}
|
|
else if (self.soundtype == 9) // Pendulum
|
|
{
|
|
precache_sound2 ("doors/penstop.wav");
|
|
precache_sound2 ("doors/penswing.wav");
|
|
precache_sound2 ("doors/penstart.wav");
|
|
|
|
self.noise1 = "doors/penstop.wav";
|
|
self.noise2 = "doors/penswing.wav";
|
|
self.noise4 = "doors/penstart.wav";
|
|
}
|
|
}
|
|
|
|
|
|
void door_rotate_incr_done()
|
|
{
|
|
// if(self.strength==2)
|
|
// cvar_set ("sv_gravity", "800");
|
|
}
|
|
|
|
void() door_rotate_incr =
|
|
{
|
|
vector newvect;
|
|
if(self.strength==2)
|
|
cvar_set ("sv_gravity", "100");
|
|
|
|
self.dflags=self.flags;
|
|
self.flags=0;
|
|
|
|
if(self.v_angle!='0 0 0')
|
|
{
|
|
if(random()>0.5&&self.v_angle_x!=0)
|
|
{
|
|
self.cnt=self.dflags=self.v_angle_x;
|
|
new_movedir('1 0 0',self.cnt);
|
|
}
|
|
else if(random()>0.5&&self.v_angle_y!=0)
|
|
{
|
|
self.cnt=self.dflags=self.v_angle_y;
|
|
new_movedir('0 1 0',self.cnt);
|
|
}
|
|
else if(self.v_angle_z!=0)
|
|
{
|
|
self.cnt=self.dflags=self.v_angle_z;
|
|
new_movedir('0 0 1',self.cnt);
|
|
}
|
|
}
|
|
newvect = self.movedir * self.cnt;
|
|
|
|
SUB_CalcAngleMove(self.angles + newvect, self.speed, door_rotate_incr_done);
|
|
};
|
|
|
|
/*QUAKED func_door (0 .5 .8) ? START_OPEN REVERSE DOOR_DONT_LINK TOGGLE SLIDE NORMAL_MOVE remove_pp no_pp
|
|
NOTE: Doors can now be activated and deactivated with the appropriate triggers.
|
|
"inactive" set to 1 to start the door deactivated.
|
|
|
|
if two doors touch, they are assumed to be connected and operate as a unit.
|
|
|
|
-----------------------FIELDS-------------------------
|
|
TOGGLE causes the door to wait in both the start and end states for a trigger event.
|
|
|
|
START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
|
|
|
|
Key doors are allways wait -1.
|
|
|
|
"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
|
|
"angle" determines the opening direction
|
|
"level" how far (in map units) to move in the specified angle- overrides default movement that is size of door
|
|
"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
|
|
"health" if set, door must be shot open
|
|
"speed" movement speed (100 default), -1 will not move, just rotate
|
|
"wait" wait before returning (3 default, -1 = never return)
|
|
"lip" lip remaining at end of move (8 default)
|
|
"dmg" damage to inflict when blocked (2 default) If you make it
|
|
666, it will gib anything it touches, and behead players.
|
|
-1 it will hurt other things, but not players
|
|
"close_target" secondary target to fire when door closes
|
|
|
|
ROTATING DOORS: MUST HAVE AN ORIGIN BRUSH
|
|
"v_angle" Angle to turn, in: pitch yaw roll, '0 0 0' will not rotate, just move (default = '0 0 0')
|
|
"anglespeed" how quickly to turn in that direction. no anglespeed will force it to choose one that will synch the completion of the rotation iwth the completion of the move. (default = 0)
|
|
"strength" When set to 1, it will throw something if it gets in the way
|
|
|
|
"soundtype"
|
|
0) no sound
|
|
1) Big metal door, swinging
|
|
2) Big stone door, sliding
|
|
3) Big wood door, swinging
|
|
4) Normal wood door, swinging
|
|
5) Big wood door, sliding
|
|
6) Drawbridge
|
|
7) Rotating walkway
|
|
8) Big metal door, sliding
|
|
9) Pendulum swinging
|
|
|
|
Puzzle Pieces (use the puzzle_id value from the pieces)
|
|
puzzle_piece_1
|
|
puzzle_piece_2
|
|
puzzle_piece_3
|
|
puzzle_piece_4
|
|
no_puzzle_msg: message when player doesn't have the right pieces
|
|
--------------------------------------------------------
|
|
|
|
*/
|
|
void func_door()
|
|
{
|
|
float movedist, num_axes;
|
|
door_sounds();
|
|
|
|
SetMovedir ();
|
|
// check for clockwise rotation
|
|
if (self.spawnflags & REVERSE)
|
|
{
|
|
self.movedir = self.movedir * -1;
|
|
self.v_angle = self.v_angle * -1;
|
|
}
|
|
|
|
self.max_health = self.health;
|
|
self.solid = SOLID_BSP;
|
|
self.movetype = MOVETYPE_PUSH;
|
|
setorigin (self, self.origin);
|
|
setmodel (self, self.model);
|
|
self.classname = "door";
|
|
|
|
self.use = door_use;
|
|
|
|
if (self.abslight)
|
|
self.drawflags = self.drawflags | MLS_ABSLIGHT;
|
|
|
|
if (self.speed==-1)
|
|
self.speed=0;
|
|
else if(!self.speed)
|
|
self.speed = 100;
|
|
|
|
if (!self.wait)
|
|
self.wait = 3;
|
|
|
|
if (!self.lip)
|
|
self.lip = 8;
|
|
|
|
if(world.spawnflags&MISSIONPACK)
|
|
self.blocked = door_blocked_mp;
|
|
else
|
|
self.blocked = door_blocked;
|
|
if (!self.dmg)
|
|
// self.dmg = -1;
|
|
self.dmg = 2;
|
|
|
|
self.pos1 = self.origin;
|
|
// dprintf("Worldspawn.spawnflags = %s\n",world.spawnflags);
|
|
if(world.spawnflags&MISSIONPACK)
|
|
{
|
|
// dprint("Using new door code\n");
|
|
if(self.level)
|
|
movedist = self.level - self.lip;
|
|
else
|
|
{
|
|
//was: movedist=fabs(self.movedir*self.size) - self.lip;
|
|
// dprintv("Door movedir = %s\n",self.movedir);
|
|
// dprintv("Door size = %s\n",self.size);
|
|
num_axes=0;
|
|
movedist=0;
|
|
if(fabs(self.movedir_x)>0.001)
|
|
{
|
|
// dprint("X axis\n");
|
|
movedist+=fabs(self.movedir_x*self.size_x);
|
|
num_axes+=1;
|
|
}
|
|
if(fabs(self.movedir_y)>0.001)
|
|
{
|
|
// dprint("Y axis\n");
|
|
movedist+=fabs(self.movedir_y*self.size_y);
|
|
num_axes+=1;
|
|
}
|
|
if(fabs(self.movedir_z)>0.001)
|
|
{
|
|
// dprint("Z axis\n");
|
|
movedist+=fabs(self.movedir_z*self.size_z);
|
|
num_axes+=1;
|
|
}
|
|
movedist=movedist/num_axes - self.lip;
|
|
// dprintf("Door movedist = %s\n",movedist);
|
|
}
|
|
self.pos2 = self.pos1 + self.movedir*movedist;
|
|
}
|
|
else
|
|
{
|
|
// dprint("Using old door code\n");
|
|
if(self.level)
|
|
self.pos2 = self.pos1 + self.movedir*(self.level - self.lip);
|
|
else
|
|
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
|
|
}
|
|
// dprintv("Pos1: %s\n",self.pos1);
|
|
// dprintv("Pos2: %s\n",self.pos2);
|
|
if(self.v_angle!='0 0 0')
|
|
{
|
|
self.o_angle=self.angles;
|
|
self.v_angle+=self.angles;
|
|
}
|
|
|
|
if(self.wait== -2)
|
|
{
|
|
self.th_die = chunk_death;
|
|
// self.takedamage = DAMAGE_YES;
|
|
if (!self.health)
|
|
{
|
|
if ((self.thingtype == THINGTYPE_GLASS) || (self.thingtype == THINGTYPE_CLEARGLASS))
|
|
self.max_health = self.health = 25;
|
|
else if ((self.thingtype == THINGTYPE_GREYSTONE) || (self.thingtype == THINGTYPE_BROWNSTONE))
|
|
self.max_health = self.health = 75;
|
|
else if (self.thingtype == THINGTYPE_WOOD)
|
|
self.max_health = self.health = 50;
|
|
else if (self.thingtype == THINGTYPE_METAL)
|
|
self.max_health = self.health = 100;
|
|
else if (self.thingtype == THINGTYPE_FLESH)
|
|
self.max_health = self.health = 30;
|
|
else
|
|
self.max_health = self.health = 25;
|
|
}
|
|
}
|
|
|
|
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
|
|
// but spawn in the open position
|
|
if (self.spawnflags & DOOR_START_OPEN)
|
|
{
|
|
if(self.v_angle!='0 0 0')
|
|
{
|
|
self.angles = self.v_angle;
|
|
self.v_angle = self.o_angle;
|
|
self.o_angle = self.angles;
|
|
}
|
|
setorigin (self, self.pos2);
|
|
self.pos2 = self.pos1;
|
|
self.pos1 = self.origin;
|
|
}
|
|
|
|
self.state = STATE_BOTTOM;
|
|
|
|
if (self.health)
|
|
{
|
|
self.takedamage = DAMAGE_YES;
|
|
self.th_die =self.th_pain= door_killed;
|
|
}
|
|
|
|
if (self.puzzle_piece_1 != string_null ||
|
|
self.puzzle_piece_2 != string_null ||
|
|
self.puzzle_piece_3 != string_null ||
|
|
self.puzzle_piece_4 != string_null)
|
|
self.wait = -1;
|
|
|
|
self.touch = door_touch;
|
|
|
|
// LinkDoors can't be done until all of the doors have been spawned, so
|
|
// the sizes can be detected properly.
|
|
self.think = LinkDoors;
|
|
self.nextthink = self.ltime + 0.1;
|
|
|
|
if (self.cnt)
|
|
{
|
|
self.touch = SUB_Null;
|
|
self.use = door_rotate_incr;
|
|
}
|
|
}
|
|
|
|
|
|
/*QUAKED func_door_smashing (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE SLIDE NORMAL_MOVE remove_pp no_pp
|
|
NOTE: Doors can now be activated and deactivated with the appropriate triggers.
|
|
"inactive" set to 1 to start the door deactivated.
|
|
|
|
if two doors touch, they are assumed to be connected and operate as a unit.
|
|
|
|
-----------------------FIELDS-------------------------
|
|
TOGGLE causes the door to wait in both the start and end states for a trigger event.
|
|
|
|
START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
|
|
|
|
Key doors are allways wait -1.
|
|
|
|
"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
|
|
"angle" determines the opening direction
|
|
"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
|
|
"speed" movement speed (100 default)
|
|
"wait" wait before returning (3 default, -1 = never return)
|
|
"lip" lip remaining at end of move (8 default)
|
|
"dmg" damage to inflict when blocked (2 default)
|
|
"close_target" secondary target to fire when door closes
|
|
|
|
|
|
"soundtype"
|
|
0) no sound
|
|
1) Big metal door, swinging
|
|
2) Big stone door, sliding
|
|
3) Big wood door, swinging
|
|
4) Normal wood door, swinging
|
|
5) Big wood door, sliding
|
|
6) Drawbridge
|
|
7) Rotating walkway
|
|
8) Big metal door, sliding
|
|
9) Pendulum swinging
|
|
|
|
|
|
|
|
Puzzle Pieces (use the puzzle_id value from the pieces)
|
|
puzzle_piece_1
|
|
puzzle_piece_2
|
|
puzzle_piece_3
|
|
puzzle_piece_4
|
|
no_puzzle_msg: message when player doesn't have the right pieces
|
|
--------------------------------------------------------
|
|
void func_door_smashing()
|
|
{
|
|
door_sounds();
|
|
|
|
SetMovedir ();
|
|
|
|
self.solid = SOLID_BSP;
|
|
self.movetype = MOVETYPE_PUSH;
|
|
setorigin (self, self.origin);
|
|
setmodel (self, self.model);
|
|
self.classname = "door";
|
|
|
|
if(world.spawnflags&MISSIONPACK)
|
|
self.blocked = door_blocked_mp;
|
|
else
|
|
self.blocked = door_blocked;
|
|
self.use = door_use;
|
|
|
|
if (!self.speed)
|
|
self.speed = 100;
|
|
if (!self.wait)
|
|
self.wait = 3;
|
|
if (!self.lip)
|
|
self.lip = 8;
|
|
if (!self.dmg)
|
|
self.dmg = 2;
|
|
|
|
self.pos1 = self.origin;
|
|
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
|
|
|
|
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
|
|
// but spawn in the open position
|
|
if (self.spawnflags & DOOR_START_OPEN)
|
|
{
|
|
setorigin (self, self.pos2);
|
|
self.pos2 = self.pos1;
|
|
self.pos1 = self.origin;
|
|
}
|
|
|
|
self.state = STATE_BOTTOM;
|
|
self.takedamage = DAMAGE_YES;
|
|
self.th_die = chunk_death;
|
|
|
|
if(self.soundtype == 1)
|
|
{
|
|
self.thingtype = THINGTYPE_GREYSTONE;
|
|
self.max_health = self.health = 75;
|
|
}
|
|
else if(self.soundtype == 4)
|
|
{
|
|
self.thingtype = THINGTYPE_METAL;
|
|
self.max_health = self.health = 100;
|
|
}
|
|
else {
|
|
self.thingtype = THINGTYPE_WOOD;
|
|
self.max_health = self.health = 50;
|
|
}
|
|
|
|
self.touch = door_touch;
|
|
|
|
// LinkDoors can't be done until all of the doors have been spawned, so
|
|
// the sizes can be detected properly.
|
|
self.think = LinkDoors;
|
|
self.nextthink = self.ltime + 0.1;
|
|
}*/
|
|
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
SECRET DOORS
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
void fd_secret_move1();
|
|
void fd_secret_move2();
|
|
void fd_secret_move3();
|
|
void fd_secret_move4();
|
|
void fd_secret_move5();
|
|
void fd_secret_move6();
|
|
void fd_secret_done();
|
|
|
|
float SECRET_OPEN_ONCE = 1; // stays open
|
|
float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
|
|
float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
|
|
float SECRET_NO_SHOOT = 8; // only opened by trigger
|
|
float SECRET_YES_SHOOT = 16; // shootable even if targeted
|
|
|
|
|
|
void fd_secret_use()
|
|
{
|
|
local float temp;
|
|
|
|
self.health = 10000;
|
|
|
|
// exit if still moving around...
|
|
if(self.origin != self.oldorigin)
|
|
return;
|
|
|
|
if(self.inactive)
|
|
return;
|
|
|
|
self.message = 0; // no more message
|
|
|
|
SUB_UseTargets(); // fire all targets / killtargets
|
|
|
|
if(!self.spawnflags & SECRET_NO_SHOOT)
|
|
{
|
|
self.th_pain = SUB_Null;
|
|
self.takedamage = DAMAGE_NO;
|
|
}
|
|
self.velocity = '0 0 0';
|
|
|
|
// Make a sound, wait a little...
|
|
|
|
sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
|
|
self.nextthink = self.ltime + 0.1;
|
|
|
|
temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
|
|
makevectors(self.mangle);
|
|
|
|
if(!self.t_width)
|
|
{
|
|
if (self.spawnflags & SECRET_1ST_DOWN)
|
|
self. t_width = fabs(v_up * self.size);
|
|
else
|
|
self. t_width = fabs(v_right * self.size);
|
|
}
|
|
|
|
if (!self.t_length)
|
|
self. t_length = fabs(v_forward * self.size);
|
|
|
|
if (self.spawnflags & SECRET_1ST_DOWN)
|
|
self.dest1 = self.origin - v_up * self.t_width;
|
|
else
|
|
self.dest1 = self.origin + v_right * (self.t_width * temp);
|
|
|
|
self.dest2 = self.dest1 + v_forward * self.t_length;
|
|
SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
|
|
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
}
|
|
|
|
|
|
/* Wait after the first movement... */
|
|
|
|
void fd_secret_move1()
|
|
{
|
|
self.nextthink = self.ltime + 1;
|
|
self.think = fd_secret_move2;
|
|
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
|
|
}
|
|
|
|
|
|
/* Start moving sideways with sound... */
|
|
|
|
void fd_secret_move2()
|
|
{
|
|
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
|
|
}
|
|
|
|
|
|
/* Wait here until it's time to go back... */
|
|
|
|
void fd_secret_move3()
|
|
{
|
|
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
|
|
if(!self.spawnflags & SECRET_OPEN_ONCE)
|
|
{
|
|
self.nextthink = self.ltime + self.wait;
|
|
self.think = fd_secret_move4;
|
|
}
|
|
}
|
|
|
|
|
|
/* Move backward... */
|
|
|
|
void fd_secret_move4()
|
|
{
|
|
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
|
|
}
|
|
|
|
|
|
/* Wait for one second... */
|
|
|
|
void fd_secret_move5()
|
|
{
|
|
self.nextthink = self.ltime + 1;
|
|
self.think = fd_secret_move6;
|
|
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
|
|
}
|
|
|
|
void fd_secret_move6()
|
|
{
|
|
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
|
|
}
|
|
|
|
void fd_secret_done()
|
|
{
|
|
if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
|
|
{
|
|
self.health = 10000;
|
|
self.takedamage = DAMAGE_YES;
|
|
self.th_pain = fd_secret_use;
|
|
}
|
|
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
|
|
}
|
|
|
|
void secret_blocked()
|
|
{
|
|
if (time < self.attack_finished)
|
|
return;
|
|
self.attack_finished = time + 0.5;
|
|
T_Damage (other, self, self, self.dmg);
|
|
}
|
|
|
|
|
|
/*
|
|
* secret_touch() -- Prints messages.
|
|
*/
|
|
|
|
void secret_touch()
|
|
{
|
|
string s;
|
|
|
|
if (other.classname != "player")
|
|
return;
|
|
|
|
if (self.attack_finished > time)
|
|
return;
|
|
|
|
self.attack_finished = time + 2;
|
|
|
|
if (self.message)
|
|
{
|
|
s = getstring(self.message);
|
|
centerprint (other, s);
|
|
sound (other, CHAN_BODY, "misc/comm.wav", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
|
|
/*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot x remove_pp no_pp
|
|
NOTE: Doors can now be activated and deactivated with the appropriate triggers.
|
|
"inactive" set to 1 to start the door deactivated.
|
|
|
|
Basic secret door. Slides back, then to the side. Angle determines direction.
|
|
-----------------------FIELDS-------------------------
|
|
wait = # of seconds before coming back
|
|
1st_left = 1st move is left of arrow
|
|
1st_down = 1st move is down from arrow
|
|
always_shoot = even if targeted, keep shootable
|
|
t_width = override WIDTH to move back (or height if going down)
|
|
t_length = override LENGTH to move sideways
|
|
"dmg" damage to inflict when blocked (2 default)
|
|
"close_target" secondary target to fire when door closes
|
|
|
|
If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
|
|
|
|
"soundtype"
|
|
0) no sound
|
|
1) Big metal door, swinging
|
|
2) Big stone door, sliding
|
|
3) Big wood door, swinging
|
|
4) Normal wood door, swinging
|
|
5) Big wood door, sliding
|
|
6) Drawbridge
|
|
7) Rotating walkway
|
|
8) Big metal door, sliding
|
|
9) Pendulum swinging
|
|
|
|
|
|
Puzzle Pieces (use the puzzle_id value from the pieces)
|
|
puzzle_piece_1
|
|
puzzle_piece_2
|
|
puzzle_piece_3
|
|
puzzle_piece_4
|
|
no_puzzle_msg: message when player doesn't have the right pieces
|
|
--------------------------------------------------------
|
|
*/
|
|
|
|
void func_door_secret()
|
|
{
|
|
door_sounds();
|
|
|
|
if (!self.dmg)
|
|
self.dmg = 2;
|
|
|
|
// Magic formula...
|
|
self.mangle = self.angles;
|
|
self.angles = '0 0 0';
|
|
if(world.spawnflags&MISSIONPACK)
|
|
{
|
|
if(self.mangle=='0 -1 0')
|
|
{
|
|
self.mangle='-90 0 0';
|
|
}
|
|
else if(self.mangle=='0 -2 0')
|
|
{
|
|
self.mangle='90 0 0';
|
|
}
|
|
}
|
|
|
|
self.solid = SOLID_BSP;
|
|
self.movetype = MOVETYPE_PUSH;
|
|
self.classname = "door";
|
|
setmodel (self, self.model);
|
|
setorigin (self, self.origin);
|
|
|
|
self.touch = secret_touch;
|
|
self.blocked = secret_blocked;
|
|
self.speed = 50;
|
|
self.use = fd_secret_use;
|
|
if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
|
|
{
|
|
self.health = 10000;
|
|
self.takedamage = DAMAGE_YES;
|
|
self.th_pain = fd_secret_use;
|
|
self.th_die = fd_secret_use;
|
|
}
|
|
self.oldorigin = self.origin;
|
|
if (!self.wait)
|
|
self.wait = 5; // 5 seconds before closing
|
|
}
|
|
|
|
/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE DOOR_DONT_LINK remove_pp no_pp TOGGLE X_AXIS Y_AXIS
|
|
NOTE: Doors can now be activated and deactivated with the appropriate triggers.
|
|
"inactive" set to 1 to start the door deactivated.
|
|
|
|
if two doors touch, they are assumed to be connected and operate as
|
|
a unit.
|
|
|
|
TOGGLE causes the door to wait in both the start and end states for
|
|
a trigger event.
|
|
|
|
START_OPEN causes the door to move to its destination when spawned,
|
|
and operate in reverse. It is used to temporarily or permanently
|
|
close off an area when triggered (not usefull for touch or
|
|
takedamage doors).
|
|
|
|
Key doors are allways wait -1.
|
|
|
|
You need to have an origin brush as part of this entity. The
|
|
center of that brush will be
|
|
the point around which it is rotated. It will rotate around the Z
|
|
axis by default. You can
|
|
check either the X_AXIS or Y_AXIS box to change that.
|
|
|
|
REVERSE will cause the door to rotate in the opposite direction.
|
|
|
|
"flags" is how many degrees the door will be rotated.
|
|
"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
|
|
"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
|
|
"health" if set, door must be shot open
|
|
"speed" movement speed (100 default)
|
|
"wait" wait before returning (3 default, -1 = never return)
|
|
"dmg" damage to inflict when blocked (2 default)
|
|
a "dmg" of -1 will make it only hurt non-players
|
|
"flags2" will damage the object that touches it
|
|
"strength" When set to 1, it will throw something if it gets in the way
|
|
"close_target" secondary target to fire when door closes
|
|
|
|
"soundtype"
|
|
0) no sound
|
|
1) Big metal door, swinging
|
|
2) Big stone door, sliding
|
|
3) Big wood door, swinging
|
|
4) Normal wood door, swinging
|
|
5) Big wood door, sliding
|
|
6) Drawbridge
|
|
7) Rotating walkway
|
|
8) Big metal door, sliding
|
|
9) Pendulum swinging
|
|
|
|
|
|
"abslight" - to set the absolute light level
|
|
|
|
Puzzle Pieces (use the puzzle_id value from the pieces)
|
|
puzzle_piece_1
|
|
puzzle_piece_2
|
|
puzzle_piece_3
|
|
puzzle_piece_4
|
|
no_puzzle_msg: message when player doesn't have the right pieces
|
|
*/
|
|
|
|
void func_door_rotating()
|
|
{
|
|
vector vec;
|
|
|
|
self.dflags=self.flags;//don't ask
|
|
self.flags=0;
|
|
|
|
// set the axis of rotation
|
|
if (self.spawnflags & 64)
|
|
self.movedir = '0 0 1';
|
|
else if (self.spawnflags & 128)
|
|
self.movedir = '1 0 0';
|
|
else
|
|
self.movedir = '0 1 0';
|
|
|
|
// check for clockwise rotation
|
|
if (self.spawnflags & 2)
|
|
self.movedir = self.movedir * -1;
|
|
|
|
// CHEAT hack to get the puzzle piece flags stored in the
|
|
// same area, without re-arranging the fields so that the
|
|
// designers don't complain
|
|
self.spawnflags (-) 192;
|
|
if (self.spawnflags & 8)
|
|
self.spawnflags (+) DOOR_REMOVE_PP;
|
|
if (self.spawnflags & 16)
|
|
self.spawnflags (+) DOOR_NO_PP;
|
|
|
|
if (self.spawnflags & 32)
|
|
self.spawnflags (+) DOOR_TOGGLE;
|
|
|
|
self.pos1 = self.angles;
|
|
self.pos2 = self.angles + self.movedir * self.dflags;
|
|
|
|
self.max_health = self.health;
|
|
self.solid = SOLID_BSP;
|
|
self.movetype = MOVETYPE_PUSH;
|
|
setorigin (self, self.origin);
|
|
setmodel (self, self.model);
|
|
self.classname = "door_rotating";
|
|
|
|
if (self.abslight)
|
|
self.drawflags (+) MLS_ABSLIGHT;
|
|
|
|
if (!self.speed)
|
|
self.speed = 100;
|
|
if (self.wait==0)
|
|
self.wait = 3;
|
|
if (!self.dmg)
|
|
// self.dmg = -1;
|
|
self.dmg = 2;
|
|
if(self.wait== -2)
|
|
{
|
|
self.th_die = chunk_death;
|
|
// self.takedamage = DAMAGE_YES;
|
|
if (!self.health)
|
|
{
|
|
if ((self.thingtype == THINGTYPE_GLASS) || (self.thingtype == THINGTYPE_CLEARGLASS))
|
|
self.max_health = self.health = 25;
|
|
else if ((self.thingtype == THINGTYPE_GREYSTONE) || (self.thingtype == THINGTYPE_BROWNSTONE))
|
|
self.max_health = self.health = 75;
|
|
else if (self.thingtype == THINGTYPE_WOOD)
|
|
self.max_health = self.health = 50;
|
|
else if (self.thingtype == THINGTYPE_METAL)
|
|
self.max_health = self.health = 100;
|
|
else if (self.thingtype == THINGTYPE_FLESH)
|
|
self.max_health = self.health = 30;
|
|
else
|
|
self.max_health = self.health = 25;
|
|
}
|
|
}
|
|
|
|
door_sounds();
|
|
|
|
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
|
|
// but spawn in the open position
|
|
if (self.spawnflags & DOOR_START_OPEN)
|
|
{
|
|
self.angles = self.pos2;
|
|
vec = self.pos2;
|
|
self.pos2 = self.pos1;
|
|
self.pos1 = vec;
|
|
self.movedir = self.movedir * -1;
|
|
}
|
|
|
|
self.state = STATE_BOTTOM;
|
|
|
|
self.touch = door_touch;
|
|
if(world.spawnflags&MISSIONPACK)
|
|
self.blocked = door_blocked_mp;
|
|
else
|
|
self.blocked = door_blocked;
|
|
self.use = door_use;
|
|
|
|
if (self.puzzle_piece_1 != string_null ||
|
|
self.puzzle_piece_2 != string_null ||
|
|
self.puzzle_piece_3 != string_null ||
|
|
self.puzzle_piece_4 != string_null)
|
|
self.wait = -1;
|
|
|
|
// LinkDoors can't be done until all of the doors have been spawned, so
|
|
// the sizes can be detected properly.
|
|
|
|
self.think = LinkDoors;
|
|
self.nextthink = self.ltime + 0.1;
|
|
|
|
if (self.cnt)
|
|
{
|
|
self.touch = SUB_Null;
|
|
self.use = door_rotate_incr;
|
|
}
|
|
|
|
if (self.flags2)
|
|
{
|
|
self.touch = door_damage;
|
|
self.flags2=FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* $Log: /H2 Mission Pack/HCode/Doors.hc $
|
|
*
|
|
* 26 3/19/98 2:26p Mgummelt
|
|
*
|
|
* 25 3/18/98 3:49p Mgummelt
|
|
* Last minute original game fixes, doors, eidolon, icemace, rats.
|
|
*
|
|
* 24 3/16/98 1:08a Jweier
|
|
*
|
|
* 23 3/16/98 12:46a Mgummelt
|
|
*
|
|
* 22 3/02/98 11:51a Mgummelt
|
|
*
|
|
* 21 2/27/98 6:08p Mgummelt
|
|
*
|
|
* 20 2/18/98 6:02p Jmonroe
|
|
* added cache4 functions, added puzzle piece cache_file4 cmds
|
|
*
|
|
* 19 2/17/98 11:59a Mgummelt
|
|
*
|
|
* 18 2/05/98 12:30p Mgummelt
|
|
*
|
|
* 17 2/04/98 4:58p Mgummelt
|
|
* spawnflags on monsters cleared out
|
|
*
|
|
* 16 2/04/98 11:36a Mgummelt
|
|
*
|
|
* 15 2/03/98 10:56a Mgummelt
|
|
*
|
|
* 14 2/03/98 1:43a Mgummelt
|
|
*
|
|
* 13 2/02/98 5:07p Mgummelt
|
|
*
|
|
* 12 2/02/98 4:45p Mgummelt
|
|
*
|
|
* 11 2/02/98 3:41p Mgummelt
|
|
*
|
|
* 10 2/02/98 10:38a Mgummelt
|
|
*
|
|
* 9 1/28/98 6:55p Mgummelt
|
|
*
|
|
* 8 1/19/98 6:20p Mgummelt
|
|
*
|
|
* 7 1/13/98 5:39p Mgummelt
|
|
*
|
|
* 6 1/08/98 4:25p Mgummelt
|
|
*
|
|
* 81 10/28/97 1:00p Mgummelt
|
|
* Massive replacement, rewrote entire code... just kidding. Added
|
|
* support for 5th class.
|
|
*
|
|
* 79 8/30/97 6:58p Mgummelt
|
|
*
|
|
* 78 8/28/97 1:54p Rjohnson
|
|
* Puzzle piece update
|
|
*
|
|
* 77 8/20/97 7:54p Rjohnson
|
|
* Removed message for deathmatch
|
|
*
|
|
* 76 8/15/97 3:35p Bgokey
|
|
*
|
|
* 75 8/12/97 6:10p Mgummelt
|
|
*
|
|
* 74 8/05/97 11:13a Mgummelt
|
|
*
|
|
* 73 8/05/97 11:12a Mgummelt
|
|
*
|
|
* 72 7/25/97 3:59p Mgummelt
|
|
*
|
|
* 71 7/21/97 4:03p Mgummelt
|
|
*
|
|
* 70 7/21/97 4:02p Mgummelt
|
|
*
|
|
* 69 7/17/97 4:16p Rlove
|
|
*
|
|
* 68 7/16/97 8:47p Mgummelt
|
|
*
|
|
* 67 7/14/97 4:43p Mgummelt
|
|
*
|
|
* 66 7/14/97 2:11p Mgummelt
|
|
*
|
|
* 65 7/14/97 2:11p Mgummelt
|
|
*
|
|
* 64 7/10/97 7:09p Rlove
|
|
*
|
|
* 63 7/09/97 7:35a Rlove
|
|
* New thingtype of CLEARGLASS
|
|
*
|
|
* 62 7/08/97 4:46p Rlove
|
|
*
|
|
* 61 7/08/97 4:37p Rlove
|
|
*
|
|
* 60 7/08/97 3:23p Rjohnson
|
|
* Switched messages to using a string index
|
|
*
|
|
* 59 7/08/97 8:00a Rlove
|
|
*
|
|
* 58 7/03/97 3:24p Mgummelt
|
|
*
|
|
* 57 7/03/97 11:43a Mgummelt
|
|
*
|
|
* 56 7/03/97 11:20a Mgummelt
|
|
*
|
|
* 55 7/03/97 10:47a Mgummelt
|
|
*
|
|
* 54 7/01/97 4:55p Mgummelt
|
|
*
|
|
* 53 6/26/97 11:16a Rjohnson
|
|
* Global text for puzzle messages
|
|
*
|
|
* 52 6/18/97 5:31p Jweier
|
|
*
|
|
* 51 6/18/97 2:33p Jweier
|
|
*
|
|
* 50 6/18/97 12:59p Mgummelt
|
|
*
|
|
* 49 6/17/97 3:35p Mgummelt
|
|
*
|
|
* 48 6/16/97 2:18p Jweier
|
|
* Fixed rotating door spawnflag problem
|
|
*
|
|
* 47 6/16/97 9:14a Jweier
|
|
*
|
|
* 46 6/01/97 5:08a Mgummelt
|
|
*
|
|
* 45 5/27/97 8:22p Mgummelt
|
|
*
|
|
* 43 5/27/97 7:58a Rlove
|
|
* New thingtypes of GreyStone,BrownStone, and Cloth.
|
|
*
|
|
* 42 5/24/97 2:48p Rlove
|
|
* Taking out old Id sounds
|
|
*
|
|
* 41 5/23/97 11:51p Mgummelt
|
|
*
|
|
* 40 5/23/97 5:03p Jweier
|
|
*
|
|
* 39 5/22/97 6:23p Jweier
|
|
*
|
|
* 38 5/22/97 5:18p Rlove
|
|
* New door sounds
|
|
*
|
|
* 37 5/19/97 11:36p Mgummelt
|
|
*
|
|
* 36 5/11/97 7:30a Mgummelt
|
|
*
|
|
* 35 5/06/97 4:27p Rjohnson
|
|
* Added absolute light level
|
|
*
|
|
* 34 5/06/97 4:24p Rjohnson
|
|
* Added abslight to rotating doors
|
|
*
|
|
* 33 4/30/97 5:03p Mgummelt
|
|
*
|
|
* 32 4/29/97 1:09p Mgummelt
|
|
*
|
|
* 31 4/29/97 12:34p Mgummelt
|
|
*
|
|
* 30 4/26/97 1:34p Jweier
|
|
*
|
|
* 29 4/22/97 5:55p Mgummelt
|
|
*
|
|
* 28 4/22/97 4:42p Rjohnson
|
|
* Fixed a problem with doors
|
|
*
|
|
* 27 4/19/97 1:01p Rjohnson
|
|
* Fixed a problem with the doors and puzzle pieces
|
|
*
|
|
* 26 4/18/97 4:46p Rjohnson
|
|
* Added messages for when you don't have the puzzle pieces
|
|
*
|
|
* 25 4/16/97 4:53p Rjohnson
|
|
* Added info for quake-ed
|
|
*
|
|
* 24 4/16/97 4:45p Rjohnson
|
|
* Doors now work with puzzle pieces
|
|
*
|
|
* 23 4/05/97 9:49a Rlove
|
|
* Uncommented out line 387 - linked buttons appear to be the culprit.
|
|
*
|
|
* 22 4/04/97 6:49p Jweier
|
|
* fixed breakable brush problem (in EntitiesTouching)
|
|
*
|
|
* 21 4/03/97 6:55a Rlove
|
|
* Had to comment out line 384 - it was crashing the game
|
|
*
|
|
* 20 3/29/97 12:41p Aleggett
|
|
*
|
|
* 19 3/27/97 12:23p Jweier
|
|
* Fixed up some linking problems with the rotating doors
|
|
*
|
|
* 18 3/25/97 9:41a Jweier
|
|
*
|
|
* 17 3/24/97 11:00a Jweier
|
|
*
|
|
* 16 3/24/97 10:49a Jweier
|
|
* func_door_rotating !!!
|
|
*
|
|
* 15 3/21/97 5:44p Jweier
|
|
*
|
|
* 14 3/21/97 10:06a Rlove
|
|
* Changed break_die to chunk_death
|
|
*
|
|
* 13 3/18/97 5:27p Aleggett
|
|
* Added smashable door...
|
|
*
|
|
* 12 3/13/97 4:06p Jweier
|
|
*
|
|
* 11 3/13/97 9:57a Rlove
|
|
* Changed constant DAMAGE_AIM to DAMAGE_YES and the old DAMAGE_YES to
|
|
* DAMAGE_YES
|
|
*
|
|
* 10 3/12/97 6:46p Jweier
|
|
*
|
|
* 9 3/12/97 6:19p Jweier
|
|
* De-kludged the door slide, works better now
|
|
*
|
|
* 8 3/07/97 5:25p Jweier
|
|
* More door slidin' madness! (read: fixed odd door slide problem)
|
|
*
|
|
* 7 3/06/97 5:50p Jweier
|
|
*
|
|
* 6 3/06/97 5:41p Jweier
|
|
* Doors now crash down and slide up by default
|
|
*
|
|
* 5 2/26/97 5:45p Jweier
|
|
* Doors can slide into place or crash into it (still no bounce though..)
|
|
*
|
|
* 4 11/19/96 8:49a Rlove
|
|
* func_door is back in
|
|
*
|
|
* 3 11/18/96 3:29p Rlove
|
|
* Changed sounds variable to soundtype
|
|
*
|
|
* 2 11/11/96 1:12p Rlove
|
|
* Added Source Safe stuff
|
|
*/
|