Merge branch 'TimePath/gamerules' into 'master'
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 27 Aug 2017 12:00:52 +0000 (12:00 +0000)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 27 Aug 2017 12:00:52 +0000 (12:00 +0000)
Lightly refactor gamemodes

See merge request !472

53 files changed:
qcsrc/common/gamemodes/_mod.inc
qcsrc/common/gamemodes/_mod.qh
qcsrc/common/gamemodes/gamemode/nexball/_mod.inc
qcsrc/common/gamemodes/gamemode/nexball/_mod.qh
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/nexball/sv_weapon.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/nexball/sv_weapon.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qh
qcsrc/common/gamemodes/rules.qc [new file with mode: 0644]
qcsrc/common/gamemodes/rules.qh [new file with mode: 0644]
qcsrc/common/gamemodes/sv_rules.qc [new file with mode: 0644]
qcsrc/common/gamemodes/sv_rules.qh [new file with mode: 0644]
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/base.qh
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/playerstats.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/g_world.qh
qcsrc/server/mutators/gamemode.qh
qcsrc/server/mutators/mutator/gamemode_assault.qc
qcsrc/server/mutators/mutator/gamemode_assault.qh
qcsrc/server/mutators/mutator/gamemode_ca.qc
qcsrc/server/mutators/mutator/gamemode_ca.qh
qcsrc/server/mutators/mutator/gamemode_ctf.qc
qcsrc/server/mutators/mutator/gamemode_ctf.qh
qcsrc/server/mutators/mutator/gamemode_cts.qc
qcsrc/server/mutators/mutator/gamemode_cts.qh
qcsrc/server/mutators/mutator/gamemode_deathmatch.qh
qcsrc/server/mutators/mutator/gamemode_domination.qc
qcsrc/server/mutators/mutator/gamemode_domination.qh
qcsrc/server/mutators/mutator/gamemode_freezetag.qc
qcsrc/server/mutators/mutator/gamemode_freezetag.qh
qcsrc/server/mutators/mutator/gamemode_invasion.qc
qcsrc/server/mutators/mutator/gamemode_invasion.qh
qcsrc/server/mutators/mutator/gamemode_keepaway.qc
qcsrc/server/mutators/mutator/gamemode_keepaway.qh
qcsrc/server/mutators/mutator/gamemode_keyhunt.qc
qcsrc/server/mutators/mutator/gamemode_keyhunt.qh
qcsrc/server/mutators/mutator/gamemode_lms.qc
qcsrc/server/mutators/mutator/gamemode_lms.qh
qcsrc/server/mutators/mutator/gamemode_race.qc
qcsrc/server/mutators/mutator/gamemode_race.qh
qcsrc/server/mutators/mutator/gamemode_tdm.qc
qcsrc/server/mutators/mutator/gamemode_tdm.qh
qcsrc/server/player.qc
qcsrc/server/race.qc
qcsrc/server/scores.qh
qcsrc/server/scores_rules.qc
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh

index c3cec69..90cfa6a 100644 (file)
@@ -1,3 +1,7 @@
 // generated file; do not modify
+#include <common/gamemodes/rules.qc>
+#ifdef SVQC
+    #include <common/gamemodes/sv_rules.qc>
+#endif
 
 #include <common/gamemodes/gamemode/_mod.inc>
index 685c277..b3ed42d 100644 (file)
@@ -1,3 +1,7 @@
 // generated file; do not modify
+#include <common/gamemodes/rules.qh>
+#ifdef SVQC
+    #include <common/gamemodes/sv_rules.qh>
+#endif
 
 #include <common/gamemodes/gamemode/_mod.qh>
index f48ef74..7872767 100644 (file)
@@ -1,3 +1,6 @@
 // generated file; do not modify
 #include <common/gamemodes/gamemode/nexball/nexball.qc>
 #include <common/gamemodes/gamemode/nexball/weapon.qc>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/nexball/sv_weapon.qc>
+#endif
index 4ac2347..a1cf544 100644 (file)
@@ -1,3 +1,6 @@
 // generated file; do not modify
 #include <common/gamemodes/gamemode/nexball/nexball.qh>
 #include <common/gamemodes/gamemode/nexball/weapon.qh>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/nexball/sv_weapon.qh>
+#endif
index 6be1d95..5a0ff2a 100644 (file)
@@ -15,6 +15,8 @@ MUTATOR_HOOKFUNCTION(cl_nb, WantEventchase)
 #ifdef SVQC
 .float metertime = _STAT(NB_METERSTART);
 
+.entity ballcarried;
+
 int autocvar_g_nexball_goalleadlimit;
 #define autocvar_g_nexball_goallimit cvar("g_nexball_goallimit")
 
@@ -69,14 +71,14 @@ float OtherTeam(float t)  //works only if there are two teams on the map!
        return e.team;
 }
 
-const float ST_NEXBALL_GOALS = 1;
+const int ST_NEXBALL_GOALS = 1;
 void nb_ScoreRules(int 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();
+    GameRules_scoring(teams, 0, 0, {
+        field_team(ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+        field(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+        field(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
+    });
 }
 
 void LogNB(string mode, entity actor)
@@ -151,6 +153,7 @@ void GiveBall(entity plyr, entity ball)
        {
                ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
                ownr.ballcarried = NULL;
+               GameRules_scoring_vip(ownr, false);
                if(ownr.metertime)
                {
                        ownr.metertime = 0;
@@ -173,6 +176,7 @@ void GiveBall(entity plyr, entity ball)
        ball.weaponentity_fld = weaponentity;
        ball.team = plyr.team;
        plyr.ballcarried = ball;
+       GameRules_scoring_vip(plyr, true);
        ball.nb_dropper = plyr;
 
        plyr.effects |= autocvar_g_nexball_basketball_effects_default;
@@ -230,8 +234,9 @@ void DropBall(entity ball, vector org, vector vel)
        WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
        WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
 
-       ball.owner.ballcarried = NULL;
-       ball.owner = NULL;
+       entity e = ball.owner; ball.owner = NULL;
+       e.ballcarried = NULL;
+       GameRules_scoring_vip(e, false);
 }
 
 void InitBall(entity this)
@@ -430,9 +435,9 @@ void GoalTouch(entity this, entity toucher)
        if(isclient)
        {
                if(pscore > 0)
-                       PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore);
+                       GameRules_scoring_add(ball.pusher, NEXBALL_GOALS, pscore);
                else if(pscore < 0)
-                       PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore);
+                       GameRules_scoring_add(ball.pusher, NEXBALL_FAULTS, -pscore);
        }
 
        if(ball.owner)  // Happens on spawnflag GOAL_TOUCHPLAYER
@@ -717,136 +722,6 @@ spawnfunc(ball_bound)
        spawnfunc_nexball_out(this);
 }
 
-//=======================//
-//       Weapon code     //
-//=======================//
-
-
-void W_Nexball_Think(entity this)
-{
-       //dprint("W_Nexball_Think\n");
-       //vector new_dir = steerlib_arrive(this.enemy.origin, 2500);
-       vector new_dir = normalize(this.enemy.origin + '0 0 50' - this.origin);
-       vector old_dir = normalize(this.velocity);
-       float _speed = vlen(this.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
-
-       this.velocity = new_vel;
-
-       this.nextthink = time;
-}
-
-void W_Nexball_Touch(entity this, entity toucher)
-{
-       entity ball, attacker;
-       attacker = this.owner;
-       //this.think = func_null;
-       //this.enemy = NULL;
-
-       PROJECTILE_TOUCH(this, toucher);
-       if(attacker.team != toucher.team || autocvar_g_nexball_basketball_teamsteal)
-               if((ball = toucher.ballcarried) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (IS_PLAYER(attacker)))
-               {
-                       toucher.velocity = toucher.velocity + normalize(this.velocity) * toucher.damageforcescale * autocvar_g_balance_nexball_secondary_force;
-                       UNSET_ONGROUND(toucher);
-                       if(!attacker.ballcarried)
-                       {
-                               LogNB("stole", attacker);
-                               _sound(toucher, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
-
-                               if(SAME_TEAM(attacker, toucher) && time > CS(attacker).teamkill_complain)
-                               {
-                                       CS(attacker).teamkill_complain = time + 5;
-                                       CS(attacker).teamkill_soundtime = time + 0.4;
-                                       CS(attacker).teamkill_soundsource = toucher;
-                               }
-
-                               GiveBall(attacker, toucher.ballcarried);
-                       }
-               }
-       delete(this);
-}
-
-void W_Nexball_Attack(entity actor, .entity weaponentity, float t)
-{
-       entity ball;
-       float mul, mi, ma;
-       if(!(ball = actor.ballcarried))
-               return;
-
-       W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
-       tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, NULL);
-       if(trace_startsolid)
-       {
-               if(actor.metertime)
-                       actor.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(actor, actor.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(entity actor, .entity weaponentity)
-{
-       if(actor.ballcarried.enemy)
-       {
-               entity _ball = actor.ballcarried;
-               W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
-               DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
-               setthink(_ball, W_Nexball_Think);
-               _ball.nextthink = time;
-               return;
-       }
-
-       if(!autocvar_g_nexball_tackling)
-               return;
-
-       W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0);
-       entity missile = new(ballstealer);
-
-       missile.owner = actor;
-
-       set_movetype(missile, 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);
-       settouch(missile, W_Nexball_Touch);
-       setthink(missile, 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;
-       IL_PUSH(g_projectiles, missile);
-       IL_PUSH(g_bot_dodge, missile);
-
-       CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
-}
-
 bool ball_customize(entity this, entity client)
 {
        if(!this.owner)
@@ -874,61 +749,6 @@ bool ball_customize(entity this, entity client)
        return true;
 }
 
-METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity weaponentity, int fire))
-{
-    TC(BallStealer, thiswep);
-    if(fire & 1)
-        if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire))
-            if(autocvar_g_nexball_basketball_meter)
-            {
-                if(actor.ballcarried && !actor.metertime)
-                    actor.metertime = time;
-                else
-                    weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
-            }
-            else
-            {
-                W_Nexball_Attack(actor, weaponentity, -1);
-                weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
-            }
-    if(fire & 2)
-        if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire))
-        {
-            W_Nexball_Attack2(actor, weaponentity);
-            weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
-        }
-
-    if(!(fire & 1) && actor.metertime && actor.ballcarried)
-    {
-        W_Nexball_Attack(actor, weaponentity, time - actor.metertime);
-        // DropBall or stealing will set metertime back to 0
-        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
-    }
-}
-
-METHOD(BallStealer, wr_setup, void(BallStealer this, entity actor, .entity weaponentity))
-{
-    TC(BallStealer, this);
-    //weapon_setup(WEP_PORTO.m_id);
-}
-
-METHOD(BallStealer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
-{
-    TC(BallStealer, this);
-}
-
-METHOD(BallStealer, wr_checkammo1, bool(BallStealer this, entity actor, .entity weaponentity))
-{
-    TC(BallStealer, this);
-    return true;
-}
-
-METHOD(BallStealer, wr_checkammo2, bool(BallStealer this, entity actor, .entity weaponentity))
-{
-    TC(BallStealer, this);
-    return true;
-}
-
 void nb_DropBall(entity player)
 {
        if(player.ballcarried && g_nexball)
@@ -1136,6 +956,7 @@ MUTATOR_HOOKFUNCTION(nb, SendWaypoint)
 
 REGISTER_MUTATOR(nb, g_nexball)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
                g_nexball_meter_period = autocvar_g_nexball_meter_period;
@@ -1155,25 +976,15 @@ REGISTER_MUTATOR(nb, g_nexball)
                InitializeEntity(NULL, nb_delayedinit, INITPRIO_GAMETYPE);
                WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
 
-               ActivateTeamplay();
-               SetLimits(autocvar_g_nexball_goallimit, autocvar_g_nexball_goalleadlimit, autocvar_timelimit_override, -1);
-               have_team_spawns = -1; // request team spawns
+               GameRules_teams(true);
+               GameRules_limit_score(autocvar_g_nexball_goallimit);
+               GameRules_limit_lead(autocvar_g_nexball_goalleadlimit);
        }
 
        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/common/gamemodes/gamemode/nexball/sv_weapon.qc b/qcsrc/common/gamemodes/gamemode/nexball/sv_weapon.qc
new file mode 100644 (file)
index 0000000..705ac6d
--- /dev/null
@@ -0,0 +1,183 @@
+#include "sv_weapon.qh"
+
+void W_Nexball_Attack(entity actor, .entity weaponentity, float t);
+void W_Nexball_Attack2(entity actor, .entity weaponentity);
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
+
+METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity weaponentity, int fire))
+{
+    TC(BallStealer, thiswep);
+    if(fire & 1)
+        if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire))
+            if(autocvar_g_nexball_basketball_meter)
+            {
+                if(actor.ballcarried && !actor.metertime)
+                    actor.metertime = time;
+                else
+                    weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+            }
+            else
+            {
+                W_Nexball_Attack(actor, weaponentity, -1);
+                weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+            }
+    if(fire & 2)
+        if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire))
+        {
+            W_Nexball_Attack2(actor, weaponentity);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
+        }
+
+    if(!(fire & 1) && actor.metertime && actor.ballcarried)
+    {
+        W_Nexball_Attack(actor, weaponentity, time - actor.metertime);
+        // DropBall or stealing will set metertime back to 0
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+    }
+}
+
+METHOD(BallStealer, wr_setup, void(BallStealer this, entity actor, .entity weaponentity))
+{
+    TC(BallStealer, this);
+    //weapon_setup(WEP_PORTO.m_id);
+}
+
+METHOD(BallStealer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+    TC(BallStealer, this);
+}
+
+METHOD(BallStealer, wr_checkammo1, bool(BallStealer this, entity actor, .entity weaponentity))
+{
+    TC(BallStealer, this);
+    return true;
+}
+
+METHOD(BallStealer, wr_checkammo2, bool(BallStealer this, entity actor, .entity weaponentity))
+{
+    TC(BallStealer, this);
+    return true;
+}
+
+void W_Nexball_Think(entity this)
+{
+       //dprint("W_Nexball_Think\n");
+       //vector new_dir = steerlib_arrive(this.enemy.origin, 2500);
+       vector new_dir = normalize(this.enemy.origin + '0 0 50' - this.origin);
+       vector old_dir = normalize(this.velocity);
+       float _speed = vlen(this.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
+
+       this.velocity = new_vel;
+
+       this.nextthink = time;
+}
+
+void W_Nexball_Touch(entity this, entity toucher)
+{
+       entity ball, attacker;
+       attacker = this.owner;
+       //this.think = func_null;
+       //this.enemy = NULL;
+
+       PROJECTILE_TOUCH(this, toucher);
+       if(attacker.team != toucher.team || autocvar_g_nexball_basketball_teamsteal)
+               if((ball = toucher.ballcarried) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (IS_PLAYER(attacker)))
+               {
+                       toucher.velocity = toucher.velocity + normalize(this.velocity) * toucher.damageforcescale * autocvar_g_balance_nexball_secondary_force;
+                       UNSET_ONGROUND(toucher);
+                       if(!attacker.ballcarried)
+                       {
+                               LogNB("stole", attacker);
+                               _sound(toucher, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
+
+                               if(SAME_TEAM(attacker, toucher) && time > CS(attacker).teamkill_complain)
+                               {
+                                       CS(attacker).teamkill_complain = time + 5;
+                                       CS(attacker).teamkill_soundtime = time + 0.4;
+                                       CS(attacker).teamkill_soundsource = toucher;
+                               }
+
+                               GiveBall(attacker, toucher.ballcarried);
+                       }
+               }
+       delete(this);
+}
+
+void W_Nexball_Attack(entity actor, .entity weaponentity, float t)
+{
+       entity ball;
+       float mul, mi, ma;
+       if(!(ball = actor.ballcarried))
+               return;
+
+       W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
+       tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, NULL);
+       if(trace_startsolid)
+       {
+               if(actor.metertime)
+                       actor.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(actor, actor.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false));
+
+
+       //TODO: use the speed_up cvar too ??
+}
+
+void W_Nexball_Attack2(entity actor, .entity weaponentity)
+{
+       if(actor.ballcarried.enemy)
+       {
+               entity _ball = actor.ballcarried;
+               W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
+               DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
+               setthink(_ball, W_Nexball_Think);
+               _ball.nextthink = time;
+               return;
+       }
+
+       if(!autocvar_g_nexball_tackling)
+               return;
+
+       W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0);
+       entity missile = new(ballstealer);
+
+       missile.owner = actor;
+
+       set_movetype(missile, 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);
+       settouch(missile, W_Nexball_Touch);
+       setthink(missile, 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;
+       IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
+
+       CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
+}
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/sv_weapon.qh b/qcsrc/common/gamemodes/gamemode/nexball/sv_weapon.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 9992a37..0150de3 100644 (file)
@@ -426,8 +426,8 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
                pointparticles(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_CPDESTROYED), this.owner.message, attacker.netname);
 
