]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote branch 'origin/master' into samual/keepaway
authorunknown <samual@xonotic.org>
Fri, 19 Nov 2010 22:51:58 +0000 (17:51 -0500)
committerunknown <samual@xonotic.org>
Fri, 19 Nov 2010 22:51:58 +0000 (17:51 -0500)
17 files changed:
defaultXonotic.cfg
qcsrc/client/scoreboard.qc
qcsrc/common/constants.qh
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/util.qc
qcsrc/menu/xonotic/dialog_multiplayer_create.c
qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/mutators/gamemode_keepaway.qc [new file with mode: 0644]
qcsrc/server/mutators/mutators.qh
qcsrc/server/progs.src
qcsrc/server/scores_rules.qc
qcsrc/server/teamplay.qc
sound/keepaway/dropped.wav [new file with mode: 0644]
sound/keepaway/pickedup.wav [new file with mode: 0644]

index 72a1ded11efc7d975ac1693cb205fae2f9497ccb..d2a47a09eca48dd42d346e3892ea60122bf1f2a6 100644 (file)
@@ -606,6 +606,8 @@ set g_cts_respawn_waves 0
 set g_cts_respawn_delay 0.25
 set g_cts_selfdamage 1 "0 = disable all selfdamage and falldamage in cts"
 set g_cts_finish_kill_delay 10 "prevent cheating by running back to the start line, and starting out with more speed than otherwise possible"
+set g_keepaway_respawn_delay 0
+set g_keepaway_respawn_waves 0
 
 // overtime
 seta timelimit_overtime 2 "duration in minutes of one added overtime, added to the timelimit"
@@ -1243,6 +1245,27 @@ set g_balance_keyhunt_damageforcescale 1
 seta g_keyhunt_teams_override 0
 set g_keyhunt_teams 0
 
+// keepaway
+set g_keepaway 0 "game mode which focuses around a ball, look at g_keepaway_win_mode for further details"
+set g_keepaway_pointlimit      -1      "total amount of points you can get, -1 for unlimited"
+set g_keepaway_pointleadlimit  -1      "mercy rule, -1 for unlimited"
+set g_keepaway_powerup 0       "powerup while holding the ball"
+set g_keepaway_powerup_damage  1.5     "damage multiplier while having powerup"
+set g_keepaway_powerup_force   1.5     "force multiplier while having powerup"
+set g_keepaway_powerup_selfdamage      1       "self damage multiplier while having powerup"
+set g_keepaway_powerup_selfforce       1.5     "self force multiplier while having powerup"
+set g_keepaway_noncarrier_warn 0       "warn players when they kill without holding the ball"
+set g_keepaway_noncarrier_damage       0.5     "damage done to other players if both you and they don't have the ball"
+set g_keepaway_noncarrier_force        0.5     "force done to other players if both you and they don't have the ball"
+set g_keepaway_noncarrier_selfdamage   1       "self damage if you don't have the ball"
+set g_keepaway_noncarrier_selfforce    1       "self force if you don't have the ball"
+seta g_keepaway_win_mode       0       "win mode for keepaway: 0 = time, 1 = kills as carrier (KAC)"
+set g_keepawayball_trail_color 254     "particle trail color from player/ball"
+set g_keepawayball_damageforcescale    1       "I don't really know what this is for. :)"
+set g_keepawayball_respawntime 15      "if no one picks up the ball, how long to wait until the ball respawns"
+seta g_keepaway_teams_override 0
+set g_keepaway_teams 0
+
 // so it can be stuffcmd-ed still
 set cl_gravity 800     "but ignored anyway"
 
index ec17dfca77efe473c73a5146513c1744f6820fe8..cb93c53257a3d9d08564c3484be83896e3db6a51 100644 (file)
@@ -248,12 +248,12 @@ string HUD_DefaultColumnLayout()
 {
        return strcat( // fteqcc sucks
                "ping pl name | ",
-               "-teams,race,lms/kills -teams,lms/deaths -teams,lms,race/suicides -race,dm,tdm/frags ", // tdm already has this in "score"
+               "-teams,race,lms/kills -teams,lms/deaths -teams,lms,race,keepaway/suicides -race,dm,tdm,keepaway/frags ", // tdm already has this in "score"
                "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
                "+lms/lives +lms/rank ",
                "+kh/caps +kh/pushes +kh/destroyed ",
                "?+race/laps ?+race/time ?+race/fastest ",
-               "+as/objectives +nexball/faults +nexball/goals ",
+               "+as/objectives +nexball/faults +nexball/goals +keepaway/drops +keepaway/pickups +keepaway/bckills ",
                "-lms,race,nexball/score");
 }
 
index 87484cd8f31c7902cf52e2ed1f69e458b9b7193d..94089951e890760956366e2e8f48eed28c2df77b 100644 (file)
@@ -34,11 +34,12 @@ const float GAME_LMS                        = 6;
 const float GAME_ARENA         = 7;
 const float GAME_KEYHUNT               = 8;
 const float GAME_ASSAULT               = 9;
-const float GAME_ONSLAUGHT     = 10;
-const float GAME_RACE  = 11;
-const float GAME_NEXBALL = 12;
-const float GAME_CTS = 13;
-const float GAME_CA            = 14;
+const float GAME_ONSLAUGHT             = 10;
+const float GAME_RACE                  = 11;
+const float GAME_NEXBALL               = 12;
+const float GAME_CTS                   = 13;
+const float GAME_CA                    = 14;
+const float GAME_KEEPAWAY              = 15;
 
 const float AS_STRING          = 1;
 const float AS_INT             = 2;
index 5192b75ac24ea37fd4a67cc72bc885b80dd3ea60..187bf63be8db373576d92ebc1a320f0527d35dcb 100644 (file)
@@ -347,6 +347,7 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
                MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH;      // DM always works
                MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH;       // Rune always works
                MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS;             // LMS always works
+               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEEPAWAY;                // Keepaway always works
 
                if(spawnpoints >= 8  && diameter > 4096) {
                        MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
@@ -406,6 +407,7 @@ string _MapInfo_GetDefault(float t)
                case MAPINFO_TYPE_ONSLAUGHT:       return "20 0";
                case MAPINFO_TYPE_NEXBALL:         return "5 20 0";
                case MAPINFO_TYPE_CTS:             return "20 0 0";
+               case MAPINFO_TYPE_KEEPAWAY:        return "30 20 0";
                default:                           return "";
        }
 }
@@ -462,6 +464,14 @@ void _MapInfo_Map_ApplyGametype(string s, float pWantedType, float pThisType, fl
                s = cdr(s);
        }
 
+       if(pWantedType == MAPINFO_TYPE_KEEPAWAY)
+       {
+               sa = car(s);
+               if(sa != "")
+                       cvar_set("fraglimit", sa);
+               s = cdr(s);
+       }
+
        // rc = timelimit timelimit_qualification laps laps_teamplay
        if(pWantedType == MAPINFO_TYPE_RACE)
        {
@@ -526,6 +536,7 @@ string _MapInfo_GetDefaultEx(float t)
                case MAPINFO_TYPE_ONSLAUGHT:       return "timelimit=20";
                case MAPINFO_TYPE_NEXBALL:         return "timelimit=20 pointlimit=5 leadlimit=0";
                case MAPINFO_TYPE_CTS:             return "timelimit=20 skill=-1";
+               case MAPINFO_TYPE_KEEPAWAY:        return "timelimit=20 pointlimit=30";
                default:                           return "";
        }
 }
@@ -650,6 +661,7 @@ float MapInfo_Type_FromString(string t)
        else if(t == "rc")      return MAPINFO_TYPE_RACE;
        else if(t == "nexball") return MAPINFO_TYPE_NEXBALL;
        else if(t == "cts")     return MAPINFO_TYPE_CTS;
