/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.

This file is part of Quake III Arena source code.

Quake III Arena source code 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.

Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
//
#include "g_local.h"

/*

  Items are any object that a player can touch to gain some effect.

  Pickup will return the number of seconds until they should respawn.

  all items should pop when dropped in lava or slime

  Respawnable items don't actually go away when picked up, they are
  just made invisible and untouchable.  This allows them to ride
  movers and respawn apropriately.
*/


#define	RESPAWN_ARMOR		25
#define	RESPAWN_HEALTH		35
#define	RESPAWN_AMMO		40
#define	RESPAWN_HOLDABLE	60
#define	RESPAWN_MEGAHEALTH	35//120
#define	RESPAWN_POWERUP		120


//======================================================================

int Pickup_Powerup( gentity_t *ent, gentity_t *other ) {
	int			quantity;
	int			i;
	gclient_t	*client;

	if ( !other->client->ps.powerups[ent->item->giTag] ) {
		// round timing to seconds to make multiple powerup timers
		// count in sync
		other->client->ps.powerups[ent->item->giTag] = 
			level.time - ( level.time % 1000 );
	}

	if ( ent->count ) {
		quantity = ent->count;
	} else {
		quantity = ent->item->quantity;
	}

	other->client->ps.powerups[ent->item->giTag] += quantity * 1000;

	// give any nearby players a "denied" anti-reward
	for ( i = 0 ; i < level.maxclients ; i++ ) {
		vec3_t		delta;
		float		len;
		vec3_t		forward;
		trace_t		tr;

		client = &level.clients[i];
		if ( client == other->client ) {
			continue;
		}
		if ( client->pers.connected == CON_DISCONNECTED ) {
			continue;
		}
		if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
			continue;
		}

    // if same team in team game, no sound
    // cannot use OnSameTeam as it expects to g_entities, not clients
  	if ( g_gametype.integer >= GT_TEAM && other->client->sess.sessionTeam == client->sess.sessionTeam  ) {
      continue;
    }

		// if too far away, no sound
		VectorSubtract( ent->s.pos.trBase, client->ps.origin, delta );
		len = VectorNormalize( delta );
		if ( len > 192 ) {
			continue;
		}

		// if not facing, no sound
		AngleVectors( client->ps.viewangles, forward, NULL, NULL );
		if ( DotProduct( delta, forward ) < 0.4 ) {
			continue;
		}

		// if not line of sight, no sound
		trap_Trace( &tr, client->ps.origin, NULL, NULL, ent->s.pos.trBase, ENTITYNUM_NONE, CONTENTS_SOLID );
		if ( tr.fraction != 1.0 ) {
			continue;
		}

		// anti-reward
		client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD;
	}
	return RESPAWN_POWERUP;
}

//======================================================================

#ifdef MISSIONPACK
int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) {
	int		clientNum;
	char	userinfo[MAX_INFO_STRING];
	float	handicap;
	int		max;

	other->client->ps.stats[STAT_PERSISTANT_POWERUP] = ent->item - bg_itemlist;
	other->client->persistantPowerup = ent;

	switch( ent->item->giTag ) {
	case PW_GUARD:
		clientNum = other->client->ps.clientNum;
		trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
		handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
		if( handicap<=0.0f || handicap>100.0f) {
			handicap = 100.0f;
		}
		max = (int)(2 *  handicap);

		other->health = max;
		other->client->ps.stats[STAT_HEALTH] = max;
		other->client->ps.stats[STAT_MAX_HEALTH] = max;
		other->client->ps.stats[STAT_ARMOR] = max;
		other->client->pers.maxHealth = max;

		break;

	case PW_SCOUT:
		clientNum = other->client->ps.clientNum;
		trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
		handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
		if( handicap<=0.0f || handicap>100.0f) {
			handicap = 100.0f;
		}
		other->client->pers.maxHealth = handicap;
		other->client->ps.stats[STAT_ARMOR] = 0;
		break;

	case PW_DOUBLER:
		clientNum = other->client->ps.clientNum;
		trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
		handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
		if( handicap<=0.0f || handicap>100.0f) {
			handicap = 100.0f;
		}
		other->client->pers.maxHealth = handicap;
		break;
	case PW_AMMOREGEN:
		clientNum = other->client->ps.clientNum;
		trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
		handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
		if( handicap<=0.0f || handicap>100.0f) {
			handicap = 100.0f;
		}
		other->client->pers.maxHealth = handicap;
		memset(other->client->ammoTimes, 0, sizeof(other->client->ammoTimes));
		break;
	default:
		clientNum = other->client->ps.clientNum;
		trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
		handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
		if( handicap<=0.0f || handicap>100.0f) {
			handicap = 100.0f;
		}
		other->client->pers.maxHealth = handicap;
		break;
	}

	return -1;
}

//======================================================================
#endif

int Pickup_Holdable( gentity_t *ent, gentity_t *other ) {

	other->client->ps.stats[STAT_HOLDABLE_ITEM] = ent->item - bg_itemlist;

	if( ent->item->giTag == HI_KAMIKAZE ) {
		other->client->ps.eFlags |= EF_KAMIKAZE;
	}

	return RESPAWN_HOLDABLE;
}


//======================================================================

