r2831 - in branches/nexuiz-2.0/data: . qcsrc/server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Mon Oct 15 18:48:02 EDT 2007
Author: div0
Date: 2007-10-15 18:48:02 -0400 (Mon, 15 Oct 2007)
New Revision: 2831
Added:
branches/nexuiz-2.0/data/qcsrc/server/mode_onslaught.qc
Modified:
branches/nexuiz-2.0/data/default.cfg
branches/nexuiz-2.0/data/game_reset.cfg
branches/nexuiz-2.0/data/qcsrc/server/g_world.qc
branches/nexuiz-2.0/data/qcsrc/server/progs.src
branches/nexuiz-2.0/data/qcsrc/server/teamplay.qc
Log:
merge of Onslaught mode (beware: it still lacks its models and sounds)
Modified: branches/nexuiz-2.0/data/default.cfg
===================================================================
--- branches/nexuiz-2.0/data/default.cfg 2007-10-15 22:38:42 UTC (rev 2830)
+++ branches/nexuiz-2.0/data/default.cfg 2007-10-15 22:48:02 UTC (rev 2831)
@@ -397,6 +397,9 @@
set g_arena_warmup 5 // time, newly spawned players have to prepare themselves in round based matches
set g_arena_powerups 0 // enables powerups (superhealth, strength and shield), which are removed by default
+// onslaught
+set g_onslaught 0
+
// server game balance settings
set g_balance_armor_regen 0
set g_balance_armor_rot 0.1
Modified: branches/nexuiz-2.0/data/game_reset.cfg
===================================================================
--- branches/nexuiz-2.0/data/game_reset.cfg 2007-10-15 22:38:42 UTC (rev 2830)
+++ branches/nexuiz-2.0/data/game_reset.cfg 2007-10-15 22:48:02 UTC (rev 2831)
@@ -15,6 +15,7 @@
set g_arena 0
set g_campaign 0
set g_keyhunt 0
+set g_onslaught 0
set teamplay 0
set gamecfg 0
Modified: branches/nexuiz-2.0/data/qcsrc/server/g_world.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/g_world.qc 2007-10-15 22:38:42 UTC (rev 2830)
+++ branches/nexuiz-2.0/data/qcsrc/server/g_world.qc 2007-10-15 22:48:02 UTC (rev 2831)
@@ -386,6 +386,8 @@
return "lms";
else if (game == GAME_KEYHUNT)
return "kh";
+ else if (game == GAME_ONSLAUGHT)
+ return "ons";
return "dm";
}
@@ -1106,6 +1108,42 @@
head.winning = 0;
}
+// Onslaught winning condition:
+// game terminates if only one team has a working generator (or none)
+float() WinningCondition_Onslaught =
+{
+ entity head;
+ local float t1, t2, t3, t4;
+ // first check if the game has ended
+ t1 = t2 = t3 = t4 = 0;
+ head = find(world, classname, "onslaught_generator");
+ while (head)
+ {
+ if (head.health > 0)
+ {
+ if (head.team == COLOR_TEAM1) t1 = 1;
+ if (head.team == COLOR_TEAM2) t2 = 1;
+ if (head.team == COLOR_TEAM3) t3 = 1;
+ if (head.team == COLOR_TEAM4) t4 = 1;
+ }
+ head = find(head, classname, "onslaught_generator");
+ }
+ if (t1 + t2 + t3 + t4 < 2)
+ {
+ // game over, only one team remains (or none)
+ ClearWinners();
+ if (t1) SetWinners(team, COLOR_TEAM1);
+ if (t2) SetWinners(team, COLOR_TEAM2);
+ if (t3) SetWinners(team, COLOR_TEAM3);
+ if (t4) SetWinners(team, COLOR_TEAM4);
+ dprint("Have a winner, ending game.\n");
+ return WINNING_YES;
+ }
+
+ // Two or more teams remain
+ return WINNING_NO;
+}
+
float() LMS_NewPlayerLives =
{
float fl;
@@ -1532,6 +1570,10 @@
{
status = WinningCondition_LMS();
}
+ else if (cvar("g_onslaught"))
+ {
+ status = WinningCondition_Onslaught();
+ }
else
{
if(teams_matter)
Added: branches/nexuiz-2.0/data/qcsrc/server/mode_onslaught.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/mode_onslaught.qc (rev 0)
+++ branches/nexuiz-2.0/data/qcsrc/server/mode_onslaught.qc 2007-10-15 22:48:02 UTC (rev 2831)
@@ -0,0 +1,477 @@
+
+.string target2;
+.float iscaptured;
+.float islinked;
+.float isshielded;
+void() onslaught_updatelinks =
+{
+ local entity l, links;
+ local float stop, t1, t2, t3, t4;
+ // first check if the game has ended
+ t1 = t2 = t3 = t4 = 0;
+ l = findchain(classname, "onslaught_generator");
+ while (l)
+ {
+ if (l.iscaptured)
+ {
+ if (l.team == COLOR_TEAM1) t1 = 1;
+ if (l.team == COLOR_TEAM2) t2 = 1;
+ if (l.team == COLOR_TEAM3) t3 = 1;
+ if (l.team == COLOR_TEAM4) t4 = 1;
+ }
+ l = l.chain;
+ }
+ if (t1 + t2 + t3 + t4 < 2)
+ {
+ // game over, only one team remains (or none)
+ return;
+ }
+ // mark generators as being shielded and networked
+ l = findchain(classname, "onslaught_generator");
+ while (l)
+ {
+ l.islinked = l.iscaptured;
+ l.isshielded = l.iscaptured;
+ l = l.chain;
+ }
+ // mark points as shielded and not networked
+ l = findchain(classname, "onslaught_controlpoint");
+ while (l)
+ {
+ l.islinked = FALSE;
+ l.isshielded = TRUE;
+ l = l.chain;
+ }
+ // flow power outward from the generators through the network
+ links = findchain(classname, "onslaught_link");
+ stop = TRUE;
+ while (stop)
+ {
+ stop = FALSE;
+ l = links;
+ while (l)
+ {
+ // if both points are captured by the same team, and only one of
+ // them is powered, mark the other one as powered as well
+ if (l.enemy.team == l.goalentity.team)
+ {
+ if (l.goalentity.islinked)
+ {
+ if (l.enemy.iscaptured)
+ if (!l.enemy.islinked)
+ {
+ stop = FALSE;
+ l.enemy.islinked = TRUE;
+ }
+ }
+ else
+ {
+ if (l.goalentity.iscaptured)
+ if (!l.goalentity.islinked)
+ {
+ stop = FALSE;
+ l.goalentity.islinked = TRUE;
+ }
+ }
+ }
+ l = l.chain;
+ }
+ }
+ // now that we know which points are powered we can mark their neighbors
+ // as unshielded if team differs
+ l = links;
+ while (l)
+ {
+ if (l.goalentity.team != l.enemy.team)
+ {
+ if (l.goalentity.islinked)
+ l.enemy.isshielded = FALSE;
+ if (l.enemy.islinked)
+ l.goalentity.isshielded = FALSE;
+ }
+ l = l.chain;
+ }
+ // now update the takedamage and alpha variables on generator shields
+ l = findchain(classname, "onslaught_generator");
+ while (l)
+ {
+ if (l.isshielded)
+ {
+ l.enemy.alpha = -1;
+ l.takedamage = DAMAGE_AIM;
+ }
+ else
+ {
+ l.enemy.alpha = -1;
+ l.takedamage = DAMAGE_AIM;
+ }
+ l = l.chain;
+ }
+ // now update the takedamage and alpha variables on control point icons
+ l = findchain(classname, "onslaught_controlpoint");
+ while (l)
+ {
+ if (l.isshielded)
+ {
+ l.enemy.alpha = -1;
+ if (l.goalentity)
+ l.goalentity.takedamage = DAMAGE_AIM;
+ }
+ else
+ {
+ l.enemy.alpha = -1;
+ if (l.goalentity)
+ l.goalentity.takedamage = DAMAGE_AIM;
+ }
+ l = l.chain;
+ }
+};
+
+void() onslaught_generator_think =
+{
+ self.nextthink = ceil(time + 1);
+ if (cvar("timelimit"))
+ if (time > cvar("timelimit") * 60 - 60)
+ {
+ // self.max_health / 120 gives 2 minutes of overtime
+ sound(self, CHAN_AUTO, "sound/onslaught/generator_decay.wav", 1, ATTN_NORM);
+ Damage(self, self, self, self.max_health / 60, DEATH_HURTTRIGGER, self.origin, '0 0 0');
+ }
+};
+
+void() onslaught_generator_deaththink =
+{
+ local vector org;
+ if (self.count > 0)
+ {
+ self.nextthink = time + 0.1;
+ self.count = self.count - 1;
+ org = randompos(self.origin + self.mins + '8 8 8', self.origin + self.maxs + '-8 -8 -8');
+ pointparticles(particleeffectnum("onslaught_generator_smallexplosion"), org, '0 0 0', 1);
+ sound(self, CHAN_AUTO, "sound/weapons/grenade_impact.wav", 1, ATTN_NORM);
+ }
+ else
+ {
+ org = self.origin;
+ pointparticles(particleeffectnum("onslaught_generator_finalexplosion"), org, '0 0 0', 1);
+ sound(self, CHAN_AUTO, "sound/weapons/rocket_impact.wav", 1, ATTN_NORM);
+ }
+};
+
+void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) onslaught_generator_damage =
+{
+ if (damage <= 0)
+ return;
+ if (attacker != self)
+ {
+ if (self.isshielded)
+ {
+ // this is protected by a shield, so ignore the damage
+ if (time > self.pain_finished)
+ if (attacker.classname == "player")
+ {
+ play2(attacker, "sound/onslaught/damageblockedbyshield.wav");
+ self.pain_finished = time + 1;
+ }
+ return;
+ }
+ if (time > self.pain_finished)
+ {
+ self.pain_finished = time + 5;
+ bprint(ColoredTeamName(self.team), " generator under attack!\n");
+ play2team(self.team, "sound/onslaught/generator_underattack.wav");
+ }
+ }
+ self.health = self.health - damage;
+ // choose an animation frame based on health
+ self.frame = 10 * bound(0, (1 - self.health / self.max_health), 1);
+ // see if the generator is still functional, or dying
+ if (self.health > 0)
+ bprint(ColoredTeamName(self.team), " generator has ", ftos(floor(self.health)), " health remaining\n");
+ else
+ {
+ if (attacker == self)
+ bprint(ColoredTeamName(self.team), " generator spontaneously exploded due to overtime!\n");
+ else
+ bprint(ColoredTeamName(self.team), " generator destroyed by ", ColoredTeamName(attacker.team), "!\n");
+ self.iscaptured = FALSE;
+ self.islinked = FALSE;
+ self.isshielded = FALSE;
+ self.takedamage = DAMAGE_NO; // can't be hurt anymore
+ self.event_damage = SUB_Null; // won't do anything if hurt
+ self.count = 30; // 30 explosions
+ self.think = onslaught_generator_deaththink; // explosion sequence
+ self.nextthink = time; // start exploding immediately
+ self.think(); // do the first explosion now
+ onslaught_updatelinks();
+ }
+};
+
+// update links after a delay
+void() onslaught_generator_delayed =
+{
+ onslaught_updatelinks();
+ // now begin normal thinking
+ self.think = onslaught_generator_think;
+ self.nextthink = time;
+};
+
+/*QUAKED onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
+Base generator.
+
+onslaught_link entities can target this.
+
+keys:
+"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
+"targetname" - name that onslaught_link entities will use to target this.
+*/
+void() onslaught_generator =
+{
+ if (!cvar("g_onslaught"))
+ {
+ remove(self);
+ return;
+ }
+ local entity e;
+ precache_model("models/onslaught/generator.md3");
+ precache_model("models/onslaught/generator_shield.md3");
+ precache_sound("sound/onslaught/generator_decay.wav");
+ precache_sound("sound/weapons/grenade_impact.wav");
+ precache_sound("sound/weapons/rocket_impact.wav");
+ precache_sound("sound/onslaught/generator_underattack.wav");
+ if (!self.team)
+ objerror("team must be set");
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_NONE;
+ self.max_health = self.health = 1000;
+ setmodel(self, "models/onslaught/generator.md3");
+ //setsize(self, '-32 -32 -24', '32 32 64');
+ setorigin(self, self.origin);
+ self.takedamage = DAMAGE_AIM;
+ self.event_damage = onslaught_generator_damage;
+ self.iscaptured = TRUE;
+ self.islinked = TRUE;
+ self.isshielded = TRUE;
+ // spawn shield model which indicates whether this can be damaged
+ self.enemy = e = spawn();
+ e.solid = SOLID_NOT;
+ e.movetype = MOVETYPE_NONE;
+ e.effects = EF_ADDITIVE;
+ setmodel(e, "models/onslaught/generator_shield.md3");
+ //setsize(e, '-32 -32 0', '32 32 128');
+ setorigin(e, self.origin);
+ e.colormap = self.colormap;
+ self.think = onslaught_generator_delayed;
+ self.nextthink = time + 0.2;
+};
+
+void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) onslaught_controlpoint_icon_damage =
+{
+ if (damage <= 0)
+ return;
+ if (self.owner.isshielded)
+ {
+ // this is protected by a shield, so ignore the damage
+ if (time > self.pain_finished)
+ if (attacker.classname == "player")
+ {
+ play2(attacker, "sound/onslaught/damageblockedbyshield.wav");
+ self.pain_finished = time + 1;
+ }
+ return;
+ }
+ if (time > self.pain_finished)
+ if (attacker.classname == "player")
+ {
+ play2team(self.team, "sound/onslaught/controlpoint_underattack.wav");
+ self.pain_finished = time + 5;
+ }
+ self.health = self.health - damage;
+ self.alpha = self.health / self.max_health;
+ self.pain_finished = time + 1;
+ // colormod flash when shot
+ self.colormod = '2 2 2';
+ if (self.health < 0)
+ {
+ sound(self, CHAN_AUTO, "sound/weapons/grenade_impact.wav", 1, ATTN_NORM);
+ pointparticles(particleeffectnum("onslaught_controlpoint_explosion"), self.origin, '0 0 0', 1);
+ bprint(ColoredTeamName(self.team), " ", self.message, " control point destroyed by ", ColoredTeamName(attacker.team), "\n");
+ self.owner.goalentity = world;
+ self.owner.islinked = FALSE;
+ self.owner.iscaptured = FALSE;
+ self.owner.team = 0;
+ self.owner.colormap = 1024;
+ onslaught_updatelinks();
+ remove(self);
+ }
+};
+
+void() onslaught_controlpoint_icon_think =
+{
+ self.nextthink = time + 0.1;
+ if (time > self.pain_finished + 1)
+ {
+ self.health = self.health + self.count;
+ if (self.health >= self.max_health)
+ self.health = self.max_health;
+ }
+ self.alpha = self.health / self.max_health;
+ // colormod flash when shot
+ self.colormod = '1 1 1' * (2 - bound(0, (self.pain_finished - time) / 10, 1));
+};
+
+void() onslaught_controlpoint_icon_buildthink =
+{
+ self.nextthink = time + 0.1;
+ self.health = self.health + self.count;
+ if (self.health >= self.max_health)
+ {
+ self.health = self.max_health;
+ self.count = self.count * 0.2; // slow repair rate from now on
+ self.think = onslaught_controlpoint_icon_think;
+ sound(self, CHAN_BODY, "sound/onslaught/controlpoint_built.wav", 1, ATTN_NORM);
+ bprint(ColoredTeamName(self.team), " captured ", self.owner.message, " control point\n");
+ self.owner.iscaptured = TRUE;
+ onslaught_updatelinks();
+ }
+ self.alpha = self.health / self.max_health;
+ // colormod flash when shot
+ self.colormod = '1 1 1' * (2 - bound(0, (self.pain_finished - time) / 10, 1));
+};
+
+void() onslaught_controlpoint_touch =
+{
+ local entity e;
+ if (other.classname != "player")
+ return;
+ // if there's already an icon built, nothing happens
+ if (self.goalentity)
+ return;
+ // shielded points are definitely off-limits
+ if (self.isshielded)
+ return;
+ // check to see if this player has a legitimate claim to capture this
+ // control point - more specifically that there is a captured path of
+ // points leading back to the team generator
+ e = findchain(classname, "onslaught_link");
+ while (e)
+ {
+ if (e.goalentity == self)
+ {
+ if (e.enemy.islinked)
+ if (e.enemy.team == other.team)
+ break;
+ }
+ else if (e.enemy == self)
+ {
+ if (e.goalentity.islinked)
+ if (e.goalentity.team == other.team)
+ break;
+ }
+ e = e.chain;
+ }
+ if (!e)
+ return;
+ // we've verified that this player has a legitimate claim to this point,
+ // so start building the captured point icon (which only captures this
+ // point if it successfully builds without being destroyed first)
+ self.goalentity = e = spawn();
+ e.owner = self;
+ e.max_health = 300;
+ e.health = e.max_health * 0.1;
+ e.alpha = e.health / e.max_health;
+ e.solid = SOLID_BBOX;
+ e.movetype = MOVETYPE_NONE;
+ setmodel(e, "models/onslaught/controlpoint_icon.md3");
+ setsize(e, '-32 -32 -32', '32 32 32');
+ setorigin(e, self.origin + '0 0 96');
+ e.takedamage = DAMAGE_AIM;
+ e.event_damage = onslaught_controlpoint_icon_damage;
+ e.team = other.team;
+ e.think = onslaught_controlpoint_icon_buildthink;
+ e.nextthink = time + 0.1;
+ e.count = e.max_health / 50; // how long it takes to build
+ sound(e, CHAN_BODY, "sound/onslaught/controlpoint_build.wav", 1, ATTN_NORM);
+ self.team = e.team;
+ self.colormap = 1024 + (self.team - 1) * 17;
+};
+
+/*QUAKED onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
+Control point. Be sure to give this enough clearance so that the shootable part has room to exist
+
+This should link to an onslaught_controlpoint entity or onslaught_generator entity.
+
+keys:
+"targetname" - name that onslaught_link entities will use to target this.
+"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
+"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
+*/
+void() onslaught_controlpoint =
+{
+ local entity e;
+ if (!cvar("g_onslaught"))
+ {
+ remove(self);
+ return;
+ }
+ precache_model("models/onslaught/controlpoint_pad.md3");
+ precache_model("models/onslaught/controlpoint_shield.md3");
+ precache_model("models/onslaught/controlpoint_icon.md3");
+ precache_sound("sound/onslaught/controlpoint_build.wav");
+ precache_sound("sound/onslaught/controlpoint_built.wav");
+ precache_sound("sound/weapons/grenade_impact.wav");
+ precache_sound("sound/onslaught/damageblockedbyshield.wav");
+ precache_sound("sound/onslaught/controlpoint_underattack.wav");
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_NONE;
+ setmodel(self, "models/onslaught/controlpoint_pad.md3");
+ //setsize(self, '-32 -32 0', '32 32 8');
+ setorigin(self, self.origin);
+ self.touch = onslaught_controlpoint_touch;
+ self.colormap = 1024;
+ self.iscaptured = FALSE;
+ self.islinked = FALSE;
+ self.isshielded = TRUE;
+ // spawn shield model which indicates whether this can be damaged
+ self.enemy = e = spawn();
+ e.solid = SOLID_NOT;
+ e.movetype = MOVETYPE_NONE;
+ e.effects = EF_ADDITIVE;
+ setmodel(e, "models/onslaught/controlpoint_shield.md3");
+ //setsize(e, '-32 -32 0', '32 32 128');
+ setorigin(e, self.origin);
+ e.colormap = self.colormap;
+ onslaught_updatelinks();
+};
+
+void() onslaught_link_delayed =
+{
+ self.goalentity = find(world, targetname, self.target);
+ self.enemy = find(world, targetname, self.target2);
+ if (!self.goalentity)
+ objerror("can not find target\n");
+ if (!self.enemy)
+ objerror("can not find target2\n");
+}
+
+/*QUAKED onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
+Link between control points.
+
+This entity targets two different onslaught_controlpoint or onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
+
+keys:
+"target" - first control point.
+"target2" - second control point.
+*/
+void() onslaught_link =
+{
+ if (!cvar("g_onslaught"))
+ {
+ remove(self);
+ return;
+ }
+ if (self.target == "" || self.target2 == "")
+ objerror("target and target2 must be set\n");
+ self.think = onslaught_link_delayed;
+ self.nextthink = time + 0.1;
+};
Modified: branches/nexuiz-2.0/data/qcsrc/server/progs.src
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/progs.src 2007-10-15 22:38:42 UTC (rev 2830)
+++ branches/nexuiz-2.0/data/qcsrc/server/progs.src 2007-10-15 22:48:02 UTC (rev 2831)
@@ -76,6 +76,7 @@
ctf.qc
domination.qc
+mode_onslaught.qc
g_hook.qc
t_swamp.qc
Modified: branches/nexuiz-2.0/data/qcsrc/server/teamplay.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/teamplay.qc 2007-10-15 22:38:42 UTC (rev 2830)
+++ branches/nexuiz-2.0/data/qcsrc/server/teamplay.qc 2007-10-15 22:48:02 UTC (rev 2831)
@@ -6,13 +6,14 @@
float GAME_LMS = 6;
float GAME_ARENA = 7;
float GAME_KEYHUNT = 8;
+float GAME_ONSLAUGHT = 10;
// client counts for each team
float c1, c2, c3, c4;
// # of bots on those teams
float cb1, cb2, cb3, cb4;
-float g_domination, g_ctf, g_tdm, g_keyhunt;
+float g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught;
float audit_teams_time;
@@ -103,6 +104,7 @@
cvar_set("g_lms", "0");
cvar_set("g_arena", "0");
cvar_set("g_keyhunt", "0");
+ cvar_set("g_onslaught", "0");
cvar_set("teamplay", "0");
}
@@ -236,6 +238,17 @@
gamemode_name = "Key Hunt";
teams_matter = 1;
}
+ else if(game == GAME_ONSLAUGHT || cvar("g_onslaught"))
+ {
+ ResetGameCvars();
+ game = GAME_ONSLAUGHT;
+ cvar_set("g_onslaught", "1");
+
+ ActivateTeamplay();
+
+ gamemode_name = "Onslaught";
+ teams_matter = 1;
+ }
else
{
// we can only assume...
@@ -301,6 +314,7 @@
g_ctf = cvar("g_ctf");
g_tdm = cvar("g_tdm");
g_keyhunt = cvar("g_keyhunt");
+ g_onslaught = cvar("g_onslaught");
}
string GetClientVersionMessage(float v) {
@@ -509,6 +523,21 @@
c1 = c2 = c3 = c4 = -1;
cb1 = cb2 = cb3 = cb4 = 0;
+ // onslaught is special
+ if(g_onslaught)
+ {
+ head = findchain(classname, "onslaught_generator");
+ while (head)
+ {
+ if (head.team == COLOR_TEAM1) c1 = 0;
+ if (head.team == COLOR_TEAM2) c2 = 0;
+ if (head.team == COLOR_TEAM3) c3 = 0;
+ if (head.team == COLOR_TEAM4) c4 = 0;
+ head = head.chain;
+ }
+ return;
+ }
+
if(g_domination)
teament_name = "dom_team";
else if(g_ctf)
More information about the nexuiz-commits
mailing list