]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'Mario/rifle_arena' into Mario/mutators
authorMario <mario.mario@y7mail.com>
Tue, 11 Jun 2013 04:58:46 +0000 (14:58 +1000)
committerMario <mario.mario@y7mail.com>
Tue, 11 Jun 2013 04:58:46 +0000 (14:58 +1000)
1  2 
mutators.cfg
qcsrc/client/projectile.qc
qcsrc/common/notifications.qh
qcsrc/server/autocvars.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_freezetag.qc
qcsrc/server/mutators/mutator_nades.qc
qcsrc/server/mutators/mutator_riflearena.qc
qcsrc/server/mutators/mutators.qh
qcsrc/server/progs.src

diff --cc mutators.cfg
index 054a32c0ae5653c94ad431354da9e733585f2c73,0000000000000000000000000000000000000000..b3e8ab94b5cef55d55464997df1c8b19c26e5f96
mode 100644,000000..100644
--- /dev/null
@@@ -1,147 -1,0 +1,158 @@@
 +// =========================
 +//  Config for all mutators
 +// =========================
 +
 +
 +// =========
 +//  dodging
 +// =========
 +set g_dodging 0 "set to 1 to enable dodging in games"
 +
 +seta cl_dodging_timeout 0.2 "determines how long apart (in seconds) two taps on the same direction key are considered a dodge. use 0 to disable"
 +
 +set sv_dodging_wall_dodging 0 "set to 1 to allow dodging off walls. 0 to disable"
 +set sv_dodging_delay 0.5 "determines how long a player has to wait to be able to dodge again after dodging"
 +set sv_dodging_up_speed 200 "the jump velocity of the dodge"
 +set sv_dodging_horiz_speed 400 "the horizontal velocity of the dodge"
 +set sv_dodging_ramp_time 0.1 "a ramp so that the horizontal part of the dodge is added smoothly (seconds)"
 +set sv_dodging_height_threshold 10 "the maximum height above ground where to allow dodging"
 +set sv_dodging_wall_distance_threshold 10 "the maximum distance from a wall that still allows dodging"
 +set sv_dodging_sound 1 "if 1 dodging makes a sound. if 0 dodging is silent"
 +
 +
 +// ===========
 +//  minstagib
 +// ===========
 +set g_minstagib 0 "enable minstagib"
 +set g_minstagib_extralives 1 "how many extra lives you will get per powerup"
 +set g_minstagib_ammo_start 10 "starting ammo"
 +set g_minstagib_ammo_drop 5 "how much ammo you'll get for weapons or cells"
 +set g_minstagib_invis_alpha 0.15
 +set g_minstagib_speed_highspeed 1.5 "speed-multiplier that applies while you carry the invincibility powerup"
 +
 +
 +// =========
 +//  vampire
 +// =========
 +set g_vampire 0 "set to 1 to enable the vampire mode, where the damage done to your opponent gets added to your own health"
 +
 +
 +// =========
 +//  sandbox
 +// =========
 +set g_sandbox 0 "allow players to spawn and edit objects around the map"
 +set g_sandbox_info 1 "print object information to the server. 1 prints info about spawned / removed objects, 2 also prints info about edited objects"
 +set g_sandbox_readonly 0 "when this mode is active, players cannot modify objects or use any sandbox commands"
 +set g_sandbox_storage_name default "name of the selected storage to use"
 +set g_sandbox_storage_autosave 5 "storage is automatically saved every specified number of seconds"
 +set g_sandbox_storage_autoload 1 "if a storage file exists for the given map, automatically load it at startup"
 +set g_sandbox_editor_flood 1 "players must wait this many seconds between spawning objects"
 +set g_sandbox_editor_maxobjects 1000 "maximum number of objects that may exist at a time"
 +set g_sandbox_editor_free 1 "0 = players can only copy or edit their own objects, 1 = players can copy but not edit other objects, 2 = players can copy and edit all object"
 +set g_sandbox_editor_distance_spawn 200 "distance at which objects spawn in front of the player"
 +set g_sandbox_editor_distance_edit 300 "distance at which players can edit or remove objects they are looking at"
 +set g_sandbox_object_scale_min 0.1 "minimum scale that objects can be set to"
 +set g_sandbox_object_scale_max 2 "maximum scale that objects can be set to"
 +set g_sandbox_object_material_velocity_min 100 "velocity objects must have while colliding for material effects to be applied"
 +set g_sandbox_object_material_velocity_factor 0.002 "velocity range which decides the intensity of material effects"
 +set cl_sandbox_clipboard ""
 +
 +
 +// ========================
 +//  invincible projectiles
 +// ========================
 +set g_invincible_projectiles 0 "set to 1 to disable any damage to projectiles in all balance configs, regardless of g_projectiles_damage"
 +
 +
 +// ===============
 +//  rocket flying
 +// ===============
 +set g_rocket_flying 0 "set to 1 to enable rocket flying in all balance configs"
 +
 +
 +// =====================
 +//  spawn near teammate
 +// =====================
 +set g_spawn_near_teammate 0 "if set, players prefer spawns near a team mate"
 +set g_spawn_near_teammate_distance 640 "max distance to consider a spawn to be near a team mate"
 +
 +
 +// ========================
 +//  NIX (No Items Xonotic)
 +// ========================
 +// at each time, everyone uses the same weapon,
 +// and in regular intervals, this weapon is cycled
 +set g_nix 0 "No Items Xonotic - instead of pickup items, everyone plays with the same weapon. After some time, a countdown will start, after which everyone will switch to another weapon, and so on"
 +set g_nix_with_laser 0 "always carry the laser as an additional weapon in NIX"
 +set g_nix_with_healtharmor 0 "when 1, health and armor still show up in NIX"
 +set g_nix_with_powerups 0 "when 1, powerups still show up in NIX"
 +
 +
 +// ================
 +//  physical items
 +// ================
 +set g_physical_items 0 "1 uses ODE physics for dropped weapons, 2 for all items, requires physics_ode to be enabled"
 +set g_physical_items_damageforcescale 3 "how affected physical weapons are by damage"
 +set g_physical_items_reset 1 "return map items to their original lotation after being picked up"
 +
 +
 +// ===============
 +//  touch explode
 +// ===============
 +set g_touchexplode 0 "touching other players causes an explosion"
 +set g_touchexplode_radius 50
 +set g_touchexplode_damage 10
 +set g_touchexplode_edgedamage 0
 +set g_touchexplode_force 150
 +
 +
 +// ================
 +//  super spectate
 +// ================
 +set g_superspectate 0 "server side, allows extended spectator functions through the cmd interface. followpowerup, followstrength, followstshield or followfc [red|blue] will transfer spectation to the relevent player, if any"
 +
 +
 +// ==================
 +//  melee only arena
 +// ==================
 +set g_melee_only 0 "enable melee only arena"
 +
 +
 +// ================
 +//  random gravity
 +// ================
 +set g_random_gravity 0 "enable random gravity mutator"
 +set g_random_gravity_delay 3 "delay between gravity changes"
 +set g_random_gravity_negative_chance 0.5 "chance of gravity being a negative value"
 +set g_random_gravity_min -2000 "minimum gravity"
 +set g_random_gravity_max 2000 "maximum gravity"
 +set g_random_gravity_positive 1000 "positive gravity multiplier"
 +set g_random_gravity_negative 1000 "negative gravity multiplier"
 +
 +
 +// =======
 +//  nades
 +// =======
 +set g_nades 0 "enable off-hand grenades"
 +set g_nades_spawn 1 "give nades right away when player spawns rather than delaying entire refire"
 +set g_nades_nade_lifetime 3.5
 +set g_nades_nade_minforce 400
 +set g_nades_nade_maxforce 2000
 +set g_nades_nade_health 25
 +set g_nades_nade_refire 6
 +set g_nades_nade_damage 225
 +set g_nades_nade_edgedamage 90
 +set g_nades_nade_radius 300
 +set g_nades_nade_force 650
 +set g_nades_nade_newton_style 0
