Created By: | ShockMan |
eMail: | shockman@brutality.com |
ICQ UIN: | 1017564 |
Difficulty Scale: | Medium\Advanced |
Intruduction Well, this will enable a new weapon when you press '4' twise. The weapon is erh... totaly insane... J |
Step 1 First open up weapons.qc and find void() superspike_touch = { blah... blah... };and after that function add: .entity owner2; .float weapon2; void() rifle_rebound = { self.velocity = normalize(self.velocity) * 1000; self.movetype = MOVETYPE_FLYMISSILE; self.angles = vectoangles(self.velocity); self.think = SUB_Remove; self.nextthink = self.ltime; self.owner = world; }; void() rifle_touch = { local float rand; 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 (14); self.owner = self.owner2; T_Damage (other, self, self.owner, 14); } else { WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_SUPERSPIKE); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); if (self.aflag == 10) { remove(self); return; } self.aflag = self.aflag + 1; // count bounces } // rebound self.movetype = MOVETYPE_BOUNCE; self.think = rifle_rebound; self.ltime = self.nextthink; self.nextthink = time + 0.1; }; void(vector org, vector dir) launch_spike2 = { newmis = spawn (); newmis.owner = self; newmis.movetype = MOVETYPE_FLYMISSILE; newmis.solid = SOLID_BBOX; newmis.angles = vectoangles(dir); newmis.touch = rifle_touch; newmis.classname = "spike"; newmis.think = SUB_Remove; newmis.nextthink = time + 14; setmodel (newmis, "progs/spike.mdl"); setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); setorigin (newmis, org); newmis.velocity = dir * 1000; }; void() W_FireRifle = { local vector dir; local entity old; makevectors (self.v_angle); if (self.ammo_nails < 3) { self.weapon = W_BestWeapon (); W_SetCurrentAmmo (); return; } self.owner2 = self.owner; sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); self.currentammo = self.ammo_nails = self.ammo_nails - 3; dir = aim (self, 1000); launch_spike2 (self.origin + '0 0 16' + v_right*6, dir); self.punchangle_x = -2; }; |
Step 2 If you are lazy and don't wan't to learn anything just go to step 7. But for the little more advanced people i will now explain what this does (WARNIG: if you don't want to learn anything from this tutorial skip this step!!) You still here? so u wanna learn something... ok, we start from the begining... first we have: .entity owner2; .float weapon2;this just declares a entity variable, and a float variable, and since they aren't inside a function it is just like we would have typed it in defs.qc, but sometimes its better to have them with the other code, so you can access them easy... Then we need to jump down to the line (since its the function that will be called first its most logical we start with it): void() W_FireRifle = This line starts the function (like u didn't know) { local vector dir; define a vector local entity old; define a entity makevectors (self.v_angle); This makes v_forward the forward looking angle, v_right to your right and v_up is up. if (self.ammo_nails < 3) if you don't have 3 nails... { self.weapon = W_BestWeapon (); ...change to your best weapon, that you have ammo for. W_SetCurrentAmmo (); Set your ammo to the correct one. return; and exit this function. } self.owner2 = self.owner; its needed to create a "false" .owner field, you will notice why soon sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); play a sound self.currentammo = self.ammo_nails = self.ammo_nails - 3; Remove the 3 nails dir = aim (self, 1000); set dir to your aiming angle. NOTE: if you want the weapon to autoaim (up/down) change 1000 to 10000 launch_spike2 (self.origin + '0 0 16' + v_forward*4, dir); Call our new Launch_Spike function. first parameter (self.origin + '0 0 16' + v_forward*4) is where to shoot from, self.origin is your origin, '0 0 16' meens +16 units on the Z axel (up), and v_forward*4 is abit forward, so it don't start in the middle of you self.punchangle_x = -2; make you shake abit (can be set lower if you want... The lower the more shake }; end the function |
Step 3 Ok, that was the first function... lets get on with it... void(vector org, vector dir) launch_spike2 = here is our new launch_spike function, it takes 2 parameters, first a vector; org, its the origin where to start from, then another vector (actualy its not a vector its a angle); dir, the direction to fire. { newmis = spawn (); Spawn a new entity newmis.owner = self; set the entity's owner to the player (self) newmis.movetype = MOVETYPE_FLYMISSILE; make the new entity a flying entity newmis.solid = SOLID_BBOX; and a solid entity newmis.angles = vectoangles(dir); make the entity face the way it is traveling (very useful!!) newmis.touch = rifle_touch; call rifle_touch if the entity touches something newmis.classname = "spike"; set the classname to "spike" newmis.think = SUB_Remove; set the think function to remove the entity... newmis.nextthink = time + 14; ... after 14 sec setmodel (newmis, "progs/spike.mdl"); a model for the entity setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); the entites size setorigin (newmis, org); the entities start position newmis.velocity = dir * 1000; And finally, set it on its way!! (entity.velocity = dir * float is a very useful formula...) }; |
Step 4 That wasn't to bad, was it? but now we come to the real stuff. void() rifle_touch = this function is called when the projectile hits something { if (other.solid == SOLID_TRIGGER) return; trigger field, do nothing if (pointcontents(self.origin) == CONTENT_SKY) { remove(self); remove the projectile if it hits a sky return; and exit the function } if (other.takedamage) If we hit something that bleeds (monsters, buttons...) { spawn_touchblood (14); spawn some blood self.owner = self.owner2; Here is he fake owner again!! (don't worry to much about it yet) T_Damage (other, self, self.owner, 14); do damage to other (the thing that is being hit), and it is self (the projectile) that does the damage, but it is self.owner (the owner of the projectile that gets the frag, or the monsters get angry at) } else if it doesn't bleed { WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); WriteByte (MSG_BROADCAST, TE_SUPERSPIKE); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); These lines sends a message to quake that tells quake to spawn a "TE_SUPERSPIKE" (its some small grey dots...) you can try to replace it with TE_EXPLOSION, just to see what it does if (self.aflag == 10) we dont want the projectile to sit in a corner and bounce, so remove it after 10 bounces... (this isn't nessesary, 'couse we did a think function that removes the spike after 14 sec, remember?) { remove(self); return; } self.aflag = self.aflag + 1; add one to the bounce count Just a little note here on .aflag, it is a float variable that is defined in defs.qc, but it is only used for doors, so it can be used for some other stuff. if you wan't to save on floats (its a good thing to do so, 'couse each .float, .entity or .vector you define takes up memory and to many of them might slow things down.) Just be careful what you use .aflag for so you dont use it for more than one thing on each entity... } Now, for the Bounce!! self.movetype = MOVETYPE_BOUNCE; First set the projectiles movetype to MOVETYPE_BOUNCE (it will make it bounce, *doh*) self.think = rifle_rebound; then set the projectile's think to the bounce code, 'couse we dont want it to go there at ones, it gotta get some time to bounce first self.ltime = self.nextthink; then we need to store the nextthink in a new variable (so it don't forget how long it have been flying self.nextthink = time + 0.1; and set the nextthink to time + 0.1 (thats about one frame) }; |
Step 5 Ok, now for fire_rebound, this is the actual bounce code... first you might wanna know this: InAngle | / |/ |--------------- NORMAL |\ | \ OutAngle This shows how "bounceing" works, the main thing this is for is light beems (and other things that aint affected by gravity?) The basic thing is that the "inangle" is always the same as the "outangle" but in "reverse" or what I shall call it... (im not to good at this stuff, hehe...) Well... back to the code... void() rifle_rebound = { self.velocity = normalize(self.velocity) * 1000; This first Normalizes (look below) the projectiles velocity then it multiply it by 1000 again... Normalize: it returns a vector with the length of 1, collinear to the given vector... self.movetype = MOVETYPE_FLYMISSILE; set the movetype to MOVETYPE_MISSILE again (else the spike would only bounce down to the floor, like a grenade) self.angles = vectoangles(self.velocity); You have seen this before... yupp, make the spike face the direction its moveing self.think = SUB_Remove; and set the think to SUB_Remove again (so it removes 14 sec after it was shoot) self.nextthink = self.ltime; get how much time it was left self.owner = world; set self.owner to world (world = nothing... well, almost) }; |
Step 6 Ok, now it might be time to explain why we had to use self.owner2, simple... self.owner = the player, then the spike would go right though him and not hurt him... thats no fun... so we set self.owner2 to self.owner and when we shall use self.owner we just set it to self.owner2, got that? if not... don't worry. its not that important. Well... now we have the Main code there, now its just a few small things to fix before we can get it to work. |
Step 7 Now find void() W_Attack and replace: else if (self.weapon == IT_NAILGUN) { player_nail1 (); }with: else if (self.weapon == IT_NAILGUN && self.weapon2 == 0) { player_nail1 (); } else if (self.weapon == IT_NAILGUN && self.weapon2 == 1) { player_shot1 (); W_FireRifle (); self.attack_finished = time + 0.8; // you can change this to make the weapon fire faster } |
Step 8 Now find void() W_ChangeWeapon and replace: else if (self.impulse == 4) { fl = IT_NAILGUN; if (self.ammo_nails < 1) am = 1; }with: else if (self.impulse == 4) { fl = IT_NAILGUN; if (self.weapon2 == 0) { self.weapon2 = 1; if (self.ammo_nails < 3) am = 1; } else { self.weapon2 = 0; if (self.ammo_nails < 1) am = 1; } } |
Step 9 Now, thats it!! compile as usual and enjoy... J If you eighter are to lazy to do this or want to use this weapon with a really cool new models and sounds (all by me =), download it here And if you find this useful, or use this code somewere... just send me a email. and maybe include my name somewere too? Bye... and please send me some feedback on this, ok?, ShockMan |