quake2-action/a_items.c

201 lines
5.4 KiB
C

/************************************************************************
* Special item spawning/management code. Mainly hacked from CTF, thanks
* Zoid.
* - zucc
*/
#include "g_local.h"
// time too wait between failures to respawn?
#define SPEC_RESPAWN_TIME 60
// time before they will get respawned
#define SPEC_TECH_TIMEOUT 60
char *tnames[] = {
"item_quiet", "item_slippers", "item_vest", "item_band", "item_lasersight",
NULL
};
void SpecThink(edict_t *spec);
static edict_t *FindSpecSpawn(void)
{
edict_t *spot = NULL;
int i = rand() % 16;
while (i--)
spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
if (!spot)
spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
if (spot == NULL)
{
gi.dprintf("Warning: failed to find special item spawn point!\n");
}
return spot;
}
static void SpawnSpec(gitem_t *item, edict_t *spot)
{
edict_t *ent;
vec3_t forward, right;
vec3_t angles;
ent = G_Spawn();
ent->classname = item->classname;
ent->item = item;
ent->spawnflags = DROPPED_ITEM;
ent->s.effects = item->world_model_flags;
ent->s.renderfx = RF_GLOW;
VectorSet (ent->mins, -15, -15, -15);
VectorSet (ent->maxs, 15, 15, 15);
// zucc dumb hack to make laser look like it is on the ground
if (stricmp(item->pickup_name, LASER_NAME) == 0)
{
VectorSet (ent->mins, -15, -15, -1);
VectorSet (ent->maxs, 15, 15, 1);
}
gi.setmodel (ent, ent->item->world_model);
ent->solid = SOLID_TRIGGER;
ent->movetype = MOVETYPE_TOSS;
ent->touch = Touch_Item;
ent->owner = ent;
angles[0] = 0;
angles[1] = rand() % 360;
angles[2] = 0;
AngleVectors (angles, forward, right, NULL);
VectorCopy (spot->s.origin, ent->s.origin);
ent->s.origin[2] += 16;
VectorScale (forward, 100, ent->velocity);
ent->velocity[2] = 300;
ent->nextthink = level.time + SPEC_RESPAWN_TIME;
ent->think = SpecThink;
gi.linkentity (ent);
}
void SpawnSpecs(edict_t *ent)
{
gitem_t *spec;
edict_t *spot;
int i;
i = 0;
while (tnames[i]) {
if ((spec = FindItemByClassname(tnames[i])) != NULL &&
(spot = FindSpecSpawn()) != NULL)
SpawnSpec(spec, spot);
i++;
}
}
void SpecThink(edict_t *spec)
{
edict_t *spot;
if ((spot = FindSpecSpawn()) != NULL) {
SpawnSpec(spec->item, spot);
G_FreeEdict(spec);
} else {
spec->nextthink = level.time + SPEC_RESPAWN_TIME;
spec->think = SpecThink;
}
}
static void MakeTouchSpecThink (edict_t *ent)
{
ent->touch = Touch_Item;
if ( deathmatch->value && !teamplay->value && !allitem->value )
{
ent->nextthink = level.time + SPEC_RESPAWN_TIME - 1;
ent->think = SpecThink;
}
else if ( teamplay->value && !allitem->value )
{
ent->nextthink = level.time + 60;
ent->think = G_FreeEdict;
}
else // allitem->value is set
{
ent->nextthink = level.time + 1;
ent->think = G_FreeEdict;
}
}
void Drop_Spec(edict_t *ent, gitem_t *item)
{
edict_t *spec;
spec = Drop_Item(ent, item);
//gi.cprintf(ent, PRINT_HIGH, "Dropping special item.\n");
spec->nextthink = level.time + 1;
spec->think = MakeTouchSpecThink;
//zucc this and the one below should probably be -- not = 0, if
// a server turns on multiple item pickup.
ent->client->pers.inventory[ITEM_INDEX(item)]--;
}
void DeadDropSpec(edict_t *ent)
{
gitem_t *spec;
edict_t *dropped;
int i;
i = 0;
while (tnames[i]) {
if ((spec = FindItemByClassname(tnames[i])) != NULL &&
ent->client->pers.inventory[ITEM_INDEX(spec)]) {
dropped = Drop_Item(ent, spec);
// hack the velocity to make it bounce random
dropped->velocity[0] = (rand() % 600) - 300;
dropped->velocity[1] = (rand() % 600) - 300;
dropped->nextthink = level.time + 1;
dropped->think = MakeTouchSpecThink;
dropped->owner = NULL;
ent->client->pers.inventory[ITEM_INDEX(spec)] = 0;
}
i++;
}
}
// frees the passed edict!
void RespawnSpec(edict_t *ent)
{
edict_t *spot;
if ((spot = FindSpecSpawn()) != NULL)
SpawnSpec(ent->item, spot);
G_FreeEdict(ent);
}
void SetupSpecSpawn(void)
{
edict_t *ent;
if (level.specspawn)
return;
//gi.bprintf (PRINT_HIGH, "got into the setup\n");
ent = G_Spawn();
ent->nextthink = level.time + 4;
ent->think = SpawnSpecs;
level.specspawn = 1;
}