]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into martin-t/bullet-trails
authorMartin Taibr <taibr.martin@gmail.com>
Mon, 2 Jul 2018 06:41:18 +0000 (08:41 +0200)
committerMartin Taibr <taibr.martin@gmail.com>
Mon, 2 Jul 2018 06:41:18 +0000 (08:41 +0200)
1  2 
qcsrc/common/effects/effectinfo.inc
qcsrc/common/mutators/mutator/overkill/okhmg.qc
qcsrc/common/mutators/mutator/overkill/okmachinegun.qc
qcsrc/common/turrets/turret/machinegun_weapon.qc
qcsrc/common/turrets/turret/walker_weapon.qc
qcsrc/common/vehicles/vehicle/spiderbot.qc
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/tracing.qh

index b023734e60ce803985088758aac6d2c690bdca40,b659e8a8517a83755718d93ea06c03c9a9989db8..c8273ecb2e2057c68fd357399486535b1aae4236
@@@ -1,8 -1,3 +1,8 @@@
 +// docs: https://www.quakewiki.net/darkplaces-wiki/effectinfo-scripting-reference/
 +// use `cl_particles_reloadeffects` to reload effects without restarting engine
 +// `dumpeffectinfo` currently doesn't work so edit effectinfo.txt manually, just try to keep the files in sync
 +// `tex` are indices into particles/particlefont.tga, the first is inclusive, second exclusive
 +
  // item respawn effect
  DEF(TE_WIZSPIKE);
  // flare particle and light
@@@ -8534,6 -8529,22 +8534,22 @@@ SUB(arc_lightning) 
        MY(velocityjitter) = '250.0 250.0 250.0';
        MY(velocitymultiplier) = 20;
  }
+ // impact smoke
+ SUB(arc_lightning) {
+       MY(alpha_min) = 40;
+       MY(alpha_max) = 40;
+       MY(alpha_fade) = 350;
+       MY(color_min) = "0x80C0FF";
+       MY(color_max) = "0x80C0FF";
+       MY(countabsolute) = 1;
+       MY(sizeincrease) = 400;
+       MY(size_min) = 4;
+       MY(size_max) = 4;
+       MY(tex_min) = 38;
+       MY(tex_max) = 38;
+       MY(type) = "smoke";
+       MY(velocitymultiplier) = 100;
+ }
  
  DEF(arc_beam);
  // sparks on beam
index 0000000000000000000000000000000000000000,d278ca9d444b052f4a2a9a3151321be48b78460f..003cd3abc6c258378eaf04be3eb2caa62cbf6b13
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,168 +1,168 @@@
 -      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okhmg_spread, WEP_CVAR_PRI(okhmg, solidpenetration), WEP_CVAR_PRI(okhmg, damage), WEP_CVAR_PRI(okhmg, force), WEP_OVERKILL_HMG.m_id, 0);