void Add_Ammo (gentity_t *ent, int weapon, int count)
{
	ent->client->ps.ammo[weapon] += count;

	// riotmod begin

	//if ( ent->client->ps.ammo[weapon] > 200 ) {
	//	ent->client->ps.ammo[weapon] = 200;
	//}

	if ( ent->client->ps.ammo[WP_SHOTGUN] > 20 ) {
		ent->client->ps.ammo[WP_SHOTGUN] = 20;
	}

	if ( ent->client->ps.ammo[WP_ROCKET_LAUNCHER] > 20 ) {
		ent->client->ps.ammo[WP_ROCKET_LAUNCHER] = 20;
	}

	if ( ent->client->ps.ammo[WP_GRENADE_LAUNCHER] > 20 ) {
		ent->client->ps.ammo[WP_GRENADE_LAUNCHER] = 20;
	}

	if ( ent->client->ps.ammo[WP_PLASMAGUN] > 40 ) {
		ent->client->ps.ammo[WP_PLASMAGUN] = 40;
	}

	if ( ent->client->ps.ammo[WP_RAILGUN] > 10 ) {
		ent->client->ps.ammo[WP_RAILGUN] = 10;
	}

	if ( ent->client->ps.ammo[WP_BFG] > 2 ) {
		ent->client->ps.ammo[WP_BFG] = 2;
	}

	if ( ent->client->ps.ammo[WP_LIGHTNING] > 200 ) {
		ent->client->ps.ammo[WP_LIGHTNING] = 200;
	}

	if ( ent->client->ps.ammo[WP_HOMING] > 200 ) {
		ent->client->ps.ammo[WP_HOMING] = 200;
	}

	if ( ent->client->ps.ammo[WP_MACHINEGUN] > 100 ) {
		ent->client->ps.ammo[WP_MACHINEGUN] = 100;
	}

	if ( ent->client->ps.ammo[WP_FAST_MACHINEGUN] > 100 ) {
		ent->client->ps.ammo[WP_FAST_MACHINEGUN] = 100;
	}

	if(ent->client->ps.ammo[WP_GRENADE_LAUNCHER] > ent->client->ps.ammo[WP_ROCKET_LAUNCHER]){
		ent->client->ps.ammo[WP_ROCKET_LAUNCHER]=ent->client->ps.ammo[WP_GRENADE_LAUNCHER];
	}else if(ent->client->ps.ammo[WP_GRENADE_LAUNCHER] < ent->client->ps.ammo[WP_ROCKET_LAUNCHER]){
		ent->client->ps.ammo[WP_GRENADE_LAUNCHER]=ent->client->ps.ammo[WP_ROCKET_LAUNCHER];
	}

	if(ent->client->ps.ammo[WP_HOMING] > ent->client->ps.ammo[WP_LIGHTNING]){
		ent->client->ps.ammo[WP_LIGHTNING]=ent->client->ps.ammo[WP_HOMING];
	}else if(ent->client->ps.ammo[WP_HOMING] < ent->client->ps.ammo[WP_LIGHTNING]){
		ent->client->ps.ammo[WP_HOMING]=ent->client->ps.ammo[WP_LIGHTNING];
	}

	if(ent->client->ps.ammo[WP_MACHINEGUN] > ent->client->ps.ammo[WP_FAST_MACHINEGUN]){
		ent->client->ps.ammo[WP_FAST_MACHINEGUN]=ent->client->ps.ammo[WP_MACHINEGUN];
	}else if(ent->client->ps.ammo[WP_MACHINEGUN] < ent->client->ps.ammo[WP_FAST_MACHINEGUN]){
		ent->client->ps.ammo[WP_MACHINEGUN]=ent->client->ps.ammo[WP_FAST_MACHINEGUN];
	}

	// riotmod end
}

int Pickup_Ammo (gentity_t *ent, gentity_t *other)
{
	int		quantity;

	if ( ent->count ) {
		quantity = ent->count;
	} else {
		quantity = ent->item->quantity;
	}

	Add_Ammo (other, ent->item->giTag, quantity);

	return RESPAWN_AMMO;
}

//======================================================================

// riotmod begin
/*
void activate_power_sound(vec3_t location) {
	gentity_t	*te;
	te = G_TempEntity(location, EV_GENERAL_SOUND);
	te->s.eventParm = G_SoundIndex("sound/activate_power.wav");
	te->r.svFlags |= SVF_BROADCAST;
}

void combo_sound(vec3_t location) {
	gentity_t	*te;
	te = G_TempEntity(location, EV_GENERAL_SOUND);
	te->s.eventParm = G_SoundIndex("sound/combo.wav");
	te->r.svFlags |= SVF_BROADCAST;
}

void upgrade_sound(vec3_t location) {
	gentity_t	*te;
	te = G_TempEntity(location, EV_GENERAL_SOUND);
	te->s.eventParm = G_SoundIndex("sound/upgrade.wav");
	te->r.svFlags |= SVF_BROADCAST;
}

#define SOUND_BONUS 0
#define SOUND_COMBO 1
#define SOUND_LEVELUP 2
#define SOUND_OBVAMP 3
#define SOUND_OBWAR 4
#define SOUND_HYPERGUN 5
#define SOUND_NANOCLOUD 6
#define SOUND_NUKE 7
#define SOUND_VAMPIRE 8

void event_sound(vec3_t location, int snd) {
	gentity_t	*te;
	te = G_TempEntity(location, EV_GENERAL_SOUND);

	if(snd==SOUND_BONUS){
		te->s.eventParm = G_SoundIndex("sound/events/bonus.wav");
	} else if(snd==SOUND_COMBO){
		te->s.eventParm = G_SoundIndex("sound/events/combo.wav");
	} else if(snd==SOUND_LEVELUP){
		te->s.eventParm = G_SoundIndex("sound/events/level_up.wav");
	} else if(snd==SOUND_OBVAMP){
		te->s.eventParm = G_SoundIndex("sound/events/obtained_vampire.wav");
	} else if(snd==SOUND_OBWAR){
		te->s.eventParm = G_SoundIndex("sound/events/obtained_warhead.wav");
	} else if(snd==SOUND_HYPERGUN){
		te->s.eventParm = G_SoundIndex("sound/events/unlocked_hypergun.wav");
	} else if(snd==SOUND_NANOCLOUD){
		te->s.eventParm = G_SoundIndex("sound/events/unlocked_nanocloud.wav");
	} else if(snd==SOUND_NUKE){
		te->s.eventParm = G_SoundIndex("sound/events/unlocked_tacnuke.wav");
	} else if(snd==SOUND_VAMPIRE){
		te->s.eventParm = G_SoundIndex("sound/events/unloced_vampire.wav");
	}
	te->r.svFlags |= SVF_BROADCAST;
}

*/

#define MINIMUM_TECH_TIME 3
#define MAXIMUM_TECH_TIME 7

// used to be six
#define TECH_LEVEL_THRESHOLD 5

// riotmod end

