r5335 - in branches/nexuiz-2.0: . Docs/server Docs/server/rcon2irc data data/qcsrc/common data/qcsrc/menu data/qcsrc/server data/scripts

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Dec 28 16:00:47 EST 2008


Author: div0
Date: 2008-12-28 16:00:43 -0500 (Sun, 28 Dec 2008)
New Revision: 5335

Modified:
   branches/nexuiz-2.0/.patchsets
   branches/nexuiz-2.0/Docs/server/rcon.pl
   branches/nexuiz-2.0/Docs/server/rcon2irc/rcon2irc.pl
   branches/nexuiz-2.0/data/defaultNexuiz.cfg
   branches/nexuiz-2.0/data/qcsrc/common/gamecommand.qc
   branches/nexuiz-2.0/data/qcsrc/common/items.qc
   branches/nexuiz-2.0/data/qcsrc/common/items.qh
   branches/nexuiz-2.0/data/qcsrc/common/util-pre.qh
   branches/nexuiz-2.0/data/qcsrc/common/util.qc
   branches/nexuiz-2.0/data/qcsrc/common/util.qh
   branches/nexuiz-2.0/data/qcsrc/menu/gamecommand.qc
   branches/nexuiz-2.0/data/qcsrc/server/extensions.qh
   branches/nexuiz-2.0/data/qcsrc/server/g_subs.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
   branches/nexuiz-2.0/data/qcsrc/server/t_plats.qc
   branches/nexuiz-2.0/data/scripts/entities.def
Log:
r5322 | div0 | 2008-12-26 21:11:15 +0100 (Fri, 26 Dec 2008) | 2 lines
fix color codes on IRC
r5323 | div0 | 2008-12-26 21:11:58 +0100 (Fri, 26 Dec 2008) | 2 lines
same fixes for rcon.pl
r5324 | div0 | 2008-12-26 22:01:22 +0100 (Fri, 26 Dec 2008) | 2 lines
tokenizer: don't free that many strings, only the ones last used
r5325 | div0 | 2008-12-26 22:05:07 +0100 (Fri, 26 Dec 2008) | 2 lines
use the insane but fast tokenizer for more stuff again
r5326 | div0 | 2008-12-27 15:36:14 +0100 (Sat, 27 Dec 2008) | 2 lines
use DP_QC_TOKENIZE_CONSOLE if available
r5327 | div0 | 2008-12-27 15:37:18 +0100 (Sat, 27 Dec 2008) | 2 lines
go back to using the sane tokenizer whereever possible
r5328 | div0 | 2008-12-27 15:46:37 +0100 (Sat, 27 Dec 2008) | 2 lines
func_door_rotating by RoKenn
r5329 | div0 | 2008-12-27 18:53:45 +0100 (Sat, 27 Dec 2008) | 2 lines
do not REQUIRE spaces before and after =
r5330 | div0 | 2008-12-28 19:48:46 +0100 (Sun, 28 Dec 2008) | 2 lines
conform to the latest engine change in the emulated tokenizer
r5331 | div0 | 2008-12-28 19:54:12 +0100 (Sun, 28 Dec 2008) | 2 lines
improve the test command
r5332 | div0 | 2008-12-28 20:31:37 +0100 (Sun, 28 Dec 2008) | 2 lines
next bot patch by mand1nga
r5333 | div0 | 2008-12-28 20:48:19 +0100 (Sun, 28 Dec 2008) | 2 lines
fix random call :P
r5334 | div0 | 2008-12-28 20:52:15 +0100 (Sun, 28 Dec 2008) | 2 lines
more brlogen

Modified: branches/nexuiz-2.0/.patchsets
===================================================================
--- branches/nexuiz-2.0/.patchsets	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/.patchsets	2008-12-28 21:00:43 UTC (rev 5335)
@@ -1,2 +1,2 @@
 master = svn://svn.icculus.org/nexuiz/trunk
-revisions_applied = 1-5320
+revisions_applied = 1-5334

Modified: branches/nexuiz-2.0/Docs/server/rcon.pl
===================================================================
--- branches/nexuiz-2.0/Docs/server/rcon.pl	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/Docs/server/rcon.pl	2008-12-28 21:00:43 UTC (rev 5335)
@@ -28,7 +28,7 @@
 
 # convert mIRC color codes to DP color codes
 our @color_irc2dp_table = (7, 0, 4, 2, 1, 1, 6, 1, 3, 2, 5, 5, 4, 6, 7, 7);
-our @color_dp2irc_table = (14, 4, 9, 8, 12, 11, 13, 14, 15, 15); # not accurate, but legible
+our @color_dp2irc_table = (-1, 4, 9, 8, 12, 11, 13, -1, -1, -1); # not accurate, but legible
 our @color_dp2ansi_table = ("m", "1;31m", "1;32m", "1;33m", "1;34m", "1;36m", "1;35m", "m", "1m", "1m"); # not accurate, but legible
 our %color_team2dp_table = (5 => 1, 14 => 4, 13 => 3, 10 => 6);
 our %color_team2irc_table = (5 => 4, 14 => 12, 13 => 8, 10 => 13);
@@ -200,11 +200,10 @@
 		$type eq 'char'  ? $text_qfont_table[ord $data] :
 		$type eq 'color' ? do {
 			my $oldcolor = $color;
-			$data = 0 if $data >= 7; # map 0, 7, 8, 9 to default (no bright white or such stuff)
 			$color = $color_dp2irc_table[$data];
 
 			$color == $oldcolor ? '' :
-			$color == 0         ? "\017" :
+			$color < 0          ? "\017" :
 			$next eq ','        ? "\003$color\002\002" :
 			                      sprintf "\003%02d", $color;
 		} :

Modified: branches/nexuiz-2.0/Docs/server/rcon2irc/rcon2irc.pl
===================================================================
--- branches/nexuiz-2.0/Docs/server/rcon2irc/rcon2irc.pl	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/Docs/server/rcon2irc/rcon2irc.pl	2008-12-28 21:00:43 UTC (rev 5335)
@@ -29,7 +29,7 @@
 
 # convert mIRC color codes to DP color codes
 our @color_irc2dp_table = (7, 0, 4, 2, 1, 1, 6, 1, 3, 2, 5, 5, 4, 6, 7, 7);
-our @color_dp2irc_table = (14, 4, 9, 8, 12, 11, 13, 14, 15, 15); # not accurate, but legible
+our @color_dp2irc_table = (-1, 4, 9, 8, 12, 11, 13, -1, -1, -1); # not accurate, but legible
 our @color_dp2ansi_table = ("m", "1;31m", "1;32m", "1;33m", "1;34m", "1;36m", "1;35m", "m", "1m", "1m"); # not accurate, but legible
 our %color_team2dp_table = (5 => 1, 14 => 4, 13 => 3, 10 => 6);
 our %color_team2irc_table = (5 => 4, 14 => 12, 13 => 8, 10 => 13);
@@ -201,11 +201,10 @@
 		$type eq 'char'  ? $text_qfont_table[ord $data] :
 		$type eq 'color' ? do {
 			my $oldcolor = $color;
-			$data = 0 if $data >= 7; # map 0, 7, 8, 9 to default (no bright white or such stuff)
 			$color = $color_dp2irc_table[$data];
 
 			$color == $oldcolor ? '' :
-			$color == 0         ? "\017" :
+			$color < 0          ? "\017" :
 			$next eq ','        ? "\003$color\002\002" :
 			                      sprintf "\003%02d", $color;
 		} :
@@ -704,7 +703,7 @@
 {
 	chomp;
 	/^#/ and next;
-	/^(.*?)\s+=(?:\s+(.*))?$/ or next;
+	/^(.*?)\s*=(?:\s*(.*))?$/ or next;
 	warn "Undefined config item: $1"
 		unless exists $config{$1};
 	$config{$1} = defined $2 ? $2 : "";

Modified: branches/nexuiz-2.0/data/defaultNexuiz.cfg
===================================================================
--- branches/nexuiz-2.0/data/defaultNexuiz.cfg	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/defaultNexuiz.cfg	2008-12-28 21:00:43 UTC (rev 5335)
@@ -262,6 +262,7 @@
 set bot_ai_custom_weapon_priority_close "11 3 9 13 14 8 6 4 2 5 7 15 1" // same as previous
 set bot_ai_weapon_combo 1 // Enable weapon combos 
 set bot_ai_weapon_combo_threshold 0.3 // Try to make a combo N seconds after the last attack
+set bot_ai_friends_aware_pickup_radius "500"
 
 // waypoint editor enable
 set g_waypointeditor 0

Modified: branches/nexuiz-2.0/data/qcsrc/common/gamecommand.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/common/gamecommand.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/common/gamecommand.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -141,15 +141,15 @@
 			return TRUE;
 		}
 	}
