Inside3D!
     

Chargeable weapons

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> QuakeC Programming
View previous topic :: View next topic  
Author Message
Senban



Joined: 14 Apr 2007
Posts: 19

PostPosted: Sat Jul 07, 2007 3:04 am    Post subject: Chargeable weapons Reply with quote

I am working on code for hand grenades for use in my mod (SuperCoop). I want to make holding down the attack button charge up the power of the throw and releasing the attack button launch the grenade (think Worms). Does anyone have any ideas how to do this, or can anyone think of a weapon mod that does something similar with .qc files that I could look at?
Back to top
View user's profile Send private message
Lardarse



Joined: 05 Nov 2005
Posts: 243
Location: Bristol, UK

PostPosted: Sat Jul 07, 2007 11:11 am    Post subject: Reply with quote

Lets try something like this:

Check for self.button0 being pressed. If it is, set a flag, and then set a variable to the current time.

While the flag is set, dheck for the button being released instead of being pressed. When it is relieased, time-that variable we created contains the length of time that the button was pressed for.

I don't know how to miodify this to throw the grenade using an impulse, though...
Back to top
View user's profile Send private message
Senban



Joined: 14 Apr 2007
Posts: 19

PostPosted: Sat Jul 07, 2007 2:56 pm    Post subject: Reply with quote

The problem I'm having is detecting the release of the attack button.
I've put an
Code:
if (!self.button0)
case in the weapon frame function but it dosn't seem to be picking up the buttons release.
Hand grenades are working as a seperate weapon (as in Quake II) so doing it with impulse commands isn't an issue.
Back to top
View user's profile Send private message
Dr. Shadowborg
Inside3D Staff


Joined: 16 Oct 2004
Posts: 726

PostPosted: Sat Jul 07, 2007 4:05 pm    Post subject: Reply with quote

Have a look at player_nail1() in player.qc. (i.e. it goes to player_nail2() then loops back to player_nail1() again.)

That should give you a few ideas. Also, you may want to put a check in w_setcurrentammo() in weapons.qc so that it doesn't reset your weaponframe to 0 when you pick up an item.
_________________
"Roboto suggests Plasma Bazooka."
Back to top
View user's profile Send private message
Senban



Joined: 14 Apr 2007
Posts: 19

PostPosted: Sun Jul 08, 2007 8:38 am    Post subject: Reply with quote

Thanks guys, I've got it working now. When I get the fine tuning done I'll post the code.
Back to top
View user's profile Send private message
Senban



Joined: 14 Apr 2007
Posts: 19

PostPosted: Sat Jul 28, 2007 6:15 pm    Post subject: Grenade Tutorial Reply with quote

This gives you a unique and entertaining secondary weapon. You select it by pressing button 6 twice (or once if you don't have the grenade launcher yet.)
Unlike quakes other weapons holding the fire button down charges the power of the shot and releasing it lobs (or simply drops, depending on how long you charged it up for) the grenade. To make things even more fun if you launch the grenade within arms reach of your target you will attach the grenade to them.

Step 1. Name rank and number.
DEFS.QC
Open defs.qc and make these the last two lines

Code:
float HAND_GRENADES = 3;
.float charge;


Setting HAND_GRENADES to a non binary number means that it doesn't take up a precious item slot, which it doesn't need because you won't be doing any self.items checks with it.

Step 2. Meat and Veg.
WEAPONS.QC

Add this to the precached sounds list at the top of weapons.qc

Code:
precache_sound ("buttons/switch04.wav");


In GrenadeTouch change: if (other.takedamage == DAMAGE_AIM)
to:
Code:
if ((other.takedamage == DAMAGE_AIM) && (self.classname != "hand_grenade"))


This is just to disable the grenade launchers ability to detonate when it hits a monster.

The next set of functions goes in weapons.qc, after "void() superspike_touch ="

Code:
//=============
//HAND GRENADES
//=============
void() PrimeGrenade =
{
   if (self.charge == 0)
      sound (self, CHAN_WEAPON, "player/axhit2.wav", 0.5, ATTN_NORM);
   
   if (self.charge >= 8)
   {
      self.charge = 8;
      self.punchangle_x = -2;
   }
   else
   {
      self.charge = self.charge + 1;
      sprint (self, "*");
   }
   self.attack_finished = time + 0.1;
};

This pulls the pin out with a nice "tink" and starts powering up for the throw.
The sprint gives the player a rudimentary charge up meter.
Code:
void() ThrowGrenade =
{
   local   entity missile, mpuff;
   
   self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
   
   sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);

   missile = spawn ();
   missile.owner = self;
   missile.movetype = MOVETYPE_BOUNCE;
   missile.solid = SOLID_BBOX;   
      
// set missile speed   

   makevectors (self.v_angle);
      
        missile.velocity = v_forward*65 + v_up * 21.5 + crandom()*v_right*3 + crandom()*v_up*3;
   missile.velocity = missile.velocity * self.charge;
   
   missile.avelocity = '-50 -5 -5';
   missile.avelocity = missile.avelocity * self.charge;
   
   missile.angles = vectoangles(missile.velocity);
   
   missile.classname = "hand_grenade";
   missile.touch = GrenadeTouch;
   
// set missile duration
   missile.nextthink = time + 3;
   missile.think = GrenadeExplode;
   
   setmodel (missile, "progs/grenade.mdl");
   setsize (missile, '0 0 0', '0 0 0');      
   setorigin (missile, self.origin);

   self.charge = 0;
   sprint (self, "\n");
   self.attack_finished = time + 0.4;   
};

