Inside3D tutorials.
Created By: | Alan Kivlin |
eMail: | alan.kivlin@cyberiacafe.co.uk |
Difficulty Scale: | Hard |
defs.qc floater.qc // floating entity routines subs.qc fight.qc(I have included some existing lines from above and below where the modification will be made, this shows how the changed file will look)
local float mspeed, aspeed; local float r; // FLOATER // controls the floating of the floaters floaterPreThink(); // FLOATER if (intermission_running)By adding a call to floaterPreThink, we are giving Quake the ability to control floating entities (floaters). This routine checks (every frame) if any floaters exist, they are processed depending on their current state which can be, falling, surfacing, floating or sinking.
new.origin = self.origin; setmodel (new, gibname); // FLOATER // give it a Z axis size so it'll show up in water // as well as out of water setsize( new, '0 0 -4', '0 0 12' ); // FLOATER new.velocity = VelocityForDamage (dm); new.movetype = MOVETYPE_BOUNCE;
new.frame = 0; new.flags = 0; // FLOATER // make the gib float floaterEnable( new, 2 ); // FLOATER
====== --- top of bounding box (56) ------ [head] ------ --- bottom of bounding box (0), origin (0) ~~~~~~ --- surface of water(diagram not actual size ;)
====== --- top of bounding box (56) ------ [head] --- water checking origin (5) ------ --- bottom of bounding box (0), origin (0) ~~~~~~ --- surface of waterHere is another example, this time its a dead body, it’s bounding box extents are:
====== --- top of bounding box (56) --- origin (24) ------ [body] --- water checking origin (6) ------ ====== --- bottom of bounding box ~~~~~~ --- surface of the water
void() PutClientInServer = { local entity spot; // FLOATER // only dead players float floaterDisable( self ); // FLOATER spot = SelectSpawnPoint ();(Next CLIENT.QC modification starts at line 791)
if (self.movetype == MOVETYPE_NOCLIP) return; // FLOATER // this was a check for < 0 but a player is also dead // when his health == 0, the reason for this minor change // is that if the player dies with a health of zero, then this // routine actually goes through the motions which causes // the player not to float properly! if( self.health <= 0 ) return; // FLOATER if (self.waterlevel != 3)
self.flags = self.flags - (self.flags & FL_ONGROUND); self.avelocity = crandom() * '0 600 0'; // FLOATER // make the head float floaterEnable( self, 5 ); // FLOATER(Next PLAYER.QC modification starts at line 573)
self.angles_x = 0; self.angles_z = 0; // FLOATER // make the player's dead body float floaterEnable( self, -18 ); // FLOATER if (self.weapon == IT_AXE)Modify COMBAT.QC (78) as follows:
if (self.flags & FL_MONSTER) { // FLOATER // make the monster's dead body float floaterEnable( self, -18 ); // FLOATER killed_monsters = killed_monsters + 1; WriteByte (MSG_ALL, SVC_KILLEDMONSTER); }Modify WORLD.QC (390) as follows:
setorigin (bodyque_head, ent.origin); setsize (bodyque_head, ent.mins, ent.maxs); // FLOATER bodyque_head.sFloating = ent.sFloating; bodyque_head.state = ent.state; bodyque_head.speed = ent.speed; bodyque_head.fOriginOffset = ent.fOriginOffset; bodyque_head.ltime = ent.ltime; if( ent.flags & FL_INWATER ) bodyque_head.flags = bodyque_head.flags | FL_INWATER; // FLOATER bodyque_head = bodyque_head.owner;The above modification makes the copy of a dead player have the same state as the player before he respawns. Modify ITEMS.QC (1380) as follows:
item.nextthink = time + 120; // remove after 2 minutes item.think = SUB_Remove; // FLOATER // make the backpack float floaterEnable( item, 6 ); // FLOATER
/* ============================================================================== FLOATER.QC by Alan Kivlin <e-mail: alan.kivin@cyberiacafe.co.uk> 12 / MAY / 1997 Description of the Modification ------------------------------- Routines for making an entity float to the surface of water. A floater will sink depending on its falling velocity, it will then float to the surface where it will bob up and down for around 30 seconds and finally it will sink until it hits the ground. Sometimes you'll find a floater will retain its avelocity, making it spin around while bobbing - I didn't code for anything like this. Also an entity will sometimes keep it's velocity_x or velocity_y. Copyright and Distribution Permissions -------------------------------------- This modification is Copyright (C) 1997 by Alan Kivlin. Authors MAY use this modification as a basis for other publicly available work. ^^^^^^^^ Use this in a commercial endeavour and become a friend of Satan. Talk to me first, ok? DISCLAIMER: Alan Kivlin (aka Virtuoso) is not responsible for any harm or psychological affects, loss of sleep, fatigue or general irresponsibility from using this modification. If you put this on a CD, you owe me one free copy of the CD. You also owe everyone in the world a Quake related competition, with the prize being a free copy of the CD to the first 10 competition winners. You pay postage too. Don't like this? Don't put it on a CD! If you take my work and rip my name off, you will burn in hell. Thanks to Dave 'Zoid' Kirsch for his Copyright and Distribution Permissions that I based the above on. ============================================================================== */ // last frame processed float fFloaterLastFrame; // "floating" when the entity is a floater .string sFloating; // origin offset when checking for water .float fOriginOffset; // floater state flags float FS_FALLING = 1; float FS_SURFACING = 2; float FS_FLOATING = 3; float FS_SINKING = 4; // maximum number of active floaters float FLOATER_MAXIMUM = 32; //---------------------------------------------------------------------------- // returns TRUE if in WATER, SLIME or LAVA float( entity ent ) floaterInWater; // makes the entity float void( entity ent, float offset ) floaterEnable; // stops the entity from floating void( entity ent ) floaterDisable; // controls the floating of the floaters void() floaterPreThink; //---------------------------------------------------------------------------- /* ============================================================================== floaterInWater returns TRUE if in WATER, SLIME or LAVA ============================================================================== */ float( entity ent ) floaterInWater = { local vector where; local float contents; where = ent.origin; where_z = where_z + ent.fOriginOffset; contents = pointcontents( where ); if( contents >= -5 && contents <= -3 ) // is in WATER (-3), SLIME (-4) or LAVA (-5) return TRUE; return FALSE; }; /* ============================================================================== floaterEnable makes the entity float ============================================================================== */ void( entity ent, float offset ) floaterEnable = { local float floatercount; local entity floater, oldest; oldest = floater = find( world, sFloating, "floating" ); while( floater ) { floatercount = floatercount + 1; if( floater.ltime <= oldest.ltime ) oldest = floater; floater = find( floater, sFloating, "floating" ); } if( floatercount == FLOATER_MAXIMUM ) floaterDisable( oldest ); ent.sFloating = "floating"; ent.state = FS_FALLING; ent.speed = 0; // save origin offset, used when checking for water ent.fOriginOffset = offset; // time to start sinking ent.ltime = time + 30 + random() * 5; if( floaterInWater( ent ) ) { // MOVETYPE_TOSS in water ent.movetype = MOVETYPE_TOSS; // set inwater flag ent.flags = ent.flags | FL_INWATER; } else { // MOVETYPE_BOUNCE out of water ent.movetype = MOVETYPE_BOUNCE; // reset inwater flag ent.flags = ent.flags - ( ent.flags & FL_INWATER ); } }; /* ============================================================================== floaterDisable stops the entity from floating ============================================================================== */ void( entity ent ) floaterDisable = { // stop floating ent.sFloating = string_null; }; /* ============================================================================== floaterPreThink controls the floating of the floaters ============================================================================== */ void() floaterPreThink = { local entity ent; if( fFloaterLastFrame == framecount ) // already processed this frame return; // set last frame so we don't process a frame more than once fFloaterLastFrame = framecount; ent = find( world, sFloating, "floating" ); while( ent ) { if( ( ent.state == FS_FLOATING ) && ( ent.flags & FL_ONGROUND ) ) { // if we are on the ground then we should be falling, this occurs // when the floater is on a moving platform that has left the water ent.state = FS_FALLING; ent.speed = 0; } if( ent.state == FS_FLOATING ) { if( ent.speed > 0 ) // floating up ent.velocity_z = ent.speed * ( 1 + frametime * 8 ); else // floating down ent.velocity_z = 0; } else if( ent.state == FS_SURFACING ) { if( ent.velocity_z > 0 ) // keep surfacing to a constant speed ent.velocity_z = ent.speed; else if( floaterInWater( ent ) ) // can't reach the surface so make it sink ent.state = FS_SINKING; } else if( ent.state == FS_SINKING ) if( ent.flags & FL_ONGROUND ) // sunk to the bottom floaterDisable( ent ); else // sink slowly ent.velocity_z = 0; if( floaterInWater( ent ) ) { if( ! ( ent.flags & FL_INWATER ) ) { // MOVETYPE_TOSS in water ent.movetype = MOVETYPE_TOSS; // set inwater flag ent.flags = ent.flags | FL_INWATER; if( ent.state == FS_FLOATING ) // start floating up ent.speed = 72 + random() * 16; else if( ent.state == FS_FALLING ) // play enter water sound sound( ent, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM ); } if( ent.state == FS_FALLING ) { if( ! ent.speed ) { if( ent.velocity_z < 0 ) // set maximum falling speed before floater should surface ent.speed = ent.velocity_z * 8; } if( ( ent.velocity_z <= ent.speed ) || ( ent.flags & FL_ONGROUND ) ) { // start surfacing ent.state = FS_SURFACING; ent.speed = 128 + random() * 32; ent.velocity_z = ent.speed; ent.velocity_x = 0; ent.velocity_y = 0; } } } else { if( ( ent.flags & FL_INWATER ) ) { // MOVETYPE_BOUNCE out of water ent.movetype = MOVETYPE_BOUNCE; // reset inwater flag ent.flags = ent.flags - FL_INWATER; if( ent.state == FS_FLOATING ) // start floating down ent.speed = 0; else if( ent.state == FS_SINKING ) { // floater has sunk out of the water ent.state = FS_FALLING; ent.speed = 0; } if( ent.state == FS_FALLING ) // play leave water sound sound( ent, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM ); } if( ent.state == FS_SURFACING ) { // once its surfaced, make it jump out ent.velocity_z = ent.speed * 1.5; // start floating down ent.state = FS_FLOATING; ent.speed = 0; } } if( ent.ltime <= time ) { if( ent.flags & FL_INWATER ) { // floater has taken in too much water so sink to the bottom ent.state = FS_SINKING; ent.ltime = time + 10 + random() * 5; } } // stop quake from making a splash sound ent.watertype = 0; // physics movement won't happen otherwise ent.flags = ent.flags - ( ent.flags & FL_ONGROUND ); ent = find( ent, sFloating, "floating" ); } };