Forum

[Tutorial] Railgun

Discuss programming in the QuakeC language.

Moderator: InsideQC Admins

[Tutorial] Railgun

Postby Dr. Shadowborg » Sat Jul 18, 2015 8:41 pm

Okay, here's how to do a railgun in QuakeC. I'm going to present this with the assumption that you already know how to compile a progs.dat, etc. This is provided in a cut and paste with comments format. Read the comments if you want to know how it works.

Open your weapons.qc file, and add this:
Code: Select all
void(float damage) W_FireRailgun =
{
local entity tempen;
local vector orgen, orgo, dir, dorg;
local float donerail, rlooplimit;

// tempen = temp entity, used for self shuffling.
// orgen = origin end
// orgo = start origin for rail
// dir = aim direction
// dorg = damage origin, used for particles, effects, etc.
// rlooplimit = runaway loop limiter, breakpoint for end of rail

   rlooplimit = 20; // only allow 20 hits

// lets make those v_forward, v_up, and v_right vectors
   makevectors(self.v_angle);

// Railgun is not free of charge.
   self.currentammo = self.ammo_cells = self.ammo_cells - 1;

// Lets make a sound
   sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);

// punch the screen for recoil
   self.punchangle_x = -4;

// Set our rail origin point.
   orgo = self.origin + self.view_ofs + v_up*-6;

// set our aiming direction
   dir = aim(self, 100000); //v_forward;

// start a traceline
   traceline(orgo, orgo+dir*2048, FALSE, self);

// set damage point incase we didn't hit anything
   dorg = trace_endpos - dir*4;

// set up our loop, if we're done (i.e. hit a wall) or
// hit our loop limit, exit
   if(trace_ent.takedamage)
   {
      while(rlooplimit > 0)
      {
// if the trace_ent can take damage...
         if(trace_ent.takedamage && trace_ent != world)
         { 
// set our endpoint 4 units ahead
          orgen = trace_endpos + dir*4;
// set our damage origin 4 units back
          dorg = trace_endpos - dir*4;
// spawn some blood
          SpawnBlood (dorg, '0 0 0', 30);
// do the damage
          T_Damage (trace_ent, self, self, damage);
// play a sound
          sound (trace_ent, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
//   Don't pentetrate buttons or anything SOLID_BSP
          if(trace_ent.solid == SOLID_BSP)
           rlooplimit = 0;
         }
         else
         {
// didn't hit anything?
// set our damage origin back 4 units
          dorg = trace_endpos - dir*4;

// Done tracing the rail shot
          rlooplimit = 0;
         }
// traceline doesn't register hits against self, so we store self in
// tempen, then set the self to trace_ent; We can now fire a new
// trace, then reset self back to the player who fired the rail,
// then we reduce the loop counter
       tempen = self;
       self = trace_ent;
       traceline(orgen, orgen + dir*2048, FALSE, self);
       self = tempen;
       rlooplimit = rlooplimit - 1;
      }
   }

//    spawn an explosion sprite if we have impacted a wall
   if(!(trace_fraction == 1.0))
   {
    newmis = spawn();
    newmis.solid = SOLID_NOT;
    newmis.takedamage = DAMAGE_NO;
    setmodel(newmis, "progs/s_explod.spr");
    setsize(newmis, '0 0 0', '0 0 0');
    setorigin(newmis, dorg);
    newmis.think = BecomeExplosion;
    newmis.nextthink = time;   
   }

// Spawn an entity for the effect
   newmis = spawn();
   newmis.solid = SOLID_NOT;
   setorigin(newmis, orgo);
   newmis.think = SUB_Remove;
   newmis.nextthink = time + 0.1;

// generate an effect from the entity to the endpoint
   WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
   WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
   WriteEntity (MSG_BROADCAST, newmis);
   WriteCoord (MSG_BROADCAST, newmis.origin_x);
   WriteCoord (MSG_BROADCAST, newmis.origin_y);
   WriteCoord (MSG_BROADCAST, newmis.origin_z);
   WriteCoord (MSG_BROADCAST, dorg_x);
   WriteCoord (MSG_BROADCAST, dorg_y);
   WriteCoord (MSG_BROADCAST, dorg_z);
};


Right above this:
Code: Select all
/*
===============================================================================

PLAYER WEAPON USE

===============================================================================
*/


Now, unless you know how to add / replace new weapons, for testing, we will simply replace the lightning gun with the railgun. Go down to W_Attack() and change this:
Code: Select all
   else if (self.weapon == IT_LIGHTNING)
   {
      player_light1();
      self.attack_finished = time + 0.1;
      sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
   }


to this:
Code: Select all
   else if (self.weapon == IT_LIGHTNING)
   {
      player_shot1();
      W_FireRailgun(100); // 100 damage
      self.attack_finished = time + 0.8;
   }


Compile, then run quake. Line up those shots and enjoy! :)
User avatar
Dr. Shadowborg
InsideQC Staff
 
Posts: 1078
Joined: Sat Oct 16, 2004 3:34 pm

Return to QuakeC Programming

Who is online

Users browsing this forum: No registered users and 1 guest