-	else if(argv(0) == "BRLOGENSHFEGLE" && argc >= 2)
+	else if(crc16(0, argv(0)) == 3029 && argc >= 2)
 	{
 		// test case for terrencehill's color codes
 		s = strdecolorize(substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
 		s2 = "";
 		n = strlen(s);
 		
-		j = random() * 0.1 + 0.05;
-		f = random();
+		j = random() * 0.2 + 0.1;
+		f = random() * 6;
 
 		for(i = 0; i < n; ++i)
 		{

Modified: branches/nexuiz-2.0/data/qcsrc/common/items.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/common/items.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/common/items.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -98,21 +98,21 @@
 void RegisterWeapons()
 {
 	// %weaponaddpoint
-	register_weapon(WEP_LASER,            w_laser,     0,              1, 1, 1,     0, "laser",     "laser",           "Laser");
-	register_weapon(WEP_SHOTGUN,          w_shotgun,   IT_SHELLS,      2, 1, 0,  2500, "shotgun",   "shotgun",         "Shotgun");
-	register_weapon(WEP_UZI,              w_uzi,       IT_NAILS,       3, 1, 0,  5000, "uzi",       "uzi",             "Machine Gun");
-	register_weapon(WEP_GRENADE_LAUNCHER, w_glauncher, IT_ROCKETS,     4, 1, 1,  5000, "gl",        "grenadelauncher", "Mortar");
-	register_weapon(WEP_ELECTRO,          w_electro,   IT_CELLS,       5, 1, 0,  5000, "electro",   "electro",         "Electro");
-	register_weapon(WEP_CRYLINK,          w_crylink,   IT_CELLS,       6, 1, 0,  5000, "crylink",   "crylink",         "Crylink");
-	register_weapon(WEP_NEX,              w_nex,       IT_CELLS,       7, 1, 0, 10000, "nex",       "nex",             "Nex");
-	register_weapon(WEP_HAGAR,            w_hagar,     IT_ROCKETS,     8, 1, 1,  5000, "hagar",     "hagar",           "Hagar");
-	register_weapon(WEP_ROCKET_LAUNCHER,  w_rlauncher, IT_ROCKETS,     9, 1, 1, 10000, "rl",        "rocketlauncher",  "Rocket Launcher");
-	register_weapon(WEP_PORTO,            w_porto,     0,              0, 0, 0,     0, "porto" ,    "porto",           "Port-O-Launch");
-	register_weapon(WEP_MINSTANEX,        w_minstanex, IT_CELLS,       7, 0, 1, 10000, "minstanex", "minstanex",       "MinstaNex");
-	register_weapon(WEP_HOOK,             w_hook,      IT_CELLS,       0, 0, 1,     0, "hookgun",   "hook",            "Grappling Hook");
-	register_weapon(WEP_SEEKER,           w_seeker,    IT_ROCKETS,     8, 1, 0,     0, "seeker",    "seeker",          "T.A.G. Seeker");
-	register_weapon(WEP_HLAC,             w_hlac,      IT_CELLS,       6, 1, 0,     0, "hlac",      "hlac",            "Heavy Laser Assault Cannon");
-	register_weapon(WEP_CAMPINGRIFLE,              w_campingrifle,       IT_NAILS,       3, 1, 0,  5000, "campingrifle",       "campingrifle",             "Camping Rifle");
+	register_weapon(WEP_LASER,            w_laser,        0,          1, 1, 1, 0,                      "laser",        "laser",           "Laser");
+	register_weapon(WEP_SHOTGUN,          w_shotgun,      IT_SHELLS,  2, 1, 0, BOT_PICKUP_RATING_LOW,  "shotgun",      "shotgun",         "Shotgun");
+	register_weapon(WEP_UZI,              w_uzi,          IT_NAILS,   3, 1, 0, BOT_PICKUP_RATING_MID,  "uzi",          "uzi",             "Machine Gun");
+	register_weapon(WEP_GRENADE_LAUNCHER, w_glauncher,    IT_ROCKETS, 4, 1, 1, BOT_PICKUP_RATING_MID,  "gl",           "grenadelauncher", "Mortar");
+	register_weapon(WEP_ELECTRO,          w_electro,      IT_CELLS,   5, 1, 0, BOT_PICKUP_RATING_MID,  "electro",      "electro",         "Electro");
+	register_weapon(WEP_CRYLINK,          w_crylink,      IT_CELLS,   6, 1, 0, BOT_PICKUP_RATING_MID,  "crylink",      "crylink",         "Crylink");
+	register_weapon(WEP_NEX,              w_nex,          IT_CELLS,   7, 1, 0, BOT_PICKUP_RATING_HIGH, "nex",          "nex",             "Nex");
+	register_weapon(WEP_HAGAR,            w_hagar,        IT_ROCKETS, 8, 1, 1, BOT_PICKUP_RATING_MID,  "hagar",        "hagar",           "Hagar");
+	register_weapon(WEP_ROCKET_LAUNCHER,  w_rlauncher,    IT_ROCKETS, 9, 1, 1, BOT_PICKUP_RATING_HIGH, "rl",           "rocketlauncher",  "Rocket Launcher");
+	register_weapon(WEP_PORTO,            w_porto,        0,          0, 0, 0, 0,                      "porto" ,       "porto",           "Port-O-Launch");
+	register_weapon(WEP_MINSTANEX,        w_minstanex,    IT_CELLS,   7, 0, 1, BOT_PICKUP_RATING_HIGH, "minstanex",    "minstanex",       "MinstaNex");
+	register_weapon(WEP_HOOK,             w_hook,         IT_CELLS,   0, 0, 1, 0,                      "hookgun",      "hook",            "Grappling Hook");
+	register_weapon(WEP_SEEKER,           w_seeker,       IT_ROCKETS, 8, 1, 0, BOT_PICKUP_RATING_HIGH, "seeker",       "seeker",          "T.A.G. Seeker");
+	register_weapon(WEP_HLAC,             w_hlac,         IT_CELLS,   6, 1, 0, BOT_PICKUP_RATING_MID,  "hlac",         "hlac",            "Heavy Laser Assault Cannon");
+	register_weapon(WEP_CAMPINGRIFLE,     w_campingrifle, IT_NAILS,   3, 1, 0, BOT_PICKUP_RATING_MID,  "campingrifle", "campingrifle",    "Camping Rifle");
 
 	register_weapons_done();
 }

Modified: branches/nexuiz-2.0/data/qcsrc/common/items.qh
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/common/items.qh	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/common/items.qh	2008-12-28 21:00:43 UTC (rev 5335)
@@ -19,6 +19,10 @@
 float WEP_LAST				= 15; float WEPBIT_ALL              = 32767;
 float WEP_COUNT             = 16;
 
+float BOT_PICKUP_RATING_LOW	= 2500;
+float BOT_PICKUP_RATING_MID	= 5000;
+float BOT_PICKUP_RATING_HIGH	= 10000;
+
 float	IT_UNLIMITED_WEAPON_AMMO  = 1;
 // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
 float	IT_UNLIMITED_SUPERWEAPONS = 2;

Modified: branches/nexuiz-2.0/data/qcsrc/common/util-pre.qh
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/common/util-pre.qh	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/common/util-pre.qh	2008-12-28 21:00:43 UTC (rev 5335)
@@ -1,3 +1,5 @@
 #define tokenize DO_NOT_DEFINE_THIS_MONSTER_tokenize
 #define tokenizebyseparator DO_NOT_DEFINE_THIS_MONSTER_tokenizebyseparator
 #define argv DO_NOT_DEFINE_THIS_MONSTER_argv
+#define argv_start_index DO_NOT_DEFINE_THIS_MONSTER_argv_start_index
+#define argv_end_index DO_NOT_DEFINE_THIS_MONSTER_argv_end_index

Modified: branches/nexuiz-2.0/data/qcsrc/common/util.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/common/util.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/common/util.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -918,6 +918,9 @@
 string (float argnum) _argv_builtin = #442;
 float (string s, string sep) _tokenizebyseparator_builtin = #479;
 #endif
+float(string s) _tokenize_console = #514;
+float(float i) _argv_start_index_builtin = #515;
+float(float i) _argv_end_index_builtin = #516;
 
 float MAX_TOKENS = 256;
 string _argv_sane_buffer[MAX_TOKENS];
@@ -949,7 +952,8 @@
 	return _argv_sane_endpos[i];
 }
 
-string TOKENIZE_SANE_WHITESPACE_CHARS = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+//string TOKENIZE_SANE_WHITESPACE_CHARS = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+string TOKENIZE_SANE_WHITESPACE_CHARS = "\x20\x0d\x0a\x09";
 string TOKENIZE_SANE_COMMENT_BREAKERS = "\x0d\x0a";
 // change this if DP changes its type to "char"!
 
@@ -961,11 +965,7 @@
 	float end;
 	float i;
 
-	_argc_sane = 0;
-	data = 0;
-	end = strlen(s);
-
-	for(i = 0; i < MAX_TOKENS; ++i)
+	for(i = 0; i < _argc_sane; ++i)
 	{
 		if(_argv_sane_buffer[i])
 			strunzone(_argv_sane_buffer[i]);
@@ -973,6 +973,10 @@
 		_argv_sane_startpos[i] = 0;
 	}
 
+	_argc_sane = 0;
+	data = 0;
+	end = strlen(s);
+
 	for(;;)
 	{
 		// skip whitespace
@@ -1033,32 +1037,45 @@
 
 
 
-var void(void) func_null;
-
 // "sane" tokenizer
 // matching the console 1:1
 
-float tokenize_sane(string s)
+float tokenize_sane_force_native(string s)
 {
+	argv = _argv_builtin;
+	argv_start_index = _argv_start_index_builtin;
+	argv_end_index = _argv_end_index_builtin;
+	return _tokenize_console(s);
+}
+
+float tokenize_sane_force_emulation(string s)
+{
 	argv = _argv_sane;
 	argv_start_index = _argv_start_index_sane;
 	argv_end_index = _argv_end_index_sane;
 	return _tokenize_sane(s);
 }
 
+float tokenize_sane(string s)
+{
+	if(checkextension("DP_QC_TOKENIZE_CONSOLE"))
+		return tokenize_sane_force_native(s);
+	return tokenize_sane_force_emulation(s);
+}
+
 float tokenize_insane(string s)
 {
 	argv = _argv_builtin;
-	argv_start_index = func_null;
-	argv_end_index = func_null;
+	argv_start_index = _argv_start_index_builtin;
+	argv_end_index = _argv_end_index_builtin;
 	return _tokenize_builtin(s);
 }
 
 float tokenizebyseparator(string s, string sep)
 {
 	argv = _argv_builtin;
-	argv_start_index = func_null;
-	argv_end_index = func_null;
+	argv_start_index = _argv_start_index_builtin;
+	argv_end_index = _argv_end_index_builtin;
 	return _tokenizebyseparator_builtin(s, sep);
 }
 

Modified: branches/nexuiz-2.0/data/qcsrc/common/util.qh
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/common/util.qh	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/common/util.qh	2008-12-28 21:00:43 UTC (rev 5335)
@@ -114,6 +114,8 @@
 var float(float) argv_start_index;
 var float(float) argv_end_index;
 float tokenize_sane(string s);
+float tokenize_sane_force_emulation(string s);
+float tokenize_sane_force_native(string s);
 float tokenize_insane(string s);
 float tokenizebyseparator(string s, string sep);
 

Modified: branches/nexuiz-2.0/data/qcsrc/menu/gamecommand.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/menu/gamecommand.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/menu/gamecommand.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -74,5 +74,44 @@
 		return;
 	}
 
+#if 0
+	if(argv(0) == "tokentest")
+	{
+		string s;
+		float i, n;
+
+		print("SANE tokenizer:\n");
+		s = cvar_string("tokentest");
+		n = tokenize_sane_force_builtin(s);
+		for(i = -n; i < n; ++i)
+		{
+			print("token ", ftos(i), ": '", argv(i), "' = ");
+			print(ftos(argv_start_index(i)), " to ", ftos(argv_end_index(i)), "\n");
+		}
+		print(".\n");
+
+		print("INSANE tokenizer:\n");
+		s = cvar_string("tokentest");
+		n = tokenize_insane(s);
+		for(i = -n; i < n; ++i)
+		{
+			print("token ", ftos(i), ": '", argv(i), "' = ");
+			print(ftos(argv_start_index(i)), " to ", ftos(argv_end_index(i)), "\n");
+		}
+		print(".\n");
+
+		print("EMULATED tokenizer:\n");
+		s = cvar_string("tokentest");
+		n = tokenize_sane_force_emulation(s);
+		for(i = -n; i < n; ++i)
+		{
+			print("token ", ftos(i), ": '", argv(i), "' = ");
+			print(ftos(argv_start_index(i)), " to ", ftos(argv_end_index(i)), "\n");
+		}
+		print(".\n");
+		return;
+	}
+#endif
+
 	print("Invalid theCommand. For a list of supported theCommands, try menu_cmd help.\n");
 }

Modified: branches/nexuiz-2.0/data/qcsrc/server/extensions.qh
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/extensions.qh	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/server/extensions.qh	2008-12-28 21:00:43 UTC (rev 5335)
@@ -819,6 +819,18 @@
 //returns 4 and the tokens are "10" "2" "3" "4"
 //possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000")
 
+//DP_QC_TOKENIZE_CONSOLE
+//idea: div0
+//darkplaces implementation: div0
+//builtin definitions:
+float(string s) tokenize_console = #514;
+float(float i) argv_start_index = #515;
+float(float i) argv_end_index = #516;
+//description:
+//this function returns tokens separated just like the console does
+//also, functions are provided to get the index of the first and last character of each token in the original string
+//Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token.
+
 //DP_QC_TRACEBOX
 //idea: id Software
 //darkplaces implementation: id Software

Modified: branches/nexuiz-2.0/data/qcsrc/server/g_subs.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/g_subs.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/server/g_subs.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -176,6 +176,7 @@
 		self.think1 ();
 }
 