+       else if(t == "keepaway") return MAPINFO_TYPE_KEEPAWAY;
        else if(t == "all")     return MAPINFO_TYPE_ALL;
        else                    return 0;
 }
@@ -670,6 +682,7 @@ string MapInfo_Type_ToString(float t)
        else if(t == MAPINFO_TYPE_RACE)            return "rc";
        else if(t == MAPINFO_TYPE_NEXBALL)         return "nexball";
        else if(t == MAPINFO_TYPE_CTS)             return "cts";
+       else if(t == MAPINFO_TYPE_KEEPAWAY)        return "keepaway";
        else if(t == MAPINFO_TYPE_ALL)             return "all";
        else                                       return "";
 }
@@ -1134,6 +1147,8 @@ float MapInfo_CurrentGametype()
                return MAPINFO_TYPE_NEXBALL;
        else if(cvar("g_cts"))
                return MAPINFO_TYPE_CTS;
+       else if(cvar("g_keepaway"))
+               return MAPINFO_TYPE_KEEPAWAY;
        else
                return MAPINFO_TYPE_DEATHMATCH;
 }
@@ -1161,20 +1176,21 @@ string MapInfo_GetGameTypeCvar(float t)
 {
        switch(t)
        {
-               case MAPINFO_TYPE_DEATHMATCH: return "g_dm";
-               case MAPINFO_TYPE_TEAM_DEATHMATCH: return "g_tdm";
-               case MAPINFO_TYPE_DOMINATION: return "g_domination";
-               case MAPINFO_TYPE_CTF: return "g_ctf";
-               case MAPINFO_TYPE_RUNEMATCH: return "g_runematch";
-               case MAPINFO_TYPE_LMS: return "g_lms";
-               case MAPINFO_TYPE_ARENA: return "g_arena";
-               case MAPINFO_TYPE_CA: return "g_ca";
-               case MAPINFO_TYPE_KEYHUNT: return "g_kh";
-               case MAPINFO_TYPE_ASSAULT: return "g_assault";
-               case MAPINFO_TYPE_ONSLAUGHT: return "g_onslaught";
-               case MAPINFO_TYPE_RACE: return "g_race";
-               case MAPINFO_TYPE_NEXBALL: return "g_nexball";
-               case MAPINFO_TYPE_CTS: return "g_cts";
+               case MAPINFO_TYPE_DEATHMATCH:           return "g_dm";
+               case MAPINFO_TYPE_TEAM_DEATHMATCH:      return "g_tdm";
+               case MAPINFO_TYPE_DOMINATION:           return "g_domination";
+               case MAPINFO_TYPE_CTF:                  return "g_ctf";
+               case MAPINFO_TYPE_RUNEMATCH:            return "g_runematch";
+               case MAPINFO_TYPE_LMS:                  return "g_lms";
+               case MAPINFO_TYPE_ARENA:                        return "g_arena";
+               case MAPINFO_TYPE_CA:                   return "g_ca";
+               case MAPINFO_TYPE_KEYHUNT:              return "g_kh";
+               case MAPINFO_TYPE_ASSAULT:              return "g_assault";
+               case MAPINFO_TYPE_ONSLAUGHT:            return "g_onslaught";
+               case MAPINFO_TYPE_RACE:                         return "g_race";
+               case MAPINFO_TYPE_NEXBALL:              return "g_nexball";
+               case MAPINFO_TYPE_CTS:                  return "g_cts";
+               case MAPINFO_TYPE_KEEPAWAY:             return "g_keepaway";
                default: return "";
        }
 }
@@ -1196,6 +1212,7 @@ void MapInfo_SwitchGameType(float t)
        cvar_set("g_race",       (t == MAPINFO_TYPE_RACE)            ? "1" : "0");
        cvar_set("g_nexball",    (t == MAPINFO_TYPE_NEXBALL)         ? "1" : "0");
        cvar_set("g_cts",        (t == MAPINFO_TYPE_CTS)             ? "1" : "0");