int Pickup_Weapon (gentity_t *ent, gentity_t *other) {
	int		quantity;
	// riotmod begin
	int		grenades;
	int		tech;
	int		techtime;
	int		heal;
	int		chance;
	int		bullets;
	int		shells;
	int		nanomachines;
	int		slugs;
	int		kinetic;
	int		upgraded;
	int		ntechtime;
	int		dropval;
	int		dropped_weapon;
	int		drop_tech_level;
	int		leveldif;
	int		armor_level;
	int		ticker;
	int		health_level;
	int		random_item;

	if (ent->item->giTag == WP_BACKPACK) {

		//other->client->ps.stats[STAT_TECH_PICKUPS] = other->client->ps.stats[STAT_TECH_PICKUPS] + 1;
		//trap_SendServerCommand( other->client->ps.clientNum, va("print \"%i Powerballs picked up!\n\"",other->client->ps.stats[STAT_TECH_PICKUPS]) );

		// make sure tech-related player stats have good initial values
		if(other->client->last_tech){}else{ other->client->last_tech = 0; }
		if(other->client->current_tech){}else{ other->client->current_tech = 0; }
		if(other->client->last_last_tech){}else{ other->client->last_last_tech = 0; }
		if(other->client->tech_value){}else{ other->client->tech_value = 0; }
		if(other->client->tech_level){}else{ other->client->tech_level = 0; }
		if(other->client->ps.powerups[PW_QUAD]<level.time){ other->client->ps.powerups[PW_QUAD]=level.time; }
		if(other->client->ps.powerups[PW_BATTLESUIT]<level.time){ other->client->ps.powerups[PW_BATTLESUIT]=level.time; }
		if(other->client->ps.powerups[PW_INVIS]<level.time){ other->client->ps.powerups[PW_INVIS]=level.time; }
		if(other->client->ps.powerups[PW_HASTE]<level.time){ other->client->ps.powerups[PW_HASTE]=level.time; }
		if(other->client->ps.powerups[PW_REGEN]<level.time){ other->client->ps.powerups[PW_REGEN]=level.time; }
		if(other->client->ps.powerups[PW_FLIGHT]<level.time){ other->client->ps.powerups[PW_FLIGHT]=level.time; }

		// Record data about this pickup
		other->client->tech_count = other->client->tech_count + 1;
		other->client->last_last_tech = other->client->last_tech;
		other->client->last_tech = other->client->current_tech;

		// What's in this tech?
		dropped_weapon = (ent->count >> 8);
		drop_tech_level = (ent->count & 0x00FF);
		bullets = (ent->damage >> 8);
		shells = (ent->damage & 0x00FF);
		nanomachines = (ent->splashDamage >> 8);
		slugs = (ent->splashDamage & 0x00FF);
		kinetic = (ent->splashRadius >> 8);
		grenades = (ent->health >> 8);
		tech = (ent->health & 0x00FF);
		heal = (ent->splashRadius & 0x00FF);

		ScorePlum(other, other->r.currentOrigin, tech);

		//trap_SendServerCommand( other->client->ps.clientNum, va("print \"PICKUP: %i\n\"\n",tech) );

		// check the level difference and
		// alter the drop value accordingly
		leveldif = drop_tech_level - other->client->tech_level;
/*		if(leveldif>=5){
			tech = tech + 5;
		} else if(leveldif>=4) {
			tech = tech + 4;
		} else if(leveldif>=3) {
			tech = tech + 3;
		} else if(leveldif>=2) {
			tech = tech + 2;
		}
*/
		if(leveldif>=8){
			tech = tech + 10;
		} else if(leveldif==7) {
			tech = tech + 8;
		} else if(leveldif==6) {
			tech = tech + 6;
		} else if(leveldif==5) {
			tech = tech + 5;
		} else if(leveldif==4) {
			tech = tech + 4;
		} else if(leveldif==3) {
			tech = tech + 2;
		} else if(leveldif==2) {
			tech = tech + 1;
		}

		// Add some "random" xp
		//tech = tech + ((rand() % TECH_LEVEL_THRESHOLD)+1);

		// Calculate and save player tech level
		other->client->tech_value = other->client->tech_value + tech;

		upgraded = 0;
		while(other->client->tech_value>TECH_LEVEL_THRESHOLD) {
			other->client->tech_value = other->client->tech_value - TECH_LEVEL_THRESHOLD;
			other->client->tech_level = other->client->tech_level + 1;
			upgraded = 1;
		}
		if(other->client->tech_value<0){ other->client->tech_value = 0; }
		//if(other->client->tech_level>10){ upgraded = 0; other->client->tech_level = 10; }

		if(upgraded==1){
			/*
			// remove awards
			other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | 
				EF_LEVEL_ZERO | EF_LEVEL_ONE | EF_LEVEL_TWO | EF_LEVEL_THREE | EF_LEVEL_FOUR | EF_LEVEL_FIVE | EF_LEVEL_SIX | EF_LEVEL_SEVEN | EF_LEVEL_EIGHT | EF_LEVEL_NINE | EF_LEVEL_TEN |
                                EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET );

			if(other->client->tech_level==1){
				other->client->ps.eFlags |= EF_LEVEL_ONE;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==2){
				other->client->ps.eFlags |= EF_LEVEL_TWO;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==3){
				other->client->ps.eFlags |= EF_LEVEL_THREE;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==4){
				other->client->ps.eFlags |= EF_LEVEL_FOUR;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==5){
				other->client->ps.eFlags |= EF_LEVEL_FIVE;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==6){
				other->client->ps.eFlags |= EF_LEVEL_SIX;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==7){
				other->client->ps.eFlags |= EF_LEVEL_SEVEN;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==8){
				other->client->ps.eFlags |= EF_LEVEL_EIGHT;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==9){
				other->client->ps.eFlags |= EF_LEVEL_NINE;
 				other->client->rewardTime = level.time + 10000;
			} else if(other->client->tech_level==10){
				other->client->ps.eFlags |= EF_LEVEL_TEN;
 				other->client->rewardTime = level.time + 10000;
			}
			*/
/*
			// add the sprite over the player's head
 			other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE |
                         EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_LEVELUP );
 			other->client->ps.eFlags |= EF_AWARD_LEVELUP;
 			other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
*/
/*
			upgrade_sound(other->r.currentOrigin);
			if(other->client->tech_level==1){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 1\n\"" );
			} else if(other->client->tech_level==2){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 2\n\"" );
			} else if(other->client->tech_level==3){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 3\n\"" );
			} else if(other->client->tech_level==4){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 4\n\"" );
			} else if(other->client->tech_level==5){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 5\n\"" );
			} else if(other->client->tech_level==6){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 6\n\"" );
			} else if(other->client->tech_level==7){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 7\n\"" );
			} else if(other->client->tech_level==8){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 8\n\"" );
			} else if(other->client->tech_level==9){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 9\n\"" );
			} else if(other->client->tech_level==10){
				trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up! Level 10\n\"" );
			}
*/

			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up!\n\"" );

			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/level_up.wav"));

			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/upgrade.wav"));

			//upgrade_sound(other->r.currentOrigin);

			//event_sound(other->r.currentOrigin,SOUND_LEVELUP);

			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Level Up!\n\"" );
		}

		other->client->ps.stats[STAT_TECH_LEVEL] = other->client->tech_level;

		//if(other->client->tech_count>12){
		//	dropval = 12;
		//} else {
			dropval = other->client->tech_count;
		//}
		dropval = dropval + (other->client->tech_level * 2);
		other->client->ps.stats[STAT_TECH_DROP] = dropval;

		// select a tech at random
		tech = rand() % 4;

		// small chance to get regen
		chance = (rand() % 100) + 1;
		if(chance>95){
			tech = 4;
		}

		// small chance to get new weapon
		chance = (rand() % 100) + 1;
		chance = chance + other->client->ps.stats[STAT_TECH_LEVEL];
		if(chance>=99){
			random_item = (rand() % 4) + 1;
			if(random_item==1){
				if(other->client->ps.stats[STAT_GOT_HOMING]==0){
					other->client->ps.stats[STAT_GOT_HOMING] = 1;
					//event_sound(other->r.currentOrigin,SOUND_NANOCLOUD);
					//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Unlocked Nanobolt!\n\"" );
					//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/unlocked_nanocloud.wav"));
				}
				other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_HOMING );
				if((other->client->ps.ammo[WP_HOMING]<50)||(other->client->ps.ammo[WP_LIGHTNING]<50)){
					other->client->ps.ammo[WP_HOMING] = 50;
					other->client->ps.ammo[WP_LIGHTNING] = 50;
				}
			} else if(random_item==2){
				if(other->client->ps.stats[STAT_GOT_FAST]==0){
					other->client->ps.stats[STAT_GOT_FAST] = 1;
					//event_sound(other->r.currentOrigin,SOUND_HYPERGUN);
					//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Unlocked Hypergun!\n\"" );
					//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/unlocked_hypergun.wav"));
				}
				other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_FAST_MACHINEGUN );
				if((other->client->ps.ammo[WP_MACHINEGUN]<50)||(other->client->ps.ammo[WP_FAST_MACHINEGUN]<50)){
					other->client->ps.ammo[WP_FAST_MACHINEGUN] = 50;
					other->client->ps.ammo[WP_MACHINEGUN] = 50;
				}
			} else if(random_item==3){
				if(other->client->ps.stats[STAT_GOT_NUKE]==0){
					other->client->ps.stats[STAT_GOT_NUKE] = 1;
					//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Unlocked Tactical Nuclear Device!\n\"" );
					//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/unlocked_tacnuke.wav"));
					//event_sound(other->r.currentOrigin,SOUND_NUKE);
				} else {
					//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Nuclear Warhead!\n\"" );
					//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/obtained_warhead.wav"));
					//event_sound(other->r.currentOrigin,SOUND_OBWAR);
				}
				other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BFG );
				other->client->ps.ammo[WP_BFG] = other->client->ps.ammo[WP_BFG] + 1;
				if(other->client->ps.ammo[WP_BFG]>2){ other->client->ps.ammo[WP_BFG] = 2; }
			} else if(random_item==4){
				if(other->client->ps.stats[STAT_GOT_VAMPIRE]==0){
					other->client->ps.stats[STAT_GOT_VAMPIRE] = 1;
					//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Unlocked Vampire!\n\"" );
					//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/unlocked_vampire.wav"));
					//event_sound(other->r.currentOrigin,SOUND_VAMPIRE);
				} else {
					//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Vampire Recharged!\n\"" );
					//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/obtained_vampire.wav"));
					//event_sound(other->r.currentOrigin,SOUND_OBVAMP);
				}
				other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PULSE );
				other->client->ps.ammo[WP_PULSE] = other->client->ps.ammo[WP_PULSE] + 20;
				if(other->client->ps.ammo[WP_PULSE]>50){ other->client->ps.ammo[WP_PULSE] = 50; }
			}
		}