+// FIXME: I fixed this function only for rotation around the main axes
 void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
 {
 	vector	delta;
@@ -183,16 +184,26 @@
 
 	if (!tspeed)
 		objerror ("No speed is defined!");
-
+	
+	// take the shortest distance for the angles
+	self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
+	self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
+	self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
 	delta = destangle - self.angles;
 	traveltime = vlen (delta) / tspeed;
-
-	self.avelocity = delta * (1 / traveltime);
-
+  
 	self.think1 = func;
 	self.finalangle = destangle;
+	self.think = SUB_CalcAngleMoveDone;
 
-	self.think = SUB_CalcAngleMoveDone;
+	if (traveltime < 0.1)
+	{
+		self.avelocity = '0 0 0';
+		self.nextthink = self.ltime + 0.1;
+		return;
+	}
+
+	self.avelocity = delta * (1 / traveltime);
 	self.nextthink = self.ltime + traveltime;
 }
 

Modified: branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -10,25 +10,178 @@
 	return vlen(self.origin - e.origin) < 1500;
 }
 
+.float max_armorvalue;
+float havocbot_pickupevalfunc(entity item)
+{
+	float i, j, rating, base, position, need_shells, need_nails, need_rockets, need_cells;
+	rating = 0;
+
+	base = item.bot_pickupbasevalue;
+
+	need_shells = self.weapons & WEPBIT_SHOTGUN;
+	need_nails = self.weapons & WEPBIT_UZI;
+	need_cells = self.weapons & ( WEPBIT_HOOK | WEPBIT_HLAC | WEPBIT_MINSTANEX | WEPBIT_NEX | WEPBIT_ELECTRO | WEPBIT_CRYLINK );
+	need_rockets = self.weapons & ( WEPBIT_ROCKET_LAUNCHER | WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_SEEKER );
+
+	if( item.weapons )
+	{
+		if( self.weapons & item.weapons == item.weapons )
+			rating = 0.5 + bound(0, skill / 20, 0.5);
+		else
+			rating = 1;
+		
+		if( bot_custom_weapon )
+		{
+			for(i = WEP_FIRST; i < WEP_LAST ; ++i){		
+				if( power2of(i-1) & item.weapons  != item.weapons )
+					continue;
+
+				position = -1;
+				for(j = 0; j < WEP_LAST ; ++j){
+					if(
+						bot_weapons_far[j] == i ||
+						bot_weapons_mid[j] == i ||
+						bot_weapons_close[j] == i
+					)
+					{
+						position = j;
+						break;
+					}
+				}
+
+				if (position >= 0 ) 
+				{
+					position = WEP_LAST - position;
+					// item.bot_pickupbasevalue is overwritten here
+					base = BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ));
+					break;
+				}
+			}
+		}
+	}
+
+	if (item.ammo_shells)
+	if (self.ammo_shells < g_pickup_shells_max && need_cells )
+		rating = rating + max(0, 1 - self.ammo_shells / g_pickup_shells_max);
+
+	if (item.ammo_nails)
+	if (self.ammo_nails < g_pickup_nails_max && need_nails )
+		rating = rating + max(0, 1 - self.ammo_nails / g_pickup_nails_max);
+
+	if (item.ammo_rockets)
+	if (self.ammo_rockets < g_pickup_rockets_max && need_rockets)
+		rating = rating + max(0, 1 - self.ammo_rockets / g_pickup_rockets_max);
+
+	if (item.ammo_cells)
+	if (self.ammo_cells < g_pickup_cells_max && need_cells)
+		rating = rating + max(0, 1 - self.ammo_cells / g_pickup_cells_max);
+
+	if (item.armorvalue)
+	if (self.armorvalue < item.max_armorvalue)
+		rating = rating + max(0, 1 - self.armorvalue / item.max_armorvalue);
+
+	if (item.health)
+	if (self.health < item.max_health)
+		rating = rating + max(0, 1 - self.health / item.max_health);
+
+	// TODO: if the item is not recognized then default to item.bot_pickupevalfunc(self, item);
+		
+	return base * rating;
+};
+
 void havocbot_goalrating_items(float ratingscale, vector org, float sradius)
 {
 	local entity head;
-	local float t;
+	local entity player;	
+	local float rating, d, discard, distance, friend_distance, enemy_distance;
 	ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
 	head = findchainfloat(bot_pickup, TRUE);
+	
 	while (head)
 	{
-		if (head.solid) // must be possible to pick up (respawning items don't count)
-		if (vlen(head.origin - org) < sradius)
+		distance = vlen(head.origin - org);
+		friend_distance = 10000; enemy_distance = 10000;
+		rating = 0;
+	
+		if(!head.solid || distance > sradius ){
+			head = head.chain;
+			continue;		
+		}
+
+		if(teamplay)
 		{
-			// debugging
-			//if (!head.bot_pickupevalfunc || head.model == "")
-			//	eprint(head);
-			// get the value of the item
-			t = head.bot_pickupevalfunc(self, head);
-			if (t > 0)
-				navigation_routerating(head, t * ratingscale, 2000);
+			discard = FALSE;
+			
+			FOR_EACH_PLAYER(player)
+			{
+
+				if ( self == player || player.deadflag != DEAD_NO)
+					continue;
+
+				d = vlen(player.origin - head.origin); // distance between player and item
+
+				if ( player.team == self.team )
+				{
+					if ( clienttype(player) != CLIENTTYPE_REAL || discard )
+						continue;
+
+					if( d > friend_distance)
+						continue;
+					
+					friend_distance = d;
+
+					discard = TRUE;
+					
+					if( head.health && player.health > self.health )
+						continue;
+
+					if( head.armorvalue && player.armorvalue > self.armorvalue)
+						continue;
+											
+					if( head.weapons )
+					if( (player.weapons & head.weapons) != head.weapons)
+						continue;
+
+					if (head.ammo_shells && player.ammo_shells > self.ammo_shells)
+						continue;
+
+					if (head.ammo_nails && player.ammo_nails > self.ammo_nails)
+						continue;
+
+					if (head.ammo_rockets && player.ammo_rockets > self.ammo_rockets)
+						continue;
+
+					if (head.ammo_cells && player.ammo_cells > self.ammo_cells )
+						continue;
+
+					discard = FALSE;
+				}
+				else
+				{
+					// If enemy only track distances
+					// TODO: track only if visible ?
+					if( d < enemy_distance )
+						enemy_distance = d;
+				}
+			}
+
+			// Rate the item only if no one needs it, or if an enemy is closer to it
+			if (	(enemy_distance < friend_distance && distance < enemy_distance) ||
+				(friend_distance > cvar("bot_ai_friends_aware_pickup_radius") ) || !discard )
+			{
+			//	rating = head.bot_pickupevalfunc(self, head);
+				rating = havocbot_pickupevalfunc(head);
+			}				
 		}
+		else
+		{
+		//	rating = head.bot_pickupevalfunc(self, head);
+			rating = havocbot_pickupevalfunc(head);
+		}
+
+		if(rating > 0)
+			navigation_routerating(head, rating * ratingscale, 2000);
+			
 		head = head.chain;
 	}
 };