+ #include "okhmg.qh"
+ #ifdef SVQC
+ REGISTER_MUTATOR(okhmg_nadesupport, true);
+ MUTATOR_HOOKFUNCTION(okhmg_nadesupport, Nade_Damage)
+ {
+       if (M_ARGV(1, entity) != WEP_OVERKILL_HMG) return;
+       return = true;
+       M_ARGV(3, float) /* damage */ = (M_ARGV(0, entity)).max_health * 0.1;
+ }
+ void W_OverkillHeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+ {
+       if (!PHYS_INPUT_BUTTON_ATCK(actor))
+       {
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
+       {
+               W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       W_DecreaseAmmo(WEP_OVERKILL_HMG, actor, WEP_CVAR_PRI(okhmg, ammo), weaponentity);
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(okhmg, damage), WEP_OVERKILL_HMG.m_id);
+       if(!autocvar_g_norecoil)
+       {
+               actor.punchangle_x = random () - 0.5;
+               actor.punchangle_y = random () - 0.5;
+       }
+       float okhmg_spread = bound(WEP_CVAR_PRI(okhmg, spread_min), WEP_CVAR_PRI(okhmg, spread_min) + (WEP_CVAR_PRI(okhmg, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR_PRI(okhmg, spread_max));
++      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okhmg_spread, WEP_CVAR_PRI(okhmg, solidpenetration), WEP_CVAR_PRI(okhmg, damage), WEP_CVAR_PRI(okhmg, force), WEP_OVERKILL_HMG.m_id, EFFECT_RIFLE);
+       actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+       W_MachineGun_MuzzleFlash(actor, weaponentity);
+       W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
+       if (autocvar_g_casings >= 2) // casing code
+       {
+               makevectors(actor.v_angle); // for some reason, this is lost
+               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, actor, weaponentity);
+       }
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okhmg, refire) * W_WeaponRateFactor(actor);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okhmg, refire), W_OverkillHeavyMachineGun_Attack_Auto);
+ }
+ METHOD(OverkillHeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+ {
+     if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
+         PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+     else
+         PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ }
+ METHOD(OverkillHeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+ {
+       if ((WEP_CVAR_SEC(okhmg, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(okhmg, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(okhmg, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+     if (WEP_CVAR(okhmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okhmg, ammo))
+       {
+               // Forced reload.
+         thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+               {
+                       return;
+               }
+               actor.(weaponentity).misc_bulletcounter = 0;
+               W_OverkillHeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR_SEC(okhmg, refire_type) == 0)) // Secondary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okhmg, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(okhmg, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okhmg, animtime), w_ready);
+       }
+ }
+ METHOD(OverkillHeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+ {
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okhmg, ammo);
+       if (autocvar_g_balance_okhmg_reload_ammo)
+       {
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_HMG.m_id]) >= WEP_CVAR_PRI(okhmg, ammo);
+       }
+       return ammo_amount;
+ }
+ METHOD(OverkillHeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+ {
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(okhmg, ammo);
+       if (autocvar_g_balance_okhmg_reload_ammo)
+       {
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_HMG.m_id]) >= WEP_CVAR_SEC(okhmg, ammo);
+       }
+       return ammo_amount;
+ }
+ METHOD(OverkillHeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+ {
+     W_Reload(actor, weaponentity, WEP_CVAR_PRI(okhmg, ammo), SND_RELOAD);
+ }
+ METHOD(OverkillHeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
+ {
+     return WEAPON_THINKING_WITH_PORTALS;
+ }
+ METHOD(OverkillHeavyMachineGun, wr_killmessage, Notification(entity thiswep))
+ {
+     if(w_deathtype & HITTYPE_SECONDARY)
+         return WEAPON_OVERKILL_HMG_MURDER_SNIPE;
+     else
+         return WEAPON_OVERKILL_HMG_MURDER_SPRAY;
+ }
+ #endif
+ #ifdef CSQC
+ METHOD(OverkillHeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
+ {
+     vector org2;
+     org2 = w_org + w_backoff * 2;
+     pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+     if(!w_issilent)
+         sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+ }
+ #endif
index 0000000000000000000000000000000000000000,63c1e245b4ad1121cfbf593ac4e563da67c6b2b0..27502a75985dc28b90eb529ba3b787aec0fa3bdf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,156 +1,155 @@@
 -      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okmachinegun_spread, WEP_CVAR_PRI(okmachinegun, solidpenetration), WEP_CVAR_PRI(okmachinegun, damage), WEP_CVAR_PRI(okmachinegun, force), WEP_OVERKILL_MACHINEGUN.m_id, 0);
+ #include "okmachinegun.qh"
+ #ifdef SVQC
+ void W_OverkillMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+ {
+       float okmachinegun_spread;
+       if(!(fire & 1))
+       {
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity))
+       if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+       {
+               W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       W_DecreaseAmmo(WEP_OVERKILL_MACHINEGUN, actor, WEP_CVAR_PRI(okmachinegun, ammo), weaponentity);
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(okmachinegun, damage), WEP_OVERKILL_MACHINEGUN.m_id);
+       if(!autocvar_g_norecoil)
+       {
+               actor.punchangle_x = random() - 0.5;
+               actor.punchangle_y = random() - 0.5;
+       }
+       okmachinegun_spread = bound(WEP_CVAR_PRI(okmachinegun, spread_min), WEP_CVAR_PRI(okmachinegun, spread_min) + (WEP_CVAR_PRI(okmachinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR_PRI(okmachinegun, spread_max));
 -
++      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okmachinegun_spread, WEP_CVAR_PRI(okmachinegun, solidpenetration), WEP_CVAR_PRI(okmachinegun, damage), WEP_CVAR_PRI(okmachinegun, force), WEP_OVERKILL_MACHINEGUN.m_id, EFFECT_RIFLE);
+       actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+       W_MachineGun_MuzzleFlash(actor, weaponentity);
+       W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
+       if(autocvar_g_casings >= 2) // casing code
+       {
+               makevectors(actor.v_angle); // for some reason, this is lost
+               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, actor, weaponentity);
+       }
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okmachinegun, refire) * W_WeaponRateFactor(actor);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okmachinegun, refire), W_OverkillMachineGun_Attack_Auto);
+ }
+ METHOD(OverkillMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+ {
+       if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
+               PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+       else
+               PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ }
+ METHOD(OverkillMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+ {
+       if ((WEP_CVAR_SEC(okmachinegun, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(okmachinegun, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(okmachinegun, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+       if (WEP_CVAR(okmachinegun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okmachinegun, ammo))
+       {
+               // Forced reload
+               thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+               {
+                       return;
+               }
+               actor.(weaponentity).misc_bulletcounter = 0;
+               W_OverkillMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR_SEC(okmachinegun, refire_type) == 0)) // Secondary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(okmachinegun, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(okmachinegun, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okmachinegun, animtime), w_ready);
+       }
+ }
+ METHOD(OverkillMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+ {
+       float ammo_amount;
+       ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okmachinegun, ammo);
+       if (WEP_CVAR(okmachinegun, reload_ammo))
+       {
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR_PRI(okmachinegun, ammo);
+       }
+       return ammo_amount;
+ }
+ METHOD(OverkillMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+ {
+       return true; // Blaster secondary is unlimited.
+ }
+ METHOD(OverkillMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+ {
+       W_Reload(actor, weaponentity, WEP_CVAR_PRI(okmachinegun, ammo), SND_RELOAD);
+ }
+ METHOD(OverkillMachineGun, wr_suicidemessage, Notification(entity thiswep))
+ {
+       return WEAPON_THINKING_WITH_PORTALS;
+ }
+ METHOD(OverkillMachineGun, wr_killmessage, Notification(entity thiswep))
+ {
+       return WEAPON_OVERKILL_MACHINEGUN_MURDER;
+ }
+ #endif
+ #ifdef CSQC
+ METHOD(OverkillMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
+ {
+       vector org2;
+       org2 = w_org + w_backoff * 2;
+       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+       if(!w_issilent)
+               sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
+ }
+ #endif
index 83ed8cfda51d4608874c1145fe53dadcb689a645,619d7a9072d9a1e127e8e4698caa0c99bd8fc6f2..b3c5c5197d3cf02f4c1d7b7814a314c15b20eaa7
@@@ -11,13 -11,13 +11,13 @@@ METHOD(MachineGunTurretAttack, wr_think
      if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
          if (isPlayer) {
              turret_initparams(actor);
-             W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MachineGunTurretAttack_FIRE, CH_WEAPON_B, 0);
+             W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MachineGunTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_MACHINEGUN.m_id);
              actor.tur_shotdir_updated = w_shotdir;
              actor.tur_shotorg = w_shotorg;
              actor.tur_head = actor;
              weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
          }
 -        fireBullet (actor, weaponentity, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, 0);
 +        fireBullet(actor, weaponentity, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, EFFECT_RIFLE_WEAK);
          W_MachineGun_MuzzleFlash(actor, weaponentity);
          setattachment(actor.(weaponentity).muzzle_flash, actor.tur_head, "tag_fire");
      }
index c1e433aea7df12a6c1fa2db9a2b8d1511e8be802,d81b738ed4510b8565584752f76c50c785765471..121f15c62823b6abf891e7d225e92505ed9e4d7a
@@@ -9,14 -9,14 +9,14 @@@ METHOD(WalkerTurretAttack, wr_think, vo
      if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
          if (isPlayer) {
              turret_initparams(actor);
-             W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WalkerTurretAttack_FIRE, CH_WEAPON_B, 0);
+             W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WalkerTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_WALK_GUN.m_id);
              actor.tur_shotdir_updated = w_shotdir;
              actor.tur_shotorg = w_shotorg;
              actor.tur_head = actor;
              weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
          }
          sound (actor, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM);
 -        fireBullet (actor, weaponentity, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_WALK_GUN.m_id, 0);
 +        fireBullet(actor, weaponentity, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_WALK_GUN.m_id, EFFECT_RIFLE_WEAK);
          Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, actor.tur_shotorg, actor.tur_shotdir_updated * 1000, 1);
      }
  }
index 8d782f927ff7de9a3010efcc4d6a24cf9c2b6ecf,09d0eb2af9175c6012b0a903677483e2e7c6d0cc..5a69976effc905965c50480e25440094babb9c81
@@@ -63,7 -63,7 +63,7 @@@ bool spiderbot_frame(entity this, floa
                .entity weaponentity = weaponentities[slot];
                this.(weaponentity).m_switchweapon = WEP_Null;
        }
-       this.vehicle_weapon2mode = vehic.vehicle_weapon2mode;
+       STAT(VEHICLESTAT_W2MODE, this) = STAT(VEHICLESTAT_W2MODE, vehic);
  
  
  #if 1 // 0 to enable per-gun impact aux crosshairs
  
                        .entity weaponentity = weaponentities[0]; // TODO: unhardcode
                        fireBullet(this, weaponentity, v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_solidpenetration,
 -                              autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_VH_SPID_MINIGUN.m_id, 0);
 +                              autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_VH_SPID_MINIGUN.m_id, EFFECT_RIFLE_WEAK);
  
                        sound (gun, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM);
                        //trailparticles(this, _particleeffectnum("spiderbot_minigun_trail"), v, trace_endpos);
@@@ -449,7 -449,7 +449,7 @@@ void spiderbot_blowup(entity this
        SUB_SetFade(g1, time, min(this.respawntime, 10));
        SUB_SetFade(g2, time, min(this.respawntime, 10));
  
-       RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_SPID_DEATH.m_id, NULL);
+       RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_SPID_DEATH.m_id, DMG_NOWEP, NULL);
  
        this.alpha = this.tur_head.alpha = this.gun1.alpha = this.gun2.alpha = -1;
        set_movetype(this, MOVETYPE_NONE);