++
++
++// =============
++//  rifle arena
++// =============
++set g_riflearena 0
++set g_riflearena_rifle_secondary_spread 0
++set g_riflearena_rifle_secondary_shots 1
++set g_riflearena_rifle_secondary_animtime 0.15
++set g_riflearena_rifle_secondary_refire 0.15
++set g_riflearena_rifle_secondary_damage 40
Simple merge
index 5767432225423b3baaadf822f2112119d5e75878,d85c1911e0415f728b8465a03a33da372bface8b..853b717443cb8cc3e2c4d37d4e77d5ef51eaf9e1
@@@ -476,7 -475,7 +476,7 @@@ void Send_Notification_WOVA
        MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_FIRE,             0, 0, "",             NO_CPID,             "0 0", _("^K1You got a little bit too crispy!"), _("^K1You felt a little too hot!")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_GENERIC,          0, 0, "",             NO_CPID,             "0 0", _("^K1You killed your own dumb self!"), _("^K1You need to be more careful!")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_LAVA,             0, 0, "",             NO_CPID,             "0 0", _("^K1You couldn't stand the heat!"), "") \
-       MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE,                             0, 0, "",                         NO_CPID,                     "0 0", _("^K1You forgot to put the pin back in!"), _("^K1Try throwing the nade!")) \
 -      MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE,                             0, 0, "",                         NO_CPID,                         "0 0", _("^K1You ate your own grenade!"), _("^K1Tastes like chicken!")) \
++      MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE,                             0, 0, "",                         NO_CPID,                         "0 0", _("^K1You forgot to put the pin back in!"), _("^K1Tastes like chicken!")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NOAMMO,           0, 0, "",             NO_CPID,             "0 0", _("^K1You were killed for running out of ammo..."), _("^K1You are respawning for running out of ammo...")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_ROT,              0, 0, "",             NO_CPID,             "0 0", _("^K1You grew too old without taking your medicine"), _("^K1You need to preserve your health")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SHOOTING_STAR,    0, 0, "",             NO_CPID,             "0 0", _("^K1You became a shooting star!"), "") \
Simple merge
index 6e8b5d16a4170ff81d6fe2cb068e4e088bcdf3a3,b0aa2c12dd5884b0d8280b9b105f74ce310e9ec4..8489c8a46dca54ca444cc84ab60288755e0978c8
@@@ -915,17 -919,8 +915,18 @@@ void readlevelcvars(void
        CHECK_MUTATOR_ADD("g_rocket_flying", mutator_rocketflying, !cvar("g_minstagib"));
        CHECK_MUTATOR_ADD("g_vampire", mutator_vampire, !cvar("g_minstagib"));
        CHECK_MUTATOR_ADD("g_superspectate", mutator_superspec, 1);
 +      CHECK_MUTATOR_ADD("g_pinata", mutator_pinata, !cvar("g_minstagib"));
 +      CHECK_MUTATOR_ADD("g_midair", mutator_midair, 1);
 +      CHECK_MUTATOR_ADD("g_bloodloss", mutator_bloodloss, !cvar("g_minstagib"));
 +      CHECK_MUTATOR_ADD("g_random_gravity", mutator_random_gravity, 1);
 +      CHECK_MUTATOR_ADD("g_norecoil", mutator_norecoil, 1);
 +      CHECK_MUTATOR_ADD("g_multijump", mutator_multijump, 1);
 +      CHECK_MUTATOR_ADD("g_jump_grunt", mutator_jump_grunt, 1);
 +      CHECK_MUTATOR_ADD("g_footsteps", mutator_footsteps, 1);
 +      CHECK_MUTATOR_ADD("g_melee_only", mutator_melee_only, !cvar("g_minstagib"));
 +      CHECK_MUTATOR_ADD("g_nades", mutator_nades, 1);
        CHECK_MUTATOR_ADD("g_sandbox", sandbox, 1);
+     CHECK_MUTATOR_ADD("g_riflearena", mutator_riflearena, !cvar("g_minstagib"));
        
        #undef CHECK_MUTATOR_ADD
        
index 4466ccf53540ff3fd760959a28982b861ddb2850,0000000000000000000000000000000000000000..a7c0fea5116f424ab98e840e305ac55448781fc6
mode 100644,000000..100644
--- /dev/null
@@@ -1,405 -1,0 +1,405 @@@
-               return FALSE; // TODO: fix this to support all modes that don't disable weapon dropping
 +.entity nade;
 +.entity fake_nade;
 +.float nade_refire;
 +
 +void nade_timer_think()
 +{
 +      self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
 +      self.nextthink = time;
 +      if(!self.owner || wasfreed(self.owner))
 +              remove(self);
 +      
 +}
 +
 +void nade_burn_spawn(entity _nade)
 +{
 +      float p;
 +      
 +      switch(_nade.realowner.team)
 +      {
 +              case NUM_TEAM_1: p = PROJECTILE_NADE_RED_BURN; break;
 +              case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE_BURN; break;
 +              case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW_BURN; break;
 +              case NUM_TEAM_4: p = PROJECTILE_NADE_PINK_BURN; break;
 +              default:                 p = PROJECTILE_NADE_BURN; break;
 +      }
 +      
 +      CSQCProjectile(_nade, TRUE, p, TRUE);
 +}
 +
 +void nade_spawn(entity _nade)
 +{
 +      float p;
 +      entity timer = spawn();
 +      setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3");
 +      setattachment(timer, _nade, "");
 +      timer.classname = "nade_timer";
 +      timer.colormap = _nade.colormap;
 +      timer.glowmod = _nade.glowmod;
 +      timer.think = nade_timer_think;
 +      timer.nextthink = time;
 +      timer.wait = _nade.wait;
 +      timer.owner = _nade;    
 +      timer.skin = 10;
 +      
 +      switch(_nade.realowner.team)
 +      {
 +              case NUM_TEAM_1: p = PROJECTILE_NADE_RED; break;
 +              case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE; break;
 +              case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW; break;
 +              case NUM_TEAM_4: p = PROJECTILE_NADE_PINK; break;
 +              default:                 p = PROJECTILE_NADE; break;
 +      }
 +      
 +      CSQCProjectile(_nade, TRUE, p, TRUE);
 +      
 +}
 +
 +void nade_boom() // TODO: DamageInfo
 +{
 +      string expef;
 +      
 +      switch(self.realowner.team)
 +      {
 +              case NUM_TEAM_1: expef = "nade_red_explode"; break;
 +              case NUM_TEAM_2: expef = "nade_blue_explode"; break;
 +              case NUM_TEAM_3: expef = "nade_yellow_explode"; break;
 +              case NUM_TEAM_4: expef = "nade_pink_explode"; break;
 +              default:                 expef = "nade_explode"; break;
 +      }
 +      
 +      sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTN_NORM);
 +      sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
 +      pointparticles(particleeffectnum(expef), self.origin + '0 0 1', '0 0 0', 1);
 +
 +      self.takedamage = DAMAGE_NO;
 +      RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
 +                               autocvar_g_nades_nade_radius, self, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
 +
 +      remove(self);
 +}
 +
 +void nade_touch()
 +{
 +      PROJECTILE_TOUCH;
 +      //setsize(self, '-2 -2 -2', '2 2 2');
 +      //UpdateCSQCProjectile(self);
 +      if(self.health == autocvar_g_nades_nade_health)
 +      {
 +              spamsound(self, CH_SHOTS, strcat("weapons/grenade_bounce", ftos(1 + rint(random() * 5)), ".wav"), VOL_BASE, ATTN_NORM);
 +              return;
 +      }
 +
 +      self.enemy = other;
 +      nade_boom();
 +}
 +
 +void nade_beep()
 +{
 +      sound(self, CH_SHOTS_SINGLE, "overkill/grenadebip.ogg", VOL_BASE, 0.5 *(ATTN_LARGE + ATTN_MAX));
 +      self.think = nade_boom;
 +      self.nextthink = max(self.wait, time);
 +}
 +
 +void nade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 +{
 +      if(DEATH_ISWEAPON(deathtype, WEP_LASER))
 +              return;
 +
 +      if(DEATH_ISWEAPON(deathtype, WEP_NEX) || DEATH_ISWEAPON(deathtype, WEP_MINSTANEX))
 +      {
 +              force *= 6;
 +              damage = autocvar_g_nades_nade_health * 0.55;
 +      }
 +
 +      if(DEATH_ISWEAPON(deathtype, WEP_UZI))
 +              damage = autocvar_g_nades_nade_health * 0.1;
 +
 +      if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && !(deathtype & HITTYPE_SECONDARY))
 +              damage = autocvar_g_nades_nade_health * 1.1;
 +              
 +      if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && (deathtype & HITTYPE_SECONDARY))
 +      {
 +              damage = autocvar_g_nades_nade_health * 0.1;
 +              force *= 15;
 +      }
 +      
 +      self.velocity += force;
 +
 +      if(!damage)
 +              return;
 +
 +      if(self.health == autocvar_g_nades_nade_health)
 +      {
 +              sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, 0.5 *(ATTN_LARGE + ATTN_MAX));
 +              self.nextthink = max(time + autocvar_g_nades_nade_lifetime, time);
 +              self.think = nade_beep;
 +      }
 +
 +      self.health   -= damage;
 +      self.realowner = attacker;
 +
 +      if(self.health <= 0)
 +              W_PrepareExplosionByDamage(attacker, nade_boom);
 +      else
 +              nade_burn_spawn(self);
 +}
 +
 +void toss_nade(entity e, vector _velocity, float _time)
 +{
 +      entity _nade = e.nade;
 +      e.nade = world;
 +      
 +      remove(e.fake_nade);
 +      e.fake_nade = world;
 +      
 +      makevectors(e.v_angle);
 +      
 +      W_SetupShot(e, FALSE, FALSE, "", CH_WEAPON_A, 0);
 +      
 +      Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
 +      
 +      //setorigin(_nade, CENTER_OR_VIEWOFS(e) + (v_right * 10) * -1);
 +      setorigin(_nade, w_shotorg + (v_right * 10) * -1);
 +      setmodel(_nade, "models/weapons/v_ok_grenade.md3");
 +      setattachment(_nade, world, "");
 +      PROJECTILE_MAKETRIGGER(_nade);
 +      setsize(_nade, '-16 -16 -16', '16 16 16');
 +      _nade.movetype = MOVETYPE_BOUNCE;
 +      
 +      tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, FALSE, _nade);
 +      if (trace_startsolid)
 +              setorigin(_nade, e.origin);
 +      
 +      if(e.crouch)
 +              _nade.velocity = '0 0 -10';
 +      else if(autocvar_g_nades_nade_newton_style == 1)
 +              _nade.velocity = e.velocity + _velocity;
 +      else if(autocvar_g_nades_nade_newton_style == 2)
 +              _nade.velocity = _velocity;
 +      else
 +              _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, TRUE);
 +
 +      //_nade.solid = SOLID_BBOX; // TODO: remember why this was needed
 +      _nade.touch = nade_touch;
 +      _nade.health = autocvar_g_nades_nade_health;
 +      _nade.takedamage = DAMAGE_AIM;
 +      _nade.event_damage = nade_damage;
 +      _nade.teleportable = TRUE;
 +      _nade.pushable = TRUE;
 +      _nade.gravity = 1;
 +      _nade.missile_flags = MIF_SPLASH | MIF_ARC;
 +      _nade.damagedbycontents = TRUE;
 +      _nade.angles = vectoangles(_nade.velocity);
 +      _nade.flags = FL_PROJECTILE;
 +
 +      nade_spawn(_nade);
 +
 +      if(_time)
 +      {
 +              _nade.think = nade_boom;
 +              _nade.nextthink = _time;
 +      }
 +
 +      e.nade_refire = time + autocvar_g_nades_nade_refire;
 +}
 +
 +void nade_prime()
 +{
 +      if(self.nade)
 +              remove(self.nade);
 +              
 +      if(self.fake_nade)
 +              remove(self.fake_nade);
 +      
 +      self.nade = spawn();
 +      setmodel(self.nade, "null");
 +      setattachment(self.nade, self, "bip01 l hand");
 +      self.nade.classname = "nade";
 +      self.nade.realowner = self;
 +      self.nade.colormap = self.colormap;
 +      self.nade.glowmod = self.glowmod;
 +      self.nade.wait = time + autocvar_g_nades_nade_lifetime;
 +      self.nade.lifetime = time;
 +      self.nade.think = nade_beep;
 +      self.nade.nextthink = max(self.nade.wait - 3, time);
 +      self.nade.projectiledeathtype = DEATH_NADE;
 +
 +      self.fake_nade = spawn();
 +      setmodel(self.fake_nade, "models/weapons/h_ok_grenade.iqm");
 +      setattachment(self.fake_nade, self.weaponentity, "");
 +      self.fake_nade.classname = "fake_nade";
 +      //self.fake_nade.viewmodelforclient = self;
 +      self.fake_nade.realowner = self.fake_nade.owner = self;
 +      self.fake_nade.colormap = self.colormap;
 +      self.fake_nade.glowmod = self.glowmod;
 +      self.fake_nade.think = SUB_Remove;
 +      self.fake_nade.nextthink = self.nade.wait;
 +}
 +
 +float CanThrowNade()
 +{
 +      if(self.vehicle)
 +              return FALSE;
 +              
 +      if(gameover)
 +              return FALSE;
 +              
 +      if(self.deadflag != DEAD_NO)
 +              return FALSE;
 +      
 +      if not(autocvar_g_nades)
 +              return FALSE; // allow turning them off mid match
 +              
 +      if(forbidWeaponUse())
 +              return FALSE;
 +              
 +      if not(IS_PLAYER(self))
 +              return FALSE;
 +              
 +      return TRUE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_ForbidThrowing)
 +{
 +      if(!g_weaponarena || !g_minstagib)
++              return FALSE; // TODO: fix this to support all modes that disable weapon dropping
 +              
 +      if(!CanThrowNade())
 +              return FALSE;
 +              
 +      if(!self.nade)
 +      {
 +              if(self.nade_refire < time)
 +              {
 +                      Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW);
 +                      nade_prime();
 +                      self.nade_refire = time + autocvar_g_nades_nade_refire;
 +              }
 +      }
 +      else
 +      {
 +              if(time - self.nade.lifetime >= 1)
 +              {
 +                      makevectors(self.v_angle);
 +                      float _force = time - self.nade.lifetime;
 +                      _force /= autocvar_g_nades_nade_lifetime;
 +                      _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
 +                      toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
 +              }
 +      }
 +      
 +      return TRUE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_VehicleEnter)
 +{
 +      if(other.nade)
 +              toss_nade(other, '0 0 100', max(other.nade.wait, time + 0.05));
 +      
 +      return FALSE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_PlayerPreThink)
 +{
 +      float key_pressed = ((g_grappling_hook || client_hasweapon(self, WEP_HOOK, FALSE, FALSE) || WEPSET_CONTAINS_AW(weaponsInMap, WEP_HOOK)) ? self.button16 : self.BUTTON_HOOK);
 +      
 +      if(self.nade)
 +              if(self.nade.wait - 0.1 <= time)
 +                      toss_nade(self, '0 0 0', time + 0.05);
 +                      
 +      if(CanThrowNade())
 +      if(self.nade_refire < time)
 +      {
 +              if(key_pressed)
 +              {
 +                      if(!self.nade)
 +                              nade_prime();
 +              }
 +              else if(time - self.nade.lifetime >= 1)
 +              {
 +                      if(self.nade)
 +                      {
 +                              makevectors(self.v_angle);
 +                              float _force = time - self.nade.lifetime;
 +                              _force /= autocvar_g_nades_nade_lifetime;
 +                              _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));                         
 +                              toss_nade(self, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
 +                      }
 +              }
 +      }
 +
 +      return FALSE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_PlayerSpawn)
 +{
 +      if(autocvar_g_nades_spawn)
 +              self.nade_refire = time + autocvar_g_spawnshieldtime;
 +      else
 +              self.nade_refire  = time + autocvar_g_nades_nade_refire;
 +
 +      return FALSE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_PlayerDies)
 +{
 +      if(self.nade)
 +              toss_nade(self, '0 0 100', max(self.nade.wait, time + 0.05));
 +              
 +      return FALSE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_RemovePlayer)
 +{
 +      if(self.nade)
 +              remove(self.nade);
 +
 +      if(self.fake_nade)
 +              remove(self.fake_nade);
 +              
 +      return FALSE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_BuildMutatorsString)
 +{
 +      ret_string = strcat(ret_string, ":Nades");
 +      return FALSE;
 +}
 +
 +MUTATOR_HOOKFUNCTION(nades_BuildMutatorsPrettyString)
 +{
 +      ret_string = strcat(ret_string, ", Nades");
 +      return FALSE;
 +}
 +
 +MUTATOR_DEFINITION(mutator_nades)
 +{
 +      MUTATOR_HOOK(ForbidThrowCurrentWeapon, nades_ForbidThrowing, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(VehicleEnter, nades_VehicleEnter, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(PlayerPreThink, nades_PlayerPreThink, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(PlayerSpawn, nades_PlayerSpawn, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(PlayerDies, nades_PlayerDies, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(MakePlayerObserver, nades_RemovePlayer, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(ClientDisconnect, nades_RemovePlayer, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(BuildMutatorsString, nades_BuildMutatorsString, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(BuildMutatorsPrettyString, nades_BuildMutatorsPrettyString, CBC_ORDER_ANY);
 +      
 +      MUTATOR_ONADD
 +      {
 +              precache_model("models/ok_nade_counter/ok_nade_counter.md3");
 +              
 +              precache_model("models/weapons/h_ok_grenade.iqm");
 +              precache_model("models/weapons/v_ok_grenade.md3");
 +              precache_sound("weapons/rocket_impact.wav");
 +              precache_sound("weapons/grenade_bounce1.wav");
 +              precache_sound("weapons/grenade_bounce2.wav");
 +              precache_sound("weapons/grenade_bounce3.wav");
 +              precache_sound("weapons/grenade_bounce4.wav");
 +              precache_sound("weapons/grenade_bounce5.wav");
 +              precache_sound("weapons/grenade_bounce6.wav");
 +              precache_sound("overkill/grenadebip.ogg");
 +      }
 +
 +      return FALSE;
 +}
index 0000000000000000000000000000000000000000,540f70d35bb079c79adfe6b5567a44b49c523b2c..b1a65f4699b6eba49c8552e82a6f7a7df9ac901b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,408 +1,119 @@@
 -.entity ra_nade;
 -.float ra_nade_refire;
 -
 -float ra_CanThrowNade()
 -{
 -      if(self.vehicle)
 -              return FALSE;
 -              
 -      if(gameover)
 -              return FALSE;
 -              
 -      if(self.deadflag)
 -              return FALSE;
 -              
 -      if not(IS_PLAYER(self))
 -              return FALSE;
 -              
 -      if not(autocvar_g_riflearena_nades)
 -              return FALSE;
 -              
 -      if(forbidWeaponUse())
 -              return FALSE;
 -              
 -      return TRUE;
 -}
 -
 -void ra_nade_timer_think()
 -{
 -      self.skin = 8 - (self.owner.wait - time) / (autocvar_g_riflearena_nade_lifetime / 10);
 -      self.nextthink = time;
 -      if(!self.owner || wasfreed(self.owner))
 -              remove(self);
 -      
 -}
 -
 -void ra_nade_burn_spawn(entity nade)
 -{
 -      switch(nade.realowner.team)
 -      {
 -              case NUM_TEAM_1:
 -                      CSQCProjectile(nade, TRUE, PROJECTILE_NADE_RED_BURN, TRUE);
 -                      break;
 -              case NUM_TEAM_2:
 -                      CSQCProjectile(nade, TRUE, PROJECTILE_NADE_BLUE_BURN, TRUE);
 -                      break;
 -              default:
 -                      CSQCProjectile(nade, TRUE, PROJECTILE_NADE_RED_BURN, TRUE);
 -                      break;
 -      }
 -}
 -
 -void ra_nade_spawn(entity nade)
 -{
 -      entity timer = spawn();
 -      setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3");
 -      setattachment(timer, nade, "");
 -      timer.classname = "nade_timer";
 -      timer.colormap = nade.colormap;
 -      timer.glowmod = nade.glowmod;
 -      timer.think = ra_nade_timer_think;
 -      timer.nextthink = time;
 -      timer.wait = nade.wait;
 -      timer.owner = nade;     
 -      timer.skin = 10;
 -      
 -      CSQCProjectile(nade, TRUE, ((nade.realowner.team == NUM_TEAM_2) ? PROJECTILE_NADE_BLUE: PROJECTILE_NADE_RED) , TRUE);
 -      
 -}
 -
 -void ra_nade_boom() // TODO: DamageInfo
 -{
 -      sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTN_NORM);
 -      sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
 -      pointparticles(particleeffectnum((self.realowner.team == NUM_TEAM_2) ? "nade_blue_explode" : "nade_red_explode"), self.origin + '0 0 1', '0 0 0', 1);
 -
 -
 -      self.takedamage = DAMAGE_NO;
 -      RadiusDamage(self, self.realowner, autocvar_g_riflearena_nade_damage, autocvar_g_riflearena_nade_edgedamage,
 -                               autocvar_g_riflearena_nade_radius, self, autocvar_g_riflearena_nade_force, self.projectiledeathtype, self.enemy);
 -
 -      remove(self);
 -}
 -
 -void ra_nade_touch()
 -{
 -      PROJECTILE_TOUCH;
 -      setsize(self, '-2 -2 -2', '2 2 2');
 -      UpdateCSQCProjectile(self);
 -      if(self.health == autocvar_g_riflearena_nade_health)
 -      {
 -              spamsound(self, CH_SHOTS, strcat("weapons/grenade_bounce", ftos(1 + rint(random() * 5)), ".wav"), VOL_BASE, ATTN_NORM);
 -              return;
 -      }
 -
 -      self.enemy = other;
 -      ra_nade_boom();
 -}
 -
 -void ra_nade_beep()
 -{
 -      sound(self, CH_SHOTS_SINGLE, "overkill/grenadebip.wav", VOL_BASE, 0.5 *(ATTN_LARGE + ATTN_MAX));
 -      self.think = ra_nade_boom;
 -      self.nextthink = max(self.wait, time);
 -}
 -
 -void ra_nade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 -{
 -      if(DEATH_ISWEAPON(deathtype, WEP_LASER))
 -              return;
 -      
 -      self.velocity += force;
 -
 -      if(!damage)
 -              return;
 -
 -      if(self.health == autocvar_g_riflearena_nade_health)
 -      {
 -              sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, 0.5 *(ATTN_LARGE + ATTN_MAX));
 -              self.nextthink = max(time + autocvar_g_riflearena_nade_lifetime, time);
 -              self.think = ra_nade_beep;
 -      }
 -
 -      self.health   -= damage;
 -      self.realowner = attacker;
 -
 -      if(self.health <= 0)
 -              W_PrepareExplosionByDamage(attacker, ra_nade_boom);
 -      else
 -              ra_nade_burn_spawn(self);
 -}
 -
 -void ra_toss_nade(entity ent, vector _velocity, float _time)
 -{
 -      entity _nade = ent.ra_nade;
 -      ent.ra_nade = world;
 -      
 -      setorigin(_nade, gettaginfo(_nade, gettagindex(_nade, "Object001")));
 -      setattachment(_nade, world, "");
 -      PROJECTILE_MAKETRIGGER(_nade);
 -      setsize(_nade, '-16 -16 -16', '16 16 16');
 -      _nade.movetype = MOVETYPE_BOUNCE;
 -      
 -      if(ent.crouch)
 -              _nade.velocity = '0 0 -10';
 -      else if(autocvar_g_riflearena_nade_newton_style == 1)
 -              _nade.velocity = ent.velocity + _velocity;
 -      else if(autocvar_g_riflearena_nade_newton_style == 2)
 -              _nade.velocity = _velocity;
 -      else
 -              _nade.velocity = W_CalculateProjectileVelocity(ent.velocity, _velocity, FALSE);
 -
 -      _nade.solid = SOLID_BBOX;
 -      _nade.touch = ra_nade_touch;
 -      _nade.health = autocvar_g_riflearena_nade_health;
 -      _nade.takedamage = DAMAGE_YES;
 -      _nade.event_damage = ra_nade_damage;
 -      _nade.teleportable = TRUE;
 -
 -      ra_nade_spawn(_nade);
 -
 -      if(_time)
 -      {
 -              _nade.think = ra_nade_boom;
 -              _nade.nextthink = _time;
 -      }
 -      else
 -              _nade.projectiledeathtype = DEATH_NADE_NORMAL;
 -
 -      ent.ra_nade_refire = time + autocvar_g_riflearena_nade_refire;
 -}
 -
 -void ra_nade_prime()
 -{
 -      if(self.ra_nade)
 -              remove(self.ra_nade);
 -      
 -      self.ra_nade = spawn();
 -      setmodel(self.ra_nade, "models/weapons/h_ok_grenade.iqm");
 -      setattachment(self.ra_nade, self.weaponentity, "");
 -      self.ra_nade.classname = "nade";
 -      self.ra_nade.realowner = self;
 -      self.ra_nade.colormap = self.colormap;
 -      self.ra_nade.glowmod = self.glowmod;
 -      self.ra_nade.wait = time + autocvar_g_riflearena_nade_lifetime;
 -      self.ra_nade.cnt = time;
 -      self.ra_nade.think = ra_nade_beep;
 -      self.ra_nade.nextthink = max(self.ra_nade.wait - 3, time);
 -      self.ra_nade.projectiledeathtype = DEATH_NADE_NORMAL;
 -}
 -
+ void ra_SetCvars()
+ {
+       cvar_settemp("g_balance_rifle_secondary_spread", ftos(cvar("g_riflearena_rifle_secondary_spread")));
+       cvar_settemp("g_balance_rifle_secondary_shots", ftos(cvar("g_riflearena_rifle_secondary_shots")));
+       cvar_settemp("g_balance_rifle_secondary_animtime", ftos(cvar("g_riflearena_rifle_secondary_animtime")));
+       cvar_settemp("g_balance_rifle_secondary_refire", ftos(cvar("g_riflearena_rifle_secondary_refire")));
+       cvar_settemp("g_balance_rifle_secondary_damage", ftos(cvar("g_riflearena_rifle_secondary_damage")));
+ }
 -MUTATOR_HOOKFUNCTION(ra_VehicleEnter)
 -{
 -      if(other.ra_nade)
 -              ra_toss_nade(other, '0 0 100', max(other.ra_nade.wait, time + 0.05));
 -              
 -      return FALSE;
 -}
 -
+ MUTATOR_HOOKFUNCTION(ra_PlayerDamage)
+ {
+       if(IS_PLAYER(frag_attacker))
+       if(IS_PLAYER(frag_target))
+       {
+               if (DEATH_ISWEAPON(frag_deathtype, WEP_LASER))
+               {
+                       if(frag_attacker == frag_target)
+                               frag_damage = 5;
+                       else
+                               frag_damage = 0;
+                       if (frag_target != frag_attacker)
+                       {
+                               if (frag_target.health >= 1 && IS_PLAYER(frag_target))
+                                       centerprint(frag_attacker, "Laser inflicts no damage!");
+                               frag_force = '0 0 0';
+                       }
+               }
+       }
+               
+       return FALSE;
+ }
+ MUTATOR_HOOKFUNCTION(ra_PlayerSpawn)
+ {
+       WEPSET_CLEAR_E(self);
+       WEPSET_OR_EW(self, WEP_RIFLE);
+       WEPSET_OR_EW(self, WEP_LASER);
+       
 -      self.ra_nade_refire = time + 2;
 -      
+       return FALSE;
+ }
+ MUTATOR_HOOKFUNCTION(ra_FilterItem)
+ {
+       switch (self.items)
+       {
+               case IT_5HP:
+               case IT_ARMOR_SHARD:
+                       return FALSE;
+       }
+               
+       return TRUE;
+ }
 -MUTATOR_HOOKFUNCTION(ra_PlayerThink)
 -{
 -      if(self.ra_nade)
 -              if(self.ra_nade.wait - 0.1 <= time)
 -                      ra_toss_nade(self, '0 0 0', time + 0.05);
 -
 -      if(ra_CanThrowNade())
 -      if(self.ra_nade_refire < time)
 -      {
 -              if(self.BUTTON_HOOK)
 -              {
 -                      if(!self.ra_nade)
 -                              ra_nade_prime();
 -              }
 -              else if(time - self.ra_nade.cnt >= 1)
 -              {
 -                      if(self.ra_nade)
 -                      {
 -                              makevectors(self.v_angle);
 -                              float _force = time - self.ra_nade.cnt;
 -                              _force /= autocvar_g_riflearena_nade_lifetime;
 -                              _force = autocvar_g_riflearena_nade_minforce + (_force * (autocvar_g_riflearena_nade_maxforce - autocvar_g_riflearena_nade_minforce));                          
 -                              ra_toss_nade(self, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
 -                      }
 -              }
 -      }
 -      
 -      self.hasweapon_complain_spam = time + 5; // this isn't needed, so keep it off
 -      
 -      return FALSE;
 -}
 -
 -MUTATOR_HOOKFUNCTION(ra_RemovePlayer)
 -{
 -      if(self.ra_nade)
 -              remove(self.ra_nade);
 -              
 -      return FALSE;
 -}
 -
+ MUTATOR_HOOKFUNCTION(ra_StartItems)
+ {
+       start_items |= IT_UNLIMITED_AMMO;
+       start_ammo_nails = 100;
+       
+       g_grappling_hook = 0;
+       return FALSE;
+ }
 -MUTATOR_HOOKFUNCTION(ra_PlayerDies)
 -{
 -      if(self.ra_nade)
 -              ra_toss_nade(self, '0 0 100', max(self.ra_nade.wait, time + 0.05));
 -
 -      return 0;
 -}
 -
+ MUTATOR_HOOKFUNCTION(ra_ForbidThrowCurrentWeapon)
+ {
 -      if(!ra_CanThrowNade())
 -              return 1;
 -
 -      if(!self.ra_nade)
 -      {
 -              if(self.ra_nade_refire < time)
 -              {
 -                      Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE);
 -                      ra_nade_prime();
 -                      self.ra_nade_refire  = time + autocvar_g_riflearena_nade_refire;
 -              }
 -      }
 -      else
 -      {
 -              if(time - self.ra_nade.cnt >= 1)
 -              {
 -                      makevectors(self.v_angle);
 -                      float _force = time - self.ra_nade.cnt;
 -                      _force /= autocvar_g_riflearena_nade_lifetime;
 -                      _force = autocvar_g_riflearena_nade_minforce + (_force * (autocvar_g_riflearena_nade_maxforce - autocvar_g_riflearena_nade_minforce));
 -                      ra_toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
 -              }
 -      }
 -      return 1;
++      return TRUE;
+ }
+ MUTATOR_HOOKFUNCTION(ra_BuildMutatorsString)
+ {
+       ret_string = strcat(ret_string, ":RA");
 -      return 0;
++      return FALSE;
+ }
+ MUTATOR_HOOKFUNCTION(ra_BuildMutatorsPrettyString)
+ {
+       ret_string = strcat(ret_string, ", Rifle Arena");
 -      return 0;
++      return FALSE;
+ }
+ MUTATOR_HOOKFUNCTION(ra_SetModname)
+ {
+       modname = "Rifle Arena";
+       return TRUE;
+ }
+ MUTATOR_DEFINITION(mutator_riflearena)
+ {
 -      MUTATOR_HOOK(VehicleEnter, ra_VehicleEnter, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerDamage_Calculate, ra_PlayerDamage, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerSpawn, ra_PlayerSpawn, CBC_ORDER_ANY);
+       MUTATOR_HOOK(FilterItem, ra_FilterItem, CBC_ORDER_ANY);
+       MUTATOR_HOOK(SetStartItems, ra_StartItems, CBC_ORDER_ANY);
 -      MUTATOR_HOOK(MakePlayerObserver, ra_RemovePlayer, CBC_ORDER_ANY);
 -      MUTATOR_HOOK(ClientDisconnect, ra_RemovePlayer, CBC_ORDER_ANY);
 -      MUTATOR_HOOK(PlayerDies, ra_PlayerDies, CBC_ORDER_ANY);
 -      MUTATOR_HOOK(PlayerPreThink, ra_PlayerThink, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ForbidThrowCurrentWeapon, ra_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
+       MUTATOR_HOOK(BuildMutatorsString, ra_BuildMutatorsString, CBC_ORDER_ANY);
+       MUTATOR_HOOK(BuildMutatorsPrettyString, ra_BuildMutatorsPrettyString, CBC_ORDER_ANY);
+       
+       MUTATOR_ONADD
+       {
+               ra_SetCvars();
+               
 -              precache_model("models/ok_nade_counter/ok_nade_counter.md3");
 -              
 -              precache_model("models/weapons/h_ok_grenade.iqm");
 -              precache_model("models/weapons/v_ok_grenade.md3");
 -              precache_sound("weapons/rocket_impact.wav");
 -              precache_sound("weapons/grenade_bounce1.wav");
 -              precache_sound("weapons/grenade_bounce2.wav");
 -              precache_sound("weapons/grenade_bounce3.wav");
 -              precache_sound("weapons/grenade_bounce4.wav");
 -              precache_sound("weapons/grenade_bounce5.wav");
 -              precache_sound("weapons/grenade_bounce6.wav");
 -              precache_sound("overkill/grenadebip.wav");
 -              
+               weapon_action(WEP_LASER, WR_PRECACHE);
+               weapon_action(WEP_RIFLE, WR_PRECACHE);
+               
+               get_weaponinfo(WEP_HOOK).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+       
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               get_weaponinfo(WEP_HOOK).spawnflags &~= WEP_FLAG_MUTATORBLOCKED;
+       }
+       
+       MUTATOR_ONREMOVE
+       {
+               print("This cannot be removed at runtime\n");
+               return -1;
+       }
 -      return 0;
++      return FALSE;
+ }
index b3a3a4b34247918fe07f7dbf306b65c4892a8dd5,a6ace7b99fd6326788d860eabf2748eb2270d905..f6f79c73f8eec9fd179b2a3478ca05629e17e0d7
@@@ -21,15 -21,6 +21,16 @@@ MUTATOR_DECLARATION(mutator_vampire)
  MUTATOR_DECLARATION(mutator_superspec);
  MUTATOR_DECLARATION(mutator_minstagib);
  MUTATOR_DECLARATION(mutator_touchexplode);
 +MUTATOR_DECLARATION(mutator_pinata);
 +MUTATOR_DECLARATION(mutator_midair);
 +MUTATOR_DECLARATION(mutator_bloodloss);
 +MUTATOR_DECLARATION(mutator_random_gravity);
 +MUTATOR_DECLARATION(mutator_norecoil);
 +MUTATOR_DECLARATION(mutator_multijump);
 +MUTATOR_DECLARATION(mutator_jump_grunt);
 +MUTATOR_DECLARATION(mutator_footsteps);
 +MUTATOR_DECLARATION(mutator_melee_only);
 +MUTATOR_DECLARATION(mutator_nades);
+ MUTATOR_DECLARATION(mutator_riflearena);
  
  MUTATOR_DECLARATION(sandbox);
index 22514d748881fa9b90442d10d9ba934c04e7a7d3,8ce3adc7397b5e1d8d1f6c92d04c9016543efc69..a98580589ec3d0a4567a65149c33cd828d279f65
@@@ -248,16 -248,7 +248,17 @@@ mutators/sandbox.q
  mutators/mutator_superspec.qc
  mutators/mutator_minstagib.qc
  mutators/mutator_touchexplode.qc
 +mutators/mutator_pinata.qc
 +mutators/mutator_midair.qc
 +mutators/mutator_bloodloss.qc
 +mutators/mutator_random_gravity.qc
 +mutators/mutator_norecoil.qc
 +mutators/mutator_multijump.qc
 +mutators/mutator_jump_grunt.qc
 +mutators/mutator_footsteps.qc
 +mutators/mutator_melee_only.qc
 +mutators/mutator_nades.qc
+ mutators/mutator_riflearena.qc
  
  ../warpzonelib/anglestransform.qc
  ../warpzonelib/mathlib.qc