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"
seta g_keyhunt_teams_override 0
set g_keyhunt_teams 0
+// keepaway
+set g_keepaway 0 "Keepaway: w00t"
+set g_keepawayball_respawntime 5
+set g_keepawayball_damageforcescale 1
+set g_keepawayball_trail_color "0.2 0.4 1"
+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"
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;
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;
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 "";
}
}
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)
{
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 "";
}
}
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;
}
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 "";
}
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;
}
{
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 "";
}
}
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)
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
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";
}
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)
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();
}
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, ""));
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;
BADCVAR("g_runematch");
BADCVAR("g_tdm");
BADCVAR("g_nexball");
+ BADCVAR("g_keepaway");
BADCVAR("teamplay");
// long
--- /dev/null
+void ka_SpawnBall(void);
+void ka_TouchEvent(entity);
+void ka_RespawnBall(void);
+
+void ka_Initialize()
+{
+ if(!g_keepaway)
+ return;
+
+ precache_sound("keepaway/pickedup.wav");
+ precache_sound("keepaway/dropped.wav");
+
+ entity e;
+ e = spawn();
+ e.think = ka_SpawnBall;
+ e.nextthink = time;
+}
+
+void ka_SpawnBall()
+{
+ if(!g_keepaway) {
+ remove(self);
+ return;
+ }
+ if (!self.model) {
+ self.model = "models/nexball/ball.md3";
+ self.scale = 1.3;
+ }
+
+ precache_model(self.model);
+ setmodel(self, self.model);
+ setsize(self, BALL_MINS, BALL_MAXS);
+ ball_scale = self.scale;
+ 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();
+}
+
+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;
+ }
+}
+
+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) && (time > self.ctf_droptime + cvar("g_keepawayball_respawntime")))
+ return;
+ if (self.wait > time)
+ return;
+
+ self.owner = other;
+ other.ballcarried = 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)
+{
+ entity ball;
+ ball = self.ballcarried;
+
+ 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("ka-ball", ball);
+ //WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
+
+ ball.owner.ballcarried = world;
+ ball.owner = world;
+
+ return 1;
+}
+
+/*
+void ka_DropEvent(entity plyr, entity ball)
+{
+ 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;
+ plyr.effects = EF_LOWPRECISION;
+ plyr.alpha = 1.0;
+ ball.alpha = 1.0;
+ setorigin(ball, plyr.origin + '0 0 10');
+ ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
+
+ bprint(plyr.netname, "^7 has dropped the ball!\n");
+ WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
+ WriteString(MSG_BROADCAST, strcat("\n\n", plyr.netname, "^7 has dropped the ball!\n"));
+ sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NORM);
+
+ PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1);
+
+ // todo
+ //WaypointSprite_AttachCarrier("ka-ball", ball);
+ //WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
+
+ ball.owner.kaballcarried = world;
+ ball.owner = world;
+}
+
+
+void ka_CheckWinner()
+{
+
+}
+
+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_HOOKFUNCTION(tag_RemovePlayer)
+{
+
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(tag_GiveFragsForKill)
+{
+ frag_score = 0; // no frags counted in Tag, maybe later (TODO)
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(tag_PlayerPreThink)
+{
+ setcolor(self, 16 * self.tagcolor + self.tagcolor); // prevent cheating by changing player colors
+ 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_PlayerDies, 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;
+}
+
MUTATOR_DECLARATION(gamemode_keyhunt);
+MUTATOR_DECLARATION(gamemode_keepaway);
MUTATOR_DECLARATION(mutator_nix);
MUTATOR_DECLARATION(mutator_dodging);
mutators/base.qc
mutators/gamemode_keyhunt.qc
+mutators/gamemode_keepaway.qc
mutators/mutator_nix.qc
mutators/mutator_dodging.qc
mutators/mutator_rocketflying.qc
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()
+{
+ 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();
+}
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()
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;
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();