@@@ -464,37 -464,37 +464,37 @@@ bool spiderbot_impulse(entity this, in
        switch(_imp)
        {
                case IMP_weapon_group_1.impulse:
-                       this.vehicle.vehicle_weapon2mode = SBRM_VOLLY;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_VOLLY;
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_group_2.impulse:
-                       this.vehicle.vehicle_weapon2mode = SBRM_GUIDE;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_GUIDE;
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_group_3.impulse:
-                       this.vehicle.vehicle_weapon2mode = SBRM_ARTILLERY;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_ARTILLERY;
                        CSQCVehicleSetup(this, 0);
                        return true;
  
                case IMP_weapon_next_byid.impulse:
                case IMP_weapon_next_bypriority.impulse:
                case IMP_weapon_next_bygroup.impulse:
-                       this.vehicle.vehicle_weapon2mode += 1;
-                       if(this.vehicle.vehicle_weapon2mode > SBRM_LAST)
-                               this.vehicle.vehicle_weapon2mode = SBRM_FIRST;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) += 1;
+                       if(STAT(VEHICLESTAT_W2MODE, this.vehicle) > SBRM_LAST)
+                               STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_FIRST;
  
-                       //centerprint(this, strcat("Rocket mode is ", ftos(this.vehicle.vehicle_weapon2mode)));
+                       //centerprint(this, strcat("Rocket mode is ", ftos(STAT(VEHICLESTAT_W2MODE, this.vehicle))));
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_last.impulse:
                case IMP_weapon_prev_byid.impulse:
                case IMP_weapon_prev_bypriority.impulse:
                case IMP_weapon_prev_bygroup.impulse:
-                       this.vehicle.vehicle_weapon2mode -= 1;
-                       if(this.vehicle.vehicle_weapon2mode < SBRM_FIRST)
-                               this.vehicle.vehicle_weapon2mode = SBRM_LAST;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) -= 1;
+                       if(STAT(VEHICLESTAT_W2MODE, this.vehicle) < SBRM_FIRST)
+                               STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_LAST;
  
-                       //centerprint(this, strcat("Rocket mode is ", ftos(this.vehicle.vehicle_weapon2mode)));
+                       //centerprint(this, strcat("Rocket mode is ", ftos(STAT(VEHICLESTAT_W2MODE, this.vehicle))));
                        CSQCVehicleSetup(this, 0);
                        return true;
  
@@@ -521,7 -521,7 +521,7 @@@ METHOD(Spiderbot, vr_impact, void(Spide
  }
  METHOD(Spiderbot, vr_enter, void(Spiderbot thisveh, entity instance))
  {
-     instance.vehicle_weapon2mode = SBRM_GUIDE;
+     STAT(VEHICLESTAT_W2MODE, instance) = SBRM_GUIDE;
      set_movetype(instance, MOVETYPE_WALK);
      CSQCVehicleSetup(instance.owner, 0);
      instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_spiderbot_health) * 100;
@@@ -540,7 -540,7 +540,7 @@@ METHOD(Spiderbot, vr_think, void(Spider
  }
  METHOD(Spiderbot, vr_death, void(Spiderbot thisveh, entity instance))
  {
-     instance.health                           = 0;
+       SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
      instance.event_damage             = func_null;
      instance.takedamage                       = DAMAGE_NO;
      settouch(instance, func_null);
index 294d556379205c3f7423a81e39f0cd0d1632aabd,6319dc36ae3ba04b6c5324e6bb6743e547b47e86..bc51577c9c018661f9fbf6a896605e825e22eb95
@@@ -50,7 -50,7 +50,7 @@@ void W_MachineGun_MuzzleFlash(entity ac
  
  void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity weaponentity)
  {
-       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)), deathtype);
        if(!autocvar_g_norecoil)
        {
                actor.punchangle_x = random() - 0.5;
@@@ -61,9 -61,9 +61,9 @@@
        ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor);
  
        if(actor.(weaponentity).misc_bulletcounter == 1)
 -              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, 0);
 +              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, EFFECT_RIFLE_WEAK);
        else
 -              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, sustained_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), deathtype, 0);
 +              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, sustained_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), deathtype, EFFECT_RIFLE_WEAK);
  
        Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
  