Modified: branches/nexuiz-2.0/data/qcsrc/server/t_plats.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/t_plats.qc	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/qcsrc/server/t_plats.qc	2008-12-28 21:00:43 UTC (rev 5335)
@@ -611,6 +611,8 @@
 
 void() door_go_down;
 void() door_go_up;
+void() door_rotating_go_down;
+void() door_rotating_go_up;
 
 void door_blocked()
 {
@@ -627,9 +629,21 @@
             if (self.wait >= 0)
             {
                 if (self.state == STATE_DOWN)
-                    door_go_up ();
+			if (self.classname == "door")
+			{
+				door_go_up ();
+			} else 
+			{
+				door_rotating_go_up ();
+			}
                 else
-                    door_go_down ();
+			if (self.classname == "door")
+			{
+				door_go_down ();
+			} else 
+			{
+				door_rotating_go_down ();
+			}
             }
         } else {
             //gib dying stuff just to make sure
@@ -659,7 +673,13 @@
 	self.state = STATE_TOP;
 	if (self.spawnflags & DOOR_TOGGLE)
 		return;		// don't come down automatically
-	self.think = door_go_down;
+	if (self.classname == "door")
+	{
+		self.think = door_go_down;
+	} else 
+	{
+		self.think = door_rotating_go_down;
+	}
 	self.nextthink = self.ltime + self.wait;
 };
 
