/* 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" 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 *item ); void G_InitWeapons( void ); void Weapon_Generic( edict_t *ent ); #define ARMOR_SHARD_VALUE 5 #ifdef UNBALANCED_ARMORS #ifdef ARMOR_SYSTEM_OF_THE_DAY gitem_armor_t g_armor_info = { 25, 75, 0.80f, ARMOR_GA }; gitem_armor_t y_armor_info = { 50, 100, 0.80f, ARMOR_YA }; gitem_armor_t r_armor_info = { 100, 200, 0.80f, ARMOR_RA }; // has armor decay #else gitem_armor_t g_armor_info = { 25, 75, 0.50f, ARMOR_GA }; gitem_armor_t y_armor_info = { 50, 100, 0.66f, ARMOR_YA }; gitem_armor_t r_armor_info = { 100, 150, 0.75f, ARMOR_RA }; #endif #else gitem_armor_t g_armor_info = { 50, 100, 0.50f, ARMOR_GA }; gitem_armor_t y_armor_info = { 100, 150, 0.66f, ARMOR_YA }; gitem_armor_t r_armor_info = { 150, 200, 0.75f, ARMOR_RA }; #endif #define HEALTH_IGNORE_MAX 1 #define HEALTH_TIMED 2 void Use_Quad( edict_t *ent, gitem_t *item ); static int quad_drop_timeout_hack; //====================================================================== void DoRespawn( edict_t *ent ) { if( ent->team ) { edict_t *master; int count; int choice; master = ent->teammaster; //in ctf, when we are weapons stay, only the master of a team of weapons is spawned if( game.gametype == GAMETYPE_CTF && (dmflags->integer & DF_WEAPONS_STAY) && master->item && (master->item->type & IT_WEAPON) ) ent = master; else { for( count = 0, ent = master; ent; ent = ent->chain, count++ ); choice = rand() % count; for (count = 0, ent = master; count < choice; ent = ent->chain, count++); } } ent->r.svflags &= ~SVF_NOCLIENT; ent->r.solid = SOLID_TRIGGER; trap_LinkEntity(ent); // send an effect G_AddEvent( ent, EV_ITEM_RESPAWN, ent->item ? ent->item->tag : 0, qtrue ); } void SetRespawn( edict_t *ent, float delay ) { if( delay < 0 ) { G_FreeEdict(ent); return; } ent->flags |= FL_RESPAWN; ent->r.svflags |= SVF_NOCLIENT; ent->r.solid = SOLID_NOT; ent->nextthink = level.timemsec + 1000 * delay; ent->think = DoRespawn; trap_LinkEntity(ent); } //====================================================================== qboolean Pickup_Powerup( edict_t *ent, edict_t *other ) { int quantity; if( !ent->item || !ent->item->tag ) return qfalse; quantity = other->r.client->inventory[ent->item->tag]; //if ((game.gametype == GAMETYPE_COOP) && (ent->item->flags & ITFLAG_STAY_COOP) && (quantity > 0)) // return qfalse; other->r.client->inventory[ent->item->tag]++; if( !G_Gametype_CanRespawnItem(ent->item) ) return qtrue; //set for respawn if in multiplayer mode if( !(ent->spawnflags & DROPPED_ITEM) ) SetRespawn( ent, G_Gametype_RespawnTimeForItem(ent->item) ); if( (dmflags->integer & DF_INSTANT_ITEMS) || ( (ent->item->tag == POWERUP_QUAD) && (ent->spawnflags & DROPPED_PLAYER_ITEM) ) ) { if( (ent->item->tag == POWERUP_QUAD) && (ent->spawnflags & DROPPED_PLAYER_ITEM) ) quad_drop_timeout_hack = (ent->nextthink - level.timemsec); G_UseItem( other, ent->item ); } return qtrue; } void Drop_General( edict_t *ent, gitem_t *item ) { if( Drop_Item( ent, item ) ) { ent->r.client->inventory[item->tag]--; ValidateSelectedItem(ent); } } //====================================================================== qboolean Pickup_AmmoPack( edict_t *ent, edict_t *other ) { gclient_t *client = other->r.client; firedef_t *firedef; int i; if( !client ) return qfalse; for( i=1; i < AMMO_TOTAL; i++ ) { firedef = G_FiredefForAmmo( i ); if( firedef ) { client->inventory[i] += ent->invpak[i]; if( client->inventory[i] > firedef->ammo_max ) client->inventory[i] = firedef->ammo_max; } } if( !(ent->spawnflags & DROPPED_ITEM) && G_Gametype_CanRespawnItem(ent->item) ) SetRespawn( ent, G_Gametype_RespawnTimeForItem(ent->item) ); return qtrue; } //====================================================================== void Use_Quad( edict_t *ent, gitem_t *item ) { int timeout; ent->r.client->inventory[item->tag]--; ValidateSelectedItem(ent); if( quad_drop_timeout_hack ) { timeout = quad_drop_timeout_hack; quad_drop_timeout_hack = 0; } else { timeout = 30000; } if( ent->r.client->quad_timeout > level.timemsec ) ent->r.client->quad_timeout += timeout; else ent->r.client->quad_timeout = level.timemsec + timeout; G_Sound( ent, CHAN_ITEM, trap_SoundIndex(S_QUAD_USE), 1, ATTN_NORM ); } //====================================================================== void Use_Silencer( edict_t *ent, gitem_t *item ) { ent->r.client->inventory[item->tag]--; ValidateSelectedItem(ent); ent->r.client->silencer_shots += 30; } //====================================================================== qboolean Add_Ammo( edict_t *ent, gitem_t *item, int count, qboolean add_it ) { firedef_t *firedef; int max; if( !ent->r.client ) return qfalse; firedef = G_FiredefForAmmo( item->tag ); if( firedef ) max = firedef->ammo_max; else max = -1; if( max < 0 ) return qfalse; if( ent->r.client->inventory[item->tag] >= max ) return qfalse; if( add_it ) { ent->r.client->inventory[item->tag] += count; if( ent->r.client->inventory[item->tag] > max ) ent->r.client->inventory[item->tag] = max; } return qtrue; } qboolean Pickup_Ammo( edict_t *ent, edict_t *other ) { int oldcount; int count; qboolean weapon; weapon = (ent->item->type & IT_WEAPON); if( (weapon) && ( dmflags->integer & DF_INFINITE_AMMO ) ) count = 1000; else if( ent->count ) count = ent->count; else count = ent->item->quantity; oldcount = other->r.client->inventory[ent->item->tag]; if( !Add_Ammo (other, ent->item, count, qtrue) ) return qfalse; if( weapon && !oldcount ) { if( !other->s.weapon || (other->s.weapon != ent->item->tag && other->s.weapon == WEAP_GUNBLADE) )//newgametypes other->r.client->latched_weapon = ent->item->tag; } if( !(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) && G_Gametype_CanRespawnItem(ent->item) ) SetRespawn( ent, G_Gametype_RespawnTimeForItem(ent->item) ); return qtrue; } void Drop_Ammo( edict_t *ent, gitem_t *item ) { edict_t *dropped; int index; index = item->tag; dropped = Drop_Item( ent, item ); if( dropped ) { if( ent->r.client->inventory[index] >= item->quantity ) dropped->count = item->quantity; else dropped->count = ent->r.client->inventory[index]; ent->r.client->inventory[index] -= dropped->count; } ValidateSelectedItem(ent); } //====================================================================== void MegaHealth_think( edict_t *self ) { if( HEALTH_TO_INT(self->r.owner->health) > self->r.owner->max_health ) { self->nextthink = level.timemsec + G_FRAMETIME; //self->r.owner->health -= 1; // done in G_GameType_ClientHealthRule now return; } // player is back under max health so we can set respawn time for next MH if( !(self->spawnflags & DROPPED_ITEM) && G_Gametype_CanRespawnItem(self->item) ) SetRespawn( self, G_Gametype_RespawnTimeForItem(self->item) ); else G_FreeEdict(self); } qboolean Pickup_Health( edict_t *ent, edict_t *other ) { if( !(ent->style & HEALTH_IGNORE_MAX) ) if( HEALTH_TO_INT(other->health) >= other->max_health ) return qfalse; other->health += ent->item->quantity; if( !(ent->style & HEALTH_IGNORE_MAX) ) { if( other->health > other->max_health ) other->health = other->max_health; } else { if( game.gametype == GAMETYPE_MIDAIR ) { if( other->health > 300 ) other->health = 300; } else { if( other->health > 200 ) other->health = 200; } } if( ent->style & HEALTH_TIMED ) { ent->think = MegaHealth_think; ent->nextthink = level.timemsec + G_FRAMETIME; ent->r.owner = other; ent->flags |= FL_RESPAWN; ent->r.svflags |= SVF_NOCLIENT; ent->r.solid = SOLID_NOT; } else { if( !(ent->spawnflags & DROPPED_ITEM) && G_Gametype_CanRespawnItem(ent->item) ) SetRespawn( ent, G_Gametype_RespawnTimeForItem(ent->item) ); } return qtrue; } //====================================================================== #define SALVAGE_AVERAGE qboolean Add_Armor( edict_t *ent, edict_t *other, qboolean pick_it ) { gclient_t *client; int player_armor_tag; int item_armor_tag; gitem_armor_t *item_armor_info = NULL; int newarmortag = 0; int newcount = 0; if( !other->r.client ) return qfalse; client = other->r.client; // organize our data player_armor_tag = client->armortag; item_armor_tag = ent->item->tag; item_armor_info = (gitem_armor_t *)ent->item->info; // if player has no armor, just use it if( !player_armor_tag ) { // handle armor shards specially if( ent->item->tag == ARMOR_SHARD ) { newarmortag = ARMOR_GA; newcount = ARMOR_SHARD_VALUE; } else { newarmortag = item_armor_info->armor; newcount = item_armor_info->base_count; } } //player had armor. Mix up. else { //find player armor infos gitem_armor_t *player_armor_info = (gitem_armor_t *)game.items[player_armor_tag]->info; int player_armor_count = client->armor; // handle armor shards specially if( ent->item->tag == ARMOR_SHARD ) { //can't pick up shards if topped of RA if( player_armor_count >= ((gitem_armor_t *)game.items[ARMOR_RA]->info)->max_count ) return qfalse; newarmortag = player_armor_tag; newcount = min( player_armor_count + ARMOR_SHARD_VALUE, ((gitem_armor_t *)game.items[ARMOR_RA]->info)->max_count ); } // can't pick if he's topped up of item's armor else if( player_armor_tag >= item_armor_tag && player_armor_count >= item_armor_info->max_count ) { return qfalse; } else { //player's armor is pickable newarmortag = item_armor_info->armor; #ifdef SALVAGE_AVERAGE // convert the old armor quantity to it's quantity based in the new protection newcount = item_armor_info->base_count + (player_armor_count * (player_armor_info->protection / item_armor_info->protection)); #else //SALVAGE_AVERAGE newcount = item_armor_info->base_count + player_armor_count; #endif //SALVAGE_AVERAGE if( newcount > item_armor_info->max_count ) newcount = item_armor_info->max_count; } } // compute result if( !newarmortag || !newcount ) return qfalse; if( pick_it ) { //update player armor client->armor = newcount; client->armortag = newarmortag; // picked. Set up for respawn if( !(ent->spawnflags & DROPPED_ITEM) && G_Gametype_CanRespawnItem(ent->item) )//newgametypes SetRespawn( ent, G_Gametype_RespawnTimeForItem(ent->item) ); } return qtrue; } qboolean Pickup_Armor( edict_t *ent, edict_t *other ) { return Add_Armor( ent, other, qtrue ); } //====================================================================== //====================================================================== //=============== //Touch_Item //=============== void Touch_Item( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { qboolean taken; if( !other->r.client ) return; if( G_IsDead(other) ) return; // dead people can't pickup if( !ent->item ) return; if( !(ent->item->flags & ITFLAG_PICKABLE) ) return; // not a grabbable item if( !G_Gametype_CanPickUpItem( ent->item ) ) return; taken = G_PickupItem( ent, other ); if( taken ) { // flash the screen G_AddPlayerStateEvent( other->r.client, PSEV_PICKUP, 0 ); // for messages other->r.client->resp.last_pickup = ent; // show icon and name on status bar other->r.client->ps.stats[STAT_PICKUP_ITEM] = ent->item->tag; other->r.client->pickup_msg_time = level.time + 3.0; if (ent->item->pickup_sound) { if( ent->item->type & IT_POWERUP ) G_Sound( other, CHAN_ITEM, trap_SoundIndex(ent->item->pickup_sound), 1, ATTN_NORM ); else G_Sound( other, CHAN_AUTO, trap_SoundIndex(ent->item->pickup_sound), 1, ATTN_NORM ); } } if( !(ent->spawnflags & ITEM_TARGETS_USED) ) { G_UseTargets( ent, other ); ent->spawnflags |= ITEM_TARGETS_USED; } if (!taken) return; // wsw: Medar: I don't really know what this does tbh :P if( (ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) ) { if( ent->flags & FL_RESPAWN ) ent->flags &= ~FL_RESPAWN; else G_FreeEdict(ent); } } //====================================================================== static void drop_temp_touch( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { if( other == ent->r.owner ) return; Touch_Item( ent, other, plane, surfFlags ); } static void drop_make_touchable( edict_t *ent ) { int timeout; ent->touch = Touch_Item; timeout = G_Gametype_DroppedItemTimeout( ent->item ); if( timeout ) { ent->nextthink = level.timemsec + 1000 * timeout; 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( !G_Gametype_CanDropItem(item) ) return NULL; dropped = G_Spawn(); dropped->classname = item->classname; dropped->item = item; dropped->spawnflags = DROPPED_ITEM; VectorCopy( item_box_mins, dropped->r.mins ); VectorCopy( item_box_maxs, dropped->r.maxs ); dropped->r.solid = SOLID_TRIGGER; dropped->movetype = MOVETYPE_TOSS; dropped->touch = drop_temp_touch; dropped->r.owner = ent; dropped->s.team = ent->s.team; // wsw : jal : newgametypes dropped->s.type = ET_ITEM; // wsw : jal : simpleitems dropped->s.skinnum = item->tag; dropped->s.effects = 0; // default effects are applied client side dropped->s.renderfx = 0; dropped->s.modelindex = trap_ModelIndex( dropped->item->world_model[0] ); dropped->s.modelindex2 = trap_ModelIndex( dropped->item->world_model[1] ); if( ent->r.client ) { trace_t trace; AngleVectors( ent->r.client->v_angle, forward, right, NULL ); VectorSet( offset, 24, 0, -16 ); G_ProjectSource( ent->s.origin, offset, forward, right, dropped->s.origin ); trap_Trace (&trace, ent->s.origin, dropped->r.mins, dropped->r.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.timemsec + 1000; ent->r.client->resp.last_drop_item = item; VectorCopy( dropped->s.origin, ent->r.client->resp.last_drop_location ); trap_LinkEntity( dropped ); return dropped; } //====================================================================== //================ //G_PickupItem //================ qboolean G_PickupItem( edict_t *ent, edict_t *other ) { gitem_t *it; if( !ent || !other ) return qfalse; if( !ent->item || !(ent->item->flags & ITFLAG_PICKABLE) ) return qfalse; it = ent->item; if( it->type & IT_WEAPON ) { return Pickup_Weapon( ent, other ); } else if( it->type & IT_AMMO ) { if( !Q_stricmp(it->classname, "item_ammopack") ) return Pickup_AmmoPack( ent, other ); else return Pickup_Ammo( ent, other ); } else if( it->type & IT_ARMOR ) { return Pickup_Armor( ent, other ); } else if( it->type & IT_HEALTH ) { return Pickup_Health( ent, other ); } else if( it->type & IT_POWERUP ) { return Pickup_Powerup( ent, other ); } else if( it->type & IT_FLAG ) { return G_Gametype_CTF_Pickup_Flag( ent, other ); } return qfalse; } //================ //G_DropItem //================ void G_DropItem( edict_t *ent, gitem_t *it ) { if( !it || !(it->flags & ITFLAG_DROPABLE) ) return; if( !G_Gametype_CanDropItem(it) ) return; if( it->type & IT_WEAPON ) { Drop_Weapon( ent, it ); } else if( it->type & IT_AMMO ) { Drop_Ammo( ent, it ); } else if( it->type & IT_FLAG ) { G_Gametype_CTF_Drop_Flag( ent, it ); } else { Drop_General( ent, it ); } } //================ //G_UseItem //================ void G_UseItem( edict_t *ent, gitem_t *it ) { if( !it || !(it->flags & ITFLAG_USABLE) ) return; if( it->type & IT_WEAPON ) { Use_Weapon( ent, it ); } else if( it->type & IT_POWERUP ) { if( it->tag == POWERUP_QUAD ) Use_Quad( ent, it ); } } //====================================================================== //================ //Finish_SpawningItem //================ void Finish_SpawningItem( edict_t *ent ) { trace_t tr; vec3_t dest; VectorCopy( item_box_mins, ent->r.mins ); VectorCopy( item_box_maxs, ent->r.maxs ); if( ent->model ) { ent->s.modelindex = trap_ModelIndex( ent->model ); } else { if( ent->item->world_model[0] ) ent->s.modelindex = trap_ModelIndex( ent->item->world_model[0] ); if( ent->item->world_model[1] ) ent->s.modelindex2 = trap_ModelIndex( ent->item->world_model[1] ); } ent->s.renderfx = 0; ent->r.solid = SOLID_TRIGGER; ent->movetype = MOVETYPE_TOSS; ent->touch = Touch_Item; if( !(ent->spawnflags & 1) ) { // droptofloor // see if they start in a solid position trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, ent->s.origin, ent, MASK_SOLID ); if( tr.startsolid ) { // move it 1 unit up, cause it's typical they share the leaf with the floor VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] + 1 ); trap_Trace( &tr, dest, ent->r.mins, ent->r.maxs, ent->s.origin, ent, MASK_SOLID ); if( tr.startsolid ) { if( developer->integer ) G_Printf( "droptofloor(1): %s startsolid at %s\n", ent->classname, vtos(ent->s.origin) ); G_FreeEdict( ent ); return; } VectorCopy( dest, ent->s.origin ); } VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 128 ); trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent, MASK_SOLID ); if( tr.startsolid ) { if( developer->integer ) G_Printf( "droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin) ); G_FreeEdict( ent ); return; } VectorCopy( tr.endpos, ent->s.origin ); } else { ent->gravity = 0; } if( ent->team ) { ent->flags &= ~FL_TEAMSLAVE; ent->chain = ent->teamchain; ent->teamchain = NULL; ent->r.svflags |= SVF_NOCLIENT; ent->r.solid = SOLID_NOT; if( ent == ent->teammaster ) { ent->nextthink = level.timemsec + game.framemsec; ent->think = DoRespawn; } } trap_LinkEntity(ent); } //=============== //PrecacheItem // //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 ) { int i; char *s, *start; char data[MAX_QPATH]; int len; gitem_t *ammo; if( !it ) return; if( it->pickup_sound ) trap_SoundIndex( it->pickup_sound ); for ( i = 0; i < MAX_ITEM_MODELS; i++ ) { if( it->world_model[i] ) trap_ModelIndex( it->world_model[i] ); } if( it->icon ) trap_ImageIndex( it->icon ); // parse everything for its ammo if( it->ammo_tag ) { ammo = game.items[it->ammo_tag]; if( ammo != it ) PrecacheItem( ammo ); } // parse the space separated precache string for other items for( i = 0; i < 3; i++ ) { if( i == 0 ) s = it->precache_models; else if( i == 1 ) s = it->precache_sounds; else s = it->precache_images; if( !s || !s[0] ) continue; while( *s ) { start = s; while( *s && *s != ' ' ) s++; len = s-start; if( len >= MAX_QPATH || len < 5 ) G_Error( "PrecacheItem: %s has bad precache string", it->classname ); memcpy( data, start, len ); data[len] = 0; if( *s ) s++; if( i == 0 ) trap_ModelIndex( data ); else if (i == 1) trap_SoundIndex( data ); else trap_ImageIndex( data ); } } } //============ //SpawnItem // //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 ) { // wsw : jal : set items as ET_ITEM for simpleitems ent->s.type = ET_ITEM; ent->s.skinnum = item->tag; ent->item = item; ent->nextthink = level.timemsec + 2 * game.framemsec; // items start after other solids ent->think = Finish_SpawningItem; ent->s.effects = 0; // default effects are applied client side // flags are server animated and have special handling if( item->type & IT_FLAG ) { ent->think = G_Gametype_CTF_FlagSetup; } if( item->type & IT_HEALTH ) { if( item->tag == HEALTH_SMALL ) ent->style = HEALTH_IGNORE_MAX; else if( item->tag == HEALTH_MEGA ) ent->style = HEALTH_IGNORE_MAX|HEALTH_TIMED; } } //====================================================================== //=============== //InitItems // //Validate item tags and sort by tag into game.items list //=============== void InitItems( void ) { int tag, count; gitem_t *item; int num_items; // count items for( num_items = 1, item = &itemdefs[1]; item->classname; item++, num_items++ ) { } //clear for( tag = 0; tag < MAX_ITEMS; tag++ ) //zero will always be NULL game.items[tag] = NULL; // store item with tags in the array at position of tag value for( tag = 1, count = 0; tag < num_items; tag++ ) { game.items[tag] = NULL; for( item = &itemdefs[1]; item->classname; item++ ) { if( item->tag == tag ) { // found the same tag value twice if( game.items[tag] != NULL ) G_Error( "InitItems: Found two different items with the same tag value: %s -> %s ", game.items[tag]->classname, item->classname ); game.items[tag] = item; count++; //break; } } } //find the first with tag being zero for( item = &itemdefs[1]; item->classname; item++ ) { if( !item->tag ) break; } //asign tag values to items without tags while( item->classname ) { for( item = &itemdefs[1]; item->classname; item++ ) { if( !item->tag ) { //find a free spot for it for( tag = 1; tag < MAX_ITEMS; tag++ ) { if( !game.items[tag] ) break; } if( tag == MAX_ITEMS ) G_Error( "InitItems: Couldn't find a free spot into game.items array for %s\n", item->classname ); item->tag = tag; game.items[tag] = item; //put it on the list if( developer->value ) Com_Printf("WARNING: InitItems found item '%s' without a tag value. Assigned: %i\n", item->classname, tag ); count++; break; } } } game.numItems = count + 1; //item zero was not counted Com_Printf("Initialized %i Items\n", count ); // Init armor items game.items[ARMOR_GA]->info = (gitem_armor_t *)&g_armor_info; game.items[ARMOR_YA]->info = (gitem_armor_t *)&y_armor_info; game.items[ARMOR_RA]->info = (gitem_armor_t *)&r_armor_info; // Init weapon items G_InitWeapons(); } //=============== //SetItemNames // //Called by worldspawn //=============== void SetItemNames( void ) { int i; for( i = 0; i < game.numItems; i++ ) { if( game.items[i] ) trap_ConfigString( CS_ITEMS+i, game.items[i]->pickup_name ); } }