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