/*
		// small chance to get new weapon
		chance = (rand() % 100) + 1;
		chance = chance + other->client->ps.stats[STAT_TECH_LEVEL];
		if(chance>=99){
			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Nanocloud!\n\"" );
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_HOMING );
			if((other->client->ps.ammo[WP_HOMING]<50)||(other->client->ps.ammo[WP_LIGHTNING]<50)){
				other->client->ps.ammo[WP_HOMING] = 50;
				other->client->ps.ammo[WP_LIGHTNING] = 50;
			}
		}

		chance = (rand() % 100) + 1;
		chance = chance + other->client->ps.stats[STAT_TECH_LEVEL];
		if(chance>=99){
			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Hypergun!\n\"" );
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_FAST_MACHINEGUN );
			if((other->client->ps.ammo[WP_MACHINEGUN]<50)||(other->client->ps.ammo[WP_FAST_MACHINEGUN]<50)){
				other->client->ps.ammo[WP_FAST_MACHINEGUN] = 50;
				other->client->ps.ammo[WP_MACHINEGUN] = 50;
			}
		}

		chance = (rand() % 100) + 1;
		chance = chance + other->client->ps.stats[STAT_TECH_LEVEL];
		if(chance>=99){
			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Tactical Nuclear Device!\n\"" );
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BFG );
			other->client->ps.ammo[WP_BFG] = other->client->ps.ammo[WP_BFG] + 1;
			if(other->client->ps.ammo[WP_BFG]>2){ other->client->ps.ammo[WP_BFG] = 2; }
		}
*/
/*
		if(chance>=85){
			tech = 8; // Nanocloud
		} else if(chance>=95) {
			tech = 6; // Nuke
		} else if(chance>=100) {
			tech = 7; // Fast Machinegun
		}
*/
		// Combat Tech : 0
		// Defense Tech: 1
		// Kinetic Tech: 2
		// Stealth Tech: 3
		// Medical Tech: 4
		// Flight Tech: 5
		// TacNuke: 6
		// Fast Machinegun: 7
		// Nanocloud: 8

		techtime = (rand() % MAXIMUM_TECH_TIME) + MINIMUM_TECH_TIME;
		techtime = techtime * 1000;

		armor_level = 15;
		health_level = 50;

		// For each level, give the player a chance to get
		// a better power time
		ticker = 0;
		while(ticker<other->client->tech_level){
			ticker = ticker + 1;

			// a chance at a better tech time
			ntechtime = ((rand() % MAXIMUM_TECH_TIME) + MINIMUM_TECH_TIME);
			ntechtime = ntechtime * 1000;
			if(ntechtime>techtime){ techtime = ntechtime; }

			if(ticker>=1){
				// more bullets
				if(bullets!=0){ bullets = bullets + 1; }
				// more shells
				if(shells!=0){ shells = shells + 1; }
			}

			if(ticker>=3){
				// more nanomachines
				if(nanomachines!=0){ nanomachines = nanomachines + 1; }
				// more slugs
				if(slugs!=0){ slugs = slugs + 1; }
				armor_level = 25;
				health_level = 25;
			}

			if(ticker>=5){
				// more k-cells
				if(kinetic!=0){ kinetic = kinetic + 1; }
				// more mines
				if(grenades!=0){ grenades = grenades + 1; }
				//health_level = 0;
			}

			if(ticker>=6){
				// another chance to get tacnuke
				//if(tech!=6){
				//	chance = (rand() % 100) + 1;
				//	if(chance>=99){ tech = 6; }	// Give 'em a TacNuke
				//}
			}

			if(ticker>=10){
				armor_level = 50;
/*				if(tech!=5){
					chance = (rand() % 100) + 1;
					if(chance>=95){ tech = 5; }	// Give 'em Flight
				}
*/
			}

			if(ticker>=50){
				health_level = 0;
			}
		}

		if(bullets>50){ bullets=50; }
		if(shells>10){ shells=10; }
		if(nanomachines>50){ nanomachines=50; }
		if(slugs>5){ slugs = 5; }
		if(grenades>5){ grenades = 5; }

		// END NEW SYSTEM

		// now, let's give the player stuff

		// give the player ammo
		if(other->client->ps.stats[STAT_ARMOR]<armor_level){
			other->client->ps.stats[STAT_ARMOR] = other->client->ps.stats[STAT_ARMOR] + (rand() % armor_level) + 1;
		}

		// give the player health
		if(other->health<health_level){
			other->health = other->health + (rand() % health_level) + 1;
		}

		// give the player the backpack's weapon, if it isn't an gauntlet or a machinegun
		if ( dropped_weapon > WP_MACHINEGUN && dropped_weapon != WP_GRAPPLING_HOOK && dropped_weapon != WP_BFG) {
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << dropped_weapon );
		}

		// give ammo
		Add_Ammo( other, WP_MACHINEGUN, bullets );
		Add_Ammo( other, WP_SHOTGUN, shells );
		Add_Ammo( other, WP_GRENADE_LAUNCHER, grenades );
		Add_Ammo( other, WP_LIGHTNING, nanomachines );
		Add_Ammo( other, WP_RAILGUN, slugs );
		Add_Ammo( other, WP_PLASMAGUN, kinetic );

		//trap_SendServerCommand( other->client->ps.clientNum, va("print \"PICKUP: %i, TECH VALUE: %i, TECH LEVEL: %i, DROP VALUE: %i\n\"", tech, other->client->tech_value, other->client->tech_level, other->client->tech_count));

		// give the player a "power"
		if(tech==0){
			//trap_SendServerCommand( other->client->ps.clientNum, "print \"Combat Tech activated!\n\"" );
			other->client->ps.powerups[PW_QUAD] = other->client->ps.powerups[PW_QUAD] + techtime;
			//integrate_tech_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
			other->client->current_tech = 1;
		}else if(tech==1){
			//trap_SendServerCommand( other->client->ps.clientNum, "print \"Defense Tech activated!\n\"" );
			other->client->ps.powerups[PW_BATTLESUIT] = other->client->ps.powerups[PW_BATTLESUIT] + techtime;
			//integrate_tech_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
			other->client->current_tech = 2;
		}else if(tech==2){
			//trap_SendServerCommand( other->client->ps.clientNum, "print \"Kinetic Tech activated!!\n\"" );
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_HASTE] + techtime;
			//integrate_tech_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
			other->client->current_tech = 3;
		}else if(tech==3){
			//trap_SendServerCommand( other->client->ps.clientNum, "print \"Stealth Tech activated!\n\"" );
			other->client->ps.powerups[PW_INVIS] = other->client->ps.powerups[PW_INVIS] + techtime;
			//integrate_tech_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
			other->client->current_tech = 4;
		}else if(tech==4){
			//trap_SendServerCommand( other->client->ps.clientNum, "print \"Medical Tech activated!\n\"" );
			other->client->ps.powerups[PW_REGEN] = other->client->ps.powerups[PW_REGEN] + techtime;
			//integrate_tech_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
			other->client->current_tech = 5;
		}else if(tech==5){
			//trap_SendServerCommand( other->client->ps.clientNum, "print \"Flight Tech activated!\n\"" );
			other->client->ps.powerups[PW_FLIGHT] = other->client->ps.powerups[PW_FLIGHT] + techtime;
			//integrate_tech_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
			other->client->current_tech = 6;
		}else if(tech==6){
			// Give 'em a TacNuke
			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Tactical Nuclear Device!\n\"" );
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BFG );
			other->client->ps.ammo[WP_BFG] = other->client->ps.ammo[WP_BFG] + 1;
			if(other->client->ps.ammo[WP_BFG]>2){ other->client->ps.ammo[WP_BFG] = 2; }
			other->client->current_tech = 7;
			other->client->ps.stats[STAT_TECH_OVERLOAD] = other->client->ps.stats[STAT_TECH_OVERLOAD] + 1;

			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/activate_power.wav"));
			//activate_power_sound(other->r.currentOrigin);
		}else if(tech==7){
			// Give 'em a Fast Machinegun
			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Fast Machinegun!\n\"" );
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_FAST_MACHINEGUN );
			if((other->client->ps.ammo[WP_MACHINEGUN]<100)||(other->client->ps.ammo[WP_FAST_MACHINEGUN]<100)){
				other->client->ps.ammo[WP_FAST_MACHINEGUN] = 100;
				other->client->ps.ammo[WP_MACHINEGUN] = 100;
			}
			other->client->current_tech = 8;
			other->client->ps.stats[STAT_TECH_OVERLOAD] = other->client->ps.stats[STAT_TECH_OVERLOAD] + 1;
		}else if(tech==8){
			// Give 'em a Nanocloud
			trap_SendServerCommand( other->client->ps.clientNum, "cp \"Obtained Nanocloud!\n\"" );
			other->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_HOMING );
			if((other->client->ps.ammo[WP_HOMING]<50)||(other->client->ps.ammo[WP_LIGHTNING]<50)){
				other->client->ps.ammo[WP_HOMING] = 50;
				other->client->ps.ammo[WP_LIGHTNING] = 50;
			}
			other->client->current_tech = 9;
			other->client->ps.stats[STAT_TECH_OVERLOAD] = other->client->ps.stats[STAT_TECH_OVERLOAD] + 1;
		}

		// Check for combos

		// Combat Tech : 1
		// Defense Tech: 2
		// Stealth Tech: 3
		// Kinetic Tech: 4
		// Medical Tech: 5
		// Flight Tech: 6
		// TacNuke: 7

		// defense->combat or combat->defense - combat +5, defense +5
		if((other->client->current_tech==1)&&(other->client->last_tech==2)){
			// give 'em defense
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/bonus.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Defense Bonus!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_BONUS);
			other->client->ps.powerups[PW_BATTLESUIT]=other->client->ps.powerups[PW_BATTLESUIT]+2000;
		}
		if((other->client->current_tech==2)&&(other->client->last_tech==1)){
			// give 'em combat
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/bonus.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Combat Bonus!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_BONUS);
			other->client->ps.powerups[PW_QUAD]=other->client->ps.powerups[PW_QUAD]+2000;
		}

		// stealth->kinetic or kinetic->stealth - stealth +5, kinetic +5
		if((other->client->current_tech==3)&&(other->client->last_tech==4)){
			// give 'em kinetic
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/bonus.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Kinetic Bonus!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_BONUS);
			other->client->ps.powerups[PW_HASTE]=other->client->ps.powerups[PW_HASTE]+2000;
		}
		if((other->client->current_tech==4)&&(other->client->last_tech==3)){
			// give 'em stealth
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/bonus.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Stealth Bonus!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_BONUS);
			other->client->ps.powerups[PW_INVIS]=other->client->ps.powerups[PW_INVIS]+2000;
		}

		// Three-of-a-Kind Combos

		if((other->client->current_tech==1)&&(other->client->last_tech==1)&&(other->client->last_last_tech==1)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Three-of-a-Kind Combat Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_QUAD] = other->client->ps.powerups[PW_QUAD] + 5000;
		}

		if((other->client->current_tech==2)&&(other->client->last_tech==2)&&(other->client->last_last_tech==2)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Three-of-a-Kind Defense Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_BATTLESUIT] = other->client->ps.powerups[PW_BATTLESUIT] + 5000;
		}

		if((other->client->current_tech==3)&&(other->client->last_tech==3)&&(other->client->last_last_tech==3)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Three-of-a-Kind Stealth Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_INVIS] = other->client->ps.powerups[PW_INVIS] + 5000;
		}

		if((other->client->current_tech==4)&&(other->client->last_tech==4)&&(other->client->last_last_tech==4)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Three-of-a-Kind Kinetic Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_HASTE] + 5000;
		}

		// Three-in-a-Row Combos

		if((other->client->current_tech==3)&&(other->client->last_tech==2)&&(other->client->last_last_tech==1)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Lesser Three-in-a-Row Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_QUAD] + 1000;
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_BATTLESUIT] + 1000;
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_INVIS] + 1000;
		}

		if((other->client->current_tech==6)&&(other->client->last_tech==5)&&(other->client->last_last_tech==4)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Greater Three-in-a-Row Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_HASTE] + 2000;
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_REGEN] + 2000;
		}

		if((other->client->current_tech==1)&&(other->client->last_tech==2)&&(other->client->last_last_tech==3)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Backward Three-in-a-Row Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_REGEN] + 2000;
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_INVIS] + 2000;
		}

		if((other->client->current_tech==4)&&(other->client->last_tech==5)&&(other->client->last_last_tech==6)){
			//combo_sound(other->r.currentOrigin);
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/events/combo.wav"));
			//G_Sound(other, CHAN_VOICE, G_SoundIndex("sound/combo.wav"));
			//trap_SendServerCommand( other->client->ps.clientNum, "cp \"Greater Backward Three-in-a-Row Combo!\n\"" );
			//event_sound(other->r.currentOrigin,SOUND_COMBO);
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_QUAD] + 2000;
			other->client->ps.powerups[PW_HASTE] = other->client->ps.powerups[PW_BATTLESUIT] + 2000;
		}

	} else {
		if ( ent->count < 0 ) {
			quantity = 0; // None for you, sir!
		} else {
			if ( ent->count ) {
				quantity = ent->count;
			} else {
				quantity = ent->item->quantity;
			}

			// dropped items and teamplay weapons always have full ammo
			if ( ! (ent->flags & FL_DROPPED_ITEM) && g_gametype.integer != GT_TEAM ) {
				// respawning rules
				// drop the quantity if the already have over the minimum
				if ( other->client->ps.ammo[ ent->item->giTag ] < quantity ) {
					quantity = quantity - other->client->ps.ammo[ ent->item->giTag ];
				} else {
					quantity = 1;		// only add a single shot
				}
			}
		}

		// add the weapon
		other->client->ps.stats[STAT_WEAPONS] |= ( 1 << ent->item->giTag );

		Add_Ammo( other, ent->item->giTag, quantity );

		if (ent->item->giTag == WP_GRAPPLING_HOOK)
			other->client->ps.ammo[ent->item->giTag] = -1; // unlimited ammo
	}

	// team deathmatch has slow weapon respawns
	if ( g_gametype.integer == GT_TEAM ) {
		return g_weaponTeamRespawn.integer;
	}

	return g_weaponRespawn.integer;

	// riotmod end
}