-               PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
-               PlayerScore_Add(attacker, SP_SCORE, 10);
+               GameRules_scoring_add(attacker, ONS_TAKES, 1);
+               GameRules_scoring_add(attacker, SCORE, 10);
 
                this.owner.goalentity = NULL;
                this.owner.islinked = false;
@@ -555,8 +555,8 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, this.owner.ons_toucher.netname, this.owner.message);
                        Send_Notification(NOTIF_ALL_EXCEPT, this.owner.ons_toucher, MSG_CENTER, APP_TEAM_NUM(this.owner.ons_toucher.team, CENTER_ONS_CAPTURE_TEAM), this.owner.message);
                        Send_Notification(NOTIF_ONE, this.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, this.owner.message);
-                       PlayerScore_Add(this.owner.ons_toucher, SP_ONS_CAPS, 1);
-                       PlayerTeamScore_AddScore(this.owner.ons_toucher, 10);
+                       GameRules_scoring_add(this.owner.ons_toucher, ONS_CAPS, 1);
+                       GameRules_scoring_add_team(this.owner.ons_toucher, SCORE, 10);
                }
 
                this.owner.ons_toucher = NULL;
@@ -911,7 +911,7 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                else
                {
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_GENDESTROYED));
-                       PlayerScore_Add(attacker, SP_SCORE, 100);
+                       GameRules_scoring_add(attacker, SCORE, 100);
                }
                this.iscaptured = false;
                this.islinked = false;
@@ -2174,11 +2174,11 @@ void ons_ScoreRules()
        if(c2 >= 0) teams |= BIT(1);
        if(c3 >= 0) teams |= BIT(2);
        if(c4 >= 0) teams |= BIT(3);
-       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
-       ScoreInfo_SetLabel_TeamScore  (ST_ONS_CAPS,     "destroyed", SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS,    "caps",      SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES,    "takes",     0);
-       ScoreRules_basics_end();
+       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+           field_team(ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
+           field(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+           field(SP_ONS_TAKES, "takes", 0);
+       });
 }
 
 void ons_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up
index 0757d7b..5c7fd46 100644 (file)
@@ -5,30 +5,14 @@ void ons_Initialize();
 
 REGISTER_MUTATOR(ons, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               ons_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_onslaught_point_limit, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
-               have_team_spawns = -1; // request team spawns
-       }
+               GameRules_teams(true);
+               GameRules_limit_score(autocvar_g_onslaught_point_limit);
 
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back ons_Initialize 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;
+               ons_Initialize();
        }
-
        return false;
 }
 
diff --git a/qcsrc/common/gamemodes/rules.qc b/qcsrc/common/gamemodes/rules.qc
new file mode 100644 (file)
index 0000000..5cfbba2
--- /dev/null
@@ -0,0 +1 @@
+#include "rules.qh"
diff --git a/qcsrc/common/gamemodes/rules.qh b/qcsrc/common/gamemodes/rules.qh
new file mode 100644 (file)
index 0000000..542548d
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/gamemodes/sv_rules.qh>
+#endif
diff --git a/qcsrc/common/gamemodes/sv_rules.qc b/qcsrc/common/gamemodes/sv_rules.qc
new file mode 100644 (file)
index 0000000..a4a4bcd
--- /dev/null
@@ -0,0 +1,112 @@
+#include "sv_rules.qh"
+
+#include <server/teamplay.qh>
+
+void GameRules_teams(bool value)
+{
+    if (value) {
+        serverflags |= SERVERFLAG_TEAMPLAY;
+        teamplay = 1;
+        cvar_set("teamplay", "2");  // DP needs this for sending proper getstatus replies.
+        GameRules_spawning_teams(true);
+    } else {
+       serverflags &= ~SERVERFLAG_TEAMPLAY;
+       teamplay = 0;
+       cvar_set("teamplay", "0");  // DP needs this for sending proper getstatus replies.
+       GameRules_spawning_teams(false);
+    }
+}
+
+void GameRules_spawning_teams(bool value)
+{
+    have_team_spawns = value ? -1 : 0;
+}
+
+bool _GameRules_score_enabled = true;
+void GameRules_score_enabled(bool value)
+{
+    _GameRules_score_enabled = value;
+}
+
+bool GameRules_limit_score_initialized;
+void GameRules_limit_score(int limit)
+{
+    if (GameRules_limit_score_initialized) return;
+    if (autocvar_g_campaign) return;
+    if (limit < 0) return;
+    cvar_set("fraglimit", ftos(limit));
+    GameRules_limit_score_initialized = true;
+}
+
+bool GameRules_limit_lead_initialized;
+void GameRules_limit_lead(int limit)
+{
+    if (GameRules_limit_lead_initialized) return;
+    if (autocvar_g_campaign) return;
+    if (limit < 0) return;
+    cvar_set("leadlimit", ftos(limit));
+    GameRules_limit_lead_initialized = true;
+}
+
+bool GameRules_limit_time_initialized;
+void GameRules_limit_time(int limit)
+{
+    if (GameRules_limit_time_initialized) return;
+    if (autocvar_g_campaign) return;
+    if (limit < 0) return;
+    cvar_set("timelimit", ftos(limit));
+    GameRules_limit_time_initialized = true;
+}
+
+bool GameRules_limit_time_qualifying_initialized;
+void GameRules_limit_time_qualifying(int limit)
+{
+    if (GameRules_limit_time_qualifying_initialized) return;
+    if (autocvar_g_campaign) return;
+    if (limit < 0) return;
+    cvar_set("g_race_qualifying_timelimit", ftos(limit));
+    GameRules_limit_time_qualifying_initialized = true;
+}
+
+void GameRules_limit_fallbacks()
+{
+    GameRules_limit_score(autocvar_fraglimit_override);
+    GameRules_limit_lead(autocvar_leadlimit_override);
+    GameRules_limit_time(autocvar_timelimit_override);
+}
+
+void _GameRules_scoring_begin(int teams, float spprio, float stprio)
+{
+    ScoreRules_basics(teams, spprio, stprio, _GameRules_score_enabled);
+}
+void _GameRules_scoring_field(entity i, string label, int scoreflags)
+{
+    ScoreInfo_SetLabel_PlayerScore(i, label, scoreflags);
+}
+void _GameRules_scoring_field_team(float i, string label, int scoreflags)
+{
+    ScoreInfo_SetLabel_TeamScore(i, label, scoreflags);
+}
+void _GameRules_scoring_end()
+{
+    ScoreRules_basics_end();
+}
+
+.bool m_GameRules_scoring_vip;
+void GameRules_scoring_vip(entity player, bool value)
+{
+    player.m_GameRules_scoring_vip = value;
+}
+bool GameRules_scoring_is_vip(entity player)
+{
+    return player.m_GameRules_scoring_vip;
+}
+
+float _GameRules_scoring_add(entity client, entity sp, float value)
+{
+    return PlayerScore_Add(client, sp, value);
+}
+float _GameRules_scoring_add_team(entity client, entity sp, int st, float value)
+{
+    return PlayerTeamScore_Add(client, sp, st, value);
+}
diff --git a/qcsrc/common/gamemodes/sv_rules.qh b/qcsrc/common/gamemodes/sv_rules.qh
new file mode 100644 (file)
index 0000000..35a643d
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+// todo: accept the number of teams as a parameter
+void GameRules_teams(bool value);
+
+/**
+ * Used to disable team spawns in team modes
+ */
+void GameRules_spawning_teams(bool value);
+
+/**
+ * Disabling score disables the "score" column on the scoreboard
+ */
+void GameRules_score_enabled(bool value);
+
+void GameRules_limit_score(int limit);
+void GameRules_limit_lead(int limit);
+void GameRules_limit_time(int limit);
+void GameRules_limit_time_qualifying(int limit);
+
+/**
+ * Set any unspecified rules to their defaults
+ */
+void GameRules_limit_fallbacks();
+
+/**
+ * @param teams a bitmask of active teams
+ * @param spprio player score priority (if frags aren't enabled)
+ * @param stprio team score priority (if frags aren't enabled)
+ */
+#define GameRules_scoring(teams, spprio, stprio, fields) MACRO_BEGIN { \
+    _GameRules_scoring_begin((teams), (spprio), (stprio)); \
+    noref void(entity, string, float) field = _GameRules_scoring_field; \
+    /* todo: just have the one `field` function */ \
+    noref void(int, string, float) field_team = _GameRules_scoring_field_team; \
+    LAMBDA(fields); \
+    _GameRules_scoring_end(); \
+} MACRO_END
+
+void _GameRules_scoring_begin(int teams, float spprio, float stprio);
+void _GameRules_scoring_field(entity i, string label, int scoreflags);
+void _GameRules_scoring_field_team(float i, string label, int scoreflags);
+void _GameRules_scoring_end();
+
+/**
+ * Mark a player as being 'important' (flag carrier, ball carrier, etc)
+ * @param player the entity to mark
+ * @param value VIP status
+ */
+void GameRules_scoring_vip(entity player, bool value);
+bool GameRules_scoring_is_vip(entity player);
+
+#define GameRules_scoring_add(client, fld, value) _GameRules_scoring_add(client, SP_##fld, value)
+float _GameRules_scoring_add(entity client, entity sp, float value);
+#define GameRules_scoring_add_team(client, fld, value) _GameRules_scoring_add_team(client, SP_##fld, ST_##fld, value)
+float _GameRules_scoring_add_team(entity client, entity sp, int st, float value);
index 5307ccd..80cd21b 100644 (file)
@@ -943,7 +943,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
 
        if(IS_PLAYER(attacker))
        if(autocvar_g_monsters_score_spawned || !((this.spawnflags & MONSTERFLAG_SPAWNED) || (this.spawnflags & MONSTERFLAG_RESPAWNED)))
