/* * Copyright (c) ZeniMax Media Inc. * Licensed under the GNU General Public License 2.0. */ /* * ======================================================================= * * Item handling and item definitions. * * ======================================================================= */ #include "header/local.h" #define HEALTH_IGNORE_MAX 1 #define HEALTH_TIMED 2 qboolean Pickup_Weapon(edict_t *ent, edict_t *other); void Use_Weapon(edict_t *ent, gitem_t *inv); void Drop_Weapon(edict_t *ent, gitem_t *inv); void Weapon_Blaster(edict_t *ent); void Weapon_Shotgun(edict_t *ent); void Weapon_SuperShotgun(edict_t *ent); void Weapon_Machinegun(edict_t *ent); void Weapon_Chaingun(edict_t *ent); void Weapon_HyperBlaster(edict_t *ent); void Weapon_RocketLauncher(edict_t *ent); void Weapon_Grenade(edict_t *ent); void Weapon_GrenadeLauncher(edict_t *ent); void Weapon_Railgun(edict_t *ent); void Weapon_BFG(edict_t *ent); void Weapon_ChainFist(edict_t *ent); void Weapon_Disintegrator(edict_t *ent); void Weapon_ETF_Rifle(edict_t *ent); void Weapon_Heatbeam(edict_t *ent); void Weapon_Prox(edict_t *ent); void Weapon_Tesla(edict_t *ent); void Weapon_ProxLauncher(edict_t *ent); gitem_armor_t jacketarmor_info = {25, 50, .30, .00, ARMOR_JACKET}; gitem_armor_t combatarmor_info = {50, 100, .60, .30, ARMOR_COMBAT}; gitem_armor_t bodyarmor_info = {100, 200, .80, .60, ARMOR_BODY}; int jacket_armor_index; int combat_armor_index; int body_armor_index; static int power_screen_index; static int power_shield_index; void Use_Quad(edict_t *ent, gitem_t *item); static int quad_drop_timeout_hack; /* ====================================================================== */ gitem_t * GetItemByIndex(int index) { if ((index == 0) || (index >= game.num_items)) { return NULL; } return &itemlist[index]; } gitem_t * FindItemByClassname(char *classname) { int i; gitem_t *it; if (!classname) { return NULL; } it = itemlist; for (i = 0; i < game.num_items; i++, it++) { if (!it->classname) { continue; } if (!Q_stricmp(it->classname, classname)) { return it; } } return NULL; } gitem_t * FindItem(char *pickup_name) { int i; gitem_t *it; if (!pickup_name) { return NULL; } it = itemlist; for (i = 0; i < game.num_items; i++, it++) { if (!it->pickup_name) { continue; } if (!Q_stricmp(it->pickup_name, pickup_name)) { return it; } } return NULL; } /* ====================================================================== */ void DoRespawn(edict_t *ent) { if (!ent) { return; } if (ent->team) { edict_t *master; int count; int choice; master = ent->teammaster; for (count = 0, ent = master; ent; ent = ent->chain, count++) { } choice = count ? randk() % count : 0; for (count = 0, ent = master; count < choice; ent = ent->chain, count++) { } } if (randomrespawn && randomrespawn->value) { edict_t *newEnt; newEnt = DoRandomRespawn(ent); /* if we've changed entities, then do some sleight * of hand. otherwise, the old entity will respawn */ if (newEnt) { G_FreeEdict(ent); ent = newEnt; } } ent->svflags &= ~SVF_NOCLIENT; ent->solid = SOLID_TRIGGER; gi.linkentity(ent); /* send an effect */ ent->s.event = EV_ITEM_RESPAWN; } void SetRespawn(edict_t *ent, float delay) { if (!ent) { return; } ent->flags |= FL_RESPAWN; ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; ent->nextthink = level.time + delay; ent->think = DoRespawn; gi.linkentity(ent); } /* ====================================================================== */ qboolean Pickup_Powerup(edict_t *ent, edict_t *other) { int quantity; if (!ent || !other) { return false; } quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)]; if (((skill->value == SKILL_MEDIUM) && (quantity >= 2)) || ((skill->value >= SKILL_HARD) && (quantity >= 1))) { return false; } if ((coop->value) && (ent->item->flags & IT_STAY_COOP) && (quantity > 0)) { return false; } other->client->pers.inventory[ITEM_INDEX(ent->item)]++; if (deathmatch->value) { if (!(ent->spawnflags & DROPPED_ITEM)) { SetRespawn(ent, ent->item->quantity); } } return true; } void Drop_General(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } Drop_Item(ent, item); ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); } /* ====================================================================== */ qboolean Pickup_Adrenaline(edict_t *ent, edict_t *other) { if (!ent || !other) { return false; } if (!deathmatch->value) { other->max_health += 1; } if (other->health < other->max_health) { other->health = other->max_health; } if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(ent, ent->item->quantity); } return true; } qboolean Pickup_AncientHead(edict_t *ent, edict_t *other) { if (!ent || !other) { return false; } other->max_health += 2; if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(ent, ent->item->quantity); } return true; } qboolean Pickup_Bandolier(edict_t *ent, edict_t *other) { if (!ent || !other) { return false; } gitem_t *item; int index; if (other->client->pers.max_bullets < 250) { other->client->pers.max_bullets = 250; } if (other->client->pers.max_shells < 150) { other->client->pers.max_shells = 150; } if (other->client->pers.max_cells < 250) { other->client->pers.max_cells = 250; } if (other->client->pers.max_slugs < 75) { other->client->pers.max_slugs = 75; } if (other->client->pers.max_flechettes < 250) { other->client->pers.max_flechettes = 250; } if (g_disruptor->value) { if (other->client->pers.max_rounds < 150) { other->client->pers.max_rounds = 150; } } item = FindItem("Bullets"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_bullets) { other->client->pers.inventory[index] = other->client->pers.max_bullets; } } item = FindItem("Shells"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_shells) { other->client->pers.inventory[index] = other->client->pers.max_shells; } } if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(ent, ent->item->quantity); } return true; } qboolean Pickup_Pack(edict_t *ent, edict_t *other) { gitem_t *item; int index; if (!ent || !other) { return false; } if (other->client->pers.max_bullets < 300) { other->client->pers.max_bullets = 300; } if (other->client->pers.max_shells < 200) { other->client->pers.max_shells = 200; } if (other->client->pers.max_rockets < 100) { other->client->pers.max_rockets = 100; } if (other->client->pers.max_grenades < 100) { other->client->pers.max_grenades = 100; } if (other->client->pers.max_cells < 300) { other->client->pers.max_cells = 300; } if (other->client->pers.max_slugs < 100) { other->client->pers.max_slugs = 100; } if (other->client->pers.max_flechettes < 200) { other->client->pers.max_flechettes = 200; } if (g_disruptor->value) { if (other->client->pers.max_rounds < 200) { other->client->pers.max_rounds = 200; } } item = FindItem("Bullets"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_bullets) { other->client->pers.inventory[index] = other->client->pers.max_bullets; } } item = FindItem("Shells"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_shells) { other->client->pers.inventory[index] = other->client->pers.max_shells; } } item = FindItem("Cells"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_cells) { other->client->pers.inventory[index] = other->client->pers.max_cells; } } item = FindItem("Grenades"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_grenades) { other->client->pers.inventory[index] = other->client->pers.max_grenades; } } item = FindItem("Rockets"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_rockets) { other->client->pers.inventory[index] = other->client->pers.max_rockets; } } item = FindItem("Slugs"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_slugs) { other->client->pers.inventory[index] = other->client->pers.max_slugs; } } item = FindItem("Flechettes"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_flechettes) { other->client->pers.inventory[index] = other->client->pers.max_flechettes; } } item = FindItem("Rounds"); if (item) { index = ITEM_INDEX(item); other->client->pers.inventory[index] += item->quantity; if (other->client->pers.inventory[index] > other->client->pers.max_rounds) { other->client->pers.inventory[index] = other->client->pers.max_rounds; } } if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(ent, ent->item->quantity); } return true; } qboolean Pickup_Nuke(edict_t *ent, edict_t *other) { int quantity; if (!ent || !other) { return false; } quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)]; if (quantity >= 1) { return false; } if ((coop->value) && (ent->item->flags & IT_STAY_COOP)) { return false; } other->client->pers.inventory[ITEM_INDEX(ent->item)]++; if (deathmatch->value) { if (!(ent->spawnflags & DROPPED_ITEM)) { SetRespawn(ent, ent->item->quantity); } } return true; } void Use_IR(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); if (ent->client->ir_framenum > level.framenum) { ent->client->ir_framenum += 600; } else { ent->client->ir_framenum = level.framenum + 600; } gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/ir_start.wav"), 1, ATTN_NORM, 0); } void Use_Double(edict_t *ent, gitem_t *item) { ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); if (ent->client->double_framenum > level.framenum) { ent->client->double_framenum += 300; } else { ent->client->double_framenum = level.framenum + 300; } gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/ddamage1.wav"), 1, ATTN_NORM, 0); } void Use_Compass(edict_t *ent, gitem_t *item) { int ang; if (!ent || !item) { return; } ang = (int)(ent->client->v_angle[1]); if (ang < 0) { ang += 360; } gi.cprintf(ent, PRINT_HIGH, "Origin: %0.0f,%0.0f,%0.0f Dir: %d\n", ent->s.origin[0], ent->s.origin[1], ent->s.origin[2], ang); } void Use_Nuke(edict_t *ent, gitem_t *item) { vec3_t forward, right, start; float speed; if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); AngleVectors(ent->client->v_angle, forward, right, NULL); VectorCopy(ent->s.origin, start); speed = 100; fire_nuke(ent, start, forward, speed); } void Use_Doppleganger(edict_t *ent, gitem_t *item) { vec3_t forward, right; vec3_t createPt, spawnPt; vec3_t ang; if (!ent || !item) { return; } VectorClear(ang); ang[YAW] = ent->client->v_angle[YAW]; AngleVectors(ang, forward, right, NULL); VectorMA(ent->s.origin, 48, forward, createPt); if (!FindSpawnPoint(createPt, ent->mins, ent->maxs, spawnPt, 32)) { return; } if (!CheckGroundSpawnPoint(spawnPt, ent->mins, ent->maxs, 64, -1)) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); SpawnGrow_Spawn(spawnPt, 0); fire_doppleganger(ent, spawnPt, forward); } qboolean Pickup_Doppleganger(edict_t *ent, edict_t *other) { int quantity; if (!ent || !other) { return false; } if (!(deathmatch->value)) { return false; } quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)]; if (quantity >= 1) { return false; } other->client->pers.inventory[ITEM_INDEX(ent->item)]++; if (!(ent->spawnflags & DROPPED_ITEM)) { SetRespawn(ent, ent->item->quantity); } return true; } qboolean Pickup_Sphere(edict_t *ent, edict_t *other) { int quantity; if (!ent || !other) { return false; } if (other->client && other->client->owned_sphere) { return false; } quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)]; if (((skill->value == SKILL_MEDIUM) && (quantity >= 2)) || ((skill->value >= SKILL_HARD) && (quantity >= 1))) { return false; } if ((coop->value) && (ent->item->flags & IT_STAY_COOP) && (quantity > 0)) { return false; } other->client->pers.inventory[ITEM_INDEX(ent->item)]++; if (deathmatch->value) { if (!(ent->spawnflags & DROPPED_ITEM)) { SetRespawn(ent, ent->item->quantity); } } return true; } void Use_Defender(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } if (ent->client && ent->client->owned_sphere) { gi.cprintf(ent, PRINT_HIGH, "Only one sphere at a time!\n"); return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); Defender_Launch(ent); } void Use_Hunter(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } if (ent->client && ent->client->owned_sphere) { gi.cprintf(ent, PRINT_HIGH, "Only one sphere at a time!\n"); return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); Hunter_Launch(ent); } void Use_Vengeance(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } if (ent->client && ent->client->owned_sphere) { gi.cprintf(ent, PRINT_HIGH, "Only one sphere at a time!\n"); return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); Vengeance_Launch(ent); } /* ====================================================================== */ void Use_Quad(edict_t *ent, gitem_t *item) { int timeout; if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); if (quad_drop_timeout_hack) { timeout = quad_drop_timeout_hack; quad_drop_timeout_hack = 0; } else { timeout = 300; } if (ent->client->quad_framenum > level.framenum) { ent->client->quad_framenum += timeout; } else { ent->client->quad_framenum = level.framenum + timeout; } gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0); } /* ====================================================================== */ void Use_Breather(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); if (ent->client->breather_framenum > level.framenum) { ent->client->breather_framenum += 300; } else { ent->client->breather_framenum = level.framenum + 300; } } /* ====================================================================== */ void Use_Envirosuit(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); if (ent->client->enviro_framenum > level.framenum) { ent->client->enviro_framenum += 300; } else { ent->client->enviro_framenum = level.framenum + 300; } } /* ====================================================================== */ void Use_Invulnerability(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); if (ent->client->invincible_framenum > level.framenum) { ent->client->invincible_framenum += 300; } else { ent->client->invincible_framenum = level.framenum + 300; } gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0); } /* ====================================================================== */ void Use_Silencer(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } ent->client->pers.inventory[ITEM_INDEX(item)]--; ValidateSelectedItem(ent); ent->client->silencer_shots += 30; } /* ====================================================================== */ qboolean Pickup_Key(edict_t *ent, edict_t *other) { if (!ent || !other) { return false; } if (coop->value) { if (strcmp(ent->classname, "key_power_cube") == 0) { if (other->client->pers.power_cubes & ((ent->spawnflags & 0x0000ff00) >> 8)) { return false; } other->client->pers.inventory[ITEM_INDEX(ent->item)]++; other->client->pers.power_cubes |= ((ent->spawnflags & 0x0000ff00) >> 8); } else { if (other->client->pers.inventory[ITEM_INDEX(ent->item)]) { return false; } other->client->pers.inventory[ITEM_INDEX(ent->item)] = 1; } return true; } other->client->pers.inventory[ITEM_INDEX(ent->item)]++; return true; } /* ====================================================================== */ qboolean Add_Ammo(edict_t *ent, gitem_t *item, int count) { int index; int max; if (!ent || !item) { return false; } if (!ent->client) { return false; } if (item->tag == AMMO_BULLETS) { max = ent->client->pers.max_bullets; } else if (item->tag == AMMO_SHELLS) { max = ent->client->pers.max_shells; } else if (item->tag == AMMO_ROCKETS) { max = ent->client->pers.max_rockets; } else if (item->tag == AMMO_GRENADES) { max = ent->client->pers.max_grenades; } else if (item->tag == AMMO_CELLS) { max = ent->client->pers.max_cells; } else if (item->tag == AMMO_SLUGS) { max = ent->client->pers.max_slugs; } else if (item->tag == AMMO_FLECHETTES) { max = ent->client->pers.max_flechettes; } else if (item->tag == AMMO_PROX) { max = ent->client->pers.max_prox; } else if (item->tag == AMMO_TESLA) { max = ent->client->pers.max_tesla; } else if (item->tag == AMMO_DISRUPTOR) { max = ent->client->pers.max_rounds; } else { gi.dprintf("undefined ammo type\n"); return false; } index = ITEM_INDEX(item); if (ent->client->pers.inventory[index] == max) { return false; } ent->client->pers.inventory[index] += count; if (ent->client->pers.inventory[index] > max) { ent->client->pers.inventory[index] = max; } return true; } qboolean Pickup_Ammo(edict_t *ent, edict_t *other) { int oldcount; int count; qboolean weapon; if (!ent || !other) { return false; } weapon = (ent->item->flags & IT_WEAPON); if ((weapon) && ((int)dmflags->value & DF_INFINITE_AMMO)) { count = 1000; } else if (ent->count) { count = ent->count; } else { count = ent->item->quantity; } oldcount = other->client->pers.inventory[ITEM_INDEX(ent->item)]; if (!Add_Ammo(other, ent->item, count)) { return false; } if (weapon && !oldcount) { /* don't switch to tesla */ if ((other->client->pers.weapon != ent->item) && (!deathmatch->value || (other->client->pers.weapon == FindItem("blaster"))) && (strcmp(ent->classname, "ammo_tesla"))) { other->client->newweapon = ent->item; } } if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) && (deathmatch->value)) { SetRespawn(ent, 30); } return true; } void Drop_Ammo(edict_t *ent, gitem_t *item) { edict_t *dropped; int index; if (!ent || !item) { return; } index = ITEM_INDEX(item); dropped = Drop_Item(ent, item); if (ent->client->pers.inventory[index] >= item->quantity) { dropped->count = item->quantity; } else { dropped->count = ent->client->pers.inventory[index]; } if (ent->client->pers.weapon && (ent->client->pers.weapon->tag == AMMO_GRENADES) && (item->tag == AMMO_GRENADES) && (ent->client->pers.inventory[index] - dropped->count <= 0)) { gi.cprintf(ent, PRINT_HIGH, "Can't drop current weapon\n"); G_FreeEdict(dropped); return; } ent->client->pers.inventory[index] -= dropped->count; ValidateSelectedItem(ent); } /* ====================================================================== */ void MegaHealth_think(edict_t *self) { if (!self) { return; } if (self->owner->health > self->owner->max_health) { self->nextthink = level.time + 1; self->owner->health -= 1; return; } if (!(self->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(self, 20); } else { G_FreeEdict(self); } } qboolean Pickup_Health(edict_t *ent, edict_t *other) { if (!ent || !other) { return false; } if (!(ent->style & HEALTH_IGNORE_MAX)) { if (other->health >= other->max_health) { return false; } } other->health += ent->count; if (!(ent->style & HEALTH_IGNORE_MAX)) { if (other->health > other->max_health) { other->health = other->max_health; } } if (ent->style & HEALTH_TIMED) { ent->think = MegaHealth_think; ent->nextthink = level.time + 5; ent->owner = other; ent->flags |= FL_RESPAWN; ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; } else { if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(ent, 30); } } return true; } /* ====================================================================== */ int ArmorIndex(edict_t *ent) { if (!ent) { return 0; } if (!ent->client) { return 0; } if (ent->client->pers.inventory[jacket_armor_index] > 0) { return jacket_armor_index; } if (ent->client->pers.inventory[combat_armor_index] > 0) { return combat_armor_index; } if (ent->client->pers.inventory[body_armor_index] > 0) { return body_armor_index; } return 0; } qboolean Pickup_Armor(edict_t *ent, edict_t *other) { int old_armor_index; gitem_armor_t *oldinfo; gitem_armor_t *newinfo; int newcount; float salvage; int salvagecount; if (!ent || !other) { return false; } /* get info on new armor */ newinfo = (gitem_armor_t *)ent->item->info; old_armor_index = ArmorIndex(other); /* handle armor shards specially */ if (ent->item->tag == ARMOR_SHARD) { if (!old_armor_index) { other->client->pers.inventory[jacket_armor_index] = 2; } else { other->client->pers.inventory[old_armor_index] += 2; } } /* if player has no armor, just use it */ else if (!old_armor_index) { other->client->pers.inventory[ITEM_INDEX(ent->item)] = newinfo->base_count; } /* use the better armor */ else { /* get info on old armor */ if (old_armor_index == jacket_armor_index) { oldinfo = &jacketarmor_info; } else if (old_armor_index == combat_armor_index) { oldinfo = &combatarmor_info; } else { oldinfo = &bodyarmor_info; } if (newinfo->normal_protection > oldinfo->normal_protection) { /* calc new armor values */ salvage = oldinfo->normal_protection / newinfo->normal_protection; salvagecount = salvage * other->client->pers.inventory[old_armor_index]; newcount = newinfo->base_count + salvagecount; if (newcount > newinfo->max_count) { newcount = newinfo->max_count; } /* zero count of old armor so it goes away */ other->client->pers.inventory[old_armor_index] = 0; /* change armor to new item with computed value */ other->client->pers.inventory[ITEM_INDEX(ent->item)] = newcount; } else { /* calc new armor values */ salvage = newinfo->normal_protection / oldinfo->normal_protection; salvagecount = salvage * newinfo->base_count; newcount = other->client->pers.inventory[old_armor_index] + salvagecount; if (newcount > oldinfo->max_count) { newcount = oldinfo->max_count; } /* if we're already maxed out then we don't need the new armor */ if (other->client->pers.inventory[old_armor_index] >= newcount) { return false; } /* update current armor value */ other->client->pers.inventory[old_armor_index] = newcount; } } if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value)) { SetRespawn(ent, 20); } return true; } /* ====================================================================== */ int PowerArmorType(edict_t *ent) { if (!ent) { return POWER_ARMOR_NONE; } if (!ent->client) { return POWER_ARMOR_NONE; } if (!(ent->flags & FL_POWER_ARMOR)) { return POWER_ARMOR_NONE; } if (ent->client->pers.inventory[power_shield_index] > 0) { return POWER_ARMOR_SHIELD; } if (ent->client->pers.inventory[power_screen_index] > 0) { return POWER_ARMOR_SCREEN; } return POWER_ARMOR_NONE; } void Use_PowerArmor(edict_t *ent, gitem_t *item) { int index; if (ent->flags & FL_POWER_ARMOR) { ent->flags &= ~FL_POWER_ARMOR; gi.sound(ent, CHAN_AUTO, gi.soundindex( "misc/power2.wav"), 1, ATTN_NORM, 0); } else { index = ITEM_INDEX(FindItem("cells")); if (!ent->client->pers.inventory[index]) { gi.cprintf(ent, PRINT_HIGH, "No cells for power armor.\n"); return; } ent->flags |= FL_POWER_ARMOR; gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_NORM, 0); } } qboolean Pickup_PowerArmor(edict_t *ent, edict_t *other) { int quantity; if (!ent || !other) { return false; } quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)]; other->client->pers.inventory[ITEM_INDEX(ent->item)]++; if (deathmatch->value) { if (!(ent->spawnflags & DROPPED_ITEM)) { SetRespawn(ent, ent->item->quantity); } /* auto-use for DM only if we didn't already have one */ if (!quantity) { ent->item->use(other, ent->item); } } return true; } void Drop_PowerArmor(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } if ((ent->flags & FL_POWER_ARMOR) && (ent->client->pers.inventory[ITEM_INDEX(item)] == 1)) { Use_PowerArmor(ent, item); } Drop_General(ent, item); } /* ====================================================================== */ void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane /* unused */, csurface_t *surf /* unused */) { qboolean taken; if (!ent || !other) { return; } if (!other->client) { return; } if (other->health < 1) { return; /* dead people can't pickup */ } if (!ent->item->pickup) { return; /* not a grabbable item? */ } taken = ent->item->pickup(ent, other); if (taken) { /* flash the screen */ other->client->bonus_alpha = 0.25; /* show icon and name on status bar */ other->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(ent->item->icon); other->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS + ITEM_INDEX(ent->item); other->client->pickup_msg_time = level.time + 3.0; /* change selected item */ if (ent->item->use) { other->client->pers.selected_item = other->client->ps.stats[STAT_SELECTED_ITEM] = ITEM_INDEX(ent->item); } if (ent->item->pickup == Pickup_Health) { if (ent->count == 2) { gi.sound(other, CHAN_ITEM, gi.soundindex("items/s_health.wav"), 1, ATTN_NORM, 0); } else if (ent->count == 10) { gi.sound(other, CHAN_ITEM, gi.soundindex("items/n_health.wav"), 1, ATTN_NORM, 0); } else if (ent->count == 25) { gi.sound(other, CHAN_ITEM, gi.soundindex("items/l_health.wav"), 1, ATTN_NORM, 0); } else /* (ent->count == 100) */ { gi.sound(other, CHAN_ITEM, gi.soundindex("items/m_health.wav"), 1, ATTN_NORM, 0); } } else if (ent->item->pickup_sound) { gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0); } /* activate item instantly if appropriate */ /* moved down here so activation sounds override the pickup sound */ if (deathmatch->value) { if ((((int)dmflags->value & DF_INSTANT_ITEMS) && (ent->item->flags & IT_INSTANT_USE)) || ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM))) { if ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM)) { quad_drop_timeout_hack = (ent->nextthink - level.time) / FRAMETIME; } if (ent->item->use) { ent->item->use(other, ent->item); } else { gi.dprintf("Powerup has no use function!\n"); } } } } if (!(ent->spawnflags & ITEM_TARGETS_USED)) { G_UseTargets(ent, other); ent->spawnflags |= ITEM_TARGETS_USED; } if (!taken) { return; } if (!((coop->value) && (ent->item->flags & IT_STAY_COOP)) || (ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM))) { if (ent->flags & FL_RESPAWN) { ent->flags &= ~FL_RESPAWN; } else { G_FreeEdict(ent); } } } /* ====================================================================== */ void drop_temp_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) { if (!ent || !other) { return; } if (other == ent->owner) { return; } Touch_Item(ent, other, plane, surf); } void drop_make_touchable(edict_t *ent) { if (!ent) { return; } ent->touch = Touch_Item; if (deathmatch->value) { ent->nextthink = level.time + 29; ent->think = G_FreeEdict; } } edict_t * Drop_Item(edict_t *ent, gitem_t *item) { edict_t *dropped; vec3_t forward, right; vec3_t offset; if (!ent || !item) { return NULL; } dropped = G_Spawn(); dropped->classname = item->classname; dropped->item = item; dropped->spawnflags = DROPPED_ITEM; dropped->s.effects = item->world_model_flags; dropped->s.renderfx = RF_GLOW | RF_IR_VISIBLE; VectorSet(dropped->mins, -15, -15, -15); VectorSet(dropped->maxs, 15, 15, 15); gi.setmodel(dropped, dropped->item->world_model); dropped->solid = SOLID_TRIGGER; dropped->movetype = MOVETYPE_TOSS; dropped->touch = drop_temp_touch; dropped->owner = ent; if (ent->client) { trace_t trace; AngleVectors(ent->client->v_angle, forward, right, NULL); VectorSet(offset, 24, 0, -16); G_ProjectSource(ent->s.origin, offset, forward, right, dropped->s.origin); trace = gi.trace(ent->s.origin, dropped->mins, dropped->maxs, dropped->s.origin, ent, CONTENTS_SOLID); VectorCopy(trace.endpos, dropped->s.origin); } else { AngleVectors(ent->s.angles, forward, right, NULL); VectorCopy(ent->s.origin, dropped->s.origin); } VectorScale(forward, 100, dropped->velocity); dropped->velocity[2] = 300; dropped->think = drop_make_touchable; dropped->nextthink = level.time + 1; gi.linkentity(dropped); return dropped; } void Use_Item(edict_t *ent, edict_t *other /* unused */, edict_t *activator /* unused */) { if (!ent) { return; } ent->svflags &= ~SVF_NOCLIENT; ent->use = NULL; if (ent->spawnflags & ITEM_NO_TOUCH) { ent->solid = SOLID_BBOX; ent->touch = NULL; } else { ent->solid = SOLID_TRIGGER; ent->touch = Touch_Item; } gi.linkentity(ent); } /* ====================================================================== */ void droptofloor(edict_t *ent) { if (!ent) { return; } trace_t tr; vec3_t dest; float *v; v = tv(-15, -15, -15); VectorCopy(v, ent->mins); v = tv(15, 15, 15); VectorCopy(v, ent->maxs); if (ent->model) { gi.setmodel(ent, ent->model); } else if (ent->item->world_model) { gi.setmodel(ent, ent->item->world_model); } ent->solid = SOLID_TRIGGER; ent->movetype = MOVETYPE_TOSS; ent->touch = Touch_Item; v = tv(0, 0, -128); VectorAdd(ent->s.origin, v, dest); tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID); if (tr.startsolid) { gi.dprintf("droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin)); G_FreeEdict(ent); return; } VectorCopy(tr.endpos, ent->s.origin); if (ent->team) { ent->flags &= ~FL_TEAMSLAVE; ent->chain = ent->teamchain; ent->teamchain = NULL; ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; if (ent == ent->teammaster) { ent->nextthink = level.time + FRAMETIME; ent->think = DoRespawn; } } if (ent->spawnflags & ITEM_NO_TOUCH) { ent->solid = SOLID_BBOX; ent->touch = NULL; ent->s.effects &= ~EF_ROTATE; ent->s.renderfx &= ~RF_GLOW; } if (ent->spawnflags & ITEM_TRIGGER_SPAWN) { ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; ent->use = Use_Item; } gi.linkentity(ent); } /* * Precaches all data needed for a given item. * This will be called for each item spawned in a level, * and for each item in each client's inventory. */ void PrecacheItem(gitem_t *it) { char *s, *start; char data[MAX_QPATH]; int len; gitem_t *ammo; if (!it) { return; } if (it->pickup_sound) { gi.soundindex(it->pickup_sound); } if (it->world_model) { gi.modelindex(it->world_model); } if (it->view_model) { gi.modelindex(it->view_model); } if (it->icon) { gi.imageindex(it->icon); } /* parse everything for its ammo */ if (it->ammo && it->ammo[0]) { ammo = FindItem(it->ammo); if (ammo != it) { PrecacheItem(ammo); } } /* parse the space seperated precache string for other items */ s = it->precaches; if (!s || !s[0]) { return; } while (*s) { start = s; while (*s && *s != ' ') { s++; } len = s - start; if ((len >= MAX_QPATH) || (len < 5)) { gi.error("PrecacheItem: %s has bad precache string", it->classname); } memcpy(data, start, len); data[len] = 0; if (*s) { s++; } /* determine type based on extension */ if (!strcmp(data + len - 3, "md2")) { gi.modelindex(data); } else if (!strcmp(data + len - 3, "sp2")) { gi.modelindex(data); } else if (!strcmp(data + len - 3, "wav")) { gi.soundindex(data); } if (!strcmp(data + len - 3, "pcx")) { gi.imageindex(data); } } } /* * Create the item marked for spawn creation */ void Item_TriggeredSpawn(edict_t *self, edict_t *other /* unused */, edict_t *activator /* unused */) { self->svflags &= ~SVF_NOCLIENT; self->use = NULL; if (strcmp(self->classname, "key_power_cube")) { self->spawnflags = 0; } droptofloor(self); } /* * Set up an item to spawn in later. */ void SetTriggeredSpawn(edict_t *ent) { if (!ent) { return; } /* don't do anything on key_power_cubes. */ if (!strcmp(ent->classname, "key_power_cube")) { return; } ent->think = NULL; ent->nextthink = 0; ent->use = Item_TriggeredSpawn; ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; } /* * ============ * Sets the clipping size and * plants the object on the floor. * * Items can't be immediately dropped * to floor, because they might be on * an entity that hasn't spawned yet. * ============ */ void SpawnItem(edict_t *ent, gitem_t *item) { if (!ent || !item) { return; } if (!g_disruptor->value) { if ((!strcmp(ent->classname, "ammo_disruptor")) || (!strcmp(ent->classname, "weapon_disintegrator"))) { G_FreeEdict(ent); return; } } if (ent->spawnflags > 1) { if (strcmp(ent->classname, "key_power_cube") != 0) { ent->spawnflags = 0; gi.dprintf("%s at %s has invalid spawnflags set\n", ent->classname, vtos(ent->s.origin)); } } /* some items will be prevented in deathmatch */ if (deathmatch->value) { if ((int)dmflags->value & DF_NO_ARMOR) { if ((item->pickup == Pickup_Armor) || (item->pickup == Pickup_PowerArmor)) { G_FreeEdict(ent); return; } } if ((int)dmflags->value & DF_NO_ITEMS) { if (item->pickup == Pickup_Powerup) { G_FreeEdict(ent); return; } if (item->pickup == Pickup_Sphere) { G_FreeEdict(ent); return; } if (item->pickup == Pickup_Doppleganger) { G_FreeEdict(ent); return; } } if ((int)dmflags->value & DF_NO_HEALTH) { if ((item->pickup == Pickup_Health) || (item->pickup == Pickup_Adrenaline) || (item->pickup == Pickup_AncientHead)) { G_FreeEdict(ent); return; } } if ((int)dmflags->value & DF_INFINITE_AMMO) { if ((item->flags == IT_AMMO) || (strcmp(ent->classname, "weapon_bfg") == 0)) { G_FreeEdict(ent); return; } } if ((int)dmflags->value & DF_NO_MINES) { if (!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")) { G_FreeEdict(ent); return; } } if ((int)dmflags->value & DF_NO_NUKES) { if (!strcmp(ent->classname, "ammo_nuke")) { G_FreeEdict(ent); return; } } if ((int)dmflags->value & DF_NO_SPHERES) { if (item->pickup == Pickup_Sphere) { G_FreeEdict(ent); return; } } } /* DM only items */ if (!deathmatch->value) { if ((item->pickup == Pickup_Doppleganger) || (item->pickup == Pickup_Nuke)) { G_FreeEdict(ent); return; } if ((item->use == Use_Vengeance) || (item->use == Use_Hunter)) { G_FreeEdict(ent); return; } } PrecacheItem(item); if (coop->value && (strcmp(ent->classname, "key_power_cube") == 0)) { ent->spawnflags |= (1 << (8 + level.power_cubes)); level.power_cubes++; } /* don't let them drop items that stay in a coop game */ if ((coop->value) && (item->flags & IT_STAY_COOP)) { item->drop = NULL; } ent->item = item; ent->nextthink = level.time + 2 * FRAMETIME; /* items start after other solids */ ent->think = droptofloor; ent->s.effects = item->world_model_flags; ent->s.renderfx = RF_GLOW; if (ent->model) { gi.modelindex(ent->model); } if (ent->spawnflags & 1) { SetTriggeredSpawn(ent); } } /* ====================================================================== */ gitem_t itemlist[] = { { NULL }, /* leave index 0 alone */ /* QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_armor_body", Pickup_Armor, NULL, NULL, NULL, "misc/ar1_pkup.wav", "models/items/armor/body/tris.md2", EF_ROTATE, NULL, "i_bodyarmor", "Body Armor", 3, 0, NULL, IT_ARMOR, 0, &bodyarmor_info, ARMOR_BODY, "" }, /* QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_armor_combat", Pickup_Armor, NULL, NULL, NULL, "misc/ar1_pkup.wav", "models/items/armor/combat/tris.md2", EF_ROTATE, NULL, "i_combatarmor", "Combat Armor", 3, 0, NULL, IT_ARMOR, 0, &combatarmor_info, ARMOR_COMBAT, "" }, /* QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_armor_jacket", Pickup_Armor, NULL, NULL, NULL, "misc/ar1_pkup.wav", "models/items/armor/jacket/tris.md2", EF_ROTATE, NULL, "i_jacketarmor", "Jacket Armor", 3, 0, NULL, IT_ARMOR, 0, &jacketarmor_info, ARMOR_JACKET, "" }, /* QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_armor_shard", Pickup_Armor, NULL, NULL, NULL, "misc/ar2_pkup.wav", "models/items/armor/shard/tris.md2", EF_ROTATE, NULL, "i_jacketarmor", "Armor Shard", 3, 0, NULL, IT_ARMOR, 0, NULL, ARMOR_SHARD, "" }, /* QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_power_screen", Pickup_PowerArmor, Use_PowerArmor, Drop_PowerArmor, NULL, "misc/ar3_pkup.wav", "models/items/armor/screen/tris.md2", EF_ROTATE, NULL, "i_powerscreen", "Power Screen", 0, 60, NULL, IT_ARMOR, 0, NULL, 0, "" }, /* QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_power_shield", Pickup_PowerArmor, Use_PowerArmor, Drop_PowerArmor, NULL, "misc/ar3_pkup.wav", "models/items/armor/shield/tris.md2", EF_ROTATE, NULL, "i_powershield", "Power Shield", 0, 60, NULL, IT_ARMOR, 0, NULL, 0, "misc/power2.wav misc/power1.wav" }, /* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) always owned, never in the world */ { "weapon_blaster", NULL, Use_Weapon, NULL, Weapon_Blaster, "misc/w_pkup.wav", NULL, 0, "models/weapons/v_blast/tris.md2", "w_blaster", "Blaster", 0, 0, NULL, IT_WEAPON | IT_STAY_COOP, WEAP_BLASTER, NULL, 0, "weapons/blastf1a.wav misc/lasfly.wav" }, /* QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_shotgun", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Shotgun, "misc/w_pkup.wav", "models/weapons/g_shotg/tris.md2", EF_ROTATE, "models/weapons/v_shotg/tris.md2", "w_shotgun", "Shotgun", 0, 1, "Shells", IT_WEAPON | IT_STAY_COOP, WEAP_SHOTGUN, NULL, 0, "weapons/shotgf1b.wav weapons/shotgr1b.wav" }, /* QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_supershotgun", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_SuperShotgun, "misc/w_pkup.wav", "models/weapons/g_shotg2/tris.md2", EF_ROTATE, "models/weapons/v_shotg2/tris.md2", "w_sshotgun", "Super Shotgun", 0, 2, "Shells", IT_WEAPON | IT_STAY_COOP, WEAP_SUPERSHOTGUN, NULL, 0, "weapons/sshotf1b.wav" }, /* QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_machinegun", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Machinegun, "misc/w_pkup.wav", "models/weapons/g_machn/tris.md2", EF_ROTATE, "models/weapons/v_machn/tris.md2", "w_machinegun", "Machinegun", 0, 1, "Bullets", IT_WEAPON | IT_STAY_COOP, WEAP_MACHINEGUN, NULL, 0, "weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav" }, /* QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_chaingun", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Chaingun, "misc/w_pkup.wav", "models/weapons/g_chain/tris.md2", EF_ROTATE, "models/weapons/v_chain/tris.md2", "w_chaingun", "Chaingun", 0, 1, "Bullets", IT_WEAPON | IT_STAY_COOP, WEAP_CHAINGUN, NULL, 0, "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav" }, /* QUAKED weapon_etf_rifle (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_etf_rifle", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_ETF_Rifle, "misc/w_pkup.wav", "models/weapons/g_etf_rifle/tris.md2", EF_ROTATE, "models/weapons/v_etf_rifle/tris.md2", "w_etf_rifle", "ETF Rifle", 0, 1, "Flechettes", IT_WEAPON, WEAP_ETFRIFLE, NULL, 0, "weapons/nail1.wav models/proj/flechette/tris.md2", }, /* QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_grenades", Pickup_Ammo, Use_Weapon, Drop_Ammo, Weapon_Grenade, "misc/am_pkup.wav", "models/items/ammo/grenades/medium/tris.md2", 0, "models/weapons/v_handgr/tris.md2", "a_grenades", "Grenades", 3, 5, "grenades", IT_AMMO | IT_WEAPON, WEAP_GRENADES, NULL, AMMO_GRENADES, "weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav " }, /* QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_grenadelauncher", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_GrenadeLauncher, "misc/w_pkup.wav", "models/weapons/g_launch/tris.md2", EF_ROTATE, "models/weapons/v_launch/tris.md2", "w_glauncher", "Grenade Launcher", 0, 1, "Grenades", IT_WEAPON | IT_STAY_COOP, WEAP_GRENADELAUNCHER, NULL, 0, "models/objects/grenade/tris.md2 weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav" }, /* QUAKED weapon_proxlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_proxlauncher", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_ProxLauncher, "misc/w_pkup.wav", "models/weapons/g_plaunch/tris.md2", EF_ROTATE, "models/weapons/v_plaunch/tris.md2", "w_proxlaunch", "Prox Launcher", 0, 1, "Prox", IT_WEAPON, WEAP_PROXLAUNCH, NULL, AMMO_PROX, "weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav weapons/proxwarn.wav weapons/proxopen.wav", }, /* QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_rocketlauncher", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_RocketLauncher, "misc/w_pkup.wav", "models/weapons/g_rocket/tris.md2", EF_ROTATE, "models/weapons/v_rocket/tris.md2", "w_rlauncher", "Rocket Launcher", 0, 1, "Rockets", IT_WEAPON | IT_STAY_COOP, WEAP_ROCKETLAUNCHER, NULL, 0, "models/objects/rocket/tris.md2 weapons/rockfly.wav weapons/rocklf1a.wav weapons/rocklr1b.wav models/objects/debris2/tris.md2" }, /* QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_hyperblaster", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_HyperBlaster, "misc/w_pkup.wav", "models/weapons/g_hyperb/tris.md2", EF_ROTATE, "models/weapons/v_hyperb/tris.md2", "w_hyperblaster", "HyperBlaster", 0, 1, "Cells", IT_WEAPON | IT_STAY_COOP, WEAP_HYPERBLASTER, NULL, 0, "weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav" }, /* QUAKED weapon_plasmabeam (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_plasmabeam", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Heatbeam, "misc/w_pkup.wav", "models/weapons/g_beamer/tris.md2", EF_ROTATE, "models/weapons/v_beamer/tris.md2", "w_heatbeam", "Plasma Beam", 0, 2, "Cells", IT_WEAPON, WEAP_PLASMA, NULL, 0, "models/weapons/v_beamer2/tris.md2 weapons/bfg__l1a.wav", }, /* QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_railgun", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Railgun, "misc/w_pkup.wav", "models/weapons/g_rail/tris.md2", EF_ROTATE, "models/weapons/v_rail/tris.md2", "w_railgun", "Railgun", 0, 1, "Slugs", IT_WEAPON | IT_STAY_COOP, WEAP_RAILGUN, NULL, 0, "weapons/rg_hum.wav" }, /* QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_bfg", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_BFG, "misc/w_pkup.wav", "models/weapons/g_bfg/tris.md2", EF_ROTATE, "models/weapons/v_bfg/tris.md2", "w_bfg", "BFG10K", 0, 50, "Cells", IT_WEAPON | IT_STAY_COOP, WEAP_BFG, NULL, 0, "sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav" }, /* QUAKED weapon_chainfist (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_chainfist", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_ChainFist, "misc/w_pkup.wav", "models/weapons/g_chainf/tris.md2", EF_ROTATE, "models/weapons/v_chainf/tris.md2", "w_chainfist", "Chainfist", 0, 0, NULL, IT_WEAPON | IT_MELEE, WEAP_CHAINFIST, NULL, 1, "weapons/sawidle.wav weapons/sawhit.wav", }, /* QUAKED weapon_disintegrator (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "weapon_disintegrator", Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Disintegrator, "misc/w_pkup.wav", "models/weapons/g_dist/tris.md2", EF_ROTATE, "models/weapons/v_dist/tris.md2", "w_disintegrator", "Disruptor", 0, 1, "Rounds", IT_WEAPON, WEAP_DISRUPTOR, NULL, 1, "models/items/spawngro/tris.md2 models/proj/disintegrator/tris.md2 weapons/disrupt.wav weapons/disint2.wav weapons/disrupthit.wav", }, /* QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_shells", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/items/ammo/shells/medium/tris.md2", 0, NULL, "a_shells", "Shells", 3, 10, NULL, IT_AMMO, 0, NULL, AMMO_SHELLS, "" }, /* QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_bullets", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/items/ammo/bullets/medium/tris.md2", 0, NULL, "a_bullets", "Bullets", 3, 50, NULL, IT_AMMO, 0, NULL, AMMO_BULLETS, "" }, /* QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_cells", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/items/ammo/cells/medium/tris.md2", 0, NULL, "a_cells", "Cells", 3, 50, NULL, IT_AMMO, 0, NULL, AMMO_CELLS, "" }, /* QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_rockets", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/items/ammo/rockets/medium/tris.md2", 0, NULL, "a_rockets", "Rockets", 3, 5, NULL, IT_AMMO, 0, NULL, AMMO_ROCKETS, "" }, /* QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_slugs", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/items/ammo/slugs/medium/tris.md2", 0, NULL, "a_slugs", "Slugs", 3, 10, NULL, IT_AMMO, 0, NULL, AMMO_SLUGS, "" }, /* QUAKED ammo_flechettes (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_flechettes", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/ammo/am_flechette/tris.md2", 0, NULL, "a_flechettes", "Flechettes", 3, 50, NULL, IT_AMMO, 0, NULL, AMMO_FLECHETTES }, /* QUAKED ammo_prox (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_prox", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/ammo/am_prox/tris.md2", 0, NULL, "a_prox", "Prox", 3, 5, NULL, IT_AMMO, 0, NULL, AMMO_PROX, "models/weapons/g_prox/tris.md2 weapons/proxwarn.wav" }, /* QUAKED ammo_tesla (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_tesla", Pickup_Ammo, Use_Weapon, Drop_Ammo, Weapon_Tesla, "misc/am_pkup.wav", "models/ammo/am_tesl/tris.md2", 0, "models/weapons/v_tesla/tris.md2", "a_tesla", "Tesla", 3, 5, "Tesla", IT_AMMO | IT_WEAPON, 0, NULL, AMMO_TESLA, "models/weapons/v_tesla2/tris.md2 weapons/teslaopen.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav models/weapons/g_tesla/tris.md2" }, /* QUAKED ammo_nuke (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_nuke", Pickup_Nuke, Use_Nuke, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/weapons/g_nuke/tris.md2", EF_ROTATE, NULL, "p_nuke", "A-M Bomb", 3, 300, "A-M Bomb", IT_POWERUP, 0, NULL, 0, "weapons/nukewarn2.wav world/rumble.wav" }, /* QUAKED ammo_disruptor (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "ammo_disruptor", Pickup_Ammo, NULL, Drop_Ammo, NULL, "misc/am_pkup.wav", "models/ammo/am_disr/tris.md2", 0, NULL, "a_disruptor", "Rounds", 3, 15, NULL, IT_AMMO, 0, NULL, AMMO_DISRUPTOR }, /* QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_quad", Pickup_Powerup, Use_Quad, Drop_General, NULL, "items/pkup.wav", "models/items/quaddama/tris.md2", EF_ROTATE, NULL, "p_quad", "Quad Damage", 2, 60, NULL, IT_POWERUP|IT_INSTANT_USE, 0, NULL, 0, "items/damage.wav items/damage2.wav items/damage3.wav" }, /* QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_invulnerability", Pickup_Powerup, Use_Invulnerability, Drop_General, NULL, "items/pkup.wav", "models/items/invulner/tris.md2", EF_ROTATE, NULL, "p_invulnerability", "Invulnerability", 2, 300, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "items/protect.wav items/protect2.wav items/protect4.wav" }, /* QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_silencer", Pickup_Powerup, Use_Silencer, Drop_General, NULL, "items/pkup.wav", "models/items/silencer/tris.md2", EF_ROTATE, NULL, "p_silencer", "Silencer", 2, 60, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "" }, /* QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_breather", Pickup_Powerup, Use_Breather, Drop_General, NULL, "items/pkup.wav", "models/items/breather/tris.md2", EF_ROTATE, NULL, "p_rebreather", "Rebreather", 2, 60, NULL, IT_STAY_COOP | IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "items/airout.wav" }, /* QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_enviro", Pickup_Powerup, Use_Envirosuit, Drop_General, NULL, "items/pkup.wav", "models/items/enviro/tris.md2", EF_ROTATE, NULL, "p_envirosuit", "Environment Suit", 2, 60, NULL, IT_STAY_COOP | IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "items/airout.wav" }, /* QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN Special item that gives +2 to maximum health */ { "item_ancient_head", Pickup_AncientHead, NULL, NULL, NULL, "items/pkup.wav", "models/items/c_head/tris.md2", EF_ROTATE, NULL, "i_fixme", "Ancient Head", 2, 60, NULL, 0, 0, NULL, 0, "" }, /* QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN gives +1 to maximum health */ { "item_adrenaline", Pickup_Adrenaline, NULL, NULL, NULL, "items/pkup.wav", "models/items/adrenal/tris.md2", EF_ROTATE, NULL, "p_adrenaline", "Adrenaline", 2, 60, NULL, 0, 0, NULL, 0, "" }, /* QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_bandolier", Pickup_Bandolier, NULL, NULL, NULL, "items/pkup.wav", "models/items/band/tris.md2", EF_ROTATE, NULL, "p_bandolier", "Bandolier", 2, 60, NULL, 0, 0, NULL, 0, "" }, /* QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_pack", Pickup_Pack, NULL, NULL, NULL, "items/pkup.wav", "models/items/pack/tris.md2", EF_ROTATE, NULL, "i_pack", "Ammo Pack", 2, 180, NULL, 0, 0, NULL, 0, "" }, /* QUAKED item_ir_goggles (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_ir_goggles", Pickup_Powerup, Use_IR, Drop_General, NULL, "items/pkup.wav", "models/items/goggles/tris.md2", EF_ROTATE, NULL, "p_ir", "IR Goggles", 2, 60, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "misc/ir_start.wav" }, /* QUAKED item_double (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_double", Pickup_Powerup, Use_Double, Drop_General, NULL, "items/pkup.wav", "models/items/ddamage/tris.md2", EF_ROTATE, NULL, "p_double", "Double Damage", 2, 60, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "misc/ddamage1.wav misc/ddamage2.wav misc/ddamage3.wav" }, /* QUAKED item_compass (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_compass", Pickup_Powerup, Use_Compass, NULL, NULL, "items/pkup.wav", "models/objects/fire/tris.md2", EF_ROTATE, NULL, "p_compass", "compass", 2, 60, NULL, IT_POWERUP, 0, NULL, 0, }, /* QUAKED item_sphere_vengeance (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_sphere_vengeance", Pickup_Sphere, Use_Vengeance, NULL, NULL, "items/pkup.wav", "models/items/vengnce/tris.md2", EF_ROTATE, NULL, "p_vengeance", "vengeance sphere", 2, 60, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "spheres/v_idle.wav" }, /* QUAKED item_sphere_hunter (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_sphere_hunter", Pickup_Sphere, Use_Hunter, NULL, NULL, "items/pkup.wav", "models/items/hunter/tris.md2", EF_ROTATE, NULL, "p_hunter", "hunter sphere", 2, 120, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "spheres/h_idle.wav spheres/h_active.wav spheres/h_lurk.wav" }, /* QUAKED item_sphere_defender (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_sphere_defender", Pickup_Sphere, Use_Defender, NULL, NULL, "items/pkup.wav", "models/items/defender/tris.md2", EF_ROTATE, NULL, "p_defender", "defender sphere", 2, 60, NULL, IT_POWERUP | IT_INSTANT_USE, 0, NULL, 0, "models/proj/laser2/tris.md2 models/items/shell/tris.md2 spheres/d_idle.wav" }, /* QUAKED item_doppleganger (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "item_doppleganger", Pickup_Doppleganger, Use_Doppleganger, Drop_General, NULL, "items/pkup.wav", "models/items/dopple/tris.md2", EF_ROTATE, NULL, "p_doppleganger", "Doppleganger", 0, 90, NULL, IT_POWERUP, 0, NULL, 0, "models/objects/dopplebase/tris.md2 models/items/spawngro2/tris.md2 models/items/hunter/tris.md2 models/items/vengnce/tris.md2", }, { NULL, Tag_PickupToken, NULL, NULL, NULL, "items/pkup.wav", "models/items/tagtoken/tris.md2", EF_ROTATE | EF_TAGTRAIL, NULL, "i_tagtoken", "Tag Token", 0, 0, NULL, IT_POWERUP | IT_NOT_GIVEABLE, 0, NULL, 1, NULL, }, /* QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN key for computer centers */ { "key_data_cd", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/data_cd/tris.md2", EF_ROTATE, NULL, "k_datacd", "Data CD", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_power_cube (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN NO_TOUCH warehouse circuits */ { "key_power_cube", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/power/tris.md2", EF_ROTATE, NULL, "k_powercube", "Power Cube", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN key for the entrance of jail3 */ { "key_pyramid", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/pyramid/tris.md2", EF_ROTATE, NULL, "k_pyramid", "Pyramid Key", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN key for the city computer */ { "key_data_spinner", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/spinner/tris.md2", EF_ROTATE, NULL, "k_dataspin", "Data Spinner", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN security pass for the security level */ { "key_pass", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/pass/tris.md2", EF_ROTATE, NULL, "k_security", "Security Pass", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN normal door key - blue */ { "key_blue_key", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/key/tris.md2", EF_ROTATE, NULL, "k_bluekey", "Blue Key", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN normal door key - red */ { "key_red_key", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/red_key/tris.md2", EF_ROTATE, NULL, "k_redkey", "Red Key", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN tank commander's head */ { "key_commander_head", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/monsters/commandr/head/tris.md2", EF_GIB, NULL, "k_comhead", "Commander's Head", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN tank commander's head */ { "key_airstrike_target", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/items/keys/target/tris.md2", EF_ROTATE, NULL, "i_airstrike", "Airstrike Marker", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, "" }, /* QUAKED key_nuke_container (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "key_nuke_container", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/weapons/g_nuke/tris.md2", EF_ROTATE, NULL, "i_contain", "Antimatter Pod", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, NULL, }, /* QUAKED key_nuke (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ { "key_nuke", Pickup_Key, NULL, Drop_General, NULL, "items/pkup.wav", "models/weapons/g_nuke/tris.md2", EF_ROTATE, NULL, "i_nuke", "Antimatter Bomb", 2, 0, NULL, IT_STAY_COOP | IT_KEY, 0, NULL, 0, NULL, }, { NULL, Pickup_Health, NULL, NULL, NULL, "items/pkup.wav", NULL, 0, NULL, "i_health", "Health", 3, 0, NULL, 0, 0, NULL, 0, "items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav" }, /* end of list marker */ {NULL} }; /* * QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ void SP_item_health(edict_t *self) { if (!self) { return; } if (deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH)) { G_FreeEdict(self); return; } self->model = "models/items/healing/medium/tris.md2"; self->count = 10; SpawnItem(self, FindItem("Health")); gi.soundindex("items/n_health.wav"); } /* * QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ void SP_item_health_small(edict_t *self) { if (!self) { return; } if (deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH)) { G_FreeEdict(self); return; } self->model = "models/items/healing/stimpack/tris.md2"; self->count = 2; SpawnItem(self, FindItem("Health")); self->style = HEALTH_IGNORE_MAX; gi.soundindex("items/s_health.wav"); } /* * QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ void SP_item_health_large(edict_t *self) { if (!self) { return; } if (deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH)) { G_FreeEdict(self); return; } self->model = "models/items/healing/large/tris.md2"; self->count = 25; SpawnItem(self, FindItem("Health")); gi.soundindex("items/l_health.wav"); } /* * QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN */ void SP_item_health_mega(edict_t *self) { if (!self) { return; } if (deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH)) { G_FreeEdict(self); return; } self->model = "models/items/mega_h/tris.md2"; self->count = 100; SpawnItem(self, FindItem("Health")); gi.soundindex("items/m_health.wav"); self->style = HEALTH_IGNORE_MAX | HEALTH_TIMED; } void InitItems(void) { game.num_items = sizeof(itemlist) / sizeof(itemlist[0]) - 1; } /* * Called by worldspawn */ void SetItemNames(void) { int i; gitem_t *it; for (i = 0; i < game.num_items; i++) { it = &itemlist[i]; gi.configstring(CS_ITEMS + i, it->pickup_name); } jacket_armor_index = ITEM_INDEX(FindItem("Jacket Armor")); combat_armor_index = ITEM_INDEX(FindItem("Combat Armor")); body_armor_index = ITEM_INDEX(FindItem("Body Armor")); power_screen_index = ITEM_INDEX(FindItem("Power Screen")); power_shield_index = ITEM_INDEX(FindItem("Power Shield")); } void SP_xatrix_item(edict_t *self) { gitem_t *item; int i; char *spawnClass = NULL; if (!self) { return; } if (!self->classname) { return; } if (!strcmp(self->classname, "ammo_magslug")) { spawnClass = "ammo_flechettes"; } else if (!strcmp(self->classname, "ammo_trap")) { spawnClass = "weapon_proxlauncher"; } else if (!strcmp(self->classname, "item_quadfire")) { float chance; chance = random(); if (chance < 0.2) { spawnClass = "item_sphere_hunter"; } else if (chance < 0.6) { spawnClass = "item_sphere_vengeance"; } else { spawnClass = "item_sphere_defender"; } } else if (!strcmp(self->classname, "weapon_boomer")) { spawnClass = "weapon_etf_rifle"; } else if (!strcmp(self->classname, "weapon_phalanx")) { spawnClass = "weapon_plasmabeam"; } /* check item spawn functions */ for (i = 0, item = itemlist; i < game.num_items; i++, item++) { if (!item->classname) { continue; } if (!strcmp(item->classname, spawnClass)) { /* found it */ SpawnItem(self, item); return; } } }