This is basically the grenade launcher code but with a different sound and modified velocity and fuse time. The velocity code is the interesting part here.
The sprint ends the charge up "meter".

Code:
void() GrenadeStick =
{
   self.nextthink = time + 0.1;
   self.ammo_cells = self.ammo_cells - 1;
   
   if (self.ammo_cells < 1)
        GrenadeExplode();
   
   self.velocity = self.enemy.velocity;
      self.angles = self.enemy.angles;
      self.origin = self.enemy.origin;
};

This bit owes a certain ammount to Homing Sticky Missiles v0.9 by Jonathan Avraham. The grenade is given .ammo_cells to use as a fuse. When the battery runs out the grenade explodes.

Code:
void(entity victim) PlaceGrenade =
{
   local   entity missile, mpuff;   

   self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
   
   sound (victim, CHAN_BODY, "buttons/switch04.wav", 1, ATTN_NORM);
   
   missile = spawn ();
   missile.owner = self;
   missile.movetype = MOVETYPE_NOCLIP;
   missile.solid = SOLID_BBOX;
   
   missile.classname = "hand_grenade";
      
// set missile duration
   missile.nextthink = time + 0.1;
   missile.ammo_cells = 30;
   missile.think = GrenadeStick;
   missile.enemy = victim;   

   setmodel (missile, "progs/grenade.mdl");
   setsize (missile, '0 0 0', '0 0 0');      
   setorigin (missile, victim.origin);

   sprint (self, "\nIt's better to give than to recieve!\n");
   self.charge = 0;   
   self.attack_finished = time + 0.4;   
};

Basicaly a rehash of ThrowGrenade. Look at the way Quake handles nails and supernails to see how this could be done more efficiently.

Code:
void() HandGrenade =
{
   local   vector   source;
   local   vector   org;

   makevectors (self.v_angle);
   source = self.origin + '0 0 16';
   traceline (source, source + v_forward*64, FALSE, self);
   if (trace_fraction == 1.0)
   {   
      ThrowGrenade();
      return;
   }
   org = trace_endpos - v_forward*4;   

   if ((trace_ent.flags == trace_ent.flags | FL_MONSTER) || (trace_ent.classname == "player"))   
      PlaceGrenade(trace_ent);
   else
      ThrowGrenade();
};

Simply determines whether grenade will be thrown or placed, based on the axe code.

Next add this to W_SetCurrentAmmo (I put it before the grenade launcher but you don't have to).
Code:
   else if (self.weapon == HAND_GRENADES)
   {
      self.currentammo = self.ammo_rockets;
      self.weaponmodel = "";
      self.weaponframe = 0;
      self.items = self.items | IT_ROCKETS;
   }


This goes in W_Attack anywhere that seems sensible.
Code:
   else if (self.weapon == HAND_GRENADES)
   {      
      PrimeGrenade();      
   }


This goes in W_ChangeWeapon before the grenade launcher.
Code:
   else if ((self.impulse == 6) && (self.items != self.items | IT_GRENADE_LAUNCHER || self.weapon == IT_GRENADE_LAUNCHER))
   {
      if (self.ammo_rockets < 1)
         am = 1;
      else
      {
         self.weapon = HAND_GRENADES;
         self.charge = 0;      
         W_SetCurrentAmmo ();
         return;
      }
   }

This is one of the most important parts of the code as it allows you to select something without checking your items, it's also important to reset self.charge at this point or players would be able to carry charged grenades about with them which is silly.

These bits go between the grenade launcher and the super nailgun in CycleWeaponCommand and CycleWeaponReverseCommand respectively.
Code:
      else if (self.weapon == HAND_GRENADES)
      {
         self.weapon = IT_GRENADE_LAUNCHER;
         if (self.ammo_rockets < 1)
            am = 1;
      }

Code:
      else if (self.weapon == HAND_GRENADES)
      {
         self.weapon = IT_SUPER_NAILGUN;
         if (self.ammo_nails < 2)
            am = 1;
      }

This code does not allow you to select hand grenades by scrolling, but it means you can use weapon scrolling to switch to a different weapon from the grenades.

Step 3. Tidy up and got to bed.
CLIENT.QC

Put this in PlayerPreThink between the death code and the jump code.
Code:
   if (self.weapon == HAND_GRENADES && self.charge > 0 && !self.button0)
   {
      player_rocket1();      
      HandGrenade();
   }

This is the most important piece of code as it let's the player perform an action by releasing the button rather than by pressing it.

Replace the grenade launcher in ClientObituary obit with this lot.
Code:
            if (targ.weapon == IT_GRENADE_LAUNCHER)
            {
               bprint (" tries to put the pin back in\n");
               return;
            }
            if (targ.weapon == HAND_GRENADES)
            {
               bprint (" forgot where he put his hand grenade\n");
               return;
            }

And finally put this after the Lightning Gun obit.
Code:
            if (rnum == HAND_GRENADES)
            {      
               deathstring = " was blown away by ";
               deathstring2 = "'s hand grenade\n";
            }
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> QuakeC Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group