-               PlayerScore_Add(attacker, SP_SCORE, +autocvar_g_monsters_score_kill);
+               GameRules_scoring_add(attacker, SCORE, +autocvar_g_monsters_score_kill);
 
        if(gibbed)
        {
index 7fc47ff..4f940c4 100644 (file)
@@ -280,6 +280,20 @@ STATIC_INIT_LATE(Mutators) {
 #define MUTATOR_ONADD                   if (mode == MUTATOR_ADDING)
 #define MUTATOR_ONREMOVE                if (mode == MUTATOR_REMOVING)
 #define MUTATOR_ONROLLBACK_OR_REMOVE    if (mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK)
+
+#define MUTATOR_STATIC() MACRO_BEGIN { \
+    MUTATOR_ONADD { \
+        /* game loads at time 1 */ \
+        if (time > 1) { \
+            error("This is a game type and it cannot be added at runtime."); \
+        } \
+    } \
+       MUTATOR_ONREMOVE { \
+               LOG_INFO("This is a game type and it cannot be removed at runtime."); \
+               return -1; \
+       } \
+} MACRO_END
+
 #define MUTATOR_ADD(name)               Mutator_Add(MUTATOR_##name)
 #define MUTATOR_REMOVE(name)            Mutator_Remove(MUTATOR_##name)
 #define MUTATOR_RETURNVALUE             CallbackChain_ReturnValue
index ae1bbff..62b0fcf 100644 (file)
@@ -1240,7 +1240,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
                        FOR_EACH_KH_KEY(key) if(key.owner == player) { ++key_count; }
 
                        float time_score;
-                       if(player.flagcarried || player.ballcarried) // this player is important
+                       if(GameRules_scoring_is_vip(player))
                                time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
                        else
                                time_score = autocvar_g_nades_bonus_score_time;
@@ -1379,7 +1379,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
 
                if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
                        nades_RemoveBonus(frag_attacker);
-               else if(frag_target.flagcarried)
+               else if(GameRules_scoring_is_vip(frag_target))
                        nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium);
                else if(autocvar_g_nades_bonus_score_spree && CS(frag_attacker).killcount > 1)
                {
index a9fc135..d8af629 100644 (file)
@@ -434,13 +434,13 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
 
 void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest)
 {
-       PlayerScore_Add(joiningplayer, SP_ELO, -1);
+       GameRules_scoring_add(joiningplayer, ELO, -1);
        // http://stats.xonotic.org/player/GgXRw6piDtFIbMArMuiAi8JG4tiin8VLjZgsKB60Uds=/elo.txt
        if(autocvar_g_playerstats_playerbasic_uri != "")
        {
                string uri = autocvar_g_playerstats_playerbasic_uri;
                if (joiningplayer.crypto_idfp == "") {
-                       PlayerScore_Add(joiningplayer, SP_ELO, -1);
+                       GameRules_scoring_add(joiningplayer, ELO, -1);
                } else {
                        // create the database if it doesn't already exist
                        if(PS_B_IN_DB < 0)
@@ -472,7 +472,7 @@ void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest)
        else
        {
                // server has this disabled, kill the DB and set status to idle
-               PlayerScore_Add(joiningplayer, SP_ELO, -1);
+               GameRules_scoring_add(joiningplayer, ELO, -1);
                if(PS_B_IN_DB >= 0)
                {
                        db_close(PS_B_IN_DB);
@@ -573,7 +573,7 @@ void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
                         if (gt == PlayerStats_GetGametype()) {
                             handled = true;
                             float e = stof(data);
-                            PlayerScore_Add(p, SP_ELO, +1 + e);
+                            GameRules_scoring_add(p, ELO, +1 + e);
                         }
                         if (gt == "") {
                             // PlayerInfo_AddItem(p, value, data);
@@ -601,7 +601,7 @@ void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
                        break;
                }
        }
-       PlayerScore_Add(p, SP_ELO, -1);
+       GameRules_scoring_add(p, ELO, -1);
 }
 #endif // SVQC
 
index d9f6143..4c3b1d2 100644 (file)
@@ -270,7 +270,6 @@ void W_Porto_Remove (entity p);
 .float bulletcounter;
 
 // Nexball
-.entity ballcarried; // Also used for keepaway
 float g_nexball_meter_period;
 
 void SUB_DontUseTargets(entity this, entity actor, entity trigger);
index 4e6820f..8a02238 100644 (file)
@@ -28,7 +28,7 @@
 
 void UpdateFrags(entity player, int f)
 {
-       PlayerTeamScore_AddScore(player, f);
+       GameRules_scoring_add_team(player, SCORE, f);
 }
 
 void GiveFrags (entity attacker, entity targ, float f, int deathtype)
@@ -41,23 +41,23 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype)
                if(targ == attacker)
                {
                        // suicide
-                       PlayerScore_Add(attacker, SP_SUICIDES, 1);
+                       GameRules_scoring_add(attacker, SUICIDES, 1);
                }
                else
                {
                        // teamkill
-                       PlayerScore_Add(attacker, SP_KILLS, -1); // or maybe add a teamkills field?
+                       GameRules_scoring_add(attacker, KILLS, -1); // or maybe add a teamkills field?
                }
        }
        else
        {
                // regular frag
-               PlayerScore_Add(attacker, SP_KILLS, 1);
+               GameRules_scoring_add(attacker, KILLS, 1);
                if(targ.playerid)
                        PS_GR_P_ADDVAL(attacker, sprintf("kills-%d", targ.playerid), 1);
        }
 
-       PlayerScore_Add(targ, SP_DEATHS, 1);
+       GameRules_scoring_add(targ, DEATHS, 1);
 
        .entity weaponentity = weaponentities[0]; // TODO: unhardcode
 
@@ -509,7 +509,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                LogDeath("accident", deathtype, targ, targ);
                GiveFrags(targ, targ, -1, deathtype);
 
-               if(PlayerScore_Add(targ, SP_SCORE, 0) == -5)
+               if(GameRules_scoring_add(targ, SCORE, 0) == -5)
                {
                        Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
                        PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
index 66612e0..64aa03b 100644 (file)
@@ -597,18 +597,6 @@ void __init_dedicated_server_shutdown() {
        MapInfo_Shutdown();
 }
 
-void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override)
-{
-       if(!autocvar_g_campaign)
-       {
-               if(fraglimit_override >= 0) cvar_set("fraglimit", ftos(fraglimit_override));
-               if(timelimit_override >= 0) cvar_set("timelimit", ftos(timelimit_override));
-               if(leadlimit_override >= 0) cvar_set("leadlimit", ftos(leadlimit_override));
-               if(qualifying_override >= 0) cvar_set("g_race_qualifying_timelimit", ftos(qualifying_override));
-       }
-       limits_are_set = true;
-}
-
 void Map_MarkAsRecent(string m);
 float world_already_spawned;
 void Nagger_Init();
@@ -759,8 +747,7 @@ spawnfunc(worldspawn)
        readlevelcvars();
        GrappleHookInit();
 
