Replacing Grenade Launcher with a Railgun.

darkfader

New member
Nov 15, 2022
19
18
3
Hey Sock, I hope you are well my Friend.

I'm in the preliminary stages of considering replacing the Grenade Launcher with a Railgun, from Q2/Q3.
Currently Q2 RTX provides a great looking model, so I will likely use this one, with some more modifications.


So, I have already replaced the existing Grenade Launcher models (World view: g_rock.mdl, and Player view: v_rock.mdl).
Now is where the hard part enters the scene ... the coding.

defscustom.qc
// Projectile models
string MODEL_PROJ_GRENADE = "progs/proj_grenade.mdl";
string MODEL_PROJ_GRENADEGRN = "progs/proj_grenadegrn.mdl";

I'm hoping to use these to replace with a Railgun slug, and potentially a tracer, but I'm unsure if this will effect other entities, specifically other monsters projectiles?

weapons.qc
/*==================
GRENADES
This looks to be the beef of my changes.
I imagine this is what controls all of the physics behind my "Grenade" turn Railgun slug.
Should I start modifying these numbers, and testing how they react, and again ... this will likely effect another part of the game, like potentially monster_army_grenade.
Unless I just give him a Railgun too, and turn him into monster_army_railgun defective? (hah)

Code:
void() W_FireGrenade =
{
    local vector dir, avel;
   
    // Ran out of ammo, switch to next best weapon
    if (self.attack_finished > time) return;
    if (self.ammo_rockets < 1) { forceweaponswitch(0.2); return;}

    self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
    sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
    self.effects = self.effects | EF_MUZZLEFLASH;
    self.attack_finished = time + 0.6;
    self.punchangle_x = -2;
    player_grenreset();            // reset weaponframe

    makevectors (self.v_angle);
    // Has the player aimed left/right? then no auto aim assist
    if (self.v_angle_x) {
        dir = v_forward*SPEED_PLAYGRENADE + v_up * ELEV_ZAXIS + crandom()*v_right*10 + crandom()*v_up*10;
    }
    else {
        // Check for auto aim state
        if (autoaim_cvar < 1) dir = aim(self, SPEED_PLAYAIM);
        else dir = normalize(v_forward * SPEED_PLAYGRENADE);
        // Work out default speed and elevation
        dir = dir * SPEED_PLAYGRENADE;
        dir_z = ELEV_ZAXIS;
    }
    avel = vecrand(100,200,FALSE);
    Launch_Grenade(self.origin, dir, avel, CT_PROJ_GL);
};

Anyway, I'm just hoping to establish a starting point, and get your opinion.
I know that this is quite a process, and a huge undertaking for myself.

Thanks, my Friend.


UPDATE:
I've found an existing modification integrating Q2 Weapons (Railgun) into Quake 1 I will start sifting through.
 
Last edited:
Awesome! :D I've been waiting for somebody to do something like this! :D I'm excited to see this come out. :)

Will we be able to use this in other mods/maps too? :) If so, that'd be amazing! :D
 
Awesome! :D I've been waiting for somebody to do something like this! :D I'm excited to see this come out. :)

Will we be able to use this in other mods/maps too? :) If so, that'd be amazing! :D
Hey Woof,
Thanks for the enthusiasm.
I appreciate it.

This project will likely take me upwards of 1-2 years to develop, design, and release.
I'm having to learn a lot about the coding, 3d modeling in blender, to create my items before mapping.
And everything I do will be returned for the public (though tread at your own risk on using my finished coding. lol)
 
I think I have figured it out, Sock.
I found the Class types for projectiles, CT_XXX_XXX

I have already modified my weapon, and just trying out all the Class types to see which fits best.


weapons.qc
Code:
/*======================================================================
GRENADES
======================================================================*/
void() W_FireGrenade =
{
    local vector org, dir;
    
    // Ran out of ammo, switch to next best weapon
    if (self.attack_finished > time) return;
    if (self.ammo_rockets < 1) { forceweaponswitch(0.2); return;}

    self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
    sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
    self.effects = self.effects | EF_MUZZLEFLASH;
    self.attack_finished = time + 0.8;
    self.punchangle_x = -2;
    player_grenreset();            // reset weaponframe

    makevectors (self.v_angle);
    org = self.origin + v_forward * 8 + '0 0 16';
    
        // Check for auto aim state
        if (autoaim_cvar < 1) dir = aim(self, SPEED_RLPLAYER2);
        else dir = normalize(v_forward * SPEED_RLPLAYER2);
        // Straight line forward where crosshair is pointing
    
    
    launch_projectile (org, dir, CT_PROJ_RICLASER, SPEED_RLPLAYER2);
};

defscustom.qc
float SPEED_RLPLAYER2 = 2500; // Player speed for Railgun
 
Last edited:
  • Like
Reactions: El_Squish!
I'm in the preliminary stages of considering replacing the Grenade Launcher with a Railgun, from Q2/Q3.

