common: move instagib and nexball as they add custom items and weapons
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 11 Oct 2015 07:10:16 +0000 (18:10 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 11 Oct 2015 07:10:46 +0000 (18:10 +1100)
36 files changed:
qcsrc/client/progs.inc
qcsrc/client/view.qc
qcsrc/common/gamemodes/all.inc [new file with mode: 0644]
qcsrc/common/gamemodes/all.qc [new file with mode: 0644]
qcsrc/common/gamemodes/all.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/nexball/nexball.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/nexball/weapon.qc [new file with mode: 0644]
qcsrc/common/items/all.inc
qcsrc/common/items/all.qh
qcsrc/common/mutators/all.inc
qcsrc/common/mutators/all.qc
qcsrc/common/mutators/all.qh [new file with mode: 0644]
qcsrc/common/mutators/base.qh
qcsrc/common/mutators/mutator/casings.qc
qcsrc/common/mutators/mutator/damagetext.qc
qcsrc/common/mutators/mutator/instagib/instagib.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/instagib/items.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime.qc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/physics.qc
qcsrc/common/weapons/all.inc
qcsrc/common/weapons/all.qh
qcsrc/server/mutators/gamemode_nexball.qc [deleted file]
qcsrc/server/mutators/gamemode_nexball.qh [deleted file]
qcsrc/server/mutators/gamemode_nexball_weapon.qc [deleted file]
qcsrc/server/mutators/mutator_buffs.qc
qcsrc/server/mutators/mutator_instagib.qc [deleted file]
qcsrc/server/mutators/mutator_instagib_items.qc [deleted file]
qcsrc/server/mutators/mutator_nades.qc
qcsrc/server/mutators/mutators.qc
qcsrc/server/mutators/mutators.qh
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/mutators/mutators_include.qh
qcsrc/server/progs.inc
qcsrc/server/teamplay.qc

index 04eb788..61bd8b9 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "../common/buffs/all.qc"
 #include "../common/effects/all.qc"
+#include "../common/gamemodes/all.qc"
 #include "../common/items/all.qc"
 #include "../common/monsters/all.qc"
 #include "../common/mutators/all.qc"
index fad769d..4430c94 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "../common/constants.qh"
 #include "../common/mapinfo.qh"
+#include "../common/gamemodes/all.qh"
 #include "../common/nades/all.qh"
 #include "../common/stats.qh"
 #include "../common/triggers/target/music.qh"
diff --git a/qcsrc/common/gamemodes/all.inc b/qcsrc/common/gamemodes/all.inc
new file mode 100644 (file)
index 0000000..4c24beb
--- /dev/null
@@ -0,0 +1 @@
+#include "gamemode/nexball/nexball.qc"
diff --git a/qcsrc/common/gamemodes/all.qc b/qcsrc/common/gamemodes/all.qc
new file mode 100644 (file)
index 0000000..f0fc719
--- /dev/null
@@ -0,0 +1,5 @@
+#include "all.qh"
+
+#define IMPLEMENTATION
+#include "all.inc"
+#undef IMPLEMENTATION
diff --git a/qcsrc/common/gamemodes/all.qh b/qcsrc/common/gamemodes/all.qh
new file mode 100644 (file)
index 0000000..62ba616
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef GAMEMODES_ALL_H
+#define GAMEMODES_ALL_H
+
+#include "all.inc"
+
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc b/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
new file mode 100644 (file)
index 0000000..7958d66
--- /dev/null
@@ -0,0 +1,1051 @@
+#include "nexball.qh"
+
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+float autocvar_g_nexball_basketball_bouncefactor;
+float autocvar_g_nexball_basketball_bouncestop;
+float autocvar_g_nexball_basketball_carrier_highspeed;
+bool autocvar_g_nexball_basketball_meter;
+float autocvar_g_nexball_basketball_meter_maxpower;
+float autocvar_g_nexball_basketball_meter_minpower;
+float autocvar_g_nexball_delay_collect;
+float autocvar_g_nexball_delay_goal;
+float autocvar_g_nexball_delay_start;
+float autocvar_g_nexball_football_bouncefactor;
+float autocvar_g_nexball_football_bouncestop;
+bool autocvar_g_nexball_radar_showallplayers;
+bool autocvar_g_nexball_sound_bounce;
+int autocvar_g_nexball_trail_color;
+
+float autocvar_g_nexball_safepass_turnrate;
+float autocvar_g_nexball_safepass_maxdist;
+float autocvar_g_nexball_safepass_holdtime;
+float autocvar_g_nexball_viewmodel_scale;
+float autocvar_g_nexball_tackling;
+vector autocvar_g_nexball_viewmodel_offset;
+
+void basketball_touch();
+void football_touch();
+void ResetBall();
+const int NBM_NONE = 0;
+const int NBM_FOOTBALL = 2;
+const int NBM_BASKETBALL = 4;
+float nexball_mode;
+
+float OtherTeam(float t)  //works only if there are two teams on the map!
+{
+       entity e;
+       e = find(world, classname, "nexball_team");
+       if(e.team == t)
+               e = find(e, classname, "nexball_team");
+       return e.team;
+}
+
+const float ST_NEXBALL_GOALS = 1;
+const float SP_NEXBALL_GOALS = 4;
+const float SP_NEXBALL_FAULTS = 5;
+void nb_ScoreRules(float teams)
+{
+       ScoreRules_basics(teams, 0, 0, true);
+       ScoreInfo_SetLabel_TeamScore(   ST_NEXBALL_GOALS,  "goals", SFL_SORT_PRIO_PRIMARY);
+       ScoreInfo_SetLabel_PlayerScore( SP_NEXBALL_GOALS,  "goals", SFL_SORT_PRIO_PRIMARY);
+       ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
+       ScoreRules_basics_end();
+}
+
+void LogNB(string mode, entity actor)
+{
+       string s;
+       if(!autocvar_sv_eventlog)
+               return;
+       s = strcat(":nexball:", mode);
+       if(actor != world)
+               s = strcat(s, ":", ftos(actor.playerid));
+       GameLogEcho(s);
+}
+
+void ball_restart(void)
+{SELFPARAM();
+       if(self.owner)
+               DropBall(self, self.owner.origin, '0 0 0');
+       ResetBall();
+}
+
+void nexball_setstatus(void)
+{SELFPARAM();
+       self.items &= ~IT_KEY1;
+       if(self.ballcarried)
+       {
+               if(self.ballcarried.teamtime && (self.ballcarried.teamtime < time))
+               {
+                       bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
+                       setself(self.ballcarried);
+                       DropBall(self, self.owner.origin, '0 0 0');
+                       ResetBall();
+                       setself(this);
+               }
+               else
+                       self.items |= IT_KEY1;
+       }
+}
+
+void relocate_nexball(void)
+{SELFPARAM();
+       tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, true, self);
+       if(trace_startsolid)
+       {
+               vector o;
+               o = self.origin;
+               if(!move_out_of_solid(self))
+                       objerror("could not get out of solid at all!");
+               LOG_INFO("^1NOTE: this map needs FIXING. ", self.classname, " at ", vtos(o - '0 0 1'));
+               LOG_INFO(" needs to be moved out of solid, e.g. by '", ftos(self.origin.x - o.x));
+               LOG_INFO(" ", ftos(self.origin.y - o.y));
+               LOG_INFO(" ", ftos(self.origin.z - o.z), "'\n");
+               self.origin = o;
+       }
+}
+
+void DropOwner(void)
+{SELFPARAM();
+       entity ownr;
+       ownr = self.owner;
+       DropBall(self, ownr.origin, ownr.velocity);
+       makevectors(ownr.v_angle.y * '0 1 0');
+       ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
+       ownr.flags &= ~FL_ONGROUND;
+}
+
+void GiveBall(entity plyr, entity ball)
+{SELFPARAM();
+       entity ownr;
+
+       if((ownr = ball.owner))
+       {
+               ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
+               ownr.ballcarried = world;
+               if(ownr.metertime)
+               {
+                       ownr.metertime = 0;
+                       ownr.weaponentity.state = WS_READY;
+               }
+               WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
+       }
+       else
+       {
+               WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
+       }
+
+       //setattachment(ball, plyr, "");
+       setorigin(ball, plyr.origin + plyr.view_ofs);
+
+       if(ball.team != plyr.team)
+               ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam;
+
+       ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
+       ball.team = plyr.team;
+       plyr.ballcarried = ball;
+       ball.nb_dropper = plyr;
+
+       plyr.effects |= autocvar_g_nexball_basketball_effects_default;
+       ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
+
+       ball.velocity = '0 0 0';
+       ball.movetype = MOVETYPE_NONE;
+       ball.touch = func_null;
+       ball.effects |= EF_NOSHADOW;
+       ball.scale = 1; // scale down.
+
+       WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
+       WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+
+       if(autocvar_g_nexball_basketball_delay_hold)
+       {
+               ball.think = DropOwner;
+               ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
+       }
+
+       plyr.weaponentity.weapons = plyr.weapons;
+       plyr.weaponentity.switchweapon = plyr.weapon;
+       plyr.weapons = WEPSET(NEXBALL);
+       setself(plyr);
+       Weapon w = WEP_NEXBALL;
+       w.wr_resetplayer(w);
+       plyr.switchweapon = WEP_NEXBALL.m_id;
+       W_SwitchWeapon(WEP_NEXBALL.m_id);
+       setself(this);
+}
+
+void DropBall(entity ball, vector org, vector vel)
+{
+       ball.effects |= autocvar_g_nexball_basketball_effects_default;
+       ball.effects &= ~EF_NOSHADOW;
+       ball.owner.effects &= ~autocvar_g_nexball_basketball_effects_default;
+
+       setattachment(ball, world, "");
+       setorigin(ball, org);
+       ball.movetype = MOVETYPE_BOUNCE;
+       ball.flags &= ~FL_ONGROUND;
+       ball.scale = ball_scale;
+       ball.velocity = vel;
+       ball.nb_droptime = time;
+       ball.touch = basketball_touch;
+       ball.think = ResetBall;
+       ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
+
+       if(ball.owner.metertime)
+       {
+               ball.owner.metertime = 0;
+               ball.owner.weaponentity.state = WS_READY;
+       }
+
+       WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
+       WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
+       WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+
+       ball.owner.ballcarried = world;
+       ball.owner = world;
+}
+
+void InitBall(void)
+{SELFPARAM();
+       if(gameover) return;
+       self.flags &= ~FL_ONGROUND;
+       self.movetype = MOVETYPE_BOUNCE;
+       if(self.classname == "nexball_basketball")
+               self.touch = basketball_touch;
+       else if(self.classname == "nexball_football")
+               self.touch = football_touch;
+       self.cnt = 0;
+       self.think = ResetBall;
+       self.nextthink = time + autocvar_g_nexball_delay_idle + 3;
+       self.teamtime = 0;
+       self.pusher = world;
+       self.team = false;
+       _sound(self, CH_TRIGGER, self.noise1, VOL_BASE, ATTEN_NORM);
+       WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);
+       LogNB("init", world);
+}
+
+void ResetBall(void)
+{SELFPARAM();
+       if(self.cnt < 2)        // step 1
+       {
+               if(time == self.teamtime)
+                       bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
+
+               self.touch = func_null;
+               self.movetype = MOVETYPE_NOCLIP;
+               self.velocity = '0 0 0'; // just in case?
+               if(!self.cnt)
+                       LogNB("resetidle", world);
+               self.cnt = 2;
+               self.nextthink = time;
+       }
+       else if(self.cnt < 4)     // step 2 and 3
+       {
+//             dprint("Step ", ftos(self.cnt), ": Calculated velocity: ", vtos(self.spawnorigin - self.origin), ", time: ", ftos(time), "\n");
+               self.velocity = (self.spawnorigin - self.origin) * (self.cnt - 1); // 1 or 0.5 second movement
+               self.nextthink = time + 0.5;
+               self.cnt += 1;
+       }
+       else     // step 4
+       {
+//             dprint("Step 4: time: ", ftos(time), "\n");
+               if(vlen(self.origin - self.spawnorigin) > 10)  // should not happen anymore
+                       LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
+                                  vtos(self.origin - self.spawnorigin), " Velocity: ", vtos(self.velocity), "\n");
+               self.velocity = '0 0 0';
+               setorigin(self, self.spawnorigin); // make sure it's positioned correctly anyway
+               self.movetype = MOVETYPE_NONE;
+               self.think = InitBall;
+               self.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
+       }
+}
+
+void football_touch(void)
+{SELFPARAM();
+       if(other.solid == SOLID_BSP)
+       {
+               if(time > self.lastground + 0.1)
+               {
+                       _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+                       self.lastground = time;
+               }
+               if(vlen(self.velocity) && !self.cnt)
+                       self.nextthink = time + autocvar_g_nexball_delay_idle;
+               return;
+       }
+       if (!IS_PLAYER(other))
+               return;
+       if(other.health < 1)
+               return;
+       if(!self.cnt)
+               self.nextthink = time + autocvar_g_nexball_delay_idle;
+
+       self.pusher = other;
+       self.team = other.team;
+
+       if(autocvar_g_nexball_football_physics == -1)   // MrBougo try 1, before decompiling Rev's original
+       {
+               if(vlen(other.velocity))
+                       self.velocity = other.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
+       }
+       else if(autocvar_g_nexball_football_physics == 1)         // MrBougo's modded Rev style: partially independant of the height of the aiming point
+       {
+               makevectors(other.v_angle);
+               self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
+       }
+       else if(autocvar_g_nexball_football_physics == 2)         // 2nd mod try: totally independant. Really playable!
+       {
+               makevectors(other.v_angle.y * '0 1 0');
+               self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+       }
+       else     // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
+       {
+               makevectors(other.v_angle);
+               self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+       }
+       self.avelocity = -250 * v_forward;  // maybe there is a way to make it look better?
+}
+
+void basketball_touch(void)
+{SELFPARAM();
+       if(other.ballcarried)
+       {
+               football_touch();
+               return;
+       }
+       if(!self.cnt && IS_PLAYER(other) && !other.frozen && !other.deadflag && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
+       {
+               if(other.health <= 0)
+                       return;
+               LogNB("caught", other);
+               GiveBall(other, self);
+       }
+       else if(other.solid == SOLID_BSP)
+       {
+               _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+               if(vlen(self.velocity) && !self.cnt)
+                       self.nextthink = min(time + autocvar_g_nexball_delay_idle, self.teamtime);
+       }
+}
+
+void GoalTouch(void)
+{SELFPARAM();
+       entity ball;
+       float isclient, pscore, otherteam;
+       string pname;
+
+       if(gameover) return;
+       if((self.spawnflags & GOAL_TOUCHPLAYER) && other.ballcarried)
+               ball = other.ballcarried;
+       else
+               ball = other;
+       if(ball.classname != "nexball_basketball")
+               if(ball.classname != "nexball_football")
+                       return;
+       if((!ball.pusher && self.team != GOAL_OUT) || ball.cnt)
+               return;
+       EXACTTRIGGER_TOUCH;
+
+
+       if(nb_teams == 2)
+               otherteam = OtherTeam(ball.team);
+       else
+               otherteam = 0;
+
+       if((isclient = IS_CLIENT(ball.pusher)))
+               pname = ball.pusher.netname;
+       else
+               pname = "Someone (?)";
+
+       if(ball.team == self.team)               //owngoal (regular goals)
+       {
+               LogNB("owngoal", ball.pusher);
+               bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
+               pscore = -1;
+       }
+       else if(self.team == GOAL_FAULT)
+       {
+               LogNB("fault", ball.pusher);
+               if(nb_teams == 2)
+                       bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
+               else
+                       bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
+               pscore = -1;
+       }
+       else if(self.team == GOAL_OUT)
+       {
+               LogNB("out", ball.pusher);
+               if((self.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
+                       bprint(pname, "^7 went out of bounds.\n");
+               else
+                       bprint("The ball was returned.\n");
+               pscore = 0;
+       }
+       else                                                       //score
+       {
+               LogNB(strcat("goal:", ftos(self.team)), ball.pusher);
+               bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
+               pscore = 1;
+       }
+
+       _sound(ball, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NONE);
+
+       if(ball.team && pscore)
+       {
+               if(nb_teams == 2 && pscore < 0)
+                       TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
+               else
+                       TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
+       }
+       if(isclient)
+       {
+               if(pscore > 0)
+                       PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore);
+               else if(pscore < 0)
+                       PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore);
+       }
+
+       if(ball.owner)  // Happens on spawnflag GOAL_TOUCHPLAYER
+               DropBall(ball, ball.owner.origin, ball.owner.velocity);
+
+       WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
+
+       ball.cnt = 1;
+       ball.think = ResetBall;
+       if(ball.classname == "nexball_basketball")
+               ball.touch = football_touch; // better than func_null: football control until the ball gets reset
+       ball.nextthink = time + autocvar_g_nexball_delay_goal * (self.team != GOAL_OUT);
+}
+
+//=======================//
+//        team ents       //
+//=======================//
+spawnfunc(nexball_team)
+{
+       if(!g_nexball)
+       {
+               remove(self);
+               return;
+       }
+       self.team = self.cnt + 1;
+}
+
+void nb_spawnteam(string teamname, float teamcolor)
+{
+       LOG_TRACE("^2spawned team ", teamname, "\n");
+       entity e;
+       e = spawn();
+       e.classname = "nexball_team";
+       e.netname = teamname;
+       e.cnt = teamcolor;
+       e.team = e.cnt + 1;
+       nb_teams += 1;
+}
+
+void nb_spawnteams(void)
+{
+       bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
+       entity e;
+       for(e = world; (e = find(e, classname, "nexball_goal"));)
+       {
+               switch(e.team)
+               {
+               case NUM_TEAM_1:
+                       if(!t_red)
+                       {
+                               nb_spawnteam("Red", e.team-1)   ;
+                               t_red = true;
+                       }
+                       break;
+               case NUM_TEAM_2:
+                       if(!t_blue)
+                       {
+                               nb_spawnteam("Blue", e.team-1)  ;
+                               t_blue = true;
+                       }
+                       break;
+               case NUM_TEAM_3:
+                       if(!t_yellow)
+                       {
+                               nb_spawnteam("Yellow", e.team-1);
+                               t_yellow = true;
+                       }
+                       break;
+               case NUM_TEAM_4:
+                       if(!t_pink)
+                       {
+                               nb_spawnteam("Pink", e.team-1)  ;
+                               t_pink = true;
+                       }
+                       break;
+               }
+       }
+}
+
+void nb_delayedinit(void)
+{
+       if(find(world, classname, "nexball_team") == world)
+               nb_spawnteams();
+       nb_ScoreRules(nb_teams);
+}
+
+
+//=======================//
+//       spawnfuncs       //
+//=======================//
+
+void SpawnBall(void)
+{SELFPARAM();
+       if(!g_nexball) { remove(self); return; }
+
+//     balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
+
+       if(self.model == "")
+       {
+               self.model = "models/nexball/ball.md3";
+               self.scale = 1.3;
+       }
+
+       precache_model(self.model);
+       _setmodel(self, self.model);
+       setsize(self, BALL_MINS, BALL_MAXS);
+       ball_scale = self.scale;
+
+       relocate_nexball();
+       self.spawnorigin = self.origin;
+
+       self.effects = self.effects | EF_LOWPRECISION;
+
+       if(cvar(strcat("g_", self.classname, "_trail")))  //nexball_basketball :p
+       {
+               self.glow_color = autocvar_g_nexball_trail_color;
+               self.glow_trail = true;
+       }
+
+       self.movetype = MOVETYPE_FLY;
+
+       if(!autocvar_g_nexball_sound_bounce)
+               self.noise = "";
+       else if(self.noise == "")
+               self.noise = SND(NB_BOUNCE);
+       //bounce sound placeholder (FIXME)
+       if(self.noise1 == "")
+               self.noise1 = SND(NB_DROP);
+       //ball drop sound placeholder (FIXME)
+       if(self.noise2 == "")
+               self.noise2 = SND(NB_STEAL);
+       //stealing sound placeholder (FIXME)
+       if(self.noise) precache_sound(self.noise);
+       precache_sound(self.noise1);
+       precache_sound(self.noise2);
+
+       WaypointSprite_AttachCarrier(WP_NbBall, self, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
+
+       self.reset = ball_restart;
+       self.think = InitBall;
+       self.nextthink = game_starttime + autocvar_g_nexball_delay_start;
+}
+
+spawnfunc(nexball_basketball)
+{
+       nexball_mode |= NBM_BASKETBALL;
+       self.classname = "nexball_basketball";
+       if (!(balls & BALL_BASKET))
+       {
+               /*
+               CVTOV(g_nexball_basketball_effects_default);
+               CVTOV(g_nexball_basketball_delay_hold);
+               CVTOV(g_nexball_basketball_delay_hold_forteam);
+               CVTOV(g_nexball_basketball_teamsteal);
+               */
+               autocvar_g_nexball_basketball_effects_default = autocvar_g_nexball_basketball_effects_default & BALL_EFFECTMASK;
+       }
+       if(!self.effects)
+               self.effects = autocvar_g_nexball_basketball_effects_default;
+       self.solid = SOLID_TRIGGER;
+       balls |= BALL_BASKET;
+       self.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
+       self.bouncestop = autocvar_g_nexball_basketball_bouncestop;
+       SpawnBall();
+}
+
+spawnfunc(nexball_football)
+{
+       nexball_mode |= NBM_FOOTBALL;
+       self.classname = "nexball_football";
+       self.solid = SOLID_TRIGGER;
+       balls |= BALL_FOOT;
+       self.bouncefactor = autocvar_g_nexball_football_bouncefactor;
+       self.bouncestop = autocvar_g_nexball_football_bouncestop;
+       SpawnBall();
+}
+
+float nb_Goal_Customize()
+{SELFPARAM();
+       entity e, wp_owner;
+       e = WaypointSprite_getviewentity(other);
+       wp_owner = self.owner;
+       if(SAME_TEAM(e, wp_owner)) { return false; }
+
+       return true;
+}
+
+void SpawnGoal(void)
+{SELFPARAM();
+       if(!g_nexball) { remove(self); return; }
+
+       EXACTTRIGGER_INIT;
+
+       if(self.team != GOAL_OUT && Team_TeamToNumber(self.team) != -1)
+       {
+               entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (self.absmin + self.absmax) * 0.5, self, sprite, RADARICON_NONE);
+               wp.colormod = ((self.team) ? Team_ColorRGB(self.team) : '1 0.5 0');
+               self.sprite.customizeentityforclient = nb_Goal_Customize;
+       }
+
+       self.classname = "nexball_goal";
+       if(self.noise == "")
+               self.noise = "ctf/respawn.wav";
+       precache_sound(self.noise);
+       self.touch = GoalTouch;
+}
+
+spawnfunc(nexball_redgoal)
+{
+       self.team = NUM_TEAM_1;
+       SpawnGoal();
+}
+spawnfunc(nexball_bluegoal)
+{
+       self.team = NUM_TEAM_2;
+       SpawnGoal();
+}
+spawnfunc(nexball_yellowgoal)
+{
+       self.team = NUM_TEAM_3;
+       SpawnGoal();
+}
+spawnfunc(nexball_pinkgoal)
+{
+       self.team = NUM_TEAM_4;
+       SpawnGoal();
+}
+
+spawnfunc(nexball_fault)
+{
+       self.team = GOAL_FAULT;
+       if(self.noise == "")
+               self.noise = SND(TYPEHIT);
+       SpawnGoal();
+}
+
+spawnfunc(nexball_out)
+{
+       self.team = GOAL_OUT;
+       if(self.noise == "")
+               self.noise = SND(TYPEHIT);
+       SpawnGoal();
+}
+
+//
+//Spawnfuncs preserved for compatibility
+//
+
+spawnfunc(ball)
+{
+       spawnfunc_nexball_football(this);
+}
+spawnfunc(ball_football)
+{
+       spawnfunc_nexball_football(this);
+}
+spawnfunc(ball_basketball)
+{
+       spawnfunc_nexball_basketball(this);
+}
+// The "red goal" is defended by blue team. A ball in there counts as a point for red.
+spawnfunc(ball_redgoal)
+{
+       spawnfunc_nexball_bluegoal(this);       // I blame Revenant
+}
+spawnfunc(ball_bluegoal)
+{
+       spawnfunc_nexball_redgoal(this);        // but he didn't mean to cause trouble :p
+}
+spawnfunc(ball_fault)
+{
+       spawnfunc_nexball_fault(this);
+}
+spawnfunc(ball_bound)
+{
+       spawnfunc_nexball_out(this);
+}
+
+//=======================//
+//       Weapon code     //
+//=======================//
+
+
+void W_Nexball_Think()
+{SELFPARAM();
+       //dprint("W_Nexball_Think\n");
+       //vector new_dir = steerlib_arrive(self.enemy.origin, 2500);
+       vector new_dir = normalize(self.enemy.origin + '0 0 50' - self.origin);
+       vector old_dir = normalize(self.velocity);
+       float _speed = vlen(self.velocity);
+       vector new_vel = normalize(old_dir + (new_dir * autocvar_g_nexball_safepass_turnrate)) * _speed;
+       //vector new_vel = (new_dir * autocvar_g_nexball_safepass_turnrate
+
+       self.velocity = new_vel;
+
+       self.nextthink = time;
+}
+
+void W_Nexball_Touch(void)
+{SELFPARAM();
+       entity ball, attacker;
+       attacker = self.owner;
+       //self.think = func_null;
+       //self.enemy = world;
+
+       PROJECTILE_TOUCH;
+       if(attacker.team != other.team || autocvar_g_nexball_basketball_teamsteal)
+               if((ball = other.ballcarried) && !other.frozen && !other.deadflag && (IS_PLAYER(attacker)))
+               {
+                       other.velocity = other.velocity + normalize(self.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
+                       other.flags &= ~FL_ONGROUND;
+                       if(!attacker.ballcarried)
+                       {
+                               LogNB("stole", attacker);
+                               _sound(other, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
+
+                               if(SAME_TEAM(attacker, other) && time > attacker.teamkill_complain)
+                               {
+                                       attacker.teamkill_complain = time + 5;
+                                       attacker.teamkill_soundtime = time + 0.4;
+                                       attacker.teamkill_soundsource = other;
+                               }
+
+                               GiveBall(attacker, other.ballcarried);
+                       }
+               }
+       remove(self);
+}
+
+void W_Nexball_Attack(float t)
+{SELFPARAM();
+       entity ball;
+       float mul, mi, ma;
+       if(!(ball = self.ballcarried))
+               return;
+
+       W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
+       tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, world);
+       if(trace_startsolid)
+       {
+               if(self.metertime)
+                       self.metertime = 0; // Shot failed, hide the power meter
+               return;
+       }
+
+       //Calculate multiplier
+       if(t < 0)
+               mul = 1;
+       else
+       {
+               mi = autocvar_g_nexball_basketball_meter_minpower;
+               ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion
+               //One triangle wave period with 1 as max
+               mul = 2 * (t % g_nexball_meter_period) / g_nexball_meter_period;
+               if(mul > 1)
+                       mul = 2 - mul;
+               mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power
+       }
+
+       DropBall(ball, w_shotorg, W_CalculateProjectileVelocity(self.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false));
+
+
+       //TODO: use the speed_up cvar too ??
+}
+
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
+
+void W_Nexball_Attack2(void)
+{SELFPARAM();
+       if(self.ballcarried.enemy)
+       {
+               entity _ball = self.ballcarried;
+               W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
+               DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
+               _ball.think = W_Nexball_Think;
+               _ball.nextthink = time;
+               return;
+       }
+
+       if(!autocvar_g_nexball_tackling)
+               return;
+
+       W_SetupShot(self, false, 2, SND(NB_SHOOT2), CH_WEAPON_A, 0);
+       entity missile = spawn();
+
+       missile.owner = self;
+       missile.classname = "ballstealer";
+
+       missile.movetype = MOVETYPE_FLY;
+       PROJECTILE_MAKETRIGGER(missile);
+
+       //setmodel(missile, "models/elaser.mdl");  // precision set below
+       setsize(missile, '0 0 0', '0 0 0');
+       setorigin(missile, w_shotorg);
+
+       W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0);
+       missile.angles = vectoangles(missile.velocity);
+       missile.touch = W_Nexball_Touch;
+       missile.think = SUB_Remove;
+       missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
+
+       missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
+       missile.flags = FL_PROJECTILE;
+
+       CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
+}
+
+float ball_customize()
+{SELFPARAM();
+       if(!self.owner)
+       {
+               self.effects &= ~EF_FLAME;
+               self.scale = 1;
+               self.customizeentityforclient = func_null;
+               return true;
+       }
+
+       if(other == self.owner)
+       {
+               self.scale = autocvar_g_nexball_viewmodel_scale;
+               if(self.enemy)
+                       self.effects |= EF_FLAME;
+               else
+                       self.effects &= ~EF_FLAME;
+       }
+       else
+       {
+               self.effects &= ~EF_FLAME;
+               self.scale = 1;
+       }
+
+       return true;
+}
+
+       METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, bool fire1, bool fire2))
+       {
+               if(fire1)
+                       if(weapon_prepareattack(thiswep, actor, false, autocvar_g_balance_nexball_primary_refire))
+                               if(autocvar_g_nexball_basketball_meter)
+                               {
+                                       if(self.ballcarried && !self.metertime)
+                                               self.metertime = time;
+                                       else
+                                               weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+                               }
+                               else
+                               {
+                                       W_Nexball_Attack(-1);
+                                       weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+                               }
+               if(fire2)
+                       if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_nexball_secondary_refire))
+                       {
+                               W_Nexball_Attack2();
+                               weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
+                       }
+
+               if(!fire1 && self.metertime && self.ballcarried)
+               {
+                       W_Nexball_Attack(time - self.metertime);
+                       // DropBall or stealing will set metertime back to 0
+                       weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+               }
+       }
+       METHOD(BallStealer, wr_setup, void(BallStealer thiswep))
+       {
+               //weapon_setup(WEP_PORTO.m_id);
+       }
+       METHOD(BallStealer, wr_checkammo1, bool(BallStealer thiswep))
+       {
+               return true;
+       }
+       METHOD(BallStealer, wr_checkammo2, bool(BallStealer thiswep))
+       {
+               return true;
+       }
+
+MUTATOR_HOOKFUNCTION(nexball_BallDrop)
+{SELFPARAM();
+       if(self.ballcarried && g_nexball)
+               DropBall(self.ballcarried, self.origin, self.velocity);
+
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_PlayerPreThink)
+{SELFPARAM();
+       makevectors(self.v_angle);
+       if(nexball_mode & NBM_BASKETBALL)
+       {
+               if(self.ballcarried)
+               {
+                       // 'view ball'
+                       self.ballcarried.velocity = self.velocity;
+                       self.ballcarried.customizeentityforclient = ball_customize;
+
+                       setorigin(self.ballcarried, self.origin + self.view_ofs +
+                                         v_forward * autocvar_g_nexball_viewmodel_offset.x +
+                                         v_right * autocvar_g_nexball_viewmodel_offset.y +
+                                         v_up * autocvar_g_nexball_viewmodel_offset.z);
+
+                       // 'safe passing'
+                       if(autocvar_g_nexball_safepass_maxdist)
+                       {
+                               if(self.ballcarried.wait < time && self.ballcarried.enemy)
+                               {
+                                       //centerprint(self, sprintf("Lost lock on %s", self.ballcarried.enemy.netname));
+                                       self.ballcarried.enemy = world;
+                               }
+
+
+                               //tracebox(self.origin + self.view_ofs, '-2 -2 -2', '2 2 2', self.origin + self.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
+                               crosshair_trace(self);
+                               if( trace_ent &&
+                                       IS_CLIENT(trace_ent) &&
+                                       trace_ent.deadflag == DEAD_NO &&
+                                       trace_ent.team == self.team &&
+                                       vlen(trace_ent.origin - self.origin) <= autocvar_g_nexball_safepass_maxdist )
+                               {
+
+                                       //if(self.ballcarried.enemy != trace_ent)
+                                       //      centerprint(self, sprintf("Locked to %s", trace_ent.netname));
+                                       self.ballcarried.enemy = trace_ent;
+                                       self.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
+
+
+                               }
+                       }
+               }
+               else
+               {
+                       if(self.weaponentity.weapons)
+                       {
+                               self.weapons = self.weaponentity.weapons;
+                               Weapon w = WEP_NEXBALL;
+                               w.wr_resetplayer(w);
+                               self.switchweapon = self.weaponentity.switchweapon;
+                               W_SwitchWeapon(self.switchweapon);
+
+               self.weaponentity.weapons = '0 0 0';
+                       }
+               }
+
+       }
+
+       nexball_setstatus();
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_PlayerSpawn)
+{SELFPARAM();
+       self.weaponentity.weapons = '0 0 0';
+
+       if(nexball_mode & NBM_BASKETBALL)
+               self.weapons |= WEPSET(NEXBALL);
+       else
+               self.weapons = '0 0 0';
+
+       return false;
+}
+
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_maxspeed;
+
+MUTATOR_HOOKFUNCTION(nexball_PlayerPhysics)
+{SELFPARAM();
+       if(self.ballcarried)
+       {
+               self.stat_sv_airspeedlimit_nonqw *= autocvar_g_nexball_basketball_carrier_highspeed;
+               self.stat_sv_maxspeed *= autocvar_g_nexball_basketball_carrier_highspeed;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_ForbidThrowing)
+{SELFPARAM();
+       if(self.weapon == WEP_NEXBALL.m_id)
+               return true;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_FilterItem)
+{SELFPARAM();
+       if(self.classname == "droppedweapon")
+       if(self.weapon == WEP_NEXBALL.m_id)
+               return true;
+
+       return false;
+}
+
+MUTATOR_DEFINITION(gamemode_nexball)
+{
+       MUTATOR_HOOK(PlayerDies, nexball_BallDrop, CBC_ORDER_ANY);
+       MUTATOR_HOOK(MakePlayerObserver, nexball_BallDrop, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ClientDisconnect, nexball_BallDrop, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerSpawn, nexball_PlayerSpawn, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerPreThink, nexball_PlayerPreThink, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerPhysics, nexball_PlayerPhysics, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ForbidThrowCurrentWeapon, nexball_ForbidThrowing, CBC_ORDER_ANY);
+       MUTATOR_HOOK(FilterItem, nexball_FilterItem, CBC_ORDER_ANY);
+
+       MUTATOR_ONADD
+       {
+               g_nexball_meter_period = autocvar_g_nexball_meter_period;
+               if(g_nexball_meter_period <= 0)
+                       g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
+               g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
+               addstat(STAT_NB_METERSTART, AS_FLOAT, metertime);
+
+               // General settings
+               /*
+               CVTOV(g_nexball_football_boost_forward);   //100
+               CVTOV(g_nexball_football_boost_up);             //200
+               CVTOV(g_nexball_delay_idle);                       //10
+               CVTOV(g_nexball_football_physics);               //0
+               */
+               radar_showennemies = autocvar_g_nexball_radar_showallplayers;
+
+               InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
+               WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               // we actually cannot roll back nb_delayedinit here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+#endif
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/nexball.qh b/qcsrc/common/gamemodes/gamemode/nexball/nexball.qh
new file mode 100644 (file)
index 0000000..7d19c50
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef GAMEMODE_NEXBALL_H
+#define GAMEMODE_NEXBALL_H
+
+#include "weapon.qc"
+
+#ifdef SVQC
+MUTATOR_DECLARATION(gamemode_nexball);
+
+//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
+const float BALL_EFFECTMASK = 1229;
+const vector BALL_MINS = '-16 -16 -16'; // The model is 24*24*24
+const vector BALL_MAXS = '16 16 16';
+const vector BALL_ATTACHORG = '3 0 16';
+const float BALL_FOOT = 1;
+const float BALL_BASKET = 2;
+//spawnflags
+const float GOAL_TOUCHPLAYER = 1;
+//goal types
+const float GOAL_FAULT = -1;
+const float GOAL_OUT = -2;
+
+void DropBall(entity ball, vector org, vector vel);
+float autocvar_g_nexball_football_boost_forward;
+float autocvar_g_nexball_football_boost_up;
+float autocvar_g_nexball_football_physics;
+float autocvar_g_nexball_delay_idle;
+float autocvar_g_nexball_basketball_delay_hold;
+float autocvar_g_nexball_basketball_delay_hold_forteam;
+float autocvar_g_nexball_basketball_effects_default;
+float autocvar_g_nexball_basketball_teamsteal;
+float autocvar_g_nexball_meter_period;
+
+float balls;
+float ball_scale;
+float nb_teams;
+
+.entity nb_dropper;
+.float nb_droptime;
+
+.float teamtime;
+#endif
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/weapon.qc b/qcsrc/common/gamemodes/gamemode/nexball/weapon.qc
new file mode 100644 (file)
index 0000000..ae882bb
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef GAMEMODE_NEXBALL_WEAPON_H
+#define GAMEMODE_NEXBALL_WEAPON_H
+
+CLASS(BallStealer, PortoLaunch)
+/* flags     */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* impulse   */ ATTRIB(BallStealer, impulse, int, 0);
+/* refname   */ ATTRIB(BallStealer, netname, string, "ballstealer");
+/* wepname   */ ATTRIB(BallStealer, message, string, _("Ball Stealer"));
+ENDCLASS(BallStealer)
+REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
+
+#endif
index d322db4..48b92be 100644 (file)
@@ -5,4 +5,3 @@
 #include "item/jetpack.qc"
 #include "item/pickup.qc"
 #include "item/powerup.qc"
-#include "../../server/mutators/mutator_instagib_items.qc"
index 92c7757..a825b4e 100644 (file)
@@ -10,6 +10,9 @@ REGISTER_REGISTRY(RegisterItems)
 /** If you register a new item, make sure to add it to all.inc */
 #define REGISTER_ITEM(id, class) REGISTER(RegisterItems, ITEM, Items, id, m_id, NEW(class))
 
+REGISTRY_SORT(Items, m_name, 0)
+STATIC_INIT(Items) { FOREACH(Items, true, LAMBDA(it.m_id = i)); }
+
 void Dump_Items();
 
 GENERIC_COMMAND(dumpitems, "Dump all items to the console") {
index 1d02fc3..6b19a0b 100644 (file)
@@ -1,4 +1,5 @@
 #include "mutator/casings.qc"
 #include "mutator/damagetext.qc"
+#include "mutator/instagib/instagib.qc"
 #include "mutator/itemstime.qc"
 #include "mutator/waypoints/waypointsprites.qc"
index 14530a3..f0fc719 100644 (file)
@@ -1 +1,5 @@
+#include "all.qh"
+
+#define IMPLEMENTATION
 #include "all.inc"
+#undef IMPLEMENTATION
diff --git a/qcsrc/common/mutators/all.qh b/qcsrc/common/mutators/all.qh
new file mode 100644 (file)
index 0000000..ceb4b51
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef MUTATORS_ALL_H
+#define MUTATORS_ALL_H
+
+#include "all.inc"
+
+#endif
index 6e1c7c0..f6fa534 100644 (file)
@@ -265,7 +265,7 @@ STATIC_INIT_LATE(Mutators) {
 #define MUTATOR_HOOK(cb, func, order) do {                              \
     MUTATOR_ONADD {                                                     \
         if (!CallbackChain_Add(HOOK_##cb, CALLBACK_##func, order)) {    \
-            LOG_INFO("HOOK FAILED: ", #cb, ":", #func, "\n");              \
+            LOG_INFO("HOOK FAILED: ", #cb, ":", #func, "\n");           \
             return true;                                                \
         }                                                               \
     }                                                                   \
index 9ed5fef..fe945c9 100644 (file)
@@ -1,3 +1,5 @@
+#ifdef IMPLEMENTATION
+
 #include "../../util.qh"
 
 #ifdef CSQC
@@ -175,3 +177,4 @@ MUTATOR_HOOKFUNCTION(casings, CSQC_Parse_TempEntity)
 }
 
 #endif
+#endif
index e4e4be5..d1f513a 100644 (file)
@@ -1,3 +1,13 @@
+#ifndef MUTATOR_DAMAGETEXT_H
+#define MUTATOR_DAMAGETEXT_H
+
+#ifdef MENUQC
+#include "../../../menu/xonotic/tab.qc"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
 REGISTER_MUTATOR(damagetext, true);
 
 #if defined(CSQC) || defined(MENUQC)
@@ -111,7 +121,6 @@ MUTATOR_HOOKFUNCTION(damagetext, CSQC_Parse_TempEntity) {
 #endif
 
 #ifdef MENUQC
-#include "../../../menu/xonotic/tab.qc"
 CLASS(XonoticDamageTextSettings, XonoticTab)
     #include "../../../menu/gamesettings.qh"
     REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
@@ -140,3 +149,4 @@ CLASS(XonoticDamageTextSettings, XonoticTab)
     }
 ENDCLASS(XonoticDamageTextSettings)
 #endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/instagib/instagib.qc b/qcsrc/common/mutators/mutator/instagib/instagib.qc
new file mode 100644 (file)
index 0000000..cc6f405
--- /dev/null
@@ -0,0 +1,480 @@
+#ifndef MUTATOR_INSTAGIB_H
+#define MUTATOR_INSTAGIB_H
+
+#include "items.qc"
+
+#endif
+
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+
+#include "../../../../server/cl_client.qh"
+#include "../../../buffs/all.qh"
+
+#include "../../../items/all.qc"
+
+REGISTER_MUTATOR(mutator_instagib, cvar("g_instagib") && !g_nexball);
+
+spawnfunc(item_minst_cells)
+{
+       if (!g_instagib) { remove(self); return; }
+       if (!self.ammo_cells) self.ammo_cells = autocvar_g_instagib_ammo_drop;
+       StartItemA(ITEM_VaporizerCells);
+}
+
+void instagib_invisibility()
+{SELFPARAM();
+       self.strength_finished = autocvar_g_balance_powerup_strength_time;
+       StartItemA(ITEM_Invisibility);
+}
+
+void instagib_extralife()
+{SELFPARAM();
+       self.max_health = 1;
+       StartItemA(ITEM_ExtraLife);
+}
+
+void instagib_speed()
+{SELFPARAM();
+       self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+       StartItemA(ITEM_Speed);
+}
+
+.float instagib_nextthink;
+.float instagib_needammo;
+void instagib_stop_countdown(entity e)
+{
+       if (!e.instagib_needammo)
+               return;
+       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_INSTAGIB_FINDAMMO);
+       e.instagib_needammo = false;
+}
+void instagib_ammocheck()
+{SELFPARAM();
+       if(time < self.instagib_nextthink)
+               return;
+       if(!IS_PLAYER(self))
+               return; // not a player
+
+       if(self.deadflag || gameover)
+               instagib_stop_countdown(self);
+       else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO) || (self.flags & FL_GODMODE))
+               instagib_stop_countdown(self);
+       else if(autocvar_g_rm && autocvar_g_rm_laser)
+       {
+               if(!self.instagib_needammo)
+               {
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
+                       self.instagib_needammo = true;
+               }
+       }
+       else
+       {
+               self.instagib_needammo = true;
+               if (self.health <= 5)
+               {
+                       Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
+               }
+               else if (self.health <= 10)
+               {
+                       Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
+               }
+               else if (self.health <= 20)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
+               }
+               else if (self.health <= 30)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
+               }
+               else if (self.health <= 40)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
+               }
+               else if (self.health <= 50)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
+               }
+               else if (self.health <= 60)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
+               }
+               else if (self.health <= 70)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
+               }
+               else if (self.health <= 80)
+               {
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
+               }
+               else if (self.health <= 90)
+               {
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
+               }
+               else
+               {
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
+                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
+               }
+       }
+       self.instagib_nextthink = time + 1;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
+{
+       entity head;
+       FOR_EACH_PLAYER(head)
+               instagib_stop_countdown(head);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
+{
+       other.monster_loot = spawnfunc_item_minst_cells;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
+{SELFPARAM();
+       // always refill ammo
+       if(self.monsterid == MON_MAGE.monsterid)
+               self.skin = 1;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BotShouldAttack)
+{
+       if (checkentity.items & ITEM_Invisibility.m_itemid)
+               return true;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
+{SELFPARAM();
+       instagib_stop_countdown(self);
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
+{SELFPARAM();
+       self.effects |= EF_FULLBRIGHT;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPreThink)
+{
+       instagib_ammocheck();
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
+{
+       // no regeneration in instagib
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPowerups)
+{SELFPARAM();
+       if (!(self.effects & EF_FULLBRIGHT))
+               self.effects |= EF_FULLBRIGHT;
+
+       if (self.items & ITEM_Invisibility.m_itemid)
+       {
+               play_countdown(self.strength_finished, SND(POWEROFF));
+               if (time > self.strength_finished)
+               {
+                       self.alpha = default_player_alpha;
+                       self.exteriorweaponentity.alpha = default_weapon_alpha;
+                       self.items &= ~ITEM_Invisibility.m_itemid;
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
+               }
+       }
+       else
+       {
+               if (time < self.strength_finished)
+               {
+                       self.alpha = autocvar_g_instagib_invis_alpha;
+                       self.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
+                       self.items |= ITEM_Invisibility.m_itemid;
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
+               }
+       }
+
+       if (self.items & ITEM_Speed.m_itemid)
+       {
+               play_countdown(self.invincible_finished, SND(POWEROFF));
+               if (time > self.invincible_finished)
+               {
+                       self.items &= ~ITEM_Speed.m_itemid;
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
+               }
+       }
+       else
+       {
+               if (time < self.invincible_finished)
+               {
+                       self.items |= ITEM_Speed.m_itemid;
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
+               }
+       }
+       return false;
+}
+
+.float stat_sv_maxspeed;
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics)
+{SELFPARAM();
+       if(self.items & ITEM_Speed.m_itemid)
+               self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
+{
+       damage_save = 0;
+       damage_take = frag_damage;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
+{
+       // weapon dropping on death handled by FilterItem
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_Calculate)
+{
+       if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
+               frag_damage = 0;
+
+       if(IS_PLAYER(frag_target))
+       {
+               if(frag_deathtype == DEATH_FALL)
+                       frag_damage = 0; // never count fall damage
+
+               if(!autocvar_g_instagib_damagedbycontents)
+               switch(frag_deathtype)
+               {
+                       case DEATH_DROWN:
+                       case DEATH_SLIME:
+                       case DEATH_LAVA:
+                               frag_damage = 0;
+                               break;
+               }
+
+               if(IS_PLAYER(frag_attacker))
+               if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER.m_id))
+               {
+                       if(frag_target.armorvalue)
+                       {
+                               frag_target.armorvalue -= 1;
+                               frag_damage = 0;
+                               frag_target.damage_dealt += 1;
+                               frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
+                               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
+                       }
+               }
+
+               if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER.m_id))
+               {
+                       if(frag_deathtype & HITTYPE_SECONDARY)
+                       {
+                               if(!autocvar_g_instagib_blaster_keepdamage)
+                                       frag_damage = frag_mirrordamage = 0;
+
+                               if(frag_target != frag_attacker)
+                               {
+                                       if(frag_damage <= 0 && frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
+                                       if(!autocvar_g_instagib_blaster_keepforce)
+                                               frag_force = '0 0 0';
+                               }
+                       }
+               }
+       }
+
+       if(IS_PLAYER(frag_attacker))
+       if(frag_mirrordamage > 0)
+       {
+               // just lose extra LIVES, don't kill the player for mirror damage
+               if(frag_attacker.armorvalue > 0)
+               {
+                       frag_attacker.armorvalue -= 1;
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
+                       frag_attacker.damage_dealt += frag_mirrordamage;
+               }
+               frag_mirrordamage = 0;
+       }
+
+       if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Invisibility.m_itemid))
+               yoda = 1;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems)
+{
+       start_health       = warmup_start_health       = 100;
+       start_armorvalue   = warmup_start_armorvalue   = 0;
+
+       start_ammo_shells  = warmup_start_ammo_shells  = 0;
+       start_ammo_nails   = warmup_start_ammo_nails   = 0;
+       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_instagib_ammo_start");
+       start_ammo_plasma  = warmup_start_ammo_plasma  = 0;
+       start_ammo_rockets = warmup_start_ammo_rockets = 0;
+       start_ammo_fuel    = warmup_start_ammo_fuel    = 0;
+
+       start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
+       start_items |= IT_UNLIMITED_SUPERWEAPONS;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
+{SELFPARAM();
+       if(self.classname == "item_cells")
+               return true; // no normal cells?
+
+       if(self.weapon == WEP_VAPORIZER.m_id && self.classname == "droppedweapon")
+       {
+               self.ammo_cells = autocvar_g_instagib_ammo_drop;
+               return false;
+       }
+
+       if(self.weapon == WEP_DEVASTATOR.m_id || self.weapon == WEP_VORTEX.m_id)
+       {
+               entity e = spawn();
+               setorigin(e, self.origin);
+               e.noalign = self.noalign;
+        e.cnt = self.cnt;
+        e.team = self.team;
+               WITH(entity, self, e, spawnfunc_item_minst_cells(e));
+               return true;
+       }
+
+       if(self.flags & FL_POWERUP)
+               return false;
+
+       if(self.ammo_cells > autocvar_g_instagib_ammo_drop && self.classname != "item_minst_cells")
+               self.ammo_cells = autocvar_g_instagib_ammo_drop;
+
+       if(self.ammo_cells && !self.weapon)
+               return false;
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, CustomizeWaypoint)
+{SELFPARAM();
+       entity e = WaypointSprite_getviewentity(other);
+
+       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+       // but only apply this to real players, not to spectators
+       if((self.owner.flags & FL_CLIENT) && (self.owner.items & ITEM_Invisibility.m_itemid) && (e == other))
+       if(DIFF_TEAM(self.owner, e))
+               return true;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
+{
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER.m_id))
+               frag_damage = 1000; // always gib if it was a vaporizer death
+
+       return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
+{SELFPARAM();
+       if(self.ammo_cells)
+       {
+               // play some cool sounds ;)
+               if (IS_CLIENT(other))
+               {
+                       if(other.health <= 5)
+                               Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
+                       else if(other.health < 50)
+                               Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
+               }
+
+               if(other.health < 100)
+                       other.health = 100;
+
+               return MUT_ITEMTOUCH_CONTINUE;
+       }
+
+       if(self.max_health)
+       {
+               other.armorvalue = bound(other.armorvalue, 999, other.armorvalue + autocvar_g_instagib_extralives);
+               Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
+               return MUT_ITEMTOUCH_PICKUP;
+       }
+
+       return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
+{SELFPARAM();
+       if (!autocvar_g_powerups) { return false; }
+       // Can't use .itemdef here
+       if (!(self.classname == "item_strength" || self.classname == "item_invincible" || self.classname == "item_health_mega"))
+               return false;
+
+       entity e = spawn();
+
+       float r = random();
+       if (r < 0.3)
+               e.think = instagib_invisibility;
+       else if (r < 0.6)
+               e.think = instagib_extralife;
+       else
+               e.think = instagib_speed;
+
+       e.nextthink = time + 0.1;
+       e.spawnflags = self.spawnflags;
+       e.noalign = self.noalign;
+       setorigin(e, self.origin);
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":instagib");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", instagib");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
+{
+       modname = "instagib";
+       return true;
+}
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/instagib/items.qc b/qcsrc/common/mutators/mutator/instagib/items.qc
new file mode 100644 (file)
index 0000000..2d804f7
--- /dev/null
@@ -0,0 +1,78 @@
+#include "../../../items/all.qh"
+#include "../../../items/item/ammo.qh"
+#include "../../../items/item/powerup.qh"
+
+float instagib_respawntime_ammo = 45;
+float instagib_respawntimejitter_ammo = 0;
+GETTER(float, instagib_respawntime_ammo)
+GETTER(float, instagib_respawntimejitter_ammo)
+
+#ifndef MENUQC
+MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
+#endif
+
+REGISTER_ITEM(VaporizerCells, Ammo) {
+#ifndef MENUQC
+    this.m_model                =   MDL_VaporizerCells_ITEM;
+#endif
+    this.m_sound                =   "misc/itempickup.wav";
+    this.m_name                 =   "Vaporizer Ammo";
+    this.m_icon                 =   "ammo_supercells";
+#ifdef SVQC
+    this.m_botvalue             =   100;
+    this.m_itemid               =   IT_CELLS;
+    this.m_respawntime          =   GET(instagib_respawntime_ammo);
+    this.m_respawntimejitter    =   GET(instagib_respawntimejitter_ammo);
+#endif
+}
+
+#ifndef MENUQC
+MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
+#endif
+
+REGISTER_ITEM(ExtraLife, Powerup) {
+#ifndef MENUQC
+    this.m_model                =   MDL_ExtraLife_ITEM;
+#endif
+    this.m_sound                =   "misc/megahealth.wav";
+    this.m_name                 =   "Extra life";
+    this.m_icon                 =   "item_mega_health";
+    this.m_color                =   '1 0 0';
+    this.m_waypoint             =   _("Extra life");
+    this.m_waypointblink        =   2;
+    this.m_itemid               =   IT_NAILS;
+}
+
+#ifndef MENUQC
+MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+#endif
+
+REGISTER_ITEM(Invisibility, Powerup) {
+#ifndef MENUQC
+    this.m_model            =   MDL_Invisibility_ITEM;
+#endif
+    this.m_sound            =   "misc/powerup.wav";
+    this.m_name             =   "Invisibility";
+    this.m_icon             =   "strength";
+    this.m_color            =   '0 0 1';
+    this.m_waypoint         =   _("Invisibility");
+    this.m_waypointblink    =   2;
+    this.m_itemid           =   IT_STRENGTH;
+}
+
+#ifndef MENUQC
+MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+#endif
+
+REGISTER_ITEM(Speed, Powerup) {
+#ifndef MENUQC
+    this.m_model            =   MDL_Speed_ITEM;
+#endif
+    this.m_sound            =   "misc/powerup_shield.wav";
+    this.m_name             =   "Speed";
+    this.m_icon             =   "shield";
+    this.m_color            =   '1 0 1';
+    this.m_waypoint         =   _("Speed");
+    this.m_waypointblink    =   2;
+    this.m_itemid           =   IT_INVINCIBLE;
+}
index 1d615b7..170862a 100644 (file)
@@ -1,3 +1,4 @@
+#ifdef IMPLEMENTATION
 REGISTER_MUTATOR(itemstime, true);
 
 #ifdef SVQC
@@ -388,3 +389,4 @@ void HUD_ItemsTime()
 }
 
 #endif
+#endif
index 3be3266..89d1b23 100644 (file)
@@ -1,5 +1,7 @@
 #include "waypointsprites.qh"
 
+#ifdef IMPLEMENTATION
+
 REGISTER_MUTATOR(waypointsprites, true);
 
 #ifdef SVQC
@@ -1148,3 +1150,4 @@ void WaypointSprite_PlayerGone()
     WaypointSprite_DetachCarrier(self);
 }
 #endif
