mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-14 16:40:57 +00:00
1e5348cbe0
Added new graphic for text box. Made edict_t pointer arrays static in 3ZB2, Awakening2, and Zaero DLLs due to stack size concerns.
1091 lines
26 KiB
C
1091 lines
26 KiB
C
#include "bot.h"
|
||
#include "m_player.h"
|
||
|
||
|
||
qboolean Get_YenPos(char *Buff,int *curr)
|
||
{
|
||
int i;
|
||
|
||
i = *curr + 1;
|
||
|
||
while(1)
|
||
{
|
||
// if (i >= strlen(Buff)) return false;
|
||
if (Buff[i] == 0 || Buff[i] == 10 || Buff[i] == 13)
|
||
{
|
||
*curr = i;
|
||
return true;
|
||
}
|
||
if (Buff[i] == '\\')
|
||
{
|
||
*curr = i;
|
||
return true;
|
||
}
|
||
if (Buff[i] == '\t') Buff[i] = 0;
|
||
i++;
|
||
}
|
||
}
|
||
//----------------------------------------------------------------
|
||
//Load Bot Info
|
||
//
|
||
// Load bot's infomation from 3ZBConfig.cfg
|
||
//
|
||
//----------------------------------------------------------------
|
||
void Load_BotInfo()
|
||
{
|
||
char MessageSection[50];
|
||
char Buff[1024];
|
||
int i,j,k,l;
|
||
|
||
FILE *fp;
|
||
|
||
SpawnWaitingBots = 0;
|
||
ListedBotCount = 0;
|
||
|
||
//init message
|
||
memset(ClientMessage,0,sizeof(ClientMessage));
|
||
//set message section
|
||
if (!ctf->value && chedit->value)
|
||
Com_strcpy (MessageSection, sizeof(MessageSection), MESS_CHAIN_DM);
|
||
else if (ctf->value && !chedit->value)
|
||
Com_strcpy (MessageSection, sizeof(MessageSection), MESS_CTF);
|
||
else if (ctf->value && chedit->value)
|
||
Com_strcpy (MessageSection, sizeof(MessageSection), MESS_CHAIN_CTF);
|
||
else
|
||
Com_strcpy (MessageSection, sizeof(MessageSection), MESS_DEATHMATCH);
|
||
|
||
//init botlist
|
||
ListedBots = 0;
|
||
j = 1;
|
||
for(i = 0;i < MAXBOTS;i++)
|
||
{
|
||
//netname
|
||
Com_sprintf (Buff, sizeof(Buff), "Zigock[%i]",i);
|
||
Com_strcpy (Bot[i].netname, sizeof(Bot[i].netname), Buff);
|
||
//model
|
||
Com_strcpy (Bot[i].model, sizeof(Bot[i].model), "male");
|
||
//skin
|
||
Com_strcpy (Bot[i].model, sizeof(Bot[i].model), "grunt");
|
||
|
||
//param
|
||
Bot[i].param[BOP_WALK] = 0;
|
||
Bot[i].param[BOP_AIM] = 5;
|
||
Bot[i].param[BOP_PICKUP] = 5;
|
||
Bot[i].param[BOP_COMBATSKILL] = 5;
|
||
Bot[i].param[BOP_ROCJ] = 0;
|
||
Bot[i].param[BOP_VRANGE] = 90;
|
||
Bot[i].param[BOP_HRANGE] = 180;
|
||
Bot[i].param[BOP_REACTION] = 0;
|
||
|
||
//spawn flag
|
||
Bot[i].spflg = 0;
|
||
//team
|
||
Bot[i].team = j;
|
||
if (++j > 2) j = 1;
|
||
}
|
||
|
||
//botlist value
|
||
botlist = gi.cvar ("botlist", "default", CVAR_SERVERINFO | CVAR_LATCH);
|
||
gamepath = gi.cvar ("game", "0", CVAR_NOSET);
|
||
|
||
//load info
|
||
Com_sprintf (Buff, sizeof(Buff), ".\\%s\\3ZBconfig.cfg",gamepath->string);
|
||
fp = fopen(Buff, "rt");
|
||
if (fp == NULL)
|
||
{
|
||
gi.dprintf("3ZB CFG: file not found.\n");
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
fseek( fp, 0, SEEK_SET); //<2F>擪<EFBFBD>ֈړ<D688>
|
||
while(1)
|
||
{
|
||
if (fgets( Buff, sizeof(Buff), fp ) == NULL) goto MESS_NOTFOUND;
|
||
if (!Q_strncasecmp(MessageSection,Buff,strlen(MessageSection))) break; // Knightmare- was _strnicmp()
|
||
}
|
||
|
||
while(1)
|
||
{
|
||
if (fgets( Buff, sizeof(Buff), fp ) == NULL) goto MESS_NOTFOUND;
|
||
if (Buff[0] == '.' || Buff[0] == '[' || Buff[0] == '#') break;
|
||
k = (int)strlen(Buff);
|
||
if ((strlen(Buff) + strlen(ClientMessage)) > MAX_STRING_CHARS - 1) break;
|
||
Com_strcat (ClientMessage, sizeof(ClientMessage), Buff);
|
||
}
|
||
MESS_NOTFOUND:
|
||
// if (botlist->string == NULL)
|
||
// Com_strcpy (MessageSection, sizeof(MessageSection), BOTLIST_SECTION_DM);
|
||
// else
|
||
Com_sprintf (MessageSection, sizeof(MessageSection), "[%s]",botlist->string);
|
||
fseek( fp, 0, SEEK_SET); //<2F>擪<EFBFBD>ֈړ<D688>
|
||
while(1)
|
||
{
|
||
if (fgets( Buff, sizeof(Buff), fp ) == NULL)
|
||
{
|
||
MessageSection[0] = 0;
|
||
break;
|
||
}
|
||
if (!Q_strncasecmp(MessageSection, Buff,strlen(MessageSection))) break; // Knightmare- was _strnicmp()
|
||
}
|
||
//when not found
|
||
if (MessageSection[0] == 0)
|
||
{
|
||
Com_strcpy (MessageSection, sizeof(MessageSection), BOTLIST_SECTION_DM);
|
||
fseek( fp, 0, SEEK_SET); //<2F>擪<EFBFBD>ֈړ<D688>
|
||
while(1)
|
||
{
|
||
if (fgets( Buff, sizeof(Buff), fp ) == NULL) goto BOTLIST_NOTFOUND;
|
||
if (!Q_strncasecmp(MessageSection, Buff, strlen(MessageSection))) break; // Knightmare- was _strnicmp()
|
||
}
|
||
}
|
||
|
||
i = 0;
|
||
for(i = 0;i < MAXBOTS;i++)
|
||
{
|
||
if (fgets( Buff, sizeof(Buff), fp ) == NULL) break;
|
||
if (Buff[0] == '[') break;
|
||
if (Buff[0] == '\n' || Buff[0] == '#') {i--;continue;}
|
||
j = 2,k = 1;
|
||
if (!strncmp(Buff,"\\\\",2))
|
||
{
|
||
//netname
|
||
if (Get_YenPos(Buff,&k))
|
||
{
|
||
Buff[k] = 0;
|
||
if (strlen(&Buff[j]) < 21)
|
||
Com_strcpy (Bot[i].netname, sizeof(Bot[i].netname), &Buff[j]);
|
||
j = k + 1;
|
||
}
|
||
else break;
|
||
//model name
|
||
if (Get_YenPos(Buff,&k))
|
||
{
|
||
Buff[k] = 0;
|
||
if (strlen(&Buff[j]) < 21)
|
||
Com_strcpy (Bot[i].model, sizeof(Bot[i].model), &Buff[j]);
|
||
j = k + 1;
|
||
k++;
|
||
}
|
||
else break;
|
||
//skin name
|
||
if (Get_YenPos(Buff,&k))
|
||
{
|
||
Buff[k] = 0;
|
||
if (strlen(&Buff[j]) < 21)
|
||
Com_strcpy (Bot[i].skin, sizeof(Bot[i].skin), &Buff[j]);
|
||
j = k + 1;
|
||
k++;
|
||
}
|
||
else break;
|
||
for(l = 0;l < MAXBOP;l++)
|
||
{
|
||
//param0-7
|
||
if (Get_YenPos(Buff,&k))
|
||
{
|
||
Buff[k] = 0;
|
||
Bot[i].param[l] = (unsigned char)atoi(&Buff[j]);
|
||
j = k + 1;
|
||
k++;
|
||
}
|
||
else break;
|
||
}
|
||
if (l < MAXBOP) break;
|
||
//team
|
||
if (Get_YenPos(Buff,&k))
|
||
{
|
||
Buff[k] = 0;
|
||
if (Buff[j] == 'R') Bot[i].team = 1;
|
||
else if (Buff[j] == 'B') Bot[i].team = 2;
|
||
else Bot[i].team = 1;
|
||
j = k + 1;
|
||
k++;
|
||
}
|
||
else break;
|
||
//auto spawn
|
||
if (Get_YenPos(Buff,&k))
|
||
{
|
||
Buff[k] = 0;
|
||
Bot[i].spflg = atoi(&Buff[j]);
|
||
//gi.dprintf("%i %s\n",Bot[i].spflg,&Buff[j]);
|
||
if (Bot[i].spflg == BOT_SPRESERVED && autospawn->value && !chedit->value) SpawnWaitingBots++;
|
||
else Bot[i].spflg = BOT_SPAWNNOT;
|
||
}
|
||
else break;
|
||
ListedBots++;
|
||
}
|
||
}
|
||
}
|
||
BOTLIST_NOTFOUND:
|
||
fclose(fp);
|
||
|
||
gi.dprintf("%i of Bots is listed.\n",ListedBots);
|
||
spawncycle = level.time + FRAMETIME * 100;
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Get Number of Client
|
||
//
|
||
// Total Client
|
||
//
|
||
//----------------------------------------------------------------
|
||
|
||
int Get_NumOfPlayer (void) //Bot<6F><74><EFBFBD>܂߂<DC82>player<65>̐<EFBFBD>
|
||
{
|
||
int i,j;
|
||
edict_t *ent;
|
||
|
||
j = 0;
|
||
for (i=0 ; i<maxclients->value ; i++)
|
||
{
|
||
ent = g_edicts + 1 + i;
|
||
if (ent->inuse) j++;
|
||
}
|
||
return j;
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Get New Client
|
||
//
|
||
// Get new client edict
|
||
//
|
||
//----------------------------------------------------------------
|
||
|
||
edict_t *Get_NewClient (void)
|
||
{
|
||
int i;
|
||
edict_t *e;
|
||
gclient_t *client;
|
||
|
||
e = &g_edicts[(int)maxclients->value];
|
||
for ( i = maxclients->value ; i >= 1 ; i--, e--)
|
||
{
|
||
client = &game.clients[i - 1];
|
||
// the first couple seconds of server time can involve a lot of
|
||
// freeing and allocating, so relax the replacement policy
|
||
if (!e->inuse && !client->pers.connected && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
|
||
{
|
||
G_InitEdict (e);
|
||
return e;
|
||
}
|
||
}
|
||
gi.error ("ED_Alloc: no free edicts shit");
|
||
return NULL;
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------
|
||
//Bot Think
|
||
//
|
||
// Bot's think code
|
||
//
|
||
//----------------------------------------------------------------
|
||
void Bot_Think (edict_t *self)
|
||
{
|
||
gclient_t *client;
|
||
|
||
if (self->linkcount != self->monsterinfo.linkcount)
|
||
{
|
||
// self->monsterinfo.linkcount = self->linkcount;
|
||
M_CheckGround (self);
|
||
}
|
||
|
||
if (self->deadflag)
|
||
{
|
||
if (self->client->ctf_grapple) CTFPlayerResetGrapple(self);
|
||
|
||
if (self->s.modelindex == skullindex || self->s.modelindex == headindex) self->s.frame = 0;
|
||
else if (self->s.frame < FRAME_crdeath1 && self->s.frame != 0) self->s.frame = FRAME_death308;
|
||
self->s.modelindex2 = 0; // remove linked weapon model
|
||
//ZOID
|
||
self->s.modelindex3 = 0; // remove linked ctf flag
|
||
//ZOID
|
||
|
||
self->client->zc.route_trace = false;
|
||
if (self->client->respawn_time <= level.time)
|
||
{
|
||
if (self->svflags & SVF_MONSTER)
|
||
{
|
||
self->client->respawn_time = level.time;
|
||
CopyToBodyQue (self);
|
||
PutBotInServer(self);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Bots_Move_NORM (self);
|
||
if (!self->inuse) return; //removed botself
|
||
|
||
client = self->client;
|
||
|
||
ClientBeginServerFrame (self);
|
||
}
|
||
if (self->linkcount != self->monsterinfo.linkcount)
|
||
{
|
||
// self->monsterinfo.linkcount = self->linkcount;
|
||
M_CheckGround (self);
|
||
}
|
||
M_CatagorizePosition (self);
|
||
BotEndServerFrame (self);
|
||
self->nextthink = level.time + FRAMETIME;
|
||
return;
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Initialize Bot
|
||
//
|
||
// Initialize bot edict
|
||
//
|
||
//----------------------------------------------------------------
|
||
|
||
void InitializeBot (edict_t *ent,int botindex )
|
||
{
|
||
gclient_t *client;
|
||
char pinfo[200];
|
||
int index;
|
||
// int i;
|
||
|
||
index = ent-g_edicts-1;
|
||
ent->client = &game.clients[index];
|
||
|
||
client = ent->client;
|
||
|
||
memset (&client->zc,0,sizeof(zgcl_t));
|
||
memset (&client->pers, 0, sizeof(client->pers));
|
||
memset (&client->resp, 0, sizeof(client->resp));
|
||
|
||
//set botindex NO.
|
||
client->zc.botindex = botindex;
|
||
|
||
client->resp.enterframe = level.framenum;
|
||
|
||
//set netname model skil and CTF team
|
||
Com_sprintf (pinfo, sizeof(pinfo), "\\rate\\25000\\msg\\1\\fov\\90\\skin\\%s/%s\\name\\%s\\hand\\0",Bot[botindex].model,Bot[botindex].skin,Bot[botindex].netname);
|
||
ent->client->resp.ctf_team = Bot[botindex].team; //CTF_TEAM1,CTF_TEAM2
|
||
|
||
ClientUserinfoChanged (ent, pinfo);
|
||
|
||
client->pers.health = 100;
|
||
client->pers.max_health = 100;
|
||
|
||
client->pers.max_bullets = 200;
|
||
client->pers.max_shells = 100;
|
||
client->pers.max_rockets = 50;
|
||
client->pers.max_grenades = 50;
|
||
client->pers.max_cells = 200;
|
||
client->pers.max_slugs = 50;
|
||
|
||
// RAFAEL
|
||
client->pers.max_magslug = 50;
|
||
client->pers.max_trap = 5;
|
||
|
||
ent->client->pers.connected = false;
|
||
gi.dprintf ("%s connected\n", ent->client->pers.netname);
|
||
// gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
|
||
|
||
if (ctf->value) gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
|
||
client->pers.netname, CTFTeamName(ent->client->resp.ctf_team));
|
||
else gi.bprintf (PRINT_HIGH, "%s entered the game\n",
|
||
client->pers.netname);
|
||
}
|
||
|
||
void PutBotInServer (edict_t *ent)
|
||
{
|
||
static edict_t *touch[MAX_EDICTS]; // Knightmare- made static due to stack size
|
||
int i, j, entcount;
|
||
gitem_t *item;
|
||
gclient_t *client;
|
||
vec3_t spawn_origin, spawn_angles;
|
||
trace_t rs_trace;
|
||
zgcl_t *zc;
|
||
|
||
zc = &ent->client->zc;
|
||
|
||
//test
|
||
// item = FindItem("Trap");
|
||
// ent->client->pers.inventory[ITEM_INDEX(item)] = 100;
|
||
//test
|
||
|
||
//current weapon
|
||
client = ent->client;
|
||
item = Fdi_BLASTER; // FindItem("Blaster");
|
||
client->pers.selected_item = ITEM_INDEX(item);
|
||
client->pers.inventory[client->pers.selected_item] = 1;
|
||
client->pers.weapon = item;
|
||
client->silencer_shots = 0;
|
||
client->weaponstate = WEAPON_READY;
|
||
client->newweapon = NULL;
|
||
|
||
//clear powerups
|
||
client->quad_framenum = 0;
|
||
client->invincible_framenum = 0;
|
||
client->breather_framenum = 0;
|
||
client->enviro_framenum = 0;
|
||
client->grenade_blew_up = false;
|
||
client->grenade_time = 0;
|
||
|
||
j = zc->botindex;
|
||
i = zc->routeindex;
|
||
memset (&client->zc,0,sizeof(zgcl_t));
|
||
zc->botindex = j;
|
||
zc->routeindex = i;
|
||
|
||
//ZOID
|
||
client->ctf_grapple = NULL;
|
||
|
||
item = FindItem("Grapple");
|
||
if (ctf->value) client->pers.inventory[ITEM_INDEX(item)] = 1; //ponpoko
|
||
//ZOID
|
||
|
||
// clear entity values
|
||
ent->classname = "player";
|
||
ent->movetype = MOVETYPE_STEP;
|
||
ent->solid = SOLID_BBOX;
|
||
ent->model = "players/male/tris.md2";
|
||
VectorSet (ent->mins, -16, -16, -24);
|
||
VectorSet (ent->maxs, 16, 16, 32);
|
||
|
||
ent->health = ent->client->pers.health;
|
||
ent->max_health = ent->client->pers.max_health;
|
||
ent->gib_health = -40;
|
||
|
||
ent->mass = 200;
|
||
ent->target_ent = NULL;
|
||
ent->s.frame = 0;
|
||
|
||
// clear entity state values
|
||
ent->s.modelindex = MAX_MODELS-1; // will use the skin specified model
|
||
ent->s.skinnum = ent - g_edicts - 1;
|
||
ShowGun(ent); // ### Hentai ### special gun model
|
||
|
||
ent->s.sound = 0;
|
||
|
||
ent->monsterinfo.scale = MODEL_SCALE;
|
||
|
||
ent->pain = player_pain;
|
||
ent->die = player_die;
|
||
ent->touch = NULL;
|
||
|
||
ent->moveinfo.decel = level.time;
|
||
ent->pain_debounce_time = level.time;
|
||
ent->targetname = NULL;
|
||
|
||
ent->moveinfo.speed = 1.0; //<2F>W<EFBFBD><57><EFBFBD><EFBFBD><EFBFBD>v<EFBFBD><76><EFBFBD>̈ړ<CC88><DA93><EFBFBD><EFBFBD>ɂ<C982><C282>Ēlj<C492>
|
||
ent->moveinfo.state = GETTER; //CTF<54>X<EFBFBD>e<EFBFBD>[<5B>^<5E>X<EFBFBD><58><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
ent->prethink = NULL;
|
||
ent->think = Bot_Think;
|
||
ent->nextthink = level.time + FRAMETIME;
|
||
ent->svflags /*|*/= SVF_MONSTER ;
|
||
ent->s.renderfx = 0;
|
||
ent->s.effects = 0;
|
||
|
||
SelectSpawnPoint (ent, spawn_origin, spawn_angles);
|
||
VectorCopy (spawn_origin, ent->s.origin);
|
||
VectorCopy (spawn_angles, ent->s.angles);
|
||
spawn_origin[2] -= 300;
|
||
rs_trace = gi.trace(ent->s.origin,ent->mins,ent->maxs,spawn_origin,ent,MASK_SOLID);
|
||
if (!rs_trace.allsolid) VectorCopy (rs_trace.endpos, ent->s.origin);
|
||
VectorSet(ent->velocity,0,0,0);
|
||
ent->moveinfo.speed = 0;
|
||
ent->groundentity = rs_trace.ent;
|
||
ent->client->ps.pmove.pm_flags &= ~PMF_DUCKED;
|
||
|
||
Set_BotAnim(ent,ANIM_BASIC,FRAME_run1,FRAME_run6);
|
||
client->anim_run = true;
|
||
|
||
ent->client->ctf_grapple = NULL;
|
||
ent->client->quad_framenum = level.framenum;
|
||
ent->client->invincible_framenum = level.framenum;
|
||
ent->client->enviro_framenum = level.framenum;
|
||
ent->client->breather_framenum = level.framenum;
|
||
ent->client->weaponstate = WEAPON_READY;
|
||
ent->takedamage = DAMAGE_AIM;
|
||
ent->air_finished = level.time + 12;
|
||
ent->clipmask = MASK_PLAYERSOLID;//MASK_MONSTERSOLID;
|
||
ent->flags &= ~FL_NO_KNOCKBACK;
|
||
|
||
ent->client->anim_priority = ANIM_BASIC;
|
||
// ent->client->anim_run = true;
|
||
ent->s.frame = FRAME_run1-1;
|
||
ent->client->anim_end = FRAME_run6;
|
||
ent->deadflag = DEAD_NO;
|
||
ent->svflags &= ~SVF_DEADMONSTER;
|
||
|
||
zc->waitin_obj = NULL;
|
||
zc->first_target = NULL;
|
||
zc->first_target = NULL;
|
||
zc->zcstate = STS_IDLE;
|
||
|
||
if (ent->client->resp.enterframe == level.framenum && !chedit->value)
|
||
{
|
||
gi.WriteByte (svc_muzzleflash);
|
||
gi.WriteShort (ent-g_edicts);
|
||
gi.WriteByte (MZ_LOGIN);
|
||
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
||
}
|
||
else if (!chedit->value)
|
||
{
|
||
gi.WriteByte (svc_muzzleflash);
|
||
gi.WriteShort (ent-g_edicts);
|
||
gi.WriteByte (MZ_RESPAWN);
|
||
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
||
}
|
||
gi.linkentity (ent);
|
||
VectorAdd (spawn_origin, ent->mins, ent->absmin);
|
||
VectorAdd (spawn_origin, ent->maxs, ent->absmax);
|
||
entcount = gi.BoxEdicts ( ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID);
|
||
while (entcount-- > 0)
|
||
{
|
||
if (Q_stricmp (touch[entcount]->classname, "player") == 0)
|
||
if (touch[entcount] != ent)
|
||
T_Damage (touch[entcount], ent, ent, vec3_origin, touch[entcount]->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
|
||
}
|
||
|
||
if (ctf->value)
|
||
{
|
||
CTFPlayerResetGrapple(ent);
|
||
client->zc.ctfstate = CTFS_OFFENCER;
|
||
}
|
||
|
||
|
||
gi.linkentity (ent);
|
||
G_TouchTriggers (ent);
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Spawn Bot
|
||
//
|
||
// spawn bots
|
||
//
|
||
// int i index of bot list
|
||
//
|
||
//----------------------------------------------------------------
|
||
|
||
qboolean SpawnBot(int i)
|
||
{
|
||
edict_t *bot,*ent;
|
||
int k,j;
|
||
|
||
|
||
//gi.cprintf (NULL,PRINT_HIGH,"Called %s %s %s\n",Bot[i].netname,Bot[i].model,Bot[i].skin);
|
||
//return false;
|
||
|
||
if ( Get_NumOfPlayer () >= game.maxclients )
|
||
{
|
||
gi.cprintf (NULL,PRINT_HIGH,"Can't add bots\n");
|
||
return false;
|
||
}
|
||
|
||
bot = Get_NewClient();
|
||
if (bot == NULL) return false;
|
||
|
||
InitializeBot( bot , i);
|
||
PutBotInServer ( bot );
|
||
|
||
j = targetindex;
|
||
if (chedit->value)
|
||
{
|
||
for(k = CurrentIndex - 1;k > 0 ;k--)
|
||
{
|
||
if (Route[k].index == 0) break;
|
||
|
||
if (Route[k].state == GRS_NORMAL)
|
||
{
|
||
if (--j <= 0) break;
|
||
}
|
||
}
|
||
|
||
bot->client->zc.rt_locktime = level.time + FRAMETIME * 20;
|
||
bot->client->zc.route_trace = true;
|
||
bot->client->zc.routeindex = k;
|
||
VectorCopy(Route[k].Pt,bot->s.origin);
|
||
VectorAdd (bot->s.origin, bot->mins, bot->absmin);
|
||
VectorAdd (bot->s.origin, bot->maxs, bot->absmax);
|
||
bot->client->ps.pmove.pm_flags |= PMF_DUCKED;
|
||
gi.linkentity (bot);
|
||
// bot->s.modelindex = 0;
|
||
|
||
gi.WriteByte (svc_muzzleflash);
|
||
gi.WriteShort (bot-g_edicts);
|
||
gi.WriteByte (MZ_LOGIN);
|
||
gi.multicast (bot->s.origin, MULTICAST_PVS);
|
||
|
||
ent = &g_edicts[1];
|
||
if (ent->inuse && ent->client && !(ent->svflags & SVF_MONSTER))
|
||
{
|
||
ent->takedamage = DAMAGE_NO;
|
||
ent->movetype = MOVETYPE_NOCLIP;
|
||
ent->target_ent = bot;
|
||
ent->solid = SOLID_NOT;
|
||
ent->client->ps.pmove.pm_type = PM_FREEZE;
|
||
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION ;
|
||
VectorCopy(ent->s.origin,ent->moveinfo.start_origin);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Spawn Call
|
||
//
|
||
// spawn bots
|
||
//
|
||
// int i index of bot list
|
||
//
|
||
//----------------------------------------------------------------
|
||
void Bot_SpawnCall()
|
||
{
|
||
int i;
|
||
|
||
for(i = 0;i < MAXBOTS;i++)
|
||
{
|
||
if (Bot[i].spflg == BOT_SPRESERVED)
|
||
{
|
||
if (SpawnBot(i)) Bot[i].spflg = BOT_SPAWNED;
|
||
else
|
||
{
|
||
Bot[i].spflg = BOT_SPAWNNOT;
|
||
targetindex = 0;
|
||
}
|
||
SpawnWaitingBots--;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
//----------------------------------------------------------------
|
||
//Spawn Bot Reserving
|
||
//
|
||
// spawn bots reserving
|
||
//
|
||
//----------------------------------------------------------------
|
||
void SpawnBotReserving()
|
||
{
|
||
int i;
|
||
|
||
for(i = 0;i < MAXBOTS; i++)
|
||
{
|
||
if (Bot[i].spflg == BOT_SPAWNNOT)
|
||
{
|
||
Bot[i].spflg = BOT_SPRESERVED;
|
||
SpawnWaitingBots++;
|
||
return;
|
||
}
|
||
}
|
||
gi.cprintf (NULL, PRINT_HIGH, "Now max of bots(%i) already spawned.\n",MAXBOTS);
|
||
}
|
||
//----------------------------------------------------------------
|
||
//Spawn Bot Reserving 2
|
||
//
|
||
// randomized spawn bots reserving
|
||
//
|
||
//----------------------------------------------------------------
|
||
void SpawnBotReserving2(int *red,int *blue)
|
||
{
|
||
int i,j;
|
||
|
||
j = (int)(random() * ListedBots);
|
||
|
||
for(i = 0;i < ListedBots; i++,j++)
|
||
{
|
||
if (j >= ListedBots) j = 0;
|
||
if (Bot[j].spflg == BOT_SPAWNNOT)
|
||
{
|
||
Bot[j].spflg = BOT_SPRESERVED;
|
||
SpawnWaitingBots++;
|
||
if (*red > *blue) Bot[j].team = 2;
|
||
else Bot[j].team = 1;
|
||
|
||
if (Bot[j].team == 1) *red = *red + 1;
|
||
else if (Bot[j].team == 2) *blue = *blue + 1;
|
||
//gi.cprintf(NULL,PRINT_HIGH,"team %i\n",Bot[j].team);
|
||
return;
|
||
}
|
||
}
|
||
SpawnBotReserving();
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Remove Bot
|
||
//
|
||
// remove bots
|
||
//
|
||
// int i index of bot list
|
||
//
|
||
//----------------------------------------------------------------
|
||
void RemoveBot()
|
||
{
|
||
int i;
|
||
int botindex;
|
||
edict_t *e,*ent;
|
||
gclient_t *client;
|
||
|
||
for(i = MAXBOTS - 1;i >= 0;i--)
|
||
{
|
||
if (Bot[i].spflg == BOT_SPAWNED || Bot[i].spflg == BOT_NEXTLEVEL)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i < 0)
|
||
{
|
||
gi.cprintf (NULL, PRINT_HIGH, "No Bots in server.");
|
||
return;
|
||
}
|
||
|
||
botindex = i;
|
||
|
||
e = &g_edicts[(int)maxclients->value];
|
||
for ( i = maxclients->value ; i >= 1 ; i--, e--)
|
||
{
|
||
if (!e->inuse) continue;
|
||
client = /*e->client;*/&game.clients[i - 1];
|
||
if (client == NULL) continue;
|
||
// the first couple seconds of server time can involve a lot of
|
||
// freeing and allocating, so relax the replacement policy
|
||
if (!client->pers.connected && (e->svflags & SVF_MONSTER))
|
||
{
|
||
if (client->zc.botindex == botindex)
|
||
{
|
||
if (Bot[botindex].spflg != BOT_NEXTLEVEL) Bot[botindex].spflg = BOT_SPAWNNOT;
|
||
else Bot[botindex].spflg = BOT_SPRESERVED;
|
||
|
||
gi.bprintf (PRINT_HIGH, "%s disconnected\n", e->client->pers.netname);
|
||
|
||
// send effect
|
||
gi.WriteByte (svc_muzzleflash);
|
||
gi.WriteShort (e-g_edicts);
|
||
gi.WriteByte (MZ_LOGOUT);
|
||
gi.multicast (e->s.origin, MULTICAST_PVS);
|
||
|
||
e->s.modelindex = 0;
|
||
e->solid = SOLID_NOT;
|
||
|
||
if (ctf->value) {
|
||
CTFPlayerResetGrapple(e);
|
||
// Fix by Bouman- drop flag and tech on bot removal
|
||
CTFDeadDropFlag(e);
|
||
CTFDeadDropTech(e);
|
||
// end Bouman fix
|
||
}
|
||
|
||
gi.linkentity (e);
|
||
|
||
e->inuse = false;
|
||
G_FreeEdict (e);
|
||
|
||
if (targetindex)
|
||
{
|
||
ent = &g_edicts[1];
|
||
|
||
if (ent->inuse)
|
||
{
|
||
ent->health = 100;
|
||
ent->movetype = MOVETYPE_WALK;
|
||
ent->takedamage = DAMAGE_AIM;
|
||
ent->target_ent = NULL;
|
||
ent->solid = SOLID_BBOX;
|
||
ent->client->ps.pmove.pm_type = PM_NORMAL;
|
||
ent->client->ps.pmove.pm_flags = PMF_DUCKED;
|
||
VectorCopy(ent->moveinfo.start_origin,ent->s.origin);
|
||
VectorCopy(ent->moveinfo.start_origin,ent->s.old_origin);
|
||
}
|
||
targetindex = 0;
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
gi.error ("Can't remove bot.");
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
//Level Change Removing
|
||
//
|
||
//
|
||
//
|
||
//----------------------------------------------------------------
|
||
void Bot_LevelChange()
|
||
{
|
||
int i,j,k;
|
||
|
||
j = 0,k = 0;
|
||
|
||
for(i = 0;i < MAXBOTS;i++)
|
||
{
|
||
if (Bot[i].spflg)
|
||
{
|
||
if (Bot[i].spflg == BOT_SPAWNED)
|
||
{
|
||
k++;
|
||
Bot[i].spflg = BOT_NEXTLEVEL;
|
||
}
|
||
j++;
|
||
}
|
||
}
|
||
for(i = 0;i < k; i++)
|
||
{
|
||
RemoveBot();
|
||
}
|
||
|
||
SpawnWaitingBots = k;//j;
|
||
}
|
||
//----------------------------------------------------------------
|
||
//
|
||
// Ragomode menu
|
||
//
|
||
void ZigockClientJoin(edict_t *ent,int zclass)
|
||
{
|
||
PMenu_Close(ent);
|
||
|
||
ent->moveinfo.sound_end = CLS_ALPHA; //PutClient<6E>̑O<CC91>ɃN<C983><4E><EFBFBD>X<EFBFBD><58><EFBFBD><EFBFBD>
|
||
|
||
ent->svflags &= ~SVF_NOCLIENT;
|
||
PutClientInServer (ent);
|
||
// add a teleportation effect
|
||
ent->s.event = EV_PLAYER_TELEPORT;
|
||
// hold in place briefly
|
||
ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
|
||
ent->client->ps.pmove.pm_time = 14;
|
||
|
||
if (ctf->value)
|
||
{
|
||
gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
|
||
ent->client->pers.netname, CTFTeamName(ent->client->resp.ctf_team/*desired_team*/));
|
||
}
|
||
}
|
||
void ClientJoinAsAlpha(edict_t *ent,pmenu_t *entries)
|
||
{
|
||
ZigockClientJoin(ent,1);
|
||
}
|
||
|
||
pmenu_t zgjoinmenu[] = {
|
||
{ "*Quake II", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*3rd Zigock Rago", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "alpha", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ "beta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ "gamma", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ "delta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ "epsilon", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ "zeta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ "eta", PMENU_ALIGN_LEFT, NULL, ClientJoinAsAlpha },
|
||
{ NULL, PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "Use [ and ] to move cursor", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "ENTER to select class", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "ESC to Exit Menu", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "(TAB to Return)", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
};
|
||
|
||
void ZigockJoinMenu(edict_t *ent)
|
||
{
|
||
PMenu_Open(ent, zgjoinmenu,4, sizeof(zgjoinmenu) / sizeof(pmenu_t));
|
||
}
|
||
|
||
qboolean ZigockStartClient(edict_t *ent)
|
||
{
|
||
if (ent->moveinfo.sound_end != CLS_NONE)
|
||
return false;
|
||
|
||
// start as 'observer'
|
||
ent->movetype = MOVETYPE_NOCLIP;
|
||
ent->solid = SOLID_NOT;
|
||
ent->svflags |= SVF_NOCLIENT;
|
||
ent->client->ps.gunindex = 0;
|
||
gi.linkentity (ent);
|
||
|
||
ZigockJoinMenu(ent);
|
||
return true;
|
||
}
|
||
|
||
|
||
//===============================
|
||
|
||
// AirStrike
|
||
|
||
//===============================
|
||
static void AirSight_Explode (edict_t *ent)
|
||
{
|
||
vec3_t origin;
|
||
int mod;
|
||
|
||
// if (ent->owner->client && !(ent->owner->svflags & SVF_DEADMONSTER))
|
||
// PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
|
||
|
||
gi.sound (ent, CHAN_AUTO, gi.soundindex("3zb/airexp.wav"), 1, ATTN_NONE, 0);
|
||
|
||
//FIXME: if we are onground then raise our Z just a bit since we are a point?
|
||
mod = MOD_AIRSTRIKE;
|
||
|
||
T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
|
||
|
||
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
|
||
gi.WriteByte (svc_temp_entity);
|
||
if (ent->waterlevel)
|
||
{
|
||
gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
|
||
}
|
||
else
|
||
{
|
||
gi.WriteByte (TE_ROCKET_EXPLOSION);
|
||
}
|
||
gi.WritePosition (origin);
|
||
gi.multicast (ent->s.origin, MULTICAST_PHS);
|
||
|
||
G_FreeEdict (ent);
|
||
}
|
||
|
||
void AirSight_Think(edict_t *ent)
|
||
{
|
||
// gi.sound (ent, CHAN_AUTO, gi.soundindex("medic/medatck1.wav"), 1, ATTN_NORM, 0);
|
||
gi.sound (ent, CHAN_BODY, gi.soundindex("3zb/airloc.wav"), 1, ATTN_NONE, 0);
|
||
|
||
ent->dmg = 120 + random() * 60;
|
||
ent->dmg_radius = 200;
|
||
|
||
ent->s.modelindex = gi.modelindex ("sprites/airsight.sp2");
|
||
VectorCopy(ent->target_ent->s.origin,ent->s.origin);
|
||
|
||
if ( ent->owner->client->resp.ctf_team == CTF_TEAM2 && ctf->value)
|
||
{
|
||
ent->s.frame = 1;
|
||
}
|
||
else ent->s.frame = 0;
|
||
|
||
ent->think = AirSight_Explode;
|
||
ent->nextthink = level.time + FRAMETIME * 6;
|
||
gi.linkentity (ent);
|
||
}
|
||
void AirStrike_Think(edict_t *ent)
|
||
{
|
||
int i,j;
|
||
edict_t *target,*sight;
|
||
trace_t rs_trace;
|
||
|
||
vec3_t point;
|
||
|
||
ent->nextthink = level.time + ent->moveinfo.speed * 0.5 /300;
|
||
ent->think = G_FreeEdict;
|
||
// ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
|
||
|
||
VectorCopy(ent->s.origin,point);
|
||
point[2] = ent->moveinfo.start_angles[2];
|
||
|
||
j = 1;
|
||
for ( i = 1 ; i <= maxclients->value; i++)
|
||
{
|
||
target = &g_edicts[i];
|
||
if (!target->inuse || target->deadflag || target == ent->owner) continue;
|
||
|
||
if ( target->classname[0] == 'p')
|
||
{
|
||
//ctf <20>Ȃ<EFBFBD><C882>`<60>[<5B><><EFBFBD><EFBFBD><EFBFBD>C<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD>
|
||
if (!ctf->value || (ctf->value && ent->owner->client->resp.ctf_team != target->client->resp.ctf_team))
|
||
{
|
||
rs_trace = gi.trace (point,NULL,NULL,target->s.origin,ent, CONTENTS_SOLID | CONTENTS_WINDOW | CONTENTS_LAVA | CONTENTS_SLIME);
|
||
|
||
if (rs_trace.fraction == 1.0)
|
||
{
|
||
sight = G_Spawn();
|
||
|
||
sight->classname = "airstrike";
|
||
sight->think = AirSight_Think;
|
||
sight->nextthink = level.time + FRAMETIME * 2 * (float)j;
|
||
sight->movetype = MOVETYPE_NOCLIP;
|
||
sight->solid = SOLID_NOT;
|
||
sight->owner = ent->owner;
|
||
sight->target_ent = target;
|
||
gi.linkentity (sight);
|
||
j++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
void Cmd_AirStrike(edict_t *ent)
|
||
{
|
||
edict_t *viper;
|
||
trace_t rs_trace;
|
||
|
||
vec3_t strpoint,tts,tte,tmp;
|
||
|
||
vec_t f;
|
||
|
||
VectorCopy(ent->s.origin,strpoint);
|
||
strpoint[2] += 8190;
|
||
|
||
rs_trace = gi.trace (ent->s.origin,NULL,NULL,strpoint,ent, MASK_SHOT);
|
||
|
||
if (!(rs_trace.surface && (rs_trace.surface->flags & SURF_SKY)))
|
||
{
|
||
gi.cprintf(ent,PRINT_HIGH,"can't call Viper.\n");
|
||
return;
|
||
}
|
||
/* if ((rs_trace.endpos[2] - ent->s.origin[2]) < 300)
|
||
{
|
||
gi.cprintf(ent,PRINT_HIGH,"can't call Viper.\n");
|
||
}*/
|
||
|
||
VectorCopy(rs_trace.endpos,strpoint);
|
||
strpoint[2] -= 16; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ւ<EFBFBD><D682>炷
|
||
|
||
f = ent->s.angles[YAW]*M_PI*2 / 360;
|
||
tts[0] = cos(f) * (-8190) ;
|
||
tts[1] = sin(f) * (-8190) ;
|
||
tts[2] = 0;
|
||
|
||
tte[0] = cos(f) *8190 ;
|
||
tte[1] = sin(f) *8190 ;
|
||
tte[2] = 0;
|
||
|
||
viper = G_Spawn();
|
||
VectorClear (viper->mins);
|
||
VectorClear (viper->maxs);
|
||
viper->movetype = /*MOVETYPE_FLYMISSILE;//MOVETYPE_STEP;*/MOVETYPE_NOCLIP;
|
||
viper->solid = SOLID_NOT;
|
||
viper->owner = ent;
|
||
viper->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2");
|
||
|
||
VectorCopy(ent->s.angles,viper->s.angles);
|
||
viper->s.angles[2] = 0;
|
||
rs_trace = gi.trace (strpoint,NULL,NULL,tts,ent, MASK_SHOT);
|
||
tts[0] = cos(f) * (-600) ;
|
||
tts[1] = sin(f) * (-600) ;
|
||
VectorAdd(rs_trace.endpos,tts,tmp);
|
||
VectorCopy(tmp,viper->s.origin);
|
||
|
||
|
||
viper->velocity[0] = cos(f) * 300;
|
||
viper->velocity[1] = sin(f) * 300;
|
||
viper->velocity[2] = 0;
|
||
|
||
rs_trace = gi.trace (strpoint,NULL,NULL,tte,ent, MASK_SHOT);
|
||
VectorSubtract(viper->s.origin,rs_trace.endpos,tts);
|
||
f = VectorLength(tts);
|
||
|
||
gi.sound (viper, CHAN_AUTO, gi.soundindex("world/flyby1.wav"), 1, ATTN_NONE, 0);
|
||
|
||
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/incoming.wav"), 1, ATTN_NONE, 0);
|
||
|
||
viper->nextthink = level.time + f *0.75 /300;
|
||
viper->think = AirStrike_Think;
|
||
viper->moveinfo.speed = f;
|
||
|
||
// viper->s.sound = gi.soundindex ("weapons/rockfly.wav");
|
||
|
||
// viper->s.effects |= EF_ROTATE | EF_COLOR_SHELL;
|
||
// viper->s.renderfx |= RF_SHELL_BLUE | RF_SHELL_GREEN;
|
||
VectorCopy(strpoint,viper->moveinfo.start_angles); //strikepoint
|
||
|
||
// viper->think = Pod_think;
|
||
// viper->nextthink = level.time + FRAMETIME;
|
||
viper->classname = "viper";
|
||
viper->s.origin[2] += 16;
|
||
gi.linkentity (viper);
|
||
}
|
||
|