📄 p_client.c
字号:
self->s.frame = FRAME_death201-1;
self->client->anim_end = FRAME_death206;
break;
case 2:
self->s.frame = FRAME_death301-1;
self->client->anim_end = FRAME_death308;
break;
}
gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
}
}
self->deadflag = DEAD_DEAD;
gi.linkentity (self);
}
//=======================================================================
/*
==============
InitClientPersistant
This is only called when the game first initializes in single player,
but is called after each death and level change in deathmatch
==============
*/
void InitClientPersistant (gclient_t *client)
{
gitem_t *item;
memset (&client->pers, 0, sizeof(client->pers));
item = FindItem("Blaster");
client->pers.selected_item = ITEM_INDEX(item);
client->pers.inventory[client->pers.selected_item] = 1;
client->pers.weapon = item;
//ZOID
client->pers.lastweapon = item;
//ZOID
//ZOID
item = FindItem("Grapple");
client->pers.inventory[ITEM_INDEX(item)] = 1;
//ZOID
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;
client->pers.connected = true;
}
void InitClientResp (gclient_t *client)
{
//ZOID
int ctf_team = client->resp.ctf_team;
qboolean id_state = client->resp.id_state;
//ZOID
memset (&client->resp, 0, sizeof(client->resp));
//ZOID
client->resp.ctf_team = ctf_team;
client->resp.id_state = id_state;
//ZOID
client->resp.enterframe = level.framenum;
client->resp.coop_respawn = client->pers;
//ZOID
if (ctf->value && client->resp.ctf_team < CTF_TEAM1)
CTFAssignTeam(client);
//ZOID
}
/*
==================
SaveClientData
Some information that should be persistant, like health,
is still stored in the edict structure, so it needs to
be mirrored out to the client structure before all the
edicts are wiped.
==================
*/
void SaveClientData (void)
{
int i;
edict_t *ent;
for (i=0 ; i<game.maxclients ; i++)
{
ent = &g_edicts[1+i];
if (!ent->inuse)
continue;
game.clients[i].pers.health = ent->health;
game.clients[i].pers.max_health = ent->max_health;
game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE|FL_NOTARGET|FL_POWER_ARMOR));
if (coop->value)
game.clients[i].pers.score = ent->client->resp.score;
}
}
void FetchClientEntData (edict_t *ent)
{
ent->health = ent->client->pers.health;
ent->max_health = ent->client->pers.max_health;
ent->flags |= ent->client->pers.savedFlags;
if (coop->value)
ent->client->resp.score = ent->client->pers.score;
}
/*
=======================================================================
SelectSpawnPoint
=======================================================================
*/
/*
================
PlayersRangeFromSpot
Returns the distance to the nearest player from the given spot
================
*/
float PlayersRangeFromSpot (edict_t *spot)
{
edict_t *player;
float bestplayerdistance;
vec3_t v;
int n;
float playerdistance;
bestplayerdistance = 9999999;
for (n = 1; n <= maxclients->value; n++)
{
player = &g_edicts[n];
if (!player->inuse)
continue;
if (player->health <= 0)
continue;
VectorSubtract (spot->s.origin, player->s.origin, v);
playerdistance = VectorLength (v);
if (playerdistance < bestplayerdistance)
bestplayerdistance = playerdistance;
}
return bestplayerdistance;
}
/*
================
SelectRandomDeathmatchSpawnPoint
go to a random point, but NOT the two points closest
to other players
================
*/
edict_t *SelectRandomDeathmatchSpawnPoint (void)
{
edict_t *spot, *spot1, *spot2;
int count = 0;
int selection;
float range, range1, range2;
spot = NULL;
range1 = range2 = 99999;
spot1 = spot2 = NULL;
while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
{
count++;
range = PlayersRangeFromSpot(spot);
if (range < range1)
{
range1 = range;
spot1 = spot;
}
else if (range < range2)
{
range2 = range;
spot2 = spot;
}
}
if (!count)
return NULL;
if (count <= 2)
{
spot1 = spot2 = NULL;
}
else
count -= 2;
selection = rand() % count;
spot = NULL;
do
{
spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
if (spot == spot1 || spot == spot2)
selection++;
} while(selection--);
return spot;
}
/*
================
SelectFarthestDeathmatchSpawnPoint
================
*/
edict_t *SelectFarthestDeathmatchSpawnPoint (void)
{
edict_t *bestspot;
float bestdistance, bestplayerdistance;
edict_t *spot;
spot = NULL;
bestspot = NULL;
bestdistance = 0;
while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
{
bestplayerdistance = PlayersRangeFromSpot (spot);
if (bestplayerdistance > bestdistance)
{
bestspot = spot;
bestdistance = bestplayerdistance;
}
}
if (bestspot)
{
return bestspot;
}
// if there is a player just spawned on each and every start spot
// we have no choice to turn one into a telefrag meltdown
spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
return spot;
}
edict_t *SelectDeathmatchSpawnPoint (void)
{
if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
return SelectFarthestDeathmatchSpawnPoint ();
else
return SelectRandomDeathmatchSpawnPoint ();
}
edict_t *SelectCoopSpawnPoint (edict_t *ent)
{
int index;
edict_t *spot = NULL;
char *target;
index = ent->client - game.clients;
// player 0 starts in normal player spawn point
if (!index)
return NULL;
spot = NULL;
// assume there are four coop spots at each spawnpoint
while (1)
{
spot = G_Find (spot, FOFS(classname), "info_player_coop");
if (!spot)
return NULL; // we didn't have enough...
target = spot->targetname;
if (!target)
target = "";
if ( Q_stricmp(game.spawnpoint, target) == 0 )
{ // this is a coop spawn point for one of the clients here
index--;
if (!index)
return spot; // this is it
}
}
return spot;
}
/*
===========
SelectSpawnPoint
Chooses a player start, deathmatch start, coop start, etc
============
*/
void SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
{
edict_t *spot = NULL;
if (deathmatch->value)
//ZOID
if (ctf->value)
spot = SelectCTFSpawnPoint(ent);
else
//ZOID
spot = SelectDeathmatchSpawnPoint ();
else if (coop->value)
spot = SelectCoopSpawnPoint (ent);
// find a single player start spot
if (!spot)
{
while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
{
if (!game.spawnpoint[0] && !spot->targetname)
break;
if (!game.spawnpoint[0] || !spot->targetname)
continue;
if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
break;
}
if (!spot)
{
if (!game.spawnpoint[0])
{ // there wasn't a spawnpoint without a target, so use any
spot = G_Find (spot, FOFS(classname), "info_player_start");
}
if (!spot)
gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
}
}
VectorCopy (spot->s.origin, origin);
origin[2] += 9;
VectorCopy (spot->s.angles, angles);
}
//======================================================================
void InitBodyQue (void)
{
int i;
edict_t *ent;
level.body_que = 0;
for (i=0; i<BODY_QUEUE_SIZE ; i++)
{
ent = G_Spawn();
ent->classname = "bodyque";
}
}
void body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
if (self->health < -40)
{
gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n= 0; n < 4; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
self->s.origin[2] -= 48;
ThrowClientHead (self, damage);
self->takedamage = DAMAGE_NO;
}
}
void CopyToBodyQue (edict_t *ent)
{
edict_t *body;
// grab a body que and cycle to the next one
body = &g_edicts[(int)maxclients->value + level.body_que + 1];
level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
// FIXME: send an effect on the removed body
gi.unlinkentity (ent);
gi.unlinkentity (body);
body->s = ent->s;
body->s.number = body - g_edicts;
body->svflags = ent->svflags;
VectorCopy (ent->mins, body->mins);
VectorCopy (ent->maxs, body->maxs);
VectorCopy (ent->absmin, body->absmin);
VectorCopy (ent->absmax, body->absmax);
VectorCopy (ent->size, body->size);
body->solid = ent->solid;
body->clipmask = ent->clipmask;
body->owner = ent->owner;
body->movetype = ent->movetype;
body->die = body_die;
body->takedamage = DAMAGE_YES;
gi.linkentity (body);
}
void respawn (edict_t *self)
{
if (deathmatch->value || coop->value)
{
if (self->movetype != MOVETYPE_NOCLIP)
CopyToBodyQue (self);
self->svflags &= ~SVF_NOCLIENT;
PutClientInServer (self);
// add a teleportation effect
self->s.event = EV_PLAYER_TELEPORT;
// hold in place briefly
self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
self->client->ps.pmove.pm_time = 14;
self->client->respawn_time = level.time;
return;
}
// restart the entire server
gi.AddCommandString ("menu_loadgame\n");
}
//==============================================================
/*
===========
PutClientInServer
Called when a player connects to a server or respawns in
a deathmatch.
============
*/
void PutClientInServer (edict_t *ent)
{
vec3_t mins = {-16, -16, -24};
vec3_t maxs = {16, 16, 32};
int index;
vec3_t spawn_origin, spawn_angles;
gclient_t *client;
int i;
client_persistant_t saved;
client_respawn_t resp;
// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
SelectSpawnPoint (ent, spawn_origin, spawn_angles);
index = ent-g_edicts-1;
client = ent->client;
// deathmatch wipes most client data every spawn
if (deathmatch->value)
{
char userinfo[MAX_INFO_STRING];
resp = client->resp;
memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
InitClientPersistant (client);
ClientUserinfoChanged (ent, userinfo);
}
else if (coop->value)
{
int n;
char userinfo[MAX_INFO_STRING];
resp = client->resp;
memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
// this is kind of ugly, but it's how we want to handle keys in coop
for (n = 0; n < MAX_ITEMS; n++)
{
if (itemlist[n].flags & IT_KEY)
resp.coop_respawn.inventory[n] = client->pers.inventory[n];
}
client->pers = resp.coop_respawn;
ClientUserinfoChanged (ent, userinfo);
if (resp.score > client->pers.score)
client->pers.score = resp.score;
}
else
{
memset (&resp, 0, sizeof(resp));
}
// clear everything but the persistant data
saved = client->pers;
memset (client, 0, sizeof(*client));
client->pers = saved;
if (client->pers.health <= 0)
InitClientPersistant(client);
client->resp = resp;
// copy some data from the client to the entity
FetchClientEntData (ent);
// clear entity values
ent->groundentity = NULL;
ent->client = &game.clients[index];
ent->takedamage = DAMAGE_AIM;
ent->movetype = MOVETYPE_WALK;
ent->viewheight = 22;
ent->inuse = true;
ent->classname = "player";
ent->mass = 200;
ent->solid = SOLID_BBOX;
ent->deadflag = DEAD_NO;
ent->air_finished = level.time + 12;
ent->clipmask = MASK_PLAYERSOLID;
ent->model = "players/male/tris.md2";
ent->pain = player_pain;
ent->die = player_die;
ent->waterlevel = 0;
ent->watertype = 0;
ent->flags &= ~FL_NO_KNOCKBACK;
ent->svflags &= ~SVF_DEADMONSTER;
VectorCopy (mins, ent->mins);
VectorCopy (maxs, ent->maxs);
VectorClear (ent->velocity);
// clear playerstate values
memset (&ent->client->ps, 0, sizeof(client->ps));
client->ps.pmove.origin[0] = spawn_origin[0]*8;
client->ps.pmove.origin[1] = spawn_origin[1]*8;
client->ps.pmove.origin[2] = spawn_origin[2]*8;
//ZOID
client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
//ZOID
if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
{
client->ps.fov = 90;
}
else
{
client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
if (client->ps.fov < 1)
client->ps.fov = 90;
else if (client->ps.fov > 160)
client->ps.fov = 160;
}
client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
// clear entity state values
ent->s.effects = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -