Quake

Quake GPL Source Release
Log | Files | Refs

plats.qc (8573B)


      1 /*
      2 	plats.qc
      3 
      4 	platform functions
      5 
      6 	Copyright (C) 1996-1997  Id Software, Inc.
      7 
      8 	This program is free software; you can redistribute it and/or
      9 	modify it under the terms of the GNU General Public License
     10 	as published by the Free Software Foundation; either version 2
     11 	of the License, or (at your option) any later version.
     12 
     13 	This program is distributed in the hope that it will be useful,
     14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     16 
     17 	See the GNU General Public License for more details.
     18 
     19 	You should have received a copy of the GNU General Public License
     20 	along with this program; if not, write to:
     21 
     22 		Free Software Foundation, Inc.
     23 		59 Temple Place - Suite 330
     24 		Boston, MA  02111-1307, USA
     25 
     26 */
     27 
     28 
     29 void() plat_center_touch;
     30 void() plat_outside_touch;
     31 void() plat_trigger_use;
     32 void() plat_go_up;
     33 void() plat_go_down;
     34 void() plat_crush;
     35 float PLAT_LOW_TRIGGER = 1;
     36 
     37 void() plat_spawn_inside_trigger =
     38 {
     39 	local entity	trigger;
     40 	local vector	tmin, tmax;
     41 
     42 //
     43 // middle trigger
     44 //	
     45 	trigger = spawn();
     46 	trigger.touch = plat_center_touch;
     47 	trigger.movetype = MOVETYPE_NONE;
     48 	trigger.solid = SOLID_TRIGGER;
     49 	trigger.enemy = self;
     50 	
     51 	tmin = self.mins + '25 25 0';
     52 	tmax = self.maxs - '25 25 -8';
     53 	tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
     54 	if (self.spawnflags & PLAT_LOW_TRIGGER)
     55 		tmax_z = tmin_z + 8;
     56 	
     57 	if (self.size_x <= 50)
     58 	{
     59 		tmin_x = (self.mins_x + self.maxs_x) / 2;
     60 		tmax_x = tmin_x + 1;
     61 	}
     62 	if (self.size_y <= 50)
     63 	{
     64 		tmin_y = (self.mins_y + self.maxs_y) / 2;
     65 		tmax_y = tmin_y + 1;
     66 	}
     67 	
     68 	setsize (trigger, tmin, tmax);
     69 };
     70 
     71 void() plat_hit_top =
     72 {
     73 	sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self.noise1, 1, ATTN_NORM);
     74 	self.state = STATE_TOP;
     75 	self.think = plat_go_down;
     76 	self.nextthink = self.ltime + 3;
     77 };
     78 
     79 void() plat_hit_bottom =
     80 {
     81 	sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self.noise1, 1, ATTN_NORM);
     82 	self.state = STATE_BOTTOM;
     83 };
     84 
     85 void() plat_go_down =
     86 {
     87 	sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
     88 	self.state = STATE_DOWN;
     89 	SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
     90 };
     91 
     92 void() plat_go_up =
     93 {
     94 	sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
     95 	self.state = STATE_UP;
     96 	SUB_CalcMove (self.pos1, self.speed, plat_hit_top);
     97 };
     98 
     99 void() plat_center_touch =
    100 {
    101 	if (other.classname != "player")
    102 		return;
    103 		
    104 	if (other.health <= 0)
    105 		return;
    106 
    107 	self = self.enemy;
    108 	if (self.state == STATE_BOTTOM)
    109 		plat_go_up ();
    110 	else if (self.state == STATE_TOP)
    111 		self.nextthink = self.ltime + 1;	// delay going down
    112 };
    113 
    114 void() plat_outside_touch =
    115 {
    116 	if (other.classname != "player")
    117 		return;
    118 
    119 	if (other.health <= 0)
    120 		return;
    121 		
    122 //dprint ("plat_outside_touch\n");
    123 	self = self.enemy;
    124 	if (self.state == STATE_TOP)
    125 		plat_go_down ();
    126 };
    127 
    128 void() plat_trigger_use =
    129 {
    130 	if (self.think)
    131 		return;		// allready activated
    132 	plat_go_down();
    133 };
    134 
    135 
    136 void() plat_crush =
    137 {
    138 //dprint ("plat_crush\n");
    139 
    140 	other.deathtype = "squish";
    141 	T_Damage (other, self, self, 1);
    142 	
    143 	if (self.state == STATE_UP)
    144 		plat_go_down ();
    145 	else if (self.state == STATE_DOWN)
    146 		plat_go_up ();
    147 	else
    148 		objerror ("plat_crush: bad self.state\n");
    149 };
    150 
    151 void() plat_use =
    152 {
    153 	self.use = SUB_Null;
    154 	if (self.state != STATE_UP)
    155 		objerror ("plat_use: not in up state");
    156 	plat_go_down();
    157 };
    158 
    159 
    160 /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
    161 speed	default 150
    162 
    163 Plats are always drawn in the extended position, so they will light correctly.
    164 
    165 If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
    166 
    167 If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height.
    168 Set "sounds" to one of the following:
    169 1) base fast
    170 2) chain slow
    171 */
    172 
    173 
    174 void() func_plat =
    175 
    176 {
    177 local entity t;
    178 
    179 	if (!self.t_length)
    180 		self.t_length = 80;
    181 	if (!self.t_width)
    182 		self.t_width = 10;
    183 
    184 	if (self.sounds == 0)
    185 		self.sounds = 2;
    186 // FIX THIS TO LOAD A GENERIC PLAT SOUND
    187 
    188 	if (self.sounds == 1)
    189 	{
    190 		precache_sound ("plats/plat1.wav");
    191 		precache_sound ("plats/plat2.wav");
    192 		self.noise = "plats/plat1.wav";
    193 		self.noise1 = "plats/plat2.wav";
    194 	}
    195 
    196 	if (self.sounds == 2)
    197 	{
    198 		precache_sound ("plats/medplat1.wav");
    199 		precache_sound ("plats/medplat2.wav");
    200 		self.noise = "plats/medplat1.wav";
    201 		self.noise1 = "plats/medplat2.wav";
    202 	}
    203 
    204 
    205 	self.mangle = self.angles;
    206 	self.angles = '0 0 0';
    207 
    208 	self.classname = "plat";
    209 	self.solid = SOLID_BSP;
    210 	self.movetype = MOVETYPE_PUSH;
    211 	setorigin (self, self.origin);	
    212 	setmodel (self, self.model);
    213 	setsize (self, self.mins , self.maxs);
    214 
    215 	self.blocked = plat_crush;
    216 	if (!self.speed)
    217 		self.speed = 150;
    218 
    219 // pos1 is the top position, pos2 is the bottom
    220 	self.pos1 = self.origin;
    221 	self.pos2 = self.origin;
    222 	if (self.height)
    223 		self.pos2_z = self.origin_z - self.height;
    224 	else
    225 		self.pos2_z = self.origin_z - self.size_z + 8;
    226 
    227 	self.use = plat_trigger_use;
    228 
    229 	plat_spawn_inside_trigger ();	// the "start moving" trigger	
    230 
    231 	if (self.targetname)
    232 	{
    233 		self.state = STATE_UP;
    234 		self.use = plat_use;
    235 	}
    236 	else
    237 	{
    238 		setorigin (self, self.pos2);
    239 		self.state = STATE_BOTTOM;
    240 	}
    241 };
    242 
    243 //============================================================================
    244 
    245 void() train_next;
    246 void() func_train_find;
    247 
    248 void() train_blocked =
    249 {
    250 	if (time < self.attack_finished)
    251 		return;
    252 	self.attack_finished = time + 0.5;
    253 	other.deathtype = "squish";
    254 	T_Damage (other, self, self, self.dmg);
    255 };
    256 
    257 void() train_use =
    258 {
    259 	if (self.think != func_train_find)
    260 		return;		// already activated
    261 	train_next();
    262 };
    263 
    264 void() train_wait =
    265 {
    266 	if (self.wait)
    267 	{
    268 		self.nextthink = self.ltime + self.wait;
    269 		sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self.noise, 1, ATTN_NORM);
    270 	}
    271 	else
    272 		self.nextthink = self.ltime + 0.1;
    273 	
    274 	self.think = train_next;
    275 };
    276 
    277 void() train_next =
    278 {
    279 	local entity	targ;
    280 
    281 	targ = find (world, targetname, self.target);
    282 	self.target = targ.target;
    283 	if (!self.target)
    284 		objerror ("train_next: no next target");
    285 	if (targ.wait)
    286 		self.wait = targ.wait;
    287 	else
    288 		self.wait = 0;
    289 	sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
    290 	SUB_CalcMove (targ.origin - self.mins, self.speed, train_wait);
    291 };
    292 
    293 void() func_train_find =
    294 
    295 {
    296 	local entity	targ;
    297 
    298 	targ = find (world, targetname, self.target);
    299 	self.target = targ.target;
    300 	setorigin (self, targ.origin - self.mins);
    301 	if (!self.targetname)
    302 	{	// not triggered, so start immediately
    303 		self.nextthink = self.ltime + 0.1;
    304 		self.think = train_next;
    305 	}
    306 };
    307 
    308 /*QUAKED func_train (0 .5 .8) ?
    309 Trains are moving platforms that players can ride.
    310 The targets origin specifies the min point of the train at each corner.
    311 The train spawns at the first target it is pointing at.
    312 If the train is the target of a button or trigger, it will not begin moving until activated.
    313 speed	default 100
    314 dmg		default	2
    315 sounds
    316 1) ratchet metal
    317 
    318 */
    319 void() func_train =
    320 {	
    321 	if (!self.speed)
    322 		self.speed = 100;
    323 	if (!self.target)
    324 		objerror ("func_train without a target");
    325 	if (!self.dmg)
    326 		self.dmg = 2;
    327 
    328 	if (self.sounds == 0)
    329 	{
    330 		self.noise = ("misc/null.wav");
    331 		precache_sound ("misc/null.wav");
    332 		self.noise1 = ("misc/null.wav");
    333 		precache_sound ("misc/null.wav");
    334 	}
    335 
    336 	if (self.sounds == 1)
    337 	{
    338 		self.noise = ("plats/train2.wav");
    339 		precache_sound ("plats/train2.wav");
    340 		self.noise1 = ("plats/train1.wav");
    341 		precache_sound ("plats/train1.wav");
    342 	}
    343 
    344 	self.cnt = 1;
    345 	self.solid = SOLID_BSP;
    346 	self.movetype = MOVETYPE_PUSH;
    347 	self.blocked = train_blocked;
    348 	self.use = train_use;
    349 	self.classname = "train";
    350 
    351 	setmodel (self, self.model);
    352 	setsize (self, self.mins , self.maxs);
    353 	setorigin (self, self.origin);
    354 
    355 // start trains on the second frame, to make sure their targets have had
    356 // a chance to spawn
    357 	self.nextthink = self.ltime + 0.1;
    358 	self.think = func_train_find;
    359 };
    360 
    361 /*QUAKED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8)
    362 This is used for the final bos
    363 */
    364 void() misc_teleporttrain =
    365 {	
    366 	if (!self.speed)
    367 		self.speed = 100;
    368 	if (!self.target)
    369 		objerror ("func_train without a target");
    370 
    371 	self.cnt = 1;
    372 	self.solid = SOLID_NOT;
    373 	self.movetype = MOVETYPE_PUSH;
    374 	self.blocked = train_blocked;
    375 	self.use = train_use;
    376 	self.avelocity = '100 200 300';
    377 
    378 	self.noise = ("misc/null.wav");
    379 	precache_sound ("misc/null.wav");
    380 	self.noise1 = ("misc/null.wav");
    381 	precache_sound ("misc/null.wav");
    382 
    383 	precache_model2 ("progs/teleport.mdl");
    384 	setmodel (self, "progs/teleport.mdl");
    385 	setsize (self, self.mins , self.maxs);
    386 	setorigin (self, self.origin);
    387 
    388 // start trains on the second frame, to make sure their targets have had
    389 // a chance to spawn
    390 	self.nextthink = self.ltime + 0.1;
    391 	self.think = func_train_find;
    392 };
    393