Adding *NEW* weapons (I don't mean replace) to Quake is probably the hardest thing to do and for someone just starting out with QC, you really are trying to climb the tallest mountain first. Its easier to add monsters than do anything to weapons!

1. How does the player select the weapon?
All of the weapon impulse (1-9) keys are already taken, so do you double up the keys like Rogue did with expansion pack 2 and have the player cycle around weapons on a single key? Maybe you could retire some weapons like the NG because once the player has the SNG, the NG is pointless. (Oh the pun) So maybe you could display the SNG on impulse 4 once the player picks it up and that would then free up impulse 5 to use for the Railgun. To change impulse functionality you need to open up weapons.qc and change all these functions "W_Attack", "W_ChangeWeapon", "CycleWeaponCommand", "CycleWeaponReverseCommand", "W_SetCurrentAmmo" and "W_BestWeapon". This is a lot of functions to change and this is not even half of it!

2. How is the weapon stored in the players inventory?
Quake keeps track of player inventory in the "items" variable using bits (0/1) and there are 24 bits per variable. All of the current items are defined in "defs.qc" and the variables start with "IT_". Unfortunately most of the items bits are taken, so most mods create an "items2" variable like Ritual/Rogue expansion packs did. AD does something similar with an extra inventory variable called "moditems" and is defined in "defscustom.qc".

3. What does the weapon look like?
You will need two models, the G_ model is used as the pickup item in the level and the V_ model is the one used on the HUD so that the player can see the weapon being animated. (the V model does have a certain animation layout) Next you will need to add all the model animation code to the "player.qc" file. A railgun is a deadly weapon and you will most likely need a lot of reloading frames to it slow it down and not be instantly firing all the time. Also will have to cope with the player trying to speed up reload times by fast switching weapons.

4. What ammo does the weapon use?
The default Quake HUD shows 4 types of ammo (shell, nail, rocket, cells) and the only way to get around this limitation is either new engine code (like what Ritual/Rogue did) or have custom HUD layouts. Unfortunately not all Quake clients support custom HUDs (Even Kexengine is fixed) so its probably best to stick with the existing ammo types otherwise the player will not see what they have got. A good pick for railguns could be the cell ammo and the default damage for 1 cell is 30. A railgun would probably do about 120-130 dmg each shot, so maybe consider multiple cell consumption to balance it out against other weapons.

5. How does the weapon fire?
Now this is the fun part, the code will require to check for reload lockout timers, ammo quantity, fire the weapon and update all the various inventory variables. All weapon firing functions are in "weapons.qc" and have to be linked to the impulse code as well. There are axe, bullet, spike, grenade, rocket and lightning weapon types already defined. Ideally you would add a new weapon type "rail" and start the function by checking if the weapon is locked (reload times), does the player have the right amount ammo, start the weapon animations and finally fire the weapon and check for things that are hit.

Luckily for you there is a railgun feature/code in AD already for the fire wraiths "mon_wraith.qc" and the function is called "wraith_debuff_trail". The spiral like visuals are created in segments (very much like lightning) and in large maps this is going to be a problem. The segments are 32 units long and a player firing this at 600 map units is 19 entities. The longer distance, the more entities required and that is where slowdowns will start to happen because the client/server code structure will want to update with these new entities. It might be worthwhile having a limit on the railgun range to prevent network traffic issues.

Other things to consider is what happens to anything that the railgun hits? Do they move backward with a recoil effect? Could this weapon be used to knock monsters off ledges? Do the monsters go into a pain animations? Could you stunlock enemies with the railgun? Does the railgun effect go through enemies and strike other targets in a line? Also will need other resources like sounds (firing, reload, impact etc) which I imagine can come from Q2 (so remember to credit for this).

Will we be able to use this in other mods/maps too? :) If so, that'd be amazing! :D
Unfortunately Quake is not plug and play friendly, this weapon would have to be added manually to any other mod.
 
@Fairweather are you familiar with setting up animations for weapons in blender?
I had used your blender tutorials on youtube.

It's just a simple use of bones (or "armatures") to animate set bits of the model. Any Youtube tutorial on the subject should be simple to follow, but I haven't gotten around to doing a fully-fledged tutorial for it yet because I personally find it a bit difficult to explain. Maybe @Kebby could give you some insight :)
 
  • Like
Reactions: darkfader
.... once the player has the SNG, the NG is pointless. (Oh the pun)

That is actually a GREAT point (pun intended)
My projectile is similar to a nail, bouncing off the walls, both Nailguns are redundant.
Maybe I should consider replacing the SNG with my Nine Inch Railgun. One for clipping off hordes of monsters (NG), and one for precision (Nine Inch Nailgun). Unsure if it should be Nine Inch Nailgun or Nine Inch Railgun, plus maybe I could redesign a new NIN Ammo model in ode for the old NIN, Trent.
 
Last edited:
I've somehow lost my Super Nailgun damage associated in defscustom.qc
1668829153086.png


I have the same level of damage for both weapons, NG and SNG.
I use ad_test11 map to test the weapon damage.