-       if(!limits_are_set)
-               SetLimits(autocvar_fraglimit_override, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
+    GameRules_limit_fallbacks();
 
        if(warmup_limit == 0)
                warmup_limit = (autocvar_timelimit > 0) ? autocvar_timelimit * 60 : autocvar_timelimit;
@@ -1905,7 +1892,7 @@ void CheckRules_World()
                                totalplayers = playerswithlaps = readyplayers = 0;
                                FOREACH_CLIENT(IS_PLAYER(it), {
                                        ++totalplayers;
-                                       if(PlayerScore_Add(it, SP_RACE_FASTEST, 0))
+                                       if(GameRules_scoring_add(it, RACE_FASTEST, 0))
                                                ++playerswithlaps;
                                        if(it.ready)
                                                ++readyplayers;
index 4d5401a..034407b 100644 (file)
@@ -10,9 +10,6 @@ const int WINNING_YES = 1; // winner found
 const int WINNING_NEVER = 2; // no winner, enter overtime if time limit is reached
 const int WINNING_STARTSUDDENDEATHOVERTIME = 3; // no winner, enter suddendeath overtime NOW
 
-bool limits_are_set = false;
-void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override);
-
 float WinningCondition_Scores(float limit, float leadlimit);
 void SetWinners(.float field, float value);
 void IntermissionThink(entity this);
index c6fdeb2..5de2a65 100644 (file)
@@ -6,6 +6,7 @@
 #include <server/scores.qh>
 #include <server/scores_rules.qh>
 #include <server/teamplay.qh>
+#include <common/gamemodes/rules.qh>
 
 #include "mutator.qh"
 
index bd88131..affa033 100644 (file)
@@ -55,13 +55,13 @@ void assault_objective_decrease_use(entity this, entity actor, entity trigger)
        {
                if(this.enemy.health - this.dmg > 0.5)
                {
-                       PlayerTeamScore_Add(actor, SP_SCORE, ST_SCORE, this.dmg);
+                       GameRules_scoring_add_team(actor, SCORE, this.dmg);
                        this.enemy.health = this.enemy.health - this.dmg;
                }
                else
                {
-                       PlayerTeamScore_Add(actor, SP_SCORE, ST_SCORE, this.enemy.health);
-                       PlayerTeamScore_Add(actor, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
+                       GameRules_scoring_add_team(actor, SCORE, this.enemy.health);
+                       GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
                        this.enemy.health = -1;
 
                        if(this.enemy.message)
@@ -614,16 +614,3 @@ MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
        // readyrestart not supported (yet)
        return true;
 }
-
-// scoreboard setup
-void assault_ScoreRules()
-{
-       int teams = 0;
-       teams |= BIT(0);
-       teams |= BIT(1); // always red vs blue
-
-       ScoreRules_basics(teams, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, true);
-       ScoreInfo_SetLabel_TeamScore(  ST_ASSAULT_OBJECTIVES,    "objectives",      SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES,    "objectives",      SFL_SORT_PRIO_PRIMARY);
-       ScoreRules_basics_end();
-}
index 8fd4074..f437d98 100644 (file)
@@ -2,33 +2,20 @@
 
 #include "../gamemode.qh"
 
-void assault_ScoreRules();
+const int ST_ASSAULT_OBJECTIVES = 1;
 
 REGISTER_MUTATOR(as, false)
 {
-       ActivateTeamplay();
-       have_team_spawns = -1; // request team spawns
-
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               assault_ScoreRules();
+        GameRules_teams(true);
+        int teams = BITS(2); // always red vs blue
+        GameRules_scoring(teams, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, {
+            field_team(ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
+            field(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
+        });
        }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back assault_Initialize 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;
 }
 
@@ -55,8 +42,5 @@ void(entity bot) havocbot_ast_reset_role;
 void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
 void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
 
-// scoreboard stuff
-const float ST_ASSAULT_OBJECTIVES = 1;
-
 // predefined spawnfuncs
 void target_objective_decrease_activate(entity this);
index ca402f7..159df8a 100644 (file)
@@ -366,7 +366,7 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
        float excess = max(0, frag_damage - damage_take - damage_save);
 
        if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
-               PlayerTeamScore_Add(frag_attacker, SP_SCORE, ST_SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
+               GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
 }
 
 MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
index 5aba748..0982fcc 100644 (file)
@@ -21,52 +21,30 @@ bool CA_CheckWinner();
 void CA_RoundStart();
 bool ca_isEliminated(entity e);
 
-void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override);
-
 REGISTER_MUTATOR(ca, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               // game loads at time 1
-               if (time > 1) error("This is a game type and it cannot be added at runtime.");
-
-               allowed_to_spawn = true;
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_ca_team_spawns);
+        GameRules_limit_score(autocvar_g_ca_point_limit);
+        GameRules_limit_lead(autocvar_g_ca_point_leadlimit);
 
                ca_teams = autocvar_g_ca_teams_override;
                if (ca_teams < 2)
                        ca_teams = cvar("g_ca_teams"); // read the cvar directly as it gets written earlier in the same frame
-               ca_teams = bound(2, ca_teams, 4);
-
-               int teams = 0;
-               if(ca_teams >= 1) teams |= BIT(0);
-               if(ca_teams >= 2) teams |= BIT(1);
-               if(ca_teams >= 3) teams |= BIT(2);
-               if(ca_teams >= 4) teams |= BIT(3);
 
-               ca_teams = teams; // now set it?
-
-        ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
-        ScoreInfo_SetLabel_TeamScore(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
-        ScoreRules_basics_end();
+               ca_teams = BITS(bound(2, ca_teams, 4));
+        GameRules_scoring(ca_teams, SFL_SORT_PRIO_PRIMARY, 0, {
+            field_team(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
+        });
 
+               allowed_to_spawn = true;
                round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
                round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-
                EliminatedPlayers_Init(ca_isEliminated);
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, autocvar_timelimit_override, -1);
-
-               if (autocvar_g_ca_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
        }
-
        return 0;
 }
 
index 4c88d5e..3cf560e 100644 (file)
@@ -1,43 +1,8 @@
 #include "gamemode_ctf.qh"
 
-#ifndef CSQC
 #include <common/effects/all.qh>
-void ctf_Initialize();
-
-REGISTER_MUTATOR(ctf, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               ctf_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_capturelimit_override, autocvar_captureleadlimit_override, autocvar_timelimit_override, -1);
-               have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back ctf_Initialize 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
-
-#ifdef SVQC
 #include <common/vehicles/all.qh>
 #include <server/teamplay.qh>
-#endif
 
 #include <lib/warpzone/common.qh>
 
@@ -278,10 +243,10 @@ bool ctf_CaptureShield_CheckStatus(entity p)
        if(ctf_captureshield_max_ratio <= 0)
                return false;
 
-       s  = PlayerScore_Add(p, SP_CTF_CAPS,    0);
-       s2 = PlayerScore_Add(p, SP_CTF_PICKUPS, 0);
-       s3 = PlayerScore_Add(p, SP_CTF_RETURNS, 0);
-       s4 = PlayerScore_Add(p, SP_CTF_FCKILLS, 0);
+       s  = GameRules_scoring_add(p, CTF_CAPS, 0);
+       s2 = GameRules_scoring_add(p, CTF_PICKUPS, 0);
+       s3 = GameRules_scoring_add(p, CTF_RETURNS, 0);
+       s4 = GameRules_scoring_add(p, CTF_FCKILLS, 0);
 
        sr = ((s - s2) + (s3 + s4));
 
@@ -292,10 +257,10 @@ bool ctf_CaptureShield_CheckStatus(entity p)
        FOREACH_CLIENT(IS_PLAYER(it), {
                if(DIFF_TEAM(it, p))
                        continue;
-               se  = PlayerScore_Add(it, SP_CTF_CAPS,    0);
-               se2 = PlayerScore_Add(it, SP_CTF_PICKUPS, 0);
-               se3 = PlayerScore_Add(it, SP_CTF_RETURNS, 0);
-               se4 = PlayerScore_Add(it, SP_CTF_FCKILLS, 0);
+               se  = GameRules_scoring_add(it, CTF_CAPS, 0);
+               se2 = GameRules_scoring_add(it, CTF_PICKUPS, 0);
+               se3 = GameRules_scoring_add(it, CTF_RETURNS, 0);
+               se4 = GameRules_scoring_add(it, CTF_FCKILLS, 0);
 
                ser = ((se - se2) + (se3 + se4));
 
@@ -387,8 +352,8 @@ void ctf_Handle_Drop(entity flag, entity player, int droptype)
        ctf_EventLog("dropped", player.team, player);
 
        // scoring
-       PlayerTeamScore_AddScore(player, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop));
-       PlayerScore_Add(player, SP_CTF_DROPS, 1);
+       GameRules_scoring_add_team(player, SCORE, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop));
+       GameRules_scoring_add(player, CTF_DROPS, 1);
 
        // waypoints
        if(autocvar_g_ctf_flag_dropped_waypoint) {
@@ -419,6 +384,7 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        // transfer flag to player
        flag.owner = player;
        flag.owner.flagcarried = flag;
+       GameRules_scoring_vip(player, true);
 
        // reset flag
        if(player.vehicle)
@@ -476,6 +442,7 @@ void ctf_Handle_Throw(entity player, entity receiver, int droptype)
        setattachment(flag, NULL, "");
        setorigin(flag, player.origin + FLAG_DROP_OFFSET);
        flag.owner.flagcarried = NULL;
+       GameRules_scoring_vip(flag.owner, false);
        flag.owner = NULL;
        flag.solid = SOLID_TRIGGER;
        flag.ctf_dropper = player;
@@ -602,16 +569,16 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
        float pscore = 0;
        if(enemy_flag.score_capture || flag.score_capture)
                pscore = floor((max(1, enemy_flag.score_capture) + max(1, flag.score_capture)) * 0.5);
-       PlayerTeamScore_AddScore(player, ((pscore) ? pscore : autocvar_g_ctf_score_capture));
+       GameRules_scoring_add_team(player, SCORE, ((pscore) ? pscore : autocvar_g_ctf_score_capture));
        float capscore = 0;
        if(enemy_flag.score_team_capture || flag.score_team_capture)
                capscore = floor((max(1, enemy_flag.score_team_capture) + max(1, flag.score_team_capture)) * 0.5);
-       PlayerTeamScore_Add(player, SP_CTF_CAPS, ST_CTF_CAPS, ((capscore) ? capscore : 1));
+       GameRules_scoring_add_team(player, CTF_CAPS, ((capscore) ? capscore : 1));
 
-       old_time = PlayerScore_Add(player, SP_CTF_CAPTIME, 0);
+       old_time = GameRules_scoring_add(player, CTF_CAPTIME, 0);
        new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
        if(!old_time || new_time < old_time)
-               PlayerScore_Add(player, SP_CTF_CAPTIME, new_time - old_time);
+               GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
 
        // effects
        Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
@@ -624,7 +591,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
                if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
 
                if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
-                       { PlayerTeamScore_AddScore(enemy_flag.ctf_dropper, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
+                       { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
        }
 
        // reset the flag
@@ -650,8 +617,8 @@ void ctf_Handle_Return(entity flag, entity player)
        // scoring
        if(IS_PLAYER(player))
        {
-               PlayerTeamScore_AddScore(player, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return
-               PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns
+               GameRules_scoring_add_team(player, SCORE, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return
+               GameRules_scoring_add(player, CTF_RETURNS, 1); // add to count of returns
 
                nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium);
        }
@@ -660,7 +627,7 @@ void ctf_Handle_Return(entity flag, entity player)
 
        if(flag.ctf_dropper)
        {
-               PlayerScore_Add(flag.ctf_dropper, SP_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
+               GameRules_scoring_add(flag.ctf_dropper, SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
                ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag
                flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
        }
@@ -681,6 +648,7 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
        // attach the flag to the player
        flag.owner = player;
        player.flagcarried = flag;
+       GameRules_scoring_vip(player, true);
        if(player.vehicle)
        {
                setattachment(flag, player.vehicle, "");
@@ -735,13 +703,13 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
        _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
 
        // scoring
-       PlayerScore_Add(player, SP_CTF_PICKUPS, 1);
+       GameRules_scoring_add(player, CTF_PICKUPS, 1);
        nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor);
        switch(pickuptype)
        {
                case PICKUP_BASE:
                {
-                       PlayerTeamScore_AddScore(player, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base));
+                       GameRules_scoring_add_team(player, SCORE, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base));
                        ctf_EventLog("steal", flag.team, player);
                        break;
                }
@@ -751,7 +719,7 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
                        pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
                        pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
                        LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score));
-                       PlayerTeamScore_AddScore(player, pickup_dropped_score);
+                       GameRules_scoring_add_team(player, SCORE, pickup_dropped_score);
                        ctf_EventLog("pickup", flag.team, player);
                        break;
                }
@@ -1167,6 +1135,7 @@ void ctf_RespawnFlag(entity flag)
                WaypointSprite_Kill(flag.wps_flagcarrier);
 
                flag.owner.flagcarried = NULL;
+               GameRules_scoring_vip(flag.owner, false);
 
                if(flag.speedrunning)
                        ctf_FakeTimeLimit(flag.owner, -1);
@@ -2170,8 +2139,8 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
 
        if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
        {
-               PlayerTeamScore_AddScore(frag_attacker, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
-               PlayerScore_Add(frag_attacker, SP_CTF_FCKILLS, 1);
+               GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
+               GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
        }
 
        if(frag_target.flagcarried)
@@ -2690,15 +2659,15 @@ spawnfunc(team_CTL_bluelolly)  { spawnfunc_item_flag_team2(this);    }
 void ctf_ScoreRules(int teams)
 {
        CheckAllowedTeams(NULL);
-       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
-       ScoreInfo_SetLabel_TeamScore  (ST_CTF_CAPS,     "caps",      SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPS,    "caps",      SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPTIME, "captime",   SFL_LOWER_IS_BETTER | SFL_TIME);
-       ScoreInfo_SetLabel_PlayerScore(SP_CTF_PICKUPS, "pickups",   0);
-       ScoreInfo_SetLabel_PlayerScore(SP_CTF_FCKILLS, "fckills",   0);
-       ScoreInfo_SetLabel_PlayerScore(SP_CTF_RETURNS, "returns",   0);
-       ScoreInfo_SetLabel_PlayerScore(SP_CTF_DROPS,   "drops",     SFL_LOWER_IS_BETTER);
-       ScoreRules_basics_end();
+       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+        field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+        field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+        field(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
+        field(SP_CTF_PICKUPS, "pickups", 0);
+        field(SP_CTF_FCKILLS, "fckills", 0);
+        field(SP_CTF_RETURNS, "returns", 0);
+        field(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
+       });
 }
 
 // code from here on is just to support maps that don't have flag and team entities
index 8ef8608..0b86a57 100644 (file)
@@ -3,6 +3,23 @@
 #ifdef SVQC
 
 #include "../gamemode.qh"
+
+void ctf_Initialize();
+
+REGISTER_MUTATOR(ctf, false)
+{
+    MUTATOR_STATIC();
+    MUTATOR_ONADD
+    {
+        GameRules_teams(true);
+        GameRules_limit_score(autocvar_capturelimit_override);
+        GameRules_limit_lead(autocvar_captureleadlimit_override);
+
+        ctf_Initialize();
+    }
+    return 0;
+}
+
 // used in cheats.qc
 void ctf_RespawnFlag(entity flag);
 
index 3de77f3..20f4b38 100644 (file)
@@ -32,18 +32,16 @@ void havocbot_role_cts(entity this)
 
 void cts_ScoreRules()
 {
-       ScoreRules_basics(0, 0, 0, false);
-       if(g_race_qualifying)
-       {
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-       }
-       else
-       {
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS,    "laps",      SFL_SORT_PRIO_PRIMARY);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME,    "time",      SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_LOWER_IS_BETTER | SFL_TIME);
-       }
-       ScoreRules_basics_end();
+    GameRules_score_enabled(false);
+    GameRules_scoring(0, 0, 0, {
+        if (g_race_qualifying) {
+            field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+        } else {
+            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+        }
+    });
 }
 
 void cts_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
@@ -149,7 +147,7 @@ MUTATOR_HOOKFUNCTION(cts, reset_map_global)
        FOREACH_CLIENT(true, {
                if(it.race_place)
                {
-                       s = PlayerScore_Add(it, SP_RACE_FASTEST, 0);
+                       s = GameRules_scoring_add(it, RACE_FASTEST, 0);
                        if(!s)
                                it.race_place = 0;
                }
@@ -206,7 +204,7 @@ MUTATOR_HOOKFUNCTION(cts, MakePlayerObserver)
 {
        entity player = M_ARGV(0, entity);
 
-       if(PlayerScore_Add(player, SP_RACE_FASTEST, 0))
+       if(GameRules_scoring_add(player, RACE_FASTEST, 0))
                player.frags = FRAGS_LMS_LOSER;
        else
                player.frags = FRAGS_SPECTATOR;
index 2a18fe9..c90919e 100644 (file)
@@ -7,31 +7,16 @@ void cts_Initialize();
 
 REGISTER_MUTATOR(cts, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-
                g_race_qualifying = true;
                independent_players = 1;
-               SetLimits(0, 0, autocvar_timelimit_override, -1);
+        GameRules_limit_score(0);
+        GameRules_limit_lead(0);
 
                cts_Initialize();
        }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back cts_Initialize 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;
 }
 
index d3cc197..f45b080 100644 (file)
@@ -4,24 +4,6 @@
 
 REGISTER_MUTATOR(dm, false)
 {
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back dm_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               error("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
+    MUTATOR_STATIC();
        return 0;
 }
index 7c645e4..be38553 100644 (file)
@@ -64,7 +64,7 @@ void dompoint_captured(entity this)
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_DOMINATION_CAPTURE_TIME, head.netname, this.message, points, wait_time);
 
        if(this.enemy.playerid == this.enemy_playerid)
-               PlayerScore_Add(this.enemy, SP_DOM_TAKES, 1);
+               GameRules_scoring_add(this.enemy, DOM_TAKES, 1);
        else
                this.enemy = NULL;
 
@@ -176,8 +176,8 @@ void dompointthink(entity this)
                // give credit to the individual player, if he is still there
                if (this.enemy.playerid == this.enemy_playerid)
                {
-                       PlayerScore_Add(this.enemy, SP_SCORE, fragamt);
-                       PlayerScore_Add(this.enemy, SP_DOM_TICKS, fragamt);
+                       GameRules_scoring_add(this.enemy, SCORE, fragamt);
+                       GameRules_scoring_add(this.enemy, DOM_TICKS, fragamt);
                }
                else
                        this.enemy = NULL;
@@ -559,10 +559,10 @@ void ScoreRules_dom(int teams)
 {
        if(domination_roundbased)
        {
-               ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
-               ScoreInfo_SetLabel_TeamScore  (ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
-               ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES, "takes", 0);
-               ScoreRules_basics_end();
+           GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+            field_team(ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_DOM_TAKES, "takes", 0);
+           });
        }
        else
        {
@@ -572,11 +572,11 @@ void ScoreRules_dom(int teams)
                        sp_domticks = SFL_SORT_PRIO_PRIMARY;
                else
                        sp_score = SFL_SORT_PRIO_PRIMARY;
-               ScoreRules_basics(teams, sp_score, sp_score, true);
-               ScoreInfo_SetLabel_TeamScore  (ST_DOM_TICKS,    "ticks",     sp_domticks);
-               ScoreInfo_SetLabel_PlayerScore(SP_DOM_TICKS,    "ticks",     sp_domticks);
-               ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES,    "takes",     0);
-               ScoreRules_basics_end();
+               GameRules_scoring(teams, sp_score, sp_score, {
+            field_team(ST_DOM_TICKS, "ticks", sp_domticks);
+            field(SP_DOM_TICKS, "ticks", sp_domticks);
+            field(SP_DOM_TAKES, "takes", 0);
+               });
        }
 }
 
index 609fcfd..cf5e54f 100644 (file)
@@ -11,27 +11,19 @@ void dom_Initialize();
 
 REGISTER_MUTATOR(dom, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               dom_Initialize();
-
                int fraglimit_override = autocvar_g_domination_point_limit;
                if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
                        fraglimit_override = autocvar_g_domination_roundbased_point_limit;
 
-               ActivateTeamplay();
-               SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, autocvar_timelimit_override, -1);
-               have_team_spawns = -1; // request team spawns
-       }
+               GameRules_teams(true);
+        GameRules_limit_score(fraglimit_override);
+        GameRules_limit_lead(autocvar_g_domination_point_leadlimit);
 
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
+               dom_Initialize();
        }
-
        return 0;
 }
 
index 9e9878c..88afaa7 100644 (file)
@@ -7,13 +7,6 @@ float autocvar_g_freezetag_round_timelimit;
 int autocvar_g_freezetag_teams_override;
 float autocvar_g_freezetag_warmup;
 
-void freezetag_ScoreRules(int teams)
-{
-       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true); // SFL_SORT_PRIO_PRIMARY
-       ScoreInfo_SetLabel_PlayerScore(SP_FREEZETAG_REVIVALS, "revivals", 0);
-       ScoreRules_basics_end();
-}
-
 void freezetag_count_alive_players()
 {
        total_players = redalive = bluealive = yellowalive = pinkalive = 0;
@@ -173,14 +166,14 @@ void freezetag_Add_Score(entity targ, entity attacker)
        {
                // you froze your own dumb targ
                // counted as "suicide" already
-               PlayerScore_Add(targ, SP_SCORE, -1);
+               GameRules_scoring_add(targ, SCORE, -1);
        }
        else if(IS_PLAYER(attacker))
        {
                // got frozen by an enemy
                // counted as "kill" and "death" already
-               PlayerScore_Add(targ, SP_SCORE, -1);
-               PlayerScore_Add(attacker, SP_SCORE, +1);
+               GameRules_scoring_add(targ, SCORE, -1);
+               GameRules_scoring_add(attacker, SCORE, +1);
        }
        // else nothing - got frozen by the game type rules themselves
 }
