📄 p_client.c
字号:
/*
Copyright (C) 1997-2001 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "g_local.h"
#include "m_player.h"
void SP_misc_teleporter_dest (edict_t *ent);
//
// Gross, ugly, disgustuing hack section
//
// this function is an ugly as hell hack to fix some map flaws
//
// the coop spawn spots on some maps are SNAFU. There are coop spots
// with the wrong targetname as well as spots with no name at all
//
// we use carnal knowledge of the maps to fix the coop spot targetnames to match
// that of the nearest named single player spot
static void SP_FixCoopSpots (edict_t *self)
{
edict_t *spot;
vec3_t d;
spot = NULL;
while(1)
{
spot = G_Find(spot, FOFS(classname), "info_player_start");
if (!spot)
return;
if (!spot->targetname)
continue;
VectorSubtract(self->s.origin, spot->s.origin, d);
if (VectorLength(d) < 384)
{
if ((!self->targetname) || stricmp(self->targetname, spot->targetname) != 0)
{
// gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
self->targetname = spot->targetname;
}
return;
}
}
}
// now if that one wasn't ugly enough for you then try this one on for size
// some maps don't have any coop spots at all, so we need to create them
// where they should have been
static void SP_CreateCoopSpots (edict_t *self)
{
edict_t *spot;
if(stricmp(level.mapname, "security") == 0)
{
spot = G_Spawn();
spot->classname = "info_player_coop";
spot->s.origin[0] = 188 - 64;
spot->s.origin[1] = -164;
spot->s.origin[2] = 80;
spot->targetname = "jail3";
spot->s.angles[1] = 90;
spot = G_Spawn();
spot->classname = "info_player_coop";
spot->s.origin[0] = 188 + 64;
spot->s.origin[1] = -164;
spot->s.origin[2] = 80;
spot->targetname = "jail3";
spot->s.angles[1] = 90;
spot = G_Spawn();
spot->classname = "info_player_coop";
spot->s.origin[0] = 188 + 128;
spot->s.origin[1] = -164;
spot->s.origin[2] = 80;
spot->targetname = "jail3";
spot->s.angles[1] = 90;
return;
}
}
/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
The normal starting point for a level.
*/
void SP_info_player_start(edict_t *self)
{
if (!coop->value)
return;
if(stricmp(level.mapname, "security") == 0)
{
// invoke one of our gross, ugly, disgusting hacks
self->think = SP_CreateCoopSpots;
self->nextthink = level.time + FRAMETIME;
}
}
/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
potential spawning position for deathmatch games
*/
void SP_info_player_deathmatch(edict_t *self)
{
if (!deathmatch->value)
{
G_FreeEdict (self);
return;
}
SP_misc_teleporter_dest (self);
}
/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
potential spawning position for coop games
*/
void SP_info_player_coop(edict_t *self)
{
if (!coop->value)
{
G_FreeEdict (self);
return;
}
if((stricmp(level.mapname, "jail2") == 0) ||
(stricmp(level.mapname, "jail4") == 0) ||
(stricmp(level.mapname, "mine1") == 0) ||
(stricmp(level.mapname, "mine2") == 0) ||
(stricmp(level.mapname, "mine3") == 0) ||
(stricmp(level.mapname, "mine4") == 0) ||
(stricmp(level.mapname, "lab") == 0) ||
(stricmp(level.mapname, "boss1") == 0) ||
(stricmp(level.mapname, "fact3") == 0) ||
(stricmp(level.mapname, "biggun") == 0) ||
(stricmp(level.mapname, "space") == 0) ||
(stricmp(level.mapname, "command") == 0) ||
(stricmp(level.mapname, "power2") == 0) ||
(stricmp(level.mapname, "strike") == 0))
{
// invoke one of our gross, ugly, disgusting hacks
self->think = SP_FixCoopSpots;
self->nextthink = level.time + FRAMETIME;
}
}
/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
The deathmatch intermission point will be at one of these
Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw. 'pitch yaw roll'
*/
void SP_info_player_intermission(void)
{
}
//=======================================================================
void player_pain (edict_t *self, edict_t *other, float kick, int damage)
{
// player pain is handled at the end of the frame in P_DamageFeedback
}
qboolean IsFemale (edict_t *ent)
{
char *info;
if (!ent->client)
return false;
info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
if (info[0] == 'f' || info[0] == 'F')
return true;
return false;
}
void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
{
int mod;
char *message;
char *message2;
qboolean ff;
if (coop->value && attacker->client)
meansOfDeath |= MOD_FRIENDLY_FIRE;
if (deathmatch->value || coop->value)
{
ff = meansOfDeath & MOD_FRIENDLY_FIRE;
mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
message = NULL;
message2 = "";
switch (mod)
{
case MOD_SUICIDE:
message = "suicides";
break;
case MOD_FALLING:
message = "cratered";
break;
case MOD_CRUSH:
message = "was squished";
break;
case MOD_WATER:
message = "sank like a rock";
break;
case MOD_SLIME:
message = "melted";
break;
case MOD_LAVA:
message = "does a back flip into the lava";
break;
case MOD_EXPLOSIVE:
case MOD_BARREL:
message = "blew up";
break;
case MOD_EXIT:
message = "found a way out";
break;
case MOD_TARGET_LASER:
message = "saw the light";
break;
case MOD_TARGET_BLASTER:
message = "got blasted";
break;
case MOD_BOMB:
case MOD_SPLASH:
case MOD_TRIGGER_HURT:
message = "was in the wrong place";
break;
}
if (attacker == self)
{
switch (mod)
{
case MOD_HELD_GRENADE:
message = "tried to put the pin back in";
break;
case MOD_HG_SPLASH:
case MOD_G_SPLASH:
if (IsFemale(self))
message = "tripped on her own grenade";
else
message = "tripped on his own grenade";
break;
case MOD_R_SPLASH:
if (IsFemale(self))
message = "blew herself up";
else
message = "blew himself up";
break;
case MOD_BFG_BLAST:
message = "should have used a smaller gun";
break;
default:
if (IsFemale(self))
message = "killed herself";
else
message = "killed himself";
break;
}
}
if (message)
{
gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message);
if (deathmatch->value)
self->client->resp.score--;
self->enemy = NULL;
return;
}
self->enemy = attacker;
if (attacker && attacker->client)
{
switch (mod)
{
case MOD_BLASTER:
message = "was blasted by";
break;
case MOD_SHOTGUN:
message = "was gunned down by";
break;
case MOD_SSHOTGUN:
message = "was blown away by";
message2 = "'s super shotgun";
break;
case MOD_MACHINEGUN:
message = "was machinegunned by";
break;
case MOD_CHAINGUN:
message = "was cut in half by";
message2 = "'s chaingun";
break;
case MOD_GRENADE:
message = "was popped by";
message2 = "'s grenade";
break;
case MOD_G_SPLASH:
message = "was shredded by";
message2 = "'s shrapnel";
break;
case MOD_ROCKET:
message = "ate";
message2 = "'s rocket";
break;
case MOD_R_SPLASH:
message = "almost dodged";
message2 = "'s rocket";
break;
case MOD_HYPERBLASTER:
message = "was melted by";
message2 = "'s hyperblaster";
break;
case MOD_RAILGUN:
message = "was railed by";
break;
case MOD_BFG_LASER:
message = "saw the pretty lights from";
message2 = "'s BFG";
break;
case MOD_BFG_BLAST:
message = "was disintegrated by";
message2 = "'s BFG blast";
break;
case MOD_BFG_EFFECT:
message = "couldn't hide from";
message2 = "'s BFG";
break;
case MOD_HANDGRENADE:
message = "caught";
message2 = "'s handgrenade";
break;
case MOD_HG_SPLASH:
message = "didn't see";
message2 = "'s handgrenade";
break;
case MOD_HELD_GRENADE:
message = "feels";
message2 = "'s pain";
break;
case MOD_TELEFRAG:
message = "tried to invade";
message2 = "'s personal space";
break;
//ZOID
case MOD_GRAPPLE:
message = "was caught by";
message2 = "'s grapple";
break;
//ZOID
}
if (message)
{
gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
if (deathmatch->value)
{
if (ff)
attacker->client->resp.score--;
else
attacker->client->resp.score++;
}
return;
}
}
}
gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
if (deathmatch->value)
self->client->resp.score--;
}
void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
void TossClientWeapon (edict_t *self)
{
gitem_t *item;
edict_t *drop;
qboolean quad;
float spread;
if (!deathmatch->value)
return;
item = self->client->pers.weapon;
if (! self->client->pers.inventory[self->client->ammo_index] )
item = NULL;
if (item && (strcmp (item->pickup_name, "Blaster") == 0))
item = NULL;
if (!((int)(dmflags->value) & DF_QUAD_DROP))
quad = false;
else
quad = (self->client->quad_framenum > (level.framenum + 10));
if (item && quad)
spread = 22.5;
else
spread = 0.0;
if (item)
{
self->client->v_angle[YAW] -= spread;
drop = Drop_Item (self, item);
self->client->v_angle[YAW] += spread;
drop->spawnflags = DROPPED_PLAYER_ITEM;
}
if (quad)
{
self->client->v_angle[YAW] += spread;
drop = Drop_Item (self, FindItemByClassname ("item_quad"));
self->client->v_angle[YAW] -= spread;
drop->spawnflags |= DROPPED_PLAYER_ITEM;
drop->touch = Touch_Item;
drop->nextthink = level.time + (self->client->quad_framenum - level.framenum) * FRAMETIME;
drop->think = G_FreeEdict;
}
}
/*
==================
LookAtKiller
==================
*/
void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
{
vec3_t dir;
if (attacker && attacker != world && attacker != self)
{
VectorSubtract (attacker->s.origin, self->s.origin, dir);
}
else if (inflictor && inflictor != world && inflictor != self)
{
VectorSubtract (inflictor->s.origin, self->s.origin, dir);
}
else
{
self->client->killer_yaw = self->s.angles[YAW];
return;
}
if (dir[0])
self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
else {
self->client->killer_yaw = 0;
if (dir[1] > 0)
self->client->killer_yaw = 90;
else if (dir[1] < 0)
self->client->killer_yaw = -90;
}
if (self->client->killer_yaw < 0)
self->client->killer_yaw += 360;
}
/*
==================
player_die
==================
*/
void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
VectorClear (self->avelocity);
self->takedamage = DAMAGE_YES;
self->movetype = MOVETYPE_TOSS;
self->s.modelindex2 = 0; // remove linked weapon model
//ZOID
self->s.modelindex3 = 0; // remove linked ctf flag
//ZOID
self->s.angles[0] = 0;
self->s.angles[2] = 0;
self->s.sound = 0;
self->client->weapon_sound = 0;
self->maxs[2] = -8;
// self->solid = SOLID_NOT;
self->svflags |= SVF_DEADMONSTER;
if (!self->deadflag)
{
self->client->respawn_time = level.time + 1.0;
LookAtKiller (self, inflictor, attacker);
self->client->ps.pmove.pm_type = PM_DEAD;
ClientObituary (self, inflictor, attacker);
//ZOID
// if at start and same team, clear
if (ctf->value && meansOfDeath == MOD_TELEFRAG &&
self->client->resp.ctf_state < 2 &&
self->client->resp.ctf_team == attacker->client->resp.ctf_team) {
attacker->client->resp.score--;
self->client->resp.ctf_state = 0;
}
CTFFragBonuses(self, inflictor, attacker);
//ZOID
TossClientWeapon (self);
//ZOID
CTFPlayerResetGrapple(self);
CTFDeadDropFlag(self);
CTFDeadDropTech(self);
//ZOID
if (deathmatch->value && !self->client->showscores)
Cmd_Help_f (self); // show scores
}
// remove powerups
self->client->quad_framenum = 0;
self->client->invincible_framenum = 0;
self->client->breather_framenum = 0;
self->client->enviro_framenum = 0;
self->flags &= ~FL_POWER_ARMOR;
// clear inventory
memset(self->client->pers.inventory, 0, sizeof(self->client->pers.inventory));
if (self->health < -40)
{ // gib
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);
ThrowClientHead (self, damage);
//ZOID
self->client->anim_priority = ANIM_DEATH;
self->client->anim_end = 0;
//ZOID
self->takedamage = DAMAGE_NO;
}
else
{ // normal death
if (!self->deadflag)
{
static int i;
i = (i+1)%3;
// start a death animation
self->client->anim_priority = ANIM_DEATH;
if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
{
self->s.frame = FRAME_crdeath1-1;
self->client->anim_end = FRAME_crdeath5;
}
else switch (i)
{
case 0:
self->s.frame = FRAME_death101-1;
self->client->anim_end = FRAME_death106;
break;
case 1:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -