1 #include "bot.h"
2 #include "m_player.h"
3
4
Get_YenPos(char * Buff,int * curr)5 qboolean Get_YenPos(char *Buff,int *curr)
6 {
7 int i;
8
9 i = *curr + 1;
10
11 while(1)
12 {
13 // if(i >= strlen(Buff)) return false;
14 if(Buff[i] == 0 || Buff[i] == 10 || Buff[i] == 13)
15 {
16 *curr = i;
17 return true;
18 }
19 if(Buff[i] == '\\')
20 {
21 *curr = i;
22 return true;
23 }
24 if(Buff[i] == '\t') Buff[i] = 0;
25 i++;
26 }
27 }
28 //----------------------------------------------------------------
29 //Load Bot Info
30 //
31 // Load bot's infomation from 3ZBConfig.cfg
32 //
33 //----------------------------------------------------------------
Load_BotInfo()34 void Load_BotInfo()
35 {
36 char MessageSection[50];
37 char Buff[1024];
38 int i,j,k,l;
39
40 FILE *fp;
41
42 SpawnWaitingBots = 0;
43 ListedBotCount = 0;
44
45 //init message
46 memset(ClientMessage,0,sizeof(ClientMessage));
47 //set message section
48 if(!ctf->value && chedit->value) strcpy(MessageSection,MESS_CHAIN_DM);
49 else if(ctf->value && !chedit->value) strcpy(MessageSection,MESS_CTF);
50 else if(ctf->value && chedit->value) strcpy(MessageSection,MESS_CHAIN_CTF);
51 else strcpy(MessageSection,MESS_DEATHMATCH);
52
53 //init botlist
54 ListedBots = 0;
55 j = 1;
56 for(i = 0;i < MAXBOTS;i++)
57 {
58 //netname
59 sprintf(Buff,"Zigock[%i]",i);
60 strcpy(Bot[i].netname,Buff);
61 //model
62 strcpy(Bot[i].model,"male");
63 //skin
64 strcpy(Bot[i].model,"grunt");
65
66 //param
67 Bot[i].param[BOP_WALK] = 0;
68 Bot[i].param[BOP_AIM] = 5;
69 Bot[i].param[BOP_PICKUP] = 5;
70 Bot[i].param[BOP_COMBATSKILL] = 5;
71 Bot[i].param[BOP_ROCJ] = 0;
72 Bot[i].param[BOP_VRANGE] = 90;
73 Bot[i].param[BOP_HRANGE] = 180;
74 Bot[i].param[BOP_REACTION] = 0;
75
76 //spawn flag
77 Bot[i].spflg = 0;
78 //team
79 Bot[i].team = j;
80 if(++j > 2) j = 1;
81 }
82
83 //botlist value
84 botlist = gi.cvar ("botlist", "default", CVAR_SERVERINFO | CVAR_LATCH);
85 gamepath = gi.cvar ("game", "0", CVAR_NOSET);
86
87 //load info
88 sprintf(Buff,"%s/3ZBConfig.cfg",gamepath->string);
89 fp = fopen(Buff,"rt");
90 if(fp == NULL)
91 {
92 gi.dprintf("3ZB CFG: file not found.\n");
93 return;
94 }
95 else
96 {
97 fseek( fp, 0, SEEK_SET); //�擪�ֈړ�
98 while(1)
99 {
100 if(fgets( Buff, sizeof(Buff), fp ) == NULL) goto MESS_NOTFOUND;
101 if(!_strnicmp(MessageSection,Buff,strlen(MessageSection))) break;
102 }
103
104 while(1)
105 {
106 if(fgets( Buff, sizeof(Buff), fp ) == NULL) goto MESS_NOTFOUND;
107 if(Buff[0] == '.' || Buff[0] == '[' || Buff[0] == '#') break;
108 k = strlen(Buff);
109 if((strlen(Buff) + strlen(ClientMessage)) > MAX_STRING_CHARS - 1) break;
110 strcat(ClientMessage,Buff);
111 }
112 MESS_NOTFOUND:
113 //if(botlist->string == NULL) strcpy(MessageSection,BOTLIST_SECTION_DM);
114 //else
115 sprintf(MessageSection,"[%s]",botlist->string);
116 fseek( fp, 0, SEEK_SET); //�擪�ֈړ�
117 while(1)
118 {
119 if(fgets( Buff, sizeof(Buff), fp ) == NULL)
120 {
121 MessageSection[0] = 0;
122 break;
123 }
124 if(!_strnicmp(MessageSection,Buff,strlen(MessageSection))) break;
125 }
126 //when not found
127 if(MessageSection[0] == 0)
128 {
129 strcpy(MessageSection,BOTLIST_SECTION_DM);
130 fseek( fp, 0, SEEK_SET); //�擪�ֈړ�
131 while(1)
132 {
133 if(fgets( Buff, sizeof(Buff), fp ) == NULL) goto BOTLIST_NOTFOUND;
134 if(!_strnicmp(MessageSection,Buff,strlen(MessageSection))) break;
135 }
136 }
137
138 i = 0;
139 for(i = 0;i < MAXBOTS;i++)
140 {
141 if(fgets( Buff, sizeof(Buff), fp ) == NULL) break;
142 if(Buff[0] == '[') break;
143 if(Buff[0] == '\n' || Buff[0] == '#') {i--;continue;}
144 j = 2,k = 1;
145 if(!strncmp(Buff,"\\\\",2))
146 {
147 //netname
148 if(Get_YenPos(Buff,&k))
149 {
150 Buff[k] = 0;
151 if(strlen(&Buff[j]) < 21) strcpy(Bot[i].netname,&Buff[j]);
152 j = k + 1;
153 }
154 else break;
155 //model name
156 if(Get_YenPos(Buff,&k))
157 {
158 Buff[k] = 0;
159 if(strlen(&Buff[j]) < 21) strcpy(Bot[i].model,&Buff[j]);
160 j = k + 1;
161 k++;
162 }
163 else break;
164 //skin name
165 if(Get_YenPos(Buff,&k))
166 {
167 Buff[k] = 0;
168 if(strlen(&Buff[j]) < 21) strcpy(Bot[i].skin,&Buff[j]);
169 j = k + 1;
170 k++;
171 }
172 else break;
173 for(l = 0;l < MAXBOP;l++)
174 {
175 //param0-7
176 if(Get_YenPos(Buff,&k))
177 {
178 Buff[k] = 0;
179 Bot[i].param[l] = (unsigned char)atoi(&Buff[j]);
180 j = k + 1;
181 k++;
182 }
183 else break;
184 }
185 if(l < MAXBOP) break;
186 //team
187 if(Get_YenPos(Buff,&k))
188 {
189 Buff[k] = 0;
190 if(Buff[j] == 'R') Bot[i].team = 1;
191 else if(Buff[j] == 'B') Bot[i].team = 2;
192 else Bot[i].team = 1;
193 j = k + 1;
194 k++;
195 }
196 else break;
197 //auto spawn
198 if(Get_YenPos(Buff,&k))
199 {
200 Buff[k] = 0;
201 Bot[i].spflg = atoi(&Buff[j]);
202 //gi.dprintf("%i %s\n",Bot[i].spflg,&Buff[j]);
203 if(Bot[i].spflg == BOT_SPRESERVED && autospawn->value && !chedit->value) SpawnWaitingBots++;
204 else Bot[i].spflg = BOT_SPAWNNOT;
205 }
206 else break;
207 ListedBots++;
208 }
209 }
210 }
211 BOTLIST_NOTFOUND:
212 fclose(fp);
213
214 gi.dprintf("%i of Bots is listed.\n",ListedBots);
215 spawncycle = level.time + FRAMETIME * 100;
216 }
217
218 //----------------------------------------------------------------
219 //Get Number of Client
220 //
221 // Total Client
222 //
223 //----------------------------------------------------------------
224
Get_NumOfPlayer(void)225 int Get_NumOfPlayer (void) //Bot���܂߂�player�̐�
226 {
227 int i,j;
228 edict_t *ent;
229
230 j = 0;
231 for (i=0 ; i<maxclients->value ; i++)
232 {
233 ent = g_edicts + 1 + i;
234 if (ent->inuse) j++;
235 }
236 return j;
237 }
238
239 //----------------------------------------------------------------
240 //Get New Client
241 //
242 // Get new client edict
243 //
244 //----------------------------------------------------------------
245
Get_NewClient(void)246 edict_t *Get_NewClient (void)
247 {
248 int i;
249 edict_t *e;
250 gclient_t *client;
251
252 e = &g_edicts[(int)maxclients->value];
253 for ( i = maxclients->value ; i >= 1 ; i--, e--)
254 {
255 client = &game.clients[i - 1];
256 // the first couple seconds of server time can involve a lot of
257 // freeing and allocating, so relax the replacement policy
258 if (!e->inuse && !client->pers.connected && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
259 {
260 G_InitEdict (e);
261 return e;
262 }
263 }
264 gi.error ("ED_Alloc: no free edicts shit");
265 return NULL;
266 }
267
268
269 //----------------------------------------------------------------
270 //Bot Think
271 //
272 // Bot's think code
273 //
274 //----------------------------------------------------------------
Bot_Think(edict_t * self)275 void Bot_Think (edict_t *self)
276 {
277 gclient_t *client;
278
279 if (self->linkcount != self->monsterinfo.linkcount)
280 {
281 // self->monsterinfo.linkcount = self->linkcount;
282 M_CheckGround (self);
283 }
284
285 if(self->deadflag)
286 {
287 if(self->client->ctf_grapple) CTFPlayerResetGrapple(self);
288
289 if(self->s.modelindex == skullindex || self->s.modelindex == headindex) self->s.frame = 0;
290 else if(self->s.frame < FRAME_crdeath1 && self->s.frame != 0) self->s.frame = FRAME_death308;
291 self->s.modelindex2 = 0; // remove linked weapon model
292 //ZOID
293 self->s.modelindex3 = 0; // remove linked ctf flag
294 //ZOID
295
296 self->client->zc.route_trace = false;
297 if(self->client->respawn_time <= level.time)
298 {
299 if(self->svflags & SVF_MONSTER)
300 {
301 self->client->respawn_time = level.time;
302 CopyToBodyQue (self);
303 PutBotInServer(self);
304 }
305 }
306 }
307 else
308 {
309 Bots_Move_NORM (self);
310 if(!self->inuse) return; //removed botself
311
312 client = self->client;
313
314 ClientBeginServerFrame (self);
315 }
316 if (self->linkcount != self->monsterinfo.linkcount)
317 {
318 // self->monsterinfo.linkcount = self->linkcount;
319 M_CheckGround (self);
320 }
321 M_CatagorizePosition (self);
322 BotEndServerFrame (self);
323 self->nextthink = level.time + FRAMETIME;
324 return;
325 }
326
327 //----------------------------------------------------------------
328 //Initialize Bot
329 //
330 // Initialize bot edict
331 //
332 //----------------------------------------------------------------
333
InitializeBot(edict_t * ent,int botindex)334 void InitializeBot (edict_t *ent,int botindex )
335 {
336 gclient_t *client;
337 char pinfo[200];
338 int index;
339
340 index = ent-g_edicts-1;
341 ent->client = &game.clients[index];
342
343 client = ent->client;
344
345 memset (&client->zc,0,sizeof(zgcl_t));
346 memset (&client->pers, 0, sizeof(client->pers));
347 memset (&client->resp, 0, sizeof(client->resp));
348
349 //set botindex NO.
350 client->zc.botindex = botindex;
351
352 client->resp.enterframe = level.framenum;
353
354 //set netname model skil and CTF team
355 sprintf(pinfo,"\\rate\\25000\\msg\\1\\fov\\90\\skin\\%s/%s\\name\\%s\\hand\\0",Bot[botindex].model,Bot[botindex].skin,Bot[botindex].netname);
356 ent->client->resp.ctf_team = Bot[botindex].team; //CTF_TEAM1,CTF_TEAM2
357
358 ClientUserinfoChanged (ent, pinfo);
359
360 client->pers.health = 100;
361 client->pers.max_health = 100;
362
363 client->pers.max_bullets = 200;
364 client->pers.max_shells = 100;
365 client->pers.max_rockets = 50;
366 client->pers.max_grenades = 50;
367 client->pers.max_cells = 200;
368 client->pers.max_slugs = 50;
369
370 // RAFAEL
371 client->pers.max_magslug = 50;
372 client->pers.max_trap = 5;
373
374 ent->client->pers.connected = false;
375 gi.dprintf ("%s connected\n", ent->client->pers.netname);
376 // gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
377
378 if(ctf->value) gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
379 client->pers.netname, CTFTeamName(ent->client->resp.ctf_team));
380 else gi.bprintf (PRINT_HIGH, "%s entered the game\n",
381 client->pers.netname);
382 }
383
PutBotInServer(edict_t * ent)384 void PutBotInServer (edict_t *ent)
385 {
386 edict_t *touch[MAX_EDICTS];
387 int i,j,entcount;
388 gitem_t *item;
389 gclient_t *client;
390 vec3_t spawn_origin, spawn_angles;
391 trace_t rs_trace;
392
393
394 zgcl_t *zc;
395
396 zc = &ent->client->zc;
397
398 //test
399 // item = FindItem("Trap");
400 // ent->client->pers.inventory[ITEM_INDEX(item)] = 100;
401 //test
402
403 //current weapon
404 client = ent->client;
405 item = Fdi_BLASTER;//FindItem("Blaster");
406 client->pers.selected_item = ITEM_INDEX(item);
407 client->pers.inventory[client->pers.selected_item] = 1;
408 client->pers.weapon = item;
409 client->silencer_shots = 0;
410 client->weaponstate = WEAPON_READY;
411 client->newweapon = NULL;
412
413 //clear powerups
414 client->quad_framenum = 0;
415 client->invincible_framenum = 0;
416 client->breather_framenum = 0;
417 client->enviro_framenum = 0;
418 client->grenade_blew_up = false;
419 client->grenade_time = 0;
420
421 j = zc->botindex;
422 i = zc->routeindex;
423 memset (&client->zc,0,sizeof(zgcl_t));
424 zc->botindex = j;
425 zc->routeindex = i;
426
427 //ZOID
428 client->ctf_grapple = NULL;
429
430 item = FindItem("Grapple");
431 if(ctf->value) client->pers.inventory[ITEM_INDEX(item)] = 1; //ponpoko
432 //ZOID
433
434 // clear entity values
435 ent->classname = "player";
436 ent->movetype = MOVETYPE_STEP;
437 ent->solid = SOLID_BBOX;
438 ent->model = "players/male/tris.md2";
439 VectorSet (ent->mins, -16, -16, -24);
440 VectorSet (ent->maxs, 16, 16, 32);
441
442 ent->health = ent->client->pers.health;
443 ent->max_health = ent->client->pers.max_health;
444 ent->gib_health = -40;
445
446 ent->mass = 200;
447 ent->target_ent = NULL;
448 ent->s.frame = 0;
449
450 // clear entity state values
451 ent->s.modelindex = 255; // will use the skin specified model
452 ent->s.skinnum = ent - g_edicts - 1;
453 ShowGun(ent); // ### Hentai ### special gun model
454
455 ent->s.sound = 0;
456
457 ent->monsterinfo.scale = MODEL_SCALE;
458
459 ent->pain = player_pain;
460 ent->die = player_die;
461 ent->touch = NULL;
462
463 ent->moveinfo.decel = level.time;
464 ent->pain_debounce_time = level.time;
465 ent->targetname = NULL;
466
467 ent->moveinfo.speed = 1.0; //�W�����v���̈ړ����ɂ��Ēlj�
468 ent->moveinfo.state = GETTER; //CTF�X�e�[�^�X������
469
470 ent->prethink = NULL;
471 ent->think = Bot_Think;
472 ent->nextthink = level.time + FRAMETIME;
473 ent->svflags /*|*/= SVF_MONSTER ;
474 ent->s.renderfx = 0;
475 ent->s.effects = 0;
476
477 SelectSpawnPoint (ent, spawn_origin, spawn_angles);
478 VectorCopy (spawn_origin, ent->s.origin);
479 VectorCopy (spawn_angles, ent->s.angles);
480 spawn_origin[2] -= 300;
481 rs_trace = gi.trace(ent->s.origin,ent->mins,ent->maxs,spawn_origin,ent,MASK_SOLID);
482 if(!rs_trace.allsolid) VectorCopy (rs_trace.endpos, ent->s.origin);
483 VectorSet(ent->velocity,0,0,0);
484 ent->moveinfo.speed = 0;
485 ent->groundentity = rs_trace.ent;
486 ent->client->ps.pmove.pm_flags &= ~PMF_DUCKED;
487
488 Set_BotAnim(ent,ANIM_BASIC,FRAME_run1,FRAME_run6);
489 client->anim_run = true;
490
491 ent->client->ctf_grapple = NULL;
492 ent->client->quad_framenum = level.framenum;
493 ent->client->invincible_framenum = level.framenum;
494 ent->client->enviro_framenum = level.framenum;
495 ent->client->breather_framenum = level.framenum;
496 ent->client->weaponstate = WEAPON_READY;
497 ent->takedamage = DAMAGE_AIM;
498 ent->air_finished = level.time + 12;
499 ent->clipmask = MASK_PLAYERSOLID;//MASK_MONSTERSOLID;
500 ent->flags &= ~FL_NO_KNOCKBACK;
501
502 ent->client->anim_priority = ANIM_BASIC;
503 // ent->client->anim_run = true;
504 ent->s.frame = FRAME_run1-1;
505 ent->client->anim_end = FRAME_run6;
506 ent->deadflag = DEAD_NO;
507 ent->svflags &= ~SVF_DEADMONSTER;
508
509 zc->waitin_obj = NULL;
510 zc->first_target = NULL;
511 zc->first_target = NULL;
512 zc->zcstate = STS_IDLE;
513
514 if(ent->client->resp.enterframe == level.framenum && !chedit->value)
515 {
516 gi.WriteByte (svc_muzzleflash);
517 gi.WriteShort (ent-g_edicts);
518 gi.WriteByte (MZ_LOGIN);
519 gi.multicast (ent->s.origin, MULTICAST_PVS);
520 }
521 else if(!chedit->value)
522 {
523 gi.WriteByte (svc_muzzleflash);
524 gi.WriteShort (ent-g_edicts);
525 gi.WriteByte (MZ_RESPAWN);
526 gi.multicast (ent->s.origin, MULTICAST_PVS);
527 }
528 gi.linkentity (ent);
529 VectorAdd (spawn_origin, ent->mins, ent->absmin);
530 VectorAdd (spawn_origin, ent->maxs, ent->absmax);
531 entcount = gi.BoxEdicts ( ent->absmin ,ent->absmax,touch,MAX_EDICTS,AREA_SOLID);
532 while (entcount-- > 0)
533 {
534 if(Q_stricmp (touch[entcount]->classname, "player") == 0)
535 if(touch[entcount] != ent)
536 T_Damage (touch[entcount], ent, ent, vec3_origin, touch[entcount]->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
537 }
538
539 if(ctf->value)
540 {
541 CTFPlayerResetGrapple(ent);
542 client->zc.ctfstate = CTFS_OFFENCER;
543 }
544
545
546 gi.linkentity (ent);
547 G_TouchTriggers (ent);
548 }
549
550 //----------------------------------------------------------------
551 //Spawn Bot
552 //
553 // spawn bots
554 //
555 // int i index of bot list
556 //
557 //----------------------------------------------------------------
558
SpawnBot(int i)559 qboolean SpawnBot(int i)
560 {
561 edict_t *bot,*ent;
562 int k,j;
563
564
565 //gi.cprintf (NULL,PRINT_HIGH,"Called %s %s %s\n",Bot[i].netname,Bot[i].model,Bot[i].skin);
566 //return false;
567
568 if( Get_NumOfPlayer () >= game.maxclients )
569 {
570 gi.cprintf (NULL,PRINT_HIGH,"Can't add bots\n");
571 return false;
572 }
573
574 bot = Get_NewClient();
575 if(bot == NULL) return false;
576
577 InitializeBot( bot , i);
578 PutBotInServer ( bot );
579
580 j = targetindex;
581 if(chedit->value)
582 {
583 for(k = CurrentIndex - 1;k > 0 ;k--)
584 {
585 if(Route[k].index == 0) break;
586
587 if(Route[k].state == GRS_NORMAL)
588 {
589 if(--j <= 0) break;
590 }
591 }
592
593 bot->client->zc.rt_locktime = level.time + FRAMETIME * 20;
594 bot->client->zc.route_trace = true;
595 bot->client->zc.routeindex = k;
596 VectorCopy(Route[k].Pt,bot->s.origin);
597 VectorAdd (bot->s.origin, bot->mins, bot->absmin);
598 VectorAdd (bot->s.origin, bot->maxs, bot->absmax);
599 bot->client->ps.pmove.pm_flags |= PMF_DUCKED;
600 gi.linkentity (bot);
601 // bot->s.modelindex = 0;
602
603 gi.WriteByte (svc_muzzleflash);
604 gi.WriteShort (bot-g_edicts);
605 gi.WriteByte (MZ_LOGIN);
606 gi.multicast (bot->s.origin, MULTICAST_PVS);
607
608 ent = &g_edicts[1];
609 if(ent->inuse && ent->client && !(ent->svflags & SVF_MONSTER))
610 {
611 ent->takedamage = DAMAGE_NO;
612 ent->movetype = MOVETYPE_NOCLIP;
613 ent->target_ent = bot;
614 ent->solid = SOLID_NOT;
615 ent->client->ps.pmove.pm_type = PM_FREEZE;
616 ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION ;
617 VectorCopy(ent->s.origin,ent->moveinfo.start_origin);
618 }
619 }
620
621 return true;
622 }
623
624 //----------------------------------------------------------------
625 //Spawn Call
626 //
627 // spawn bots
628 //
629 // int i index of bot list
630 //
631 //----------------------------------------------------------------
Bot_SpawnCall()632 void Bot_SpawnCall()
633 {
634 int i;
635
636 for(i = 0;i < MAXBOTS;i++)
637 {
638 if(Bot[i].spflg == BOT_SPRESERVED)
639 {
640 if(SpawnBot(i)) Bot[i].spflg = BOT_SPAWNED;
641 else
642 {
643 Bot[i].spflg = BOT_SPAWNNOT;
644 targetindex = 0;
645 }
646 SpawnWaitingBots--;
647 break;
648 }
649 }
650 }
651 //----------------------------------------------------------------
652 //Spawn Bot Reserving
653 //
654 // spawn bots reserving
655 //
656 //----------------------------------------------------------------
SpawnBotReserving()657 void SpawnBotReserving()
658 {
659 int i;
660
661 for(i = 0;i < MAXBOTS; i++)
662 {
663 if(Bot[i].spflg == BOT_SPAWNNOT)
664 {
665 Bot[i].spflg = BOT_SPRESERVED;
666 SpawnWaitingBots++;
667 return;
668 }
669 }
670 gi.cprintf (NULL, PRINT_HIGH, "Now max of bots(%i) already spawned.\n",MAXBOTS);
671 }
672 //----------------------------------------------------------------
673 //Spawn Bot Reserving 2
674 //
675 // randomized spawn bots reserving
676 //
677 //----------------------------------------------------------------
SpawnBotReserving2(int * red,int * blue)678 void SpawnBotReserving2(int *red,int *blue)
679 {
680 int i,j;
681
682 j = (int)(random() * ListedBots);
683
684 for(i = 0;i < ListedBots; i++,j++)
685 {
686 if(j >= ListedBots) j = 0;
687 if(Bot[j].spflg == BOT_SPAWNNOT)
688 {
689 Bot[j].spflg = BOT_SPRESERVED;
690 SpawnWaitingBots++;
691 if(*red > *blue) Bot[j].team = 2;
692 else Bot[j].team = 1;
693
694 if(Bot[j].team == 1) *red = *red + 1;
695 else if(Bot[j].team == 2) *blue = *blue + 1;
696 //gi.cprintf(NULL,PRINT_HIGH,"team %i\n",Bot[j].team);
697 return;
698 }
699 }
700 SpawnBotReserving();
701 }
702
703 //----------------------------------------------------------------
704 //Remove Bot
705 //
706 // remove bots
707 //
708 // int i index of bot list
709 //
710 //----------------------------------------------------------------
RemoveBot()711 void RemoveBot()
712 {
713 int i;
714 int botindex;
715 edict_t *e,*ent;
716 gclient_t *client;
717
718 for(i = MAXBOTS - 1;i >= 0;i--)
719 {
720 if(Bot[i].spflg == BOT_SPAWNED || Bot[i].spflg == BOT_NEXTLEVEL)
721 {
722 break;
723 }
724 }
725
726 if(i < 0)
727 {
728 gi.cprintf (NULL, PRINT_HIGH, "No Bots in server.");
729 return;
730 }
731
732 botindex = i;
733
734 e = &g_edicts[(int)maxclients->value];
735 for ( i = maxclients->value ; i >= 1 ; i--, e--)
736 {
737 if(!e->inuse) continue;
738 client = /*e->client;*/&game.clients[i - 1];
739 if(client == NULL) continue;
740 // the first couple seconds of server time can involve a lot of
741 // freeing and allocating, so relax the replacement policy
742 if (!client->pers.connected && (e->svflags & SVF_MONSTER))
743 {
744 if(client->zc.botindex == botindex)
745 {
746 if(Bot[botindex].spflg != BOT_NEXTLEVEL) Bot[botindex].spflg = BOT_SPAWNNOT;
747 else Bot[botindex].spflg = BOT_SPRESERVED;
748
749 gi.bprintf (PRINT_HIGH, "%s disconnected\n", e->client->pers.netname);
750
751 // send effect
752 gi.WriteByte (svc_muzzleflash);
753 gi.WriteShort (e-g_edicts);
754 gi.WriteByte (MZ_LOGOUT);
755 gi.multicast (e->s.origin, MULTICAST_PVS);
756
757 e->s.modelindex = 0;
758 e->solid = SOLID_NOT;
759
760 if(ctf->value) CTFPlayerResetGrapple(e);
761
762 gi.linkentity (e);
763
764 e->inuse = false;
765 G_FreeEdict (e);
766
767 if(targetindex)
768 {
769 ent = &g_edicts[1];
770
771 if(ent->inuse)
772 {
773 ent->health = 100;
774 ent->movetype = MOVETYPE_WALK;
775 ent->takedamage = DAMAGE_AIM;
776 ent->target_ent = NULL;
777 ent->solid = SOLID_BBOX;
778 ent->client->ps.pmove.pm_type = PM_NORMAL;
779 ent->client->ps.pmove.pm_flags = PMF_DUCKED;
780 VectorCopy(ent->moveinfo.start_origin,ent->s.origin);
781 VectorCopy(ent->moveinfo.start_origin,ent->s.old_origin);
782 }
783 targetindex = 0;
784 }
785 return;
786 }
787 }
788 }
789 gi.error ("Can't remove bot.");
790 }
791
792 //----------------------------------------------------------------
793 //Level Change Removing
794 //
795 //
796 //
797 //----------------------------------------------------------------
Bot_LevelChange()798 void Bot_LevelChange()
799 {
800 int i,j,k;
801
802 j = 0,k = 0;
803
804 for(i = 0;i < MAXBOTS;i++)
805 {
806 if(Bot[i].spflg)
807 {
808 if(Bot[i].spflg == BOT_SPAWNED)
809 {
810 k++;
811 Bot[i].spflg = BOT_NEXTLEVEL;
812 }
813 j++;
814 }
815 }
816 for(i = 0;i < k; i++)
817 {
818 RemoveBot();
819 }
820
821 SpawnWaitingBots = k;//j;
822 }
823 //----------------------------------------------------------------
824 //
825 // Ragomode menu
826 //
ZigockClientJoin(edict_t * ent,int zclass)827 void ZigockClientJoin(edict_t *ent,int zclass)
828 {
829 PMenu_Close(ent);
830
831 ent->moveinfo.sound_end = CLS_ALPHA; //PutClient�̑O�ɃN���X����
832
833 ent->svflags &= ~SVF_NOCLIENT;
834 PutClientInServer (ent);
835 // add a teleportation effect
836 ent->s.event = EV_PLAYER_TELEPORT;
837 // hold in place briefly
838 ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
839 ent->client->ps.pmove.pm_time = 14;
840
841 if(ctf->value)
842 {
843 gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
844 ent->client->pers.netname, CTFTeamName(ent->client->resp.ctf_team/*desired_team*/));
845 }
846 }
ClientJoinAsAlpha(edict_t * ent,pmenu_t * entries)847 void ClientJoinAsAlpha(edict_t *ent,pmenu_t *entries)
848 {
849 ZigockClientJoin(ent,1);
850 }
851
852 pmenu_t zgjoinmenu[] = {
853 { "*Quake II", PMENU_ALIGN_CENTER, NULL, NULL },
854 { "*3rd Zigock Rago", PMENU_ALIGN_CENTER, NULL, NULL },
855 { NULL, PMENU_ALIGN_CENTER, NULL, NULL },
856 { NULL, PMENU_ALIGN_CENTER, NULL, NULL },
857 { "alpha", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
858 { "beta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
859 { "gamma", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
860 { "delta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
861 { "epsilon", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
862 { "zeta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
863 { "eta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
864 { NULL, PMENU_ALIGN_LEFT, NULL, NULL },
865 { "Use [ and ] to move cursor", PMENU_ALIGN_LEFT, NULL, NULL },
866 { "ENTER to select class", PMENU_ALIGN_LEFT, NULL, NULL },
867 { "ESC to Exit Menu", PMENU_ALIGN_LEFT, NULL, NULL },
868 { "(TAB to Return)", PMENU_ALIGN_LEFT, NULL, NULL },
869 };
870
ZigockJoinMenu(edict_t * ent)871 void ZigockJoinMenu(edict_t *ent)
872 {
873 PMenu_Open(ent, zgjoinmenu,4, sizeof(zgjoinmenu) / sizeof(pmenu_t));
874 }
875
ZigockStartClient(edict_t * ent)876 qboolean ZigockStartClient(edict_t *ent)
877 {
878 if (ent->moveinfo.sound_end != CLS_NONE)
879 return false;
880
881 // start as 'observer'
882 ent->movetype = MOVETYPE_NOCLIP;
883 ent->solid = SOLID_NOT;
884 ent->svflags |= SVF_NOCLIENT;
885 ent->client->ps.gunindex = 0;
886 gi.linkentity (ent);
887
888 ZigockJoinMenu(ent);
889 return true;
890 }
891
892
893 //===============================
894
895 // AirStrike
896
897 //===============================
AirSight_Explode(edict_t * ent)898 static void AirSight_Explode (edict_t *ent)
899 {
900 vec3_t origin;
901 int mod;
902
903 // if (ent->owner->client && !(ent->owner->svflags & SVF_DEADMONSTER))
904 // PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
905
906 gi.sound (ent, CHAN_AUTO, gi.soundindex("3zb/airexp.wav"), 1, ATTN_NONE, 0);
907
908 //FIXME: if we are onground then raise our Z just a bit since we are a point?
909 mod = MOD_AIRSTRIKE;
910
911 T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
912
913 VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
914 gi.WriteByte (svc_temp_entity);
915 if (ent->waterlevel)
916 {
917 gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
918 }
919 else
920 {
921 gi.WriteByte (TE_ROCKET_EXPLOSION);
922 }
923 gi.WritePosition (origin);
924 gi.multicast (ent->s.origin, MULTICAST_PHS);
925
926 G_FreeEdict (ent);
927 }
928
AirSight_Think(edict_t * ent)929 void AirSight_Think(edict_t *ent)
930 {
931 // gi.sound (ent, CHAN_AUTO, gi.soundindex("medic/medatck1.wav"), 1, ATTN_NORM, 0);
932 gi.sound (ent, CHAN_BODY, gi.soundindex("3zb/airloc.wav"), 1, ATTN_NONE, 0);
933
934 ent->dmg = 120 + random() * 60;
935 ent->dmg_radius = 200;
936
937 ent->s.modelindex = gi.modelindex ("sprites/airsight.sp2");
938 VectorCopy(ent->target_ent->s.origin,ent->s.origin);
939
940 if( ent->owner->client->resp.ctf_team == CTF_TEAM2 && ctf->value)
941 {
942 ent->s.frame = 1;
943 }
944 else ent->s.frame = 0;
945
946 ent->think = AirSight_Explode;
947 ent->nextthink = level.time + FRAMETIME * 6;
948 gi.linkentity (ent);
949 }
AirStrike_Think(edict_t * ent)950 void AirStrike_Think(edict_t *ent)
951 {
952 int i,j;
953 edict_t *target,*sight;
954 trace_t rs_trace;
955
956 vec3_t point;
957
958 ent->nextthink = level.time + ent->moveinfo.speed * 0.5 /300;
959 ent->think = G_FreeEdict;
960 // ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
961
962 VectorCopy(ent->s.origin,point);
963 point[2] = ent->moveinfo.start_angles[2];
964
965 j = 1;
966 for ( i = 1 ; i <= maxclients->value; i++)
967 {
968 target = &g_edicts[i];
969 if(!target->inuse || target->deadflag || target == ent->owner) continue;
970
971 if( target->classname[0] == 'p')
972 {
973 //ctf �Ȃ�`�[�����C�g����
974 if(!ctf->value || (ctf->value && ent->owner->client->resp.ctf_team != target->client->resp.ctf_team))
975 {
976 rs_trace = gi.trace (point,NULL,NULL,target->s.origin,ent, CONTENTS_SOLID | CONTENTS_WINDOW | CONTENTS_LAVA | CONTENTS_SLIME);
977
978 if(rs_trace.fraction == 1.0)
979 {
980 sight = G_Spawn();
981
982 sight->classname = "airstrike";
983 sight->think = AirSight_Think;
984 sight->nextthink = level.time + FRAMETIME * 2 * (float)j;
985 sight->movetype = MOVETYPE_NOCLIP;
986 sight->solid = SOLID_NOT;
987 sight->owner = ent->owner;
988 sight->target_ent = target;
989 gi.linkentity (sight);
990 j++;
991 }
992 }
993 }
994 }
995
996 }
Cmd_AirStrike(edict_t * ent)997 void Cmd_AirStrike(edict_t *ent)
998 {
999 edict_t *viper;
1000 trace_t rs_trace;
1001
1002 vec3_t strpoint,tts,tte,tmp;
1003
1004 vec_t f;
1005
1006 VectorCopy(ent->s.origin,strpoint);
1007 strpoint[2] += 8190;
1008
1009 rs_trace = gi.trace (ent->s.origin,NULL,NULL,strpoint,ent, MASK_SHOT);
1010
1011 if(!(rs_trace.surface && (rs_trace.surface->flags & SURF_SKY)))
1012 {
1013 gi.cprintf(ent,PRINT_HIGH,"can't call Viper.\n");
1014 return;
1015 }
1016 /* if((rs_trace.endpos[2] - ent->s.origin[2]) < 300)
1017 {
1018 gi.cprintf(ent,PRINT_HIGH,"can't call Viper.\n");
1019 }*/
1020
1021 VectorCopy(rs_trace.endpos,strpoint);
1022 strpoint[2] -= 16; //������Ƃ������ւ��炷
1023
1024 f = ent->s.angles[YAW]*M_PI*2 / 360;
1025 tts[0] = cos(f) * (-8190) ;
1026 tts[1] = sin(f) * (-8190) ;
1027 tts[2] = 0;
1028
1029 tte[0] = cos(f) *8190 ;
1030 tte[1] = sin(f) *8190 ;
1031 tte[2] = 0;
1032
1033 viper = G_Spawn();
1034 VectorClear (viper->mins);
1035 VectorClear (viper->maxs);
1036 viper->movetype = /*MOVETYPE_FLYMISSILE;//MOVETYPE_STEP;*/MOVETYPE_NOCLIP;
1037 viper->solid = SOLID_NOT;
1038 viper->owner = ent;
1039 viper->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2");
1040
1041 VectorCopy(ent->s.angles,viper->s.angles);
1042 viper->s.angles[2] = 0;
1043 rs_trace = gi.trace (strpoint,NULL,NULL,tts,ent, MASK_SHOT);
1044 tts[0] = cos(f) * (-600) ;
1045 tts[1] = sin(f) * (-600) ;
1046 VectorAdd(rs_trace.endpos,tts,tmp);
1047 VectorCopy(tmp,viper->s.origin);
1048
1049
1050 viper->velocity[0] = cos(f) * 300;
1051 viper->velocity[1] = sin(f) * 300;
1052 viper->velocity[2] = 0;
1053
1054 rs_trace = gi.trace (strpoint,NULL,NULL,tte,ent, MASK_SHOT);
1055 VectorSubtract(viper->s.origin,rs_trace.endpos,tts);
1056 f = VectorLength(tts);
1057
1058 gi.sound (viper, CHAN_AUTO, gi.soundindex("world/flyby1.wav"), 1, ATTN_NONE, 0);
1059
1060 gi.sound (ent, CHAN_AUTO, gi.soundindex("world/incoming.wav"), 1, ATTN_NONE, 0);
1061
1062 viper->nextthink = level.time + f *0.75 /300;
1063 viper->think = AirStrike_Think;
1064 viper->moveinfo.speed = f;
1065
1066 // viper->s.sound = gi.soundindex ("weapons/rockfly.wav");
1067
1068 // viper->s.effects |= EF_ROTATE | EF_COLOR_SHELL;
1069 // viper->s.renderfx |= RF_SHELL_BLUE | RF_SHELL_GREEN;
1070 VectorCopy(strpoint,viper->moveinfo.start_angles); //strikepoint
1071
1072 // viper->think = Pod_think;
1073 // viper->nextthink = level.time + FRAMETIME;
1074 viper->classname = "viper";
1075 viper->s.origin[2] += 16;
1076 gi.linkentity (viper);
1077 }
1078
1079