@@ -733,7 +753,14 @@
 			starte = self;
 			do
 			{
-				door_go_down ();
+				if (self.classname == "door") 
+				{
+					door_go_down ();
+				}
+				else
+				{
+					door_rotating_go_down ();
+				}
 				self = self.enemy;
 			} while ( (self != starte) && (self != world) );
 			self = oself;
@@ -745,7 +772,13 @@
 	starte = self;
 	do
 	{
-		door_go_up ();
+		if (self.classname == "door")
+		{
+			door_go_up ();
+		} else 
+		{
+			door_rotating_go_up ();
+		}
 		self = self.enemy;
 	} while ( (self != starte) && (self != world) );
 	self = oself;
@@ -824,6 +857,104 @@
 	}
 };
 
+
+void door_rotating_blocked()
+{
+
+    if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
+        Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+    } else {
+
+        if((self.dmg) && (other.takedamage == DAMAGE_YES))    // Shall we bite?
+            Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+
+         //Dont chamge direction for dead or dying stuff
+        if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
+            if (self.wait >= 0)
+            {
+                if (self.state == STATE_DOWN)
+                    door_rotating_go_up ();
+                else
+                    door_rotating_go_down ();
+            }
+        } else {
+            //gib dying stuff just to make sure
+            if((self.dmg) && (other.takedamage != DAMAGE_NO))    // Shall we bite?
+                Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+        }
+    }
+
+	//T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
+// if a door has a negative wait, it would never come back if blocked,
+// so let it just squash the object to death real fast
+/*	if (self.wait >= 0)
+	{
+		if (self.state == STATE_DOWN)
+			door_rotating_go_up ();
+		else
+			door_rotating_go_down ();
+	}
+*/
+};
+
+
+void door_rotating_hit_top()
+{
+	if (self.noise1 != "")
+		sound (self, CHAN_TRIGGER, self.noise1, VOL_BASE, ATTN_NORM);
+	self.state = STATE_TOP;
+	if (self.spawnflags & DOOR_TOGGLE)
+		return;		// don't come down automatically
+	self.think = door_rotating_go_down;
+	self.nextthink = self.ltime + self.wait;
+};
+
+void door_rotating_hit_bottom()
+{
+	if (self.noise1 != "")
+		sound (self, CHAN_TRIGGER, self.noise1, VOL_BASE, ATTN_NORM);
+	self.state = STATE_BOTTOM;
+};
+
+void door_rotating_go_down()
+{
+	if (self.noise2 != "")
+		sound (self, CHAN_TRIGGER, self.noise2, VOL_BASE, ATTN_NORM);
+	if (self.max_health)
+	{
+		self.takedamage = DAMAGE_YES;
+		self.health = self.max_health;
+	}
+
+	self.state = STATE_DOWN;
+	SUB_CalcAngleMove (self.pos1, self.speed, door_hit_bottom);
+};
+
+void door_rotating_go_up()
+{
+	if (self.state == STATE_UP)
+		return;		// already going up
+
+	if (self.state == STATE_TOP)
+	{	// reset top wait time
+		self.nextthink = self.ltime + self.wait;
+		return;
+	}
+	if (self.noise2 != "")
+		sound (self, CHAN_TRIGGER, self.noise2, VOL_BASE, ATTN_NORM);
+	self.state = STATE_UP;
+	SUB_CalcAngleMove (self.pos2, self.speed, door_rotating_hit_top);
+
+	string oldmessage;
+	oldmessage = self.message;
+	self.message = "";
+	SUB_UseTargets();
+	self.message = oldmessage;
+};
+
+
+
+
 /*
 =============================================================================
 
@@ -854,17 +985,17 @@
 
 float EntitiesTouching(entity e1, entity e2)
 {
-	if (e1.mins_x > e2.maxs_x)
+	if (e1.absmin_x > e2.absmax_x)
 		return FALSE;
-	if (e1.mins_y > e2.maxs_y)
+	if (e1.absmin_y > e2.absmax_y)
 		return FALSE;
-	if (e1.mins_z > e2.maxs_z)
+	if (e1.absmin_z > e2.absmax_z)
 		return FALSE;
-	if (e1.maxs_x < e2.mins_x)
+	if (e1.absmax_x < e2.absmin_x)
 		return FALSE;
-	if (e1.maxs_y < e2.mins_y)
+	if (e1.absmax_y < e2.absmin_y)
 		return FALSE;
-	if (e1.maxs_z < e2.mins_z)
+	if (e1.absmax_z < e2.absmin_z)
 		return FALSE;
 	return TRUE;
 };
@@ -894,13 +1025,12 @@
 			return;
 		if (self.items)
 			return;
-
 		self.trigger_field = spawn_field(self.absmin, self.absmax);
 
 		return;		// don't want to link this door
 	}
 
-	cmins = self.absmin;
+	cmins = self.absmin;			  
 	cmaxs = self.absmax;
 
 	starte = self;
@@ -970,7 +1100,7 @@
 
 TOGGLE causes the door to wait in both the start and end states for a trigger event.
 
-START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
 
 "message"	is printed when the door is touched if it is a trigger door and it hasn't been fired yet
 "angle"		determines the opening direction
@@ -1060,6 +1190,114 @@
 	InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
 };
 
+/*QUAKED spawnfunc_func_door_rotating (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK x x TOGGLE X_AXIS Y_AXIS BIDIR
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor. 
+This feature is NOT YET IMPLEMENTED!
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
+
+"message"	is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"		determines the destination angle for opening. negative values reverse the direction.
+"targetname"    if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"	if set, door must be shot open
+"speed"		movement speed (100 default)
+"wait"		wait before returning (3 default, -1 = never return)
+"dmg"		damage to inflict when blocked (2 default)
+"sounds"
+0)	no sound
+1)	stone
+2)	base
+3)	stone chain
+4)	screechy metal
+FIXME: only one sound set available at the time being
+*/
+
+void door_rotating_init_startopen()
+{
+	self.angles = self.movedir;
+	self.pos2 = '0 0 0';
+	self.pos1 = self.movedir;
+}
+
+
+void spawnfunc_func_door_rotating()
+{
+	
+	//if (!self.deathtype) // map makers can override this
+	//	self.deathtype = " got in the way";
+
+	// I abuse "movedir" for denoting the axis for now
+	if (self.spawnflags & 64) // X (untested)
+		self.movedir = '0 0 1';
+	else if (self.spawnflags & 128) // Y (untested)
+		self.movedir = '1 0 0';
+	else // Z
+		self.movedir = '0 1 0';
+
+	if (self.angles_y==0) self.angles_y = 90;
+
+	self.movedir = self.movedir * self.angles_y;
+	self.angles = '0 0 0';
+
+	self.max_health = self.health;
+	InitMovingBrushTrigger();
+	//self.effects |= EF_LOWPRECISION;
+	self.classname = "door_rotating";
+
+	self.blocked = door_blocked;
+	self.use = door_use;
+
+    if(self.spawnflags & 8)
+        self.dmg = 10000;
+
+    if(self.dmg && (!self.message))
+		self.message = "was squished";
+    if(self.dmg && (!self.message2))
+		self.message2 = "was squished by";
+
+    if (self.sounds > 0)
+	{
+		precache_sound ("plats/medplat1.wav");
+		precache_sound ("plats/medplat2.wav");
+		self.noise2 = "plats/medplat1.wav";
+		self.noise1 = "plats/medplat2.wav";
+	}
+
+	if (!self.speed)
+		self.speed = 50;
+	if (!self.wait)
+		self.wait = 1;
+
+	self.pos1 = '0 0 0';
+	self.pos2 = self.movedir;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+	if (self.spawnflags & DOOR_START_OPEN)
+		InitializeEntity(self, door_rotating_init_startopen, INITPRIO_SETLOCATION);
+
+	self.state = STATE_BOTTOM;
+
+	if (self.health)
+	{
+		self.takedamage = DAMAGE_YES;
+		self.event_damage = door_damage;
+	}
+
+	if (self.items)
+		self.wait = -1;
+
+	self.touch = door_touch;
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+	InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
+};
+
 /*
 =============================================================================
 

Modified: branches/nexuiz-2.0/data/scripts/entities.def
===================================================================
--- branches/nexuiz-2.0/data/scripts/entities.def	2008-12-28 19:52:15 UTC (rev 5334)
+++ branches/nexuiz-2.0/data/scripts/entities.def	2008-12-28 21:00:43 UTC (rev 5335)
@@ -90,6 +90,29 @@
 TOGGLE: causes the door to wait in both the start and end states for a trigger event.
 */
 