//======================================================================

int Pickup_Health (gentity_t *ent, gentity_t *other) {
	int			max;
	int			quantity;

	// small and mega healths will go over the max
#ifdef MISSIONPACK
	if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
		max = other->client->ps.stats[STAT_MAX_HEALTH];
	}
	else
#endif
	if ( ent->item->quantity != 5 && ent->item->quantity != 100 ) {
		max = other->client->ps.stats[STAT_MAX_HEALTH];
	} else {
		max = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
	}

	if ( ent->count ) {
		quantity = ent->count;
	} else {
		quantity = ent->item->quantity;
	}

	other->health += quantity;

	if (other->health > max ) {
		other->health = max;
	}
	other->client->ps.stats[STAT_HEALTH] = other->health;

	if ( ent->item->quantity == 100 ) {		// mega health respawns slow
		return RESPAWN_MEGAHEALTH;
	}

	return RESPAWN_HEALTH;
}

//======================================================================

int Pickup_Armor( gentity_t *ent, gentity_t *other ) {
#ifdef MISSIONPACK
	int		upperBound;

	other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;

	if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
		upperBound = other->client->ps.stats[STAT_MAX_HEALTH];
	}
	else {
		upperBound = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
	}

	if ( other->client->ps.stats[STAT_ARMOR] > upperBound ) {
		other->client->ps.stats[STAT_ARMOR] = upperBound;
	}
#else
	other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
	if ( other->client->ps.stats[STAT_ARMOR] > other->client->ps.stats[STAT_MAX_HEALTH] * 2 ) {
		other->client->ps.stats[STAT_ARMOR] = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
	}
#endif

	return RESPAWN_ARMOR;
}

//======================================================================

/*
===============
RespawnItem
===============
*/
void RespawnItem( gentity_t *ent ) {
	// randomly select from teamed entities
	if (ent->team) {
		gentity_t	*master;
		int	count;
		int choice;

		if ( !ent->teammaster ) {
			G_Error( "RespawnItem: bad teammaster");
		}
		master = ent->teammaster;

		for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
			;

		choice = rand() % count;

		for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
			;
	}

	ent->r.contents = CONTENTS_TRIGGER;
	ent->s.eFlags &= ~EF_NODRAW;
	ent->r.svFlags &= ~SVF_NOCLIENT;
	trap_LinkEntity (ent);

	if ( ent->item->giType == IT_POWERUP ) {
		// play powerup spawn sound to all clients
		gentity_t	*te;

		// if the powerup respawn sound should Not be global
		if (ent->speed) {
			te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
		}
		else {
			te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
		}
		te->s.eventParm = G_SoundIndex( "sound/items/poweruprespawn.wav" );
		te->r.svFlags |= SVF_BROADCAST;
	}

	if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE ) {
		// play powerup spawn sound to all clients
		gentity_t	*te;

		// if the powerup respawn sound should Not be global
		if (ent->speed) {
			te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
		}
		else {
			te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
		}
		te->s.eventParm = G_SoundIndex( "sound/items/kamikazerespawn.wav" );
		te->r.svFlags |= SVF_BROADCAST;
	}

	// play the normal respawn sound only to nearby clients
	G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );

	ent->nextthink = 0;
}


