Charge Shot
Moderator: InsideQC Admins
25 posts
• Page 1 of 2 • 1, 2
Charge Shot
I decided to make a new topic on this cause i want to be mroe specific.
Lets keep it basic, lets say i have the rocket launcher. and i press mouse1 to fire. just like normal. I also want to be able to hold down mouse1 to charge, and depending on how long i hold it it shoots a bigger rocket. Like maybe 3 levels. hold down for 1 second, is a little bigger, 3 seconds bigger, 5 seconds biggest. How would i go about doing that?
Lets keep it basic, lets say i have the rocket launcher. and i press mouse1 to fire. just like normal. I also want to be able to hold down mouse1 to charge, and depending on how long i hold it it shoots a bigger rocket. Like maybe 3 levels. hold down for 1 second, is a little bigger, 3 seconds bigger, 5 seconds biggest. How would i go about doing that?
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
I do this for the E-Rifle's primary fire in Conquest. The basic idea is this:
In player.qc, set up some new frames for your weapon to charge. The first frame sets up your charging stuff. The second frame is called repeatedly while you charge. The rest of the frames are to animate firing the weapon once the player lets go (i.e. the rocket firing frames for your code). Here's my e-rifle code:
My e-rifle only uses 2 frames to animate the firing, and it's a little complex. Rest-assured, you can just call player_rocket1() and do just fine (and W_FireRocket()).
Now that you have the player frames for animating, the player will stay in the charging frame until he releases the button or reaches maximum charge (if self.t_width is set to TRUE by the charging function, then the weapon fires itself without permission; you can omit that feature if you like).
The next step is to write the functions that start the charge and manage building the charge. In this code, the start function initializes the variables we're using, and the charge function increases the charge by 1 every 0.2 seconds.
.float chargeLevel should, of course, be in your defs.qc at the bottom.
Not so bad so far, I hope. These two functions are called by the frames in player.qc. I'd recommend sticking them in weapons.qc by your weapon fire code (W_FireRocket in your case).
The final step is to modify your firing function to use extra ammo and do extra damage based on the charge. Now, Conquest's ammo and weapon system is *very* different from normal Quake, so I'll be paraphrasing here and writing partial code.
Then use self.dmg in the missile's explode function instead of 120. The missile should be more powerful, physically bigger (in new engines with .scale support), and take more ammo when charged.
I hope that's all correct! Like I said, the fire function is all paraphrasing and uncompiled/tested. It works for my e-rifle but I had to change the code to be more like normal quake.
Have fun!
In player.qc, set up some new frames for your weapon to charge. The first frame sets up your charging stuff. The second frame is called repeatedly while you charge. The rest of the frames are to animate firing the weapon once the player lets go (i.e. the rocket firing frames for your code). Here's my e-rifle code:
- Code: Select all
void() player_e_rifle =[$nailatt2, player_e_riflecharging ]
{
StartE_Rifle();
self.attack_finished = gametime + 0.2;
};
void() player_e_riflecharging =[$nailatt2, player_e_riflefire1 ]
{
self.attack_finished = gametime + 0.2;
if(!self.button0 || self.t_width)
return; // go to firing frames
self.think = player_e_riflecharging; // otherwise keep charging
ChargeE_Rifle();
};
void() player_e_riflefire1 =[$nailatt2, player_e_riflefire2 ]
{
self.weaponframe = 0;
self.frame = $shotatt1 + self.weaponframe;
W_FireE_Rifle();
};
void() player_e_riflefire2 =[$nailatt2, player_e_riflefire2 ]
{
self.weaponframe = self.weaponframe + 1;
self.frame = $shotatt1 + self.weaponframe;
if(self.frame > $shotatt6)
self.frame = $shotatt6;
if(self.weaponframe >= 6)
self.think = player_run;
};
My e-rifle only uses 2 frames to animate the firing, and it's a little complex. Rest-assured, you can just call player_rocket1() and do just fine (and W_FireRocket()).
Now that you have the player frames for animating, the player will stay in the charging frame until he releases the button or reaches maximum charge (if self.t_width is set to TRUE by the charging function, then the weapon fires itself without permission; you can omit that feature if you like).
The next step is to write the functions that start the charge and manage building the charge. In this code, the start function initializes the variables we're using, and the charge function increases the charge by 1 every 0.2 seconds.
.float chargeLevel should, of course, be in your defs.qc at the bottom.
- Code: Select all
void() StartE_Rifle =
{
self.weaponframe = 0;
self.chargeLevel = 1; // always start at 1
self.t_length = gametime + 0.2; // wait this long before increasing charge
self.t_width = 0; // not done yet
};
void() ChargeE_Rifle =
{
// if the charge is below our ammo (we have enough ammo to charge more) and the charge level is less than 5, our max charge, go ahead and charge more
if(self.chargeLevel < self.ammo_cells && self.chargeLevel < 5)
{
// self.t_length is our timer for charging weapons. Don't charge every frame, just every 0.2 seconds.
if(self.t_length < time)
{
self.t_length = time + 0.2;
self.chargeLevel = self.chargeLevel + 1;
}
}
else // if we're at max charge or out of ammo, go ahead and fire
self.t_width = 1;
};
Not so bad so far, I hope. These two functions are called by the frames in player.qc. I'd recommend sticking them in weapons.qc by your weapon fire code (W_FireRocket in your case).
The final step is to modify your firing function to use extra ammo and do extra damage based on the charge. Now, Conquest's ammo and weapon system is *very* different from normal Quake, so I'll be paraphrasing here and writing partial code.
- Code: Select all
void() W_FireE_Rifle =
{
float am, pwr;
am = self.ammo_cells;
// Only fire if we have ammo and not a zero or negative charge for some reason
if(am <= 0 || self.chargeLevel < 1)
return;
// only use as much ammo as we have
if(self.chargeLevel > am)
self.chargeLevel = am;
// Take ammo
self.currentammo = self.ammo_cells = self.ammo_cells - self.chargeLevel;
// Determine power
pwr = 1.0 + ((self.chargeLevel-1)*0.5); // our rocket's damage will range from 100% to 300% with a charge of 1-5
// fire missile
..... blah blah blah .....
// Set a variable on the missile so we can know, when it's time to explode, how powerful it is
missile.dmg = 120*pwr;
missile.scale = pwr; // make the missile bigger; remove this line if you don't want to include new engine effects etc in your mod
// Note that you could also make the missile move faster/slower based on power.
// Reset charge level, since we're done with it now
self.chargeLevel = 0;
}
Then use self.dmg in the missile's explode function instead of 120. The missile should be more powerful, physically bigger (in new engines with .scale support), and take more ammo when charged.
I hope that's all correct! Like I said, the fire function is all paraphrasing and uncompiled/tested. It works for my e-rifle but I had to change the code to be more like normal quake.
Have fun!
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
- Wazat
- Posts: 771
- Joined: Fri Oct 15, 2004 9:50 pm
- Location: Middle 'o the desert, USA
Here is my quick and dirty rocket charging code...
Open up defs.qc and put the following at the bottom:
We're going to use "rockettime" to keep track of when the fire button was pressed and we will use rocketdamage to determine how much damage the rocket will do depending on how long the fire button was held.
Open up weapons.qc and find the T_MissileTouch function and replace:
with:
The rocket will now do "rocketdamage" instead of 120 damage.
Now locate the W_WeaponFrame function. Replace:
with:
What we are doing here is checking to see if the fire button is being pressed. If it is, record the current game time into rockettime.
If we are holding the rocket launcher and still holding the fire button then check to see if the game time has gone 1 or 2 seconds past rockettime. If it has then load the the appropriate damage into rocketdamage. Fire weapon after fire button has been released.
rockettime + 1 = slightly more than a second
rockettime + 2 = slightly more than two seconds
You could try something less to get it closer to one and two seconds... I actually enjoyed the effect when I had the numbers set to 5 and 10. At these settings you would have to go hide somewhere to fully charge!
Like I said, this a quick and dirty way to do this. Personally, I like Wazats method as it allows you to use some of the player frames... this will give other players a visual que of someone charging their weapon!
Open up defs.qc and put the following at the bottom:
- Code: Select all
float rockettime;
float rocketdamage;
We're going to use "rockettime" to keep track of when the fire button was pressed and we will use rocketdamage to determine how much damage the rocket will do depending on how long the fire button was held.
Open up weapons.qc and find the T_MissileTouch function and replace:
- Code: Select all
T_RadiusDamage (self, self.owner, 120, other);
with:
- Code: Select all
T_RadiusDamage (self, self.owner, rocketdamage, other);
The rocket will now do "rocketdamage" instead of 120 damage.
Now locate the W_WeaponFrame function. Replace:
- Code: Select all
if (self.button0)
{
SuperDamageSound ();
W_Attack ();
}
with:
- Code: Select all
if (self.button0) //Are we pressing the fire button?
{
if (rockettime == 0)
rockettime = time; //Put game time into rockettime
if (self.weapon == IT_ROCKET_LAUNCHER) //If we have the rocket launcher check the stuff below
{
if (rockettime + 2 <= time) //If two seconds passed we now have the maximum strength rocket
{
centerprint(self, "Giant Rocket");
rocketdamage = 360;
}
else if (rockettime + 1 <= time) //If one second passed we now have a medium strength rocket
{
centerprint(self, "Big Rocket");
rocketdamage = 240;
}
else //If less than one second has passed we now have a normal strength rocket
{
centerprint(self, "Normal Rocket");
rocketdamage = 120;
}
return;
}
}
if (rockettime > 0)
{
SuperDamageSound ();
W_Attack ();
rockettime = 0;
}
What we are doing here is checking to see if the fire button is being pressed. If it is, record the current game time into rockettime.
If we are holding the rocket launcher and still holding the fire button then check to see if the game time has gone 1 or 2 seconds past rockettime. If it has then load the the appropriate damage into rocketdamage. Fire weapon after fire button has been released.
rockettime + 1 = slightly more than a second
rockettime + 2 = slightly more than two seconds
You could try something less to get it closer to one and two seconds... I actually enjoyed the effect when I had the numbers set to 5 and 10. At these settings you would have to go hide somewhere to fully charge!
Like I said, this a quick and dirty way to do this. Personally, I like Wazats method as it allows you to use some of the player frames... this will give other players a visual que of someone charging their weapon!
Good God! You shot my leg off!
-