@@@ -86,7 -86,7 +86,7 @@@
  // weapon frames
  void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
  {
-       if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon) // abort immediately if switching
+       if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon || !weapon_prepareattack_check(thiswep, actor, weaponentity, (fire & 2), -1)) // abort immediately if switching
        {
                w_ready(thiswep, actor, weaponentity, fire);
                return;
@@@ -113,7 -113,7 +113,7 @@@ void W_MachineGun_Attack_Auto(Weapon th
  {
        float machinegun_spread;
  
-       if(!(fire & 1))
+       if(!(fire & 1) || !weapon_prepareattack_check(thiswep, actor, weaponentity, false, -1))
        {
                w_ready(thiswep, actor, weaponentity, fire);
                return;
  
        W_DecreaseAmmo(WEP_MACHINEGUN, actor, WEP_CVAR(machinegun, sustained_ammo), weaponentity);
  
-       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage), WEP_MACHINEGUN.m_id);
        if(!autocvar_g_norecoil)
        {
                actor.punchangle_x = random() - 0.5;
        }
  
        machinegun_spread = bound(WEP_CVAR(machinegun, spread_min), WEP_CVAR(machinegun, spread_min) + (WEP_CVAR(machinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(machinegun, spread_max));
 -      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, machinegun_spread, WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, 0);
 +      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, machinegun_spread, WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, EFFECT_RIFLE_WEAK);
  
        actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
  
  
  void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentity, int fire)
  {
-       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage), WEP_MACHINEGUN.m_id);
        if(!autocvar_g_norecoil)
        {
                actor.punchangle_x = random() - 0.5;
                actor.punchangle_y = random() - 0.5;
        }
  
 -      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, burst_speed), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, 0);
 +      fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, burst_speed), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, EFFECT_RIFLE_WEAK);
  
        Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
  
index f713200eee5cb0343bd9c311f6dcae79082109be,d6996042dc56967ebf02c29a946329ea40ce4323..b96fa35831c0095baf37399663968e4e75e7597f
@@@ -8,7 -8,7 +8,7 @@@ void W_Rifle_FireBullet(Weapon thiswep
  
        W_DecreaseAmmo(thiswep, actor, pAmmo, weaponentity);
  
-       W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots);
+       W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots, deathtype);
  
        Send_Effect(EFFECT_RIFLE_MUZZLEFLASH, w_shotorg, w_shotdir * 2000, 1);
  
@@@ -19,7 -19,7 +19,7 @@@
        }
  
        for(i = 0; i < pShots; ++i)
 -              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, pSpread, pSolidPenetration, pDamage, pForce, deathtype, (pTracer ? EF_RED : EF_BLUE));
 +              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, pSpread, pSolidPenetration, pDamage, pForce, deathtype, (pTracer ? EFFECT_RIFLE : EFFECT_RIFLE_WEAK));
  
        if(autocvar_g_casings >= 2)
      {
@@@ -159,7 -159,11 +159,11 @@@ METHOD(Rifle, wr_checkammo2, bool(entit
  }
  METHOD(Rifle, wr_resetplayer, void(entity thiswep, entity actor))
  {
-     actor.rifle_accumulator = time - WEP_CVAR(rifle, bursttime);
+     for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+     {
+         .entity weaponentity = weaponentities[slot];
+         actor.(weaponentity).rifle_accumulator = time - WEP_CVAR(rifle, bursttime);
+     }
  }
  METHOD(Rifle, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
  {
@@@ -223,5 -227,9 +227,9 @@@ METHOD(Rifle, wr_zoom, bool(entity this
          return false;
      }
  }
+ METHOD(Rifle, wr_zoomdir, bool(entity thiswep))
+ {
+     return button_attack2 && !WEP_CVAR(rifle, secondary);
+ }
  
  #endif
index 5429b35417a7f2afb4b20bb57cecb65f6e4e6c97,4acceed7184c924af8ffca37017fe3b8794191b4..fe465e52848bf34d739c8a650bdda87436c8c8a1
@@@ -2,15 -2,16 +2,16 @@@
  
  #ifdef SVQC
  
- void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary)
+ void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary, float ammocount, float damage, float bullets, float spread, float solidpenetration, float force)
  {
-       W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo), weaponentity);
+       W_DecreaseAmmo(thiswep, actor, ammocount, weaponentity);
  
-       W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets));
-       for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
-               fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, EFFECT_RIFLE_WEAK);
+       W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), damage * bullets, WEP_SHOTGUN.m_id);
+       for(int sc = 0;sc < bullets;sc = sc + 1)
 -              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, WEP_SHOTGUN.m_id, 0);
