201 lines
5.4 KiB
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;
|
||
|
}
|