📄 g_misc.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.
*/
// g_misc.c
#include "g_local.h"
/*QUAKED func_group (0 0 0) ?
Used to group brushes together just for editor convenience.
*/
//=====================================================
void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator)
{
ent->count ^= 1; // toggle state
// gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
gi.SetAreaPortalState (ent->style, ent->count);
}
/*QUAKED func_areaportal (0 0 0) ?
This is a non-visible object that divides the world into
areas that are seperated when this portal is not activated.
Usually enclosed in the middle of a door.
*/
void SP_func_areaportal (edict_t *ent)
{
ent->use = Use_Areaportal;
ent->count = 0; // allways start closed;
}
//=====================================================
/*
=================
Misc functions
=================
*/
void VelocityForDamage (int damage, vec3_t v)
{
v[0] = 100.0 * crandom();
v[1] = 100.0 * crandom();
v[2] = 200.0 + 100.0 * random();
if (damage < 50)
VectorScale (v, 0.7, v);
else
VectorScale (v, 1.2, v);
}
void ClipGibVelocity (edict_t *ent)
{
if (ent->velocity[0] < -300)
ent->velocity[0] = -300;
else if (ent->velocity[0] > 300)
ent->velocity[0] = 300;
if (ent->velocity[1] < -300)
ent->velocity[1] = -300;
else if (ent->velocity[1] > 300)
ent->velocity[1] = 300;
if (ent->velocity[2] < 200)
ent->velocity[2] = 200; // always some upwards
else if (ent->velocity[2] > 500)
ent->velocity[2] = 500;
}
/*
=================
gibs
=================
*/
void gib_think (edict_t *self)
{
self->s.frame++;
self->nextthink = level.time + FRAMETIME;
if (self->s.frame == 10)
{
self->think = G_FreeEdict;
self->nextthink = level.time + 8 + random()*10;
}
}
void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
vec3_t normal_angles, right;
if (!self->groundentity)
return;
self->touch = NULL;
if (plane)
{
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
vectoangles (plane->normal, normal_angles);
AngleVectors (normal_angles, NULL, right, NULL);
vectoangles (right, self->s.angles);
if (self->s.modelindex == sm_meat_index)
{
self->s.frame++;
self->think = gib_think;
self->nextthink = level.time + FRAMETIME;
}
}
}
void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
G_FreeEdict (self);
}
void ThrowGib (edict_t *self, char *gibname, int damage, int type)
{
edict_t *gib;
vec3_t vd;
vec3_t origin;
vec3_t size;
float vscale;
gib = G_Spawn();
VectorScale (self->size, 0.5, size);
VectorAdd (self->absmin, size, origin);
gib->s.origin[0] = origin[0] + crandom() * size[0];
gib->s.origin[1] = origin[1] + crandom() * size[1];
gib->s.origin[2] = origin[2] + crandom() * size[2];
gi.setmodel (gib, gibname);
gib->solid = SOLID_NOT;
gib->s.effects |= EF_GIB;
gib->flags |= FL_NO_KNOCKBACK;
gib->takedamage = DAMAGE_YES;
gib->die = gib_die;
if (type == GIB_ORGANIC)
{
gib->movetype = MOVETYPE_TOSS;
gib->touch = gib_touch;
vscale = 0.5;
}
else
{
gib->movetype = MOVETYPE_BOUNCE;
vscale = 1.0;
}
VelocityForDamage (damage, vd);
VectorMA (self->velocity, vscale, vd, gib->velocity);
ClipGibVelocity (gib);
gib->avelocity[0] = random()*600;
gib->avelocity[1] = random()*600;
gib->avelocity[2] = random()*600;
gib->think = G_FreeEdict;
gib->nextthink = level.time + 10 + random()*10;
gi.linkentity (gib);
}
void ThrowHead (edict_t *self, char *gibname, int damage, int type)
{
vec3_t vd;
float vscale;
self->s.skinnum = 0;
self->s.frame = 0;
VectorClear (self->mins);
VectorClear (self->maxs);
self->s.modelindex2 = 0;
gi.setmodel (self, gibname);
self->solid = SOLID_NOT;
self->s.effects |= EF_GIB;
self->s.effects &= ~EF_FLIES;
self->s.sound = 0;
self->flags |= FL_NO_KNOCKBACK;
self->svflags &= ~SVF_MONSTER;
self->takedamage = DAMAGE_YES;
self->die = gib_die;
if (type == GIB_ORGANIC)
{
self->movetype = MOVETYPE_TOSS;
self->touch = gib_touch;
vscale = 0.5;
}
else
{
self->movetype = MOVETYPE_BOUNCE;
vscale = 1.0;
}
VelocityForDamage (damage, vd);
VectorMA (self->velocity, vscale, vd, self->velocity);
ClipGibVelocity (self);
self->avelocity[YAW] = crandom()*600;
self->think = G_FreeEdict;
self->nextthink = level.time + 10 + random()*10;
gi.linkentity (self);
}
void ThrowClientHead (edict_t *self, int damage)
{
vec3_t vd;
char *gibname;
if (rand()&1)
{
gibname = "models/objects/gibs/head2/tris.md2";
self->s.skinnum = 1; // second skin is player
}
else
{
gibname = "models/objects/gibs/skull/tris.md2";
self->s.skinnum = 0;
}
self->s.origin[2] += 32;
self->s.frame = 0;
gi.setmodel (self, gibname);
VectorSet (self->mins, -16, -16, 0);
VectorSet (self->maxs, 16, 16, 16);
self->takedamage = DAMAGE_NO;
self->solid = SOLID_NOT;
self->s.effects = EF_GIB;
self->s.sound = 0;
self->flags |= FL_NO_KNOCKBACK;
self->movetype = MOVETYPE_BOUNCE;
VelocityForDamage (damage, vd);
VectorAdd (self->velocity, vd, self->velocity);
if (self->client) // bodies in the queue don't have a client anymore
{
self->client->anim_priority = ANIM_DEATH;
self->client->anim_end = self->s.frame;
}
gi.linkentity (self);
}
/*
=================
debris
=================
*/
void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
G_FreeEdict (self);
}
void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
{
edict_t *chunk;
vec3_t v;
chunk = G_Spawn();
VectorCopy (origin, chunk->s.origin);
gi.setmodel (chunk, modelname);
v[0] = 100 * crandom();
v[1] = 100 * crandom();
v[2] = 100 + 100 * crandom();
VectorMA (self->velocity, speed, v, chunk->velocity);
chunk->movetype = MOVETYPE_BOUNCE;
chunk->solid = SOLID_NOT;
chunk->avelocity[0] = random()*600;
chunk->avelocity[1] = random()*600;
chunk->avelocity[2] = random()*600;
chunk->think = G_FreeEdict;
chunk->nextthink = level.time + 5 + random()*5;
chunk->s.frame = 0;
chunk->flags = 0;
chunk->classname = "debris";
chunk->takedamage = DAMAGE_YES;
chunk->die = debris_die;
gi.linkentity (chunk);
}
void BecomeExplosion1 (edict_t *self)
{
//ZOID
//flags are important
if (strcmp(self->classname, "item_flag_team1") == 0) {
CTFResetFlag(CTF_TEAM1); // this will free self!
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
CTFTeamName(CTF_TEAM1));
return;
}
if (strcmp(self->classname, "item_flag_team2") == 0) {
CTFResetFlag(CTF_TEAM2); // this will free self!
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
CTFTeamName(CTF_TEAM1));
return;
}
// techs are important too
if (self->item && (self->item->flags & IT_TECH)) {
CTFRespawnTech(self); // this frees self!
return;
}
//ZOID
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_EXPLOSION1);
gi.WritePosition (self->s.origin);
gi.multicast (self->s.origin, MULTICAST_PVS);
G_FreeEdict (self);
}
void BecomeExplosion2 (edict_t *self)
{
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_EXPLOSION2);
gi.WritePosition (self->s.origin);
gi.multicast (self->s.origin, MULTICAST_PVS);
G_FreeEdict (self);
}
/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
Target: next path corner
Pathtarget: gets used when an entity that has
this path_corner targeted touches it
*/
void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
vec3_t v;
edict_t *next;
if (other->movetarget != self)
return;
if (other->enemy)
return;
if (self->pathtarget)
{
char *savetarget;
savetarget = self->target;
self->target = self->pathtarget;
G_UseTargets (self, other);
self->target = savetarget;
}
if (self->target)
next = G_PickTarget(self->target);
else
next = NULL;
if ((next) && (next->spawnflags & 1))
{
VectorCopy (next->s.origin, v);
v[2] += next->mins[2];
v[2] -= other->mins[2];
VectorCopy (v, other->s.origin);
next = G_PickTarget(next->target);
}
other->goalentity = other->movetarget = next;
if (self->wait)
{
other->monsterinfo.pausetime = level.time + self->wait;
other->monsterinfo.stand (other);
return;
}
if (!other->movetarget)
{
other->monsterinfo.pausetime = level.time + 100000000;
other->monsterinfo.stand (other);
}
else
{
VectorSubtract (other->goalentity->s.origin, other->s.origin, v);
other->ideal_yaw = vectoyaw (v);
}
}
void SP_path_corner (edict_t *self)
{
if (!self->targetname)
{
gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
G_FreeEdict (self);
return;
}
self->solid = SOLID_TRIGGER;
self->touch = path_corner_touch;
VectorSet (self->mins, -8, -8, -8);
VectorSet (self->maxs, 8, 8, 8);
self->svflags |= SVF_NOCLIENT;
gi.linkentity (self);
}
/*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
Makes this the target of a monster and it will head here
when first activated before going after the activator. If
hold is selected, it will stay here.
*/
void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
edict_t *activator;
if (other->movetarget != self)
return;
if (self->target)
{
other->target = self->target;
other->goalentity = other->movetarget = G_PickTarget(other->target);
if (!other->goalentity)
{
gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target);
other->movetarget = self;
}
self->target = NULL;
}
else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY)))
{
other->monsterinfo.pausetime = level.time + 100000000;
other->monsterinfo.aiflags |= AI_STAND_GROUND;
other->monsterinfo.stand (other);
}
if (other->movetarget == self)
{
other->target = NULL;
other->movetarget = NULL;
other->goalentity = other->enemy;
other->monsterinfo.aiflags &= ~AI_COMBAT_POINT;
}
if (self->pathtarget)
{
char *savetarget;
savetarget = self->target;
self->target = self->pathtarget;
if (other->enemy && other->enemy->client)
activator = other->enemy;
else if (other->oldenemy && other->oldenemy->client)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -