1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 /*****************************************************************************
31  * name:		ai_team.c
32  *
33  * desc:		Quake3 bot AI
34  *
35  *
36  *****************************************************************************/
37 
38 #include "g_local.h"
39 #include "../botlib/botlib.h"
40 #include "../botlib/be_aas.h"
41 #include "../botlib/be_ea.h"
42 #include "../botlib/be_ai_char.h"
43 #include "../botlib/be_ai_chat.h"
44 #include "../botlib/be_ai_gen.h"
45 #include "../botlib/be_ai_goal.h"
46 #include "../botlib/be_ai_move.h"
47 #include "../botlib/be_ai_weap.h"
48 #include "../botlib/botai.h"
49 //
50 #include "ai_main.h"
51 #include "ai_dmq3.h"
52 #include "ai_chat.h"
53 #include "ai_cmd.h"
54 #include "ai_dmnet.h"
55 
56 
57 /*
58 ==================
59 BotValidTeamLeader
60 ==================
61 */
BotValidTeamLeader(bot_state_t * bs)62 int BotValidTeamLeader( bot_state_t *bs ) {
63 	if ( !strlen( bs->teamleader ) ) {
64 		return qfalse;
65 	}
66 	if ( ClientFromName( bs->teamleader ) == -1 ) {
67 		return qfalse;
68 	}
69 	return qtrue;
70 }
71 
72 /*
73 ==================
74 BotNumTeamMates
75 ==================
76 */
BotNumTeamMates(bot_state_t * bs)77 int BotNumTeamMates( bot_state_t *bs ) {
78 	int i, numplayers;
79 	char buf[MAX_INFO_STRING];
80 
81 	numplayers = 0;
82 	for ( i = 0; i < level.maxclients; i++ ) {
83 		trap_GetConfigstring( CS_PLAYERS + i, buf, sizeof( buf ) );
84 		//if no config string or no name
85 		if ( !strlen( buf ) || !strlen( Info_ValueForKey( buf, "n" ) ) ) {
86 			continue;
87 		}
88 		//skip spectators
89 		if ( atoi( Info_ValueForKey( buf, "t" ) ) == TEAM_SPECTATOR ) {
90 			continue;
91 		}
92 		//
93 		if ( BotSameTeam( bs, i ) ) {
94 			numplayers++;
95 		}
96 	}
97 	return numplayers;
98 }
99 
100 /*
101 ==================
102 BotClientTravelTimeToGoal
103 ==================
104 */
BotClientTravelTimeToGoal(int client,bot_goal_t * goal)105 int BotClientTravelTimeToGoal( int client, bot_goal_t *goal ) {
106 	playerState_t ps;
107 	int areanum;
108 
109 	if ( BotAI_GetClientState( client, &ps ) ) {
110 		areanum = BotPointAreaNum( ps.origin );
111 	} else {
112 		areanum = 0;
113 	}
114 
115 	if ( !areanum ) {
116 		return 1;
117 	}
118 	return trap_AAS_AreaTravelTimeToGoalArea( areanum, ps.origin, goal->areanum, TFL_DEFAULT );
119 }
120 
121 /*
122 ==================
123 BotSortTeamMatesByBaseTravelTime
124 ==================
125 */
BotSortTeamMatesByBaseTravelTime(bot_state_t * bs,int * teammates,int maxteammates)126 int BotSortTeamMatesByBaseTravelTime( bot_state_t *bs, int *teammates, int maxteammates ) {
127 
128 	int i, j, k, numteammates, traveltime;
129 	char buf[MAX_INFO_STRING];
130 	int traveltimes[MAX_CLIENTS];
131 	bot_goal_t *goal;
132 
133 	if ( BotCTFTeam( bs ) == CTF_TEAM_RED ) {
134 		goal = &ctf_redflag;
135 	} else { goal = &ctf_blueflag;}
136 
137 	numteammates = 0;
138 	for ( i = 0; i < level.maxclients; i++ ) {
139 		trap_GetConfigstring( CS_PLAYERS + i, buf, sizeof( buf ) );
140 		//if no config string or no name
141 		if ( !strlen( buf ) || !strlen( Info_ValueForKey( buf, "n" ) ) ) {
142 			continue;
143 		}
144 		//skip spectators
145 		if ( atoi( Info_ValueForKey( buf, "t" ) ) == TEAM_SPECTATOR ) {
146 			continue;
147 		}
148 		//
149 		if ( BotSameTeam( bs, i ) && goal ) {
150 			//
151 			traveltime = BotClientTravelTimeToGoal( i, goal );
152 			//
153 			for ( j = 0; j < numteammates; j++ ) {
154 				if ( traveltime < traveltimes[j] ) {
155 					for ( k = numteammates; k > j; k-- ) {
156 						traveltimes[k] = traveltimes[k - 1];
157 						teammates[k] = teammates[k - 1];
158 					}
159 					traveltimes[j] = traveltime;
160 					teammates[j] = i;
161 					break;
162 				}
163 			}
164 			if ( j >= numteammates ) {
165 				traveltimes[j] = traveltime;
166 				teammates[j] = i;
167 			}
168 			numteammates++;
169 			if ( numteammates >= maxteammates ) {
170 				break;
171 			}
172 		}
173 	}
174 	return numteammates;
175 }
176 
177 /*
178 ==================
179 BotSayTeamOrders
180 ==================
181 */
BotSayTeamOrder(bot_state_t * bs,int toclient)182 void BotSayTeamOrder( bot_state_t *bs, int toclient ) {
183 	char teamchat[MAX_MESSAGE_SIZE];
184 	char buf[MAX_MESSAGE_SIZE];
185 	char name[MAX_NETNAME];
186 
187 	//if the bot is talking to itself
188 	if ( bs->client == toclient ) {
189 		//don't show the message just put it in the console message queue
190 		trap_BotGetChatMessage( bs->cs, buf, sizeof( buf ) );
191 		ClientName( bs->client, name, sizeof( name ) );
192 		Com_sprintf( teamchat, sizeof( teamchat ), "(%s): %s", name, buf );
193 		trap_BotQueueConsoleMessage( bs->cs, CMS_CHAT, teamchat );
194 	} else {
195 		trap_BotEnterChat( bs->cs, bs->client, CHAT_TEAM );
196 	}
197 }
198 
199 /*
200 ==================
201 BotCTFOrders
202 ==================
203 */
BotCTFOrders_BothFlagsNotAtBase(bot_state_t * bs)204 void BotCTFOrders_BothFlagsNotAtBase( bot_state_t *bs ) {
205 	int numteammates, defenders, attackers, i, other;
206 	int teammates[MAX_CLIENTS] = {0};
207 	char name[MAX_NETNAME], carriername[MAX_NETNAME];
208 
209 	numteammates = BotSortTeamMatesByBaseTravelTime( bs, teammates, sizeof( teammates ) );
210 	//different orders based on the number of team mates
211 	switch ( bs->numteammates ) {
212 	case 1: break;
213 	case 2:
214 	{
215 		//tell the one not carrying the flag to attack the enemy base
216 		if ( teammates[0] != bs->flagcarrier ) {
217 			other = teammates[0];
218 		} else { other = teammates[1];}
219 		ClientName( other, name, sizeof( name ) );
220 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
221 		BotSayTeamOrder( bs, other );
222 		break;
223 	}
224 	case 3:
225 	{
226 		//tell the one closest to the base not carrying the flag to accompany the flag carrier
227 		if ( teammates[0] != bs->flagcarrier ) {
228 			other = teammates[0];
229 		} else { other = teammates[1];}
230 		ClientName( other, name, sizeof( name ) );
231 		ClientName( bs->flagcarrier, carriername, sizeof( carriername ) );
232 		if ( bs->flagcarrier == bs->client ) {
233 			BotAI_BotInitialChat( bs, "cmd_accompanyme", name, NULL );
234 		} else {
235 			BotAI_BotInitialChat( bs, "cmd_accompany", name, carriername, NULL );
236 		}
237 		BotSayTeamOrder( bs, other );
238 		//tell the one furthest from the the base not carrying the flag to get the enemy flag
239 		if ( teammates[2] != bs->flagcarrier ) {
240 			other = teammates[2];
241 		} else { other = teammates[1];}
242 		ClientName( other, name, sizeof( name ) );
243 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
244 		BotSayTeamOrder( bs, other );
245 		break;
246 	}
247 	default:
248 	{
249 		defenders = (int) ( float ) numteammates * 0.4 + 0.5;
250 		attackers = (int) ( float ) numteammates * 0.5 + 0.5;
251 		ClientName( bs->flagcarrier, carriername, sizeof( carriername ) );
252 		for ( i = 0; i < defenders; i++ ) {
253 			//
254 			if ( teammates[i] == bs->flagcarrier ) {
255 				continue;
256 			}
257 			//
258 			ClientName( teammates[i], name, sizeof( name ) );
259 			if ( bs->flagcarrier == bs->client ) {
260 				BotAI_BotInitialChat( bs, "cmd_accompanyme", name, NULL );
261 			} else {
262 				BotAI_BotInitialChat( bs, "cmd_accompany", name, carriername, NULL );
263 			}
264 			BotSayTeamOrder( bs, teammates[i] );
265 		}
266 		for ( i = 0; i < attackers; i++ ) {
267 			//
268 			if ( teammates[numteammates - i - 1] == bs->flagcarrier ) {
269 				continue;
270 			}
271 			//
272 			ClientName( teammates[numteammates - i - 1], name, sizeof( name ) );
273 			BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
274 			BotSayTeamOrder( bs, teammates[numteammates - i - 1] );
275 		}
276 		//
277 		break;
278 	}
279 	}
280 }
281 
282 /*
283 ==================
284 BotCTFOrders
285 ==================
286 */
BotCTFOrders_FlagNotAtBase(bot_state_t * bs)287 void BotCTFOrders_FlagNotAtBase( bot_state_t *bs ) {
288 	int numteammates, defenders, attackers, i;
289 	int teammates[MAX_CLIENTS];
290 	char name[MAX_NETNAME];
291 
292 	numteammates = BotSortTeamMatesByBaseTravelTime( bs, teammates, sizeof( teammates ) );
293 	//different orders based on the number of team mates
294 	switch ( bs->numteammates ) {
295 	case 1: break;
296 	case 2:
297 	{
298 		//the one closest to the base will defend the base
299 		ClientName( teammates[0], name, sizeof( name ) );
300 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
301 		BotSayTeamOrder( bs, teammates[0] );
302 		//the other will get the flag
303 		ClientName( teammates[1], name, sizeof( name ) );
304 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
305 		BotSayTeamOrder( bs, teammates[1] );
306 		break;
307 	}
308 	case 3:
309 	{
310 		//the one closest to the base will defend the base
311 		ClientName( teammates[0], name, sizeof( name ) );
312 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
313 		BotSayTeamOrder( bs, teammates[0] );
314 		//the other two get the flag
315 		ClientName( teammates[1], name, sizeof( name ) );
316 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
317 		BotSayTeamOrder( bs, teammates[1] );
318 		//
319 		ClientName( teammates[2], name, sizeof( name ) );
320 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
321 		BotSayTeamOrder( bs, teammates[2] );
322 		break;
323 	}
324 	default:
325 	{
326 		defenders = (int) ( float ) numteammates * 0.3 + 0.5;
327 		attackers = (int) ( float ) numteammates * 0.5 + 0.5;
328 		for ( i = 0; i < defenders; i++ ) {
329 			//
330 			ClientName( teammates[i], name, sizeof( name ) );
331 			BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
332 			BotSayTeamOrder( bs, teammates[i] );
333 		}
334 		for ( i = 0; i < attackers; i++ ) {
335 			//
336 			ClientName( teammates[numteammates - i - 1], name, sizeof( name ) );
337 			BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
338 			BotSayTeamOrder( bs, teammates[numteammates - i - 1] );
339 		}
340 		//
341 		break;
342 	}
343 	}
344 }
345 
346 /*
347 ==================
348 BotCTFOrders
349 ==================
350 */
BotCTFOrders_EnemyFlagNotAtBase(bot_state_t * bs)351 void BotCTFOrders_EnemyFlagNotAtBase( bot_state_t *bs ) {
352 	int numteammates, defenders, attackers, i, other;
353 	int teammates[MAX_CLIENTS];
354 	char name[MAX_NETNAME], carriername[MAX_NETNAME];
355 
356 	numteammates = BotSortTeamMatesByBaseTravelTime( bs, teammates, sizeof( teammates ) );
357 	//different orders based on the number of team mates
358 	switch ( numteammates ) {
359 	case 1: break;
360 	case 2:
361 	{
362 		//tell the one not carrying the flag to defend the base
363 		if ( teammates[0] == bs->flagcarrier ) {
364 			other = teammates[1];
365 		} else { other = teammates[0];}
366 		ClientName( other, name, sizeof( name ) );
367 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
368 		BotSayTeamOrder( bs, other );
369 		break;
370 	}
371 	case 3:
372 	{
373 		//tell the one closest to the base not carrying the flag to defend the base
374 		if ( teammates[0] != bs->flagcarrier ) {
375 			other = teammates[0];
376 		} else { other = teammates[1];}
377 		ClientName( other, name, sizeof( name ) );
378 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
379 		BotSayTeamOrder( bs, other );
380 		//tell the one furthest from the base not carrying the flag to accompany the flag carrier
381 		if ( teammates[2] != bs->flagcarrier ) {
382 			other = teammates[2];
383 		} else { other = teammates[1];}
384 		ClientName( other, name, sizeof( name ) );
385 		ClientName( bs->flagcarrier, carriername, sizeof( carriername ) );
386 		if ( bs->flagcarrier == bs->client ) {
387 			BotAI_BotInitialChat( bs, "cmd_accompanyme", name, NULL );
388 		} else {
389 			BotAI_BotInitialChat( bs, "cmd_accompany", name, carriername, NULL );
390 		}
391 		BotSayTeamOrder( bs, other );
392 		break;
393 	}
394 	default:
395 	{
396 		//40% will defend the base
397 		defenders = (int) ( float ) numteammates * 0.4 + 0.5;
398 		//50% accompanies the flag carrier
399 		attackers = (int) ( float ) numteammates * 0.5 + 0.5;
400 		for ( i = 0; i < defenders; i++ ) {
401 			//
402 			if ( teammates[i] == bs->flagcarrier ) {
403 				continue;
404 			}
405 			ClientName( teammates[i], name, sizeof( name ) );
406 			BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
407 			BotSayTeamOrder( bs, teammates[i] );
408 		}
409 		ClientName( bs->flagcarrier, carriername, sizeof( carriername ) );
410 		for ( i = 0; i < attackers; i++ ) {
411 			//
412 			if ( teammates[numteammates - i - 1] == bs->flagcarrier ) {
413 				continue;
414 			}
415 			//
416 			ClientName( teammates[numteammates - i - 1], name, sizeof( name ) );
417 			if ( bs->flagcarrier == bs->client ) {
418 				BotAI_BotInitialChat( bs, "cmd_accompanyme", name, NULL );
419 			} else {
420 				BotAI_BotInitialChat( bs, "cmd_accompany", name, carriername, NULL );
421 			}
422 			BotSayTeamOrder( bs, teammates[numteammates - i - 1] );
423 		}
424 		//
425 		break;
426 	}
427 	}
428 }
429 
430 
431 /*
432 ==================
433 BotCTFOrders
434 ==================
435 */
BotCTFOrders_BothFlagsAtBase(bot_state_t * bs)436 void BotCTFOrders_BothFlagsAtBase( bot_state_t *bs ) {
437 	int numteammates, defenders, attackers, i;
438 	int teammates[MAX_CLIENTS] = {0};
439 	char name[MAX_NETNAME];
440 //	char buf[MAX_MESSAGE_SIZE];
441 
442 	numteammates = BotSortTeamMatesByBaseTravelTime( bs, teammates, sizeof( teammates ) );
443 	//different orders based on the number of team mates
444 	switch ( numteammates ) {
445 	case 1: break;
446 	case 2:
447 	{
448 		//the one closest to the base will defend the base
449 		ClientName( teammates[0], name, sizeof( name ) );
450 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
451 		BotSayTeamOrder( bs, teammates[0] );
452 		//the other will get the flag
453 		ClientName( teammates[1], name, sizeof( name ) );
454 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
455 		BotSayTeamOrder( bs, teammates[1] );
456 		break;
457 	}
458 	case 3:
459 	{
460 		//the one closest to the base will defend the base
461 		ClientName( teammates[0], name, sizeof( name ) );
462 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
463 		BotSayTeamOrder( bs, teammates[0] );
464 		//the second one closest to the base will defend the base
465 		ClientName( teammates[1], name, sizeof( name ) );
466 		BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
467 		BotSayTeamOrder( bs, teammates[1] );
468 		//the other will get the flag
469 		ClientName( teammates[2], name, sizeof( name ) );
470 		BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
471 		BotSayTeamOrder( bs, teammates[2] );
472 		break;
473 	}
474 	default:
475 	{
476 		defenders = (int) ( float ) numteammates * 0.5 + 0.5;
477 		attackers = (int) ( float ) numteammates * 0.3 + 0.5;
478 		for ( i = 0; i < defenders; i++ ) {
479 			//
480 			ClientName( teammates[i], name, sizeof( name ) );
481 			BotAI_BotInitialChat( bs, "cmd_defendbase", name, NULL );
482 			BotSayTeamOrder( bs, teammates[i] );
483 		}
484 		for ( i = 0; i < attackers; i++ ) {
485 			//
486 			ClientName( teammates[numteammates - i - 1], name, sizeof( name ) );
487 			BotAI_BotInitialChat( bs, "cmd_getflag", name, NULL );
488 			BotSayTeamOrder( bs, teammates[numteammates - i - 1] );
489 		}
490 		//
491 		break;
492 	}
493 	}
494 }
495 
496 
497 /*
498 ==================
499 BotTeamOrders
500 ==================
501 */
BotTeamOrders(bot_state_t * bs)502 void BotTeamOrders( bot_state_t *bs ) {
503 	//no teamplay orders at this time
504 }
505 
506 
507 /*
508 ==================
509 BotTeamAI
510 ==================
511 */
BotTeamAI(bot_state_t * bs)512 void BotTeamAI( bot_state_t *bs ) {
513 	int numteammates, flagstatus;
514 	char netname[MAX_NETNAME];
515 
516 	//
517 	if ( gametype != GT_TEAM && gametype != GT_CTF ) {
518 		return;
519 	}
520 	//make sure we've got a valid team leader
521 	if ( !BotValidTeamLeader( bs ) ) {
522 		//
523 		if ( !bs->askteamleader_time && !bs->becometeamleader_time ) {
524 			if ( bs->entergame_time + 10 > trap_AAS_Time() ) {
525 				bs->askteamleader_time = trap_AAS_Time() + 5 + random() * 10;
526 			} else {
527 				bs->becometeamleader_time = trap_AAS_Time() + 5 + random() * 10;
528 			}
529 		}
530 		if ( bs->askteamleader_time && bs->askteamleader_time < trap_AAS_Time() ) {
531 			//if asked for a team leader and no repsonse
532 			BotAI_BotInitialChat( bs, "whoisteamleader", NULL );
533 			trap_BotEnterChat( bs->cs, bs->client, CHAT_TEAM );
534 			bs->askteamleader_time = 0;
535 			bs->becometeamleader_time = trap_AAS_Time() + 15 + random() * 10;
536 		}
537 		if ( bs->becometeamleader_time && bs->becometeamleader_time < trap_AAS_Time() ) {
538 			BotAI_BotInitialChat( bs, "iamteamleader", NULL );
539 			trap_BotEnterChat( bs->cs, bs->client, CHAT_TEAM );
540 			ClientName( bs->client, netname, sizeof( netname ) );
541 			strncpy( bs->teamleader, netname, sizeof( bs->teamleader ) );
542 			bs->teamleader[sizeof( bs->teamleader )-1] = '\0';
543 			bs->becometeamleader_time = 0;
544 		}
545 		return;
546 	}
547 	bs->askteamleader_time = 0;
548 	bs->becometeamleader_time = 0;
549 
550 	//return if this bot is NOT the team leader
551 	ClientName( bs->client, netname, sizeof( netname ) );
552 	if ( Q_stricmp( netname, bs->teamleader ) != 0 ) {
553 		return;
554 	}
555 	//
556 	//if the game starts OR a new player comes onto the team OR a player leaves the team
557 	//
558 	numteammates = BotNumTeamMates( bs );
559 	//give orders
560 	switch ( gametype ) {
561 	case GT_TEAM:
562 	{
563 		if ( bs->numteammates != numteammates || bs->forceorders ) {
564 			bs->teamgiveorders_time = trap_AAS_Time();
565 			bs->numteammates = numteammates;
566 			bs->forceorders = qfalse;
567 		}
568 		//if it's time to give orders
569 		if ( bs->teamgiveorders_time < trap_AAS_Time() - 5 ) {
570 			BotTeamOrders( bs );
571 			//
572 			bs->teamgiveorders_time = 0;
573 		}
574 		break;
575 	}
576 	case GT_CTF:
577 	{
578 		//
579 		if ( bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders ) {
580 			bs->teamgiveorders_time = trap_AAS_Time();
581 			bs->numteammates = numteammates;
582 			bs->flagstatuschanged = qfalse;
583 			bs->forceorders = qfalse;
584 		}
585 		//if it's time to give orders
586 		if ( bs->teamgiveorders_time && bs->teamgiveorders_time < trap_AAS_Time() - 3 ) {
587 			//
588 			if ( BotCTFTeam( bs ) == CTF_TEAM_RED ) {
589 				flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
590 			} else { flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;}
591 			//
592 			switch ( flagstatus ) {
593 			case 0: BotCTFOrders_BothFlagsAtBase( bs ); break;
594 			case 1: BotCTFOrders_EnemyFlagNotAtBase( bs ); break;
595 			case 2: BotCTFOrders_FlagNotAtBase( bs ); break;
596 			case 3: BotCTFOrders_BothFlagsNotAtBase( bs ); break;
597 			}
598 			//
599 			bs->teamgiveorders_time = 0;
600 		}
601 		break;
602 	}
603 	}
604 }
605 
606 
607