@@ -489,8 +482,8 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 
                        // EVERY team mate nearby gets a point (even if multiple!)
                        FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
-                               PlayerScore_Add(it, SP_FREEZETAG_REVIVALS, +1);
-                               PlayerScore_Add(it, SP_SCORE, +1);
+                               GameRules_scoring_add(it, FREEZETAG_REVIVALS, +1);
+                               GameRules_scoring_add(it, SCORE, +1);
                                nades_GiveBonus(it,autocvar_g_nades_bonus_score_low);
                        });
 
@@ -579,16 +572,11 @@ void freezetag_Initialize()
        freezetag_teams = autocvar_g_freezetag_teams_override;
        if(freezetag_teams < 2)
                freezetag_teams = cvar("g_freezetag_teams"); // read the cvar directly as it gets written earlier in the same frame
-       freezetag_teams = bound(2, freezetag_teams, 4);
 
-       int teams = 0;
-       if(freezetag_teams >= 1) teams |= BIT(0);
-       if(freezetag_teams >= 2) teams |= BIT(1);
-       if(freezetag_teams >= 3) teams |= BIT(2);
-       if(freezetag_teams >= 4) teams |= BIT(3);
-
-       freezetag_teams = teams; // now set it?
-       freezetag_ScoreRules(freezetag_teams);
+       freezetag_teams = BITS(bound(2, freezetag_teams, 4));
+       GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
+           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+       });
 
        round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
        round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
index fda0737..a258d82 100644 (file)
@@ -9,32 +9,16 @@ void freezetag_Initialize();
 
 REGISTER_MUTATOR(ft, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               freezetag_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, autocvar_timelimit_override, -1);
-
-               if (autocvar_g_freezetag_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back freezetag_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_freezetag_team_spawns);
+        GameRules_limit_score(autocvar_g_freezetag_point_limit);
+        GameRules_limit_lead(autocvar_g_freezetag_point_leadlimit);
 
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
+               freezetag_Initialize();
        }
-
        return 0;
 }
 
