]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into mirceakitsune/universal_reload_system
authorMircea Kitsune <sonichedgehog_hyperblast00@yahoo.com>
Sun, 23 Jan 2011 16:01:49 +0000 (18:01 +0200)
committerMircea Kitsune <sonichedgehog_hyperblast00@yahoo.com>
Sun, 23 Jan 2011 16:01:49 +0000 (18:01 +0200)
18 files changed:
1  2 
qcsrc/server/w_crylink.qc
qcsrc/server/w_electro.qc
qcsrc/server/w_fireball.qc
qcsrc/server/w_grenadelauncher.qc
qcsrc/server/w_hagar.qc
qcsrc/server/w_hlac.qc
qcsrc/server/w_hook.qc
qcsrc/server/w_laser.qc
qcsrc/server/w_minelayer.qc
qcsrc/server/w_minstanex.qc
qcsrc/server/w_nex.qc
qcsrc/server/w_porto.qc
qcsrc/server/w_rocketlauncher.qc
qcsrc/server/w_seeker.qc
qcsrc/server/w_shotgun.qc
qcsrc/server/w_sniperrifle.qc
qcsrc/server/w_tuba.qc
qcsrc/server/w_uzi.qc

index d20811bfad86c8ee9516be0a9be1b53f53293a9d,8a3380eae4356b657f00f04e1a936d2eb67c7107..d45edbbed7bc58bc2962eb0cb9af48b186569936
@@@ -9,61 -9,6 +9,61 @@@ REGISTER_WEAPON(CRYLINK, w_crylink, IT_
  .entity queuenext;
  .entity queueprev;
  
 +// weapon load persistence, for weapons that support reloading
 +.float crylink_load;
 +
 +void W_Crylink_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_crylink_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.crylink_load;
 +              self.clip_size = autocvar_g_balance_crylink_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Crylink_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_crylink_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_cells -= 1;
 +      }
 +      self.crylink_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_crylink_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Crylink_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_crylink_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_crylink_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_crylink_reload_time, W_Crylink_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Crylink_CheckLinks(entity e)
  {
        float i;
@@@ -374,17 -319,8 +374,17 @@@ void W_Crylink_Attack (void
        vector forward, right, up;
        float maxdmg;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_cells = self.ammo_cells - autocvar_g_balance_crylink_primary_ammo;
 +      {
 +              if(autocvar_g_balance_crylink_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_crylink_primary_ammo;
 +                      self.crylink_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= autocvar_g_balance_crylink_primary_ammo;
 +      }
  
        maxdmg = autocvar_g_balance_crylink_primary_damage*autocvar_g_balance_crylink_primary_shots;
        maxdmg *= 1 + autocvar_g_balance_crylink_primary_bouncedamagefactor * autocvar_g_balance_crylink_primary_bounces;
@@@ -486,17 -422,8 +486,17 @@@ void W_Crylink_Attack2 (void
        local entity proj, prevproj, firstproj;
        float maxdmg;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_cells = self.ammo_cells - autocvar_g_balance_crylink_secondary_ammo;
 +      {
 +              if(autocvar_g_balance_crylink_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_crylink_secondary_ammo;
 +                      self.crylink_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= autocvar_g_balance_crylink_secondary_ammo;
 +      }
  
        maxdmg = autocvar_g_balance_crylink_secondary_damage*autocvar_g_balance_crylink_secondary_shots;
        maxdmg *= 1 + autocvar_g_balance_crylink_secondary_bouncedamagefactor * autocvar_g_balance_crylink_secondary_bounces;
@@@ -584,7 -511,6 +584,7 @@@ void spawnfunc_weapon_crylink (void
  
  float w_crylink(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
        {
                if (random() < 0.10)
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_crylink_reload_ammo && self.clip_load < min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo)) // forced reload
 +                      W_Crylink_Reload();
 +              else if (self.BUTTON_ATCK)
                {
                        if (!self.crylink_waitrelease)
                        if (weapon_prepareattack(0, autocvar_g_balance_crylink_primary_refire))
                precache_sound ("weapons/crylink_fire.wav");
                precache_sound ("weapons/crylink_fire2.wav");
                precache_sound ("weapons/crylink_linkjoin.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_CRYLINK);
 +              W_Crylink_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
        {
                // don't "run out of ammo" and switch weapons while waiting for release
                if(self.crylink_lastgroup && self.crylink_waitrelease)
                        return TRUE;
 -              return self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo;
 +
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_crylink_reload_ammo && self.crylink_load >= autocvar_g_balance_crylink_primary_ammo);
 +              return ammo_amount;
        }
        else if (req == WR_CHECKAMMO2)
        {
                // don't "run out of ammo" and switch weapons while waiting for release
                if(self.crylink_lastgroup && self.crylink_waitrelease)
                        return TRUE;
 -              return self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo;
 +
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_crylink_reload_ammo && self.crylink_load >= autocvar_g_balance_crylink_secondary_ammo);
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.crylink_load = autocvar_g_balance_crylink_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Crylink_Reload();
        }
        return TRUE;
  };
@@@ -729,16 -634,16 +729,16 @@@ float w_crylink(float req
        }
        else if (req == WR_SUICIDEMESSAGE)
        {
-               w_deathtypestring = "%s succeeded at self-destructing themself with the Crylink";
+               w_deathtypestring = _("%s succeeded at self-destructing themself with the Crylink");
        }
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_BOUNCE)
-                       w_deathtypestring = "%s could not hide from %s's Crylink"; // unchecked: SPLASH (SECONDARY can't be)
+                       w_deathtypestring = _("%s could not hide from %s's Crylink"); // unchecked: SPLASH (SECONDARY can't be)
                else if(w_deathtype & HITTYPE_SPLASH)
-                       w_deathtypestring = "%s was too close to %s's Crylink"; // unchecked: SECONDARY
+                       w_deathtypestring = _("%s was too close to %s's Crylink"); // unchecked: SECONDARY
                else
-                       w_deathtypestring = "%s took a close look at %s's Crylink"; // unchecked: SECONDARY
+                       w_deathtypestring = _("%s took a close look at %s's Crylink"); // unchecked: SECONDARY
        }
        return TRUE;
  }
index 4ad5157d25520de700fdbdde5b1b93eb17d05d6e,f5491f39aa1054b2c112e70581731437f631d0f0..154e7275c625b1cf1403727fa26bdc1804e07183
@@@ -5,61 -5,6 +5,61 @@@ REGISTER_WEAPON(ELECTRO, w_electro, IT_
  .float electro_count;
  .float electro_secondarytime;
  
 +// weapon load persistence, for weapons that support reloading
 +.float electro_load;
 +
 +void W_Electro_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_electro_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.electro_load;
 +              self.clip_size = autocvar_g_balance_electro_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Electro_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_electro_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_cells -= 1;
 +      }
 +      self.electro_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_electro_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Electro_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_electro_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_electro_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_electro_reload_time, W_Electro_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Plasma_Explode_Combo (void);
  
  void W_Plasma_TriggerCombo(vector org, float rad, entity own)
@@@ -165,18 -110,6 +165,18 @@@ void W_Electro_Attack(
  {
        local entity proj;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_electro_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_electro_primary_ammo;
 +                      self.electro_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= autocvar_g_balance_electro_primary_ammo;
 +      }
 +
        W_SetupShot_ProjectileSize (self, '0 0 -3', '0 0 -3', FALSE, 2, "weapons/electro_fire.wav", CHAN_WEAPON, autocvar_g_balance_electro_primary_damage);
  
        pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
        proj.projectiledeathtype = WEP_ELECTRO;
        setorigin(proj, w_shotorg);
  
 -      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_cells = self.ammo_cells - autocvar_g_balance_electro_primary_ammo;
        proj.movetype = MOVETYPE_FLY;
        W_SETUPPROJECTILEVELOCITY(proj, g_balance_electro_primary);
        proj.angles = vectoangles(proj.velocity);
@@@ -212,18 -147,6 +212,18 @@@ void W_Electro_Attack2(
  {
        local entity proj;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_electro_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_electro_secondary_ammo;
 +                      self.electro_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= autocvar_g_balance_electro_secondary_ammo;
 +      }
 +
        W_SetupShot_ProjectileSize (self, '0 0 -4', '0 0 -4', FALSE, 2, "weapons/electro_fire2.wav", CHAN_WEAPON, autocvar_g_balance_electro_secondary_damage);
  
        w_shotdir = v_forward; // no TrueAim for grenades please
        proj.projectiledeathtype = WEP_ELECTRO | HITTYPE_SECONDARY;
        setorigin(proj, w_shotorg);
  
 -      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_cells = self.ammo_cells - autocvar_g_balance_electro_secondary_ammo;
        //proj.glow_size = 50;
        //proj.glow_color = 45;
        proj.movetype = MOVETYPE_BOUNCE;
        CSQCProjectile(proj, TRUE, PROJECTILE_ELECTRO, FALSE); // no culling, it has sound
  
        other = proj; MUTATOR_CALLHOOK(EditProjectile);
 -      }
 +}
  
  .vector hook_start, hook_end;
  float lgbeam_send(entity to, float sf)
  }
  .entity lgbeam;
  .float prevlgfire;
 +float lgbeam_checkammo()
 +{
 +      if(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)
 +              return TRUE;
 +      else if(autocvar_g_balance_electro_reload_ammo)
 +              return self.owner.clip_load > 0;
 +      else
 +              return self.owner.ammo_cells > 0;
 +}
 +
  void lgbeam_think()
  {
        self.owner.prevlgfire = time;
                remove(self);
                return;
        }
 -      if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK || self.owner.freezetag_frozen)
 +
 +      if (self.owner.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK || self.owner.freezetag_frozen)
        {
                if(self == self.owner.lgbeam)
                        self.owner.lgbeam = world;
  
        float dt, f;
        dt = frametime;
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)
        {
                if(autocvar_g_balance_electro_primary_ammo)
                {
 -                      dt = min(dt, self.owner.ammo_cells / autocvar_g_balance_electro_primary_ammo);
 -                      self.owner.ammo_cells = max(0, self.owner.ammo_cells - autocvar_g_balance_electro_primary_ammo * frametime);
 +                      if(autocvar_g_balance_electro_reload_ammo)
 +                      {
 +                              dt = min(dt, self.owner.clip_load / autocvar_g_balance_electro_primary_ammo);
 +                              self.owner.clip_load = max(0, self.owner.clip_load - autocvar_g_balance_electro_primary_ammo * frametime);
 +                              self.owner.electro_load = self.owner.clip_load;
 +                      }
 +                      else
 +                      {
 +                              dt = min(dt, self.owner.ammo_cells / autocvar_g_balance_electro_primary_ammo);
 +                              self.owner.ammo_cells = max(0, self.owner.ammo_cells - autocvar_g_balance_electro_primary_ammo * frametime);
 +                      }
                }
        }
  
@@@ -440,7 -344,6 +440,7 @@@ void w_electro_checkattack(
  .float BUTTON_ATCK_prev;
  float w_electro(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
        {
                self.BUTTON_ATCK=FALSE;
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_electro_reload_ammo && self.clip_load < min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo)) // forced reload
 +                      W_Electro_Reload();
 +              else if (self.BUTTON_ATCK)
                {
                        if(autocvar_g_balance_electro_lightning)
                                if(self.BUTTON_ATCK_prev)
                                }
                                self.BUTTON_ATCK_prev = 0;
                        }
 -              }
  
 -              if (self.BUTTON_ATCK2)
 -              if (time >= self.electro_secondarytime)
 -              if (weapon_prepareattack(1, autocvar_g_balance_electro_secondary_refire))
 -              {
 -                      W_Electro_Attack2();
 -                      self.electro_count = autocvar_g_balance_electro_secondary_count;
 -                      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_electro_secondary_animtime, w_electro_checkattack);
 -                      self.electro_secondarytime = time + autocvar_g_balance_electro_secondary_refire2 * W_WeaponRateFactor();
 +                      if (self.BUTTON_ATCK2)
 +                      {
 +                              if (time >= self.electro_secondarytime)
 +                              if (weapon_prepareattack(1, autocvar_g_balance_electro_secondary_refire))
 +                              {
 +                                      W_Electro_Attack2();
 +                                      self.electro_count = autocvar_g_balance_electro_secondary_count;
 +                                      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_electro_secondary_animtime, w_electro_checkattack);
 +                                      self.electro_secondarytime = time + autocvar_g_balance_electro_secondary_refire2 * W_WeaponRateFactor();
 +                              }
 +                      }
                }
        }
        else if (req == WR_PRECACHE)
                precache_sound ("weapons/electro_fire2.wav");
                precache_sound ("weapons/electro_impact.wav");
                precache_sound ("weapons/electro_impact_combo.wav");
 +              precache_sound ("weapons/reload.wav");
                if(autocvar_g_balance_electro_lightning)
                {
                        precache_sound ("weapons/lgbeam_fire.wav");
                }
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_ELECTRO);
 +              W_Electro_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
        {
                if(autocvar_g_balance_electro_lightning)
 -                      return !autocvar_g_balance_electro_primary_ammo || (self.ammo_cells > 0);
 +                      ammo_amount = !autocvar_g_balance_electro_primary_ammo || (self.ammo_cells > 0);
                else
 -                      return self.ammo_cells >= autocvar_g_balance_electro_primary_ammo;
 +                      ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_primary_ammo;
 +              if(autocvar_g_balance_electro_reload_ammo)
 +              {
 +                      if(autocvar_g_balance_electro_lightning)
 +                              ammo_amount += !autocvar_g_balance_electro_primary_ammo || (self.electro_load > 0);
 +                      else
 +                              ammo_amount += self.electro_load >= autocvar_g_balance_electro_primary_ammo;
 +              }
 +              return ammo_amount;
        }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_cells >= autocvar_g_balance_electro_secondary_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_electro_reload_ammo && self.electro_load >= autocvar_g_balance_electro_secondary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_RESETPLAYER)
        {
                self.electro_secondarytime = time;
 +
 +              // all weapons must be fully loaded when we spawn
 +              self.electro_load = autocvar_g_balance_electro_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Shotgun_Reload();
        }
        return TRUE;
  };