/*
===============
Touch_Item
===============
*/
void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
	int			respawn;
	qboolean	predict;

	if (!other->client)
		return;
	if (other->health < 1)
		return;		// dead people can't pickup

	// the same pickup rules are used for client side and server side
	if ( !BG_CanItemBeGrabbed( g_gametype.integer, &ent->s, &other->client->ps ) ) {
		return;
	}

	G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname );

	predict = other->client->pers.predictItemPickup;

	// call the item-specific pickup function
	switch( ent->item->giType ) {
	case IT_WEAPON:
		respawn = Pickup_Weapon(ent, other);
//		predict = qfalse;
		break;
	case IT_AMMO:
		respawn = Pickup_Ammo(ent, other);
//		predict = qfalse;
		break;
	case IT_ARMOR:
		respawn = Pickup_Armor(ent, other);
		break;
	case IT_HEALTH:
		respawn = Pickup_Health(ent, other);
		break;
	case IT_POWERUP:
		respawn = Pickup_Powerup(ent, other);
		predict = qfalse;
		break;
#ifdef MISSIONPACK
	case IT_PERSISTANT_POWERUP:
		respawn = Pickup_PersistantPowerup(ent, other);
		break;
#endif
	case IT_TEAM:
		respawn = Pickup_Team(ent, other);
		break;
	case IT_HOLDABLE:
		respawn = Pickup_Holdable(ent, other);
		break;
	default:
		return;
	}

	if ( !respawn ) {
		return;
	}

	// play the normal pickup sound
	if (predict) {
		G_AddPredictableEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
	} else {
		G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
	}

	// powerup pickups are global broadcasts
	if ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM) {
		// if we want the global sound to play
		if (!ent->speed) {
			gentity_t	*te;

			te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
			te->s.eventParm = ent->s.modelindex;
			te->r.svFlags |= SVF_BROADCAST;
		} else {
			gentity_t	*te;

			te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
			te->s.eventParm = ent->s.modelindex;
			// only send this temp entity to a single client
			te->r.svFlags |= SVF_SINGLECLIENT;
			te->r.singleClient = other->s.number;
		}
	}

	// fire item targets
	G_UseTargets (ent, other);

	// wait of -1 will not respawn
	if ( ent->wait == -1 ) {
		ent->r.svFlags |= SVF_NOCLIENT;
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		ent->unlinkAfterEvent = qtrue;
		return;
	}

	// non zero wait overrides respawn time
	if ( ent->wait ) {
		respawn = ent->wait;
	}

	// random can be used to vary the respawn time
	if ( ent->random ) {
		respawn += crandom() * ent->random;
		if ( respawn < 1 ) {
			respawn = 1;
		}
	}

	// dropped items will not respawn
	if ( ent->flags & FL_DROPPED_ITEM ) {
		ent->freeAfterEvent = qtrue;
	}

	// picked up items still stay around, they just don't
	// draw anything.  This allows respawnable items
	// to be placed on movers.
	ent->r.svFlags |= SVF_NOCLIENT;
	ent->s.eFlags |= EF_NODRAW;
	ent->r.contents = 0;

	// ZOID
	// A negative respawn times means to never respawn this item (but don't 
	// delete it).  This is used by items that are respawned by third party 
	// events such as ctf flags
	if ( respawn <= 0 ) {
		ent->nextthink = 0;
		ent->think = 0;
	} else {
		ent->nextthink = level.time + respawn * 1000;
		ent->think = RespawnItem;
	}
	trap_LinkEntity( ent );
}


//======================================================================

/*
================
LaunchItem

Spawns an item and tosses it forward
================
*/
gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) {
	gentity_t	*dropped;

	dropped = G_Spawn();

	dropped->s.eType = ET_ITEM;
	dropped->s.modelindex = item - bg_itemlist;	// store item number in modelindex
	dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item

	dropped->classname = item->classname;
	dropped->item = item;
	VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
	VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
	dropped->r.contents = CONTENTS_TRIGGER;

	dropped->touch = Touch_Item;

	G_SetOrigin( dropped, origin );
	dropped->s.pos.trType = TR_GRAVITY;
	dropped->s.pos.trTime = level.time;
	VectorCopy( velocity, dropped->s.pos.trDelta );

	dropped->s.eFlags |= EF_BOUNCE_HALF;
#ifdef MISSIONPACK
	if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF)			&& item->giType == IT_TEAM) { // Special case for CTF flags
#else
	if (g_gametype.integer == GT_CTF && item->giType == IT_TEAM) { // Special case for CTF flags
#endif
		dropped->think = Team_DroppedFlagThink;
		dropped->nextthink = level.time + 30000;
		Team_CheckDroppedItem( dropped );
	} else { // auto-remove after 30 seconds
		dropped->think = G_FreeEntity;
		dropped->nextthink = level.time + 30000;
	}

	dropped->flags = FL_DROPPED_ITEM;

	trap_LinkEntity (dropped);

	return dropped;
}

/*
================
Drop_Item

Spawns an item and tosses it forward
================
*/
gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) {
	vec3_t	velocity;
	vec3_t	angles;

	VectorCopy( ent->s.apos.trBase, angles );
	angles[YAW] += angle;
	angles[PITCH] = 0;	// always forward

	AngleVectors( angles, velocity, NULL, NULL );
	VectorScale( velocity, 150, velocity );
	velocity[2] += 200 + crandom() * 50;
	
	return LaunchItem( item, ent->s.pos.trBase, velocity );
}


/*
================
Use_Item

Respawn the item
================
*/
void Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
	RespawnItem( ent );
}

//======================================================================

/*
================
FinishSpawningItem

Traces down to find where an item should rest, instead of letting them
free fall from their spawn points
================
*/
void FinishSpawningItem( gentity_t *ent ) {
	trace_t		tr;
	vec3_t		dest;

	VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
	VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );

	ent->s.eType = ET_ITEM;
	ent->s.modelindex = ent->item - bg_itemlist;		// store item number in modelindex
	ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item

	ent->r.contents = CONTENTS_TRIGGER;
	ent->touch = Touch_Item;
	// useing an item causes it to respawn
	ent->use = Use_Item;

	if ( ent->spawnflags & 1 ) {
		// suspended
		G_SetOrigin( ent, ent->s.origin );
	} else {
		// drop to floor
		VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
		trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
		if ( tr.startsolid ) {
			G_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
			G_FreeEntity( ent );
			return;
		}

		// allow to ride movers
		ent->s.groundEntityNum = tr.entityNum;

		G_SetOrigin( ent, tr.endpos );
	}

	// team slaves and targeted items aren't present at start
	if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		return;
	}

	// powerups don't spawn in for a while
	if ( ent->item->giType == IT_POWERUP ) {
		float	respawn;

		respawn = 45 + crandom() * 15;
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		ent->nextthink = level.time + respawn * 1000;
		ent->think = RespawnItem;
		return;
	}


	trap_LinkEntity (ent);
}


qboolean	itemRegistered[MAX_ITEMS];

/*
==================
G_CheckTeamItems
==================
*/
void G_CheckTeamItems( void ) {

	// Set up team stuff
	Team_InitGame();

	if( g_gametype.integer == GT_CTF ) {
		gitem_t	*item;

		// check for the two flags
		item = BG_FindItem( "Red Flag" );
		if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" );
		}
		item = BG_FindItem( "Blue Flag" );
		if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" );
		}
	}
