InsideQC
 - Front Page

Tutorials are copyrighted by their author and the Inside3D staff. And may be used in any Quake modification provided that the author and the InsideQC staff are credited. Please direct any comments to the author.


Created By: Triften Chmil
eMail: tlccod@c2i2.com
ICQ UIN: 2651988
Difficulty Scale: Medium


Introduction
This tutorial will tell you how to change the regular wussy nailgun into a weapon of mass destruction. Instead of regular nails, you will have time-delay explosive nails (a la Ghost in the Shell). 1.5 seconds after the last one hits, everyone with a nail sticking out of the will go critical and make a BIG mess.


Step 1
First, open weapons.qc and go down to launch_spike. It'll look like this:
/*
===============
launch_spike

Used for both the player and the ogre (From QTest? Now, that's a bit outdated, eh?)
===============
*/
Above this we will create a new function, W_FireDarts. We have to create a new function or else the scraggs will be certain death. Just cut and paste this or whatever:

void(float ox) W_FireDarts =// the ox makes the nails come out of each barrel
{
	local vector dir;
	local entity dart; //our dart entity

	if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
	{
		W_FireSuperSpikes (); //fire spikes and not darts if you are using the super nailgun
		return;
	}

	self.punchangle_x = -4;//the kickback
	
	self.currentammo = self.ammo_nails = self.ammo_nails - 1;
	sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
	self.attack_finished = time + 0.2;
	dir = aim (self, 1000);
	dart = spawn ();//creat the dart
	dart.owner = self;//you are the owner
	dart.movetype = MOVETYPE_FLYMISSILE;//It doesn't bounce
	dart.solid = SOLID_BBOX;//it doesn't share space with other items

	dart.angles = vectoangles(dir);
	
	dart.touch = dart_touch;//when touched call dart_touch
	dart.classname = "spike";
	dart.think = SUB_Remove;   //After 6 seconds of uneventful flight,
	dart.nextthink = time + 6; //remove the dart
	setmodel (dart, "progs/spike.mdl");
	setsize (dart, VEC_ORIGIN, VEC_ORIGIN);		
	setorigin (dart, self.origin + '0 0 16' + v_right*ox);

	dart.velocity = dir * 700; //the dart's speed
};


Step 2
Above this we will have to define the various touch and think functions Here goes:
void() dart_touch =
{
local float rand;
	if (other == self.owner)
		return; //If it hits you, do nothing

	if (other.solid == SOLID_TRIGGER)
		return;	// trigger field, do nothing

	if (pointcontents(self.origin) == CONTENT_SKY)
	{
		remove(self);
		return;
	}

// hit something that bleeds
	if (other.takedamage)
	{
		spawn_touchblood (4);
		T_Damage (other, self, self.owner, 4); //Low damage
		self.velocity = (self.velocity * 0);    //Set's the spike up so it sticks
		self.avelocity = VEC_ORIGIN;            //to an enemy
		self.enemy = other;
		dart_wait = time + 1.5; //the time delay for detonation
		self.think = dart_stick;        //In a tenth second
		self.nextthink = (time + 0.10); //go to dart_stick
		self.touch = dart_fuse;         //now when touched call dart_fuse

	}
	else //otherwise the dart hits a wall...
	{
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
		WriteByte (MSG_BROADCAST, TE_SPIKE);
		WriteCoord (MSG_BROADCAST, self.origin_x);
		WriteCoord (MSG_BROADCAST, self.origin_y);
		WriteCoord (MSG_BROADCAST, self.origin_z);
		remove(self);
	}
};

Above this we define dart_fuse and dart_stick

void() dart_fuse = //this is our touch function { if (time > dart_wait) //if touching something and 1.5 seconds pass, then.. { // T_RadiusDamage (self, self.owner, 120, world); //You can chose to do radius dmg T_Damage (other, other, self.owner, 400); //or dmg only to the poor sap with WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); //the dart. WriteByte (MSG_BROADCAST, TE_EXPLOSION); //Then the dart becomes an explosion WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); BecomeExplosion (); remove(self); //The dart exploded, therefore we remove it } }; void() dart_stick = //our think function { if ( ((self.enemy != world) && (self.enemy.health > 1)) ) //if the dart is on a live enemy then.. { self.origin = self.enemy.origin; //it stays on the enemy and if ( (self.velocity == VEC_ORIGIN) ) //moves with the enemy { self.avelocity = VEC_ORIGIN; } } else //if the enemy dies then.. { WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); //explode harmlessly WriteByte (MSG_BROADCAST, TE_EXPLOSION); //or you could make it do damage, WriteCoord (MSG_BROADCAST, self.origin_x); //doesn't matter. WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); BecomeExplosion (); } self.nextthink = (time + 0.10); //after another .1 sec check this function again };



Step 3
Finally we mention functions ahead of time to define later and add one thing to player.qc. Add this above dart_fuse:
void() s_explode1;
void() BecomeExplosion;
float dart_wait;
void() W_FireSuperSpikes;
Open player.qc and find this:

void() player_nail1   =[$nailatt1, player_nail2  ] 
{
	self.effects = self.effects | EF_MUZZLEFLASH;

	if (!self.button0)
		{player_run ();return;}
	self.weaponframe = self.weaponframe + 1;
	if (self.weaponframe == 9)
		self.weaponframe = 1;
	SuperDamageSound();
	W_FireSpikes (4);
	self.attack_finished = time + 0.2;
};
void() player_nail2   =[$nailatt2, player_nail1  ]
{
	self.effects = self.effects | EF_MUZZLEFLASH;

	if (!self.button0)
		{player_run ();return;}
	self.weaponframe = self.weaponframe + 1;
	if (self.weaponframe == 9)
		self.weaponframe = 1;
	SuperDamageSound();
	W_FireSpikes (-4);
	self.attack_finished = time + 0.2;
};
Change both of the W_FireSpikes to W_FireDarts. Leave the 4 and -4 alone.


Step 4
Compile and run in with guns a-blazin'!