Junrall - Posts: 191
- Joined: Mon Sep 21, 2009 12:27 am
- Location: North West Oregon, USA
Either of the above should work rather well to to tie in with what he has coded previously from my understanding. Though Wazats E-Rifle Code includes animation frames in which you need to have it look like it is charging so I'd vouce for Wazats if you are going to learn from them. Though Dunralls Code seems easier to merge in with what you have at the moment (I haven't looked through your QCs Ghost).
- LonePossum.
- Posts: 38
- Joined: Mon Nov 02, 2009 11:07 am
Junrall's method will work too. I do recommend you make those into .floats instead of floats though, or two players will interfere with each other. Also, if the player fires a rocket and starts charging another before the rocket explodes, that will weaken the rocket in flight. However, this is solved by making "rocketdamage" into a .float. Then it's local to the player, and when you fire the rocket you can copy the damage from the player into the rocket.
// in the fire function, "self" is the player
missile.rockettime = self.rockettime;
...
// in the explode function, "self" is now the rocket
T_RadiusDamage (self, self.owner, self.rocketdamage, other);
Animation frames are a great way to show that you're charging. You could also attach a model or sprite to the weapon muzzle to show the charging effect, if you're using a newer engine & model format. In addition to .scale, good ways to show that the rocket is super-powerful include using a different model for each charge level, changing the projectile's .colormod (change the color w/ new engine feature), doing custom explosion effects (either with a new sprite, or spawning more explosion effects/sprites in random locations around the boom to make it more fantastic looking, or by using new engine effects), and firing multiple rockets with a spread instead of 1 powerful one.
You could even do cool stuff like make the rocket bounce off walls, exploding each time, and/or split into more rockets on bounce. Charging ricochet rockets FTW!
Have fun! And let us know when you have it working, or if you get stuck somewhere.
// in the fire function, "self" is the player
missile.rockettime = self.rockettime;
...
// in the explode function, "self" is now the rocket
T_RadiusDamage (self, self.owner, self.rocketdamage, other);
Animation frames are a great way to show that you're charging. You could also attach a model or sprite to the weapon muzzle to show the charging effect, if you're using a newer engine & model format. In addition to .scale, good ways to show that the rocket is super-powerful include using a different model for each charge level, changing the projectile's .colormod (change the color w/ new engine feature), doing custom explosion effects (either with a new sprite, or spawning more explosion effects/sprites in random locations around the boom to make it more fantastic looking, or by using new engine effects), and firing multiple rockets with a spread instead of 1 powerful one.
You could even do cool stuff like make the rocket bounce off walls, exploding each time, and/or split into more rockets on bounce. Charging ricochet rockets FTW!
Have fun! And let us know when you have it working, or if you get stuck somewhere.
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
- Wazat
- Posts: 771
- Joined: Fri Oct 15, 2004 9:50 pm
- Location: Middle 'o the desert, USA
Wazat wrote:
// in the fire function, "self" is the player
missile.rockettime = self.rockettime;
...
// in the explode function, "self" is now the rocket
T_RadiusDamage (self, self.owner, self.rocketdamage, other);
Lol!
Good God! You shot my leg off!
-

Junrall - Posts: 191
- Joined: Mon Sep 21, 2009 12:27 am
- Location: North West Oregon, USA
There shall be a video of it working some time soon.
In this game all of the guns "Charge" and one of the guns that charges happens to shoot ricocheting bullets but as for now he is just working on getting the basics of it sorted.
.
In this game all of the guns "Charge" and one of the guns that charges happens to shoot ricocheting bullets but as for now he is just working on getting the basics of it sorted.
- LonePossum.
- Posts: 38
- Joined: Mon Nov 02, 2009 11:07 am
Junrall: Of course! I spy on all the members of this forum just in case they come up with a good idea worth stealing. Then I kill them and make it look like an accident (Officer: "It looks like the walrus fell from the floor above and crushed him. Happens all the time."), and steal their ideas for my own. 95% of my modding ideas come from other people, and the remaining 5% come from the voices in my head who claim to be the real me.
Bwahahahaha...
LonePossum: Sounds good. When you get to the ricochet part, let us know. We're happy to help!
Bwahahahaha...
LonePossum: Sounds good. When you get to the ricochet part, let us know. We're happy to help!
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
- Wazat
- Posts: 771
- Joined: Fri Oct 15, 2004 9:50 pm
- Location: Middle 'o the desert, USA
I gave up on it, but now that i think of it, i could easily do it like the nailgun, except like 10 of the functions. player_charge1();..... and on the 10th one actually shoot something. Not really "charging" just giving the illusion.
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
Well here's my code anyway, it may or may not help:
- Code: Select all
if (self.button0) // if you're holding the button
if (self.weapon == IT_BOW)
{
if (self.pull < 10)
{
self.pull = self.pull + 1;
centerprint (self, "ëååð ðõììéîç¡\n\n\n\n");
}
if (self.pull >= 10)
if (self.pull < 20)
{
self.pull = self.pull + 1;
centerprint (self, "** keep pulling! **\n\n\n\n");
}
if (self.pull >= 20)
if (self.pull < 30)
{
self.pull = self.pull + 1;
centerprint (self, "*** keep pulling! ***\n\n\n\n");
}
if (self.pull >= 30)
if (self.pull < 40)
{
self.pull = self.pull + 1;
centerprint (self, "**** keep pulling! ****\n\n\n\n");
}
if (self.pull >= 40)
if (self.pull < 50)
{
self.pull = self.pull + 1;
centerprint (self, "***** keep pulling! *****\n\n\n\n");
}
if (self.pull >= 50)
if (self.pull < 60)
{
self.pull = self.pull + 1;
centerprint (self, "****** keep pulling! ******\n\n\n\n");
}
if (self.pull >= 60)
if (self.pull < 70)
{
self.pull = self.pull + 1;
centerprint (self, "******* keep pulling! *******\n\n\n\n");
}
if (self.pull >= 70)
{
self.pull = self.pull + 1;
centerprint (self, "******** íáøéíõí ðï÷åò¡ ********\n\n\n\n");
}
}
if (self.pull < 10 && !self.button0)
if (self.pull >= 1 && !self.button0) // no rapid fire
{
self.pull = 0;
}
if (self.pull >= 10 && !self.button0) // you released the button
{
Crossbow();
player_shot1 (); // crossbow shooting animation
}
- Code: Select all
void() Crossbow =
{
msg_entity = self;
newmis = spawn ();
newmis.voided=0;
newmis.owner = self;
newmis.movetype = MOVETYPE_BOUNCE;
newmis.solid = SOLID_BBOX;
newmis.classname = "arrow";
makevectors (self.v_angle);
if (self.v_angle_x)
{
if (self.pull >= 10)
if (self.pull < 20)
newmis.velocity = v_forward*600 + v_up * 300 + crandom()*v_right*15 + crandom()*v_up*15;
if (self.pull >= 20)
if (self.pull < 30)
newmis.velocity = v_forward*800 + v_up * 275 + crandom()*v_right*13 + crandom()*v_up*13;
if (self.pull >= 30)
if (self.pull < 40)
newmis.velocity = v_forward*1000 + v_up * 250 + crandom()*v_right*11 + crandom()*v_up*11;
if (self.pull >= 40)
if (self.pull < 50)
newmis.velocity = v_forward*1200 + v_up * 225 + crandom()*v_right*9 + crandom()*v_up*9;
if (self.pull >= 50)
if (self.pull < 60)
newmis.velocity = v_forward*1500 + v_up * 200 + crandom()*v_right*7 + crandom()*v_up*7;
if (self.pull >= 60)
if (self.pull < 70)
newmis.velocity = v_forward*2000 + v_up * 175 + crandom()*v_right*5 + crandom()*v_up*5;
if (self.pull >= 70)
newmis.velocity = v_forward*2500 + v_up * 150 + crandom()*v_right*2.5 + crandom()*v_up*2.5;
}
newmis.avelocity = '-50 0 5000'; // pitch & rotation
newmis.angles = vectoangles(newmis.velocity);
newmis.touch = ArrowTouch;
setmodel (newmis, "progs/arrow.mdl");
setsize (newmis, '-1 -1 -1', '-1 -1 -1');
setorigin (newmis, self.origin);
newmis.nextthink = time + 5;
newmis.think = SUB_Remove;
self.pull = 0;
};
Welcome to the Overlook Hotel: The-Overlook-Hotel.game-server.cc
-

redrum - Posts: 410
- Joined: Wed Mar 28, 2007 11:35 pm
- Location: Long Island, New York
This is Pure luck I tell ya. I was just about to start the Charging code for my mod, And Now I can just look at this topic! Thanks alot guys. I will now implement charging into Prime!
-

Mexicouger - Posts: 514
- Joined: Sat May 01, 2010 10:12 pm
Yea, it would have helped back then if i knew "self.button0" is the code to see if the fire button is help down *facepalm*
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
Don't facepalm yourself for that. We are always learning. You and I have learned alot from that Point and this point. I turned jumping into an impulse command because I didn't know what happened and how the game knew to jump. Now I know
-

Mexicouger - Posts: 514
- Joined: Sat May 01, 2010 10:12 pm
yea but its something really simple as taking a closer look at the code. what makes shotgun different from nialgun and lightning as far as the button press and hold. Not something like AI coding or something (which i still dont fully understand)
- Ghost_Fang
- Posts: 336
- Joined: Thu Nov 12, 2009 4:37 am
25 posts
• Page 1 of 2 • 1, 2
Who is online
Users browsing this forum: No registered users and 1 guest