+       cvar_set("g_keepaway",   (t == MAPINFO_TYPE_KEEPAWAY)        ? "1" : "0");
 }
 
 void MapInfo_LoadMap(string s)
index 1fcc0dc662783ebd056281a5732a9d75ca98a31f..64076e7121a5f91f7d4432b107aeb29cf5d90b6a 100644 (file)
@@ -12,7 +12,8 @@ float MAPINFO_TYPE_KEYHUNT            = 1024;
 float MAPINFO_TYPE_ASSAULT             = 2048;
 float MAPINFO_TYPE_ONSLAUGHT           = 4096;
 float MAPINFO_TYPE_NEXBALL             = 8192;
-float MAPINFO_TYPE_ALL                 = 16383; // this has to include all above bits
+float MAPINFO_TYPE_KEEPAWAY    = 16384;
+float MAPINFO_TYPE_ALL                 = 32767; // this has to include all above bits
 
 float MAPINFO_FEATURE_WEAPONS       = 1; // not defined for minstagib-only maps
 
index 8c87b7fdad4f0e81a26e66633d9bb9032c7020a8..823709c9505c83482e85636d6339159b083d480e 100644 (file)
@@ -439,6 +439,7 @@ string GametypeNameFromType(float g)
        else if (g == GAME_RACE) return "rc";
        else if (g == GAME_NEXBALL) return "nexball";
        else if (g == GAME_CTS) return "cts";
+       else if (g == GAME_KEEPAWAY) return "ka";
        return "dm";
 }
 
index 4fb8ac0ca5836e662ef911416e356e532c81c6cc..c47684bc66b6dc251204999feef7410b1bf1c727 100644 (file)
@@ -39,6 +39,8 @@ void XonoticServerCreateTab_fill(entity me)
                        if(e.checked) e0 = NULL;
                me.TD(me, 1, me.columns / n, e = makeXonoticGametypeButton(1, "g_arena", "Arena"));
                        if(e.checked) e0 = NULL;
+               me.TD(me, 1, me.columns / n, e = makeXonoticGametypeButton(1, "g_keepaway", "Keepaway"));
+                       if(e.checked) e0 = NULL;
                me.TD(me, 1, me.columns / n, e = makeXonoticGametypeButton(1, "g_race", "Race"));
                        if(e.checked) e0 = NULL;
                me.TD(me, 1, me.columns / n, e = makeXonoticGametypeButton(1, "g_cts", "Race CTS"));
index 467357810c005b050953b8f34192d727e7c27f82..4abb65ae3f7ebc60ae78ed926f12813066974b03 100644 (file)
@@ -28,6 +28,7 @@ CLASS(XonoticMapInfoDialog) EXTENDS(XonoticDialog)
        ATTRIB(XonoticMapInfoDialog, typeRaceLabel, entity, NULL)
        ATTRIB(XonoticMapInfoDialog, typeCTSLabel, entity, NULL)
        ATTRIB(XonoticMapInfoDialog, typeNexballLabel, entity, NULL)
+       ATTRIB(XonoticMapInfoDialog, typeKeepawayLabel, entity, NULL)
 
        ATTRIB(XonoticMapInfoDialog, currentMapIndex, float, 0)
        ATTRIB(XonoticMapInfoDialog, currentMapBSPName, string, string_null)
@@ -83,6 +84,7 @@ void XonoticMapInfoDialog_loadMapInfo(entity me, float i, entity mlb)
        me.typeRaceLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE);
        me.typeCTSLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CTS);
        me.typeNexballLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_NEXBALL);
+       me.typeKeepawayLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_KEEPAWAY);
 
        MapInfo_ClearTemps();
 }
@@ -146,6 +148,8 @@ void XonoticMapInfoDialog_fill(entity me)
                        me.typeCTSLabel = e;
                me.TD(me, 1, wgt, e = makeXonoticTextLabel(0, "Nexball"));
                        me.typeNexballLabel = e;
+               me.TD(me, 1, wgt, e = makeXonoticTextLabel(0, "Keepaway"));
+                       me.typeKeepawayLabel = e;
 
        me.gotoRC(me, me.rows - 2, 0);
                me.TD(me, 1, me.columns, e = makeXonoticTextLabel(0.5, ""));
index b99f27544a81488fc4cbbaae2a742b16eb718cad..e8b9c55120aa8b5206b617aef040286c52ba2306 100644 (file)
@@ -17,7 +17,7 @@ float require_spawnfunc_prefix; // if this float exists, only functions with spa
 
 float ctf_score_value(string parameter);
 
-float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_ca, g_lms, g_runematch, g_race, g_nexball, g_cts;
+float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_ca, g_lms, g_runematch, g_race, g_nexball, g_cts, g_keepaway;
 float g_cloaked, g_footsteps, g_jump_grunt, g_grappling_hook, g_midair, g_minstagib, g_pinata, g_norecoil, g_minstagib_invis_alpha, g_bloodloss;
 float g_warmup_limit;
 float g_warmup_allguns;
@@ -559,6 +559,10 @@ void target_voicescript_clear(entity pl);
 .float metertime;
 float g_nexball_meter_period;
 
+// Keepaway
+
+.entity kaballcarried;
+
 void SUB_DontUseTargets();
 void SUB_UseTargets();
 
index ded4518d396daabf16db0d4d5f8918274734a930..5f7614c7a21014b31f895328a3e994474c385a24 100644 (file)
@@ -329,6 +329,7 @@ void cvar_changes_init()
                BADCVAR("g_runematch");
                BADCVAR("g_tdm");
                BADCVAR("g_nexball");
+               BADCVAR("g_keepaway");
                BADCVAR("teamplay");
 
                // long
diff --git a/qcsrc/server/mutators/gamemode_keepaway.qc b/qcsrc/server/mutators/gamemode_keepaway.qc
new file mode 100644 (file)
index 0000000..378c45b
--- /dev/null
@@ -0,0 +1,270 @@
+void ka_SpawnBall(void);
+void ka_TouchEvent(entity);
+void ka_RespawnBall(void);
+
+void ka_Initialize()
+{
+       print("^4ka_Initialize was just called!\n");
+
+       if(!g_keepaway)
+               return;
+               
+       precache_sound("keepaway/pickedup.wav");
+       precache_sound("keepaway/dropped.wav");
+
+       ScoreRules_keepaway();
+       
+       entity e;
+       e = spawn();
+       e.think = ka_SpawnBall;
+       e.nextthink = time;
+}
+
+void ka_SpawnBall() // self = the ball
+{
+       if(!g_keepaway) { 
+               remove(self); 
+               return; 
+       }
+       if (!self.model) {
+               self.model = "models/orbs/orbblue.md3"; 
+               self.scale = 1;
+       }
+
+       precache_model(self.model);
+       setmodel(self, self.model);
+       setsize(self, BALL_MINS, BALL_MAXS);
+       ball_scale = self.scale;
+       self.classname = "keepawayball";
+       self.damageforcescale = cvar("g_keepawayball_damageforcescale");
+       self.effects = self.effects | EF_FULLBRIGHT;
+       self.movetype = MOVETYPE_BOUNCE;
+       self.touch = ka_TouchEvent;
+       self.think = ka_RespawnBall;
+       self.nextthink = time;
+       self.flags = FL_ITEM;
+       //self.reset = ka_Reset;
+       self.owner = world;
+       
+       // todo: Waypoints and radar
+       WaypointSprite_AttachCarrier("nb-ball", self);
+       //bprint("^4ka_SpawnBall was just called!\n");
+}
+
+void ka_RespawnBall()
+{
+       if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
+       {
+               makevectors(self.angles);
+               self.movetype = MOVETYPE_BOUNCE;
+               self.velocity = '0 0 200';
+               self.angles = '0 0 0';
+               self.solid = SOLID_TRIGGER;
+               //self.touch = ka_TouchEvent;
+               self.think = ka_RespawnBall;
+               self.nextthink = time + cvar("g_keepawayball_respawntime");
+       }
+       else
+       {
+               // sorry, can't spawn, better luck next frame
+               self.think = ka_RespawnBall;
+               self.nextthink = time;
+       }
+       //bprint("^4ka_RespawnBall was just called!\n");
+}
+
+void ka_TouchEvent(entity plyr)
+{
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+       {
+               self.think = ka_SpawnBall;
+               self.nextthink = time;
+               return;
+       }
+       if(!plyr) 
+               return;
+       if(!self) 
+               return;
+       if(other.classname != "player" || other.health < 1)
+               return;
+       if(self.wait > time)
+               return;
+       //if(time > self.ctf_droptime + cvar("g_keepawayball_respawntime"))
+       //      return;
+
+       self.owner = other;
+       other.kaballcarried = self;
+       setattachment(self, other, "");
+       setorigin(self, BALL_ATTACHORG);
+       
+       self.velocity = '0 0 0';
+       self.movetype = MOVETYPE_NONE;
+       self.touch = SUB_Null;
+       self.alpha = 0.01;
+       
+       self.think = SUB_Null;
+       self.nextthink = 0;
+
+       self.glow_color = cvar("g_keepawayball_trail_color");
+       self.glow_trail = TRUE;
+       plyr.effects |= 8;
+       plyr.alpha = 0.6;
+
+       bprint(other.netname, "^7 has picked up the ball!\n");
+       WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
+       WriteString(MSG_BROADCAST, strcat("\n\n", other.netname, "^7 has picked up the ball!\n"));
+       sound(self.owner, CHAN_AUTO, "keepaway/pickedup.wav", VOL_BASE, ATTN_NORM);
+       
+       PlayerScore_Add(other, SP_KEEPAWAY_PICKUPS, 1);
+
+       // todo: Waypoints and radar
+}
+
+MUTATOR_HOOKFUNCTION(ka_RemovePlayer)
+{
+       if(self.kaballcarried) {
+               entity ball;
+               ball = self.kaballcarried;
+
+               setattachment(ball, world, "");
+               ball.movetype = MOVETYPE_BOUNCE;
+               ball.solid = SOLID_TRIGGER;
+               ball.wait = time + 1;
+               ball.ctf_droptime = time;
+               ball.think = ka_SpawnBall;
+               ball.nextthink = time + cvar("g_keepawayball_respawntime");
+               ball.touch = ka_TouchEvent;
+               self.effects = EF_LOWPRECISION;
+               self.alpha = 1.0;
+               ball.alpha = 1.0;
+               setorigin(ball, self.origin + '0 0 10');
+               ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
+       
+               bprint(self.netname, "^7 has dropped the ball!\n");
+               WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
+               WriteString(MSG_BROADCAST, strcat("\n\n", self.netname, "^7 has dropped the ball!\n"));
+               sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NORM);   
+               
+               PlayerScore_Add(self, SP_KEEPAWAY_DROPS, 1);
+               
+               // todo
+               WaypointSprite_AttachCarrier("nb-ball", ball);
+               WaypointSprite_Kill(self.waypointsprite_attachedforcarrier);
+               
+               ball.owner.kaballcarried = world;
+               ball.owner = world;
+       }
+       
+       if((frag_attacker || frag_target) && !(frag_attacker == frag_target)) {
+               if(frag_target.kaballcarried) // get amount of times killing carrier
+                       PlayerScore_Add(frag_attacker, SP_KEEPAWAY_CARRIERKILLS, 1);
+               else if not(frag_attacker.kaballcarried)
+                       if(cvar("g_keepaway_noncarrier_warn"))
+                               centerprint_atprio(frag_attacker, (CENTERPRIO_SPAM + 5), "Killing people while you don't have the ball gives no points!");
+       
+               if(frag_attacker.kaballcarried) // get kills as carrier
+                       PlayerScore_Add(frag_attacker, SP_KEEPAWAY_SCORE, 1);
+       }
+       return 1;
+}
+/*
+MUTATOR_HOOKFUNCTION(ka_Scoring)
+{
+       if not(frag_attacker == frag_target)
+       {
+               if(frag_target.kaballcarried) { // get amount of times killing carrier
+                       PlayerScore_Add(frag_attacker, SP_KEEPAWAY_CARRIERKILLS, 1);
+                       //ka_RemovePlayer();
+               }
+               else if not(frag_attacker.kaballcarried)
+                       if(cvar("g_keepaway_noncarrier_warn"))
+                               centerprint_atprio(frag_attacker, (CENTERPRIO_SPAM + 5), "Killing people while you don't have the ball gives no points!");
+
+               if(frag_attacker.kaballcarried) // get kills as carrier
+                       PlayerScore_Add(frag_attacker, SP_KEEPAWAY_SCORE, 1);
+       }
+       return 1;
+}
+
+
+MUTATOR_HOOKFUNCTION(ka_PlayerDies)
+{
+       float i;
+       entity e;
+
+       float temp_tag_players_count;
+       temp_tag_players_count = tag_players_count;
+
+       if(frag_target.tagcolor == frag_target.tagcolor_original) // if this is the first time we die... (our tagcolor remained unchanged)
+       {
+               for(i = 0; i < temp_tag_players_count; ++i) // check other players...
+               {
+                       e = tag_players[i];
+                       if(e == world) // empty slot, skip to next
+                       {
+                               if(temp_tag_players_count < TAGCOLOR_MAX - 1) // just in case
+                                       ++temp_tag_players_count;
+                               continue;
+                       }
+
+                       if(e.tagcolor == frag_target.tagcolor_original) // and see if they have our original tag color
+                       {
+                               tag_GetFragAttackers_ColorOwner();
+                               centerprint(e, strcat("^1Your master ^7", frag_target.netname, "^1 was tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"));
+                               e.tagcolor = frag_attacker.tagcolor; // if so, remove it, our tag color has now "died out" from this round and we can not win anymore. The attacker will "summon" all of our previously fragged targets, and also us.
+                               setcolor(e, 16 * e.tagcolor + e.tagcolor);
+                       }
+               }
+       }
+       else
+       {
+               frag_target.tagcolor = frag_attacker.tagcolor;
+               setcolor(frag_target, 16 * frag_target.tagcolor + frag_target.tagcolor);
+       }
+
+       tag_GetFragAttackers_ColorOwner();
+
+       if(color_owner_self)
+               color_owner_green = "^2your own";
+       centerprint(frag_attacker, strcat("^2You tagged ^7", frag_target.netname, " ^2with ^7", color_owner_green, " ^2color.\n"));
+
+       if(color_owner_self)
+               color_owner_red = "^1their own";
+       centerprint(frag_target, strcat("^1You were tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"));
+       bprint("^7", frag_target.netname, "^1 was tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n");
+
+       frag_target.health = cvar("g_balance_health_start"); // "respawn" the player :P
+
+       tag_CheckWinner();
+
+       return 1;
+}
+*/
+
+
+MUTATOR_DEFINITION(gamemode_keepaway)
+{
+       MUTATOR_HOOK(MakePlayerObserver, ka_RemovePlayer, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ClientDisconnect, ka_RemovePlayer, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerDies, ka_RemovePlayer, CBC_ORDER_ANY);
+       //MUTATOR_HOOK(PlayerSpawn, ka_PlayerSpawn, CBC_ORDER_ANY);
+       //MUTATOR_HOOK(GiveFragsForKill, ka_GiveFragsForKill, CBC_ORDER_FIRST);
+       //MUTATOR_HOOK(PlayerPreThink, ka_PlayerPreThink, CBC_ORDER_FIRST);
+
+       MUTATOR_ONADD
+       {
+               if(time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               g_keepaway = 1;
+               ka_Initialize();
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               g_keepaway = 0;
+               error("This is a game type and it cannot be removed at runtime.");
+       }
+
+       return 0;
+}
+
index 542014e8691275dfe11870f8d97118036f5f846e..d0cf0f7213372eea4d7e6560b5fe81f8b95b6246 100644 (file)
@@ -1,4 +1,5 @@
 MUTATOR_DECLARATION(gamemode_keyhunt);
+MUTATOR_DECLARATION(gamemode_keepaway);
 
 MUTATOR_DECLARATION(mutator_nix);
 MUTATOR_DECLARATION(mutator_dodging);
index c2718d4e8642d69e006bc84400a4ff442d235b39..93f9bf56d92c1bf20b79beb88a0767cb7634bdc8 100644 (file)
@@ -177,6 +177,7 @@ cheats.qc
 
 mutators/base.qc
 mutators/gamemode_keyhunt.qc
+mutators/gamemode_keepaway.qc
 mutators/mutator_nix.qc
 mutators/mutator_dodging.qc
 mutators/mutator_rocketflying.qc
index 4db1b4493af571ec3b12f504347a6461a41beba1..78b6560f9f2c45216e7f5b561ca99ee68ff4734e 100644 (file)
@@ -187,3 +187,19 @@ void ScoreRules_nexball(float teams)
        ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
        ScoreRules_basics_end();
 }
+
+// Keep Away stuff
+#define SP_KEEPAWAY_PICKUPS 4
+#define SP_KEEPAWAY_CARRIERKILLS 5
+#define SP_KEEPAWAY_DROPS 6
+#define SP_KEEPAWAY_SCORE 7
+void ScoreRules_keepaway()
+{
+       print("^4ScoreRules_keepaway was just called!\n");
+       ScoreRules_basics(0, SFL_SORT_PRIO_PRIMARY, 0, FALSE);
+       ScoreInfo_SetLabel_PlayerScore(SP_KEEPAWAY_SCORE,                "score",        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_DROPS,        "drops",    SFL_LOWER_IS_BETTER);
+       ScoreRules_basics_end();
+}
index b9064c783b852a515586ade5e0826b3323380bf9..7e73bc142f93c76f9ea3a3e1263a9c9c859631b8 100644 (file)
@@ -101,6 +101,7 @@ void WriteGameCvars()
        cvar_set("g_race", ftos(g_race));
        cvar_set("g_nexball", ftos(g_nexball));
        cvar_set("g_cts", ftos(g_cts));
+       cvar_set("g_keepaway", ftos(g_keepaway));
 }
 
 void ReadGameCvars()
@@ -127,6 +128,7 @@ void ReadGameCvars()
                found += (g_race = (!found && (prev != GAME_RACE) && cvar("g_race")));
                found += (g_nexball = (!found && (prev != GAME_NEXBALL) && cvar("g_nexball")));
                found += (g_cts = (!found && (prev != GAME_CTS) && cvar("g_cts")));
+               found += (g_keepaway = (!found && (prev != GAME_KEEPAWAY) && cvar("g_keepaway")));
 
                if(found)
                        break;
@@ -373,6 +375,13 @@ void InitGameplayMode()
                have_team_spawns = -1; // request team spawns
        }
 
+       if(g_keepaway)
+       {
+               game = GAME_KEEPAWAY;
+               gamemode_name = "Keepaway";
+               MUTATOR_ADD(gamemode_keepaway);
+       }
+
        if(teams_matter)
                entcs_init();
 
diff --git a/sound/keepaway/dropped.wav b/sound/keepaway/dropped.wav
new file mode 100644 (file)
index 0000000..6867468
Binary files /dev/null and b/sound/keepaway/dropped.wav differ
diff --git a/sound/keepaway/pickedup.wav b/sound/keepaway/pickedup.wav
new file mode 100644 (file)
index 0000000..55e55a4
Binary files /dev/null and b/sound/keepaway/pickedup.wav differ