index 8ec353c..1b8b77a 100644 (file)
@@ -346,7 +346,7 @@ bool Invasion_CheckWinner()
        else
        {
                FOREACH_CLIENT(IS_PLAYER(it), {
-                       float cs = PlayerScore_Add(it, SP_KILLS, 0);
+                       float cs = GameRules_scoring_add(it, KILLS, 0);
                        if(cs > winning_score)
                        {
                                winning_score = cs;
@@ -430,10 +430,10 @@ MUTATOR_HOOKFUNCTION(inv, MonsterDies)
 
                if(IS_PLAYER(frag_attacker))
                if(SAME_TEAM(frag_attacker, frag_target)) // in non-teamplay modes, same team = same player, so this works
-                       PlayerScore_Add(frag_attacker, SP_KILLS, -1);
+                       GameRules_scoring_add(frag_attacker, KILLS, -1);
                else
                {
-                       PlayerScore_Add(frag_attacker, SP_KILLS, +1);
+                       GameRules_scoring_add(frag_attacker, KILLS, +1);
                        if(teamplay)
                                TeamScore_AddToTeam(frag_attacker.team, ST_INV_KILLS, +1);
                }
@@ -560,10 +560,13 @@ MUTATOR_HOOKFUNCTION(inv, AllowMobButcher)
 void invasion_ScoreRules(int inv_teams)
 {
        if(inv_teams) { CheckAllowedTeams(NULL); }
-       ScoreRules_basics(inv_teams, 0, 0, false);
-       if(inv_teams) ScoreInfo_SetLabel_TeamScore(ST_INV_KILLS, "frags", SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_KILLS, "frags", ((inv_teams) ? SFL_SORT_PRIO_SECONDARY : SFL_SORT_PRIO_PRIMARY));
-       ScoreRules_basics_end();
+       GameRules_score_enabled(false);
+       GameRules_scoring(inv_teams, 0, 0, {
+           if (inv_teams) {
+            field_team(ST_INV_KILLS, "frags", SFL_SORT_PRIO_PRIMARY);
+           }
+           field(SP_KILLS, "frags", ((inv_teams) ? SFL_SORT_PRIO_SECONDARY : SFL_SORT_PRIO_PRIMARY));
+       });
 }
 
 void invasion_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
@@ -573,14 +576,7 @@ void invasion_DelayedInit(entity this) // Do this check with a delay so we can w
 
        if(autocvar_g_invasion_teams)
        {
-               invasion_teams = bound(2, autocvar_g_invasion_teams, 4);
-               int teams = 0;
-               if(invasion_teams >= 1) teams |= BIT(0);
-               if(invasion_teams >= 2) teams |= BIT(1);
-               if(invasion_teams >= 3) teams |= BIT(2);
-               if(invasion_teams >= 4) teams |= BIT(3);
-
-               invasion_teams = teams; // now set it?
+               invasion_teams = BITS(bound(2, autocvar_g_invasion_teams, 4));
        }
        else
                invasion_teams = 0;
index 98322bc..0ea0e82 100644 (file)
@@ -11,37 +11,19 @@ void invasion_Initialize();
 
 REGISTER_MUTATOR(inv, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               g_invasion = true;
-               invasion_Initialize();
-
-               cvar_settemp("g_monsters", "1");
-
-               SetLimits(autocvar_g_invasion_point_limit, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
-               if (autocvar_g_invasion_teams >= 2)
-               {
-                       ActivateTeamplay();
-                       if (autocvar_g_invasion_team_spawns)
-                               have_team_spawns = -1; // request team spawns
+               if (autocvar_g_invasion_teams >= 2) {
+                       GameRules_teams(true);
+                       GameRules_spawning_teams(autocvar_g_invasion_team_spawns);
                }
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back invasion_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
+        GameRules_limit_score(autocvar_g_invasion_point_limit);
 
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
+               g_invasion = true;
+               cvar_settemp("g_monsters", "1");
+               invasion_Initialize();
        }
-
        return 0;
 }
 
index c28fd5e..7b33bea 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <common/effects/all.qh>
 
+.entity ballcarried;
+
 int autocvar_g_keepaway_ballcarrier_effects;
 float autocvar_g_keepaway_ballcarrier_damage;
 float autocvar_g_keepaway_ballcarrier_force;
@@ -76,9 +78,9 @@ void ka_TimeScoring(entity this)
        if(this.owner.ballcarried)
        { // add points for holding the ball after a certain amount of time
                if(autocvar_g_keepaway_score_timepoints)
-                       PlayerScore_Add(this.owner, SP_SCORE, autocvar_g_keepaway_score_timepoints);
+                       GameRules_scoring_add(this.owner, SCORE, autocvar_g_keepaway_score_timepoints);
 
-               PlayerScore_Add(this.owner, SP_KEEPAWAY_BCTIME, (autocvar_g_keepaway_score_timeinterval / 1)); // interval is divided by 1 so that time always shows "seconds"
+               GameRules_scoring_add(this.owner, KEEPAWAY_BCTIME, (autocvar_g_keepaway_score_timeinterval / 1)); // interval is divided by 1 so that time always shows "seconds"
                this.nextthink = time + autocvar_g_keepaway_score_timeinterval;
        }
 }
@@ -105,6 +107,7 @@ void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball c
        // attach the ball to the player
        this.owner = toucher;
        toucher.ballcarried = this;
+       GameRules_scoring_vip(toucher, true);
        setattachment(this, toucher, "");
        setorigin(this, '0 0 0');
 
@@ -131,7 +134,7 @@ void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball c
        sound(this.owner, CH_TRIGGER, SND_KA_PICKEDUP, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
 
        // scoring
-       PlayerScore_Add(toucher, SP_KEEPAWAY_PICKUPS, 1);
+       GameRules_scoring_add(toucher, KEEPAWAY_PICKUPS, 1);
 
        // waypoints
        WaypointSprite_AttachCarrier(WP_KaBallCarrier, toucher, RADARICON_FLAGCARRIER);
@@ -159,8 +162,9 @@ void ka_DropEvent(entity plyr) // runs any time that a player is supposed to los
        ball.effects &= ~EF_NODRAW;
        setorigin(ball, plyr.origin + '0 0 10');
        ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
-       ball.owner.ballcarried = world; // I hope nothing checks to see if the world has the ball in the rest of my code :P
-       ball.owner = NULL;
+       entity e = ball.owner; ball.owner = NULL;
+       e.ballcarried = NULL;
+       GameRules_scoring_vip(e, false);
        navigation_dynamicgoal_set(ball);
 
        // reset the player effects
@@ -174,7 +178,7 @@ void ka_DropEvent(entity plyr) // runs any time that a player is supposed to los
        sound(NULL, CH_TRIGGER, SND_KA_DROPPED, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
 
        // scoring
-       // PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
+       // GameRules_scoring_add(plyr, KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
 
        // waypoints
        WaypointSprite_Spawn(WP_KaBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER);
@@ -282,16 +286,16 @@ MUTATOR_HOOKFUNCTION(ka, PlayerDies)
        if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)))
        {
                if(frag_target.ballcarried) { // add to amount of times killing carrier
-                       PlayerScore_Add(frag_attacker, SP_KEEPAWAY_CARRIERKILLS, 1);
+                       GameRules_scoring_add(frag_attacker, KEEPAWAY_CARRIERKILLS, 1);
                        if(autocvar_g_keepaway_score_bckill) // add bckills to the score
-                               PlayerScore_Add(frag_attacker, SP_SCORE, autocvar_g_keepaway_score_bckill);
+                               GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_bckill);
                }
                else if(!frag_attacker.ballcarried)
                        if(autocvar_g_keepaway_noncarrier_warn)
                                Send_Notification(NOTIF_ONE_ONLY, frag_attacker, MSG_CENTER, CENTER_KEEPAWAY_WARN);
 
                if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
-                       PlayerScore_Add(frag_attacker, SP_SCORE, autocvar_g_keepaway_score_killac);
+                       GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_killac);
        }
 
        if(frag_target.ballcarried) { ka_DropEvent(frag_target); } // a player with the ball has died, drop it
@@ -441,12 +445,12 @@ MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
 // Initialization
 // ==============
 
+MODEL(KA_BALL, "models/orbs/orbblue.md3");
+
 void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
 {
        entity e = new(keepawayball);
-       e.model = "models/orbs/orbblue.md3";
-       precache_model(e.model);
-       _setmodel(e, e.model);
+       setmodel(e, MDL_KA_BALL);
        setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
        e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
        e.takedamage = DAMAGE_YES;
@@ -466,17 +470,7 @@ void ka_SpawnBall() // loads various values for the ball, runs only once at star
        InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So.
 }
 
-void ka_ScoreRules()
-{
-       ScoreRules_basics(0, SFL_SORT_PRIO_PRIMARY, 0, true); // SFL_SORT_PRIO_PRIMARY
-       ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_PICKUPS,             "pickups",              0);
-       ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_CARRIERKILLS,   "bckills",           0);
-       ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_BCTIME,                  "bctime",           SFL_SORT_PRIO_SECONDARY);
-       ScoreRules_basics_end();
-}
-
 void ka_Initialize() // run at the start of a match, initiates game mode
 {
-       ka_ScoreRules();
        ka_SpawnBall();
 }
index a13ab83..abbabbd 100644 (file)
@@ -6,26 +6,17 @@ void ka_Initialize();
 
 REGISTER_MUTATOR(ka, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               ka_Initialize();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back ka_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
+           GameRules_scoring(0, SFL_SORT_PRIO_PRIMARY, 0, {
+            field(SP_KEEPAWAY_PICKUPS, "pickups", 0);
+            field(SP_KEEPAWAY_CARRIERKILLS, "bckills", 0);
+            field(SP_KEEPAWAY_BCTIME, "bctime", SFL_SORT_PRIO_SECONDARY);
+        });
 
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
+               ka_Initialize();
        }
-
        return false;
 }
 
index d32df0f..15b6e0f 100644 (file)
@@ -85,18 +85,18 @@ int kh_key_dropped, kh_key_carried;
 
 int kh_Key_AllOwnedByWhichTeam();
 
-const float ST_KH_CAPS = 1;
+const int ST_KH_CAPS = 1;
 void kh_ScoreRules(int teams)
 {
-       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
-       ScoreInfo_SetLabel_TeamScore(  ST_KH_CAPS,      "caps",      SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_KH_CAPS,      "caps",      SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_KH_PUSHES,    "pushes",    0);
-       ScoreInfo_SetLabel_PlayerScore(SP_KH_DESTROYS,  "destroyed", SFL_LOWER_IS_BETTER);
-       ScoreInfo_SetLabel_PlayerScore(SP_KH_PICKUPS,   "pickups",   0);
-       ScoreInfo_SetLabel_PlayerScore(SP_KH_KCKILLS,   "kckills",   0);
-       ScoreInfo_SetLabel_PlayerScore(SP_KH_LOSSES,    "losses",    SFL_LOWER_IS_BETTER);
-       ScoreRules_basics_end();
+       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
+        field_team(ST_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+        field(SP_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+        field(SP_KH_PUSHES, "pushes", 0);
+        field(SP_KH_DESTROYS, "destroyed", SFL_LOWER_IS_BETTER);
+        field(SP_KH_PICKUPS, "pickups", 0);
+        field(SP_KH_KCKILLS, "kckills", 0);
+        field(SP_KH_LOSSES, "losses", SFL_LOWER_IS_BETTER);
+       });
 }
 
 bool kh_KeyCarrier_waypointsprite_visible_for_player(entity this, entity player, entity view)  // runs all the time
@@ -441,7 +441,7 @@ void kh_Key_Collect(entity key, entity player)  //a player picks up a dropped ke
        if(key.kh_dropperteam != player.team)
        {
                kh_Scores_Event(player, key, "collect", autocvar_g_balance_keyhunt_score_collect, 0);
-               PlayerScore_Add(player, SP_KH_PICKUPS, 1);
+               GameRules_scoring_add(player, KH_PICKUPS, 1);
        }
        key.kh_dropperteam = 0;
        int realteam = kh_Team_ByID(key.count);