Code:
/*======================================================================
W_FireSpikes
======================================================================*/
void(float oz, float ox) W_FireSpikes =
{
    local vector org, dir;
   
    // If run out of ammo, switch weapons to next best
    if (self.ammo_nails < 1) { forceweaponswitch(0.2); return; }

    self.effects = self.effects | EF_MUZZLEFLASH;
    self.attack_finished = time + 0.2;
    self.punchangle_x = -2;
    makevectors (self.v_angle);

    // Check for auto aim state
    // Auto aim assist (builtin function 44)
    if (autoaim_cvar < 1) dir = aim(self, SPEED_PLAYSPIKE);
    // Straight line forward where crosshair is pointing
    else dir = normalize(v_forward * SPEED_PLAYSPIKE);

    // SNG setup, sound and ammo change
    if (self.ammo_nails > 1 && self.weapon == IT_SUPER_NAILGUN) {
        sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
        self.currentammo = self.ammo_nails = self.ammo_nails - 1;
                self.attack_finished = time + 0.8;
                self.punchangle_x = -2;
                player_grenreset();
        //-------------------------------------------------------------
        // Original setup - org = self.origin + '0 0 16';
        // - SNG projectile offset idea by Kinn
        // org = self.origin + dir*14 + v_right*ox;
        // org_z = org_z + oz;
        // The SNG offset idea was hiting far below the crosshair
        // which was causing impact problems.
        // Kept the barrel offset, removed the Z adjustment instead!
        // adjusted for railgun - darkfader
        //-------------------------------------------------------------
        org = self.origin + '0 0 16';
        // Auto aim assist (builtin function 44)
            if (autoaim_cvar < 1) dir = aim(self, SPEED_RLPLAYER2);
            // Straight line forward where crosshair is pointing
            else dir = normalize(v_forward * SPEED_RLPLAYER2);
        launch_projectile (org, dir, CT_PROJ_RICLASER, SPEED_RLPLAYER2);
    }
    // NG setup, sound and ammo change
    else {
        sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
        self.currentammo = self.ammo_nails = self.ammo_nails - 1;
       
        // Original setup - org = self.origin + '0 0 16' + v_right*ox;
        // - NG projectile offset idea by Kinn
        // org = self.origin + '0 0 8' + dir*14 + v_right*ox;
        org = self.origin + '0 0 16' + v_right*ox;
        launch_projectile (org, dir, CT_PROJ_RICLASER, SPEED_PLAYSPIKE);
    }
};

Any idea why?
 

Attachments

  • 1668829106906.png
    1668829106906.png
    2.4 KB · Views: 31
Last edited:
I've somehow lost my Super Nailgun damage associated in defscustom.qc

Install the original code and search for the variable key names and then compare it to what you have changed.
I don't recommend changing nail code for your railgun idea, always create new functions for new stuff!
 
  • Like
Reactions: darkfader
I apologize for the confusion, mostly within myself.
I just found my mistake, I had changed my projectile to CT_PROJ_RICLASER, last night I was trying to find RICLASER unknowing that it was DAMAGE_LASER that controlled my damage.

I had been working on this all day yesterday, and I had been reading so much code, it all didn't make sense anymore ... and I ended up compiling the incorrect code, and never saw my changes reflected. lol

Thanks for the help, Sock.
 
@sock

I have added a custom looped sound for the Railgun, it is a 22,000hz, 16 bit, mono .wav file with loop markers.
I have added it to weapons.qc under the W_SetCurrentAmmo section

Code:
}
    else if (targ.weapon == IT_NAILGUN) {
        targ.currentammo = targ.ammo_nails;
        targ.weaponframe = 0;    // reset before setting model
        targ.weaponmodel = MODEL_VWEAP_NG;
        targ.items = targ.items | IT_NAILS;
    }
    else if (targ.weapon == IT_SUPER_NAILGUN) {
        targ.currentammo = targ.ammo_nails;
        targ.weaponframe = 0;    // reset before setting model
        sound (self, 6, "weapons/railhum.wav", 1, ATTN_NORM);
        targ.weaponmodel = MODEL_VWEAP_SNG;
        targ.items = targ.items | IT_NAILS;
    }
    else if (targ.weapon == IT_GRENADE_LAUNCHER) {
        targ.currentammo = targ.ammo_rockets;
        targ.weaponframe = 0;    // reset before setting model
        targ.weaponmodel = MODEL_VWEAP_GL;
        targ.items = targ.items | IT_ROCKETS;

In game, it starts off, then when i switch to the SNG (Railgun) it just keeps playing no matter which weapon i switch to.
When I switch back to the SNG (Railgun) it will play over the existing loop again.

Do I need to trigger the loop to stop upon switching weapons?

Thanks for the help, my Friend. I appreciate it.
 
Hey @sock
I'm on to porting over some of the Quake 2 enemies over to AD.
This is definitely a pretty big task.
I already have the animated model, just need to use the Quake 2 coding, and import it into your format.

I apologize if i overloaded you with questions.

Anyway, I hope you are good, and Happy Thanksgiving, my friend.