Esempio n. 1
0
void LoadMap(void) {
	// Need to do this anyway, otherwise teleporters will be broken
	CreateItemMarkers();

	if (!(isRACE () || isCTF ())) {
		// If we have a .bot file, use that
		if (LoadBotRoutingFromFile ()) {
			map_supported = true;
			CustomiseFrogbotMap ();
			AssignVirtualGoals ();
			AllMarkersLoaded ();
			return;
		}
	}

	// At this point it's an unsupported map
	CustomiseFrogbotMap ();
	if (FrogbotOptionEnabled (FB_OPTION_EDITOR_MODE)) {
		gedict_t* e;

		// We don't want spawnpoint markers or powerups to mess with colours
		for (e = world; (e = nextent (e)); ) {
			e->s.v.effects = (int)e->s.v.effects & ~(EF_BLUE | EF_GREEN | EF_RED);
		}

		AssignGoalNumbers ();
	}
}
Esempio n. 2
0
File: combat.c Progetto: meag/ktx
/*
============
T_RadiusDamage
============
*/
void T_RadiusDamage( gedict_t * inflictor, gedict_t * attacker, float damage, gedict_t * ignore, deathType_t dtype )
{
	float           points;
	gedict_t       *head;
	vec3_t          org;

	head = trap_findradius( world, inflictor->s.v.origin, damage + 40 );

	while ( head )
	{
		if ( head != ignore )
		{
			if ( head->s.v.takedamage )
			{
				org[0] = inflictor->s.v.origin[0] - ( head->s.v.origin[0] + ( head->s.v.mins[0] + head->s.v.maxs[0] ) * 0.5 );
				org[1] = inflictor->s.v.origin[1] - ( head->s.v.origin[1] + ( head->s.v.mins[1] + head->s.v.maxs[1] ) * 0.5 );
				org[2] = inflictor->s.v.origin[2] - ( head->s.v.origin[2] + ( head->s.v.mins[2] + head->s.v.maxs[2] ) * 0.5 );
				points = 0.5 * vlen( org );

				if ( points < 0 )
					points = 0;

				points = damage - points;

				if ( head == attacker )
					points = points * 0.5;
				// no out of water discharge damage if k_dis 2
				else if ( cvar("k_dis") == 2 && dtLG_DIS == dtype && !head->s.v.waterlevel )
					points = 0;

				if ( points > 0 )
				{
					if ( CanDamage( head, inflictor ) )
					{
						head->deathtype = dtype;

						dmg_is_splash = 1; // mark damage as splash

						if ( cvar("k_instagib") || isRACE() ) // in instagib splash applied to inflictor only, for coil jump
						{
							if ( head == attacker )
								T_Damage( head, inflictor, attacker, points );
						}
						else
						{
							// shamblers only take half damage from rocket/grenade explosions
							if ( streq(head->s.v.classname, "monster_shambler") && !cvar("k_bloodfest") )
								points = points / 2;
							T_Damage( head, inflictor, attacker, points );
						}

						dmg_is_splash = 0; // unmark splash
					}
				}
			}
		}
		head = trap_findradius( head, inflictor->s.v.origin, damage + 40 );
	}
}
Esempio n. 3
0
File: player.c Progetto: deurk/ktx
void GibPlayer()
{
	qbool bloodfest_round_connect = ( k_bloodfest && !self->ready ); // in case of bloodfest and connecion during round.
	gedict_t *p;

	self->vw_index = 0;

	if ( isRACE() || bloodfest_round_connect )
		ThrowHead( "", self->s.v.health );
	else
		ThrowHead( "progs/h_player.mdl", self->s.v.health );

	if ( bloodfest_round_connect )
		return; // do not spawn sounds and gibs, preventing abuse.

    if( match_in_progress == 2 )
	{
		ThrowGib( "progs/gib1.mdl", self->s.v.health );
		ThrowGib( "progs/gib2.mdl", self->s.v.health );
		ThrowGib( "progs/gib3.mdl", self->s.v.health );
    }

	if ( isRACE() && race.status )
		return;

	// spawn temporary entity.
	p = spawn();
	setorigin( p, PASSVEC3( self->s.v.origin ) );
	p->s.v.nextthink = g_globalvars.time + 0.1;
	p->think = ( func_t ) SUB_Remove;

	if ( TELEDEATH( self )	)
	{
		sound( p, CHAN_VOICE, "player/teledth1.wav", 1, ATTN_NONE );
	}
	else
	{
		sound( p, CHAN_VOICE, (g_random() < 0.5 ? "player/gib.wav" : "player/udeath.wav"), 1, ATTN_NONE );
	}
}
Esempio n. 4
0
File: admin.c Progetto: deurk/ktx
void ToggleFallBunny ()
{
	if (match_in_progress) {
		return;
	}

	if (isRACE()) {
		G_sprint(self, 2, "Command blocked because race mode is active\n");
		return;
	}

	if ( k_yawnmode ) {
		G_sprint(self, 2, "Command blocked because yawnmode is active\n");
		return;
	}

	cvar_toggle_msg( self, "k_fallbunny", redtext("fallbunny") );
}
Esempio n. 5
0
File: combat.c Progetto: meag/ktx
void T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage )
{
	vec3_t          dir;
	gedict_t       *oldself;
	float           save;
	float           take;
	int				i, c1 = 8, c2 = 4, hdp;
	float			dmg_dealt = 0, virtual_take = 0;
	float			non_hdp_damage; // save damage before handicap apply for kickback calculation
	float			native_damage = damage; // save damage before apply any modificator
	char            *attackerteam, *targteam, *attackername, *victimname;
	qbool			tp4teamdmg = false;

	//midair and instagib
	float playerheight = 0, midheight = 0;
	qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false;

	// can't apply damage to dead
	if ( !targ->s.v.takedamage || ISDEAD( targ ) )
		return;

	// can't damage other players in race
	if ( isRACE() && ( attacker != targ ) )
	{
			if ( targ->ct == ctPlayer || attacker->ct == ctPlayer )
				return;
	}

	// ignore almost all damage in CA while coutdown
	if ( isCA() && match_in_progress && ra_match_fight != 2 )
	{
		if ( !( 	dtTELE1 == targ->deathtype	// always do tele damage
				 || dtTELE2 == targ->deathtype	// always do tele damage
				 || dtTELE3 == targ->deathtype	// always do tele damage
				 || dtSUICIDE == targ->deathtype // do suicide damage anyway
			  )
		)
			return;
	}	

	// used by buttons and triggers to set activator for target firing
	damage_attacker = attacker;
	damage_inflictor = inflictor;

	attackerteam = getteam( attacker );
	targteam = getteam( targ );

	if ( (int)cvar("k_midair") )
		midair = true;

	// in bloodfest boss damage factor.
	if ( k_bloodfest && attacker->bloodfest_boss )
	{
		damage *= 4;
	}

	// check for quad damage powerup on the attacker
	// midair quad makes rockets fast, but no change to damage
	if ( attacker->super_damage_finished > g_globalvars.time
	     && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype
		 && !midair 
	   )
		damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually

	// ctf strength rune
	if ( attacker->ctf_flag & CTF_RUNE_STR )
		damage *= 2;

	// ctf resistance rune
	if ( targ->ctf_flag & CTF_RUNE_RES )
	{
		damage /= 2;
		ResistanceSound( targ );
	}

	// did we hurt enemy flag carrier?
	if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) )
	{
		attacker->carrier_hurt_time = g_globalvars.time;
	}

	// in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes
	if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) )
	{
		tp4teamdmg = true;
	}

	if ( midair || cvar("k_instagib") )
	{
		traceline( PASSVEC3(targ->s.v.origin),
				targ->s.v.origin[0], 
				targ->s.v.origin[1], 
				targ->s.v.origin[2] - 2048,
				true, targ );

		playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 );
	}

	// get some data before apply damage in mid air mode
	if ( midair )
	{
		inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 );

		if ( streq( inflictor->s.v.classname, "rocket" ))
			midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2];

		rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype );
		stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype );

		if ( !rl_dmg ) {
			// damage types which ignore "lowheight"
			do_dmg =   targ->ct != ctPlayer				// always do damage to non player, secret doors etc...
				 	|| dtWATER_DMG == targ->deathtype	// always do water damage
				 	|| dtLAVA_DMG  == targ->deathtype	// always do lava damage
				 	|| dtSLIME_DMG == targ->deathtype	// always do slime damage
				 	|| dtSTOMP == targ->deathtype	// always do stomp damage
				 	|| dtTELE1 == targ->deathtype	// always do tele damage
				 	|| dtTELE2 == targ->deathtype	// always do tele damage
				 	|| dtTELE3 == targ->deathtype	// always do tele damage
					|| dtSUICIDE == targ->deathtype; // do suicide damage anyway
		}
	}

	non_hdp_damage = damage; // save damage before handicap apply for kickback calculation

	// #handicap#
	if ( attacker != targ ) // attack no self
	if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player
	if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100
	if (    dtAXE  == targ->deathtype
 		 || dtSG   == targ->deathtype
		 || dtSSG  == targ->deathtype
		 || dtNG   == targ->deathtype
		 || dtSNG  == targ->deathtype
		 || dtGL   == targ->deathtype
		 || dtRL   == targ->deathtype
		 || dtLG_BEAM     == targ->deathtype
		 || dtLG_DIS      == targ->deathtype
		 || dtLG_DIS_SELF == targ->deathtype // even that impossible
	   ) {
		damage *= 0.01f * hdp;
	}

	// save damage based on the target's armor level

	save = newceil( targ->s.v.armortype * damage );

	if ( tp4teamdmg )
		save = 0; // we do not touch armor

	if ( save >= targ->s.v.armorvalue )
	{
		save = targ->s.v.armorvalue;
		targ->s.v.armortype = 0;	// lost all armor
		targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) );
	}

	dmg_dealt += save;

	if ( match_in_progress == 2 )
		targ->s.v.armorvalue = targ->s.v.armorvalue - save;

	take = newceil( damage - save );

	// mid air damage modificators
	if ( midair )
	{
		int k_midair_minheight, midair_minheight;

		k_midair_minheight = (int)cvar("k_midair_minheight");	

		if ( k_midair_minheight == 1 )
			midair_minheight = 128;
		else if ( k_midair_minheight == 2 )
			midair_minheight = 256;
		else if ( k_midair_minheight == 3 )
			midair_minheight = 512;
		else if ( k_midair_minheight == 4 )
			midair_minheight = 1024;
		else
			midair_minheight = 64;

		if ( rl_dmg || stomp_dmg )
			take = 9999;

		if ( playerheight < midair_minheight && rl_dmg )
			take = 0; // no dmg done if target is not high enough

		if ( playerheight < 45 && !inwater && rl_dmg )
			take = 0; // no rl dmg in such case

		if ( !rl_dmg && !do_dmg )
			take = 0; // unknown damage for midair, so do not damage

		if ( rl_dmg && targ == attacker )
			take = 0; // no self rl damage
	}

	// instagib damage modificators
	if ( cvar("k_instagib") )
	{
		if ( inflictor->ct == ctPlayer )
			take = 5000;

		if ( attacker == targ )
			take = 0;
	}

	// helps kill player in prewar at "wrong" places
	if ( match_in_progress != 2 && native_damage > 450 )
		take = 99999;

	// team play damage avoidance and godmode or invincibility check

	virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags

	// ignore this checks for suicide damage
	if ( dtSUICIDE != targ->deathtype )
	{
		if ( ( int ) targ->s.v.flags & FL_GODMODE )
		{
			take = 0; // what if god was one of us
		}
		else if ( targ->invincible_finished >= g_globalvars.time )
		{
			if ( targ->invincible_sound < g_globalvars.time )
			{
				sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM );
				targ->invincible_sound = g_globalvars.time + 2;
			}

			take = 0;
		}
		else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) )
		 	&& !strnull( attackerteam )
		 	&& streq( targteam, attackerteam )
		 	&& attacker->ct == ctPlayer
		 	&& strneq( inflictor->s.v.classname, "door" )
		 	&& !TELEDEATH( targ ) // do telefrag damage in tp
	   	)
	   	{
			// teamplay == 1 don't damage self and mates (armor affected anyway)
			// teamplay == 3 don't damage mates, do damage to self (armor affected anyway)

			take = 0;	   	
	   	}
	   	else if ( tp4teamdmg )
	   	{
			take = 0; // we do not touch health	   	
	   	}
	}

	take = max(0, take); // avoid negative take, if any

	if ( cvar("k_dmgfrags") )
	{
		if ( TELEDEATH( targ ) )
		{
			// tele doesn't count for any dmgfrags damage
			dmg_dealt = 0; 
		}
		else if ( targ->invincible_finished >= g_globalvars.time )
		{
			// damage dealt _not_ capped by victim's health if victim has pent
			dmg_dealt += virtual_take;
		}
		else
		{
			// damage dealt capped by victim's health
			dmg_dealt += bound( 0, virtual_take, targ->s.v.health );
		}
	}
	else
	{
		// damage dealt capped by victim's health
		dmg_dealt += bound( 0, take, targ->s.v.health );
	}

	// add to the damage total for clients, which will be sent as a single
	// message at the end of the frame
	// FIXME: remove after combining shotgun blasts?
	if ( targ->ct == ctPlayer )
	{
		targ->s.v.dmg_take += take;
		targ->s.v.dmg_save += save;
		targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor );
	}

	if ( save )
	{
		if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname ))
	        	|| ( targ->deathtype == dtWATER_DMG )
	                || ( targ->deathtype == dtEXPLO_BOX )
	                || ( targ->deathtype == dtFALL )
	                || ( targ->deathtype == dtSQUISH )
	                || ( targ->deathtype == dtCHANGELEVEL )
	                || ( targ->deathtype == dtFIREBALL )
	                || ( targ->deathtype == dtSLIME_DMG )
	                || ( targ->deathtype == dtLAVA_DMG )
	                || ( targ->deathtype == dtTRIGGER_HURT )
		)
				attackername = "world";
		else
			attackername = attacker->s.v.netname;
			victimname = targ->s.v.netname;

		log_printf(
			"\t\t<event>\n"
			"\t\t\t<damage>\n"
			"\t\t\t\t<time>%f</time>\n"
			"\t\t\t\t<attacker>%s</attacker>\n"
			"\t\t\t\t<target>%s</target>\n"
			"\t\t\t\t<type>%s</type>\n"
			"\t\t\t\t<quad>%d</quad>\n"
			"\t\t\t\t<splash>%d</splash>\n"
			"\t\t\t\t<value>%d</value>\n"
			"\t\t\t\t<armor>1</armor>\n"
			"\t\t\t</damage>\n"
			"\t\t</event>\n",
			g_globalvars.time - match_start_time,
			cleantext(attackername),
			cleantext(victimname),
			death_type( targ->deathtype ),
			(int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ),
			dmg_is_splash,
			(int)save
		);
	}

	// figure momentum add
	if ( inflictor != world
		 && (	targ->s.v.movetype == MOVETYPE_WALK
			  || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) )
			 )
	)
	{
		float nailkick;

		for ( i = 0; i < 3; i++ )
			dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5;

		VectorNormalize( dir );

		dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2];

		if ( midair && non_hdp_damage < 60 && attacker != targ ) {
			c1 = 11;
			c2 = 6;
		}

		// Yawnmode: nails increases kickback
		// - Molgrum
		if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) )
			nailkick = 1.2;
		else
			nailkick = 1.0;

		for ( i = 0; i < 3; i++ ) 
			targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 );

		if ( midair && playerheight < 45 )
			targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component

		if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) )
		{
			targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND;		
		}
	}

	if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") )
	{
		if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ )
		{
			if ( isDuel() || isFFA() || strneq(attackerteam, targteam) )
			{
				int dmg_frags;
				attacker->ps.dmg_frags += dmg_dealt; // add dealt
				dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage
				attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags);
				attacker->ps.dmg_frags -= dmg_frags * 100;
			}
		}
	}

	// do the damage

	if (    match_in_progress == 2
		 || dtSUICIDE == targ->deathtype // do suicide damage anyway
		 || TELEDEATH( targ )
		 || ( k_practice && targ->ct != ctPlayer ) // #practice mode#
		 || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2
	   ) 
	{
		targ->s.v.health -= take;

//		G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health );

		if ( take )
		{
			if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname ))
		        	|| ( targ->deathtype == dtWATER_DMG )
		                || ( targ->deathtype == dtEXPLO_BOX )
		                || ( targ->deathtype == dtFALL )
		                || ( targ->deathtype == dtSQUISH )
		                || ( targ->deathtype == dtCHANGELEVEL )
		                || ( targ->deathtype == dtFIREBALL )
		                || ( targ->deathtype == dtSLIME_DMG )
		                || ( targ->deathtype == dtLAVA_DMG )
		                || ( targ->deathtype == dtTRIGGER_HURT )
			)
				attackername = "world";
			else
				attackername = attacker->s.v.netname;
				victimname = targ->s.v.netname;

			log_printf(
				"\t\t<event>\n"
				"\t\t\t<damage>\n"
				"\t\t\t\t<time>%f</time>\n"
				"\t\t\t\t<attacker>%s</attacker>\n"
				"\t\t\t\t<target>%s</target>\n"
				"\t\t\t\t<type>%s</type>\n"
				"\t\t\t\t<quad>%d</quad>\n"
				"\t\t\t\t<splash>%d</splash>\n"
				"\t\t\t\t<value>%d</value>\n"
				"\t\t\t\t<armor>0</armor>\n"
				"\t\t\t</damage>\n"
				"\t\t</event>\n",
				g_globalvars.time - match_start_time,
				cleantext(attackername),
				cleantext(victimname),
				death_type( targ->deathtype ),
				(int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ),
				dmg_is_splash,
				(int)take
			);
		}

		if ( !targ->s.v.health || dtSUICIDE == targ->deathtype )
			targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this
	}

	// show damage in sbar
	if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess )
	{
		if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) )
		{
			if ( targ->ct == ctPlayer )			
				targ->s.v.currentammo = 1000 + Q_rint(damage);

			if ( attacker != targ && attacker->ct == ctPlayer)
				attacker->s.v.health = 1000 + Q_rint(damage);
		}
	}

	// update damage stats like: give/taked/team damage
	if ( attacker->ct == ctPlayer && targ->ct == ctPlayer )
	{
		if ( attacker == targ )
		{
			// self damage

			attacker->ps.dmg_self += dmg_dealt;
		}
		else
		{
			int items = targ->s.v.items;

			// damage to enemy weapon
			if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) )
			{
				attacker->ps.dmg_eweapon += dmg_dealt;
			}

			if ( tp_num() && streq(attackerteam, targteam) )
			{
				attacker->ps.dmg_team += dmg_dealt;
			}
			else 
			{
				attacker->ps.dmg_g += dmg_dealt;
				targ->ps.dmg_t     += dmg_dealt;
			}

			// real hits

			if ( take || save )
			{
				if ( dtRL == targ->deathtype )
					attacker->ps.wpn[wpRL].rhits++;

				if ( dtGL == targ->deathtype )
					attacker->ps.wpn[wpGL].rhits++;
			}

			// virtual hits

			if ( virtual_take || save )
			{
				if ( dtRL == targ->deathtype )
				{
					attacker->ps.wpn[wpRL].vhits++;
					// virtual given rl damage
					attacker->ps.dmg_g_rl += ( virtual_take + save );
				}

				if ( dtGL == targ->deathtype )
					attacker->ps.wpn[wpGL].vhits++;
			}
		}
	}

	// mid air bonuses
	if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg)
			MidairDamageBonus(attacker, midheight);

	if ( midair && match_in_progress == 2 && stomp_dmg ) {
		attacker->ps.mid_stomps++;
		targ->s.v.frags -= 3;
	}

 	// if targed killed, do appropriate action and return
	if ( ISDEAD( targ ) )
	{
		Killed( targ, attacker, inflictor );
		return;
	}

	// react to the damage - call pain function
	oldself = self;
	self = targ;

  	if ( (int)self->s.v.flags & FL_MONSTER )
  	{
		GetMadAtAttacker( attacker );
  	}

	if ( self->th_pain )
	{
		self->th_pain( attacker, take );
	}

	self = oldself;
}
Esempio n. 6
0
File: vote.c Progetto: deurk/ktx
int get_votes_req( int fofs, qbool diff )
{
	float percent = 51;
	int   votes, vt_req, idx, el_type;

	votes   = get_votes( fofs );

	switch ( fofs ) {
		case OV_BREAK:   percent = cvar(k_matchLess ? "k_vp_map" : "k_vp_break"); break; // in matchless mode there is no /break but /next_map so using "k_vp_map"
		case OV_PICKUP:  percent = cvar("k_vp_pickup"); break;
		case OV_RPICKUP: percent = cvar("k_vp_rpickup"); break;
		case OV_MAP:
					    percent = cvar("k_vp_map");
						idx = vote_get_maps ();
						if ( idx >= 0 && !strnull( GetMapName(maps_voted[idx].map_id) ) )
							votes = maps_voted[idx].map_votes;
						else
							votes = 0;
						break;
		case OV_ELECT:
						if ( (el_type = get_elect_type ()) == etAdmin ) {
							percent = cvar("k_vp_admin");
							break;
						}
						else if ( el_type == etCaptain ) {
							percent = cvar("k_vp_captain");
							break;
						}
						else {
							percent = 100; break; // unknown/none election
							break;
						}

						break;

		case OV_NOSPECS: percent = cvar("k_vp_nospecs"); break;
		case OV_TEAMOVERLAY: percent = cvar("k_vp_teamoverlay"); break;
		case OV_COOP:    percent = cvar("k_vp_coop"); break;
		case OV_ANTILAG: percent = cvar("k_vp_antilag"); break;
	}

	percent = bound(0.51, bound(51, percent, 100)/100, 1); // calc and bound percentage between 50% to 100%

	if (isRACE() && fofs == OV_MAP) {
		vt_req = race_count_votes_req(percent);
	}
	else {
		vt_req = ceil(percent * (CountPlayers() - CountBots()));
	}

	if ( fofs == OV_ELECT )
		vt_req = max(2, vt_req); // if election, at least 2 votes needed
	else if ( fofs == OV_BREAK && k_matchLess && match_in_progress == 1 )
		vt_req = max(2, vt_req); // at least 2 votes in this case
	else if ( fofs == OV_BREAK )
		vt_req = max(1, vt_req); // at least 1 vote in any case
	else if ( fofs == OV_RPICKUP )
		vt_req = max(3, vt_req); // at least 3 votes in this case
	else if ( fofs == OV_NOSPECS && cvar("_k_nospecs") )
		vt_req = max(1, vt_req); // at least 1 vote in this case
	else if ( fofs == OV_NOSPECS )
		vt_req = max(2, vt_req); // at least 2 votes in this case
	else if ( fofs == OV_TEAMOVERLAY )
		vt_req = max(2, vt_req); // at least 2 votes in this case
	else if ( fofs == OV_COOP )
		vt_req = max(1, vt_req); // at least 1 votes in this case
	else if ( fofs == OV_ANTILAG )
		vt_req = max(2, vt_req); // at least 2 votes in this case

	if (CountBots () > 0 && CountPlayers () - CountBots () == 1)
		vt_req = 1;

	if ( diff )
		return max(0, vt_req - votes );

	return max(0, vt_req - CountBots());
}
Esempio n. 7
0
// KTX has in-built modifications to several maps - frogbot routing relies on entity order so we have
//   to customise again here.  Called after all markers created, but before traveltime calculations
static void CustomiseFrogbotMap (void)
{
	gedict_t* ent = NULL;

	// KTX may have added a quad, so to keep routes compatible with PR1-version, we add it as a marker after others
	if (streq(g_globalvars.mapname, "aerowalk") && !FrogbotOptionEnabled(FB_OPTION_EDITOR_MODE))
	{
		gedict_t* quad = ez_find (world, "item_artifact_super_damage");
		if (quad) {
			gedict_t* nearest_marker;

			quad->fb.fl_marker = false;
			nearest_marker = LocateMarker (quad->s.v.origin);
			quad->fb.fl_marker = true;
			StartItemFB (quad);
			quad->fb.T |= MARKER_DYNAMICALLY_ADDED;

			// Quad is in same zone as nearest marker, and linked by the first path that's valid
			SetZone (nearest_marker->fb.Z_, quad->fb.index + 1);
			SetGoalForMarker (18, quad);
			AddPath (nearest_marker, quad);
			AddPath (quad, nearest_marker);

			SpawnMarkerIndicator (quad);
		}
	}

	// We stopped it from removing the telespawn earlier on...
	if (!cvar ("k_end_tele_spawn") && streq ("end", g_globalvars.mapname)) {
		vec3_t      TS_ORIGIN = { -392, 608, 40 }; // tele spawn
		gedict_t*   p = NULL;
		gedict_t*   m = NULL;

		for (p = world; (p = find (p, FOFCLSN, "info_player_deathmatch")); ) {
			if (VectorCompare (p->s.v.origin, TS_ORIGIN)) {
				p->classname = "info_player_deathmatch_removed";

				// Remove any spawn marker
				for (m = world; (m = find (m, FOFCLSN, "spawnpoint")); ) {
					if (m->k_lastspawn == p) {
						ent_remove (m);
						break;
					}
				}
				break;
			}
		}
	}

	// Expand bounding box of all items
	if (!isRACE()) {
		for (ent = world; (ent = nextent(ent)); ) {
			if (streq(ent->classname, "info_teleport_destination") ||
				streq(ent->classname, "info_player_deathmatch")) {
				continue;
			}

			if (streq(ent->classname, "marker")) {
				vec3_t mins = { -65, -65, -24 };
				vec3_t maxs = { 65,  65,  32 };
				vec3_t viewoffset = { 80, 80, 24 };
				int i;

				for (i = 0; i < 3; ++i) {
					if (ent->fb.fixed_size[i]) {
						mins[i] = -ent->fb.fixed_size[i] / 2 - (i < 2 ? 15 : 0);
						maxs[i] = ent->fb.fixed_size[i] / 2 - (i < 2 ? 15 : 0);
						viewoffset[i] = (maxs[i] - mins[i]) / 2;
					}
				}
				VectorCopy(viewoffset, ent->s.v.view_ofs);
				setsize(ent, PASSVEC3(mins), PASSVEC3(maxs));
			}
			else if ((int)ent->s.v.flags & FL_ITEM) {
				PlaceItemFB(ent);
			}
		}
	}

	// Link all teleporters
	if (FrogbotOptionEnabled (FB_OPTION_EDITOR_MODE)) {
		for (ent = world; (ent = ez_find (ent, "trigger_teleport")); ) {
			// If this teleport takes us to the marker close to the grenade, set arrow_time
			if (!strnull (ent->target)) {
				gedict_t* target = find (world, FOFS (targetname), ent->target);

				AddPath (ent, target);
			}
		}
	}
}