@@@ -624,27 -500,27 +624,27 @@@ float w_electro(float req
        else if (req == WR_SUICIDEMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s could not remember where they put plasma";
+                       w_deathtypestring = _("%s could not remember where they put plasma");
                else
-                       w_deathtypestring = "%s played with plasma";
+                       w_deathtypestring = _("%s played with plasma");
        }
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
                {
                        if(w_deathtype & HITTYPE_SPLASH) // unchecked: BOUNCE
-                               w_deathtypestring = "%s just noticed %s's blue ball";
+                               w_deathtypestring = _("%s just noticed %s's blue ball");
                        else // unchecked: BOUNCE
-                               w_deathtypestring = "%s got in touch with %s's blue ball";
+                               w_deathtypestring = _("%s got in touch with %s's blue ball");
                }
                else
                {
                        if(w_deathtype & HITTYPE_BOUNCE) // combo
-                               w_deathtypestring = "%s felt the electrifying air of %s's combo";
+                               w_deathtypestring = _("%s felt the electrifying air of %s's combo");
                        else if(w_deathtype & HITTYPE_SPLASH)
-                               w_deathtypestring = "%s got too close to %s's blue beam";
+                               w_deathtypestring = _("%s got too close to %s's blue beam");
                        else
-                               w_deathtypestring = "%s was blasted by %s's blue beam";
+                               w_deathtypestring = _("%s was blasted by %s's blue beam");
                }
        }
        return TRUE;
index dd1793906303d5868713a030d39ebfdc89d1dc65,73ff1595a79752e395cbd8b3e9c8737b3d58fea0..686a727cf7e97512087c21cc640e7edb10ea2dae
@@@ -6,65 -6,6 +6,65 @@@ REGISTER_WEAPON(FIREBALL, w_fireball, I
  .vector fireball_impactvec;
  .float fireball_primarytime;
  
 +// weapon load persistence, for weapons that support reloading
 +.float fireball_load;
 +
 +void W_Fireball_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_fireball_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.fireball_load;
 +              self.clip_size = autocvar_g_balance_fireball_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Fireball_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_fireball_reload_ammo && self.ammo_fuel) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_fuel -= 1;
 +
 +              // fuel can be a non-whole number, which brakes stuff here when between 0 and 1
 +              if(self.ammo_fuel < 1)
 +                      self.ammo_fuel = 0;
 +      }
 +      self.fireball_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_fireball_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Fireball_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_fireball_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_fuel, min(autocvar_g_balance_fireball_primary_ammo, autocvar_g_balance_fireball_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_fireball_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_fireball_reload_time, W_Fireball_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Fireball_Explode (void)
  {
        entity e;
@@@ -253,17 -194,8 +253,17 @@@ void W_Fireball_Attack1_Frame1(
  
  void W_Fireball_Attack1_Frame0()
  {
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_fuel = self.ammo_fuel - autocvar_g_balance_fireball_primary_ammo;
 +      {
 +              if(autocvar_g_balance_fireball_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_fireball_primary_ammo;
 +                      self.fireball_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_fuel -= autocvar_g_balance_fireball_primary_ammo;
 +      }
  
        W_Fireball_AttackEffect(0, '-1.25 -3.75 0');
        sound (self, CHAN_WEAPON, "weapons/fireball_prefire2.wav", VOL_BASE, ATTN_NORM);
@@@ -314,17 -246,8 +314,17 @@@ void W_Fireball_Attack2(
        vector f_diff;
        float c;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_fuel = self.ammo_fuel - autocvar_g_balance_fireball_secondary_ammo;
 +      {
 +              if(autocvar_g_balance_fireball_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_fireball_secondary_ammo;
 +                      self.fireball_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_fuel -= autocvar_g_balance_fireball_secondary_ammo;
 +      }
  
        c = mod(self.bulletcounter, 4);
        switch(c)
@@@ -381,7 -304,6 +381,7 @@@ void spawnfunc_weapon_fireball (void
  
  float w_fireball(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
        {
                self.BUTTON_ATCK = FALSE;
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 -              if (time >= self.fireball_primarytime)
 -              if (weapon_prepareattack(0, autocvar_g_balance_fireball_primary_refire))
 +              if(autocvar_g_balance_fireball_reload_ammo && self.clip_load < min(autocvar_g_balance_fireball_primary_ammo, autocvar_g_balance_fireball_secondary_ammo)) // forced reload
 +                      W_Fireball_Reload();
 +              else if (self.BUTTON_ATCK)
                {
 -                      W_Fireball_Attack1_Frame0();
 -                      self.fireball_primarytime = time + autocvar_g_balance_fireball_primary_refire2;
 +                      if (time >= self.fireball_primarytime)
 +                      if (weapon_prepareattack(0, autocvar_g_balance_fireball_primary_refire))
 +                      {
 +                              W_Fireball_Attack1_Frame0();
 +                              self.fireball_primarytime = time + autocvar_g_balance_fireball_primary_refire2;
 +                      }
                }
 -              if (self.BUTTON_ATCK2)
 -              if (weapon_prepareattack(1, autocvar_g_balance_fireball_secondary_refire))
 +              else if (self.BUTTON_ATCK2)
                {
 -                      W_Fireball_Attack2();
 -                      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_fireball_secondary_animtime, w_ready);
 +                      if (weapon_prepareattack(1, autocvar_g_balance_fireball_secondary_refire))
 +                      {
 +                              W_Fireball_Attack2();
 +                              weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_fireball_secondary_animtime, w_ready);
 +                      }
                }
        }
        else if (req == WR_PRECACHE)
                precache_sound ("weapons/fireball_fire.wav");
                precache_sound ("weapons/fireball_fire2.wav");
                precache_sound ("weapons/fireball_prefire2.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_FIREBALL);
 +              W_Fireball_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_fuel >= autocvar_g_balance_fireball_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_fuel >= autocvar_g_balance_fireball_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_fireball_reload_ammo && self.fireball_load >= autocvar_g_balance_fireball_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_fuel >= autocvar_g_balance_fireball_secondary_ammo;
 +      {
 +              ammo_amount = self.ammo_fuel >= autocvar_g_balance_fireball_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_fireball_reload_ammo && self.fireball_load >= autocvar_g_balance_fireball_secondary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_RESETPLAYER)
        {
                self.fireball_primarytime = time;
 +
 +              // all weapons must be fully loaded when we spawn
 +              self.fireball_load = autocvar_g_balance_fireball_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Fireball_Reload();
        }
        return TRUE;
  };
@@@ -492,32 -389,32 +492,32 @@@ float w_fireball(float req
        else if (req == WR_SUICIDEMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s forgot about some firemine";
+                       w_deathtypestring = _("%s forgot about some firemine");
                else
-                       w_deathtypestring = "%s should have used a smaller gun";
+                       w_deathtypestring = _("%s should have used a smaller gun");
        }
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
                {
                        if(w_deathtype & HITTYPE_HEADSHOT)
-                               w_deathtypestring = "%s tried to catch %s's firemine";
+                               w_deathtypestring = _("%s tried to catch %s's firemine");
                        else
-                               w_deathtypestring = "%s fatefully ignored %s's firemine";
+                               w_deathtypestring = _("%s fatefully ignored %s's firemine");
                }
                else
                {
                        if(w_deathtype & HITTYPE_BOUNCE)
                        {
                                if(w_deathtype & HITTYPE_SPLASH) // BFG effect
-                                       w_deathtypestring = "%s could not hide from %s's fireball";
+                                       w_deathtypestring = _("%s could not hide from %s's fireball");
                                else // laser
-                                       w_deathtypestring = "%s saw the pretty lights of %s's fireball";
+                                       w_deathtypestring = _("%s saw the pretty lights of %s's fireball");
                        }
                        else if(w_deathtype & HITTYPE_SPLASH)
-                               w_deathtypestring = "%s got too close to %s's fireball";
+                               w_deathtypestring = _("%s got too close to %s's fireball");
                        else
-                               w_deathtypestring = "%s tasted %s's fireball";
+                               w_deathtypestring = _("%s tasted %s's fireball");
                }
        }
        return TRUE;
index 970cfa72d1922443723eb1d7a55d5dda46e68b43,d5f6c5d6827f13f213330b5012a74bdbf2fd9344..1d039d5f9d8fea63dce2c83c39c7eb4810364eaa
@@@ -5,61 -5,6 +5,61 @@@ REGISTER_WEAPON(GRENADE_LAUNCHER, w_gla
  .float gl_detonate_later;
  .float gl_bouncecnt;
  
 +// weapon load persistence, for weapons that support reloading
 +.float grenadelauncher_load;
 +
 +void W_GrenadeLauncher_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_grenadelauncher_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.grenadelauncher_load;
 +              self.clip_size = autocvar_g_balance_grenadelauncher_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_GrenadeLauncher_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_grenadelauncher_reload_ammo && self.ammo_rockets) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_rockets -= 1;
 +      }
 +      self.grenadelauncher_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_grenadelauncher_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_GrenadeLauncher_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_grenadelauncher_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_rockets, min(autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_grenadelauncher_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_grenadelauncher_reload_time, W_GrenadeLauncher_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Grenade_Explode (void)
  {
        if(other.takedamage == DAMAGE_AIM)
@@@ -216,18 -161,8 +216,18 @@@ void W_Grenade_Attack (void
  {
        local entity gren;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_grenadelauncher_primary_ammo;
 +      {
 +              if(autocvar_g_balance_grenadelauncher_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_grenadelauncher_primary_ammo;
 +                      self.grenadelauncher_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_grenadelauncher_primary_ammo;
 +      }
 +
        W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CHAN_WEAPON, autocvar_g_balance_grenadelauncher_primary_damage);
        w_shotdir = v_forward; // no TrueAim for grenades please
  
@@@ -273,18 -208,8 +273,18 @@@ void W_Grenade_Attack2 (void
  {
        local entity gren;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_grenadelauncher_secondary_ammo;
 +      {
 +              if(autocvar_g_balance_grenadelauncher_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_grenadelauncher_secondary_ammo;
 +                      self.grenadelauncher_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_grenadelauncher_secondary_ammo;
 +      }
 +
        W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CHAN_WEAPON, autocvar_g_balance_grenadelauncher_secondary_damage);
        w_shotdir = v_forward; // no TrueAim for grenades please
  
@@@ -335,7 -260,6 +335,7 @@@ float w_glauncher(float req
  {
        entity nade;
        float nadefound;
 +      float ammo_amount;
  
        if (req == WR_AIM)
        {
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 -              if (weapon_prepareattack(0, autocvar_g_balance_grenadelauncher_primary_refire))
 +              if(autocvar_g_balance_grenadelauncher_reload_ammo && self.clip_load < min(autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_secondary_ammo)) // forced reload
 +                      W_GrenadeLauncher_Reload();
 +              else if (self.BUTTON_ATCK)
                {
 -                      W_Grenade_Attack();
 -                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_grenadelauncher_primary_animtime, w_ready);
 +                      if (weapon_prepareattack(0, autocvar_g_balance_grenadelauncher_primary_refire))
 +                      {
 +                              W_Grenade_Attack();
 +                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_grenadelauncher_primary_animtime, w_ready);
 +                      }
                }
 -              if (self.BUTTON_ATCK2)
 +              else if (self.BUTTON_ATCK2)
                {
                        if (cvar("g_balance_grenadelauncher_secondary_remote_detonateprimary"))
                        {
                precache_sound ("weapons/grenade_bounce6.wav");
                precache_sound ("weapons/grenade_stick.wav");
                precache_sound ("weapons/grenade_fire.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_GRENADE_LAUNCHER);
 +              W_GrenadeLauncher_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_rockets >= autocvar_g_balance_grenadelauncher_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_rockets >= autocvar_g_balance_grenadelauncher_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_grenadelauncher_reload_ammo && self.grenadelauncher_load >= autocvar_g_balance_grenadelauncher_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_rockets >= autocvar_g_balance_grenadelauncher_secondary_ammo;
 +      {
 +              ammo_amount = self.ammo_rockets >= autocvar_g_balance_grenadelauncher_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_grenadelauncher_reload_ammo && self.grenadelauncher_load >= autocvar_g_balance_grenadelauncher_secondary_ammo);
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.grenadelauncher_load = autocvar_g_balance_grenadelauncher_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_GrenadeLauncher_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -455,19 -354,19 +455,19 @@@ float w_glauncher(float req
        else if (req == WR_SUICIDEMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s tried out his own grenade";
+                       w_deathtypestring = _("%s tried out his own grenade");
                else
-                       w_deathtypestring = "%s detonated";
+                       w_deathtypestring = _("%s detonated");
        }
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SPLASH)
                        if(w_deathtype & HITTYPE_BOUNCE) // (must be secondary then)
-                               w_deathtypestring = "%s didn't see %s's grenade";
+                               w_deathtypestring = _("%s didn't see %s's grenade");
                        else // unchecked: SECONDARY
-                               w_deathtypestring = "%s almost dodged %s's grenade";
+                               w_deathtypestring = _("%s almost dodged %s's grenade");
                else // unchecked: SECONDARY, BOUNCE
-                       w_deathtypestring = "%s ate %s's grenade";
+                       w_deathtypestring = _("%s ate %s's grenade");
        }
        return TRUE;
  }
diff --combined qcsrc/server/w_hagar.qc
index e982c3a213718828b3986f302074a12ff4c2d0b8,5fb25642e2fa41383515d11085393ac64c74707f..7ad6ee210206d80ecbcde1664b06800fd84368bf
@@@ -3,62 -3,6 +3,62 @@@ REGISTER_WEAPON(HAGAR, w_hagar, IT_ROCK
  #else
  #ifdef SVQC
  // NO bounce protection, as bounces are limited!
 +
 +// weapon load persistence, for weapons that support reloading
 +.float hagar_load;
 +
 +void W_Hagar_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_hagar_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.hagar_load;
 +              self.clip_size = autocvar_g_balance_hagar_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Hagar_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_hagar_reload_ammo && self.ammo_rockets) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_rockets -= 1;
 +      }
 +      self.hagar_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_hagar_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Hagar_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_hagar_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_rockets, min(autocvar_g_balance_hagar_primary_ammo, autocvar_g_balance_hagar_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_hagar_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_hagar_reload_time, W_Hagar_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Hagar_Explode (void)
  {
        self.event_damage = SUB_Null;
@@@ -100,18 -44,8 +100,18 @@@ void W_Hagar_Attack (void
  {
        local entity missile;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_hagar_primary_ammo;
 +      {
 +              if(autocvar_g_balance_hagar_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_hagar_primary_ammo;
 +                      self.hagar_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_hagar_primary_ammo;
 +      }
 +
        W_SetupShot (self, FALSE, 2, "weapons/hagar_fire.wav", CHAN_WEAPON, autocvar_g_balance_hagar_primary_damage);
  
        pointparticles(particleeffectnum("hagar_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
@@@ -145,18 -79,8 +145,18 @@@ void W_Hagar_Attack2 (void
  {
        local entity missile;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_hagar_secondary_ammo;
 +      {
 +              if(autocvar_g_balance_hagar_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_hagar_secondary_ammo;
 +                      self.hagar_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_hagar_secondary_ammo;
 +      }
 +
        W_SetupShot (self, FALSE, 2, "weapons/hagar_fire.wav", CHAN_WEAPON, autocvar_g_balance_hagar_secondary_damage);
  
        pointparticles(particleeffectnum("hagar_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
@@@ -194,7 -118,6 +194,7 @@@ void spawnfunc_weapon_hagar (void
  
  float w_hagar(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
                if (random()>0.15)
                        self.BUTTON_ATCK = bot_aim(autocvar_g_balance_hagar_primary_speed, 0, autocvar_g_balance_hagar_primary_lifetime, FALSE);
                }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 -              if (weapon_prepareattack(0, autocvar_g_balance_hagar_primary_refire))
 +              if(autocvar_g_balance_hagar_reload_ammo && self.clip_load < min(autocvar_g_balance_hagar_primary_ammo, autocvar_g_balance_hagar_secondary_ammo)) // forced reload
 +                      W_Hagar_Reload();
 +              else if (self.BUTTON_ATCK)
                {
 -                      W_Hagar_Attack();
 -                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hagar_primary_refire, w_ready);
 +                      if (weapon_prepareattack(0, autocvar_g_balance_hagar_primary_refire))
 +                      {
 +                              W_Hagar_Attack();
 +                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hagar_primary_refire, w_ready);
 +                      }
                }
 -              if (self.BUTTON_ATCK2 && autocvar_g_balance_hagar_secondary)
 -              if (weapon_prepareattack(1, autocvar_g_balance_hagar_secondary_refire))
 +              else if (self.BUTTON_ATCK2 && autocvar_g_balance_hagar_secondary)
                {
 -                      W_Hagar_Attack2();
 -                      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hagar_secondary_refire, w_ready);
 +                      if (weapon_prepareattack(1, autocvar_g_balance_hagar_secondary_refire))
 +                      {
 +                              W_Hagar_Attack2();
 +                              weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hagar_secondary_refire, w_ready);
 +                      }
                }
        }
        else if (req == WR_PRECACHE)
                precache_model ("models/weapons/v_hagar.md3");
                precache_model ("models/weapons/h_hagar.iqm");
                precache_sound ("weapons/hagar_fire.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_HAGAR);
 +              W_Hagar_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_rockets >= autocvar_g_balance_hagar_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_rockets >= autocvar_g_balance_hagar_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_hagar_reload_ammo && self.hagar_load >= autocvar_g_balance_hagar_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_rockets >= autocvar_g_balance_hagar_secondary_ammo;
 +      {
 +              ammo_amount = self.ammo_rockets >= autocvar_g_balance_hagar_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_hagar_reload_ammo && self.hagar_load >= autocvar_g_balance_hagar_secondary_ammo);
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.hagar_load = autocvar_g_balance_hagar_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Hagar_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -286,13 -182,13 +286,13 @@@ float w_hagar(float req
                precache_sound("weapons/hagexp3.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s played with tiny rockets";
+               w_deathtypestring = _("%s played with tiny rockets");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_BOUNCE) // must be secondary; unchecked: SPLASH
-                       w_deathtypestring = "%s hoped %s's missiles wouldn't bounce";
+                       w_deathtypestring = _("%s hoped %s's missiles wouldn't bounce");
                else // unchecked: SPLASH, SECONDARY
-                       w_deathtypestring = "%s was pummeled by %s";
+                       w_deathtypestring = _("%s was pummeled by %s");
        }
        return TRUE;
  }
diff --combined qcsrc/server/w_hlac.qc
index 10ae59c0367d410762a16cd999d85224000c0382,4bba3b8051b8d4d504caf0047c9b3d1579e53062..2344f66bf8173ed3bf57b52705ba9a774609ff0d
@@@ -3,61 -3,6 +3,61 @@@ REGISTER_WEAPON(HLAC, w_hlac, IT_CELLS
  #else
  #ifdef SVQC
  
 +// weapon load persistence, for weapons that support reloading
 +.float hlac_load;
 +
 +void W_HLAC_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_hlac_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.hlac_load;
 +              self.clip_size = autocvar_g_balance_hlac_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_HLAC_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_hlac_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_cells -= 1;
 +      }
 +      self.hlac_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_hlac_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_HLAC_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_hlac_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_hlac_primary_ammo, autocvar_g_balance_hlac_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_hlac_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_hlac_reload_time, W_HLAC_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_HLAC_Touch (void)
  {
        PROJECTILE_TOUCH;
@@@ -77,17 -22,10 +77,17 @@@ void W_HLAC_Attack (void
        local entity missile;
      float spread;
  
 -    if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -    {
 -        self.ammo_cells = self.ammo_cells - autocvar_g_balance_hlac_primary_ammo;
 -    }
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_hlac_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_hlac_primary_ammo;
 +                      self.hlac_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= autocvar_g_balance_hlac_primary_ammo;
 +      }
  
      spread = autocvar_g_balance_hlac_primary_spread_min + (autocvar_g_balance_hlac_primary_spread_add * self.misc_bulletcounter);
      spread = min(spread,autocvar_g_balance_hlac_primary_spread_max);
@@@ -178,17 -116,10 +178,17 @@@ void W_HLAC_Attack2 (void
  {
      float i;
  
 -    if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -    {
 -        self.ammo_cells = self.ammo_cells - autocvar_g_balance_hlac_secondary_ammo;
 -    }
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_hlac_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_hlac_secondary_ammo;
 +                      self.hlac_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= autocvar_g_balance_hlac_secondary_ammo;
 +      }
  
      for(i=autocvar_g_balance_hlac_secondary_shots;i>0;--i)
          W_HLAC_Attack2f();
@@@ -236,31 -167,25 +236,31 @@@ void spawnfunc_weapon_hlac (void
  
  float w_hlac(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
          self.BUTTON_ATCK = bot_aim(autocvar_g_balance_hlac_primary_speed, 0, autocvar_g_balance_hlac_primary_lifetime, FALSE);
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 -              if (weapon_prepareattack(0, autocvar_g_balance_hlac_primary_refire))
 +              if(autocvar_g_balance_hlac_reload_ammo && self.clip_load < min(autocvar_g_balance_hlac_primary_ammo, autocvar_g_balance_hlac_secondary_ammo)) // forced reload
 +                      W_HLAC_Reload();
 +              else if (self.BUTTON_ATCK)
                {
 -                      self.misc_bulletcounter = 0;
 -                      W_HLAC_Attack();
 -                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hlac_primary_refire, HLAC_fire1_02);
 +                      if (weapon_prepareattack(0, autocvar_g_balance_hlac_primary_refire))
 +                      {
 +                              self.misc_bulletcounter = 0;
 +                              W_HLAC_Attack();
 +                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hlac_primary_refire, HLAC_fire1_02);
 +                      }
                }
  
 -              if (self.BUTTON_ATCK2 && autocvar_g_balance_hlac_secondary)
 -              if (weapon_prepareattack(1, autocvar_g_balance_hlac_secondary_refire))
 +              else if (self.BUTTON_ATCK2 && autocvar_g_balance_hlac_secondary)
                {
 -                      W_HLAC_Attack2();
 -                      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hlac_secondary_animtime, w_ready);
 +                      if (weapon_prepareattack(1, autocvar_g_balance_hlac_secondary_refire))
 +                      {
 +                              W_HLAC_Attack2();
 +                              weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hlac_secondary_animtime, w_ready);
 +                      }
                }
 -
        }
        else if (req == WR_PRECACHE)
        {
                precache_model ("models/weapons/v_hlac.md3");
                precache_model ("models/weapons/h_hlac.iqm");
                precache_sound ("weapons/lasergun_fire.wav");
 +              precache_sound ("weapons/reload.wav");
  
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_HLAC);
 +              W_HLAC_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_cells >= autocvar_g_balance_hlac_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_hlac_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_hlac_reload_ammo && self.hlac_load >= autocvar_g_balance_hlac_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_cells >= autocvar_g_balance_hlac_secondary_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_hlac_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_hlac_reload_ammo && self.hlac_load >= autocvar_g_balance_hlac_secondary_ammo);
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.hlac_load = autocvar_g_balance_hlac_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_HLAC_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -316,9 -220,9 +316,9 @@@ float w_hlac(float req
                precache_sound("weapons/laserimpact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s should have used a smaller gun";
+               w_deathtypestring = _("%s should have used a smaller gun");
        else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = "%s was cut down by %s";
+               w_deathtypestring = _("%s was cut down by %s");
        return TRUE;
  }
  #endif
diff --combined qcsrc/server/w_hook.qc
index 9c8c63c11689e5e9f08081b12d1886cf6d326e1f,da5e3f9423d086f6bdb236a2f744ed091fa4649d..8c4cfc897a3e681ef4121f6493013837a2eedbc1
@@@ -13,12 -13,6 +13,12 @@@ REGISTER_WEAPON(HOOK, w_hook, IT_CELLS|
  .float hook_time_hooked;
  .float hook_time_fueldecrease;
  
 +void W_Hook_SetAmmoCounter()
 +{
 +      // this weapon doesn't have a reload system, so always set the clip to 0 when switching to it
 +      self.clip_load = self.clip_size = 0; // also keeps crosshair ammo from displaying
 +}
 +
  void W_Hook_ExplodeThink (void)
  {
        float dt, dmg_remaining_next, f;
@@@ -234,7 -228,6 +234,7 @@@ float w_hook(float req
        else if (req == WR_SETUP)
        {
                weapon_setup(WEP_HOOK);
 +              W_Hook_SetAmmoCounter();
                self.hook_state &~= HOOK_WAITING_FOR_RELEASE;
        }
        else if (req == WR_CHECKAMMO1)
@@@ -271,9 -264,9 +271,9 @@@ float w_hook(float req
                precache_sound("weapons/hookbomb_impact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s did the impossible";
+               w_deathtypestring = _("%s did the impossible");
        else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = "%s has run into %s's gravity bomb";
+               w_deathtypestring = _("%s has run into %s's gravity bomb");
        return TRUE;
  }
  #endif
diff --combined qcsrc/server/w_laser.qc
index 25e272c766a0615af86affb7ea73733130b18dcc,4ce1331931628366bfaf35037c429edfbbe7f3b4..6164f543d863fe2a1e5b64c6082ad8eab9141a5d
@@@ -4,54 -4,6 +4,54 @@@ REGISTER_WEAPON(LASER, w_laser, 0, 1, W
  #ifdef SVQC
  void(float imp) W_SwitchWeapon;
  
 +// weapon load persistence, for weapons that support reloading
 +.float laser_load;
 +
 +void W_Laser_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_laser_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.laser_load;
 +              self.clip_size = autocvar_g_balance_laser_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Laser_ReloadedAndReady()
 +{
 +      float t;
 +
 +      self.clip_load = autocvar_g_balance_laser_reload_ammo; // maximum load since this weapon uses no ammo
 +      self.laser_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_laser_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Laser_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_laser_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(1, 0))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_laser_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_laser_reload_time, W_Laser_ReloadedAndReady);
 +
 +      self.clip_load = -1;
 +}
 +
  void W_Laser_Touch (void)
  {
        PROJECTILE_TOUCH;
@@@ -274,40 -226,16 +274,40 @@@ float w_laser(float req
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 -              if (weapon_prepareattack(0, autocvar_g_balance_laser_primary_refire))
 +              if(autocvar_g_balance_laser_reload_ammo && self.clip_load < 1) // forced reload
 +                      W_Laser_Reload();
 +              else if (self.BUTTON_ATCK)
                {
 -                      W_Laser_Attack(0);
 -                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_laser_primary_animtime, w_ready);
 +                      if (weapon_prepareattack(0, autocvar_g_balance_laser_primary_refire))
 +                      {
 +                              // if this weapon is reloadable, decrease its load
 +                              if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +                              {
 +                                      if(autocvar_g_balance_laser_reload_ammo)
 +                                      {
 +                                              self.clip_load -= 1;
 +                                              self.laser_load = self.clip_load;
 +                                      }
 +                              }
 +
 +                              W_Laser_Attack(0);
 +                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_laser_primary_animtime, w_ready);
 +                      }
                }
 -              if (self.BUTTON_ATCK2)
 +              else if (self.BUTTON_ATCK2)
                {
                        if(autocvar_g_balance_laser_secondary)
                        {
 +                              // if this weapon is reloadable, decrease its load
 +                              if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +                              {
 +                                      if(autocvar_g_balance_laser_reload_ammo)
 +                                      {
 +                                              self.clip_load -= 1;
 +                                              self.laser_load = self.clip_load;
 +                                      }
 +                              }
 +
                                if (weapon_prepareattack(0, 0))
                                {
                                        W_Laser_Attack2();
                precache_model ("models/weapons/h_laser.iqm");
                precache_sound ("weapons/lasergun_fire.wav");
                precache_sound ("weapons/gauntlet_fire.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_LASER);
 +              W_Laser_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 +      {
                return TRUE;
 +      }
        else if (req == WR_CHECKAMMO2)
 +      {
                return TRUE;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.laser_load = autocvar_g_balance_laser_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Laser_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -371,13 -282,13 +371,13 @@@ float w_laser(float req
                precache_sound("weapons/laserimpact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s lasered themself to hell";
+               w_deathtypestring = _("%s lasered themself to hell");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s was cut in half by %s's gauntlet"; // unchecked: SPLASH
+                       w_deathtypestring = _("%s was cut in half by %s's gauntlet"); // unchecked: SPLASH
                else
-                       w_deathtypestring = "%s was lasered to death by %s"; // unchecked: SPLASH
+                       w_deathtypestring = _("%s was lasered to death by %s"); // unchecked: SPLASH
        }
        return TRUE;
  }
index d2d182223c1f1390c9ad74ff042a1db5d219f1d5,07589cf0d4a14d99e3bf264d5aeef8a384bbb751..00a836eb8e556e2eb72a72c9ee967be849fabf24
@@@ -6,61 -6,6 +6,61 @@@ void W_Mine_Think (void)
  .float minelayer_detonate, minelayer_mines;
  .float mine_time;
  
 +// weapon load persistence, for weapons that support reloading
 +.float minelayer_load;
 +
 +void W_MineLayer_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_minelayer_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.minelayer_load;
 +              self.clip_size = autocvar_g_balance_minelayer_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_MineLayer_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_minelayer_reload_ammo && self.ammo_rockets) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_rockets -= 1;
 +      }
 +      self.minelayer_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_minelayer_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_MineLayer_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_minelayer_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_rockets, autocvar_g_balance_minelayer_ammo))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_minelayer_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_minelayer_reload_time, W_MineLayer_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void spawnfunc_weapon_minelayer (void)
  {
        weapon_defaultspawnfunc(WEP_MINE_LAYER);
@@@ -269,17 -214,8 +269,17 @@@ void W_Mine_Attack (void
                }
        }
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_minelayer_ammo;
 +      {
 +              if(autocvar_g_balance_minelayer_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_minelayer_ammo;
 +                      self.minelayer_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_minelayer_ammo;
 +      }
  
        W_SetupShot_ProjectileSize (self, '-4 -4 -4', '4 4 4', FALSE, 5, "weapons/mine_fire.wav", CHAN_WEAPON, autocvar_g_balance_minelayer_damage);
        pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
@@@ -334,8 -270,6 +334,8 @@@ float w_minelayer(float req
  {
        entity mine;
        float minfound;
 +      float ammo_amount;
 +
        if (req == WR_AIM)
        {
                // aim and decide to fire if appropriate
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_minelayer_reload_ammo && self.clip_load < autocvar_g_balance_minelayer_ammo) // forced reload
 +                      W_MineLayer_Reload();
 +              else if (self.BUTTON_ATCK)
                {
                        if(weapon_prepareattack(0, autocvar_g_balance_minelayer_refire))
                        {
                        }
                }
  
 -              if (self.BUTTON_ATCK2)
 +              else if (self.BUTTON_ATCK2)
                {
                        minfound = 0;
                        for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
                precache_sound ("weapons/mine_fire.wav");
                precache_sound ("weapons/mine_stick.wav");
                precache_sound ("weapons/mine_trigger.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
        {
                weapon_setup(WEP_MINE_LAYER);
 +              W_MineLayer_SetAmmoCounter();
        }
        else if (req == WR_CHECKAMMO1)
        {
                // don't switch while placing a mine
 -              if ((ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER)
 -                      && self.ammo_rockets < autocvar_g_balance_minelayer_ammo)
 -                      return FALSE;
 +              if (ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER)
 +              {
 +                      if(self.ammo_rockets < autocvar_g_balance_minelayer_ammo)
 +                              ammo_amount = FALSE;
 +                      if(autocvar_g_balance_electro_reload_ammo && self.minelayer_load < autocvar_g_balance_minelayer_ammo)
 +                              ammo_amount = FALSE;
 +              }
 +              return ammo_amount;
        }
        else if (req == WR_CHECKAMMO2)
 +      {
                return FALSE;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.minelayer_load = autocvar_g_balance_minelayer_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_MineLayer_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -521,15 -435,15 +521,15 @@@ float w_minelayer(float req
                precache_sound("weapons/mine_exp.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s exploded";
+               w_deathtypestring = _("%s exploded");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation)
-                       w_deathtypestring = "%s got too close to %s's mine";
+                       w_deathtypestring = _("%s got too close to %s's mine");
                else if(w_deathtype & HITTYPE_SPLASH)
-                       w_deathtypestring = "%s almost dodged %s's mine";
+                       w_deathtypestring = _("%s almost dodged %s's mine");
                else
-                       w_deathtypestring = "%s stepped on %s's mine";
+                       w_deathtypestring = _("%s stepped on %s's mine");
        }
        return TRUE;
  }
index a26dba22fb40bfe6895cbb6766171bbc3a8b7e76,89f209937a83f0cd58f6d335489761e89bdb41f2..721fbe42e4c95d264c40a5bab4cee08b4ed37de7
@@@ -4,66 -4,6 +4,66 @@@ REGISTER_WEAPON(MINSTANEX, w_minstanex
  #ifdef SVQC
  .float minstanex_lasthit;
  
 +// weapon load persistence, for weapons that support reloading
 +.float minstanex_load;
 +
 +void W_Minstanex_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_minstanex_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.minstanex_load;
 +              self.clip_size = autocvar_g_balance_minstanex_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Minstanex_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_minstanex_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_cells -= 1;
 +      }
 +      self.minstanex_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_minstanex_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Minstanex_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_minstanex_reload_ammo)
 +              return;
 +
 +      if(autocvar_g_balance_minstanex_laser_ammo)
 +      {
 +              if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_minstanex_ammo, autocvar_g_balance_minstanex_laser_ammo)))
 +                      return;
 +      }
 +      else if(!W_ReloadCheck(self.ammo_cells, autocvar_g_balance_minstanex_ammo))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_minstanex_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_minstanex_reload_time, W_Minstanex_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_MinstaNex_Attack (void)
  {
        float flying;
        if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
                Damage_DamageInfo(trace_endpos, 10000, 0, 0, 800 * w_shotdir, WEP_MINSTANEX, self);
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
        {
 -              if (g_minstagib)
 -                      self.ammo_cells = self.ammo_cells - 1;
 +              if(autocvar_g_balance_minstanex_reload_ammo)
 +              {
 +                      if (g_minstagib)
 +                              self.clip_load -= - 1;
 +                      else
 +                              self.clip_load -= autocvar_g_balance_minstanex_ammo;
 +                      self.minstanex_load = self.clip_load;
 +              }
                else
 -                      self.ammo_cells = self.ammo_cells - autocvar_g_balance_minstanex_ammo;
 +              {
 +                      if (g_minstagib)
 +                              self.ammo_cells -= - 1;
 +                      else
 +                              self.ammo_cells -= autocvar_g_balance_minstanex_ammo;
 +              }
        }
  }
  
@@@ -243,30 -171,18 +243,30 @@@ void minstagib_ammocheck (void
  
  void spawnfunc_weapon_minstanex (void); // defined in t_items.qc
  
 +float minstanex_ammo;
  float w_minstanex(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
        {
 -              if(self.ammo_cells>0)
 +              if(self.ammo_cells > 0)
                        self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE);
                else
                        self.BUTTON_ATCK2 = bot_aim(autocvar_g_balance_laser_primary_speed, 0, autocvar_g_balance_laser_primary_lifetime, FALSE);
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(g_minstagib)
 +                      minstanex_ammo = 1;
 +              else
 +                      minstanex_ammo = autocvar_g_balance_minstanex_ammo;
 +
 +              // if the laser uses load, we also consider its ammo for reloading
 +              if(autocvar_g_balance_minstanex_reload_ammo && autocvar_g_balance_minstanex_laser_ammo && self.clip_load < min(minstanex_ammo, autocvar_g_balance_minstanex_laser_ammo)) // forced reload
 +                      W_Minstanex_Reload();
 +              else if(autocvar_g_balance_minstanex_reload_ammo && self.clip_load < minstanex_ammo) // forced reload
 +                      W_Minstanex_Reload();
 +              else if (self.BUTTON_ATCK)
                {
                        if (weapon_prepareattack(0, autocvar_g_balance_minstanex_refire))
                        {
                        {
                                self.jump_interval = time + autocvar_g_balance_laser_primary_refire * W_WeaponRateFactor();
  
 +                              // decrease ammo for the laser?
 +                              if(autocvar_g_balance_minstanex_laser_ammo)
 +                              {
 +                                      if(autocvar_g_balance_minstanex_reload_ammo)
 +                                              self.clip_load -= autocvar_g_balance_minstanex_laser_ammo;
 +                                      else
 +                                              self.ammo_cells -= autocvar_g_balance_minstanex_laser_ammo;
 +                              }
 +
                                // ugly minstagib hack to reuse the fire mode of the laser
                                float w;
                                w = self.weapon;
                precache_sound ("weapons/nexwhoosh1.wav");
                precache_sound ("weapons/nexwhoosh2.wav");
                precache_sound ("weapons/nexwhoosh3.wav");
 +              precache_sound ("weapons/reload.wav");
                w_laser(WR_PRECACHE);
        }
        else if (req == WR_SETUP)
        {
                weapon_setup(WEP_MINSTANEX);
 +              W_Minstanex_SetAmmoCounter();
                self.minstanex_lasthit = 0;
        }
        else if (req == WR_CHECKAMMO1)
        {
 -              if (g_minstagib)
 -                      return self.ammo_cells >= 1;
 -              else
 -                      return self.ammo_cells >= autocvar_g_balance_minstanex_ammo;
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_minstanex_ammo;
 +              ammo_amount += (autocvar_g_balance_minstanex_reload_ammo && self.minstanex_load >= autocvar_g_balance_minstanex_ammo);
 +              return ammo_amount;
        }
        else if (req == WR_CHECKAMMO2)
 -              return TRUE;
 +      {
 +              if(!autocvar_g_balance_minstanex_laser_ammo)
 +                      return TRUE;
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_minstanex_laser_ammo;
 +              ammo_amount += (autocvar_g_balance_minstanex_reload_ammo && self.minstanex_load >= autocvar_g_balance_minstanex_laser_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_RESETPLAYER)
        {
                self.minstanex_lasthit = 0;
 +
 +              // all weapons must be fully loaded when we spawn
 +              self.minstanex_load = autocvar_g_balance_minstanex_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Minstanex_Reload();
        }
        return TRUE;
  };
@@@ -361,9 -254,9 +361,9 @@@ float w_minstanex(float req
                precache_sound("weapons/neximpact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s did the impossible";
+               w_deathtypestring = _("%s did the impossible");
        else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = "%s has been vaporized by %s";
+               w_deathtypestring = _("%s has been vaporized by %s");
        return TRUE;
  }
  #endif
diff --combined qcsrc/server/w_nex.qc
index 03806f9f9f27926d90dc1d65257db69ac9a08c9d,4bc8130290d674260716b7fd7500354941aefc1d..a27cffadc9196621fdfa74aecc5356d1fba27a37
@@@ -2,62 -2,6 +2,62 @@@
  REGISTER_WEAPON(NEX, w_nex, IT_CELLS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "nex", "nex", _("Nex"))
  #else
  #ifdef SVQC
 +
 +// weapon load persistence, for weapons that support reloading
 +.float nex_load;
 +
 +void W_Nex_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_nex_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.nex_load;
 +              self.clip_size = autocvar_g_balance_nex_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Nex_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_nex_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_cells -= 1;
 +      }
 +      self.nex_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_nex_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Nex_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_nex_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_nex_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_nex_reload_time, W_Nex_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void SendCSQCNexBeamParticle(float charge) {
        vector v;
        v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
@@@ -130,17 -74,8 +130,17 @@@ void W_Nex_Attack (float issecondary
        if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
                Damage_DamageInfo(trace_endpos, mydmg, 0, 0, myforce * w_shotdir, WEP_NEX, self);
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_cells = self.ammo_cells - myammo;
 +      {
 +              if(autocvar_g_balance_nex_reload_ammo)
 +              {
 +                      self.clip_load -= myammo;
 +                      self.nex_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_cells -= myammo;
 +      }
  }
  
  void spawnfunc_weapon_nex (void); // defined in t_items.qc
  float w_nex(float req)
  {
        float dt;
 +      float ammo_amount;
        if (req == WR_AIM)
        {
                self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE);
                                self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_nex_secondary_chargepool_pause_health_regen);
                        }
  
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_nex_reload_ammo && self.clip_load < min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo)) // forced reload
 +                      W_Nex_Reload();
 +              else
                {
 -                      if (weapon_prepareattack(0, autocvar_g_balance_nex_primary_refire))
 +                      if (self.BUTTON_ATCK)
                        {
 -                              W_Nex_Attack(0);
 -                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_primary_animtime, w_ready);
 +                              if (weapon_prepareattack(0, autocvar_g_balance_nex_primary_refire))
 +                              {
 +                                      W_Nex_Attack(0);
 +                                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_primary_animtime, w_ready);
 +                              }
                        }
 -              }
 -              if ((autocvar_g_balance_nex_secondary_charge && !autocvar_g_balance_nex_secondary) ? self.BUTTON_ZOOM : self.BUTTON_ATCK2)
 -              {
 -                      if(autocvar_g_balance_nex_secondary_charge)
 +                      if ((autocvar_g_balance_nex_secondary_charge && !autocvar_g_balance_nex_secondary) ? self.BUTTON_ZOOM : self.BUTTON_ATCK2)
                        {
 -                              self.nex_charge_rottime = time + autocvar_g_balance_nex_charge_rot_pause;
 -                              dt = frametime / W_TICSPERFRAME;
 -
 -                              if(self.nex_charge < 1)
 +                              if(autocvar_g_balance_nex_secondary_charge)
                                {
 -                                      if(autocvar_g_balance_nex_secondary_chargepool)
 +                                      self.nex_charge_rottime = time + autocvar_g_balance_nex_charge_rot_pause;
 +                                      dt = frametime / W_TICSPERFRAME;
 +
 +                                      if(self.nex_charge < 1)
                                        {
 -                                              if(autocvar_g_balance_nex_secondary_ammo)
 +                                              if(autocvar_g_balance_nex_secondary_chargepool)
                                                {
 -                                                      // always deplete if secondary is held
 -                                                      self.nex_chargepool_ammo = max(0, self.nex_chargepool_ammo - autocvar_g_balance_nex_secondary_ammo * dt);
 +                                                      if(autocvar_g_balance_nex_secondary_ammo)
 +                                                      {
 +                                                              // always deplete if secondary is held
 +                                                              self.nex_chargepool_ammo = max(0, self.nex_chargepool_ammo - autocvar_g_balance_nex_secondary_ammo * dt);
  
 -                                                      dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
 -                                                      self.nex_chargepool_pauseregen_finished = time + autocvar_g_balance_nex_secondary_chargepool_pause_regen;
 -                                                      dt = min(dt, self.nex_chargepool_ammo);
 -                                                      dt = max(0, dt);
 +                                                              dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
 +                                                              self.nex_chargepool_pauseregen_finished = time + autocvar_g_balance_nex_secondary_chargepool_pause_regen;
 +                                                              dt = min(dt, self.nex_chargepool_ammo);
 +                                                              dt = max(0, dt);
  
 -                                                      self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
 +                                                              self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
 +                                                      }
                                                }
 -                                      }
  
 -                                      else if(autocvar_g_balance_nex_secondary_ammo)
 -                                      {
 -                                              if(self.BUTTON_ATCK2) // only eat ammo when the button is pressed
 +                                              else if(autocvar_g_balance_nex_secondary_ammo)
                                                {
 -                                                      dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
 -                                                      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +                                                      if(self.BUTTON_ATCK2) // only eat ammo when the button is pressed
                                                        {
 -                                                              dt = min(dt, (self.ammo_cells - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo);
 -                                                              dt = max(0, dt);
 -                                                              if(dt > 0)
 +                                                              dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
 +                                                              if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
                                                                {
 -                                                                      self.ammo_cells = max(autocvar_g_balance_nex_secondary_ammo, self.ammo_cells - autocvar_g_balance_nex_secondary_ammo * dt);
 +                                                                      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +                                                                      if(autocvar_g_balance_nex_reload_ammo)
 +                                                                      {
 +                                                                              dt = min(dt, (self.clip_load - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo);
 +                                                                              dt = max(0, dt);
 +                                                                              if(dt > 0)
 +                                                                              {
 +                                                                                      self.clip_load = max(autocvar_g_balance_nex_secondary_ammo, self.clip_load - autocvar_g_balance_nex_secondary_ammo * dt);
 +                                                                              }
 +                                                                              self.nex_load = self.clip_load;
 +                                                                      }
 +                                                                      else
 +                                                                      {
 +                                                                              dt = min(dt, (self.ammo_cells - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo);
 +                                                                              dt = max(0, dt);
 +                                                                              if(dt > 0)
 +                                                                              {
 +                                                                                      self.ammo_cells = max(autocvar_g_balance_nex_secondary_ammo, self.ammo_cells - autocvar_g_balance_nex_secondary_ammo * dt);
 +                                                                              }
 +                                                                      }
                                                                }
 +                                                              self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
                                                        }
 -                                                      self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
                                                }
 -                                      }
  
 -                                      else
 -                                      {
 -                                              dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
 -                                              self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
 +                                              else
 +                                              {
 +                                                      dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
 +                                                      self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
 +                                              }
                                        }
                                }
 -                      }
 -                      else if(autocvar_g_balance_nex_secondary)
 -                      {
 -                              if (weapon_prepareattack(0, autocvar_g_balance_nex_secondary_refire))
 +                              else if(autocvar_g_balance_nex_secondary)
                                {
 -                                      W_Nex_Attack(1);
 -                                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_secondary_animtime, w_ready);
 +                                      if (weapon_prepareattack(0, autocvar_g_balance_nex_secondary_refire))
 +                                      {
 +                                              W_Nex_Attack(1);
 +                                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_secondary_animtime, w_ready);
 +                                      }
                                }
                        }
                }
                precache_sound ("weapons/nexwhoosh1.wav");
                precache_sound ("weapons/nexwhoosh2.wav");
                precache_sound ("weapons/nexwhoosh3.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_NEX);
 +              W_Nex_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_cells >= autocvar_g_balance_nex_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_nex_reload_ammo && self.nex_load >= autocvar_g_balance_nex_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_cells >= autocvar_g_balance_nex_primary_ammo; // don't allow charging if we don't have enough ammo
 +      {
 +              // don't allow charging if we don't have enough ammo
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_nex_reload_ammo && self.nex_load >= autocvar_g_balance_nex_secondary_ammo);
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.nex_load = autocvar_g_balance_nex_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Nex_Reload();
 +      }
 +
        return TRUE;
  };
  #endif
@@@ -329,9 -221,9 +329,9 @@@ float w_nex(float req
                precache_sound("weapons/neximpact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s did the impossible";
+               w_deathtypestring = _("%s did the impossible");
        else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = "%s has been vaporized by %s";
+               w_deathtypestring = _("%s has been vaporized by %s");
        return TRUE;
  }
  #endif
diff --combined qcsrc/server/w_porto.qc
index 6d2981ae2ded54ab73784b41ac0b9b7c5c7aaf34,4e9a2cd706d91b359c60f37dd0e92f079add2162..d8a418ebb06c9931730e6ec80c0e372ec414390b
@@@ -7,12 -7,6 +7,12 @@@ REGISTER_WEAPON(PORTO, w_porto, 0, 0, W
  .float porto_v_angle_held;
  .vector right_vector;
  
 +void W_Porto_SetAmmoCounter()
 +{
 +      // this weapon doesn't have a reload system, so always set the clip to 0 when switching to it
 +      self.clip_load = self.clip_size = 0; // also keeps crosshair ammo from displaying
 +}
 +
  void W_Porto_Success (void)
  {
        if(self.owner == world)
@@@ -276,10 -270,7 +276,10 @@@ float w_porto(float req
                precache_sound ("porto/unsupported.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_PORTO);
 +              W_Porto_SetAmmoCounter();
 +      }
        else if (req == WR_RESETPLAYER)
        {
                self.porto_current = world;
@@@ -299,9 -290,9 +299,9 @@@ float w_porto(float req
                // nothing to do
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s did the impossible";
+               w_deathtypestring = _("%s did the impossible");
        else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = "%s felt %s doing the impossible to him";
+               w_deathtypestring = _("%s felt %s doing the impossible to him");
        return TRUE;
  }
  #endif
index 85116a1e03df31f37ea23faf52edeae54396cdac,21874b79053a00f3dafe378d763c82931a3edc6e..471350484faa4b0109272f4e345a3ddbf4a2d8d1
@@@ -5,61 -5,6 +5,61 @@@ REGISTER_WEAPON(ROCKET_LAUNCHER, w_rlau
  .float rl_release;
  .float rl_detonate_later;
  
 +// weapon load persistence, for weapons that support reloading
 +.float rocketlauncher_load;
 +
 +void W_RocketLauncher_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_rocketlauncher_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.rocketlauncher_load;
 +              self.clip_size = autocvar_g_balance_rocketlauncher_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_RocketLauncher_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_rocketlauncher_reload_ammo && self.ammo_rockets) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_rockets -= 1;
 +      }
 +      self.rocketlauncher_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_rocketlauncher_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_RocketLauncher_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_rocketlauncher_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_rockets, autocvar_g_balance_rocketlauncher_ammo))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_rocketlauncher_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_rocketlauncher_reload_time, W_RocketLauncher_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Rocket_Unregister()
  {
        if(self.owner && self.owner.lastrocket == self)
@@@ -303,17 -248,8 +303,17 @@@ void W_Rocket_Attack (void
        local entity missile;
        local entity flash;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_rocketlauncher_ammo;
 +      {
 +              if(autocvar_g_balance_rocketlauncher_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_rocketlauncher_ammo;
 +                      self.rocketlauncher_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_rocketlauncher_ammo;
 +      }
  
        W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 5, "weapons/rocket_fire.wav", CHAN_WEAPON, autocvar_g_balance_rocketlauncher_damage);
        pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
@@@ -369,8 -305,6 +369,8 @@@ float w_rlauncher(float req
  {
        entity rock;
        float rockfound;
 +      float ammo_amount;
 +
        if (req == WR_AIM)
        {
                // aim and decide to fire if appropriate
        }
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_rocketlauncher_reload_ammo && self.clip_load < autocvar_g_balance_rocketlauncher_ammo) // forced reload
 +                      W_RocketLauncher_Reload();
 +              else
                {
 -                      if(self.rl_release || autocvar_g_balance_rocketlauncher_guidestop)
 -                      if(weapon_prepareattack(0, autocvar_g_balance_rocketlauncher_refire))
 +                      if (self.BUTTON_ATCK)
                        {
 -                              W_Rocket_Attack();
 -                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_rocketlauncher_animtime, w_ready);
 -                              self.rl_release = 0;
 +                              if(self.rl_release || autocvar_g_balance_rocketlauncher_guidestop)
 +                              if(weapon_prepareattack(0, autocvar_g_balance_rocketlauncher_refire))
 +                              {
 +                                      W_Rocket_Attack();
 +                                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_rocketlauncher_animtime, w_ready);
 +                                      self.rl_release = 0;
 +                              }
                        }
 -              }
 -              else
 -                      self.rl_release = 1;
 +                      else
 +                              self.rl_release = 1;
  
 -              if (self.BUTTON_ATCK2)
 -              {
 -                      rockfound = 0;
 -                      for(rock = world; (rock = find(rock, classname, "rocket")); ) if(rock.owner == self)
 +                      if (self.BUTTON_ATCK2)
                        {
 -                              if(!rock.rl_detonate_later)
 +                              rockfound = 0;
 +                              for(rock = world; (rock = find(rock, classname, "rocket")); ) if(rock.owner == self)
                                {
 -                                      rock.rl_detonate_later = TRUE;
 -                                      rockfound = 1;
 +                                      if(!rock.rl_detonate_later)
 +                                      {
 +                                              rock.rl_detonate_later = TRUE;
 +                                              rockfound = 1;
 +                                      }
                                }
 +                              if(rockfound)
 +                                      sound (self, CHAN_WEAPON2, "weapons/rocket_det.wav", VOL_BASE, ATTN_NORM);
                        }
 -                      if(rockfound)
 -                              sound (self, CHAN_WEAPON2, "weapons/rocket_det.wav", VOL_BASE, ATTN_NORM);
                }
        }
        else if (req == WR_PRECACHE)
                precache_sound ("weapons/rocket_det.wav");
                precache_sound ("weapons/rocket_fire.wav");
                precache_sound ("weapons/rocket_mode.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
        {
                weapon_setup(WEP_ROCKET_LAUNCHER);
 +              W_RocketLauncher_SetAmmoCounter();
                self.rl_release = 1;
        }
        else if (req == WR_CHECKAMMO1)
        {
                // don't switch while guiding a missile
 -              if ((ATTACK_FINISHED(self) <= time || self.weapon != WEP_ROCKET_LAUNCHER)
 -                      && self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo)
 -                      return FALSE;
 +              if (ATTACK_FINISHED(self) <= time || self.weapon != WEP_ROCKET_LAUNCHER)
 +              {
 +                      if(self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo)
 +                              ammo_amount = FALSE;
 +                      if(autocvar_g_balance_electro_reload_ammo && self.minelayer_load < autocvar_g_balance_rocketlauncher_ammo)
 +                              ammo_amount = FALSE;
 +              }
 +              return ammo_amount;
        }
        else if (req == WR_CHECKAMMO2)
                return FALSE;
        else if (req == WR_RESETPLAYER)
        {
                self.rl_release = 0;
 +
 +              // all weapons must be fully loaded when we spawn
 +              self.rocketlauncher_load = autocvar_g_balance_rocketlauncher_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_RocketLauncher_Reload();
        }
        return TRUE;
  };
@@@ -562,15 -477,15 +562,15 @@@ float w_rlauncher(float req
                precache_sound("weapons/rocket_impact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s exploded";
+               w_deathtypestring = _("%s exploded");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation)
-                       w_deathtypestring = "%s got too close to %s's rocket";
+                       w_deathtypestring = _("%s got too close to %s's rocket");
                else if(w_deathtype & HITTYPE_SPLASH)
-                       w_deathtypestring = "%s almost dodged %s's rocket";
+                       w_deathtypestring = _("%s almost dodged %s's rocket");
                else
-                       w_deathtypestring = "%s ate %s's rocket";
+                       w_deathtypestring = _("%s ate %s's rocket");
        }
        return TRUE;
  }
diff --combined qcsrc/server/w_seeker.qc
index cb050f399ca7d8e8845fd664df3e18bba84ce665,81d55a2265e62387359c843f37636462fd7afac6..9e02e2eca0895d117c8092c27137b8c0b4f329cd
@@@ -5,61 -5,6 +5,61 @@@ REGISTER_WEAPON(SEEKER, w_seeker, IT_RO
  //.float proxytime; = autoswitch
  //.float tl; = wait
  
 +// weapon load persistence, for weapons that support reloading
 +.float seeker_load;
 +
 +void W_Seeker_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_seeker_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.seeker_load;
 +              self.clip_size = autocvar_g_balance_seeker_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Seeker_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_seeker_reload_ammo && self.ammo_rockets) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_rockets -= 1;
 +      }
 +      self.seeker_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_seeker_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Seeker_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_seeker_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_rockets, min(autocvar_g_balance_seeker_missile_ammo, autocvar_g_balance_seeker_tag_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_seeker_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_seeker_reload_time, W_Seeker_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void Seeker_Missile_Explode ()
  {
        self.event_damage = SUB_Null;
@@@ -213,17 -158,8 +213,17 @@@ void Seeker_Fire_Missile(vector f_diff
  {
        local entity missile;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_seeker_missile_ammo;
 +      {
 +              if(autocvar_g_balance_seeker_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_seeker_missile_ammo;
 +                      self.seeker_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_seeker_missile_ammo;
 +      }
  
        makevectors(self.v_angle);
        W_SetupShot_ProjectileSize (self, '-2 -2 -2', '2 2 2', FALSE, 2, "weapons/seeker_fire.wav", CHAN_WEAPON, 0);
@@@ -358,17 -294,8 +358,17 @@@ void Seeker_Tag_Touch(
  void Seeker_Fire_Tag()
  {
        local entity missile;
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_seeker_tag_ammo;
 +      {
 +              if(autocvar_g_balance_seeker_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_seeker_tag_ammo;
 +                      self.seeker_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_seeker_tag_ammo;
 +      }
  
        W_SetupShot_ProjectileSize (self, '-2 -2 -2', '2 2 2', FALSE, 2, "weapons/tag_fire.wav", CHAN_WEAPON, autocvar_g_balance_seeker_missile_damage * autocvar_g_balance_seeker_missile_count);
  
@@@ -426,17 -353,8 +426,17 @@@ void Seeker_Fire_Flac(
        vector f_diff;
        float c;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_seeker_flac_ammo;
 +      {
 +              if(autocvar_g_balance_seeker_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_seeker_flac_ammo;
 +                      self.seeker_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_rockets -= autocvar_g_balance_seeker_flac_ammo;
 +      }
  
        c = mod(self.bulletcounter, 4);
        switch(c)
@@@ -495,33 -413,25 +495,33 @@@ void spawnfunc_weapon_seeker (void
  
  float w_seeker(float req)
  {
 +      float ammo_amount;
 +
        if (req == WR_AIM)
                self.BUTTON_ATCK = bot_aim(autocvar_g_balance_seeker_tag_speed, 0, 20, FALSE);
  
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_seeker_reload_ammo && self.clip_load < min(autocvar_g_balance_seeker_missile_ammo, autocvar_g_balance_seeker_tag_ammo)) // forced reload
 +                      W_Seeker_Reload();
 +
 +              else if (self.BUTTON_ATCK)
 +              {
                        if (weapon_prepareattack(0, autocvar_g_balance_seeker_tag_refire))
                        {
                                Seeker_Fire_Tag();
                                weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_seeker_tag_animtime, w_ready);
                        }
 +              }
  
 -              if (self.BUTTON_ATCK2)
 +              else if (self.BUTTON_ATCK2)
 +              {
                        if (weapon_prepareattack(1, autocvar_g_balance_seeker_flac_refire))
                        {
                                Seeker_Fire_Flac();
                                weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_seeker_flac_animtime, w_ready);
                        }
 -
 +              }
        }
        else if (req == WR_PRECACHE)
        {
                precache_sound ("weapons/tag_fire.wav");
                precache_sound ("weapons/flac_fire.wav");
                precache_sound ("weapons/seeker_fire.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_SEEKER);
 +              W_Seeker_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_rockets >= autocvar_g_balance_seeker_tag_ammo + autocvar_g_balance_seeker_missile_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_seeker_missile_ammo;
 +              ammo_amount += (autocvar_g_balance_seeker_reload_ammo && self.seeker_load >= autocvar_g_balance_seeker_missile_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_rockets >= autocvar_g_balance_seeker_flac_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_seeker_flac_ammo;
 +              ammo_amount += (autocvar_g_balance_seeker_reload_ammo && self.seeker_load >= autocvar_g_balance_seeker_flac_ammo);
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.seeker_load = autocvar_g_balance_seeker_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Seeker_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -631,13 -520,13 +631,13 @@@ float w_seeker(float req
                precache_sound("weapons/tag_impact.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s played with tiny rockets";
+               w_deathtypestring = _("%s played with tiny rockets");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s ran into %s's flac";
+                       w_deathtypestring = _("%s ran into %s's flac");
                else
-                       w_deathtypestring = "%s was tagged by %s";
+                       w_deathtypestring = _("%s was tagged by %s");
        }
        return TRUE;
  }
index 7d515ddeea28c0857dadc25b817386fc4bd62a55,6d0d094eb404c7800de4316a68397d04b7e0cbef..fa398933b38671ecf94a2fd7f7b39c7eb1ba03a7
@@@ -2,62 -2,6 +2,62 @@@
  REGISTER_WEAPON(SHOTGUN, w_shotgun, IT_SHELLS, 2, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_LOW, "shotgun", "shotgun", _("Shotgun"))
  #else
  #ifdef SVQC
 +
 +// weapon load persistence, for weapons that support reloading
 +.float shotgun_load;
 +
 +void W_Shotgun_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_shotgun_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.shotgun_load;
 +              self.clip_size = autocvar_g_balance_shotgun_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_Shotgun_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_shotgun_reload_ammo && self.ammo_shells) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_shells -= 1;
 +      }
 +      self.shotgun_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_shotgun_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_Shotgun_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_shotgun_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_shells, autocvar_g_balance_shotgun_primary_ammo))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_shotgun_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_shotgun_reload_time, W_Shotgun_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  void W_Shotgun_Attack (void)
  {
        float   sc;
        bulletspeed = autocvar_g_balance_shotgun_primary_speed;
        bulletconstant = autocvar_g_balance_shotgun_primary_bulletconstant;
  
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_shotgun_reload_ammo)
 +              {
 +                      self.clip_load -= ammoamount;
 +                      self.shotgun_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_shells -= ammoamount;
 +      }
 +
        W_SetupShot (self, autocvar_g_antilag_bullets && bulletspeed >= autocvar_g_antilag_bullets, 5, "weapons/shotgun_fire.wav", CHAN_WEAPON, d * bullets);
        for (sc = 0;sc < bullets;sc = sc + 1)
                fireBallisticBullet(w_shotorg, w_shotdir, spread, bulletspeed, 5, d, 0, f, WEP_SHOTGUN, 0, 1, bulletconstant);
        endFireBallisticBullet();
 -      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_shells = self.ammo_shells - ammoamount;
  
        pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 1000, autocvar_g_balance_shotgun_primary_ammo);
  
        flash.nextthink = time + 0.06;
        flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
        W_AttachToShotorg(flash, '5 0 0');
 -
  }
  
  void shotgun_meleethink (void)
@@@ -167,7 -102,6 +167,7 @@@ void spawnfunc_weapon_shotgun(); // def
  
  float w_shotgun(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
                if(vlen(self.origin-self.enemy.origin) <= autocvar_g_balance_shotgun_secondary_melee_range)
                        self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE);
                        self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
        else if (req == WR_THINK)
        {
 -              if (self.BUTTON_ATCK)
 +              if(autocvar_g_balance_shotgun_reload_ammo && self.clip_load < autocvar_g_balance_shotgun_primary_ammo) // forced reload
 +                      W_Shotgun_Reload();
 +              else
                {
 -                      if (time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
 +                      if (self.BUTTON_ATCK)
                        {
 -                              if(weapon_prepareattack(0, autocvar_g_balance_shotgun_primary_animtime))
 +                              if (time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
                                {
 -                                      W_Shotgun_Attack();
 -                                      self.shotgun_primarytime = time + autocvar_g_balance_shotgun_primary_refire;
 -                                      weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_shotgun_primary_animtime, w_ready);
 +                                      if(weapon_prepareattack(0, autocvar_g_balance_shotgun_primary_animtime))
 +                                      {
 +                                              W_Shotgun_Attack();
 +                                              self.shotgun_primarytime = time + autocvar_g_balance_shotgun_primary_refire;
 +                                              weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_shotgun_primary_animtime, w_ready);
 +                                      }
                                }
                        }
 -              }
 -              if (self.BUTTON_ATCK2 && autocvar_g_balance_shotgun_secondary)
 -              if (weapon_prepareattack(1, autocvar_g_balance_shotgun_secondary_refire))
 -              {
 -                      // attempt forcing playback of the anim by switching to another anim (that we never play) here...
 -                      weapon_thinkf(WFRAME_FIRE1, 0, W_Shotgun_Attack2);
 +                      if (self.BUTTON_ATCK2 && autocvar_g_balance_shotgun_secondary)
 +                      if (weapon_prepareattack(1, autocvar_g_balance_shotgun_secondary_refire))
 +                      {
 +                              // attempt forcing playback of the anim by switching to another anim (that we never play) here...
 +                              weapon_thinkf(WFRAME_FIRE1, 0, W_Shotgun_Attack2);
 +                      }
                }
        }
        else if (req == WR_PRECACHE)
                precache_sound ("misc/itempickup.wav");
                precache_sound ("weapons/shotgun_fire.wav");
                precache_sound ("weapons/shotgun_melee.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_SHOTGUN);
 +              W_Shotgun_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_shells >= autocvar_g_balance_shotgun_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_shells >= autocvar_g_balance_shotgun_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_shotgun_reload_ammo && self.shotgun_load >= autocvar_g_balance_shotgun_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
        {
 +              // melee attack is always available
                return TRUE;
        }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.shotgun_load = autocvar_g_balance_shotgun_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_Shotgun_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -265,13 -176,13 +265,13 @@@ float w_shotgun(float req
                precache_sound("weapons/ric3.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s did the impossible";
+               w_deathtypestring = _("%s did the impossible");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%2$s ^7slapped %1$s ^7around a bit with a large ^2shotgun";
+                       w_deathtypestring = _("%2$s ^7slapped %1$s ^7around a bit with a large ^2shotgun");
                else
-                       w_deathtypestring = "%s was gunned by %s";
+                       w_deathtypestring = _("%s was gunned by %s");
        }
        return TRUE;
  }
index 3320ae792a133ac2b360b1788a471e902917154c,a03a9b6108491e565170634feba2b7940815a8ae..3e2d3a665e0cd93c33425198c3625c9ed9228f26
@@@ -8,81 -8,87 +8,81 @@@ REGISTER_WEAPON(SNIPERRIFLE, w_sniperri
  
  .float sniperrifle_accumulator;
  
 -float W_SniperRifle_CheckMaxBullets(float checkammo)
 +// weapon load persistence, for weapons that support reloading
 +.float sniperrifle_load;
 +
 +void W_SniperRifle_SetAmmoCounter()
  {
 -      float maxbulls;
 -      maxbulls = autocvar_g_balance_sniperrifle_magazinecapacity;
 -      if(!maxbulls)
 -              maxbulls = 8; // match HUD
 -      if(checkammo)
 -              if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -                      maxbulls = min(maxbulls, floor(self.ammo_nails / min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)));
 -      if(self.sniperrifle_bulletcounter > maxbulls || !autocvar_g_balance_sniperrifle_magazinecapacity)
 -              self.sniperrifle_bulletcounter = maxbulls;
 -      return (self.sniperrifle_bulletcounter == maxbulls);
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_sniperrifle_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.sniperrifle_load;
 +              self.clip_size = autocvar_g_balance_sniperrifle_reload_ammo; // for the crosshair ammo display
 +      }
  }
  
  void W_SniperRifle_ReloadedAndReady()
  {
        float t;
 -      self.sniperrifle_bulletcounter = autocvar_g_balance_sniperrifle_magazinecapacity;
 -      W_SniperRifle_CheckMaxBullets(TRUE);
 -      t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reloadtime - 1;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_nails -= 1;
 +      }
 +      self.sniperrifle_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reload_time - 1;
        ATTACK_FINISHED(self) = t;
        w_ready();
  }
  
 -float W_SniperRifle_Reload()
 +void W_SniperRifle_Reload()
  {
 -      float t;
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_sniperrifle_reload_ammo)
 +              return;
  
 -      W_SniperRifle_CheckMaxBullets(TRUE);
 +      if(!W_ReloadCheck(self.ammo_nails, min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)))
 +              return;
  
 -      if(self.ammo_nails < min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)) // when we get here, bulletcounter must be 0 or -1
 -      {
 -              print("cannot reload... not enough bullets\n");
 -              self.sniperrifle_bulletcounter = -1; // reload later
 -              W_SwitchToOtherWeapon(self);
 -              return 0;
 -      }
 -      
 -      if (self.sniperrifle_bulletcounter >= autocvar_g_balance_sniperrifle_magazinecapacity)
 -              return 0;
 -
 -      if (self.weaponentity)
 -      {
 -              if (self.weaponentity.wframe == WFRAME_RELOAD)
 -                      return 0;
 -
 -              // allow to switch away while reloading, but this will cause a new reload!
 -              self.weaponentity.state = WS_READY;
 -      }
 +      float t;
  
 -      sound (self, CHAN_WEAPON2, "weapons/campingrifle_reload.wav", VOL_BASE, ATTN_NORM);
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
  
 -      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reloadtime + 1;
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reload_time + 1;
        ATTACK_FINISHED(self) = t;
  
 -      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reloadtime, W_SniperRifle_ReloadedAndReady);
 -
 -      self.sniperrifle_bulletcounter = -1;
 -
 -      return 1;
 -}
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reload_time, W_SniperRifle_ReloadedAndReady);
  
 -void W_SniperRifle_CheckReloadAndReady()
 -{
 -      w_ready();
 -      if(self.sniperrifle_bulletcounter <= 0)
 -              if(W_SniperRifle_Reload())
 -                      return;
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
  }
  
  void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
  {
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -              self.ammo_nails -= pAmmo;
 +      {
 +              if(autocvar_g_balance_sniperrifle_reload_ammo)
 +              {
 +                      self.clip_load -= pAmmo;
 +                      self.sniperrifle_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_nails -= pAmmo;
 +      }
  
        if(deathtype & HITTYPE_SECONDARY)
                W_SetupShot (self, autocvar_g_antilag_bullets && pSpeed >= autocvar_g_antilag_bullets, 2, "weapons/campingrifle_fire2.wav", CHAN_WEAPON, autocvar_g_balance_sniperrifle_secondary_damage + autocvar_g_balance_sniperrifle_secondary_headshotaddeddamage);
        else
                W_SetupShot (self, autocvar_g_antilag_bullets && pSpeed >= autocvar_g_antilag_bullets, 2, "weapons/campingrifle_fire.wav", CHAN_WEAPON, autocvar_g_balance_sniperrifle_primary_damage + autocvar_g_balance_sniperrifle_primary_headshotaddeddamage);
  
 -      pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
 +      pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
  
        if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
        {
  
        if (autocvar_g_casings >= 2)
                SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
 -      
 -      self.sniperrifle_bulletcounter = self.sniperrifle_bulletcounter - 1;
 -      W_SniperRifle_CheckMaxBullets(TRUE);
  }
  
  void W_SniperRifle_Attack()
@@@ -128,7 -137,9 +128,7 @@@ void spawnfunc_weapon_campingrifle (voi
  void W_SniperRifle_BulletHail_Continue()
  {
        float r, sw, af;
 -      W_SniperRifle_CheckReloadAndReady();
 -      if(self.sniperrifle_bulletcounter < 0)
 -              return; // reloading, so we are done
 +
        sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
        af = ATTACK_FINISHED(self);
        self.switchweapon = self.weapon;
@@@ -166,15 -177,14 +166,15 @@@ void W_SniperRifle_BulletHail(float mod
        else
        {
                // just one shot
 -              weapon_thinkf(fr, animtime, W_SniperRifle_CheckReloadAndReady);
 +              weapon_thinkf(fr, animtime, w_ready);
        }
  }
  
  .float bot_secondary_sniperriflemooth;
  float w_sniperrifle(float req)
  {
 -      float full;
 +      float ammo_amount;
 +
        if (req == WR_AIM)
        {
                self.BUTTON_ATCK=FALSE;
        }
        else if (req == WR_THINK)
        {
 -              if(self.sniperrifle_bulletcounter < 0) // forced reload (e.g. because interrupted)
 -              {
 -            self.wish_reload = 1;
 -              }
 +              if(autocvar_g_balance_sniperrifle_reload_ammo && self.clip_load < min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)) // forced reload
 +            W_SniperRifle_Reload();
                else
                {
                        self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
                                if (autocvar_g_balance_sniperrifle_secondary)
                                {
                      if(autocvar_g_balance_sniperrifle_secondary_reload)
 -                        self.wish_reload = 1;
 +                        W_SniperRifle_Reload();
                      else
                      {
                          if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
                                }
                        }
                }
 -        if(self.wish_reload)
 -        {
 -            if(self.switchweapon == self.weapon)
 -            {
 -                if(self.weaponentity.state == WS_READY)
 -                {
 -                    self.wish_reload = 0;
 -                    W_SniperRifle_Reload();
 -                }
 -            }
 -        }
        }
        else if (req == WR_PRECACHE)
        {
                precache_model ("models/weapons/g_campingrifle.md3");
                precache_model ("models/weapons/v_campingrifle.md3");
                precache_model ("models/weapons/h_campingrifle.iqm");
 -              precache_sound ("weapons/campingrifle_reload.wav");
                precache_sound ("weapons/campingrifle_fire.wav");
                precache_sound ("weapons/campingrifle_fire2.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
        {
                weapon_setup(WEP_SNIPERRIFLE);
 -
 -              full = W_SniperRifle_CheckMaxBullets(TRUE);
 -              if(autocvar_g_balance_sniperrifle_auto_reload_on_switch)
 -                      if(!full)
 -                              self.sniperrifle_bulletcounter = -1;
 +              W_SniperRifle_SetAmmoCounter();
        }
        else if (req == WR_CHECKAMMO1)
 -              return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
 +      {
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_primary_ammo;
 +              ammo_amount += (autocvar_g_balance_sniperrifle_reload_ammo && self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo);
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 -              return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
 -      else if (req == WR_RELOAD)
        {
 -        self.wish_reload = 1;
 +              ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_secondary_ammo;
 +              ammo_amount += (autocvar_g_balance_sniperrifle_reload_ammo && self.sniperrifle_load >= autocvar_g_balance_sniperrifle_secondary_ammo);
 +              return ammo_amount;
        }
        else if (req == WR_RESETPLAYER)
        {
                self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
 -              self.sniperrifle_bulletcounter = autocvar_g_balance_sniperrifle_magazinecapacity;
 -              W_SniperRifle_CheckMaxBullets(FALSE);
 +
 +              // all weapons must be fully loaded when we spawn
 +              self.sniperrifle_load = autocvar_g_balance_sniperrifle_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_SniperRifle_Reload();
        }
        return TRUE;
  };
@@@ -300,32 -318,32 +300,32 @@@ float w_sniperrifle(float req
        else if (req == WR_SUICIDEMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s shot themself automatically";
+                       w_deathtypestring = _("%s shot themself automatically");
                else
-                       w_deathtypestring = "%s sniped themself somehow";
+                       w_deathtypestring = _("%s sniped themself somehow");
        }
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
                {
                        if(w_deathtype & HITTYPE_BOUNCE)
-                               w_deathtypestring = "%s failed to hide from %s's bullet hail";
+                               w_deathtypestring = _("%s failed to hide from %s's bullet hail");
                        else
-                               w_deathtypestring = "%s died in %s's bullet hail";
+                               w_deathtypestring = _("%s died in %s's bullet hail");
                }
                else
                {
                        if(w_deathtype & HITTYPE_BOUNCE)
                        {
                                // TODO special headshot message here too?
-                               w_deathtypestring = "%s failed to hide from %s's rifle";
+                               w_deathtypestring = _("%s failed to hide from %s's rifle");
                        }
                        else
                        {
                                if(w_deathtype & HITTYPE_HEADSHOT)
-                                       w_deathtypestring = "%s got hit in the head by %s";
+                                       w_deathtypestring = _("%s got hit in the head by %s");
                                else
-                                       w_deathtypestring = "%s was sniped by %s";
+                                       w_deathtypestring = _("%s was sniped by %s");
                        }
                }
        }
diff --combined qcsrc/server/w_tuba.qc
index 92d7413d658d9a4e5c25a8e2820a4fa7e3d0174a,98767516ae33e5611fec209b6db0cd1bb7dbb398..0973c5f92a8a24c4da171faa91e64f24cfe05f6e
@@@ -7,12 -7,6 +7,12 @@@ REGISTER_WEAPON(TUBA, w_tuba, 0, 1, WEP
  .entity tuba_note;
  .float tuba_smoketime;
  
 +void W_Tuba_SetAmmoCounter()
 +{
 +      // this weapon doesn't have a reload system, so always set the clip to 0 when switching to it
 +      self.clip_load = self.clip_size = 0; // also keeps crosshair ammo from displaying
 +}
 +
  float Tuba_GetNote(entity pl, float hittype)
  {
        float note;
@@@ -242,10 -236,7 +242,10 @@@ float w_tuba(float req
                //      precache_sound(TUBA_NOTE(i));
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_TUBA);
 +              W_Porto_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
                return TRUE; // TODO use fuel?
        else if (req == WR_CHECKAMMO2)
@@@ -266,11 -257,11 +266,11 @@@ float w_tuba(float req
        }
        else if (req == WR_SUICIDEMESSAGE)
        {
-               w_deathtypestring = "%s hurt his own ears with the @!#%%'n Tuba";
+               w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Tuba");
        }
        else if (req == WR_KILLMESSAGE)
        {
-               w_deathtypestring = "%s died of %s's great playing on the @!#%%'n Tuba";
+               w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Tuba");
        }
        return TRUE;
  }
diff --combined qcsrc/server/w_uzi.qc
index 1fe188e69ef17145c7ee49987a69afccd67974e6,0e563405a1fa858ebdbd6719868e30859fd89eef..360c8913345dee4cca9b38adfb9a0b15573ab357
@@@ -3,63 -3,8 +3,63 @@@ REGISTER_WEAPON(UZI, w_uzi, IT_NAILS, 3
  #else
  #ifdef SVQC
  
 +// weapon load persistence, for weapons that support reloading
 +.float uzi_load;
 +
 +void W_UZI_SetAmmoCounter()
 +{
 +      // set clip_load to the weapon we have switched to, if the gun uses reloading
 +      if(!autocvar_g_balance_uzi_reload_ammo)
 +              self.clip_load = 0; // also keeps crosshair ammo from displaying
 +      else
 +      {
 +              self.clip_load = self.uzi_load;
 +              self.clip_size = autocvar_g_balance_uzi_reload_ammo; // for the crosshair ammo display
 +      }
 +}
 +
 +void W_UZI_ReloadedAndReady()
 +{
 +      float t;
 +
 +      // now do the ammo transfer
 +      self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
 +      while(self.clip_load < autocvar_g_balance_uzi_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
 +      {
 +              self.clip_load += 1;
 +              self.ammo_nails -= 1;
 +      }
 +      self.uzi_load = self.clip_load;
 +
 +      t = ATTACK_FINISHED(self) - autocvar_g_balance_uzi_reload_time - 1;
 +      ATTACK_FINISHED(self) = t;
 +      w_ready();
 +}
 +
 +void W_UZI_Reload()
 +{
 +      // return if reloading is disabled for this weapon
 +      if(!autocvar_g_balance_uzi_reload_ammo)
 +              return;
 +
 +      if(!W_ReloadCheck(self.ammo_nails, min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo)))
 +              return;
 +
 +      float t;
 +
 +      sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
 +
 +      t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_uzi_reload_time + 1;
 +      ATTACK_FINISHED(self) = t;
 +
 +      weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_uzi_reload_time, W_UZI_ReloadedAndReady);
 +
 +      self.old_clip_load = self.clip_load;
 +      self.clip_load = -1;
 +}
 +
  // leilei's fancy muzzleflash stuff
 -void Uzi_Flash_Go() 
 +void UZI_Flash_Go() 
  {     
        self.frame = self.frame + 2;
        self.scale = self.scale * 0.5;
@@@ -85,7 -30,7 +85,7 @@@ void UziFlash(
        setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below
        
        self.muzzle_flash.scale = 0.75;
 -      self.muzzle_flash.think = Uzi_Flash_Go;
 +      self.muzzle_flash.think = UZI_Flash_Go;
        self.muzzle_flash.nextthink = time + 0.02;
        self.muzzle_flash.frame = 2;
        self.muzzle_flash.alpha = 0.75;
        self.muzzle_flash.owner = self;
  }
  
 -void W_Uzi_Attack (float deathtype)
 +void W_UZI_Attack (float deathtype)
  {
 -      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 -      {
 -              if (self.misc_bulletcounter == 1)
 -                      self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_first_ammo;
 -              else
 -                      self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_sustained_ammo;
 -      }
        W_SetupShot (self, autocvar_g_antilag_bullets && autocvar_g_balance_uzi_speed >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CHAN_WEAPON, ((self.misc_bulletcounter == 1) ? autocvar_g_balance_uzi_first_damage : autocvar_g_balance_uzi_sustained_damage));
        if (!g_norecoil)
        {
        // casing code
        if (autocvar_g_casings >= 2)
                SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
 +
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_uzi_reload_ammo)
 +              {
 +                      if (self.misc_bulletcounter == 1)
 +                              self.clip_load -= autocvar_g_balance_uzi_first_ammo;
 +                      else
 +                              self.clip_load -= autocvar_g_balance_uzi_sustained_ammo;
 +                      self.uzi_load = self.clip_load;
 +              }
 +              else
 +              {
 +                      if (self.misc_bulletcounter == 1)
 +                              self.ammo_nails -= autocvar_g_balance_uzi_first_ammo;
 +                      else
 +                              self.ammo_nails -= autocvar_g_balance_uzi_sustained_ammo;
 +              }
 +      }
  }
  
  // weapon frames
@@@ -159,7 -91,7 +159,7 @@@ void uzi_fire1_02(
                        return;
                }
                self.misc_bulletcounter = self.misc_bulletcounter + 1;
 -              W_Uzi_Attack(WEP_UZI);
 +              W_UZI_Attack(WEP_UZI);
                weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
        }
        else
  void uzi_mode1_fire_auto()
  {
        float uzi_spread;
 +
 +      // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      {
 +              if(autocvar_g_balance_uzi_reload_ammo)
 +              {
 +                      self.clip_load -= autocvar_g_balance_uzi_sustained_ammo;
 +                      self.uzi_load = self.clip_load;
 +              }
 +              else
 +                      self.ammo_nails -= autocvar_g_balance_uzi_sustained_ammo;
 +      }
        
        if (self.BUTTON_ATCK)
                weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_mode1_fire_auto);
        
        if (autocvar_g_casings >= 2) // casing code
                SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
 -      
 -      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)   
 -              self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_sustained_ammo;
 -      
  }
  
  void uzi_mode1_fire_burst()
@@@ -259,7 -183,6 +259,7 @@@ void spawnfunc_weapon_machinegun(); // 
  
  float w_uzi(float req)
  {
 +      float ammo_amount;
        if (req == WR_AIM)
                if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
                        self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
                }
        else if (req == WR_THINK)
        {
 -              if(autocvar_g_balance_uzi_mode == 1)
 +              if(autocvar_g_balance_uzi_reload_ammo && self.clip_load < min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo)) // forced reload
 +                      W_UZI_Reload();
 +              else if(autocvar_g_balance_uzi_mode == 1)
                {
                        if (self.BUTTON_ATCK)
                        if (weapon_prepareattack(0, 0))
                                        w_ready();
                                        return FALSE;
                                }
 -                              
 -                              if not(self.items & IT_UNLIMITED_WEAPON_AMMO)   
 -                                      self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_burst_ammo;
 +
 +                              // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
 +                              if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +                              {
 +                                      if(autocvar_g_balance_uzi_reload_ammo)
 +                                      {
 +                                              self.clip_load -= autocvar_g_balance_uzi_burst_ammo;
 +                                              self.uzi_load = self.clip_load;
 +                                      }
 +                                      else
 +                                              self.ammo_nails -= autocvar_g_balance_uzi_burst_ammo;
 +                              }
  
                                self.misc_bulletcounter = autocvar_g_balance_uzi_burst * -1;
                                uzi_mode1_fire_burst();
                        if (weapon_prepareattack(0, 0))
                        {
                                self.misc_bulletcounter = 1;
 -                              W_Uzi_Attack(WEP_UZI); // sets attack_finished
 +                              W_UZI_Attack(WEP_UZI); // sets attack_finished
                                weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
                        }
  
                        if (weapon_prepareattack(1, 0))
                        {
                                self.misc_bulletcounter = 1;
 -                              W_Uzi_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
 +                              W_UZI_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
                                weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_first_refire, w_ready);
                        }
                }
                precache_model ("models/weapons/v_uzi.md3");
                precache_model ("models/weapons/h_uzi.iqm");
                precache_sound ("weapons/uzi_fire.wav");
 +              precache_sound ("weapons/reload.wav");
        }
        else if (req == WR_SETUP)
 +      {
                weapon_setup(WEP_UZI);
 +              W_UZI_SetAmmoCounter();
 +      }
        else if (req == WR_CHECKAMMO1)
 +      {
                if(autocvar_g_balance_uzi_mode == 1)
 -                      return self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo;
 +                      ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo;
                else
 -                      return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
 +                      ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
 +
 +              if(autocvar_g_balance_uzi_reload_ammo)
 +              {
 +                      if(autocvar_g_balance_uzi_mode == 1)
 +                              ammo_amount += self.uzi_load >= autocvar_g_balance_uzi_sustained_ammo;
 +                      else
 +                              ammo_amount += self.uzi_load >= autocvar_g_balance_uzi_first_ammo;
 +              }
 +              return ammo_amount;
 +      }
        else if (req == WR_CHECKAMMO2)
 +      {
                if(autocvar_g_balance_uzi_mode == 1)
 -                      return self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo;
 +                      ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo;
                else
 -                      return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
 +                      ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
 +
 +              if(autocvar_g_balance_uzi_reload_ammo)
 +              {
 +                      if(autocvar_g_balance_uzi_mode == 1)
 +                              ammo_amount += self.uzi_load >= autocvar_g_balance_uzi_burst_ammo;
 +                      else
 +                              ammo_amount += self.uzi_load >= autocvar_g_balance_uzi_first_ammo;
 +              }
 +              return ammo_amount;
 +      }
 +      else if (req == WR_RESETPLAYER)
 +      {
 +              // all weapons must be fully loaded when we spawn
 +              self.uzi_load = autocvar_g_balance_uzi_reload_ammo;
 +      }
 +      else if (req == WR_RELOAD)
 +      {
 +              W_UZI_Reload();
 +      }
        return TRUE;
  };
  #endif
@@@ -407,13 -284,13 +407,13 @@@ float w_uzi(float req
                precache_sound("weapons/ric3.wav");
        }
        else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = "%s did the impossible";
+               w_deathtypestring = _("%s did the impossible");
        else if (req == WR_KILLMESSAGE)
        {
                if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = "%s was sniped by %s";
+                       w_deathtypestring = _("%s was sniped by %s");
                else
-                       w_deathtypestring = "%s was riddled full of holes by %s";
+                       w_deathtypestring = _("%s was riddled full of holes by %s");
        }
        return TRUE;
  }