+#endif
index 1a799c8..731cba8 100644 (file)
@@ -1,6 +1,5 @@
 #include "physics.qh"
-#include "triggers/trigger/swamp.qh"
-#include "triggers/trigger/jumppads.qh"
+#include "triggers/include.qh"
 #include "viewloc.qh"
 
 #ifdef SVQC
 // client side physics
 bool Physics_Valid(string thecvar)
 {
-       if(!autocvar_g_physics_clientselect) { return false; }
-
-       string l = strcat(" ", autocvar_g_physics_clientselect_options, " ");
-
-       if(strstrofs(l, strcat(" ", thecvar, " "), 0) >= 0)
-               return true;
-
-       return false;
+       return autocvar_g_physics_clientselect && strhasword(autocvar_g_physics_clientselect_options, thecvar);
 }
 
 float Physics_ClientOption(entity pl, string option)
index 3257215..fc89a0c 100644 (file)
@@ -27,5 +27,3 @@
 #include "weapon/arc.qc"
 #include "weapon/hmg.qc"
 #include "weapon/rpc.qc"
-
-#include "../../server/mutators/gamemode_nexball_weapon.qc"
index 7bf6715..e3f6c7e 100644 (file)
@@ -150,23 +150,22 @@ REGISTRY_SORT(Weapons, netname, WEP_HARDCODED_IMPULSES + 1)
 
 STATIC_INIT(register_weapons_done)
 {
-    for (int i = 0; i < Weapons_COUNT; ++i) {
-        Weapon it = Weapons[i];
+    FOREACH(Weapons, true, LAMBDA(
         it.m_id = i;
         WepSet set = WepSet_FromWeapon(it.m_id);
         WEPSET_ALL |= set;
         if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
         it.weapon = it.m_id;
         it.weapons = set;
-        #ifdef CSQC
-        it.wr_init(it);
-        #endif
         int imp = WEP_IMPULSE_BEGIN + it.m_id - 1;
         if (imp <= WEP_IMPULSE_END)
             localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", it.netname, imp));
         else
             LOG_TRACEF(_("Impulse limit exceeded, weapon will not be directly accessible: %s\n"), it.netname);
-    }
+    ));
+    #ifdef CSQC
+    FOREACH(Weapons, true, LAMBDA(it.wr_init(it)));
+    #endif
     weaponorder_byid = "";
     for (int i = Weapons_MAX - 1; i >= 1; --i)
         if (Weapons[i])
diff --git a/qcsrc/server/mutators/gamemode_nexball.qc b/qcsrc/server/mutators/gamemode_nexball.qc
deleted file mode 100644 (file)
index 6d5cd76..0000000
+++ /dev/null
@@ -1,1048 +0,0 @@
-#include "gamemode_nexball.qh"
-
-#include "gamemode.qh"
-
-float autocvar_g_nexball_basketball_bouncefactor;
-float autocvar_g_nexball_basketball_bouncestop;
-float autocvar_g_nexball_basketball_carrier_highspeed;
-bool autocvar_g_nexball_basketball_meter;
-float autocvar_g_nexball_basketball_meter_maxpower;
-float autocvar_g_nexball_basketball_meter_minpower;
-float autocvar_g_nexball_delay_collect;
-float autocvar_g_nexball_delay_goal;
-float autocvar_g_nexball_delay_start;
-float autocvar_g_nexball_football_bouncefactor;
-float autocvar_g_nexball_football_bouncestop;
-bool autocvar_g_nexball_radar_showallplayers;
-bool autocvar_g_nexball_sound_bounce;
-int autocvar_g_nexball_trail_color;
-
-float autocvar_g_nexball_safepass_turnrate;
-float autocvar_g_nexball_safepass_maxdist;
-float autocvar_g_nexball_safepass_holdtime;
-float autocvar_g_nexball_viewmodel_scale;
-float autocvar_g_nexball_tackling;
-vector autocvar_g_nexball_viewmodel_offset;
-
-void basketball_touch();
-void football_touch();
-void ResetBall();
-const float NBM_NONE = 0;
-const float NBM_FOOTBALL = 2;
-const float NBM_BASKETBALL = 4;
-float nexball_mode;
-
-float OtherTeam(float t)  //works only if there are two teams on the map!
-{
-       entity e;
-       e = find(world, classname, "nexball_team");
-       if(e.team == t)
-               e = find(e, classname, "nexball_team");
-       return e.team;
-}
-
-const float ST_NEXBALL_GOALS = 1;
-const float SP_NEXBALL_GOALS = 4;
-const float SP_NEXBALL_FAULTS = 5;
-void nb_ScoreRules(float teams)
-{
-       ScoreRules_basics(teams, 0, 0, true);
-       ScoreInfo_SetLabel_TeamScore(   ST_NEXBALL_GOALS,  "goals", SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore( SP_NEXBALL_GOALS,  "goals", SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
-       ScoreRules_basics_end();
-}
-
-void LogNB(string mode, entity actor)
-{
-       string s;
-       if(!autocvar_sv_eventlog)
-               return;
-       s = strcat(":nexball:", mode);
-       if(actor != world)
-               s = strcat(s, ":", ftos(actor.playerid));
-       GameLogEcho(s);
-}
-
-void ball_restart(void)
-{SELFPARAM();
-       if(self.owner)
-               DropBall(self, self.owner.origin, '0 0 0');
-       ResetBall();
-}
-
-void nexball_setstatus(void)
-{SELFPARAM();
-       self.items &= ~IT_KEY1;
-       if(self.ballcarried)
-       {
-               if(self.ballcarried.teamtime && (self.ballcarried.teamtime < time))
-               {
-                       bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
-                       setself(self.ballcarried);
-                       DropBall(self, self.owner.origin, '0 0 0');
-                       ResetBall();
-                       setself(this);
-               }
-               else
-                       self.items |= IT_KEY1;
-       }
-}
-
-void relocate_nexball(void)
-{SELFPARAM();
-       tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, true, self);
-       if(trace_startsolid)
-       {
-               vector o;
-               o = self.origin;
-               if(!move_out_of_solid(self))
-                       objerror("could not get out of solid at all!");
-               LOG_INFO("^1NOTE: this map needs FIXING. ", self.classname, " at ", vtos(o - '0 0 1'));
-               LOG_INFO(" needs to be moved out of solid, e.g. by '", ftos(self.origin.x - o.x));
-               LOG_INFO(" ", ftos(self.origin.y - o.y));
-               LOG_INFO(" ", ftos(self.origin.z - o.z), "'\n");
-               self.origin = o;
-       }
-}
-
-void DropOwner(void)
-{SELFPARAM();
-       entity ownr;
-       ownr = self.owner;
-       DropBall(self, ownr.origin, ownr.velocity);
-       makevectors(ownr.v_angle.y * '0 1 0');
-       ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
-       ownr.flags &= ~FL_ONGROUND;
-}
-
-void GiveBall(entity plyr, entity ball)
-{SELFPARAM();
-       entity ownr;
-
-       if((ownr = ball.owner))
-       {
-               ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
-               ownr.ballcarried = world;
-               if(ownr.metertime)
-               {
-                       ownr.metertime = 0;
-                       ownr.weaponentity.state = WS_READY;
-               }
-               WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
-       }
-       else
-       {
-               WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
-       }
-
-       //setattachment(ball, plyr, "");
-       setorigin(ball, plyr.origin + plyr.view_ofs);
-
-       if(ball.team != plyr.team)
-               ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam;
-
-       ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
-       ball.team = plyr.team;
-       plyr.ballcarried = ball;
-       ball.nb_dropper = plyr;
-
-       plyr.effects |= autocvar_g_nexball_basketball_effects_default;
-       ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
-
-       ball.velocity = '0 0 0';
-       ball.movetype = MOVETYPE_NONE;
-       ball.touch = func_null;
-       ball.effects |= EF_NOSHADOW;
-       ball.scale = 1; // scale down.
-
-       WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
-       WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
-       if(autocvar_g_nexball_basketball_delay_hold)
-       {
-               ball.think = DropOwner;
-               ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
-       }
-
-       plyr.weaponentity.weapons = plyr.weapons;
-       plyr.weaponentity.switchweapon = plyr.weapon;
-       plyr.weapons = WEPSET(NEXBALL);
-       setself(plyr);
-       Weapon w = WEP_NEXBALL;
-       w.wr_resetplayer(w);
-       plyr.switchweapon = WEP_NEXBALL.m_id;
-       W_SwitchWeapon(WEP_NEXBALL.m_id);
-       setself(this);
-}
-
-void DropBall(entity ball, vector org, vector vel)
-{
-       ball.effects |= autocvar_g_nexball_basketball_effects_default;
-       ball.effects &= ~EF_NOSHADOW;
-       ball.owner.effects &= ~autocvar_g_nexball_basketball_effects_default;
-
-       setattachment(ball, world, "");
-       setorigin(ball, org);
-       ball.movetype = MOVETYPE_BOUNCE;
-       ball.flags &= ~FL_ONGROUND;
-       ball.scale = ball_scale;
-       ball.velocity = vel;
-       ball.nb_droptime = time;
-       ball.touch = basketball_touch;
-       ball.think = ResetBall;
-       ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
-
-       if(ball.owner.metertime)
-       {
-               ball.owner.metertime = 0;
-               ball.owner.weaponentity.state = WS_READY;
-       }
-
-       WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
-       WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
-       WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
-       ball.owner.ballcarried = world;
-       ball.owner = world;
-}
-
-void InitBall(void)
-{SELFPARAM();
-       if(gameover) return;
-       self.flags &= ~FL_ONGROUND;
-       self.movetype = MOVETYPE_BOUNCE;
-       if(self.classname == "nexball_basketball")
-               self.touch = basketball_touch;
-       else if(self.classname == "nexball_football")
-               self.touch = football_touch;
-       self.cnt = 0;
-       self.think = ResetBall;
-       self.nextthink = time + autocvar_g_nexball_delay_idle + 3;
-       self.teamtime = 0;
-       self.pusher = world;
-       self.team = false;
-       _sound(self, CH_TRIGGER, self.noise1, VOL_BASE, ATTEN_NORM);
-       WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);
-       LogNB("init", world);
-}
-
-void ResetBall(void)
-{SELFPARAM();
-       if(self.cnt < 2)        // step 1
-       {
-               if(time == self.teamtime)
-                       bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
-
-               self.touch = func_null;
-               self.movetype = MOVETYPE_NOCLIP;
-               self.velocity = '0 0 0'; // just in case?
-               if(!self.cnt)
-                       LogNB("resetidle", world);
-               self.cnt = 2;
-               self.nextthink = time;
-       }
-       else if(self.cnt < 4)     // step 2 and 3
-       {
-//             dprint("Step ", ftos(self.cnt), ": Calculated velocity: ", vtos(self.spawnorigin - self.origin), ", time: ", ftos(time), "\n");
-               self.velocity = (self.spawnorigin - self.origin) * (self.cnt - 1); // 1 or 0.5 second movement
-               self.nextthink = time + 0.5;
-               self.cnt += 1;
-       }
-       else     // step 4
-       {
-//             dprint("Step 4: time: ", ftos(time), "\n");
-               if(vlen(self.origin - self.spawnorigin) > 10)  // should not happen anymore
-                       LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
-                                  vtos(self.origin - self.spawnorigin), " Velocity: ", vtos(self.velocity), "\n");
-               self.velocity = '0 0 0';
-               setorigin(self, self.spawnorigin); // make sure it's positioned correctly anyway
-               self.movetype = MOVETYPE_NONE;
-               self.think = InitBall;
-               self.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
-       }
-}
-
-void football_touch(void)
-{SELFPARAM();
-       if(other.solid == SOLID_BSP)
-       {
-               if(time > self.lastground + 0.1)
-               {
-                       _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
-                       self.lastground = time;
-               }
-               if(vlen(self.velocity) && !self.cnt)
-                       self.nextthink = time + autocvar_g_nexball_delay_idle;
-               return;
-       }
-       if (!IS_PLAYER(other))
-               return;
-       if(other.health < 1)
-               return;
-       if(!self.cnt)
-               self.nextthink = time + autocvar_g_nexball_delay_idle;
-
-       self.pusher = other;
-       self.team = other.team;
-
-       if(autocvar_g_nexball_football_physics == -1)   // MrBougo try 1, before decompiling Rev's original
-       {
-               if(vlen(other.velocity))
-                       self.velocity = other.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
-       }
-       else if(autocvar_g_nexball_football_physics == 1)         // MrBougo's modded Rev style: partially independant of the height of the aiming point
-       {
-               makevectors(other.v_angle);
-               self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
-       }
-       else if(autocvar_g_nexball_football_physics == 2)         // 2nd mod try: totally independant. Really playable!
-       {
-               makevectors(other.v_angle.y * '0 1 0');
-               self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
-       }
-       else     // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
-       {
-               makevectors(other.v_angle);
-               self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
-       }
-       self.avelocity = -250 * v_forward;  // maybe there is a way to make it look better?
-}
-
-void basketball_touch(void)
-{SELFPARAM();
-       if(other.ballcarried)
-       {
-               football_touch();
-               return;
-       }
-       if(!self.cnt && IS_PLAYER(other) && !other.frozen && !other.deadflag && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
-       {
-               if(other.health <= 0)
-                       return;
-               LogNB("caught", other);
-               GiveBall(other, self);
-       }
-       else if(other.solid == SOLID_BSP)
-       {
-               _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
-               if(vlen(self.velocity) && !self.cnt)
-                       self.nextthink = min(time + autocvar_g_nexball_delay_idle, self.teamtime);
-       }
-}
-
-void GoalTouch(void)
-{SELFPARAM();
-       entity ball;
-       float isclient, pscore, otherteam;
-       string pname;
-
-       if(gameover) return;
-       if((self.spawnflags & GOAL_TOUCHPLAYER) && other.ballcarried)
-               ball = other.ballcarried;
-       else
-               ball = other;
-       if(ball.classname != "nexball_basketball")
-               if(ball.classname != "nexball_football")
-                       return;
-       if((!ball.pusher && self.team != GOAL_OUT) || ball.cnt)
-               return;
-       EXACTTRIGGER_TOUCH;
-
-
-       if(nb_teams == 2)
-               otherteam = OtherTeam(ball.team);
-       else
-               otherteam = 0;
-
-       if((isclient = IS_CLIENT(ball.pusher)))
-               pname = ball.pusher.netname;
-       else
-               pname = "Someone (?)";
-
-       if(ball.team == self.team)               //owngoal (regular goals)
-       {
-               LogNB("owngoal", ball.pusher);
-               bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
-               pscore = -1;
-       }
-       else if(self.team == GOAL_FAULT)
-       {
-               LogNB("fault", ball.pusher);
-               if(nb_teams == 2)
-                       bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
-               else
-                       bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
-               pscore = -1;
-       }
-       else if(self.team == GOAL_OUT)
-       {
-               LogNB("out", ball.pusher);
-               if((self.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
-                       bprint(pname, "^7 went out of bounds.\n");
-               else
-                       bprint("The ball was returned.\n");
-               pscore = 0;
-       }
-       else                                                       //score
-       {
-               LogNB(strcat("goal:", ftos(self.team)), ball.pusher);
-               bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
-               pscore = 1;
-       }
-
-       _sound(ball, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NONE);
-
-       if(ball.team && pscore)
-       {
-               if(nb_teams == 2 && pscore < 0)
-                       TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
-               else
-                       TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
-       }
-       if(isclient)
-       {
-               if(pscore > 0)
-                       PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore);
-               else if(pscore < 0)
-                       PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore);
-       }
-
-       if(ball.owner)  // Happens on spawnflag GOAL_TOUCHPLAYER
-               DropBall(ball, ball.owner.origin, ball.owner.velocity);
-
-       WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
-
-       ball.cnt = 1;
-       ball.think = ResetBall;
-       if(ball.classname == "nexball_basketball")
-               ball.touch = football_touch; // better than func_null: football control until the ball gets reset
-       ball.nextthink = time + autocvar_g_nexball_delay_goal * (self.team != GOAL_OUT);
-}
-
-//=======================//
-//        team ents       //
-//=======================//
-spawnfunc(nexball_team)
-{
-       if(!g_nexball)
-       {
-               remove(self);
-               return;
-       }
-       self.team = self.cnt + 1;
-}
-
-void nb_spawnteam(string teamname, float teamcolor)
-{
-       LOG_TRACE("^2spawned team ", teamname, "\n");
-       entity e;
-       e = spawn();
-       e.classname = "nexball_team";
-       e.netname = teamname;
-       e.cnt = teamcolor;
-       e.team = e.cnt + 1;
-       nb_teams += 1;
-}
-
-void nb_spawnteams(void)
-{
-       bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
-       entity e;
-       for(e = world; (e = find(e, classname, "nexball_goal"));)
-       {
-               switch(e.team)
-               {
-               case NUM_TEAM_1:
-                       if(!t_red)
-                       {
-                               nb_spawnteam("Red", e.team-1)   ;
-                               t_red = true;
-                       }
-                       break;
-               case NUM_TEAM_2:
-                       if(!t_blue)
-                       {
-                               nb_spawnteam("Blue", e.team-1)  ;
-                               t_blue = true;
-                       }
-                       break;
-               case NUM_TEAM_3:
-                       if(!t_yellow)
-                       {
-                               nb_spawnteam("Yellow", e.team-1);
-                               t_yellow = true;
-                       }
-                       break;
-               case NUM_TEAM_4:
-                       if(!t_pink)
-                       {
-                               nb_spawnteam("Pink", e.team-1)  ;
-                               t_pink = true;
-                       }
-                       break;
-               }
-       }
-}
-
-void nb_delayedinit(void)
-{
-       if(find(world, classname, "nexball_team") == world)
-               nb_spawnteams();
-       nb_ScoreRules(nb_teams);
-}
-
-
-//=======================//
-//       spawnfuncs       //
-//=======================//
-
-void SpawnBall(void)
-{SELFPARAM();
-       if(!g_nexball) { remove(self); return; }
-
-//     balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
-
-       if(self.model == "")
-       {
-               self.model = "models/nexball/ball.md3";
-               self.scale = 1.3;
-       }
-
-       precache_model(self.model);
-       _setmodel(self, self.model);
-       setsize(self, BALL_MINS, BALL_MAXS);
-       ball_scale = self.scale;
-
-       relocate_nexball();
-       self.spawnorigin = self.origin;
-
-       self.effects = self.effects | EF_LOWPRECISION;
-
-       if(cvar(strcat("g_", self.classname, "_trail")))  //nexball_basketball :p
-       {
-               self.glow_color = autocvar_g_nexball_trail_color;
-               self.glow_trail = true;
-       }
-
-       self.movetype = MOVETYPE_FLY;
-
-       if(!autocvar_g_nexball_sound_bounce)
-               self.noise = "";
-       else if(self.noise == "")
-               self.noise = SND(NB_BOUNCE);
-       //bounce sound placeholder (FIXME)
-       if(self.noise1 == "")
-               self.noise1 = SND(NB_DROP);
-       //ball drop sound placeholder (FIXME)
-       if(self.noise2 == "")
-               self.noise2 = SND(NB_STEAL);
-       //stealing sound placeholder (FIXME)
-       if(self.noise) precache_sound(self.noise);
-       precache_sound(self.noise1);
-       precache_sound(self.noise2);
-
-       WaypointSprite_AttachCarrier(WP_NbBall, self, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
-
-       self.reset = ball_restart;
-       self.think = InitBall;
-       self.nextthink = game_starttime + autocvar_g_nexball_delay_start;
-}
-
-spawnfunc(nexball_basketball)
-{
-       nexball_mode |= NBM_BASKETBALL;
-       self.classname = "nexball_basketball";
-       if (!(balls & BALL_BASKET))
-       {
-               /*
-               CVTOV(g_nexball_basketball_effects_default);
-               CVTOV(g_nexball_basketball_delay_hold);
-               CVTOV(g_nexball_basketball_delay_hold_forteam);
-               CVTOV(g_nexball_basketball_teamsteal);
-               */
-               autocvar_g_nexball_basketball_effects_default = autocvar_g_nexball_basketball_effects_default & BALL_EFFECTMASK;
-       }
-       if(!self.effects)
-               self.effects = autocvar_g_nexball_basketball_effects_default;
-       self.solid = SOLID_TRIGGER;
-       balls |= BALL_BASKET;
-       self.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
-       self.bouncestop = autocvar_g_nexball_basketball_bouncestop;
-       SpawnBall();
-}
-
-spawnfunc(nexball_football)
-{
-       nexball_mode |= NBM_FOOTBALL;
-       self.classname = "nexball_football";
-       self.solid = SOLID_TRIGGER;
-       balls |= BALL_FOOT;
-       self.bouncefactor = autocvar_g_nexball_football_bouncefactor;
-       self.bouncestop = autocvar_g_nexball_football_bouncestop;
-       SpawnBall();
-}
-
-float nb_Goal_Customize()
-{SELFPARAM();
-       entity e, wp_owner;
-       e = WaypointSprite_getviewentity(other);
-       wp_owner = self.owner;
-       if(SAME_TEAM(e, wp_owner)) { return false; }
-
-       return true;
-}
-
-void SpawnGoal(void)
-{SELFPARAM();
-       if(!g_nexball) { remove(self); return; }
-
-       EXACTTRIGGER_INIT;
-
-       if(self.team != GOAL_OUT && Team_TeamToNumber(self.team) != -1)
-       {
-               entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (self.absmin + self.absmax) * 0.5, self, sprite, RADARICON_NONE);
-               wp.colormod = ((self.team) ? Team_ColorRGB(self.team) : '1 0.5 0');
-               self.sprite.customizeentityforclient = nb_Goal_Customize;
-       }
-
-       self.classname = "nexball_goal";
-       if(self.noise == "")
-               self.noise = "ctf/respawn.wav";
-       precache_sound(self.noise);
-       self.touch = GoalTouch;
-}
-
-spawnfunc(nexball_redgoal)
-{
-       self.team = NUM_TEAM_1;
-       SpawnGoal();
-}
-spawnfunc(nexball_bluegoal)
-{
-       self.team = NUM_TEAM_2;
-       SpawnGoal();
-}
-spawnfunc(nexball_yellowgoal)
-{
-       self.team = NUM_TEAM_3;
-       SpawnGoal();
-}
-spawnfunc(nexball_pinkgoal)
-{
-       self.team = NUM_TEAM_4;
-       SpawnGoal();
-}
-
-spawnfunc(nexball_fault)
-{
-       self.team = GOAL_FAULT;
-       if(self.noise == "")
-               self.noise = SND(TYPEHIT);
-       SpawnGoal();
-}
-
-spawnfunc(nexball_out)
-{
-       self.team = GOAL_OUT;
-       if(self.noise == "")
-               self.noise = SND(TYPEHIT);
-       SpawnGoal();
-}
-
-//
-//Spawnfuncs preserved for compatibility
-//
-
-spawnfunc(ball)
-{
-       spawnfunc_nexball_football(this);
-}
-spawnfunc(ball_football)
-{
-       spawnfunc_nexball_football(this);
-}
-spawnfunc(ball_basketball)
-{
-       spawnfunc_nexball_basketball(this);
-}
-// The "red goal" is defended by blue team. A ball in there counts as a point for red.
-spawnfunc(ball_redgoal)
-{
-       spawnfunc_nexball_bluegoal(this);       // I blame Revenant
-}
-spawnfunc(ball_bluegoal)
-{
-       spawnfunc_nexball_redgoal(this);        // but he didn't mean to cause trouble :p
-}
-spawnfunc(ball_fault)
-{
-       spawnfunc_nexball_fault(this);
-}
-spawnfunc(ball_bound)
-{
-       spawnfunc_nexball_out(this);
-}
-
-//=======================//
-//       Weapon code     //
-//=======================//
-
-
-void W_Nexball_Think()
-{SELFPARAM();
-       //dprint("W_Nexball_Think\n");
-       //vector new_dir = steerlib_arrive(self.enemy.origin, 2500);
-       vector new_dir = normalize(self.enemy.origin + '0 0 50' - self.origin);
-       vector old_dir = normalize(self.velocity);
-       float _speed = vlen(self.velocity);
-       vector new_vel = normalize(old_dir + (new_dir * autocvar_g_nexball_safepass_turnrate)) * _speed;
-       //vector new_vel = (new_dir * autocvar_g_nexball_safepass_turnrate
-
-       self.velocity = new_vel;
-
-       self.nextthink = time;
-}
-
-void W_Nexball_Touch(void)
-{SELFPARAM();
-       entity ball, attacker;
-       attacker = self.owner;
-       //self.think = func_null;
-       //self.enemy = world;
-
-       PROJECTILE_TOUCH;
-       if(attacker.team != other.team || autocvar_g_nexball_basketball_teamsteal)
-               if((ball = other.ballcarried) && !other.frozen && !other.deadflag && (IS_PLAYER(attacker)))
-               {
-                       other.velocity = other.velocity + normalize(self.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
-                       other.flags &= ~FL_ONGROUND;
-                       if(!attacker.ballcarried)
-                       {
-                               LogNB("stole", attacker);
-                               _sound(other, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
-
-                               if(SAME_TEAM(attacker, other) && time > attacker.teamkill_complain)
-                               {
-                                       attacker.teamkill_complain = time + 5;
-                                       attacker.teamkill_soundtime = time + 0.4;
-                                       attacker.teamkill_soundsource = other;
-                               }
-
-                               GiveBall(attacker, other.ballcarried);
-                       }
-               }
-       remove(self);
-}
-
-void W_Nexball_Attack(float t)
-{SELFPARAM();
-       entity ball;
-       float mul, mi, ma;
-       if(!(ball = self.ballcarried))
-               return;
-
-       W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
-       tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, world);
-       if(trace_startsolid)
-       {
-               if(self.metertime)
-                       self.metertime = 0; // Shot failed, hide the power meter
-               return;
-       }
-
-       //Calculate multiplier
-       if(t < 0)
-               mul = 1;
-       else
-       {
-               mi = autocvar_g_nexball_basketball_meter_minpower;
-               ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion
-               //One triangle wave period with 1 as max
-               mul = 2 * (t % g_nexball_meter_period) / g_nexball_meter_period;
-               if(mul > 1)
-                       mul = 2 - mul;
-               mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power
-       }
-
-       DropBall(ball, w_shotorg, W_CalculateProjectileVelocity(self.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false));
-
-
-       //TODO: use the speed_up cvar too ??
-}
-
-vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
-
-void W_Nexball_Attack2(void)
-{SELFPARAM();
-       if(self.ballcarried.enemy)
-       {
-               entity _ball = self.ballcarried;
-               W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
-               DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
-               _ball.think = W_Nexball_Think;
-               _ball.nextthink = time;
-               return;
-       }
-
-       if(!autocvar_g_nexball_tackling)
-               return;
-
-       W_SetupShot(self, false, 2, SND(NB_SHOOT2), CH_WEAPON_A, 0);
-       entity missile = spawn();
-
-       missile.owner = self;
-       missile.classname = "ballstealer";
-
-       missile.movetype = MOVETYPE_FLY;
-       PROJECTILE_MAKETRIGGER(missile);
-
-       //setmodel(missile, "models/elaser.mdl");  // precision set below
-       setsize(missile, '0 0 0', '0 0 0');
-       setorigin(missile, w_shotorg);
-
-       W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0);
-       missile.angles = vectoangles(missile.velocity);
-       missile.touch = W_Nexball_Touch;
-       missile.think = SUB_Remove;
-       missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
-
-       missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
-       missile.flags = FL_PROJECTILE;
-
-       CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
-}
-
-float ball_customize()
-{SELFPARAM();
-       if(!self.owner)
-       {
-               self.effects &= ~EF_FLAME;
-               self.scale = 1;
-               self.customizeentityforclient = func_null;
-               return true;
-       }
-
-       if(other == self.owner)
-       {
-               self.scale = autocvar_g_nexball_viewmodel_scale;
-               if(self.enemy)
-                       self.effects |= EF_FLAME;
-               else
-                       self.effects &= ~EF_FLAME;
-       }
-       else
-       {
-               self.effects &= ~EF_FLAME;
-               self.scale = 1;
-       }
-
-       return true;
-}
-
-       METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, bool fire1, bool fire2))
-       {
-               if(fire1)
-                       if(weapon_prepareattack(thiswep, actor, false, autocvar_g_balance_nexball_primary_refire))
-                               if(autocvar_g_nexball_basketball_meter)
-                               {
-                                       if(self.ballcarried && !self.metertime)
-                                               self.metertime = time;
-                                       else
-                                               weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
-                               }
-                               else
-                               {
-                                       W_Nexball_Attack(-1);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
-                               }
-               if(fire2)
-                       if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_nexball_secondary_refire))
-                       {
-                               W_Nexball_Attack2();
-                               weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
-                       }
-
-               if(!fire1 && self.metertime && self.ballcarried)
-               {
-                       W_Nexball_Attack(time - self.metertime);
-                       // DropBall or stealing will set metertime back to 0
-                       weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
-               }
-       }
-       METHOD(BallStealer, wr_setup, void(BallStealer thiswep))
-       {
-               //weapon_setup(WEP_PORTO.m_id);
-       }
-       METHOD(BallStealer, wr_checkammo1, bool(BallStealer thiswep))
-       {
-               return true;
-       }
-       METHOD(BallStealer, wr_checkammo2, bool(BallStealer thiswep))
-       {
-               return true;
-       }
-
-MUTATOR_HOOKFUNCTION(nexball_BallDrop)
-{SELFPARAM();
-       if(self.ballcarried && g_nexball)
-               DropBall(self.ballcarried, self.origin, self.velocity);
-
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_PlayerPreThink)
-{SELFPARAM();
-       makevectors(self.v_angle);
-       if(nexball_mode & NBM_BASKETBALL)
-       {
-               if(self.ballcarried)
-               {
-                       // 'view ball'
-                       self.ballcarried.velocity = self.velocity;
-                       self.ballcarried.customizeentityforclient = ball_customize;
-
-                       setorigin(self.ballcarried, self.origin + self.view_ofs +
-                                         v_forward * autocvar_g_nexball_viewmodel_offset.x +
-                                         v_right * autocvar_g_nexball_viewmodel_offset.y +
-                                         v_up * autocvar_g_nexball_viewmodel_offset.z);
-
-                       // 'safe passing'
-                       if(autocvar_g_nexball_safepass_maxdist)
-                       {
-                               if(self.ballcarried.wait < time && self.ballcarried.enemy)
-                               {
-                                       //centerprint(self, sprintf("Lost lock on %s", self.ballcarried.enemy.netname));
-                                       self.ballcarried.enemy = world;
-                               }
-
-
-                               //tracebox(self.origin + self.view_ofs, '-2 -2 -2', '2 2 2', self.origin + self.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
-                               crosshair_trace(self);
-                               if( trace_ent &&
-                                       IS_CLIENT(trace_ent) &&
-                                       trace_ent.deadflag == DEAD_NO &&
-                                       trace_ent.team == self.team &&
-                                       vlen(trace_ent.origin - self.origin) <= autocvar_g_nexball_safepass_maxdist )
-                               {
-
-                                       //if(self.ballcarried.enemy != trace_ent)
-                                       //      centerprint(self, sprintf("Locked to %s", trace_ent.netname));
-                                       self.ballcarried.enemy = trace_ent;
-                                       self.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
-
-
-                               }
-                       }
-               }
-               else
-               {
-                       if(self.weaponentity.weapons)
-                       {
-                               self.weapons = self.weaponentity.weapons;
-                               Weapon w = WEP_NEXBALL;
-                               w.wr_resetplayer(w);
-                               self.switchweapon = self.weaponentity.switchweapon;
-                               W_SwitchWeapon(self.switchweapon);
-
-               self.weaponentity.weapons = '0 0 0';
-                       }
-               }
-
-       }
-
-       nexball_setstatus();
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_PlayerSpawn)
-{SELFPARAM();
-       self.weaponentity.weapons = '0 0 0';
-
-       if(nexball_mode & NBM_BASKETBALL)
-               self.weapons |= WEPSET(NEXBALL);
-       else
-               self.weapons = '0 0 0';
-
-       return false;
-}
-
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_maxspeed;
-
-MUTATOR_HOOKFUNCTION(nexball_PlayerPhysics)
-{SELFPARAM();
-       if(self.ballcarried)
-       {
-               self.stat_sv_airspeedlimit_nonqw *= autocvar_g_nexball_basketball_carrier_highspeed;
-               self.stat_sv_maxspeed *= autocvar_g_nexball_basketball_carrier_highspeed;
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_ForbidThrowing)
-{SELFPARAM();
-       if(self.weapon == WEP_NEXBALL.m_id)
-               return true;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_FilterItem)
-{SELFPARAM();
-       if(self.classname == "droppedweapon")
-       if(self.weapon == WEP_NEXBALL.m_id)
-               return true;
-
-       return false;
-}
-
-MUTATOR_DEFINITION(gamemode_nexball)
-{
-       MUTATOR_HOOK(PlayerDies, nexball_BallDrop, CBC_ORDER_ANY);
-       MUTATOR_HOOK(MakePlayerObserver, nexball_BallDrop, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ClientDisconnect, nexball_BallDrop, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerSpawn, nexball_PlayerSpawn, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerPreThink, nexball_PlayerPreThink, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerPhysics, nexball_PlayerPhysics, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ForbidThrowCurrentWeapon, nexball_ForbidThrowing, CBC_ORDER_ANY);
-       MUTATOR_HOOK(FilterItem, nexball_FilterItem, CBC_ORDER_ANY);
-
-       MUTATOR_ONADD
-       {
-               g_nexball_meter_period = autocvar_g_nexball_meter_period;
-               if(g_nexball_meter_period <= 0)
-                       g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
-               g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
-               addstat(STAT_NB_METERSTART, AS_FLOAT, metertime);
-
-               // General settings
-               /*
-               CVTOV(g_nexball_football_boost_forward);   //100
-               CVTOV(g_nexball_football_boost_up);             //200
-               CVTOV(g_nexball_delay_idle);                       //10
-               CVTOV(g_nexball_football_physics);               //0
-               */
-               radar_showennemies = autocvar_g_nexball_radar_showallplayers;
-
-               InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
-               WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               // we actually cannot roll back nb_delayedinit here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
diff --git a/qcsrc/server/mutators/gamemode_nexball.qh b/qcsrc/server/mutators/gamemode_nexball.qh
deleted file mode 100644 (file)
index e28fad8..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef GAMEMODE_NEXBALL_H
-#define GAMEMODE_NEXBALL_H
-
-//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
-const float BALL_EFFECTMASK = 1229;
-const vector BALL_MINS = '-16 -16 -16'; // The model is 24*24*24
-const vector BALL_MAXS = '16 16 16';
-const vector BALL_ATTACHORG = '3 0 16';
-const float BALL_FOOT = 1;
-const float BALL_BASKET = 2;
-//spawnflags
-const float GOAL_TOUCHPLAYER = 1;
-//goal types
-const float GOAL_FAULT = -1;
-const float GOAL_OUT = -2;
-
-void DropBall(entity ball, vector org, vector vel);
-float autocvar_g_nexball_football_boost_forward;
-float autocvar_g_nexball_football_boost_up;
-float autocvar_g_nexball_football_physics;
-float autocvar_g_nexball_delay_idle;
-float autocvar_g_nexball_basketball_delay_hold;
-float autocvar_g_nexball_basketball_delay_hold_forteam;
-float autocvar_g_nexball_basketball_effects_default;
-float autocvar_g_nexball_basketball_teamsteal;
-float autocvar_g_nexball_meter_period;
-
-float balls;
-float ball_scale;
-float nb_teams;
-
-.entity nb_dropper;
-.float nb_droptime;
-
-.float teamtime;
-#endif
diff --git a/qcsrc/server/mutators/gamemode_nexball_weapon.qc b/qcsrc/server/mutators/gamemode_nexball_weapon.qc
deleted file mode 100644 (file)
index ae882bb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef GAMEMODE_NEXBALL_WEAPON_H
-#define GAMEMODE_NEXBALL_WEAPON_H
-
-CLASS(BallStealer, PortoLaunch)
-/* flags     */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
-/* impulse   */ ATTRIB(BallStealer, impulse, int, 0);
-/* refname   */ ATTRIB(BallStealer, netname, string, "ballstealer");
-/* wepname   */ ATTRIB(BallStealer, message, string, _("Ball Stealer"));
-ENDCLASS(BallStealer)
-REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
-
-#endif
index 739eeb8..e222b7d 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "mutator.qh"
 
+#include "../../common/gamemodes/all.qh"
 #include "../../common/buffs/all.qh"
 
 entity buff_FirstFromFlags(int _buffs)
diff --git a/qcsrc/server/mutators/mutator_instagib.qc b/qcsrc/server/mutators/mutator_instagib.qc
deleted file mode 100644 (file)
index dc1d0eb..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-
-#include "mutator.qh"
-
-#include "../cl_client.qh"
-#include "../../common/buffs/all.qh"
-
-#include "../../common/items/all.qc"
-
-spawnfunc(item_minst_cells)
-{
-       if (!g_instagib) { remove(self); return; }
-       if (!self.ammo_cells) self.ammo_cells = autocvar_g_instagib_ammo_drop;
-       StartItemA(ITEM_VaporizerCells);
-}
-
-void instagib_invisibility()
-{SELFPARAM();
-       self.strength_finished = autocvar_g_balance_powerup_strength_time;
-       StartItemA(ITEM_Invisibility);
-}
-
-void instagib_extralife()
-{SELFPARAM();
-       self.max_health = 1;
-       StartItemA(ITEM_ExtraLife);
-}
-
-void instagib_speed()
-{SELFPARAM();
-       self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-       StartItemA(ITEM_Speed);
-}
-
-.float instagib_nextthink;
-.float instagib_needammo;
-void instagib_stop_countdown(entity e)
-{
-       if (!e.instagib_needammo)
-               return;
-       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_INSTAGIB_FINDAMMO);
-       e.instagib_needammo = false;
-}
-void instagib_ammocheck()
-{SELFPARAM();
-       if(time < self.instagib_nextthink)
-               return;
-       if(!IS_PLAYER(self))
-               return; // not a player
-
-       if(self.deadflag || gameover)
-               instagib_stop_countdown(self);
-       else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO) || (self.flags & FL_GODMODE))
-               instagib_stop_countdown(self);
-       else if(autocvar_g_rm && autocvar_g_rm_laser)
-       {
-               if(!self.instagib_needammo)
-               {
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
-                       self.instagib_needammo = true;
-               }
-       }
-       else
-       {
-               self.instagib_needammo = true;
-               if (self.health <= 5)
-               {
-                       Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
-               }
-               else if (self.health <= 10)
-               {
-                       Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
-               }
-               else if (self.health <= 20)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
-               }
-               else if (self.health <= 30)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
-               }
-               else if (self.health <= 40)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
-               }
-               else if (self.health <= 50)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
-               }
-               else if (self.health <= 60)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
-               }
-               else if (self.health <= 70)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
-               }
-               else if (self.health <= 80)
-               {
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
-               }
-               else if (self.health <= 90)
-               {
-                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
-               }
-               else
-               {
-                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
-                       Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
-               }
-       }
-       self.instagib_nextthink = time + 1;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MatchEnd)
-{
-       entity head;
-       FOR_EACH_PLAYER(head)
-               instagib_stop_countdown(head);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MonsterLoot)
-{
-       other.monster_loot = spawnfunc_item_minst_cells;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MonsterSpawn)
-{SELFPARAM();
-       // always refill ammo
-       if(self.monsterid == MON_MAGE.monsterid)
-               self.skin = 1;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_BotShouldAttack)
-{
-       if (checkentity.items & ITEM_Invisibility.m_itemid)
-               return true;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MakePlayerObserver)
-{SELFPARAM();
-       instagib_stop_countdown(self);
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerSpawn)
-{SELFPARAM();
-       self.effects |= EF_FULLBRIGHT;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerPreThink)
-{
-       instagib_ammocheck();
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerRegen)
-{
-       // no regeneration in instagib
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerPowerups)
-{SELFPARAM();
-       if (!(self.effects & EF_FULLBRIGHT))
-               self.effects |= EF_FULLBRIGHT;
-
-       if (self.items & ITEM_Invisibility.m_itemid)
-       {
-               play_countdown(self.strength_finished, SND(POWEROFF));
-               if (time > self.strength_finished)
-               {
-                       self.alpha = default_player_alpha;
-                       self.exteriorweaponentity.alpha = default_weapon_alpha;
-                       self.items &= ~ITEM_Invisibility.m_itemid;
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
-               }
-       }
-       else
-       {
-               if (time < self.strength_finished)
-               {
-                       self.alpha = autocvar_g_instagib_invis_alpha;
-                       self.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
-                       self.items |= ITEM_Invisibility.m_itemid;
-                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
-               }
-       }
-
-       if (self.items & ITEM_Speed.m_itemid)
-       {
-               play_countdown(self.invincible_finished, SND(POWEROFF));
-               if (time > self.invincible_finished)
-               {
-                       self.items &= ~ITEM_Speed.m_itemid;
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
-               }
-       }
-       else
-       {
-               if (time < self.invincible_finished)
-               {
-                       self.items |= ITEM_Speed.m_itemid;
-                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
-               }
-       }
-       return false;
-}
-
-.float stat_sv_maxspeed;
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerPhysics)
-{SELFPARAM();
-       if(self.items & ITEM_Speed.m_itemid)
-               self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_SplitHealthArmor)
-{
-       damage_save = 0;
-       damage_take = frag_damage;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_ForbidThrowing)
-{
-       // weapon dropping on death handled by FilterItem
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
-{
-       if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
-               frag_damage = 0;
-
-       if(IS_PLAYER(frag_target))
-       {
-               if(frag_deathtype == DEATH_FALL)
-                       frag_damage = 0; // never count fall damage
-
-               if(!autocvar_g_instagib_damagedbycontents)
-               switch(frag_deathtype)
-               {
-                       case DEATH_DROWN:
-                       case DEATH_SLIME:
-                       case DEATH_LAVA:
-                               frag_damage = 0;
-                               break;
-               }
-
-               if(IS_PLAYER(frag_attacker))
-               if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER.m_id))
-               {
-                       if(frag_target.armorvalue)
-                       {
-                               frag_target.armorvalue -= 1;
-                               frag_damage = 0;
-                               frag_target.damage_dealt += 1;
-                               frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
-                               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
-                       }
-               }
-
-               if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER.m_id))
-               {
-                       if(frag_deathtype & HITTYPE_SECONDARY)
-                       {
-                               if(!autocvar_g_instagib_blaster_keepdamage)
-                                       frag_damage = frag_mirrordamage = 0;
-
-                               if(frag_target != frag_attacker)
-                               {
-                                       if(frag_damage <= 0 && frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
-                                       if(!autocvar_g_instagib_blaster_keepforce)
-                                               frag_force = '0 0 0';
-                               }
-                       }
-               }
-       }
-
-       if(IS_PLAYER(frag_attacker))
-       if(frag_mirrordamage > 0)
-       {
-               // just lose extra LIVES, don't kill the player for mirror damage
-               if(frag_attacker.armorvalue > 0)
-               {
-                       frag_attacker.armorvalue -= 1;
-                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
-                       frag_attacker.damage_dealt += frag_mirrordamage;
-               }
-               frag_mirrordamage = 0;
-       }
-
-       if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Invisibility.m_itemid))
-               yoda = 1;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_SetStartItems)
-{
-       start_health       = warmup_start_health       = 100;
-       start_armorvalue   = warmup_start_armorvalue   = 0;
-
-       start_ammo_shells  = warmup_start_ammo_shells  = 0;
-       start_ammo_nails   = warmup_start_ammo_nails   = 0;
-       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_instagib_ammo_start");
-       start_ammo_plasma  = warmup_start_ammo_plasma  = 0;
-       start_ammo_rockets = warmup_start_ammo_rockets = 0;
-       start_ammo_fuel    = warmup_start_ammo_fuel    = 0;
-
-       start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
-       start_items |= IT_UNLIMITED_SUPERWEAPONS;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_FilterItem)
-{SELFPARAM();
-       if(self.classname == "item_cells")
-               return true; // no normal cells?
-
-       if(self.weapon == WEP_VAPORIZER.m_id && self.classname == "droppedweapon")
-       {
-               self.ammo_cells = autocvar_g_instagib_ammo_drop;
-               return false;
-       }
-
-       if(self.weapon == WEP_DEVASTATOR.m_id || self.weapon == WEP_VORTEX.m_id)
-       {
-               entity e = spawn();
-               setorigin(e, self.origin);
-               e.noalign = self.noalign;
-        e.cnt = self.cnt;
-        e.team = self.team;
-               WITH(entity, self, e, spawnfunc_item_minst_cells(e));
-               return true;
-       }
-
-       if(self.flags & FL_POWERUP)
-               return false;
-
-       if(self.ammo_cells > autocvar_g_instagib_ammo_drop && self.classname != "item_minst_cells")
-               self.ammo_cells = autocvar_g_instagib_ammo_drop;
-
-       if(self.ammo_cells && !self.weapon)
-               return false;
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_CustomizeWaypoint)
-{SELFPARAM();
-       entity e = WaypointSprite_getviewentity(other);
-
-       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
-       // but only apply this to real players, not to spectators
-       if((self.owner.flags & FL_CLIENT) && (self.owner.items & ITEM_Invisibility.m_itemid) && (e == other))
-       if(DIFF_TEAM(self.owner, e))
-               return true;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerDies)
-{
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER.m_id))
-               frag_damage = 1000; // always gib if it was a vaporizer death
-
-       return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_ItemTouch)
-{SELFPARAM();
-       if(self.ammo_cells)
-       {
-               // play some cool sounds ;)
-               if (IS_CLIENT(other))
-               {
-                       if(other.health <= 5)
-                               Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
-                       else if(other.health < 50)
-                               Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
-               }
-
-               if(other.health < 100)
-                       other.health = 100;
-
-               return MUT_ITEMTOUCH_CONTINUE;
-       }
-
-       if(self.max_health)
-       {
-               other.armorvalue = bound(other.armorvalue, 999, other.armorvalue + autocvar_g_instagib_extralives);
-               Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
-               return MUT_ITEMTOUCH_PICKUP;
-       }
-
-       return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_OnEntityPreSpawn)
-{SELFPARAM();
-       if (!autocvar_g_powerups) { return false; }
-       // Can't use .itemdef here
-       if (!(self.classname == "item_strength" || self.classname == "item_invincible" || self.classname == "item_health_mega"))
-               return false;
-
-       entity e = spawn();
-
-       float r = random();
-       if (r < 0.3)
-               e.think = instagib_invisibility;
-       else if (r < 0.6)
-               e.think = instagib_extralife;
-       else
-               e.think = instagib_speed;
-
-       e.nextthink = time + 0.1;
-       e.spawnflags = self.spawnflags;
-       e.noalign = self.noalign;
-       setorigin(e, self.origin);
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":instagib");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", instagib");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_SetModname)
-{
-       modname = "instagib";
-       return true;
-}
-
-MUTATOR_DEFINITION(mutator_instagib)
-{
-       MUTATOR_HOOK(MatchEnd, instagib_MatchEnd, CBC_ORDER_ANY);
-       MUTATOR_HOOK(MonsterDropItem, instagib_MonsterLoot, CBC_ORDER_ANY);
-       MUTATOR_HOOK(MonsterSpawn, instagib_MonsterSpawn, CBC_ORDER_ANY);
-       MUTATOR_HOOK(BotShouldAttack, instagib_BotShouldAttack, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerPhysics, instagib_PlayerPhysics, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerSpawn, instagib_PlayerSpawn, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerDamage_Calculate, instagib_PlayerDamage, CBC_ORDER_ANY);
-       MUTATOR_HOOK(MakePlayerObserver, instagib_MakePlayerObserver, CBC_ORDER_ANY);
-       MUTATOR_HOOK(SetStartItems, instagib_SetStartItems, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ItemTouch, instagib_ItemTouch, CBC_ORDER_ANY);
-       MUTATOR_HOOK(FilterItem, instagib_FilterItem, CBC_ORDER_ANY);
-       MUTATOR_HOOK(CustomizeWaypoint, instagib_CustomizeWaypoint, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerDies, instagib_PlayerDies, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerDamage_SplitHealthArmor, instagib_SplitHealthArmor, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerPowerups, instagib_PlayerPowerups, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ForbidThrowCurrentWeapon, instagib_ForbidThrowing, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerPreThink, instagib_PlayerPreThink, CBC_ORDER_ANY);
-       MUTATOR_HOOK(PlayerRegen, instagib_PlayerRegen, CBC_ORDER_ANY);
-       MUTATOR_HOOK(OnEntityPreSpawn, instagib_OnEntityPreSpawn, CBC_ORDER_ANY);
-       MUTATOR_HOOK(BuildMutatorsString, instagib_BuildMutatorsString, CBC_ORDER_ANY);
-       MUTATOR_HOOK(BuildMutatorsPrettyString, instagib_BuildMutatorsPrettyString, CBC_ORDER_ANY);
-       MUTATOR_HOOK(SetModname, instagib_SetModname, CBC_ORDER_ANY);
-
-       return false;
-}
diff --git a/qcsrc/server/mutators/mutator_instagib_items.qc b/qcsrc/server/mutators/mutator_instagib_items.qc
deleted file mode 100644 (file)
index deecb14..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "../../common/items/all.qh"
-#include "../../common/items/item/ammo.qh"
-#include "../../common/items/item/powerup.qh"
-
-float instagib_respawntime_ammo = 45;
-float instagib_respawntimejitter_ammo = 0;
-GETTER(float, instagib_respawntime_ammo)
-GETTER(float, instagib_respawntimejitter_ammo)
-
-#ifndef MENUQC
-MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
-#endif
-
-REGISTER_ITEM(VaporizerCells, Ammo) {
-#ifndef MENUQC
-    this.m_model                =   MDL_VaporizerCells_ITEM;
-#endif
-    this.m_sound                =   "misc/itempickup.wav";
-    this.m_name                 =   "Vaporizer Ammo";
-    this.m_icon                 =   "ammo_supercells";
-#ifdef SVQC
-    this.m_botvalue             =   100;
-    this.m_itemid               =   IT_CELLS;
-    this.m_respawntime          =   GET(instagib_respawntime_ammo);
-    this.m_respawntimejitter    =   GET(instagib_respawntimejitter_ammo);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
-#endif
-
-REGISTER_ITEM(ExtraLife, Powerup) {
-#ifndef MENUQC
-    this.m_model                =   MDL_ExtraLife_ITEM;
-#endif
-    this.m_sound                =   "misc/megahealth.wav";
-    this.m_name                 =   "Extra life";
-    this.m_icon                 =   "item_mega_health";
-    this.m_color                =   '1 0 0';
-    this.m_waypoint             =   _("Extra life");
-    this.m_waypointblink        =   2;
-    this.m_itemid               =   IT_NAILS;
-}
-
-#ifndef MENUQC
-MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
-#endif
-
-REGISTER_ITEM(Invisibility, Powerup) {
-#ifndef MENUQC
-    this.m_model            =   MDL_Invisibility_ITEM;
-#endif
-    this.m_sound            =   "misc/powerup.wav";
-    this.m_name             =   "Invisibility";
-    this.m_icon             =   "strength";
-    this.m_color            =   '0 0 1';
-    this.m_waypoint         =   _("Invisibility");
-    this.m_waypointblink    =   2;
-    this.m_itemid           =   IT_STRENGTH;
-}
-
-#ifndef MENUQC
-MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
-#endif
-
-REGISTER_ITEM(Speed, Powerup) {
-#ifndef MENUQC
-    this.m_model            =   MDL_Speed_ITEM;
-#endif
-    this.m_sound            =   "misc/powerup_shield.wav";
-    this.m_name             =   "Speed";
-    this.m_icon             =   "shield";
-    this.m_color            =   '1 0 1';
-    this.m_waypoint         =   _("Speed");
-    this.m_waypointblink    =   2;
-    this.m_itemid           =   IT_INVINCIBLE;
-}
index 1a07f5e..f665fbc 100644 (file)
@@ -5,6 +5,7 @@
 #include "gamemode_keyhunt.qh"
 #include "gamemode_freezetag.qh"
 #include "../../common/nades/all.qh"
+#include "../../common/gamemodes/all.qh"
 #include "../../common/monsters/spawn.qh"
 #include "../../common/monsters/sv_monsters.qh"
 #include "../g_subs.qh"
index de32a17..93fc4cf 100644 (file)
@@ -14,7 +14,6 @@ void mutators_add()
        CHECK_MUTATOR_ADD("g_spawn_near_teammate", mutator_spawn_near_teammate, teamplay);
        CHECK_MUTATOR_ADD("g_physical_items", mutator_physical_items, 1);
        CHECK_MUTATOR_ADD("g_touchexplode", mutator_touchexplode, 1);
-       CHECK_MUTATOR_ADD("g_instagib", mutator_instagib, !g_nexball);
        CHECK_MUTATOR_ADD("g_invincible_projectiles", mutator_invincibleprojectiles, 1);
        CHECK_MUTATOR_ADD("g_new_toys", mutator_new_toys, !cvar("g_instagib") && !cvar("g_overkill"));
        CHECK_MUTATOR_ADD("g_nix", mutator_nix, !cvar("g_instagib") && !cvar("g_overkill"));
index e1355a4..b65cbd2 100644 (file)
@@ -7,7 +7,6 @@ MUTATOR_DECLARATION(gamemode_keyhunt);
 MUTATOR_DECLARATION(gamemode_freezetag);
 MUTATOR_DECLARATION(gamemode_keepaway);
 MUTATOR_DECLARATION(gamemode_ctf);
-MUTATOR_DECLARATION(gamemode_nexball);
 MUTATOR_DECLARATION(gamemode_onslaught);
 MUTATOR_DECLARATION(gamemode_domination);
 MUTATOR_DECLARATION(gamemode_lms);
@@ -26,7 +25,6 @@ MUTATOR_DECLARATION(mutator_spawn_near_teammate);
 MUTATOR_DECLARATION(mutator_physical_items);
 MUTATOR_DECLARATION(mutator_vampire);
 MUTATOR_DECLARATION(mutator_superspec);
-MUTATOR_DECLARATION(mutator_instagib);
 MUTATOR_DECLARATION(mutator_touchexplode);
 MUTATOR_DECLARATION(mutator_pinata);
 MUTATOR_DECLARATION(mutator_midair);
index fe8fe0f..9d67e03 100644 (file)
@@ -85,7 +85,6 @@
 #include "gamemode_keepaway.qc"
 #include "gamemode_keyhunt.qc"
 #include "gamemode_lms.qc"
-#include "gamemode_nexball.qc"
 #include "gamemode_onslaught.qc"
 #include "gamemode_race.qc"
 #include "gamemode_tdm.qc"
@@ -96,7 +95,6 @@
 #include "mutator_campcheck.qc"
 #include "mutator_dodging.qc"
 #include "mutator_hook.qc"
-#include "mutator_instagib.qc"
 #include "mutator_invincibleproj.qc"
 #include "mutator_melee_only.qc"
 #include "mutator_midair.qc"
index dcd2944..e7144bc 100644 (file)
@@ -13,7 +13,6 @@
 #include "gamemode_keepaway.qh"
 #include "gamemode_keyhunt.qh"
 #include "gamemode_lms.qh"
-#include "gamemode_nexball.qh"
 #include "gamemode_onslaught.qh"
 #include "gamemode_race.qh"
 
index 2adaf83..6c48f2f 100644 (file)
@@ -79,6 +79,7 @@
 
 #include "../common/buffs/all.qc"
 #include "../common/effects/all.qc"
+#include "../common/gamemodes/all.qc"
 #include "../common/items/all.qc"
 #include "../common/monsters/all.qc"
 #include "../common/mutators/all.qc"
index 46b82ac..b279def 100644 (file)
@@ -12,6 +12,7 @@
 #include "mutators/mutators_include.qh"
 
 #include "../common/deathtypes.qh"
+#include "../common/gamemodes/all.qh"
 #include "../common/teams.qh"
 
 void TeamchangeFrags(entity e)