示例#1
0
void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, int proj_type, float duration, qboolean bounce, int flashtype)
{
	int mod;
	float chance;
	qboolean hyperblaster = false;

	// holy freeze reduces firing rate by 50%
	if (que_typeexists(self->curses, AURA_HOLYFREEZE))
	{
		if (random() <= 0.5)
			return;
	}

	// chill effect reduces attack rate/refire
	if (self->chill_time > level.time)
	{
		chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level);
		if (random() > chance)
			return;
	}

	if (proj_type == BLASTER_PROJ_BLAST)
		mod = MOD_BLASTER;
	else
		mod = MOD_HYPERBLASTER;

	damage = monster_increaseDamageByTalent(self->activator, damage);
	fire_blaster(self, start, dir, damage, speed, effect, proj_type, mod, duration, bounce);

	gi.WriteByte (svc_muzzleflash2);
	gi.WriteShort (self - g_edicts);
	gi.WriteByte (flashtype);
	gi.multicast (start, MULTICAST_PVS);
}	
示例#2
0
qboolean G_CurseValidTarget (edict_t *self, edict_t *target, qboolean vis, qboolean isCurse)
{
	if (!G_EntIsAlive(target))
		return false;
	// don't target players with invulnerability
	if (target->client && (target->client->invincible_framenum > level.framenum))
		return false;
	// don't target spawning players
	if (target->client && (target->client->respawn_time > level.time))
		return false;
	// don't target players in chat-protect
	if (!ptr->value && target->client && (target->flags & FL_CHATPROTECT))
		return false;
	// don't target spawning world monsters
	if (target->activator && !target->activator->client && (target->svflags & SVF_MONSTER) 
		&& (target->deadflag != DEAD_DEAD) && (target->nextthink-level.time > 2*FRAMETIME))
		return false;
	// don't target cloaked players
	if (target->client && target->svflags & SVF_NOCLIENT)
		return false;
	if (vis && !visible(self, target))
		return false;
	if(que_typeexists(target->curses, CURSE_FROZEN))
		return false;
	if (isCurse && (target->flags & FL_GODMODE || OnSameTeam(self, target)))
		return false;
	if (target == self)
		return false;
	
	return true;
}
示例#3
0
void PlagueCloudSpawn (edict_t *ent)
{
	float	radius;
	edict_t *e=NULL;

	if (ent->myskills.abilities[PLAGUE].disable)
		return;

	if (!V_CanUseAbilities(ent, PLAGUE, 0, false))
		return;

	if ((ent->myskills.class_num == CLASS_POLTERGEIST) && !ent->mtype && !PM_PlayerHasMonster(ent))
		return; // can't use this in human form

	radius = PLAGUE_DEFAULT_RADIUS+PLAGUE_ADDON_RADIUS*ent->myskills.abilities[PLAGUE].current_level;

	if (radius > PLAGUE_MAX_RADIUS)
		radius = PLAGUE_MAX_RADIUS;

	// find someone nearby to infect
	while ((e = findradius(e, ent->s.origin, radius)) != NULL)
	{
		if (!G_ValidTarget(ent, e, true))
			continue;
	//	if (HasActiveCurse(e, CURSE_PLAGUE))
		if (que_typeexists(e->curses, CURSE_PLAGUE))
			continue;
		// holy water grants temporary immunity to curses
		if (e->holywaterProtection > level.time)
			continue;

		PlagueCloud(ent, e);
	}
}
示例#4
0
void Cmd_HolyFreeze(edict_t *ent)
{
	qboolean sameaura=false;

	if (debuginfo->value)
		gi.dprintf("DEBUG: %s just called Cmd_HolyFreeze()\n", ent->client->pers.netname);

	if(ent->myskills.abilities[HOLY_FREEZE].disable)
		return;

	if (!G_CanUseAbilities(ent, ent->myskills.abilities[HOLY_FREEZE].current_level, 0))
		return;
	// if we already had an aura on, remove it
	if (que_typeexists(ent->auras, AURA_HOLYFREEZE))
	{
		safe_cprintf(ent, PRINT_HIGH, "Holy freeze removed.\n");
		AuraRemove(ent, AURA_HOLYFREEZE);
		return;
	}
	
	ent->client->ability_delay = level.time + DEFAULT_AURA_DELAY;
	// do we have enough power cubes?
	if (ent->client->pers.inventory[power_cube_index] < DEFAULT_AURA_INIT_COST)
	{
		safe_cprintf(ent, PRINT_HIGH, "You need more %d power cubes to use this ability.\n", 
			DEFAULT_AURA_INIT_COST-ent->client->pers.inventory[power_cube_index]);
		return;
	}
	ent->client->pers.inventory[power_cube_index] -= DEFAULT_AURA_INIT_COST;
	gi.sound(ent, CHAN_ITEM, gi.soundindex("auras/holywind.wav"), 1, ATTN_NORM, 0);
	safe_cprintf(ent, PRINT_HIGH, "Now using holy freeze aura.\n");
	aura_holyfreeze(ent);
}
示例#5
0
void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, float damage, int kick, int hspread, int vspread, int count, int flashtype)
{
	float chance;

	// holy freeze reduces firing rate by 50%
	if (que_typeexists(self->curses, AURA_HOLYFREEZE))
	{
		if (random() <= 0.5)
			return;
	}

	// chill effect reduces attack rate/refire
	if (self->chill_time > level.time)
	{
		chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level);
		if (random() > chance)
			return;
	}

	damage = monster_increaseDamageByTalent(self->activator, damage);
	fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);

	gi.WriteByte (svc_muzzleflash2);
	gi.WriteShort (self - g_edicts);
	gi.WriteByte (flashtype);
	gi.multicast (start, MULTICAST_PVS);
}
示例#6
0
void plague_think (edict_t *self)
{
	int		dmg;
	float	radius;
	edict_t *e=NULL;
	
	// plague self-terminates if:
	if (!G_EntIsAlive(self->owner) || !G_EntIsAlive(self->enemy)	//someone dies
		|| (self->owner->flags & FL_WORMHOLE)						// owner enters a wormhole
		|| (self->owner->client->tball_delay > level.time)			//owner tballs away
		|| (self->owner->flags & FL_CHATPROTECT)					//3.0 owner is in chatprotect
		|| ((self->owner->myskills.class_num == CLASS_POLTERGEIST) && (!self->owner->mtype) && !PM_PlayerHasMonster(self->owner))  //3.0 poltergeist is in human form
		|| que_findtype(self->enemy->curses, NULL, HEALING) != NULL)	//3.0 player is blessed with healing
	{
		que_removeent(self->enemy->curses, self, true);
		return;
	}

	VectorCopy(self->enemy->s.origin, self->s.origin); // follow enemy

	radius = PLAGUE_DEFAULT_RADIUS+PLAGUE_ADDON_RADIUS*self->owner->myskills.abilities[PLAGUE].current_level;

	if (radius > PLAGUE_MAX_RADIUS)
		radius = PLAGUE_MAX_RADIUS;

	// find someone nearby to infect
	while ((e = findradius(e, self->s.origin, radius)) != NULL)
	{
		if (e == self->enemy)
			continue;
		if (!G_ValidTarget(self, e, true))
			continue;
		// don't allow more than one curse of the same type
		if (que_typeexists(e->curses, CURSE_PLAGUE))
			continue;
		// holy water grants temporary immunity to curses
		if (e->holywaterProtection > level.time)
			continue;
		// spawn another plague cloud on this entity
		PlagueCloud(self->owner, e);
	}

	if (level.time > self->wait)
	{
		dmg = (float)self->owner->myskills.abilities[PLAGUE].current_level/10 * ((float)self->enemy->max_health/20);
		if (!self->enemy->client && strcmp(self->enemy->classname, "player_tank") != 0)
			dmg *= 2; // non-clients take double damage (helps with pvm)
		if (dmg < 1)
			dmg = 1;
		if (dmg > 100)
			dmg = 100;
		T_Damage(self->enemy, self->enemy, self->owner, vec3_origin, self->enemy->s.origin, vec3_origin, 
			dmg, 0, DAMAGE_NO_ABILITIES, MOD_PLAGUE); // hurt 'em
		self->wait = level.time + PLAGUE_DELAY;
	}
	
	self->nextthink = level.time + FRAMETIME;

}
示例#7
0
static qboolean parasite_cantarget (edict_t *self, edict_t *target)
{
	int para_range = PARASITE_ATTACK_RANGE;

	return (G_EntExists(target) && !que_typeexists(target->curses, CURSE_FROZEN) 
		&& !OnSameTeam(self, target) && visible(self, target) && nearfov(self, target, 45, 45) 
		&& (entdist(self, target) <= para_range));
}
示例#8
0
void CursedPlayer (edict_t *ent)
{
	int		i;
	vec3_t	forward;

	if (!G_EntIsAlive(ent))
		return;
	if (!ent->client)
		return;
	if (!que_typeexists(ent->curses, CURSE))
	{
		// reset roll angles
		ent->client->ps.pmove.delta_angles[ROLL] = 0;
		return;
	}

	if (level.time > ent->curse_delay)
	{
		ent->curse_dir = GetRandom(1, 8);
		ent->curse_delay = level.time + 2*random();
	}

	// copy current viewing angles
	VectorCopy(ent->client->v_angle, forward);

	// choose which direction to move angles
	switch (ent->curse_dir)
	{
	case 1: forward[PITCH]+=CURSE_MOVEMENT; break; // down
	case 2: forward[PITCH]-=CURSE_MOVEMENT; break; // up
	case 3: forward[YAW]+=CURSE_MOVEMENT; break; // left
	case 4: forward[YAW]-=CURSE_MOVEMENT; break; // right
	case 5: forward[YAW]+=CURSE_MOVEMENT; forward[PITCH]-=CURSE_MOVEMENT; break;
	case 6: forward[YAW]+=CURSE_MOVEMENT; forward[PITCH]+=CURSE_MOVEMENT; break;
	case 7: forward[YAW]-=CURSE_MOVEMENT; forward[PITCH]-=CURSE_MOVEMENT; break;
	case 8: forward[YAW]+=CURSE_MOVEMENT; forward[PITCH]+=CURSE_MOVEMENT; break;
	}

	// change roll angles
	if (ent->curse_dir <= 4)
		forward[ROLL] +=CURSE_MOVEMENT;
	else
		forward[ROLL] -=CURSE_MOVEMENT;
	// don't roll too much
	if ((forward[ROLL] > 0) && (forward[ROLL] > CURSE_MAX_ROLL))
		forward[ROLL] = CURSE_MAX_ROLL;
	else if ((forward[ROLL] < 0) && (forward[ROLL] < -CURSE_MAX_ROLL))
		forward[ROLL] = -CURSE_MAX_ROLL;

	// set view angles 
	for (i = 0 ; i < 3 ; i++)
		ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(forward[i]-ent->client->resp.cmd_angles[i]);
	VectorCopy(forward, ent->client->ps.viewangles);
	VectorCopy(forward, ent->client->v_angle);
}
示例#9
0
qboolean ParasiteCanAttack (edict_t *ent)
{
	// if a player initiated a jump and they are not in the water, then don't let them attack
	if (!ent->groundentity && ent->waterlevel < 1 && ent->monsterinfo.jumpup)
		return false;

	if (level.time < ent->wait)
		return false; // re-fire time
	if (ent->monsterinfo.attack_finished > level.time)
		return false;

	return ((level.time > pregame_time->value) && (level.time > ent->client->respawn_time) 
		&& (!que_typeexists(ent->curses, CURSE_FROZEN)) && (level.time > ent->holdtime));
}
示例#10
0
void wormhole_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	if (!other || !other->inuse)
		return;

	// point to monster's pilot
	if (PM_MonsterHasPilot(other))
		other = other->activator;

	if ((other == self->creator) || IsAlly(self->creator, other))
	{
		float time;
		
		// can't enter wormhole with the flag
		if (HasFlag(other))
			return;
		
		// can't enter wormhole while being hurt
		if (other->lasthurt + DAMAGE_ESCAPE_DELAY > level.time)
			return;
		
		// can't enter wormhole while cursed (this includes healing, bless)
		if (que_typeexists(other->curses, -1))
			return;

		// can't stay in wormhole long if we're warring
		if (SPREE_WAR == true && SPREE_DUDE == other)
			time = 10.0;
		else
			time = BLACKHOLE_EXIT_TIME;

		// reset railgun sniper frames
		other->client->refire_frames = 0;

		VortexRemovePlayerSummonables(other);
		V_RestoreMorphed(other, 50); // un-morph

		other->flags |= FL_WORMHOLE;
		other->movetype = MOVETYPE_NOCLIP;
		other->svflags |= SVF_NOCLIENT;
		other->client->wormhole_time = level.time + BLACKHOLE_EXIT_TIME; // must exit wormhole by this time

		self->nextthink = level.time + FRAMETIME; // close immediately
	}
}
示例#11
0
void burn_person (edict_t *target, edict_t *owner, int damage)
{
	edict_t	*flame;
	que_t *slot=NULL;

	if (level.time < pregame_time->value)
		return;
	if (que_typeexists(target->curses, CURSE_FROZEN))
		return; // attacker is frozen!
	if (!G_ValidTarget(owner, target, false))
		return;
	while ((slot = que_findtype(target->curses, slot, CURSE_BURN)) != NULL)
	{
		if (slot->time-level.time >= 9)
			return; // only allow 1 burn per second
	}

	flame = G_Spawn();
	flame->movetype = MOVETYPE_NOCLIP;
	flame->solid = SOLID_NOT;
	VectorClear(flame->mins);
	VectorClear(flame->maxs);
	flame->owner = owner;
	flame->enemy = target;
	flame->mtype = CURSE_BURN;
	flame->delay = level.time + 10;
	flame->nextthink = level.time + FRAMETIME;
	flame->PlasmaDelay = level.time + FRAMETIME;
	flame->think = fire_think;
	flame->classname = "fire";
	flame->s.sound = gi.soundindex ("weapons/bfg__l1a.wav");
	flame->dmg = damage;
	VectorCopy(target->s.origin, flame->s.origin);
	gi.linkentity (flame);

	if (!que_addent(target->curses, flame, 10))
	{
		G_FreeEdict(flame);
		return;
	}

	gi.sound (target, CHAN_ITEM, gi.soundindex ("misc/needlite.wav"), 1, ATTN_NORM, 0);
}
示例#12
0
void minisentry_lockon (edict_t *self)
{
	float	max, temp;
	vec3_t	angles, v;

	// curse causes minisentry to fail to lock-on to enemy
	if ((que_typeexists(self->curses, CURSE)) && random() <= 0.8)
		return;

	temp = self->yaw_speed;
	self->yaw_speed *= 3;
	VectorSubtract(self->enemy->s.origin, self->s.origin, v);
	vectoangles(v, angles);
	self->ideal_yaw = vectoyaw(v);
	M_ChangeYaw(self);
	self->yaw_speed = temp; // restore original yaw speed
	self->s.angles[PITCH] = angles[PITCH];
	ValidateAngles(self->s.angles);
	// maximum pitch is 65 degrees in either direction
	if (self->enemy->s.origin[2] > self->s.origin[2]) // if the enemy is above
	{	
		if (self->owner && self->owner->style == SENTRY_FLIPPED)
			max = 340; // allow 20 degrees up
		else
			max = 315; // allow 45 degrees up
		if (self->s.angles[PITCH] < max)
			self->s.angles[PITCH] = max;
	}
	else
	{
		if (self->owner && self->owner->style == SENTRY_FLIPPED)
			max = 45; // allow 45 degrees down
		else
			max = 20; // allow 20 degrees down
		if (self->s.angles[PITCH] > max)
			self->s.angles[PITCH] = max;
	}
}
示例#13
0
void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
{
	float	radius, chance;

	// holy freeze reduces firing rate by 50%
	if (que_typeexists(self->curses, AURA_HOLYFREEZE))
	{
		if (random() <= 0.5)
			return;
	}

	// chill effect reduces attack rate/refire
	if (self->chill_time > level.time)
	{
		chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level);
		if (random() > chance)
			return;
	}

	radius = damage;

	// cap damage radius
	if (damage > 125)
		radius = 125;

	// cap speed
	if (speed > 1000)
		speed = 1000;

	damage = monster_increaseDamageByTalent(self->activator, damage);
	fire_rocket (self, start, dir, damage, speed, radius, damage);

	gi.WriteByte (svc_muzzleflash2);
	gi.WriteShort (self - g_edicts);
	gi.WriteByte (flashtype);
	gi.multicast (start, MULTICAST_PVS);
}	
示例#14
0
qboolean CanCurseTarget (edict_t *caster, edict_t *target, int type, qboolean isCurse, qboolean vis)
{
	if (!G_EntIsAlive(target))
		return false;
	// don't target players with invulnerability
	if (target->client && (target->client->invincible_framenum > level.framenum))
		return false;
	// don't target spawning players
	if (target->client && (target->client->respawn_time > level.time))
		return false;
	// don't target players in chat-protect
	if (!ptr->value && target->client && (target->flags & FL_CHATPROTECT))
		return false;
	// don't target spawning world monsters
	if (target->activator && !target->activator->client && (target->svflags & SVF_MONSTER) 
		&& (target->deadflag != DEAD_DEAD) && (target->nextthink-level.time > 2*FRAMETIME))
		return false;
	// don't target cloaked players
	if (target->client && target->svflags & SVF_NOCLIENT)
		return false;
	if (vis && !visible(caster, target))
		return false;
	if(que_typeexists(target->curses, CURSE_FROZEN))
		return false;
	if (isCurse && (target->flags & FL_GODMODE || OnSameTeam(caster, target)))
		return false;
	if (target == caster)
		return false;
	// holywater gives immunity to curses for a short time.
	if (target->holywaterProtection > level.time && type != BLESS && type != HEALING)
		return false;
	// don't allow bless on flag carrier
	if ((type == BLESS) && target->client && HasFlag(target))
		return false;
	return true;
}
示例#15
0
/*
=============
P_WorldEffects
=============
*/
void P_WorldEffects (void)
{
	qboolean	breather;
	qboolean	envirosuit;
	int			waterlevel, old_waterlevel;

	if (current_player->movetype == MOVETYPE_NOCLIP)
	{
		current_player->air_finished = level.time + 12;	// don't need air
		return;
	}

	//K03 Begin
	//if (HasActiveCurse(current_player, CURSE_FROZEN))
	if (que_typeexists(current_player->curses, CURSE_FROZEN))
		current_player->air_finished = level.time + 6;
	//K03 End

	waterlevel = current_player->waterlevel;
	old_waterlevel = current_client->old_waterlevel;
	current_client->old_waterlevel = waterlevel;

	breather = current_client->breather_framenum > level.framenum;
	envirosuit = current_client->enviro_framenum > level.framenum;

	//
	// if just entered a water volume, play a sound
	//
	if (!old_waterlevel && waterlevel)
	{
		if ((current_player->client->pers.inventory[ITEM_INDEX(FindItem("Stealth Boots"))] < 1))
		{
			if((current_player->myskills.abilities[CLOAK].disable) || (current_player->myskills.abilities[CLOAK].current_level))
			{
				current_player->lastsound = level.framenum; // trigger monsters
				PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
				if (current_player->watertype & CONTENTS_LAVA)
					gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
				else if (current_player->watertype & CONTENTS_SLIME)
					gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
				else if (current_player->watertype & CONTENTS_WATER)
					gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
			}
		}
		current_player->flags |= FL_INWATER;

		// clear damage_debounce, so the pain sound will play immediately
		current_player->damage_debounce_time = level.time - 1;
	}

	//
	// if just completely exited a water volume, play a sound
	//
	if (old_waterlevel && ! waterlevel)
	{
		if ((current_player->client->pers.inventory[ITEM_INDEX(FindItem("Stealth Boots"))]<1) && !current_player->mtype)
		{
			if((current_player->myskills.abilities[CLOAK].disable) || (current_player->myskills.abilities[CLOAK].current_level < 1))
			{
				current_player->lastsound = level.framenum; // trigger monsters
				PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
				gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
			}
		}
		current_player->flags &= ~FL_INWATER;
	}

	//
	// check for head just going under water
	//
	if (old_waterlevel != 3 && waterlevel == 3)
	{
		if (current_player->client)//K03
			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
	}

	//
	// check for head just coming out of water
	//
	if (old_waterlevel == 3 && waterlevel != 3)
	{
		if (current_player->air_finished < level.time)
		{	// gasp for air
			if (current_player->client)//K03
			{
			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
			PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
			}
		}
		else  if (current_player->air_finished < level.time + 11)
		{	// just break surface
			if (current_player->client)//K03
				gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
		}
	}

	//
	// check for drowning
	//
	if (waterlevel == 3)
	{
		// breather or envirosuit give air
		if (breather || envirosuit)
		{
			current_player->air_finished = level.time + 10;

			if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
			{
				if (current_player->client)//K03
				{
				if (!current_client->breather_sound)
					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
				else
					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
				current_client->breather_sound ^= 1;
				PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
				}
				//FIXME: release a bubble?
			}
		}

		// if out of air, start drowning
		if ((current_player->air_finished < level.time) 
			&& !((current_player->myskills.class_num == CLASS_POLTERGEIST) && (current_player->mtype == 0))
			&& (current_player->myskills.abilities[WORLD_RESIST].current_level < 1 
									|| HasFlag(current_player)) 
			&& !(current_player->flags & FL_GODMODE))
		{	// drown!
			if (current_player->client->next_drown_time < level.time 
				&& current_player->health > 0)
			{
				current_player->client->next_drown_time = level.time + 1;

				// take more damage the longer underwater
				current_player->dmg += 2;
				if (current_player->dmg > 15)
					current_player->dmg = 15;

				// play a gurp sound instead of a normal pain sound
				if (current_player->client)
				{
					if (current_player->health <= current_player->dmg)
						gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
					else if (rand()&1)
						gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
					else
						gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
				}

				current_player->pain_debounce_time = level.time;

				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
			}
		}
	}
	else
	{
		current_player->air_finished = level.time + 12;
		current_player->dmg = 2;
	}

	//
	// check for sizzle damage
	//
	if (waterlevel && (current_player->watertype & (CONTENTS_LAVA|CONTENTS_SLIME)) 
		&& (current_player->myskills.abilities[WORLD_RESIST].current_level < 1 || HasFlag(current_player)) 
		&& !(current_player->flags & FL_GODMODE) 
		&& !((current_player->myskills.class_num == CLASS_POLTERGEIST) && (current_player->mtype == 0)))
	{
		if (current_player->watertype & CONTENTS_LAVA)
		{
			if (current_player->health > 0
				&& current_player->pain_debounce_time <= level.time
				&& current_client->invincible_framenum < level.framenum)
			{
				if (current_player->client)//K03
				{
				if (rand()&1)
					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
				else
					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
				}
				current_player->pain_debounce_time = level.time + 1;
			}

			if (envirosuit)	// take 1/3 damage with envirosuit
				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
			else
				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
		}

		if (current_player->watertype & CONTENTS_SLIME)
		{
			if (!envirosuit)
			{	// no damage from slime with envirosuit
				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
			}
		}
	}
}
示例#16
0
void Cmd_PlayerToMedic_f (edict_t *ent)
{
	vec3_t	boxmin, boxmax;
	trace_t	tr;
	int cost = MEDIC_INIT_COST;
	//Talent: More Ammo
	int talentLevel = getTalentLevel(ent, TALENT_MORE_AMMO);

	if (debuginfo->value)
		gi.dprintf("DEBUG: %s just called Cmd_PlayerToMedic_f()\n", ent->client->pers.netname);

	// try to switch back
	if (ent->mtype || PM_PlayerHasMonster(ent))
	{
		// don't let a player-tank unmorph if they are cocooned
		if (ent->owner && ent->owner->inuse && ent->owner->movetype == MOVETYPE_NONE)
			return;

		if (que_typeexists(ent->curses, 0))
		{
			safe_cprintf(ent, PRINT_HIGH, "You can't morph while cursed!\n");
			return;
		}

		V_RestoreMorphed(ent, 0);
		return;
	}

	//Talent: Morphing
	if(getTalentSlot(ent, TALENT_MORPHING) != -1)
		cost *= 1.0 - 0.25 * getTalentLevel(ent, TALENT_MORPHING);

//	if (!G_CanUseAbilities(ent, ent->myskills.abilities[MEDIC].current_level, cost))
//		return;

	if (!V_CanUseAbilities(ent, MEDIC, cost, true))
		return;

	if (HasFlag(ent))
	{
		safe_cprintf(ent, PRINT_HIGH, "Can't morph while carrying flag!\n");
		return;
	}

	// make sure don't get stuck in a wall
	VectorSet (boxmin, -24, -24, -24);
	VectorSet (boxmax, 24, 24, 32);
	tr = gi.trace(ent->s.origin, boxmin, boxmax, ent->s.origin, ent, MASK_SHOT);
	if (tr.fraction<1)
	{
		safe_cprintf(ent, PRINT_HIGH, "Not enough room to morph!\n");
		return;
	}
	
	V_ModifyMorphedHealth(ent, MORPH_MEDIC, true);

	VectorCopy(boxmin, ent->mins);
	VectorCopy(boxmax, ent->maxs);

	ent->monsterinfo.attack_finished = level.time + 0.5;// can't attack immediately

	ent->client->pers.inventory[power_cube_index] -= cost;
	ent->client->ability_delay = level.time + MEDIC_DELAY;

	ent->mtype = MORPH_MEDIC;
	ent->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2");
	ent->s.modelindex2 = 0;

	if (!ent->myskills.administrator)
		ent->s.skinnum = 0;
	else
		ent->s.skinnum = 2; // commander

	// set maximum hyperblaster ammo
	ent->myskills.abilities[MEDIC].max_ammo = MEDIC_HB_INITIAL_AMMO+MEDIC_HB_ADDON_AMMO
		*ent->myskills.abilities[MEDIC].current_level;

	// Talent: More Ammo
	// increases ammo 10% per talent level
	if(talentLevel > 0) ent->myskills.abilities[MEDIC].max_ammo *= 1.0 + 0.1*talentLevel;

	// give them some starting ammo
	ent->myskills.abilities[MEDIC].ammo = MEDIC_HB_START_AMMO;

	ent->client->refire_frames = 0; // reset charged weapon
	ent->client->weapon_mode = 0; // reset weapon mode
	lasersight_off(ent);

	gi.sound (ent, CHAN_WEAPON, gi.soundindex("spells/morph.wav") , 1, ATTN_NORM, 0);
}
示例#17
0
void Cmd_PlayerToParasite_f (edict_t *ent)
{
	int para_cubecost = PARASITE_INIT_COST;

	if (debuginfo->value)
		gi.dprintf("DEBUG: %s just called Cmd_PlayerToParasite_f()\n", ent->client->pers.netname);

	// try to switch back
	if (ent->mtype || PM_PlayerHasMonster(ent))
	{
		// don't let a player-tank unmorph if they are cocooned
		if (ent->owner && ent->owner->inuse && ent->owner->movetype == MOVETYPE_NONE)
			return;

		if (que_typeexists(ent->curses, 0))
		{
			gi.cprintf(ent, PRINT_HIGH, "You can't morph while cursed!\n");
			return;
		}

		V_RestoreMorphed(ent, 0);
		return;
	}

	//Talent: Morphing
	if(getTalentSlot(ent, TALENT_MORPHING) != -1)
		para_cubecost *= 1.0 - 0.25 * getTalentLevel(ent, TALENT_MORPHING);

//	if (!G_CanUseAbilities(ent, ent->myskills.abilities[BLOOD_SUCKER].current_level, para_cubecost))
	//	return;
	if (!V_CanUseAbilities(ent, BLOOD_SUCKER, para_cubecost, true))
		return;

	if (HasFlag(ent))
	{
		gi.cprintf(ent, PRINT_HIGH, "Can't morph while carrying flag!\n");
		return;
	}

	V_ModifyMorphedHealth(ent, M_MYPARASITE, true);

	ent->wait = level.time + 0.5;// can't attack immediately

	ent->client->pers.inventory[power_cube_index] -= para_cubecost;
	ent->client->ability_delay = level.time + PARASITE_DELAY;

	ent->mtype = M_MYPARASITE;
	ent->s.modelindex = gi.modelindex ("models/monsters/parasite/tris.md2");
	ent->s.modelindex2 = 0;
	ent->s.skinnum = 0;

	// decloak
	ent->svflags &= ~SVF_NOCLIENT;
	ent->client->cloaking = false;
	ent->client->cloakable = 0;

	ent->maxs[2] = 8;
	ent->viewheight = 0;

	ent->client->refire_frames = 0; // reset charged weapon
	ent->client->weapon_mode = 0; // reset weapon mode
	lasersight_off(ent);

	gi.sound (ent, CHAN_WEAPON, gi.soundindex("spells/morph.wav") , 1, ATTN_NORM, 0);
}
示例#18
0
void Cmd_PlayerToBerserk_f (edict_t *ent)
{
	int cost = BERSERK_COST;

	if (debuginfo->value)
		gi.dprintf("DEBUG: %s just called Cmd_PlayerToBerserk_f()\n", ent->client->pers.netname);

	// try to switch back
	if (ent->mtype || PM_PlayerHasMonster(ent))
	{
		// don't let a player-tank unmorph if they are cocooned
		if (ent->owner && ent->owner->inuse && ent->owner->movetype == MOVETYPE_NONE)
			return;

		if (que_typeexists(ent->curses, 0))
		{
			safe_cprintf(ent, PRINT_HIGH, "You can't morph while cursed!\n");
			return;
		}

		V_RestoreMorphed(ent, 0);
		return;
	}

	//Talent: Morphing
    if (vrx_get_talent_slot(ent, TALENT_MORPHING) != -1)
        cost *= 1.0 - 0.25 * vrx_get_talent_level(ent, TALENT_MORPHING);

	if (!V_CanUseAbilities(ent, BERSERK, cost, true))
		return;

	if (HasFlag(ent) && !hw->value)
	{
		safe_cprintf(ent, PRINT_HIGH, "Can't morph while carrying flag!\n");
		return;
	}

	V_ModifyMorphedHealth(ent, MORPH_BERSERK, true);

	ent->monsterinfo.attack_finished = level.time + 0.5;// can't attack immediately

	ent->client->pers.inventory[power_cube_index] -= cost;
	ent->client->ability_delay = level.time + BERSERK_DELAY;

	ent->mtype = MORPH_BERSERK;
	ent->s.modelindex = gi.modelindex ("models/monsters/berserk/tris.md2");
	ent->s.modelindex2 = 0;
	ent->s.skinnum = 0;

	// undo crouching / ducked state
	// try asking their client to get up
	stuffcmd(ent, "-movedown\n");
	// if their client ignores the command, force them up
	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
	{
		ent->client->ps.pmove.pm_flags &= ~PMF_DUCKED;
		ent->viewheight = 22;
		ent->maxs[2] += 28;
	}
	
	ent->client->refire_frames = 0; // reset charged weapon
	ent->client->weapon_mode = 0; // reset weapon mode
	ent->client->pers.weapon = NULL;
	ent->client->ps.gunindex = 0;
	lasersight_off(ent);

    gi.sound(ent, CHAN_WEAPON, gi.soundindex("abilities/morph.wav"), 1, ATTN_NORM, 0);
}
示例#19
0
文件: v_items.c 项目: mylemans/vrxcl
void cmd_Drink(edict_t *ent, int itemtype, int index)
{
	int i;
	item_t *slot = NULL;
	qboolean found = false;

	//Don't drink too many potions too quickly
	if (ent->client->ability_delay > level.time)
		return;

	if (ctf->value && ctf_enable_balanced_fc->value && HasFlag(ent))
		return;

	if (index)
	{
		slot = &ent->myskills.items[index-1];
		found = true;
	}
	else
	{
		//Find item in inventory
		for (i = 3; i < MAX_VRXITEMS; ++i)
		{
			if (ent->myskills.items[i].itemtype == itemtype)
			{
				slot = &ent->myskills.items[i];
				found = true;
				break;
			}
		}
	}

	if (!found)
	{
		safe_cprintf(ent, PRINT_HIGH, "You have none in stock.\n");
		return;
	}

	//use it
	switch(itemtype)
	{
	case ITEM_POTION:
		{
			int max_hp = MAX_HEALTH(ent);

			if (ent->health < max_hp)
			{
				//Use the potion
				ent->health += max_hp/* / 3*/; // make them useful once again vrx chile 1.4
				if (ent->health > max_hp)
					ent->health = max_hp;

				//You can only drink 1/sec
				ent->client->ability_delay = level.time + 3.3;
				
				//Play sound
				gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/potiondrink.wav"), 1, ATTN_NORM, 0);
				
				//Consume a potion
				slot->quantity--;
				safe_cprintf(ent, PRINT_HIGH, "You drank a potion. Potions left: %d\n", slot->quantity);
				if (slot->quantity < 1)
					V_ItemClear(slot);
			}
			else safe_cprintf(ent, PRINT_HIGH, "You don't need to drink this yet, you have lots of health.\n");
			return;

		}
		break;
	case ITEM_ANTIDOTE:
		{
			if (que_typeexists(ent->curses, 0))
			{
				int i;
				//Use the potion
				for (i = 0; i < QUE_MAXSIZE; ++i)
				{
					que_t *curse = &ent->curses[i];
					if ((curse->ent && curse->ent->inuse) && (curse->ent->atype != HEALING && curse->ent->atype != BLESS))
					{
						//destroy the curse
						if (curse->ent->enemy && (curse->ent->enemy == ent))
							G_FreeEdict(curse->ent);
						// remove entry from the queue
						curse->time = 0;
						curse->ent = NULL;
					}
				}

				//Give them a short period of curse immunity
				ent->holywaterProtection = level.time + 5.0; //5 seconds immunity

				//You can only drink 1/sec
				ent->client->ability_delay = level.time + 1.0;
				
				//Play sound
				gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/rare.wav"), 1, ATTN_NORM, 0);
				
				//Consume a potion
				slot->quantity--;
				safe_cprintf(ent, PRINT_HIGH, "You used some holywater. Vials left: %d\n", slot->quantity);
				if (slot->quantity < 1)
					V_ItemClear(slot);
				
			}
			else safe_cprintf(ent, PRINT_HIGH, "You are not cursed, so you don't need to use this yet.\n");
			return;
		}
		break;
	}
}
示例#20
0
void ParasiteAttack (edict_t *ent)
{
	int		damage, kick;
	vec3_t	forward, right, start, end, offset;
	trace_t	tr;

	if (debuginfo->value)
		gi.dprintf("%s just called ParasiteAttack()\n", ent->client->pers.userinfo);

	// terminate attack
	if (!G_EntIsAlive(ent) || (ent->parasite_frames > PARASITE_MAXFRAMES)
		|| que_typeexists(ent->curses, CURSE_FROZEN))
	{
		parasite_endattack(ent);
		return;
	}

	// calculate starting point
	AngleVectors (ent->client->v_angle, forward, right, NULL);
	VectorSet(offset, 0, 7,  ent->viewheight-8);
	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
	
	// do we already have a valid target?
	if (G_ValidTarget(ent, ent->parasite_target, true) 
		&& (entdist(ent, ent->parasite_target) <= PARASITE_RANGE)
		&& infov(ent, ent->parasite_target, 90))
	{
		VectorSubtract(ent->parasite_target->s.origin, start, forward);
		VectorNormalize(forward);
	}

	VectorMA(start, PARASITE_RANGE, forward, end);
	tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT);
	// did we hit something?
	if (G_EntIsAlive(tr.ent) && !OnSameTeam(ent, tr.ent))
	{
		if (ent->parasite_frames == 0)
		{
			ent->client->pers.inventory[power_cube_index] -= PARASITE_COST;
			gi.sound (ent, CHAN_AUTO, gi.soundindex("parasite/paratck3.wav"), 1, ATTN_NORM, 0);
			ent->client->ability_delay = level.time + PARASITE_DELAY;
		}

		ent->parasite_target = tr.ent;
		damage = 2*ent->myskills.abilities[BLOOD_SUCKER].current_level;
		if (tr.ent->groundentity)
			kick = -100;
		else
			kick = -50;
		
		T_Damage(tr.ent, ent, ent, forward, tr.endpos, 
			tr.plane.normal, damage, kick, DAMAGE_NO_ABILITIES, MOD_PARASITE);

		gi.WriteByte(svc_temp_entity);
		gi.WriteByte(TE_PARASITE_ATTACK);
		gi.WriteShort(ent-g_edicts);
		gi.WritePosition(start);
		gi.WritePosition(tr.endpos);
		gi.multicast(ent->s.origin, MULTICAST_PVS);

		ent->parasite_frames++;
	}
	else if (ent->parasite_frames)
		parasite_endattack(ent);

}
示例#21
0
void minisentry_attack (edict_t *self)
{
	int			speed, dmg_radius;
	float		chance;
	vec3_t		forward, start, aim;
	qboolean	slowed=false;

	minisentry_lockon(self);
	if (self->light_level < 1)
		return; // out of ammo
	// are we affected by holy freeze?
	//if (HasActiveCurse(self, AURA_HOLYFREEZE))
	if (que_typeexists(self->curses, AURA_HOLYFREEZE))
		slowed = true;
	
	// calculate muzzle location
	AngleVectors(self->s.angles, forward, NULL, NULL);
	VectorCopy(self->s.origin, start);
	if (self->owner && self->owner->style == SENTRY_FLIPPED)
		start[2] -= abs(self->mins[2]);
	else
		start[2] += self->maxs[2];
	VectorMA(start, (self->maxs[0] + 16), forward, start);

	if ((level.time > self->wait) && infov(self, self->enemy, 30))
	{
		speed = 650 + 35*self->creator->myskills.abilities[BUILD_SENTRY].current_level;
		MonsterAim(self, -1, speed, true, 0, aim, start);
		dmg_radius = self->radius_dmg;
		if (dmg_radius > 150)
			dmg_radius = 150;
		fire_rocket (self, start, aim, self->radius_dmg, speed, dmg_radius, self->radius_dmg);
		if (slowed)
			self->wait = level.time + 2.0;
		else if (self->chill_time > level.time)
			self->wait = level.time + (1.0 * (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level));
		else
			self->wait = level.time + 1.0;
	
	}
	self->light_level--; // decrease ammo
	
	if (slowed && !(level.framenum%2))
		return;

	// chill effect reduces attack rate/refire
	if (self->chill_time > level.time)
	{
		chance = 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level);
		if (random() > chance)
			return;
	}

	fire_bullet (self, start, forward, self->dmg, 2*self->dmg, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_SENTRY);
	gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/plaser.wav"), 1, ATTN_NORM, 0);

	gi.WriteByte (svc_muzzleflash);
	gi.WriteShort (self-g_edicts);
	gi.WriteByte (MZ_IONRIPPER|MZ_SILENCED);
	gi.multicast (start, MULTICAST_PVS);
}