r2412 - in trunk/data: . models models/keyhunt models/sprites qcsrc/server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Mon Apr 30 10:11:12 EDT 2007
Author: div0
Date: 2007-04-30 10:11:11 -0400 (Mon, 30 Apr 2007)
New Revision: 2412
Added:
trunk/data/models/keyhunt/
trunk/data/models/keyhunt/key.md3
trunk/data/models/keyhunt/key.tga
trunk/data/models/keyhunt/key2.md3
trunk/data/models/keyhunt/key3.md3
trunk/data/models/keyhunt/key_gloss.tga
trunk/data/models/keyhunt/key_glow.tga
trunk/data/models/keyhunt/key_norm.tga
trunk/data/models/sprites/key-dropped.sp2
trunk/data/models/sprites/key-dropped.tga
trunk/data/models/sprites/keycarrier-blue.sp2
trunk/data/models/sprites/keycarrier-blue.tga
trunk/data/models/sprites/keycarrier-finish.sp2
trunk/data/models/sprites/keycarrier-finish.tga
trunk/data/models/sprites/keycarrier-friend.sp2
trunk/data/models/sprites/keycarrier-friend.tga
trunk/data/models/sprites/keycarrier-pink.sp2
trunk/data/models/sprites/keycarrier-pink.tga
trunk/data/models/sprites/keycarrier-red.sp2
trunk/data/models/sprites/keycarrier-red.tga
trunk/data/models/sprites/keycarrier-yellow.sp2
trunk/data/models/sprites/keycarrier-yellow.tga
trunk/data/qcsrc/server/keyhunt.qc
trunk/data/qcsrc/server/keyhunt.qh
Modified:
trunk/data/default.cfg
trunk/data/game_reset.cfg
trunk/data/qcsrc/server/cl_client.qc
trunk/data/qcsrc/server/cl_player.qc
trunk/data/qcsrc/server/clientcommands.qc
trunk/data/qcsrc/server/g_damage.qc
trunk/data/qcsrc/server/g_world.qc
trunk/data/qcsrc/server/havocbot_roles.qc
trunk/data/qcsrc/server/miscfunctions.qc
trunk/data/qcsrc/server/progs.src
trunk/data/qcsrc/server/teamplay.qc
trunk/data/qcsrc/server/waypointsprites.qc
Log:
game mode "keyhunt", still in testing
Modified: trunk/data/default.cfg
===================================================================
--- trunk/data/default.cfg 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/default.cfg 2007-04-30 14:11:11 UTC (rev 2412)
@@ -713,3 +713,21 @@
alias g_maplist_remove "qc_cmd rpn /g_maplist g_maplist /$1 difference def"
alias g_maplist_putfirst "qc_cmd rpn /maps/$1.mapcfg fexists_assert /g_maplist /$1 g_maplist union def"
alias g_maplist_shufflenow "qc_cmd rpn /g_maplist g_maplist shuffle def"
+
+// key hunt
+set g_keyhunt 0
+set g_balance_keyhunt_delay_return 30
+set g_balance_keyhunt_delay_round 5
+set g_balance_keyhunt_delay_tracking 10
+set g_balance_keyhunt_delay_fadeout 2
+set g_balance_keyhunt_delay_collect 1.5
+set g_balance_keyhunt_delay_drop 0.4
+set g_balance_keyhunt_maxdist 150
+set g_balance_keyhunt_score_collect 3
+set g_balance_keyhunt_score_carrierfrag 2
+set g_balance_keyhunt_score_dropkey 0
+set g_balance_keyhunt_score_capture 100
+set g_balance_keyhunt_score_destroyed 50
+set g_balance_keyhunt_score_destroyed_ownfactor 1
+set g_keyhunt_teams_override 0
+set g_keyhunt_teams 0
Modified: trunk/data/game_reset.cfg
===================================================================
--- trunk/data/game_reset.cfg 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/game_reset.cfg 2007-04-30 14:11:11 UTC (rev 2412)
@@ -14,6 +14,7 @@
set g_lms 0
set g_arena 0
set g_campaign 0
+set g_keyhunt 0
set teamplay 0
set gamecfg 0
Added: trunk/data/models/keyhunt/key.md3
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key.md3
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/keyhunt/key.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/keyhunt/key2.md3
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key2.md3
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/keyhunt/key3.md3
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key3.md3
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/keyhunt/key_gloss.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key_gloss.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/keyhunt/key_glow.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key_glow.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/keyhunt/key_norm.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/keyhunt/key_norm.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/key-dropped.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/key-dropped.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/key-dropped.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/key-dropped.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-blue.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-blue.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-blue.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-blue.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-finish.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-finish.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-finish.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-finish.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-friend.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-friend.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-friend.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-friend.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-pink.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-pink.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-pink.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-pink.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-red.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-red.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-red.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-red.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-yellow.sp2
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-yellow.sp2
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/data/models/sprites/keycarrier-yellow.tga
===================================================================
(Binary files differ)
Property changes on: trunk/data/models/sprites/keycarrier-yellow.tga
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: trunk/data/qcsrc/server/cl_client.qc
===================================================================
--- trunk/data/qcsrc/server/cl_client.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/cl_client.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -287,13 +287,14 @@
WriteEntity(MSG_ONE, self);
}
- WaypointSprite_PlayerDead();
-
DropAllRunes(self);
+ kh_Key_DropAll(self);
if(self.flagcarried)
DropFlag(self.flagcarried);
+ WaypointSprite_PlayerDead();
+
DistributeFragsAmongTeam(self, self.team, 1);
if(self.frags <= 0 && self.frags > -666 && cvar("g_lms") && self.killcount != -666)
@@ -831,6 +832,7 @@
WaypointSprite_PlayerGone();
DropAllRunes(self);
+ kh_Key_DropAll(self);
if(self.flagcarried)
DropFlag(self.flagcarried);
@@ -1508,6 +1510,7 @@
minstagib_ammocheck();
ctf_setstatus();
+ kh_setstatus();
//self.angles_y=self.v_angle_y + 90; // temp
Modified: trunk/data/qcsrc/server/cl_player.qc
===================================================================
--- trunk/data/qcsrc/server/cl_player.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/cl_player.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -285,8 +285,6 @@
{
self.deaths += 1;
- // clear waypoints
- WaypointSprite_PlayerDead();
// become fully visible
self.alpha = 1;
// clear selected player display
@@ -296,8 +294,11 @@
// print an obituary message
Obituary (attacker, self, deathtype);
DropAllRunes(self);
+ kh_Key_DropAll(self);
if(self.flagcarried)
DropFlag(self.flagcarried);
+ // clear waypoints
+ WaypointSprite_PlayerDead();
// make the corpse upright (not tilted)
self.angles_x = 0;
self.angles_z = 0;
Modified: trunk/data/qcsrc/server/clientcommands.qc
===================================================================
--- trunk/data/qcsrc/server/clientcommands.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/clientcommands.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -319,6 +319,8 @@
if(self.classname == "player" && cvar("sv_spectate") == 1) {
if(self.flagcarried)
DropFlag(self.flagcarried);
+ kh_Key_DropAll(self);
+ WaypointSprite_PlayerDead();
DistributeFragsAmongTeam(self, self.team, 1.0);
self.classname = "observer";
PutClientInServer();
Modified: trunk/data/qcsrc/server/g_damage.qc
===================================================================
--- trunk/data/qcsrc/server/g_damage.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/g_damage.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -26,6 +26,11 @@
if(f > 0)
f = RunematchHandleFrags(attacker, targ, f);
}
+ else if(cvar("g_keyhunt"))
+ {
+ if(f > 0)
+ f = kh_HandleFrags(attacker, targ, f);
+ }
else if(cvar("g_lms"))
{
// count remaining lives, not frags in lms
Modified: trunk/data/qcsrc/server/g_world.qc
===================================================================
--- trunk/data/qcsrc/server/g_world.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/g_world.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -1559,7 +1559,7 @@
{
if(teams_matter)
{
- if(cvar("g_tdm") || cvar("g_runematch") || cvar("g_ctf") || cvar("g_domination"))
+ if(cvar("g_tdm") || cvar("g_runematch") || cvar("g_ctf") || cvar("g_domination") || cvar("g_keyhunt"))
status = WinningCondition_MaxTeamSum(fraglimit);
//else if()
// status = WinningCondition_MaxTeamMax(fraglimit);
Modified: trunk/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot_roles.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/havocbot_roles.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -508,6 +508,183 @@
self.havocbot_role = havocbot_role_dom;
};
+
+
+
+
+
+void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
+{
+ local entity head;
+ for(head = world; (head = find(head, classname, "item_kh_key")); )
+ {
+ if(head.owner == self)
+ continue;
+ if(!head.owner)
+ navigation_routerating(head, ratingscale_dropped);
+ else if(head.team == self.team)
+ navigation_routerating(head, ratingscale_team);
+ else
+ navigation_routerating(head, ratingscale_enemy);
+ }
+};
+
+void() havocbot_role_kh_carrier;
+void() havocbot_role_kh_defense;
+void() havocbot_role_kh_offense;
+void() havocbot_role_kh_freelancer;
+void() havocbot_role_kh_carrier =
+{
+ local entity head;
+ if (!(self.items & IT_KEY1))
+ {
+ dprint("changing role to freelancer\n");
+ self.havocbot_role = havocbot_role_kh_freelancer;
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (self.bot_strategytime < time)
+ {
+ float enemies_have_keys;
+
+ self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
+ navigation_goalrating_start();
+
+ enemies_have_keys = FALSE;
+ for(head = world; (head = find(head, classname, "item_kh_key")); )
+ {
+ if(head.owner)
+ if(head.team != self.team)
+ {
+ enemies_have_keys = TRUE;
+ break;
+ }
+ }
+
+ if(enemies_have_keys)
+ havocbot_goalrating_kh(4000, 4000, 100);
+ else
+ havocbot_goalrating_kh(10000, 10000, 1);
+ havocbot_goalrating_items(10000, self.origin, 10000);
+ navigation_goalrating_end();
+ }
+}
+
+void() havocbot_role_kh_defense =
+{
+ if (self.items & IT_KEY1)
+ {
+ dprint("changing role to carrier\n");
+ self.havocbot_role = havocbot_role_kh_carrier;
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + random() * 10 + 20;
+ if (time > self.havocbot_role_timeout)
+ {
+ dprint("changing role to freelancer\n");
+ self.havocbot_role = havocbot_role_kh_freelancer;
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (self.bot_strategytime < time)
+ {
+ self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
+ navigation_goalrating_start();
+ havocbot_goalrating_kh(4000, 1000, 1);
+ havocbot_goalrating_items(10000, self.origin, 10000);
+ navigation_goalrating_end();
+ }
+};
+
+void() havocbot_role_kh_offense =
+{
+ if (self.items & IT_KEY1)
+ {
+ dprint("changing role to carrier\n");
+ self.havocbot_role = havocbot_role_kh_carrier;
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + random() * 10 + 20;
+ if (time > self.havocbot_role_timeout)
+ {
+ dprint("changing role to freelancer\n");
+ self.havocbot_role = havocbot_role_kh_freelancer;
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (self.bot_strategytime < time)
+ {
+ self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
+ navigation_goalrating_start();
+ havocbot_goalrating_kh(1, 1000, 4000);
+ havocbot_goalrating_items(10000, self.origin, 10000);
+ navigation_goalrating_end();
+ }
+};
+
+void() havocbot_role_kh_freelancer =
+{
+ if (self.items & IT_KEY1)
+ {
+ dprint("changing role to carrier\n");
+ self.havocbot_role = havocbot_role_kh_carrier;
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + random() * 10 + 10;
+ if (time > self.havocbot_role_timeout)
+ {
+ if (random() < 0.5)
+ {
+ dprint("changing role to offense\n");
+ self.havocbot_role = havocbot_role_kh_offense;
+ }
+ else
+ {
+ dprint("changing role to defense\n");
+ self.havocbot_role = havocbot_role_kh_defense;
+ }
+ self.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (self.bot_strategytime < time)
+ {
+ self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
+ navigation_goalrating_start();
+ havocbot_goalrating_kh(1000, 4000, 1000);
+ havocbot_goalrating_items(10000, self.origin, 10000);
+ navigation_goalrating_end();
+ }
+};
+
+
+
+
+
+void() havocbot_chooserole_kh =
+{
+ local float r;
+ r = random() * 3;
+ if (r < 1)
+ self.havocbot_role = havocbot_role_kh_offense;
+ else if (r < 2)
+ self.havocbot_role = havocbot_role_kh_defense;
+ else
+ self.havocbot_role = havocbot_role_kh_freelancer;
+};
+
void() havocbot_chooserole =
{
dprint("choose a role...\n");
@@ -517,6 +694,8 @@
havocbot_chooserole_ctf();
else if (cvar("g_domination"))
havocbot_chooserole_dom();
+ else if (cvar("g_keyhunt"))
+ havocbot_chooserole_kh();
else // assume anything else is deathmatch
havocbot_chooserole_dm();
};
Added: trunk/data/qcsrc/server/keyhunt.qc
===================================================================
--- trunk/data/qcsrc/server/keyhunt.qc (rev 0)
+++ trunk/data/qcsrc/server/keyhunt.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -0,0 +1,593 @@
+string STR_ITEM_KH_KEY = "item_kh_key";
+#define FOR_EACH_KH_KEY(v) for(v = world; (v = find(v, classname, STR_ITEM_KH_KEY)); )
+
+typedef void(void) kh_Think_t;
+var kh_Think_t kh_Controller_Thinkfunc;
+string kh_Controller_Waitmsg;
+
+float kh_Team_ByID(float t)
+{
+ if(t == 0) return COLOR_TEAM1;
+ if(t == 1) return COLOR_TEAM2;
+ if(t == 2) return COLOR_TEAM3;
+ if(t == 3) return COLOR_TEAM4;
+ return 0;
+}
+
+entity kh_controller;
+float kh_tracking_enabled;
+float kh_teams;
+.entity kh_next, kh_prev; // linked list
+.float kh_droptime;
+
+float kh_sprite_dropped, kh_sprite_finish, kh_sprite_red, kh_sprite_blue, kh_sprite_pink, kh_sprite_yellow, kh_sprite_friend;
+
+float kh_GetCarrierSprite(float t)
+{
+ if(t == COLOR_TEAM1) return kh_sprite_red;
+ if(t == COLOR_TEAM2) return kh_sprite_blue;
+ if(t == COLOR_TEAM3) return kh_sprite_pink;
+ if(t == COLOR_TEAM4) return kh_sprite_yellow;
+ return 0;
+}
+
+void kh_Controller_SetThink(float t, string msg, kh_Think_t func)
+{
+ kh_Controller_Thinkfunc = func;
+ kh_controller.cnt = t;
+ if(kh_Controller_Waitmsg != "")
+ strunzone(kh_Controller_Waitmsg);
+ if(msg == "")
+ kh_Controller_Waitmsg = "";
+ else
+ kh_Controller_Waitmsg = strzone(msg);
+ if(t == 0)
+ kh_controller.nextthink = time; // force
+}
+
+void kh_Controller_Think()
+{
+ entity e;
+ if(self.cnt > 0)
+ {
+ if(kh_Controller_Waitmsg != "")
+ {
+ string s;
+ if(substring(kh_Controller_Waitmsg, strlen(kh_Controller_Waitmsg)-1, 1) == " ")
+ s = strcat(kh_Controller_Waitmsg, ftos(self.cnt));
+ else
+ s = kh_Controller_Waitmsg;
+
+ dprint(s, "\n");
+
+ FOR_EACH_PLAYER(e)
+ if(clienttype(e) == CLIENTTYPE_REAL)
+ centerprint_atprio(e, CENTERPRIO_SPAM, s);
+ }
+ self.cnt -= 1;
+ }
+ else if(self.cnt == 0)
+ {
+ FOR_EACH_PLAYER(e)
+ if(clienttype(e) == CLIENTTYPE_REAL)
+ centerprint_expire(e, CENTERPRIO_SPAM);
+ self.cnt -= 1;
+ kh_Controller_Thinkfunc();
+ }
+ self.nextthink = time + 1;
+}
+
+void kh_Log()
+{
+ string s;
+ if(!cvar("sv_eventlog"))
+ return;
+ // TODO ...
+ GameLogEcho(s, FALSE);
+}
+
+// frags f: take from cvar * f
+// frags 0: no frags
+void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner)
+{
+ float basefrags;
+ basefrags = cvar(strcat("g_balance_keyhunt_score_", what));
+
+ if(frags_player)
+ player.frags = player.frags + floor(0.5 + basefrags * frags_player);
+ if(frags_owner)
+ key.owner.frags = key.owner.frags + floor(0.5 + basefrags * frags_owner);
+}
+
+void kh_Key_Attach(entity key, float wpchange)
+{
+ setattachment(key, key.owner, "");
+ setorigin(key, '0 0 0'); // fixed later in think
+ key.angles = '0 0 0';
+ key.flags = 0;
+ key.solid = SOLID_NOT;
+ key.movetype = MOVETYPE_NONE;
+ key.team = key.owner.team;
+ key.nextthink = time;
+}
+
+void kh_Key_Detach(entity key, float wpchange)
+{
+ setattachment(key, world, "");
+ makevectors(key.owner.angles);
+ setorigin(key, key.owner.origin + key.origin_x * v_forward - key.origin_y * v_right + key.origin_z * v_up);
+ key.angles_y = key.owner.angles_y;
+ key.aiment = world;
+ key.flags = FL_ITEM;
+ key.solid = SOLID_TRIGGER;
+ key.movetype = MOVETYPE_TOSS;
+ key.pain_finished = time + cvar("g_balance_keyhunt_delay_return");
+ // let key.team stay
+}
+
+void kh_Key_AssignTo(entity key, entity player, float wpchange)
+{
+ if(key.owner == player)
+ return;
+
+ if(key.owner)
+ {
+ kh_Key_Detach(key, wpchange);
+
+ // remove from linked list
+ if(key.kh_next)
+ key.kh_next.kh_prev = key.kh_prev;
+ key.kh_prev.kh_next = key.kh_next;
+ key.kh_next = world;
+ key.kh_prev = world;
+
+ if(key.owner.kh_next == world)
+ {
+ // No longer a key carrier
+ if(wpchange)
+ WaypointSprite_Kill(key.owner.waypointsprite_attachedforcarrier);
+ else
+ WaypointSprite_DetachCarrier(key.owner);
+ }
+ }
+
+ key.owner = player;
+
+ if(player)
+ {
+ // insert into linked list
+ key.kh_next = player.kh_next;
+ key.kh_prev = player;
+ player.kh_next = key;
+ if(key.kh_next)
+ key.kh_next.kh_prev = key;
+
+ kh_Key_Attach(key, wpchange);
+
+ if(key.kh_next == world)
+ {
+ // player is now a key carrier
+ WaypointSprite_AttachCarrier("", player);
+ player.waypointsprite_attachedforcarrier.waypointsprite_for_player = kh_KeyCarrier_waypointsprite_for_player;
+ player.waypointsprite_attachedforcarrier.team = player.team;
+ }
+ }
+
+ key.pusher = world;
+}
+
+void kh_Key_Spawn(entity initial_owner, float angle)
+{
+ entity key;
+ key = spawn();
+ key.classname = STR_ITEM_KH_KEY;
+ key.touch = kh_Key_Touch;
+ key.think = kh_Key_Think;
+ key.nextthink = time;
+ key.items = IT_KEY1 | IT_KEY2;
+ key.cnt = angle;
+ setmodel(key, "models/keyhunt/key3.md3");
+ setsize(key, '0 0 -24', '0 0 25');
+
+ switch(initial_owner.team)
+ {
+ case COLOR_TEAM1:
+ key.netname = "^1red key";
+ key.colormod = '1.73 0.10 0.10';
+ break;
+ case COLOR_TEAM2:
+ key.netname = "^4blue key";
+ key.colormod = '0.10 0.10 1.73';
+ break;
+ case COLOR_TEAM3:
+ key.netname = "^6pink key";
+ key.colormod = '1.22 0.10 1.22';
+ break;
+ case COLOR_TEAM4:
+ key.netname = "^3yellow key";
+ key.colormod = '1.22 1.22 0.10';
+ break;
+ default:
+ key.netname = "NETGIER key";
+ key.colormod = '1.00 1.00 1.00';
+ break;
+ }
+
+ sprint(initial_owner, strcat("You got the ^2", key.netname, "\n"));
+
+ WaypointSprite_AttachCarrier("", key);
+ key.waypointsprite_attachedforcarrier.waypointsprite_for_player = kh_Key_waypointsprite_for_player;
+
+ kh_Key_AssignTo(key, initial_owner, TRUE);
+}
+
+void kh_Key_Remove(entity key)
+{
+ entity o;
+ o = key.owner;
+ kh_Key_AssignTo(key, world, FALSE);
+ if(o) // it was attached
+ WaypointSprite_Kill(key.waypointsprite_attachedforcarrier);
+ else // it was dropped
+ WaypointSprite_DetachCarrier(key);
+
+ remove(key);
+}
+
+void kh_Key_Collect(entity key, entity player)
+{
+ entity head;
+
+ kh_Scores_Event(player, key, "collect", 1, 0);
+ bprint(player.netname, "^7 collected the ", key.netname, "\n");
+ kh_Key_AssignTo(key, player, TRUE);
+
+ FOR_EACH_KH_KEY(key)
+ if(!key.owner || key.team != player.team)
+ goto notallowned;
+ FOR_EACH_PLAYER(head)
+ {
+ if(head.team == player.team)
+ if(head.kh_next)
+ centerprint(head, "All keys are in your team's hands!\n\nMeet the other key carriers ^1NOW^7!\n");
+ else
+ centerprint(head, "All keys are in your team's hands!\n\nHelp the key carriers to meet!\n");
+ else
+ centerprint(head, "All keys are in the enemy's hands!\n\nInterfere ^1NOW^7!\n");
+ }
+:notallowned
+}
+
+void kh_Key_DropAll(entity player)
+{
+ entity key;
+ entity mypusher;
+ mypusher = world;
+ if(player.pusher)
+ if(time < player.pushltime)
+ mypusher = player.pusher;
+ while((key = player.kh_next))
+ {
+ kh_Scores_Event(player, key, "losekey", 0, 0);
+ bprint(player.netname, "^7 lost the ", key.netname, "\n");
+ kh_Key_AssignTo(key, world, TRUE);
+ key.pusher = player.pusher;
+ key.pushltime = player.pushltime;
+ }
+}
+
+void kh_Key_Touch()
+{
+ if(self.owner) // already carried
+ return;
+ if(other.classname != "player")
+ return;
+ if(other.deadflag != DEAD_NO)
+ return;
+ if(other == self.enemy)
+ if(time < self.kh_droptime + cvar("g_balance_keyhunt_delay_collect"))
+ return; // you just dropped it!
+ kh_Key_Collect(self, other);
+}
+
+void kh_Key_Think()
+{
+ if(self.owner)
+ {
+ makevectors('0 1 0' * (self.cnt + math_mod(time, 360) * 45));
+ setorigin(self, v_forward * 16);
+
+ if(self.owner.buttonuse)
+ if(time >= self.owner.kh_droptime + cvar("g_balance_keyhunt_delay_drop"))
+ {
+ self.owner.kh_droptime = time;
+ self.kh_droptime = time; // prevent collecting this one for some time
+ self.enemy = self.owner;
+ self.pusher = world;
+ kh_Scores_Event(self.owner, self, "dropkey", 0, 0);
+ bprint(self.owner.netname, "^7 dropped the ", self.netname, "\n");
+ kh_Key_AssignTo(self, world, TRUE);
+ }
+ }
+
+ // if in nodrop or time over, end the round
+ if(!self.owner)
+ if(time > self.pain_finished)
+ kh_LoserTeam(self.team, self);
+
+ if(self.owner)
+ {
+ entity key;
+ vector p;
+ float teem;
+ teem = self.team;
+ p = self.owner.origin;
+ FOR_EACH_KH_KEY(key)
+ {
+ if(key.owner == self.owner)
+ continue;
+ if(key.owner)
+ if(key.team == teem)
+ if(vlen(key.owner.origin - p) < cvar("g_balance_keyhunt_maxdist"))
+ continue;
+ goto not_winning;
+ }
+ kh_WinnerTeam(teem);
+:not_winning
+ }
+
+ self.nextthink = time + 0.1;
+}
+
+void kh_WinnerTeam(float teem)
+{
+ // all key carriers get some points
+ entity key;
+ float first;
+ float score;
+ score = 1.0 / kh_teams;
+ first = TRUE;
+ FOR_EACH_KH_KEY(key)
+ {
+ kh_Scores_Event(key.owner, key, "capture", score, 0);
+ if(key.owner.kh_next == key)
+ {
+ if(!first)
+ bprint("^7, ");
+ bprint(key.owner.netname);
+ first = FALSE;
+ }
+ }
+ bprint("^7 captured the keys for the ", ColoredTeamName(teem), "\n");
+ kh_FinishRound();
+}
+
+void kh_LoserTeam(float teem, entity lostkey)
+{
+ entity player, key, attacker;
+ float players;
+ float keys;
+ float score;
+
+ attacker = world;
+ if(lostkey.pusher)
+ if(player.pusher.team != player.team)
+ if(player.pusher.classname == "player")
+ attacker = lostkey.pusher;
+
+ players = keys = 0;
+
+ if(attacker)
+ {
+ kh_Scores_Event(attacker, world, "push", 1, 0);
+ centerprint(attacker, "Your push is the best!\n\n\n");
+ bprint("The ", ColoredTeamName(teem), "^7 could not take care of the ", lostkey.netname, "\n");
+ }
+ else
+ {
+ FOR_EACH_PLAYER(player)
+ if(player.team != teem)
+ ++players;
+
+ FOR_EACH_KH_KEY(key)
+ if(key.owner && key.team != teem)
+ ++keys;
+
+ score = 1.0 / (keys * cvar("g_balance_keyhunt_score_destroyed_ownfactor") + players);
+
+ FOR_EACH_PLAYER(player)
+ if(player.team != teem)
+ kh_Scores_Event(player, world, "destroyed", score, 0);
+
+ FOR_EACH_KH_KEY(key)
+ if(key.owner && key.team != teem)
+ kh_Scores_Event(key.owner, world, "destroyed", score * cvar("g_balance_keyhunt_score_destroyed_ownfactor"), 0);
+
+ bprint("The ", ColoredTeamName(teem), "^7 could not take care of the ", lostkey.netname, "\n");
+ }
+
+ kh_FinishRound();
+}
+
+void kh_FinishRound()
+{
+ // prepare next round
+ entity key;
+ FOR_EACH_KH_KEY(key)
+ kh_Key_Remove(key);
+
+ kh_Controller_SetThink(cvar("g_balance_keyhunt_delay_round"), "Round starts in ", kh_StartRound);
+}
+
+float kh_EnoughPlayers()
+{
+ float i, players, teem;
+ entity player;
+
+ // find a random player per team
+ for(i = 0; i < kh_teams; ++i)
+ {
+ teem = kh_Team_ByID(i);
+ players = 0;
+ FOR_EACH_PLAYER(player)
+ if(player.deadflag == DEAD_NO)
+ if(player.team == teem)
+ ++players;
+ if(players == 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void kh_WaitForPlayers()
+{
+ if(kh_EnoughPlayers())
+ kh_Controller_SetThink(cvar("g_balance_keyhunt_delay_round"), "Round starts in ", kh_StartRound);
+ else
+ kh_Controller_SetThink(1, "Waiting for players to join...", kh_WaitForPlayers);
+}
+
+void kh_StartRound()
+{
+ float i, players, teem;
+ entity player;
+
+ if(!kh_EnoughPlayers())
+ {
+ kh_Controller_SetThink(1, "Waiting for players to join...", kh_WaitForPlayers);
+ return;
+ }
+
+ for(i = 0; i < kh_teams; ++i)
+ {
+ teem = kh_Team_ByID(i);
+ players = 0;
+ entity my_player;
+ FOR_EACH_PLAYER(player)
+ if(player.deadflag == DEAD_NO)
+ if(player.team == teem)
+ {
+ ++players;
+ if(random() * players <= 1)
+ my_player = player;
+ }
+ kh_Key_Spawn(my_player, 360 * i / kh_teams);
+ }
+
+ kh_tracking_enabled = FALSE;
+ kh_Controller_SetThink(cvar("g_balance_keyhunt_delay_tracking"), "Scanning frequency range...", kh_EnableTrackingDevice);
+}
+
+void kh_setstatus()
+{
+ if(kh_teams)
+ {
+ float kh_KEY;
+ kh_KEY = (IT_RED_FLAG_TAKEN | IT_RED_FLAG_LOST | IT_BLUE_FLAG_TAKEN | IT_BLUE_FLAG_LOST); // the one impossible combination
+ if(self.kh_next)
+ self.items = self.items | kh_KEY;
+ else
+ self.items = self.items - (self.items & kh_KEY);
+ }
+}
+
+void kh_EnableTrackingDevice()
+{
+ kh_tracking_enabled = TRUE;
+}
+
+float kh_Key_waypointsprite_for_player(entity e)
+{
+ if(!kh_tracking_enabled)
+ return 0;
+ if(!self.owner)
+ return kh_sprite_dropped;
+ if(!self.owner.owner)
+ return kh_sprite_dropped;
+ return 0; // draw only when key is not owned
+}
+
+float kh_KeyCarrier_waypointsprite_for_player(entity e)
+{
+ entity key;
+
+ if(e.classname != "player" || self.team != e.team)
+ if(!kh_tracking_enabled)
+ return 0;
+
+ FOR_EACH_KH_KEY(key)
+ if(!key.owner || key.team != e.team)
+ {
+ if(self.team == e.team)
+ return kh_sprite_friend;
+ else
+ return kh_GetCarrierSprite(self.team);
+ }
+
+ return kh_sprite_finish;
+}
+
+float kh_HandleFrags(entity attacker, entity targ, float f)
+{
+ float newfrags;
+
+ if(f <= 0)
+ return f;
+ if(attacker == targ)
+ return f;
+
+ if(targ.kh_next)
+ f = f - 1 + cvar("g_balance_keyhunt_score_carrierfrag");
+
+ if(newfrags)
+ f = f - 1 + newfrags;
+ return f;
+}
+
+void kh_init()
+{
+ precache_model("models/sprites/key-dropped.sp2");
+ precache_model("models/sprites/keycarrier-finish.sp2");
+ precache_model("models/sprites/keycarrier-friend.sp2");
+ precache_model("models/sprites/keycarrier-red.sp2");
+ precache_model("models/sprites/keycarrier-blue.sp2");
+ precache_model("models/sprites/keycarrier-pink.sp2");
+ precache_model("models/sprites/keycarrier-yellow.sp2");
+ precache_model("models/keyhunt/key3.md3");
+
+ // setup variables
+ kh_teams = cvar("g_keyhunt_teams_override");
+ if(kh_teams < 2)
+ kh_teams = cvar("g_keyhunt_teams");
+ if(kh_teams < 2)
+ kh_teams = 2;
+
+ // make a KH entity for controlling the game
+ kh_controller = spawn();
+ kh_controller.think = kh_Controller_Think;
+ kh_Controller_SetThink(0, "", kh_WaitForPlayers);
+
+ setmodel(kh_controller, "models/sprites/key-dropped.sp2");
+ kh_sprite_dropped = kh_controller.modelindex;
+ setmodel(kh_controller, "models/sprites/keycarrier-finish.sp2");
+ kh_sprite_finish = kh_controller.modelindex;
+ setmodel(kh_controller, "models/sprites/keycarrier-friend.sp2");
+ kh_sprite_friend = kh_controller.modelindex;
+ setmodel(kh_controller, "models/sprites/keycarrier-red.sp2");
+ kh_sprite_red = kh_controller.modelindex;
+ setmodel(kh_controller, "models/sprites/keycarrier-blue.sp2");
+ kh_sprite_blue = kh_controller.modelindex;
+ setmodel(kh_controller, "models/sprites/keycarrier-pink.sp2");
+ kh_sprite_pink = kh_controller.modelindex;
+ setmodel(kh_controller, "models/sprites/keycarrier-yellow.sp2");
+ kh_sprite_yellow = kh_controller.modelindex;
+ setmodel(kh_controller, "");
+}
+
+void kh_finalize()
+{
+ // to be called before intermission
+ kh_FinishRound();
+ remove(kh_controller);
+ kh_controller = world;
+}
Added: trunk/data/qcsrc/server/keyhunt.qh
===================================================================
--- trunk/data/qcsrc/server/keyhunt.qh (rev 0)
+++ trunk/data/qcsrc/server/keyhunt.qh 2007-04-30 14:11:11 UTC (rev 2412)
@@ -0,0 +1,24 @@
+float kh_teams;
+
+void kh_Log();
+void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner);
+void kh_Key_Attach(entity key, float wpchange);
+void kh_Key_Detach(entity key, float wpchange);
+void kh_Key_AssignTo(entity key, entity player, float wpchange);
+void kh_Key_Spawn(entity initial_owner, float angle);
+void kh_Key_Remove(entity key);
+void kh_Key_Collect(entity key, entity player);
+void kh_Key_DropAll(entity player);
+void kh_Key_Touch();
+void kh_Key_Think();
+void kh_WinnerTeam(float teem);
+void kh_LoserTeam(float teem, entity lostkey);
+void kh_FinishRound();
+void kh_StartRound();
+void kh_EnableTrackingDevice();
+void kh_init();
+void kh_finalize();
+float kh_KeyCarrier_waypointsprite_for_player(entity e);
+float kh_Key_waypointsprite_for_player(entity e);
+void kh_setstatus();
+float kh_HandleFrags(entity attacker, entity targ, float f);
Modified: trunk/data/qcsrc/server/miscfunctions.qc
===================================================================
--- trunk/data/qcsrc/server/miscfunctions.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/miscfunctions.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -610,6 +610,7 @@
*/
#define CENTERPRIO_POINT 1
+#define CENTERPRIO_SPAM 2
#define CENTERPRIO_REBALANCE 2
#define CENTERPRIO_VOTE 4
#define CENTERPRIO_NORMAL 5
Modified: trunk/data/qcsrc/server/progs.src
===================================================================
--- trunk/data/qcsrc/server/progs.src 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/progs.src 2007-04-30 14:11:11 UTC (rev 2412)
@@ -12,6 +12,8 @@
../common/util.qh
../common/util.qc
+keyhunt.qh
+
miscfunctions.qc
waypointsprites.qc
@@ -84,3 +86,5 @@
../common/gamecommand.qc
gamecommand.qc
+
+keyhunt.qc
Modified: trunk/data/qcsrc/server/teamplay.qc
===================================================================
--- trunk/data/qcsrc/server/teamplay.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/teamplay.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -5,13 +5,14 @@
float GAME_RUNEMATCH = 5;
float GAME_LMS = 6;
float GAME_ARENA = 7;
+float GAME_KEYHUNT = 8;
// 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;
+float g_domination, g_ctf, g_tdm, g_keyhunt;
float audit_teams_time;
@@ -101,6 +102,7 @@
cvar_set("g_runematch", "0");
cvar_set("g_lms", "0");
cvar_set("g_arena", "0");
+ cvar_set("g_keyhunt", "0");
cvar_set("teamplay", "0");
}
@@ -224,6 +226,16 @@
gamemode_name = "Arena";
teams_matter = 0;
}
+ else if(game == GAME_KEYHUNT || cvar("g_keyhunt"))
+ {
+ ResetGameCvars();
+ game = GAME_KEYHUNT;
+ cvar_set("g_keyhunt", "1");
+ fraglimit_override = cvar("g_keyhunt_point_limit");
+ ActivateTeamplay();
+ gamemode_name = "Key Hunt";
+ teams_matter = 1;
+ }
else
{
// we can only assume...
@@ -260,6 +272,8 @@
runematch_init();
else if (game == GAME_TEAM_DEATHMATCH)//cvar("g_runematch"))
tdm_init();
+ else if (game == GAME_KEYHUNT)//cvar("g_keyhunt"))
+ kh_init();
// those mutators rule each other out
if(cvar("g_minstagib"))
@@ -286,6 +300,7 @@
g_domination = cvar("g_domination");
g_ctf = cvar("g_ctf");
g_tdm = cvar("g_tdm");
+ g_keyhunt = cvar("g_keyhunt");
}
string GetClientVersionMessage(float v) {
@@ -503,7 +518,10 @@
else
{
// cover anything else by treating it like tdm with no teams spawned
- dm = cvar("g_tdm_teams");
+ if(g_keyhunt)
+ dm = kh_teams;
+ else
+ dm = cvar("g_tdm_teams");
if(dm < 2)
error("g_tdm_teams < 2, not enough teams to play team deathmatch\n");
@@ -634,6 +652,8 @@
error("Too few teams available for domination\n");
else if(g_ctf)
error("Too few teams available for ctf\n");
+ else if(g_keyhunt)
+ error("Too few teams available for key hunt\n");
else
error("Too few teams available for team deathmatch\n");
}
@@ -719,7 +739,7 @@
float smallest, selectedteam;
// don't join a team if we're not playing a team game
- if(!cvar("teamplay") && !g_domination && !g_ctf)
+ if(!cvar("teamplay") && !g_domination && !g_ctf && !g_keyhunt)
return 0;
// find out what teams are available
Modified: trunk/data/qcsrc/server/waypointsprites.qc
===================================================================
--- trunk/data/qcsrc/server/waypointsprites.qc 2007-04-30 14:04:11 UTC (rev 2411)
+++ trunk/data/qcsrc/server/waypointsprites.qc 2007-04-30 14:11:11 UTC (rev 2412)
@@ -9,7 +9,32 @@
float waypointsprite_limitedrange;
..entity owned_by_field;
+.float(entity) waypointsprite_for_player; // returns a model index or 0 for hide
+float waypointsprite_for_player_default(entity e)
+{
+ // personal waypoints
+ if(self.enemy)
+ if(self.enemy != other)
+ return FALSE;
+ // team waypoints
+ if(self.team)
+ {
+ if(self.team != other.team)
+ return FALSE;
+ if(other.classname != "player")
+ return FALSE;
+ }
+
+ // fixed waypoints
+ if(self.currentammo) // hidable?
+ if(other.cvar_cl_hidewaypoints) // wants to hide;
+ return FALSE;
+
+ // otherwise, accept the model
+ return self.modelindex;
+}
+
void WaypointSprite_Init()
{
waypointsprite_fadedistance = vlen(world.maxs - world.mins);
@@ -104,6 +129,7 @@
vector realorigin, porigin;
float distancealpha, timealpha;
float distance;
+ float newmodel;
if(self.health)
{
@@ -115,21 +141,12 @@
else
timealpha = 1;
- if(self.enemy)
- if(self.enemy != other)
- return FALSE;
- if(self.team)
- {
- if(self.team != other.team)
- return FALSE;
- if(other.classname != "player")
- return FALSE;
- }
+ // customize WP
+ newmodel = self.waypointsprite_for_player(other);
+ if(newmodel == 0)
+ return FALSE;
+ self.modelindex = newmodel;
- if(self.currentammo) // hidable?
- if(other.cvar_cl_hidewaypoints) // wants to hide;
- return FALSE;
-
porigin = other.origin + other.view_ofs_z * '0 0 1';
#ifdef ATTACHMENT_WORKS_WITH_EF_NODEPTHTEST
@@ -228,7 +245,12 @@
wp.think = WaypointSprite_Think;
wp.nextthink = time;
wp.effects = EF_NODEPTHTEST | EF_LOWPRECISION;
- setmodel(wp, strcat("models/sprites/", spr, ".sp2")); // precision set above
+ if(spr != "")
+ setmodel(wp, strcat("models/sprites/", spr, ".sp2")); // precision set above
+ else
+ wp.model = "waypoint";
+ setsize(wp, '0 0 0', '0 0 0');
+ wp.waypointsprite_for_player = waypointsprite_for_player_default;
return wp;
}
More information about the nexuiz-commits
mailing list