++              fireBullet(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, WEP_SHOTGUN.m_id, EFFECT_RIFLE_WEAK);
  
-       Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo));
+       Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, ammocount);
  
        // casing code
        if(autocvar_g_casings >= 1)
@@@ -68,7 -69,7 +69,7 @@@ void W_Shotgun_Melee_Think(entity this
                        + (v_up * swing_factor * WEP_CVAR_SEC(shotgun, melee_swing_up))
                        + (v_right * swing_factor * WEP_CVAR_SEC(shotgun, melee_swing_side)));
  
-               WarpZone_traceline_antilag(this, this.realowner.origin + this.realowner.view_ofs, targpos, false, this.realowner, ((IS_CLIENT(this.realowner)) ? ANTILAG_LATENCY(this.realowner) : 0));
+               WarpZone_traceline_antilag(this.realowner, this.realowner.origin + this.realowner.view_ofs, targpos, false, this.realowner, ((IS_CLIENT(this.realowner)) ? ANTILAG_LATENCY(this.realowner) : 0));
  
                // draw lightning beams for debugging
                //te_lightning2(NULL, targpos, this.realowner.origin + this.realowner.view_ofs + v_forward * 5 - v_up * 5);
@@@ -77,7 -78,7 +78,7 @@@
                is_player = (IS_PLAYER(trace_ent) || trace_ent.classname == "body" || IS_MONSTER(trace_ent));
  
                if((trace_fraction < 1) // if trace is good, apply the damage and remove this
-                       && (trace_ent.takedamage == DAMAGE_AIM)
+                       && (trace_ent.takedamage != DAMAGE_NO)
                        && (trace_ent != this.swing_alreadyhit)
                        && (is_player || WEP_CVAR_SEC(shotgun, melee_nonplayerdamage)))
                {
@@@ -91,7 -92,7 +92,7 @@@
                        //print(strcat(this.realowner.netname, " hitting ", target_victim.netname, " with ", strcat(ftos(swing_damage), " damage (factor: ", ftos(swing_factor), ") at "), ftos(time), " seconds.\n"));
  
                        Damage(target_victim, this.realowner, this.realowner,
-                               swing_damage, WEP_SHOTGUN.m_id | HITTYPE_SECONDARY,
+                               swing_damage, WEP_SHOTGUN.m_id | HITTYPE_SECONDARY, this.weaponentity_fld,
                                this.realowner.origin + this.realowner.view_ofs,
                                v_forward * WEP_CVAR_SEC(shotgun, force));
  
@@@ -136,7 -137,8 +137,8 @@@ void W_Shotgun_Attack2(Weapon thiswep, 
        meleetemp.realowner = actor;
        setthink(meleetemp, W_Shotgun_Melee_Think);
        meleetemp.nextthink = time + WEP_CVAR_SEC(shotgun, melee_delay) * W_WeaponRateFactor(actor);
-       W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR_SEC(shotgun, damage), WEP_CVAR_SEC(shotgun, melee_range));
+       meleetemp.weaponentity_fld = weaponentity;
+       W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR_SEC(shotgun, damage), WEP_CVAR_SEC(shotgun, melee_range), WEP_SHOTGUN.m_id | HITTYPE_SECONDARY);
  }
  
  // alternate secondary weapon frames
@@@ -151,7 -153,13 +153,13 @@@ void W_Shotgun_Attack3_Frame2(Weapon th
        }
  
        sound(actor, CH_WEAPON_SINGLE, SND_Null, VOL_BASE, ATTN_NORM); // kill previous sound
-       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, true); // actually is secondary, but we trick the last shot into playing full reload sound
+       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, true,
+               WEP_CVAR_PRI(shotgun, ammo),
+               WEP_CVAR_PRI(shotgun, damage),
+               WEP_CVAR_PRI(shotgun, bullets),
+               WEP_CVAR_PRI(shotgun, spread),
+               WEP_CVAR_PRI(shotgun, solidpenetration),
+               WEP_CVAR_PRI(shotgun, force)); // actually is secondary, but we trick the last shot into playing full reload sound
        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
  }
  void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
                return;
        }
  
-       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, false);
+       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, false,
+               WEP_CVAR_PRI(shotgun, ammo),
+               WEP_CVAR_PRI(shotgun, damage),
+               WEP_CVAR_PRI(shotgun, bullets),
+               WEP_CVAR_PRI(shotgun, spread),
+               WEP_CVAR_PRI(shotgun, solidpenetration),
+               WEP_CVAR_PRI(shotgun, force));
        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
  }
  