+/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN - DOOR_DONT_LINK - - TOGGLE X_AXIS Y_AXIS BIDIR
+Normal rotating door entity. By default, the door will activate when player walks close to it or when damage is inflicted to it.
+If DOOR_DONT_LINK is not set, the door will be linked with all doors it touches.
+BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor.
+This feature is NOT YET IMPLEMENTED!
+-------- KEYS --------
+message: is printed when the door is touched if it is a trigger door and it hasn't been fired yet, or death message if dmg is set
+message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end)
+angle: determines the destination angle for opening. negative values reverse the direction (90 default)
+targetname: if set, no touch field will be spawned and a remote button or trigger field activates the door.
+health: if set, door must be shot open
+speed: speed to rotate (in degrees per second)
+wait: wait before returning (3 default, -1 = never return)
+dmg: damage to inflict when blocked (when triggered and someone is in the way)
+sounds: when 1, use default door sounds
+noise1: sound when the door opens
+noise2: sound when the door closes
+-------- SPAWNFLAGS --------
+START_OPEN: causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or damage triggered doors).
+DOOR_DONT_LINK: the door won't link with another door it touches
+TOGGLE: causes the door to wait in both the start and end states for a trigger event.
+*/
+
 /*QUAKED func_door_secret (0 .5 .8) ? OPEN_ONCE 1ST_LEFT 1ST_DOWN NO_SHOOT ALWAYS_SHOOT
 Basic secret door. Slides back, then to the side. Angle determines direction. Opens when targeted or when shot; does not create its own trigger field like func_door does.
 -------- KEYS --------




More information about the nexuiz-commits mailing list