#ifdef MISSIONPACK
	if( g_gametype.integer == GT_1FCTF ) {
		gitem_t	*item;

		// check for all three flags
		item = BG_FindItem( "Red Flag" );
		if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" );
		}
		item = BG_FindItem( "Blue Flag" );
		if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" );
		}
		item = BG_FindItem( "Neutral Flag" );
		if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_neutralflag in map" );
		}
	}

	if( g_gametype.integer == GT_OBELISK ) {
		gentity_t	*ent;

		// check for the two obelisks
		ent = NULL;
		ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
		if( !ent ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map" );
		}

		ent = NULL;
		ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
		if( !ent ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map" );
		}
	}

	if( g_gametype.integer == GT_HARVESTER ) {
		gentity_t	*ent;

		// check for all three obelisks
		ent = NULL;
		ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
		if( !ent ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map" );
		}

		ent = NULL;
		ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
		if( !ent ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map" );
		}

		ent = NULL;
		ent = G_Find( ent, FOFS(classname), "team_neutralobelisk" );
		if( !ent ) {
			G_Printf( S_COLOR_YELLOW "WARNING: No team_neutralobelisk in map" );
		}
	}
#endif
}

/*
==============
ClearRegisteredItems
==============
*/
void ClearRegisteredItems( void ) {
	memset( itemRegistered, 0, sizeof( itemRegistered ) );

	// players always start with the base weapon
	RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
	RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
	// riotmod begin
	RegisterItem( BG_FindItemForWeapon(WP_BACKPACK));
	RegisterItem( BG_FindItemForWeapon(WP_GRENADE_LAUNCHER));

	RegisterItem( BG_FindItemForWeapon(WP_PULSE));
	RegisterItem( BG_FindItemForWeapon(WP_FAST_MACHINEGUN));
	RegisterItem( BG_FindItemForWeapon(WP_HOMING));

	RegisterItem( BG_FindItem( "Combat Power" ) );
	RegisterItem( BG_FindItem( "Defense Power" ) );
	RegisterItem( BG_FindItem( "Kinetic Power" ) );
	RegisterItem( BG_FindItem( "Stealth Power" ) );
	RegisterItem( BG_FindItem( "Regenerate Power" ) );

	RegisterItem( BG_FindItem( "Personal Teleporter" ) );
	RegisterItem( BG_FindItem( "Medkit" ) );

	// riotmod end
#ifdef MISSIONPACK
	if( g_gametype.integer == GT_HARVESTER ) {
		RegisterItem( BG_FindItem( "Red Cube" ) );
		RegisterItem( BG_FindItem( "Blue Cube" ) );
	}
#endif
}

/*
===============
RegisterItem

The item will be added to the precache list
===============
*/
void RegisterItem( gitem_t *item ) {
	if ( !item ) {
		G_Error( "RegisterItem: NULL" );
	}
	itemRegistered[ item - bg_itemlist ] = qtrue;
}


/*
===============
SaveRegisteredItems

Write the needed items to a config string
so the client will know which ones to precache
===============
*/
void SaveRegisteredItems( void ) {
	char	string[MAX_ITEMS+1];
	int		i;
	int		count;

	count = 0;
	for ( i = 0 ; i < bg_numItems ; i++ ) {
		if ( itemRegistered[i] ) {
			count++;
			string[i] = '1';
		} else {
			string[i] = '0';
		}
	}
	string[ bg_numItems ] = 0;

	G_Printf( "%i items registered\n", count );
	trap_SetConfigstring(CS_ITEMS, string);
}

/*
============
G_ItemDisabled
============
*/
int G_ItemDisabled( gitem_t *item ) {

	char name[128];

	Com_sprintf(name, sizeof(name), "disable_%s", item->classname);
	return trap_Cvar_VariableIntegerValue( name );
}

/*
============
G_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 G_SpawnItem (gentity_t *ent, gitem_t *item) {
	G_SpawnFloat( "random", "0", &ent->random );
	G_SpawnFloat( "wait", "0", &ent->wait );

	RegisterItem( item );
	if ( G_ItemDisabled(item) )
		return;

	ent->item = item;
	// some movers spawn on the second frame, so delay item
	// spawns until the third frame so they can ride trains
	ent->nextthink = level.time + FRAMETIME * 2;
	ent->think = FinishSpawningItem;

	ent->physicsBounce = 0.50;		// items are bouncy

	if ( item->giType == IT_POWERUP ) {
		G_SoundIndex( "sound/items/poweruprespawn.wav" );
		G_SpawnFloat( "noglobalsound", "0", &ent->speed);
	}

#ifdef MISSIONPACK
	if ( item->giType == IT_PERSISTANT_POWERUP ) {
		ent->s.generic1 = ent->spawnflags;
	}
#endif
}


/*
================
G_BounceItem

================
*/
void G_BounceItem( gentity_t *ent, trace_t *trace ) {
	vec3_t	velocity;
	float	dot;
	int		hitTime;

	// reflect the velocity on the trace plane
	hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
	BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
	dot = DotProduct( velocity, trace->plane.normal );
	VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );

	// cut the velocity to keep from bouncing forever
	VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );

	// check for stop
	if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {
		trace->endpos[2] += 1.0;	// make sure it is off ground
		SnapVector( trace->endpos );
		G_SetOrigin( ent, trace->endpos );
		ent->s.groundEntityNum = trace->entityNum;
		return;
	}

	VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
	VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
	ent->s.pos.trTime = level.time;
}


/*
================
G_RunItem

================
*/
void G_RunItem( gentity_t *ent ) {
	vec3_t		origin;
	trace_t		tr;
	int			contents;
	int			mask;

	// if groundentity has been set to -1, it may have been pushed off an edge
	if ( ent->s.groundEntityNum == -1 ) {
		if ( ent->s.pos.trType != TR_GRAVITY ) {
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = level.time;
		}
	}

	if ( ent->s.pos.trType == TR_STATIONARY ) {
		// check think function
		G_RunThink( ent );
		return;
	}

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// trace a line from the previous position to the current position
	if ( ent->clipmask ) {
		mask = ent->clipmask;
	} else {
		mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
	}
	trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, 
		ent->r.ownerNum, mask );

	VectorCopy( tr.endpos, ent->r.currentOrigin );

	if ( tr.startsolid ) {
		tr.fraction = 0;
	}

	trap_LinkEntity( ent );	// FIXME: avoid this for stationary?

	// check think function
	G_RunThink( ent );

	if ( tr.fraction == 1 ) {
		return;
	}

	// if it is in a nodrop volume, remove it
	contents = trap_PointContents( ent->r.currentOrigin, -1 );
	if ( contents & CONTENTS_NODROP ) {
		if (ent->item && ent->item->giType == IT_TEAM) {
			Team_FreeEntity(ent);
		} else {
			G_FreeEntity( ent );
		}
		return;
	}

	G_BounceItem( ent, &tr );
}