@@@ -177,6 -191,7 +191,7 @@@ METHOD(Shotgun, wr_aim, void(entity thi
      else
          PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
  }
  METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
  {
      if(WEP_CVAR(shotgun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload
              {
                  if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(shotgun, animtime)))
                  {
-                     W_Shotgun_Attack(thiswep, actor, weaponentity, true);
+                     W_Shotgun_Attack(thiswep, actor, weaponentity, true,
+                                               WEP_CVAR_PRI(shotgun, ammo),
+                                               WEP_CVAR_PRI(shotgun, damage),
+                                               WEP_CVAR_PRI(shotgun, bullets),
+                                               WEP_CVAR_PRI(shotgun, spread),
+                                               WEP_CVAR_PRI(shotgun, solidpenetration),
+                                               WEP_CVAR_PRI(shotgun, force));
                      actor.(weaponentity).shotgun_primarytime = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor(actor);
                      weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
                  }
              {
                  if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
                  {
-                     W_Shotgun_Attack(thiswep, actor, weaponentity, false);
+                     W_Shotgun_Attack(thiswep, actor, weaponentity, false,
+                                               WEP_CVAR_PRI(shotgun, ammo),
+                                               WEP_CVAR_PRI(shotgun, damage),
+                                               WEP_CVAR_PRI(shotgun, bullets),
+                                               WEP_CVAR_PRI(shotgun, spread),
+                                               WEP_CVAR_PRI(shotgun, solidpenetration),
+                                               WEP_CVAR_PRI(shotgun, force));
                      actor.(weaponentity).shotgun_primarytime = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor(actor);
                      weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
                  }
index 4be26497a628c480050d01b8a3bd60f732f34b7d,ddf1ff26248066b0fa719c18ab543802fc866d4b..5d35166aa6167d27e4af3bf0e519b52221f4a222
@@@ -8,7 -8,6 +8,6 @@@
  #include "weaponsystem.qh"
  
  #include "../g_damage.qh"
- #include "../g_subs.qh"
  #include "../antilag.qh"
  
  #include <common/constants.qh>
  // this function calculates w_shotorg and w_shotdir based on the weapon model
  // offset, trueaim and antilag, and won't put w_shotorg inside a wall.
  // make sure you call makevectors first (FIXME?)
- void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range)
+ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range, int deathtype)
  {
        TC(Sound, snd);
        float nudge = 1; // added to traceline target and subtracted from result  TOOD(divVerent): do we still need this? Doesn't the engine do this now for us?
        float oldsolid = ent.dphitcontentsmask;
+       Weapon wep = DEATH_WEAPONOF(deathtype);
        if(!IS_CLIENT(ent))
                antilag = false; // no antilag for non-clients!
-       if (IS_PLAYER(ent) && (ent.(weaponentity).m_weapon.spawnflags & WEP_FLAG_PENETRATEWALLS))
+       if (IS_PLAYER(ent) && (wep.spawnflags & WEP_FLAG_PENETRATEWALLS))
                ent.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE;
        else
                ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
  
        // track max damage
        if (IS_PLAYER(ent) && accuracy_canbegooddamage(ent))
-               accuracy_add(ent, ent.(weaponentity).m_weapon.m_id, maxdamage, 0);
+               accuracy_add(ent, wep.m_id, maxdamage, 0);
  
        if(IS_PLAYER(ent))
-               W_HitPlotAnalysis(ent, weaponentity, v_forward, v_right, v_up);
+               W_HitPlotAnalysis(ent, wep, v_forward, v_right, v_up);
  
        vector md = ent.(weaponentity).movedir;
        vector vecs = ((md.x > 0) ? md : '0 0 0');
                tracebox(w_shotorg, mi, ma, w_shotorg + v_forward * (vecs.x + nudge), MOVE_NORMAL, ent);
        w_shotorg = trace_endpos - v_forward * nudge;
        // calculate the shotdir from the chosen shotorg
-       w_shotdir = normalize(w_shotend - w_shotorg);
+       if(W_DualWielding(ent))
+               w_shotdir = s_forward;
+       else
+               w_shotdir = normalize(w_shotend - w_shotorg);
  
        //vector prevdir = w_shotdir;
        //vector prevorg = w_shotorg;
                ent.punchangle_x = recoil * -1;
  
        if (snd != SND_Null) {
-               int held_weapons = 0; // HACK: muffle weapon sounds slightly while dual wielding!
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       .entity wep_ent = weaponentities[slot];
-                       if(ent.(wep_ent) && ent.(wep_ent).m_switchweapon != WEP_Null)
-                               ++held_weapons;
-               }
-               sound (ent, chan, snd, ((held_weapons > 1) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM);
+               sound (ent, chan, snd, (W_DualWielding(ent) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM);
                W_PlayStrengthSound(ent);
        }
  
@@@ -310,7 -306,7 +306,7 @@@ void FireRailgunBullet (entity this, .e
  
                // apply the damage
                if (it.takedamage)
-                       Damage (it, this, this, bdamage * foff, deathtype, hitloc, it.railgunforce * ffs);
+                       Damage (it, this, this, bdamage * foff, deathtype, weaponentity, hitloc, it.railgunforce * ffs);
  
                // create a small explosion to throw gibs around (if applicable)
                //setorigin(explosion, hitloc);
@@@ -340,7 -336,7 +336,7 @@@ void fireBullet_trace_callback(vector s
        fireBullet_last_hit = NULL;
  }
  
 -void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects)
 +void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, entity tracer_effects)
  {
        vector  end;
  
        end = start + dir * max_shot_distance;
  
        fireBullet_last_hit = NULL;
 +      fireBullet_trace_callback_eff = tracer_effects;
 +
        float solid_penetration_left = 1;
        float total_damage = 0;
  
 -      if(tracereffects & EF_RED)
 -              fireBullet_trace_callback_eff = EFFECT_RIFLE;
 -      else if(tracereffects & EF_BLUE)
 -              fireBullet_trace_callback_eff = EFFECT_RIFLE_WEAK;
 -      else
 -              fireBullet_trace_callback_eff = EFFECT_BULLET;
 -
        float lag = ((IS_REAL_CLIENT(this)) ? ANTILAG_LATENCY(this) : 0);
        if(lag < 0.001)
                lag = 0;
                        yoda = 0;
                        MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage, this.(weaponentity));
                        damage = M_ARGV(4, float);
-                       float g = accuracy_isgooddamage(this, hit);
-                       Damage(hit, this, this, damage * solid_penetration_left, dtype, start, force * dir * solid_penetration_left);
+                       bool gooddamage = accuracy_isgooddamage(this, hit);
+                       Damage(hit, this, this, damage * solid_penetration_left, dtype, weaponentity, start, force * dir * solid_penetration_left);
                        // calculate hits for ballistic weapons
-                       if(g)
+                       if(gooddamage)
                        {
                                // do not exceed 100%
                                float added_damage = min(damage - total_damage, damage * solid_penetration_left);
index e6c4a0041239a5123e750859bc84e79eaa982e96,9224a970cf7b8cdfacf25edb582eb5b8adb75d54..37284ffc3d3a9d59112a55c4a17f0674dc183d6a
@@@ -10,13 -10,13 +10,13 @@@ vector w_shotend
  // this function calculates w_shotorg and w_shotdir based on the weapon model
  // offset, trueaim and antilag, and won't put w_shotorg inside a wall.
  // make sure you call makevectors first (FIXME?)
- void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range);
+ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range, int deathtype);
  
- #define W_SetupShot_Dir_ProjectileSize(ent,wepent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, max_shot_distance)
- #define W_SetupShot_ProjectileSize(ent,wepent,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, wepent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage)
- #define W_SetupShot_Dir(ent,wepent,s_forward,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, wepent, s_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
- #define W_SetupShot(ent,wepent,antilag,recoil,snd,chan,maxdamage) W_SetupShot_ProjectileSize(ent, wepent, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
- #define W_SetupShot_Range(ent,wepent,antilag,recoil,snd,chan,maxdamage,range) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, v_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, range)
+ #define W_SetupShot_Dir_ProjectileSize(ent,wepent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, max_shot_distance, deathtype)
+ #define W_SetupShot_ProjectileSize(ent,wepent,mi,ma,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_Dir_ProjectileSize(ent, wepent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, deathtype)
+ #define W_SetupShot_Dir(ent,wepent,s_forward,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_Dir_ProjectileSize(ent, wepent, s_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, deathtype)
+ #define W_SetupShot(ent,wepent,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_ProjectileSize(ent, wepent, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, deathtype)
+ #define W_SetupShot_Range(ent,wepent,antilag,recoil,snd,chan,maxdamage,range,deathtype) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, v_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, range, deathtype)
  
  vector W_CalculateProjectileVelocity(entity actor, vector pvelocity, vector mvelocity, float forceAbsolute);
  
@@@ -57,4 -57,4 +57,4 @@@ void FireRailgunBullet (entity this, .e
  entity fireBullet_trace_callback_eff;
  entity fireBullet_last_hit;
  void fireBullet_trace_callback(vector start, vector hit, vector end);
 -void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects);
 +void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, entity tracer_effects);