@@ -534,7 +534,7 @@ void kh_WinnerTeam(int winner_team)  // runs when a team wins
        {
                float f = DistributeEvenly_Get(1);
                kh_Scores_Event(key.owner, key, "capture", f, 0);
-               PlayerTeamScore_Add(key.owner, SP_KH_CAPS, ST_KH_CAPS, 1);
+               GameRules_scoring_add_team(key.owner, KH_CAPS, 1);
                nades_GiveBonus(key.owner, autocvar_g_nades_bonus_score_high);
        }
 
@@ -593,7 +593,7 @@ void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes
                        kh_Scores_Event(lostkey.kh_previous_owner, NULL, "pushed", 0, -autocvar_g_balance_keyhunt_score_push);
                        // don't actually GIVE him the -nn points, just log
                kh_Scores_Event(attacker, NULL, "push", autocvar_g_balance_keyhunt_score_push, 0);
-               PlayerScore_Add(attacker, SP_KH_PUSHES, 1);
+               GameRules_scoring_add(attacker, KH_PUSHES, 1);
                //centerprint(attacker, "Your push is the best!"); // does this really need to exist?
        }
        else
@@ -614,7 +614,7 @@ void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes
                        // don't actually GIVE him the -nn points, just log
 
                if(lostkey.kh_previous_owner.playerid == lostkey.kh_previous_owner_playerid)
-                       PlayerScore_Add(lostkey.kh_previous_owner, SP_KH_DESTROYS, 1);
+                       GameRules_scoring_add(lostkey.kh_previous_owner, KH_DESTROYS, 1);
 
                DistributeEvenly_Init(autocvar_g_balance_keyhunt_score_destroyed, keys * of + players);
 
@@ -809,7 +809,7 @@ void kh_Key_DropOne(entity key)
        key.enemy = player;
 
        kh_Scores_Event(player, key, "dropkey", 0, 0);
-       PlayerScore_Add(player, SP_KH_LOSSES, 1);
+       GameRules_scoring_add(player, KH_LOSSES, 1);
        int realteam = kh_Team_ByID(key.count);
        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_DROP), player.netname);
 
@@ -836,7 +836,7 @@ void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies
                while((key = player.kh_next))
                {
                        kh_Scores_Event(player, key, "losekey", 0, 0);
-                       PlayerScore_Add(player, SP_KH_LOSSES, 1);
+                       GameRules_scoring_add(player, KH_LOSSES, 1);
                        int realteam = kh_Team_ByID(key.count);
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_LOST), player.netname);
                        kh_Key_AssignTo(key, NULL);
@@ -972,7 +972,7 @@ float kh_HandleFrags(entity attacker, entity targ, float f)  // adds to the play
                else
                {
                        kh_Scores_Event(attacker, targ.kh_next, "carrierfrag", autocvar_g_balance_keyhunt_score_carrierfrag-1, 0);
-                       PlayerScore_Add(attacker, SP_KH_KCKILLS, 1);
+                       GameRules_scoring_add(attacker, KH_KCKILLS, 1);
                        // the frag gets added later
                }
        }
@@ -986,15 +986,7 @@ void kh_Initialize()  // sets up th KH environment
        kh_teams = autocvar_g_keyhunt_teams_override;
        if(kh_teams < 2)
                kh_teams = cvar("g_keyhunt_teams"); // read the cvar directly as it gets written earlier in the same frame
-       kh_teams = bound(2, kh_teams, 4);
-
-       int teams = 0;
-       if(kh_teams >= 1) teams |= BIT(0);
-       if(kh_teams >= 2) teams |= BIT(1);
-       if(kh_teams >= 3) teams |= BIT(2);
-       if(kh_teams >= 4) teams |= BIT(3);
-
-       kh_teams = teams; // now set it?
+       kh_teams = BITS(bound(2, kh_teams, 4));
 
        // make a KH entity for controlling the game
        kh_controller = spawn();
index d0fb5f9..77d7c06 100644 (file)
@@ -9,31 +9,16 @@ void kh_Initialize();
 
 REGISTER_MUTATOR(kh, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               kh_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, autocvar_timelimit_override, -1);
-               if (autocvar_g_keyhunt_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_keyhunt_team_spawns);
+        GameRules_limit_score(autocvar_g_keyhunt_point_limit);
+        GameRules_limit_lead(autocvar_g_keyhunt_point_leadlimit);
 
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back kh_Initialize 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;
+               kh_Initialize();
        }
-
        return 0;
 }
 
index 158492c..4d6f704 100644 (file)
@@ -71,7 +71,7 @@ int WinningCondition_LMS()
                        {
                                // a winner!
                                // and assign him his first place
-                               PlayerScore_Add(head, SP_LMS_RANK, 1);
+                               GameRules_scoring_add(head, LMS_RANK, 1);
                                if(warmup_stage)
                                        return WINNING_NO;
                                else
@@ -120,7 +120,7 @@ MUTATOR_HOOKFUNCTION(lms, reset_map_players)
        FOREACH_CLIENT(true, {
                TRANSMUTE(Player, it);
                it.frags = FRAGS_PLAYER;
-               PlayerScore_Add(it, SP_LMS_LIVES, LMS_NewPlayerLives());
+               GameRules_scoring_add(it, LMS_LIVES, LMS_NewPlayerLives());
                PutClientInServer(it);
        });
 }
@@ -133,13 +133,13 @@ MUTATOR_HOOKFUNCTION(lms, PutClientInServer)
                TRANSMUTE(Observer, player);
        else
        {
-               float tl = PlayerScore_Add(player, SP_LMS_LIVES, 0);
+               float tl = GameRules_scoring_add(player, LMS_LIVES, 0);
                if(tl < lms_lowest_lives)
                        lms_lowest_lives = tl;
                if(tl <= 0)
                        TRANSMUTE(Observer, player);
                if(warmup_stage)
-                       PlayerScore_Add(player, SP_LMS_RANK, -PlayerScore_Add(player, SP_LMS_RANK, 0));
+                       GameRules_scoring_add(player, LMS_RANK, -GameRules_scoring_add(player, LMS_RANK, 0));
        }
 }
 
@@ -151,7 +151,7 @@ MUTATOR_HOOKFUNCTION(lms, ForbidSpawn)
                return false;
        if(player.frags == FRAGS_SPECTATOR)
                return true;
-       if(PlayerScore_Add(player, SP_LMS_LIVES, 0) <= 0)
+       if(GameRules_scoring_add(player, LMS_LIVES, 0) <= 0)
        {
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_LMS_NOLIVES);
                return true;
@@ -169,7 +169,7 @@ MUTATOR_HOOKFUNCTION(lms, PlayerDies)
 void lms_RemovePlayer(entity player)
 {
        static int quitters = 0;
-       float player_rank = PlayerScore_Add(player, SP_LMS_RANK, 0);
+       float player_rank = GameRules_scoring_add(player, LMS_RANK, 0);
        if (!player_rank)
        {
                int pl_cnt = 0;
@@ -179,7 +179,7 @@ void lms_RemovePlayer(entity player)
                        if(IS_BOT_CLIENT(player))
                                bot_clear(player);
                        player.frags = FRAGS_LMS_LOSER;
-                       PlayerScore_Add(player, SP_LMS_RANK, pl_cnt + 1);
+                       GameRules_scoring_add(player, LMS_RANK, pl_cnt + 1);
                }
                else
                {
@@ -187,22 +187,22 @@ void lms_RemovePlayer(entity player)
                        FOREACH_CLIENT(true, {
                                if (it.frags == FRAGS_LMS_LOSER)
                                {
-                                       float it_rank = PlayerScore_Add(it, SP_LMS_RANK, 0);
+                                       float it_rank = GameRules_scoring_add(it, LMS_RANK, 0);
                                        if (it_rank > player_rank && it_rank <= 256)
-                                               PlayerScore_Add(it, SP_LMS_RANK, -1);
+                                               GameRules_scoring_add(it, LMS_RANK, -1);
                                        lms_lowest_lives = 0;
                                }
                                else if (it.frags != FRAGS_SPECTATOR)
                                {
-                                       float tl = PlayerScore_Add(it, SP_LMS_LIVES, 0);
+                                       float tl = GameRules_scoring_add(it, LMS_LIVES, 0);
                                        if(tl < lms_lowest_lives)
                                                lms_lowest_lives = tl;
                                }
                        });
-                       PlayerScore_Add(player, SP_LMS_RANK, 665 - quitters); // different from 666
+                       GameRules_scoring_add(player, LMS_RANK, 665 - quitters); // different from 666
                        if(!warmup_stage)
                        {
-                               PlayerScore_Add(player, SP_LMS_LIVES, -PlayerScore_Add(player, SP_LMS_LIVES, 0));
+                               GameRules_scoring_add(player, LMS_LIVES, -GameRules_scoring_add(player, LMS_LIVES, 0));
                                ++quitters;
                        }
                        player.frags = FRAGS_LMS_LOSER;
@@ -213,7 +213,7 @@ void lms_RemovePlayer(entity player)
        }
 
        if(CS(player).killcount != FRAGS_SPECTATOR)
-               if(PlayerScore_Add(player, SP_LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
+               if(GameRules_scoring_add(player, LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_NOLIVES, player.netname);
                else
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_FORFEIT, player.netname);
@@ -241,9 +241,9 @@ MUTATOR_HOOKFUNCTION(lms, ClientConnect)
        TRANSMUTE(Player, player);
        campaign_bots_may_start = true;
 
-       if(PlayerScore_Add(player, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+       if(GameRules_scoring_add(player, LMS_LIVES, LMS_NewPlayerLives()) <= 0)
        {
-               PlayerScore_Add(player, SP_LMS_RANK, 666); // mark as forced spectator for the hud code
+               GameRules_scoring_add(player, LMS_RANK, 666); // mark as forced spectator for the hud code
                player.frags = FRAGS_SPECTATOR;
        }
 }
@@ -276,7 +276,7 @@ MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill)
        if (!warmup_stage)
        {
                // remove a life
-               int tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
+               int tl = GameRules_scoring_add(frag_target, LMS_LIVES, -1);
                if(tl < lms_lowest_lives)
                        lms_lowest_lives = tl;
                if(tl <= 0)
@@ -286,7 +286,7 @@ MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill)
                        if(IS_BOT_CLIENT(frag_target))
                                bot_clear(frag_target);
                        frag_target.frags = FRAGS_LMS_LOSER;
-                       PlayerScore_Add(frag_target, SP_LMS_RANK, pl_cnt);
+                       GameRules_scoring_add(frag_target, LMS_RANK, pl_cnt);
                }
        }
        M_ARGV(2, float) = 0; // frag score
@@ -358,7 +358,7 @@ MUTATOR_HOOKFUNCTION(lms, ItemTouch)
        if(item.itemdef == ITEM_ExtraLife)
        {
                Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES);
-               PlayerScore_Add(toucher, SP_LMS_LIVES, autocvar_g_lms_extra_lives);
+               GameRules_scoring_add(toucher, LMS_LIVES, autocvar_g_lms_extra_lives);
                return MUT_ITEMTOUCH_PICKUP;
        }
 
@@ -419,18 +419,7 @@ MUTATOR_HOOKFUNCTION(lms, AddPlayerScore)
                return true; // allow writing to this field in intermission as it is needed for newly joining players
 }
 
-// scoreboard stuff
-void lms_ScoreRules()
-{
-       ScoreRules_basics(0, 0, 0, false);
-       ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES,    "lives",     SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK,     "rank",      SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
-       ScoreRules_basics_end();
-}
-
 void lms_Initialize()
 {
        lms_lowest_lives = 9999;
-
-       lms_ScoreRules();
 }
index 1f1d2d4..c69113a 100644 (file)
@@ -8,28 +8,19 @@ void lms_Initialize();
 
 REGISTER_MUTATOR(lms, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               lms_Initialize();
-
-               SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, autocvar_timelimit_override, -1);
-       }
+        GameRules_limit_score(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override));
+        GameRules_limit_lead(0);
+        GameRules_score_enabled(false);
+        GameRules_scoring(0, 0, 0, {
+            field(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
+            field(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
+        });
 
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back lms_Initialize 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;
+               lms_Initialize();
        }
-
        return 0;
 }
 
index 7628968..2f581d8 100644 (file)
@@ -37,25 +37,21 @@ void havocbot_role_race(entity this)
 
 void race_ScoreRules()
 {
-       ScoreRules_basics(race_teams, 0, 0, false);
-       if(race_teams)
-       {
-               ScoreInfo_SetLabel_TeamScore(  ST_RACE_LAPS,    "laps",       SFL_SORT_PRIO_PRIMARY);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS,    "laps",      SFL_SORT_PRIO_PRIMARY);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME,    "time",      SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_LOWER_IS_BETTER | SFL_TIME);
-       }
-       else if(g_race_qualifying)
-       {
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-       }
-       else
-       {
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS,    "laps",      SFL_SORT_PRIO_PRIMARY);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME,    "time",      SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-               ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_LOWER_IS_BETTER | SFL_TIME);
-       }
-       ScoreRules_basics_end();
+    GameRules_score_enabled(false);
+       GameRules_scoring(race_teams, 0, 0, {
+        if (race_teams) {
+            field_team(ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+        } else if (g_race_qualifying) {
+            field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+        } else {
+            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+        }
+       });
 }
 
 void race_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
@@ -201,7 +197,7 @@ MUTATOR_HOOKFUNCTION(rc, reset_map_global)
        FOREACH_CLIENT(true, {
                if(it.race_place)
                {
-                       s = PlayerScore_Add(it, SP_RACE_FASTEST, 0);
+                       s = GameRules_scoring_add(it, RACE_FASTEST, 0);
                        if(!s)
                                it.race_place = 0;
                }
@@ -251,7 +247,7 @@ MUTATOR_HOOKFUNCTION(rc, MakePlayerObserver)
        entity player = M_ARGV(0, entity);
 
        if(g_race_qualifying)
-       if(PlayerScore_Add(player, SP_RACE_FASTEST, 0))
+       if(GameRules_scoring_add(player, RACE_FASTEST, 0))
                player.frags = FRAGS_LMS_LOSER;
        else
                player.frags = FRAGS_SPECTATOR;
@@ -443,17 +439,8 @@ void rc_SetLimits()
 
        if(autocvar_g_race_teams)
        {
-               ActivateTeamplay();
-               race_teams = bound(2, autocvar_g_race_teams, 4);
-               int teams = 0;
-               if(race_teams >= 1) teams |= BIT(0);
-               if(race_teams >= 2) teams |= BIT(1);
-               if(race_teams >= 3) teams |= BIT(2);
-               if(race_teams >= 4) teams |= BIT(3);
-
-               race_teams = teams; // now set it?
-
-               have_team_spawns = -1; // request team spawns
+               GameRules_teams(true);
+               race_teams = BITS(bound(2, autocvar_g_race_teams, 4));
        }
        else
                race_teams = 0;
@@ -484,5 +471,8 @@ void rc_SetLimits()
        }
        else
                g_race_qualifying = 0;
-       SetLimits(fraglimit_override, leadlimit_override, timelimit_override, qualifying_override);
+    GameRules_limit_score(fraglimit_override);
+    GameRules_limit_lead(leadlimit_override);
+    GameRules_limit_time(timelimit_override);
+    GameRules_limit_time_qualifying(qualifying_override);
 }
index ec71a62..1e475e3 100644 (file)
@@ -7,27 +7,12 @@ void race_Initialize();
 
 REGISTER_MUTATOR(rc, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-
                rc_SetLimits();
-               race_Initialize();
-       }
 
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back race_Initialize 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;
+               race_Initialize();
        }
-
        return 0;
 }
index 101f57f..aad3193 100644 (file)
@@ -36,16 +36,9 @@ void tdm_DelayedInit(entity this)
                LOG_TRACE("No \"tdm_team\" entities found on this map, creating them anyway.");
 
                int numteams = autocvar_g_tdm_teams_override;
-
                if(numteams < 2) { numteams = autocvar_g_tdm_teams; }
-               numteams = bound(2, numteams, 4);
-
-               int teams = 0;
-               if(numteams >= 1) teams |= BIT(0);
-               if(numteams >= 2) teams |= BIT(1);
-               if(numteams >= 3) teams |= BIT(2);
-               if(numteams >= 4) teams |= BIT(3);
 
+               int teams = BITS(bound(2, numteams, 4));
                if(teams & BIT(0))
                        tdm_SpawnTeam("Red", NUM_TEAM_1);
                if(teams & BIT(1))
index e7efbae..c163962 100644 (file)
@@ -9,30 +9,15 @@ void tdm_DelayedInit(entity this);
 
 REGISTER_MUTATOR(tdm, false)
 {
+    MUTATOR_STATIC();
        MUTATOR_ONADD
        {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               InitializeEntity(NULL, tdm_DelayedInit, INITPRIO_GAMETYPE);
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, autocvar_timelimit_override, -1);
-               if (autocvar_g_tdm_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_tdm_team_spawns);
+               GameRules_limit_score(autocvar_g_tdm_point_limit);
+        GameRules_limit_lead(autocvar_g_tdm_point_leadlimit);
 
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back tdm_Initialize 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;
+               InitializeEntity(NULL, tdm_DelayedInit, INITPRIO_GAMETYPE);
        }
-
        return 0;
 }
index 82f661a..44a8777 100644 (file)
@@ -472,10 +472,10 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        if (this != attacker) {
                float realdmg = damage - excess;
                if (IS_PLAYER(attacker)) {
-                       PlayerScore_Add(attacker, SP_DMG, realdmg);
+                       GameRules_scoring_add(attacker, DMG, realdmg);
                }
                if (IS_PLAYER(this)) {
-                       PlayerScore_Add(this, SP_DMGTAKEN, realdmg);
+                       GameRules_scoring_add(this, DMGTAKEN, realdmg);
                }
        }
 
index 7f2aaaa..6fc828d 100644 (file)
@@ -11,6 +11,7 @@
 #include "../common/deathtypes/all.qh"
 #include "../common/notifications/all.qh"
 #include "../common/mapinfo.qh"
+#include <common/gamemodes/rules.qh>
 #include <common/net_linked.qh>
 #include <common/state.qh>
 #include "../common/triggers/subs.qh"
@@ -386,20 +387,20 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                float s;
                if(g_race_qualifying)
                {
-                       s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+                       s = GameRules_scoring_add(e, RACE_FASTEST, 0);
                        if(!s || t < s)
-                               PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
+                               GameRules_scoring_add(e, RACE_FASTEST, t - s);
                }
                else
                {
-                       s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+                       s = GameRules_scoring_add(e, RACE_FASTEST, 0);
                        if(!s || t < s)
-                               PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
+                               GameRules_scoring_add(e, RACE_FASTEST, t - s);
 
-                       s = PlayerScore_Add(e, SP_RACE_TIME, 0);
+                       s = GameRules_scoring_add(e, RACE_TIME, 0);
                        snew = TIME_ENCODE(time - game_starttime);
-                       PlayerScore_Add(e, SP_RACE_TIME, snew - s);
-                       l = PlayerTeamScore_Add(e, SP_RACE_LAPS, ST_RACE_LAPS, 1);
+                       GameRules_scoring_add(e, RACE_TIME, snew - s);
+                       l = GameRules_scoring_add_team(e, RACE_LAPS, 1);
 
                        if(autocvar_fraglimit)
                                if(l >= autocvar_fraglimit)
@@ -485,7 +486,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                entity oth = race_checkpoint_lastplayers[cp];
                if(oth)
                {
-                       mylaps = PlayerScore_Add(e, SP_RACE_LAPS, 0);
+                       mylaps = GameRules_scoring_add(e, RACE_LAPS, 0);
                        lother = race_checkpoint_lastlaps[cp];
                        othtime = race_checkpoint_lasttimes[cp];
                }
@@ -1177,7 +1178,7 @@ float race_GetFractionalLapCount(entity e)
        // links on CP entities)
 
        float l;
-       l = PlayerScore_Add(e, SP_RACE_LAPS, 0);
+       l = GameRules_scoring_add(e, RACE_LAPS, 0);
        if(CS(e).race_completed)
                return l; // not fractional
 
index fc4c196..79b6529 100644 (file)
@@ -66,11 +66,6 @@ float TeamScore_GetCompareValue(float t);
 float PlayerTeamScore_Add(entity player, PlayerScoreField pscorefield, float tscorefield, float score);
 
 /**
- * Adds to the generic score fields for both the player and the team.
- */
-#define PlayerTeamScore_AddScore(p, s) PlayerTeamScore_Add(p, SP_SCORE, ST_SCORE, s)
-
-/**
  * Set the label of a team score item, as well as the scoring flags.
  */
 void ScoreInfo_SetLabel_TeamScore(float i, string label, float scoreflags);
index 97e8040..2b539c9 100644 (file)
@@ -4,6 +4,7 @@
 #include <server/miscfunctions.qh>
 #include "client.qh"
 #include "scores.qh"
+#include <common/gamemodes/rules.qh>
 
 int ScoreRules_teams;
 
@@ -57,17 +58,13 @@ void ScoreRules_basics_end()
 }
 void ScoreRules_generic()
 {
-       if(teamplay)
-       {
+    int teams = 0;
+       if (teamplay) {
                CheckAllowedTeams(NULL);
-               int teams = 0;
-               if(c1 >= 0) teams |= BIT(0);
-               if(c2 >= 0) teams |= BIT(1);
-               if(c3 >= 0) teams |= BIT(2);
-               if(c4 >= 0) teams |= BIT(3);
-               ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
+               if (c1 >= 0) teams |= BIT(0);
+               if (c2 >= 0) teams |= BIT(1);
+               if (c3 >= 0) teams |= BIT(2);
+               if (c4 >= 0) teams |= BIT(3);
        }
-       else
-               ScoreRules_basics(0, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true);
-       ScoreRules_basics_end();
+       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {});
 }
index eda9b95..e93a032 100644 (file)
@@ -37,13 +37,6 @@ void default_delayedinit(entity this)
                ScoreRules_generic();
 }
 
-void ActivateTeamplay()
-{
-       serverflags |= SERVERFLAG_TEAMPLAY;
-       teamplay = 1;
-       cvar_set("teamplay", "2");  // DP needs this for sending proper getstatus replies.
-}
-
 void InitGameplayMode()
 {
        VoteReset();
@@ -59,9 +52,7 @@ void InitGameplayMode()
        max_shot_distance = min(230000, vlen(world.maxs - world.mins));
 
        MapInfo_LoadMapSettings(mapname);
-       serverflags &= ~SERVERFLAG_TEAMPLAY;
-       teamplay = 0;
-       cvar_set("teamplay", "0");  // DP needs this for sending proper getstatus replies.
+       GameRules_teams(false);
 
        if (!cvar_value_issafe(world.fog))
        {
index 127ac7a..8d0ea9c 100644 (file)
@@ -18,8 +18,6 @@ void LogTeamchange(float player_id, float team_number, float type);
 
 void default_delayedinit(entity this);
 
-void ActivateTeamplay();
-
 void InitGameplayMode();
 
 string GetClientVersionMessage(entity this);