/* * $Header: /H2 Mission Pack/HCode/PLATS.hc 29 2/18/98 6:02p Jmonroe $ */ void() newplat_center_touch; void() newplat_go_up; void() newplat_go_down; void() plat_center_touch; //void() plat_outside_touch; void() plat_trigger_use; void() plat_go_up; void() plat_go_down; void() plat_crush; float PLAT_LOW_TRIGGER = 1; void() crusher_hit_bottom; void() crusher_hit_top; void() crusher_trigger_use; void() crusher_go_up; void() crusher_go_down; float CRUSH_MULT = 1; float CRUSH_SLIDE = 2; float CRUSH_START_OPEN = 4; float CRUSH_ENDPOS = 8; float START_BOTTOM = 1; float START_RTRN= 2; float CONTINUE= 4; void() train_wait; float TRAIN_GLOW = 1; float TRAIN_WAITTRIG = 2; float TRAIN_RETURN = 4; float ANGLEMATCH = 32; float USE_ORIGIN = 64; float ANGLE_WAIT = 128; void() plat_spawn_inside_trigger = { entity trigger; vector tmin, tmax; //middle trigger trigger = spawn(); if (self.classname == "newplat") trigger.touch = newplat_center_touch; else trigger.touch = plat_center_touch; trigger.movetype = MOVETYPE_NONE; trigger.solid = SOLID_TRIGGER; trigger.enemy = self; tmin = self.mins + '25 25 0'; tmax = self.maxs - '25 25 -8'; tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8); if (self.spawnflags & PLAT_LOW_TRIGGER) tmax_z = tmin_z + 8; if (self.size_x <= 50) { tmin_x = (self.mins_x + self.maxs_x) / 2; tmax_x = tmin_x + 1; } if (self.size_y <= 50) { tmin_y = (self.mins_y + self.maxs_y) / 2; tmax_y = tmin_y + 1; } setsize (trigger, tmin, tmax); }; void() plat_hit_top = { sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_TOP; self.think = plat_go_down; self.nextthink = self.ltime + 3; }; void() plat_hit_bottom = { sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_BOTTOM; }; void() plat_go_down = { sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_DOWN; SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom); }; void() plat_go_up = { sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_UP; SUB_CalcMove (self.pos1, self.speed, plat_hit_top); }; void() plat_center_touch = { if (other.classname != "player"&&other.movetype!=MOVETYPE_PUSHPULL)//Monsters too? return; if (other.health <= 0) return; self = self.enemy; if (self.state == STATE_BOTTOM) plat_go_up (); else if (self.state == STATE_TOP) self.nextthink = self.ltime + 1; // delay going down }; /* void() plat_outside_touch = { if (other.classname != "player"&&other.movetype!=MOVETYPE_PUSHPULL) return; if (other.health <= 0) return; self = self.enemy; if (self.state == STATE_TOP) plat_go_down (); }; */ void() plat_trigger_use = { if (self.think) return; // allready activated plat_go_down(); }; void() plat_crush = { T_Damage (other, self, self, 1); if (self.state == STATE_UP) plat_go_down (); else if (self.state == STATE_DOWN) plat_go_up (); else objerror ("plat_crush: bad self.state\n"); }; void() plat_use = { self.use = SUB_Null; if (self.state != STATE_UP) objerror ("plat_use: not in up state"); plat_go_down(); }; /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER speed default 150 Plats are always drawn in the extended position, so they will light correctly. 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. If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height. Set "soundtype" to one of the following: 1) pulley 2) chain */ void() func_plat = { if (!self.t_length) self.t_length = 80; if (!self.t_width) self.t_width = 10; if (self.soundtype == 0) self.soundtype = 2; // FIX THIS TO LOAD A GENERIC PLAT SOUND if (self.soundtype == 1) { precache_sound ("plats/pulyplt1.wav"); precache_sound ("plats/pulyplt2.wav"); self.noise = "plats/pulyplt1.wav"; self.noise1 = "plats/pulyplt2.wav"; } if (self.soundtype == 2) { precache_sound ("plats/chainplt1.wav"); precache_sound ("plats/chainplt2.wav"); self.noise = "plats/chainplt1.wav"; self.noise1 = "plats/chainplt2.wav"; } self.mangle = self.angles; self.angles = '0 0 0'; self.classname = "plat"; self.solid = SOLID_BSP; self.movetype = MOVETYPE_PUSH; setorigin (self, self.origin); setmodel (self, self.model); setsize (self, self.mins , self.maxs); self.blocked = plat_crush; if (!self.speed) self.speed = 150; // pos1 is the top position, pos2 is the bottom self.pos1 = self.origin; self.pos2 = self.origin; if (self.height) self.pos2_z = self.origin_z - self.height; else self.pos2_z = self.origin_z - self.size_z + 8; self.use = plat_trigger_use; plat_spawn_inside_trigger (); // the "start moving" trigger if (self.targetname) { self.state = STATE_UP; self.use = plat_use; } else { setorigin (self, self.pos2); self.state = STATE_BOTTOM; } }; //============================================================================ void() train_next; void() func_train_find; void() train_blocked = { if (time < self.attack_finished) return; self.attack_finished = time + 0.5; T_Damage (other, self, self, self.dmg); }; void() train_use = { if(self.wait==-1) self.use=SUB_Null; if (self.spawnflags & TRAIN_GLOW) { self.effects = EF_BRIGHTLIGHT; } if (self.decap != 1) { self.decap = 1; if (self.think != train_next) { self.think = func_train_find; train_next(); } } else { if (self.spawnflags & TRAIN_RETURN) self.decap = 0; else self.decap = 2; } }; void() train_wait = { //Check to make sure train is active if(self.decap!=2) { self.think = train_next; if(self.wait==-2) { if(self.th_die) { if(self.pausetime) { self.think=self.th_die; self.nextthink=self.ltime+self.pausetime; } else { self.th_die(); return; } } else { if(self.pausetime) { self.think=chunk_death; self.nextthink=self.ltime+self.pausetime; } else { chunk_death(); return; } } } else if(self.wait==-1) self.nextthink=-1; else if (self.wait) { self.nextthink = self.ltime + self.wait; sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); } else self.nextthink = self.ltime + 0.1; } if (self.decap == 0 || self.decap == 2) self.effects = 0; }; void() train_rotate = { local entity targ; local vector dir; targ = self.enemy; if (targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0) { dir = self.angles; dir += targ.mangle; SUB_CalcAngleMove (dir, self.speed, train_wait); } else train_wait(); }; void() train_next = { local entity targ; local vector dir; float targ_speed, targ_aspeed; targ = find (world, targetname, self.target); self.target = targ.target; if (!self.decap && self.spawnflags & TRAIN_RETURN) if (self.netname == targ.targetname) self.decap = 2; if (!self.target) objerror ("train_next: no next target"); if (targ.wait) self.wait = targ.wait; else self.wait = 0; self.enemy = targ; sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); if (targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0) { dir = self.angles; dir += targ.mangle; if(targ.speed) targ_speed=targ.speed; else targ_speed = self.speed; if(targ.anglespeed) targ_aspeed=targ.anglespeed; else targ_aspeed = self.anglespeed; if(targ.spawnflags&SYNCH) SUB_CalcMoveAndAngleInit (targ.origin - self.mins, targ_speed, dir, targ_aspeed, train_wait,TRUE); else SUB_CalcMoveAndAngleInit (targ.origin - self.mins, targ_speed, dir, targ_aspeed, train_wait,FALSE); } else SUB_CalcMove (targ.origin - self.mins, self.speed, train_rotate); if (self.spawnflags & TRAIN_WAITTRIG) self.decap = 2; }; void() func_train_find = { local entity targ; targ = find (world, targetname, self.target); self.target = targ.target; setorigin (self, targ.origin - self.mins); if (!self.targetname) { // not triggered, so start immediately self.decap = 1; self.nextthink = self.ltime + 0.1; self.think = train_next; } }; /*QUAKED func_train (0 .5 .8) ? GLOW TOGGLE RETURN TRANSLUCENT Hexen 2 Release V1.11 version Trains Trains are moving platforms that players can ride. The targets origin specifies the min point of the train at each corner. The train spawns at the first target it is pointing at. If the train is the target of a button or trigger, it will not begin moving until activated. speed default 100 dmg default 2 soundtype 1) ratchet metal if train is only moving to one spot "angle" - to tell it's direction "distance" - in pixels, how far to move "speed" - how fast it moves between spots (default=100) "anglespeed" - how fast it rotates to a new angle (default = 100) "wait" - -1 will make it stop forever, -2 will make it blow up (you can put the waits on the pathcorners and it will take the wait from there. "pausetime" - How long to wait after getting to the end of it's path before blowing up, default is 0 NOTE: If you give it a wait of -2, be sure to set the thingtype. thingtype - type of chunks and sprites it will generate 0 - glass 1 - grey stone (default for trains) 2 - wood 3 - metal 4 - flesh 5 - fire 6 - clay 7 - leaves 8 - hay 9 - brown stone 10 - cloth 11 - wood & leaf 12 - wood & metal 13 - wood stone 14 - metal stone 15 - metal cloth The train will modify it's angles by whatever angles it's next path point has, so if it heads towards a path corner with an angle of '0 90 0', the train will rotate '0 90 0' on it's way to the pathpoint. If you make the anglespeed the same as the angle, the turn should finish right as the train gets to the new spot. NOTE: A path_corner using spawnflag "SYNCH" will make the train automatically calculate a new anglespeed based on the distance it's going and will finish the turn at the same time the move is done. As usual, any rotating brush needs an origin brush. "abslight" - to set the absolute light level if TRAIN_GLOW is checked, changes to a light globe sprite and lights up an area */ void func_train_mp(); void() func_train = { entity targ; if(world.spawnflags&MISSIONPACK) { func_train_mp(); return; } self.decap = 0; if (self.spawnflags & TRAIN_GLOW) { self.solid = SOLID_NOT; setmodel (self, "models/s_light.spr"); } else { self.solid = SOLID_BSP; setmodel (self, self.model); } if (!self.speed) self.speed = 100; if (!self.anglespeed) self.anglespeed = 100; if (!self.target) objerror ("func_train without a target"); if (!self.dmg) self.dmg = 2; if (self.soundtype == 1) { self.noise = ("plats/train2.wav"); precache_sound ("plats/train2.wav"); self.noise1 = ("plats/train1.wav"); precache_sound ("plats/train1.wav"); } else { self.noise = self.noise1 = "misc/null.wav"; // precache_sound ("misc/null.wav"); } if(self.wait==-2) { if(!self.thingtype) self.thingtype=1; if(!self.th_die) self.th_die=chunk_death; } self.cnt = 1; self.movetype = MOVETYPE_PUSH; self.blocked = train_blocked; self.use = train_use; self.classname = "train"; setsize (self, self.mins , self.maxs); setorigin (self, self.origin); targ = find(world, target, self.target); self.netname = targ.target; if (self.abslight) self.drawflags(+)MLS_ABSLIGHT; if (self.spawnflags & 8) { self.drawflags(+)DRF_TRANSLUCENT; self.solid = SOLID_NOT; } // start trains on the second frame, to make sure their targets have had // a chance to spawn self.nextthink = self.ltime + 0.1; self.think = func_train_find; }; /*QUAK-ED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8) This is used for the final bos */ /* void() misc_teleporttrain = { if (!self.speed) self.speed = 100; if (!self.target) objerror ("func_train without a target"); self.cnt = 1; self.solid = SOLID_NOT; self.movetype = MOVETYPE_PUSH; self.blocked = train_blocked; self.use = train_use; self.avelocity = '100 200 300'; self.noise = ("misc/null.wav"); precache_sound ("misc/null.wav"); self.noise1 = ("misc/null.wav"); precache_sound ("misc/null.wav"); precache_model2 ("models/teleport.mdl"); setmodel (self, "models/teleport.mdl"); 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.nextthink = self.ltime + 0.1; self.think = func_train_find; }; */ void() newplat_hit_bottom = { sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_BOTTOM; self.lifetime = time + self.wait; if (((self.spawnflags & START_RTRN) && !(self.spawnflags & START_BOTTOM)) || (self.spawnflags & CONTINUE)) { self.nextthink = self.ltime + self.wait; self.think=newplat_go_up; } setorigin (self.enemy, self.origin); }; void() newplat_hit_top = { sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_TOP; self.lifetime = time + self.wait; if (((self.spawnflags & START_RTRN) && (self.spawnflags & START_BOTTOM)) || (self.spawnflags & CONTINUE)) { self.nextthink = self.ltime + self.wait; self.think=newplat_go_down; } setorigin (self.enemy, self.origin); }; void() newplat_trigger_use = { if (self.think) return; // already activated if ((self.state==STATE_MOVING) || (self.lifetime > time)) return; if (self.state == STATE_BOTTOM) newplat_go_up (); else newplat_go_down (); }; void() newplat_calc_down = { self.state=STATE_MOVING; SUB_CalcMove (self.pos2, self.speed, newplat_hit_bottom); }; void() newplat_go_down = { sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); newplat_calc_down(); }; void() newplat_calc_up = { self.state=STATE_MOVING; SUB_CalcMove (self.pos1, self.speed, newplat_hit_top); }; void() newplat_go_up = { sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); newplat_calc_up(); }; void() newplat_crush = { T_Damage (other, self, self, 1); if (self.velocity_z < 0) newplat_calc_down (); else if (self.velocity_z > 0) newplat_calc_up(); else objerror ("newplat_crush: bad self.state\n"); }; void() newplat_center_touch = { if ((other.classname != "player"&&other.movetype!=MOVETYPE_PUSHPULL) || (other.health <= 0)) return; self = self.enemy; if ((self.state==STATE_MOVING) || (self.lifetime > time)) return; if (self.state == STATE_BOTTOM) newplat_go_up (); else newplat_go_down (); }; void() newplat_spawn_inside_trigger = { local entity trigger; //middle trigger trigger = spawn(); trigger.touch = newplat_center_touch; trigger.movetype = MOVETYPE_PUSH; trigger.solid = SOLID_TRIGGER; trigger.enemy = self; self.enemy = trigger; setsize (trigger, self.mins,self.maxs); }; /*QUAKED func_newplat (0 .5 .8) ? START_BOTTOM STRT_RTRN CONTINUE speed default 150 If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height. Set "soundtype" to one of the following: 1) base fast 2) chain slow START_BOTTOM - where plat starts at if checked plat starts at the bottom of it's movement START_RTRN - if check will return plat to start position. CONTINUE - plat will never stop moving height - distance plat moves up or down wait - amount of time plat waits before moving (default 3) */ void() func_newplat = { if (!self.t_length) self.t_length = 80; if (!self.t_width) self.t_width = 10; if (self.soundtype == 0) self.soundtype = 2; if (self.soundtype == 1) { precache_sound ("plats/pulyplt1.wav"); precache_sound ("plats/pulyplt2.wav"); self.noise = "plats/pulyplt1.wav"; self.noise1 = "plats/pulyplt2.wav"; } if (self.soundtype == 2) { precache_sound ("plats/chainplt1.wav"); precache_sound ("plats/chainplt2.wav"); self.noise = "plats/chainplt1.wav"; self.noise1 = "plats/chainplt2.wav"; } self.mangle = self.angles; self.angles = '0 0 0'; self.classname = "newplat"; self.solid = SOLID_BSP; self.movetype = MOVETYPE_PUSH; setorigin (self, self.origin); setmodel (self, self.model); setsize (self, self.mins , self.maxs); if (!self.speed) self.speed = 150; if (!self.wait) self.wait = 3; // pos1 is the top position, pos2 is the bottom self.pos1 = self.origin; self.pos2 = self.origin; if (self.spawnflags & START_BOTTOM) self.state=STATE_BOTTOM; else self.state=STATE_TOP; if (self.state==STATE_BOTTOM) { self.pos1_z = self.origin_z + self.height; self.pos2_z = self.origin_z; } else { self.pos1_z = self.origin_z; self.pos2_z = self.origin_z - self.height; } self.use = newplat_trigger_use; self.blocked = newplat_crush; newplat_spawn_inside_trigger (); //set the "start moving" trigger }; /* =============================================================================== FUNC_CRUSHER =============================================================================== */ void() crusher_slide_next = { local vector vdestdelta; local float len, tspeed; tspeed = self.speed; if (!tspeed) objerror("No speed 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 = crusher_hit_bottom; else if (self.state == STATE_UP) self.think = crusher_hit_top; self.nextthink = self.ltime + 0.1; return; } //Set destdelta to the vector needed to move vdestdelta = self.finaldest - self.origin; //Get the length of the vector len = vlen (vdestdelta); //If the length is this small, just stop if (len < 1) { if (self.state == STATE_DOWN) crusher_hit_bottom(); else if (self.state == STATE_UP) crusher_hit_top(); else dprint("NO STATE\n"); return; } self.nextthink = self.ltime + 0.1; self.think = crusher_slide_next; self.velocity = vdestdelta * ((len / (len / 3)) / (self.speed / 100)); }; void(vector tdest) crusher_slide = { self.finaldest = tdest; crusher_slide_next(); }; void() crusher_hit_top = { sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_TOP; if (self.spawnflags & CRUSH_MULT) return; if (!self.level) { self.think = crusher_go_down; self.nextthink = self.ltime + 1; } else self.nextthink = -1; }; void() crusher_hit_bottom = { sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); self.state = STATE_BOTTOM; if (self.level && self.spawnflags & CRUSH_ENDPOS) return; self.think = crusher_go_up; self.nextthink = self.ltime + 1; }; void() crusher_go_down = { sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_DOWN; if (self.spawnflags & CRUSH_SLIDE) crusher_slide(self.pos2); else SUB_CalcMove (self.pos2, self.speed, crusher_hit_bottom); }; void() crusher_go_up = { sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); self.state = STATE_UP; if (self.spawnflags & CRUSH_SLIDE) crusher_slide(self.pos1); else SUB_CalcMove (self.pos1, self.speed, crusher_hit_top); }; void() crusher_trigger_use = { if (!self.level) self.level = TRUE; else self.level = FALSE; //HCC doesn't like these together in one statement if (self.think) if (self.spawnflags & CRUSH_MULT) return; // already activated crusher_go_down(); }; void() crusher_crush = { //Crusher does not return like a plat, it just keeps on crushin' T_Damage (other, self, self, self.dmg); }; void() crusher_use = { if (!self.level) self.level = TRUE; else self.level = FALSE; crusher_go_down(); }; /*QUAKED func_crusher (0 .5 .8) ? multiple slide start_open end_open speed default 150 dmg default 10 If not targetname is given, crushers will start working immediatly Crushers are always drawn in the extended position, so they will light correctly. start_open = start in open position multiple = go once, return, and wait to be triggered again slide = slide move (like doors) end_open = stop in the position opposite what they were drawn in "lip" same as doors "speed" speed of the crusher "wait pause until going in the other direction "targetname" if set, no trigger is needed (use with multiple) "dmg" damage the crusher does to a victim Set "soundtype" to one of the following: 1) base fast 2) chain slow 3) Guillotine */ void() func_crusher = { SetMovedir(); if (self.soundtype == 0) self.soundtype = 2; if (self.soundtype == 1) { precache_sound ("plats/plat1.wav"); precache_sound ("plats/plat2.wav"); self.noise = "plats/plat1.wav"; self.noise1 = "plats/plat2.wav"; } else if (self.soundtype == 2) { precache_sound ("plats/medplat1.wav"); precache_sound ("plats/medplat2.wav"); self.noise = "plats/medplat1.wav"; self.noise1 = "plats/medplat2.wav"; } else if (self.soundtype == 3) { precache_sound3 ("plats/guiltin1.wav"); precache_sound3 ("plats/guiltin2.wav"); self.noise = "plats/guiltin1.wav"; self.noise1 = "plats/guiltin2.wav"; } self.mangle = self.angles; self.angles = '0 0 0'; self.classname = "crusher"; self.solid = SOLID_BSP; self.movetype = MOVETYPE_PUSH; setorigin (self, self.origin); setmodel (self, self.model); setsize (self, self.mins , self.maxs); self.level = TRUE; if (!self.dmg) self.dmg = 10; self.blocked = crusher_crush; if (!self.speed) self.speed = 150; self.pos1 = self.origin; self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); if (self.spawnflags & CRUSH_START_OPEN) { setorigin (self, self.pos2); self.pos2 = self.pos1; self.pos1 = self.origin; } self.use = crusher_trigger_use; if (self.targetname) { self.state = STATE_UP; self.use = crusher_use; } else { setorigin (self, self.pos2); self.state = STATE_BOTTOM; self.nextthink = self.ltime + 0.1; self.think = crusher_use; } }; void reset_solid (void) { } void rot_mov_dmg (void) { if(other==world) return; if(other.classname=="player") { self.solid=SOLID_TRIGGER; self.think=reset_solid; thinktime self : 0.1; } if(other.takedamage) { if(self.noise1) sound(self,CHAN_VOICE,self.noise1,1,ATTN_NORM); self.pain_finished=time+self.wait; T_Damage(other,self,self.owner,self.dmg); } } void rot_mov_snd (void) { if(self.pain_finished<=time) { sound(self,CHAN_VOICE,self.noise,1,ATTN_NORM); self.pain_finished=time+self.wait; } self.think=rot_mov_snd; thinktime self : self.wait; } void rot_mov_activate (void) { if(self.dmg) self.touch=rot_mov_dmg; if(!self.avelocity) self.avelocity=self.o_angle; if(self.noise) if(!self.wait) objerror ("func_rotating_movechain: sound, but no delay time"); else { self.think=rot_mov_snd; thinktime self : 0; } } float NOANGLECHAIN = 1; /*QUAKED func_rotating_movechain (0 .5 .8) ? NOANGLECHAIN Only one other object in the world should have the same netname. If not, it will find and use only the first one it finds! If you're making multiple sawblades, for instance, label the mover and the rotater "sawblade1" for the first one, "sawblade2" for the second, and so on. If you give it a targetname, it will wait to be activated, this can be seperate from the object it's attached to. It will not do damage until it's been activated. NOANGLECHAIN = Setting this flag will stop it from modifying it's angles by the owner's angles, but will still movechain. dmg = How much damage it should do when it touches. noise = Noise it should make, if any, be sure to set the wait time noise1 = noise it should make when it hits something wait = Length of the sound so it knows when to loop it. avelocity = The direction and speed it should spin: pitch yaw roll (this is relative to it's own axis, not the world) netname = the name of the object it's linked to, that object must have a matching netname!!! Needs something to tell it to stop? A way to make it die at the end of a path or if triggered again? Maybe make movechain_angle optional spawnflag? What do YOU think? We'd like to know... */ void func_rotating_movechain (void) { if(!self.netname) objerror ("func_rotating_movechain has no netname"); self.owner=find(world,netname,self.netname); if(self.owner.classname=="world") objerror ("func_rotating_movechain has no owner!"); self.solid=SOLID_TRIGGER; self.movetype=MOVETYPE_NOCLIP; setmodel(self,self.model); setsize(self,self.mins,self.maxs); setorigin(self,self.origin); //dprint(vtos(self.avelocity)); self.owner.movechain=self; if(!self.spawnflags&NOANGLECHAIN) self.flags+=FL_MOVECHAIN_ANGLE; if(self.targetname) { self.use=rot_mov_activate; self.o_angle=self.avelocity; self.avelocity='0 0 0'; } else { self.think=rot_mov_activate; thinktime self : 3;//wait a few secs for board to start } } /* * $Log: /H2 Mission Pack/HCode/PLATS.hc $ * * 29 2/18/98 6:02p Jmonroe * added cache4 functions, added puzzle piece cache_file4 cmds * * 28 2/12/98 5:55p Jmonroe * remove unreferenced funcs * * 27 2/05/98 12:30p Mgummelt * * 26 2/04/98 4:58p Mgummelt * spawnflags on monsters cleared out * * 25 2/03/98 9:47a Mgummelt * * 24 2/02/98 5:14p Mgummelt * * 23 2/02/98 5:07p Mgummelt * * 22 1/28/98 3:10p Mgummelt * * 21 1/19/98 6:21p Mgummelt * * 20 1/16/98 2:11p Mgummelt * * 19 1/14/98 7:43p Mgummelt * * 18 1/14/98 2:35p Mgummelt * * 17 1/13/98 3:35p Mgummelt * * 63 10/28/97 1:01p Mgummelt * Massive replacement, rewrote entire code... just kidding. Added * support for 5th class. * * 61 9/16/97 4:17p Rjohnson * Updates * * 60 9/01/97 3:35a Jweier * * 57 8/28/97 1:54p Rjohnson * Puzzle piece update * * 56 8/25/97 5:07p Jweier * * 55 8/23/97 7:15p Rlove * * 54 8/15/97 3:03p Bgokey * * 53 7/21/97 3:03p Rlove * * 52 7/14/97 6:24p Rlove * * 51 7/14/97 12:44p Rlove * * 50 7/07/97 5:06p Mgummelt * * 49 7/03/97 4:12p Mgummelt * * 48 7/03/97 12:48p Mgummelt * * 47 7/03/97 11:26a Mgummelt * * 46 6/18/97 4:00p Mgummelt * * 45 6/18/97 10:46a Rjohnson * Code cleanu * * 44 6/14/97 2:22p Mgummelt * * 43 6/13/97 3:28p Mgummelt * * 42 6/12/97 12:44p Mgummelt * * 41 6/11/97 10:26a Mgummelt * * 40 6/03/97 5:25p Jweier * * 39 5/27/97 8:22p Mgummelt * * 38 5/22/97 11:32a Rjohnson * Translucent trains don't block you * * 37 5/19/97 4:24p Rjohnson * Translucent train options * * 36 5/16/97 11:27p Mgummelt * * 35 5/15/97 2:44p Mgummelt * * 34 5/15/97 12:30a Mgummelt * * 33 5/12/97 11:12p Mgummelt * * 32 5/10/97 1:54p Mgummelt * * 31 5/09/97 4:57p Mgummelt * * 30 5/08/97 5:47p Mgummelt * * 29 5/06/97 4:27p Rjohnson * Added absolute light level * * 28 5/02/97 4:37p Jweier * * 27 4/26/97 10:19a Jweier * rotating trains * * 26 4/04/97 4:30p Mgummelt * * 25 3/27/97 6:28p Jweier * * 24 3/27/97 6:12p Jweier * * 23 3/27/97 1:59p Jweier * * 22 3/25/97 6:01p Jweier * * 21 3/25/97 5:43p Jweier * * 20 3/25/97 11:02a Jweier * added CRUSH_START_OPEN * * 19 3/20/97 7:51p Jweier * fixed train problem * * 18 3/20/97 6:22p Jweier * * 17 3/20/97 5:07p Jweier * light trains are off until triggered on, and go off when they stop * * 16 3/15/97 12:16p Jweier * If RETURN is checked, trains will run their whole route before * stopping. * * 15 3/07/97 6:45p Jweier * * 14 3/07/97 6:39p Jweier * func_trains can now be toggled, and made to wait at each target to be * triggered again * * 13 2/28/97 5:37p Rlove * A little clean up * * 12 2/28/97 5:17p Rlove * New Plats now crush you and are triggerable * * 11 2/28/97 11:26a Jweier * func_crushers have damage fields now * * 10 2/28/97 11:21a Jweier * func_crusher implemented - let the smooshing begin! * * 9 2/28/97 10:59a Jweier * Added more func_crusher options * * 8 2/27/97 6:12p Jweier * Added basic crusher entity * * 6 2/21/97 5:55p Jweier * Added light train ability * * 5 1/27/97 4:23p Rlove * Rebuilt plats so they make sense * * 4 12/16/96 12:42p Rlove * New gauntlets, artifacts, and inventory * * 1 12/13/96 3:47p Rlove * * 3 11/18/96 3:29p Rlove * Changed sounds variable to soundtype * * 2 11/11/96 1:19p Rlove * Added Source Safe stuff */