Пример #1
0
void deflect_think (edict_t *self)
{
	edict_t *player = G_GetClient(self->enemy);
	//Find my slot
	que_t *slot = NULL;
	slot = que_findtype(self->enemy->curses, NULL, DEFLECT);

	// Blessing self-terminates if the enemy dies or the duration expires
	if (!slot || !que_valident(slot))
	{
		if (player && level.time >= self->monsterinfo.selected_time)
			gi.cprintf(player, PRINT_HIGH, "Deflect has expired\n");

		que_removeent(self->enemy->curses, self, true);
		return;
	}

	// warn player that deflect is about to expire
//	if (player && !(level.framenum % 10) && (level.time >= slot->time - 5))
//		gi.cprintf(player, PRINT_HIGH, "Deflect will expire in %.0f seconds\n", slot->time - level.time);

	//Stick with the target
	VectorCopy(self->enemy->s.origin, self->s.origin);
	gi.linkentity(self);

	DeflectProjectiles(self->enemy, self->random, false);

	//Next think
	self->nextthink = level.time + FRAMETIME;

}
Пример #2
0
void curse_think(edict_t *self)
{
	//Find my curse slot
	que_t *slot = NULL;
	slot = que_findtype(self->enemy->curses, NULL, self->atype);

	// curse self-terminates if the enemy dies or the duration expires
	if (!slot || !que_valident(slot))
	{
		que_removeent(self->enemy->curses, self, true);
		return;
	}

	CurseEffects(self->enemy, 10, 242);

	//Stick with the target
	VectorCopy(self->enemy->s.origin, self->s.origin);
	gi.linkentity(self);

	//Next think time
	self->nextthink = level.time + FRAMETIME;

	LifeDrain(self);// 3.5 this must be called last, because it may free the curse ent
	Bleed(self);//4.2
}
Пример #3
0
void Bless_think(edict_t *self)
{
	//Find my slot
	que_t *slot = NULL;
	slot = que_findtype(self->enemy->curses, NULL, BLESS);

	// Blessing self-terminates if the enemy dies or the duration expires
	if (!slot || !que_valident(slot))
	{
		self->enemy->superspeed = false;
		que_removeent(self->enemy->curses, self, true);
		return;
	}

	//Stick with the target
	VectorCopy(self->enemy->s.origin, self->s.origin);
	gi.linkentity(self);

	//give them super speed
	self->enemy->superspeed = true;

	//Next think
	self->nextthink = level.time + FRAMETIME;

}
Пример #4
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;

}
Пример #5
0
void salvation_think (edict_t *self)
{
	int		radius;
	edict_t *other=NULL;
	que_t	*slot=NULL;

	// check status of owner
	if (!CheckAuraOwner(self, COST_FOR_SALVATION))
	{
		que_removeent(self->owner->auras, self, true);
		return;
	}

	// use cubes
	if (!(level.framenum % DEFAULT_AURA_FRAMES))
	{
		int cube_cost = DEFAULT_AURA_COST;

		self->owner->client->pers.inventory[power_cube_index] -= cube_cost;
	}
	que_addent(self->owner->auras, self, DEFAULT_AURA_DURATION);
	// move aura with owner
	VectorCopy(self->owner->s.origin,self->s.origin);
	self->nextthink = level.time + FRAMETIME;
	if (level.framenum % DEFAULT_AURA_SCAN_FRAMES)
		return;

	radius = 256;

	// scan for targets
	while ((other = findradius (other, self->s.origin, radius)) != NULL)
	{
		slot = NULL;
		if (other == self->owner)
			continue;
		if (!G_EntExists(other))
			continue;
		if (other->health < 1)
			continue;
		if (OnSameTeam(self->owner, other) < 2)
			continue;
		if (!visible(self->owner, other))
			continue;
		slot = que_findtype(other->auras, slot, AURA_SALVATION);
		if (slot && (slot->ent->owner != self->owner))
			continue;
		que_addent(other->auras, self, DEFAULT_AURA_DURATION);
	}
}
Пример #6
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);
}
Пример #7
0
void Cmd_Salvation(edict_t *ent)
{
	que_t		*slot=NULL;
	qboolean	sameaura=false;

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

	if(ent->myskills.abilities[SALVATION].disable)
		return;
	if (!G_CanUseAbilities(ent, ent->myskills.abilities[SALVATION].current_level, 0))
		return;

	// if we already had an aura on, remove it
	if ((slot = que_findtype(ent->auras, slot, AURA_SALVATION)) != NULL)
	{
		// owner is turning off his own aura
		if (slot->ent && slot->ent->owner 
			&& slot->ent->owner->inuse && slot->ent->owner == ent)
		{
			AuraRemove(ent, AURA_SALVATION);
			safe_cprintf(ent, PRINT_HIGH, "Salvation removed.\n");
			return;
		}

		AuraRemove(ent, AURA_SALVATION);
	}

	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/salvation.wav"), 1, ATTN_NORM, 0);
	safe_cprintf(ent, PRINT_HIGH, "Now using salvation aura.\n");
	aura_salvation(ent);
}
Пример #8
0
void	PlaceLaser (edict_t *ent)
{
	edict_t		*laser,
				*grenade;
	edict_t		*blip = NULL;//GHz
	vec3_t		forward,
				wallp,
				start,
				end;
	trace_t		tr;
	trace_t		endTrace;
	int health=0;

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

	health = LASER_INITIAL_HEALTH+LASER_ADDON_HEALTH*ent->myskills.abilities[BUILD_LASER].current_level;

	// valid ent ?
  	if ((!ent->client) || (ent->health<=0))
	   return;

	if ((deathmatch->value) && (level.time < pregame_time->value)) {
		if (ent->client)
			safe_cprintf(ent, PRINT_HIGH, "You cannot use this ability in pre-game!\n");
		return;
	}

	if (Q_strcasecmp (gi.args(), "remove") == 0) {
		RemoveLaserDefense(ent);
		return;
	}

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

	//3.0 amnesia disables lasers
	if (que_findtype(ent->curses, NULL, AMNESIA) != NULL)
		return;

	if (ent->myskills.abilities[BUILD_LASER].current_level < 1)
	{
		safe_cprintf(ent, PRINT_HIGH, "You can't make lasers due to not training in it!\n");
		return;
	}
	// cells for laser ?
	if (ent->client->pers.inventory[power_cube_index] < LASER_COST)
	{
		safe_cprintf(ent, PRINT_HIGH, "Not enough Power Cubes for laser.\n");
		return;
	}

	if (ent->client->ability_delay > level.time) {
		safe_cprintf (ent, PRINT_HIGH, "You can't use abilities for another %2.1f seconds\n", ent->client->ability_delay - level.time);
		return;
	}
	
	ent->client->ability_delay = level.time + DELAY_LASER;

	//gi.dprintf("DEBUG: %s is attempting to place a laser...\n", ent->client->pers.netname);
	
	// GHz: Reached max number allowed ?
	if (ent->num_lasers >= MAX_LASERS) {
		safe_cprintf(ent, PRINT_HIGH, "You have reached the max of %d lasers\n", MAX_LASERS);
		return;
	}

	// Setup "little look" to close wall
	VectorCopy(ent->s.origin,wallp);

	// Cast along view angle
	AngleVectors (ent->client->v_angle, forward, NULL, NULL);

	// Setup end point
	wallp[0]=ent->s.origin[0]+forward[0]*128;
	wallp[1]=ent->s.origin[1]+forward[1]*128;
	wallp[2]=ent->s.origin[2]+forward[2]*128;

	// trace
	tr = gi.trace (ent->s.origin, NULL, NULL, wallp, ent, MASK_SOLID);

	// Line complete ? (ie. no collision)
	if (tr.fraction == 1.0)
	{
		safe_cprintf (ent, PRINT_HIGH, "Too far from wall.\n");
		return;
	}

	// Hit sky ?
	if (tr.surface)
		if (tr.surface->flags & SURF_SKY)
			return;
/*
	while (blip = findradius (blip, ent->s.origin, 64))
	{
		if (!visible(ent, blip))
			continue;

		 if ( (!strcmp(blip->classname, "worldspawn") )
		  || (!strcmp(blip->classname, "info_player_start") )
		  || (!strcmp(blip->classname, "info_player_deathmatch") )
		  || (!strcmp(blip->classname, "item_flagreturn_team1") )
		  || (!strcmp(blip->classname, "item_flagreturn_team2") )
		  || (!strcmp(blip->classname, "misc_teleporter_dest") )
		  || (!strcmp(blip->classname, "info_teleport_destination") ) )
		 {
		  	safe_cprintf (ent, PRINT_HIGH, "Laser is too close to a spawnpoint or flag.\n");
		  	return ;
		 }
	}
*/

	// Ok, lets stick one on then ...
	safe_cprintf (ent, PRINT_HIGH, "Laser attached.\n");
/*
	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
	{
		ent->client->pers.inventory[power_cube_index] -= LASER_COST;
		ent->client->pers.inventory[ITEM_INDEX(FindItem("Lasers"))]--;
	}*/

    // get entities for both objects
	grenade = G_Spawn();
	laser = G_Spawn();

	// setup the Grenade
	VectorClear (grenade->mins);
	VectorClear (grenade->maxs);
    VectorCopy (tr.endpos, grenade->s.origin);
    vectoangles(tr.plane.normal, grenade->s.angles);

	grenade -> movetype		= MOVETYPE_NONE;
	grenade -> clipmask		= MASK_SHOT;
	grenade->solid = SOLID_BBOX;
	VectorSet(grenade->mins, -3, -3, 0);
	VectorSet(grenade->maxs, 3, 3, 6);
	grenade -> takedamage	= DAMAGE_NO;
	grenade -> s.modelindex	= gi.modelindex ("models/objects/grenade2/tris.md2");
    grenade -> owner        = ent;
    grenade -> creator      = laser;
    grenade -> monsterinfo.aiflags = AI_NOSTEP;
	grenade -> classname	= "laser_defense_gr";
	grenade -> nextthink	= level.time + LASER_TIMEUP+GetRandom(0,30);//GetRandom((LASER_TIMEUP/2),(2*LASER_TIMEUP));
	grenade -> think		= laser_cleanup;


	// Now lets find the other end of the laser
    // by starting at the grenade position
    VectorCopy (grenade->s.origin, start);

	// setup laser movedir (projection of laser)
    G_SetMovedir (grenade->s.angles, laser->movedir);

	gi.linkentity (grenade);

    VectorMA (start, 2048, laser->movedir, end);

	endTrace = gi.trace (start, NULL, NULL, end, ent, MASK_SOLID);

	// -----------
	// Setup laser
	// -----------
	laser->movetype		= MOVETYPE_NONE;
	laser->solid			= SOLID_NOT;
	laser->s.renderfx		= RF_BEAM|RF_TRANSLUCENT;
	laser->s.modelindex	= 1;			// must be non-zero
	laser->s.sound		= gi.soundindex ("world/laser.wav");
	laser->classname		= "laser_defense";
	laser->s.frame		= 2 /* ent->myskills.build_lasers*/;	// as it gets higher in levels, the bigger it gets. beam diameter
    laser->owner          = laser;
	laser->s.skinnum		= laser_colour[LASER_DEFENSE_COLOR];
  	laser->dmg			= LASER_INITIAL_DMG+LASER_ADDON_DMG*ent->myskills.abilities[BUILD_LASER].current_level;
    laser->think          = pre_target_laser_def_think;
	//laser->delay			= level.time + LASER_TIMEUP;
	laser->health = health;
	laser->creator		= grenade;
	laser->activator		= ent;

	// start off ...
	target_laser_off (laser);
	VectorCopy (endTrace.endpos, laser->s.old_origin);

	// ... but make automatically come on
	laser -> nextthink = level.time + 2;

	// Set orgin of laser to point of contact with wall
	VectorCopy(endTrace.endpos,laser->s.origin);

	/*
	while (blip = findradius (blip, laser->s.origin, 64))
	{
		if (!visible(laser, blip))
			continue;

		 if ( (!strcmp(blip->classname, "worldspawn") )
		  || (!strcmp(blip->classname, "info_player_start") )
		  || (!strcmp(blip->classname, "info_player_deathmatch") )
		  || (!strcmp(blip->classname, "item_flagreturn_team1") )
		  || (!strcmp(blip->classname, "item_flagreturn_team2") )
		  || (!strcmp(blip->classname, "misc_teleporter_dest") )
		  || (!strcmp(blip->classname, "info_teleport_destination") ) )
		 {
		  	safe_cprintf (ent, PRINT_HIGH, "Laser is too close to a spawnpoint or flag.\nLaser Removed.\n");
			G_FreeEdict(laser);
			G_FreeEdict(grenade);
		  	return ;
		 }
	}
	*/

	// convert normal at point of contact to laser angles
	vectoangles(tr.plane.normal,laser->s.angles);

	// setup laser movedir (projection of laser)
	G_SetMovedir (laser->s.angles, laser->movedir);

	VectorSet (laser->mins, -18, -18, -18);
	VectorSet (laser->maxs, 18, 18, 18);

// link to world
	gi.linkentity (laser);
	ent->num_lasers++; // GHz: add to laser counter

	//If you use this spell, you uncloak!
	ent->svflags &= ~SVF_NOCLIENT;
	ent->client->cloaking = false;
	ent->client->cloakable = 0;

	ent->client->pers.inventory[power_cube_index] -= LASER_COST;
	//gi.dprintf("DEBUG: %s successfully created a laser.\n", ent->client->pers.netname);
}
Пример #9
0
void M_MoveFrame (edict_t *self)
{
	mmove_t	*move;
	int		index;
//	int		frames;
	float	temp;
//	edict_t *curse;
	que_t	*slot=NULL;

	if (!self->inuse)
		return;

	move = self->monsterinfo.currentmove;
	self->nextthink = level.time + FRAMETIME;

	if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) 
		&& (self->monsterinfo.nextframe <= move->lastframe))
	{
		self->s.frame = self->monsterinfo.nextframe;
		self->monsterinfo.nextframe = 0;
	}
	else
	{
		if (self->s.frame == move->lastframe)
		{
			if (move->endfunc)
			{
				move->endfunc (self);

				// regrab move, endfunc is very likely to change it
				move = self->monsterinfo.currentmove;

				// check for death
				if (self->svflags & SVF_DEADMONSTER)
					return;
			}
		}

		if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
		{
			self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
			self->s.frame = move->firstframe;
		}
		else
		{
			if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
			{
				self->s.frame++;
				if (self->s.frame > move->lastframe)
					self->s.frame = move->firstframe;
			}
		}
	}

	index = self->s.frame - move->firstframe;
	if (move->frame[index].aifunc)
		if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
		{
			self->monsterinfo.scale = 1.0;

			//4.5 monster bonus flags
			if (self->monsterinfo.bonus_flags & BF_FANATICAL)
				self->monsterinfo.scale *= 2.0;
			if (self->monsterinfo.bonus_flags & BF_GHOSTLY)
				self->monsterinfo.scale *= 0.5;

			// is this monster slowed by the holyfreeze aura?
			slot = que_findtype(self->curses, slot, AURA_HOLYFREEZE);
			if (slot)
			{
				temp = 1 / (1 + 0.1 * slot->ent->owner->myskills.abilities[HOLY_FREEZE].current_level);
				if (temp < 0.25) temp = 0.25;
				self->monsterinfo.scale *= temp;
			}

			// chill effect slows monster movement rate
			if(self->chill_time > level.time)
				self->monsterinfo.scale *= 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level);

			// 3.5 weaken slows down target
			if ((slot = que_findtype(self->curses, NULL, WEAKEN)) != NULL)
			{
				temp = 1 / (1 + WEAKEN_SLOW_BASE + WEAKEN_SLOW_BONUS 
					* slot->ent->owner->myskills.abilities[WEAKEN].current_level);
				self->monsterinfo.scale *= temp;
			}

			//caltrops
			if (self->slowed_time > level.time)
				self->monsterinfo.scale *= self->slowed_factor;

			move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
		}
		else
		{
			// we're not going anywhere!
			move->frame[index].aifunc (self, 0);
		}

	if (move->frame[index].thinkfunc)
		move->frame[index].thinkfunc (self);
}
Пример #10
0
void holyfreeze_think (edict_t *self)
{
	int		radius;
	edict_t *target=NULL, *curse=NULL;
	que_t	*slot;

	// check status of owner
	if (!CheckAuraOwner(self, DEFAULT_AURA_COST))
	{
	//gi.dprintf("aura removed itself\n");

		que_removeent(self->owner->auras, self, true);
		return;
	}
	
	// owner has an active aura
	que_addent(self->owner->auras, self, DEFAULT_AURA_DURATION);

	// use cubes
	if (!(level.framenum % DEFAULT_AURA_FRAMES))
	{
		int cube_cost = DEFAULT_AURA_COST;

		self->owner->client->pers.inventory[power_cube_index] -= cube_cost;
	}

	// move aura with owner
	VectorCopy(self->owner->s.origin,self->s.origin);
	self->nextthink = level.time + FRAMETIME;
	if (level.framenum % DEFAULT_AURA_SCAN_FRAMES)
		return;

	// scan for targets
	radius = DEFAULT_AURA_MIN_RADIUS+self->owner->myskills.abilities[HOLY_FREEZE].current_level*DEFAULT_AURA_ADDON_RADIUS;
	if (radius > DEFAULT_AURA_MAX_RADIUS)
		radius = DEFAULT_AURA_MAX_RADIUS;

	while ((target = findradius (target, self->s.origin, radius)) != NULL)
	{
		slot = NULL;
		if (target == self->owner)
			continue;
		if (!G_ValidTarget(self->owner, target, true))
			continue;
		// FIXME: make this into a loop search if we plan to allow
		// more than one curse of the same type
		slot = que_findtype(target->curses, slot, AURA_HOLYFREEZE);
		if (slot && (slot->ent->owner != self->owner))
		{
		//	gi.dprintf("already slowed by someone else\n");
			continue; // already slowed by someone else
		}
		if (!slot) // aura doesn't exist in que or timed out
		{
			if (random() > 0.5)
				gi.sound(target, CHAN_ITEM, gi.soundindex("spells/blue1.wav"), 1, ATTN_NORM, 0);
			else
				gi.sound(target, CHAN_ITEM, gi.soundindex("spells/blue3.wav"), 1, ATTN_NORM, 0);
		}
		que_addent(target->curses, self, DEFAULT_AURA_DURATION);
	}
}
Пример #11
0
void minisentry_think (edict_t *self)
{
	float	modifier, temp;
	que_t	*slot=NULL;

	if (!self->owner || !self->owner->inuse)
	{
		minisentry_remove(self);
		return;
	}
	else if (self->removetime > 0)
	{
		qboolean converted=false;

		if (self->flags & FL_CONVERTED)
			converted = true;

		if (level.time > self->removetime)
		{
			// if we were converted, try to convert back to previous owner
			if (converted && self->prev_owner && self->prev_owner->inuse)
			{
				if (!ConvertOwner(self->prev_owner, self, 0, false))
				{
					minisentry_remove(self);
					return;
				}
			}
			else
			{
				minisentry_remove(self);
				return;
			}
		}
		// warn the converted monster's current owner
		else if (converted && self->creator && self->creator->inuse && self->creator->client 
			&& (level.time > self->removetime-5) && !(level.framenum%10))
				safe_cprintf(self->creator, PRINT_HIGH, "%s conversion will expire in %.0f seconds\n", 
					V_GetMonsterName(self), self->removetime-level.time);	
	}

	// sentry is stunned
	if (self->holdtime > level.time)
	{
		M_SetEffects(self);
		self->nextthink = level.time + FRAMETIME;
		return;
	}

	// toggle sentry spotlight
	if (level.daytime && self->flashlight)
		FL_make(self);
	else if (!level.daytime && !self->flashlight)
		FL_make(self);

	// is the sentry slowed by holy freeze?
	temp = self->yaw_speed;
	slot = que_findtype(self->curses, slot, AURA_HOLYFREEZE);
	if (slot)
	{
		modifier = 1 / (1 + 0.1 * slot->ent->owner->myskills.abilities[HOLY_FREEZE].current_level);
		if (modifier < 0.25) modifier = 0.25;
		self->yaw_speed *= modifier;
	}

	// chill effect slows sentry rotation speed
	if(self->chill_time > level.time)
		self->yaw_speed *= 1 / (1 + CHILL_DEFAULT_BASE + CHILL_DEFAULT_ADDON * self->chill_level);

	if (!self->enemy)
	{
		minisentry_regenerate(self);
		if (minisentry_findtarget(self))
			minisentry_attack(self);
		else
			minisentry_idle(self);
	}
	else
	{
		if (G_ValidTarget(self, self->enemy, true) 
			&& (entdist(self, self->enemy)<=SENTRY_ATTACK_RANGE))
		{
			minisentry_attack(self);
		}
		else
		{
			self->enemy = NULL;
			if (minisentry_findtarget(self))
			{
				minisentry_attack(self);
			}
			else
			{
				minisentry_idle(self);
				VectorCopy(self->move_angles, self->s.angles);
			}
		}
	}

	self->yaw_speed = temp; // restore original yaw speed
	M_SetEffects(self);
	self->nextthink = level.time + FRAMETIME;
}
Пример #12
0
void Cmd_Bless(edict_t *ent)
{
	int radius;
	float duration, cooldown;
	edict_t *target = NULL;

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

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

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

	if (!V_CanUseAbilities(ent, BLESS, BLESS_COST, true))
		return;

	radius = SHAMAN_CURSE_RADIUS_BASE + (SHAMAN_CURSE_RADIUS_BONUS * ent->myskills.abilities[BLESS].current_level);
	duration = BLESS_DURATION_BASE + (BLESS_DURATION_BONUS * ent->myskills.abilities[BLESS].current_level);

	//Blessing self?
	if (Q_strcasecmp(gi.argv(1), "self") == 0)
	{
		if (HasFlag(ent))
		{
			gi.cprintf(ent, PRINT_HIGH, "Can't use this while carrying the flag!\n");
			return;
		}

		if (!curse_add(ent, ent, BLESS, 0, duration))
		{
			gi.cprintf(ent, PRINT_HIGH, "Unable to bless self.\n");
			return;
		}
		target = ent;
	}
	else
	{
		target = curse_Attack(ent, BLESS, radius, duration, false);
	}

	if (target != NULL)
	{
		que_t *slot = NULL;

		//Finish casting the spell
		ent->client->ability_delay = level.time + BLESS_DELAY;
		ent->client->pers.inventory[power_cube_index] -= BLESS_COST;

		cooldown = 2.0 * duration;
		if (cooldown > 10.0)
			cooldown = 10.0;

		ent->myskills.abilities[BLESS].delay = level.time + cooldown;

		//Change the curse think to the bless think
		slot = que_findtype(target->curses, NULL, BLESS);
		if (slot)
		{
			slot->ent->think = Bless_think;
			slot->ent->nextthink = level.time + FRAMETIME;
		}

		//Notify the target
		if (target == ent)
		{
			gi.cprintf(target, PRINT_HIGH, "YOU HAVE BEEN BLESSED FOR %0.1f seconds!!\n", duration);
		}
		else if ((target->client) && !(target->svflags & SVF_MONSTER))
		{
			gi.cprintf(target, PRINT_HIGH, "YOU HAVE BEEN BLESSED FOR %0.1f seconds!!\n", duration);
			gi.cprintf(ent, PRINT_HIGH, "Blessed %s for %0.1f seconds.\n", target->myskills.player_name, duration);
		}
		else
		{
			gi.cprintf(ent, PRINT_HIGH, "Blessed %s for %0.1f seconds.\n", target->classname, duration);
		}
		//Play the spell sound!
		gi.sound(target, CHAN_ITEM, gi.soundindex("curses/bless.wav"), 1, ATTN_NORM, 0);
	}
}
Пример #13
0
void Cmd_Healing(edict_t *ent)
{
	int radius;
	float duration;
	edict_t *target = NULL;

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

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

	if (!G_CanUseAbilities(ent, ent->myskills.abilities[HEALING].current_level, HEALING_COST))
		return;

	radius = SHAMAN_CURSE_RADIUS_BASE + (SHAMAN_CURSE_RADIUS_BONUS * ent->myskills.abilities[HEALING].current_level);
	duration = HEALING_DURATION_BASE + (HEALING_DURATION_BONUS * ent->myskills.abilities[HEALING].current_level);

	//Blessing self?
	if (Q_strcasecmp(gi.argv(1), "self") == 0)
	{
		if (!curse_add(ent, ent, HEALING, 0, duration))
		{
			gi.cprintf(ent, PRINT_HIGH, "Unable to bless self.\n");
			return;
		}
		target = ent;
	}
	else
	{
		target = curse_Attack(ent, HEALING, radius, duration, false);
	}
	if (target != NULL)
	{
		que_t *slot = NULL;
		//Finish casting the spell
		ent->client->ability_delay = level.time + HEALING_DELAY;
		ent->client->pers.inventory[power_cube_index] -= HEALING_COST;

		//Change the curse think to the healing think
		slot = que_findtype(target->curses, NULL, HEALING);
		if (slot)
		{
			slot->ent->think = Healing_think;
			slot->ent->nextthink = level.time + FRAMETIME;
		}

		//Notify the target
		if (target == ent)
		{
			gi.cprintf(target, PRINT_HIGH, "YOU HAVE BEEN BLESSED WITH %0.1f seconds OF HEALING!!\n", duration);
		}
		else if ((target->client) && !(target->svflags & SVF_MONSTER))
		{
			gi.cprintf(target, PRINT_HIGH, "YOU HAVE BEEN BLESSED WITH %0.1f seconds OF HEALING!!\n", duration);
			gi.cprintf(ent, PRINT_HIGH, "Blessed %s with healing for %0.1f seconds.\n", target->myskills.player_name, duration);
		}
		else
		{
			gi.cprintf(ent, PRINT_HIGH, "Blessed %s with healing for %0.1f seconds.\n", target->classname, duration);
		}
		//Play the spell sound!
		gi.sound(target, CHAN_ITEM, gi.soundindex("curses/prayer.wav"), 1, ATTN_NORM, 0);
	}
}
Пример #14
0
void Healing_think(edict_t *self)
{
	//Find my slot
	que_t *slot = NULL;	
	int heal_amount = HEALING_HEAL_BASE + HEALING_HEAL_BONUS * self->owner->myskills.abilities[HEALING].current_level;
	float cooldown = 1.0;

	slot = que_findtype(self->enemy->curses, NULL, HEALING);

	// Blessing self-terminates if the enemy dies or the duration expires
	if (!slot || !que_valident(slot))
	{
		que_removeent(self->enemy->curses, self, true);
		return;
	}

	//Stick with the target
	VectorCopy(self->enemy->s.origin, self->s.origin);
	gi.linkentity(self);

	//Next think time
	self->nextthink = level.time + cooldown;

	//Heal the target's armor
	if (!self->enemy->client)
	{
		//Check to make sure it's a monster
		if (!self->enemy->mtype)
			return;
		
		heal_amount = self->enemy->max_health * (0.01 * self->owner->myskills.abilities[HEALING].current_level); // 1% healed per level
		
		if (heal_amount > 100)
			heal_amount = 100;

		//Heal the momster's health
		self->enemy->health += heal_amount;
		if (self->enemy->health > self->enemy->max_health)
			self->enemy->health = self->enemy->max_health;

		if (self->enemy->monsterinfo.power_armor_type)
		{
			heal_amount = self->enemy->monsterinfo.power_armor_power * (0.01 * self->owner->myskills.abilities[HEALING].current_level); // 1% healed per level
			
			if (heal_amount > 100)
				heal_amount = 100;

			//Heal the monster's armor
			self->enemy->monsterinfo.power_armor_power += heal_amount;
			if (self->enemy->monsterinfo.power_armor_power > self->enemy->monsterinfo.max_armor)
				self->enemy->monsterinfo.power_armor_power = self->enemy->monsterinfo.max_armor;
		}
	}
	else
	{
		if (self->enemy->health < MAX_HEALTH(self->enemy))
		{
			//Heal health
			self->enemy->health += heal_amount;
			if (self->enemy->health > MAX_HEALTH(self->enemy))
				self->enemy->health = MAX_HEALTH(self->enemy);
		}

		if (self->enemy->client->pers.inventory[body_armor_index] < MAX_ARMOR(self->enemy))
		{
			//Heal armor
			heal_amount *= 0.5; // don't heal as much armor
			if (heal_amount < 1)
				heal_amount = 1;
			self->enemy->client->pers.inventory[body_armor_index] += heal_amount;
			if (self->enemy->client->pers.inventory[body_armor_index] > MAX_ARMOR(self->enemy))
				self->enemy->client->pers.inventory[body_armor_index] = MAX_ARMOR(self->enemy);
		}
	}
}
Пример #15
0
qboolean curse_add(edict_t *target, edict_t *caster, int type, int curse_level, float duration)
{
	edict_t *curse;
	que_t	*slot = NULL;
	
	//Find out if this curse already exists
	slot = que_findtype(target->curses, NULL, type);
	if(slot != NULL)
	{
		//If the current curse in effect has a level greater than the caster's curse level
		//if (slot->ent->owner->myskills.abilities[type].current_level > caster->myskills.abilities[type].current_level)
		if (slot->ent->monsterinfo.level > curse_level)//4.4
			//Can't re-curse this player
			return false;
		else
		{
            //Refresh the curse with the new level/ent/duration
			return que_addent(target->curses, slot->ent, duration);
		}
	}

	/*
	//Talent: Evil curse (improves curse duration)
	talentLevel = getTalentLevel(caster, TALENT_EVIL_CURSE);
	if(talentLevel > 0)
	{
		//Curses only
		if(type != BLESS && type != HEALING)
			duration *= 1.0 + 0.25 * talentLevel;
	}
	*/

	//Create the curse entity
	curse=G_Spawn();
	curse->classname = "curse";
	curse->solid = SOLID_NOT;
	curse->svflags |= SVF_NOCLIENT;
	curse->monsterinfo.level = curse_level;//4.2
	curse->monsterinfo.selected_time = duration;//4.2
	VectorClear(curse->velocity);
	VectorClear(curse->mins);
	VectorClear(curse->maxs);

	//Set curse type, target, and caster
	curse->owner = caster;
	curse->enemy = target;
	curse->atype = type;

	//First think in 1/2 a second
	curse->nextthink = level.time + FRAMETIME;
	curse->think = curse_think;

	//Set origin to target's origin
	VectorCopy(target->s.origin, curse->s.origin);
	gi.linkentity(curse);

	//Try to add the curse to the que
	if (!que_addent(target->curses, curse, duration))
	{
		G_FreeEdict(curse);
		return false;
	}
	return true;
}
Пример #16
0
void ApplyThrust (edict_t *ent)
{
	int talentLevel, cost = JETPACK_AMMO;
    vec3_t forward, right;
    vec3_t pack_pos, jet_vector;

	if(ent->myskills.abilities[JETPACK].disable && level.time > pregame_time->value)
		return;

	//Talent: Flight
	if ((talentLevel = getTalentLevel(ent, TALENT_FLIGHT)) > 0)
	{
		int num;
		
		num = 0.4 * talentLevel;
		if (num < 1)
			num = 1;
		cost -= num;
	}

	//4.0 better jetpack check.
	if ((level.time > pregame_time->value) && !trading->value)  // allow jetpack in pregame and trading
		if (!G_CanUseAbilities (ent, ent->myskills.abilities[JETPACK].current_level, cost) )
			return;
	//can't use abilities (spawning sentry gun/drone/etc...)
	if (ent->holdtime > level.time)
		return;
	//4.07 can't use jetpack while being hurt
	if (ent->lasthurt+DAMAGE_ESCAPE_DELAY > level.time)
		return;
	//amnesia disables jetpack
	if (que_findtype(ent->curses, NULL, AMNESIA) != NULL)
		return;

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

	if (ent->client->snipertime >= level.time)
	{
		safe_cprintf(ent, PRINT_HIGH, "You can't use jetpack while trying to snipe!\n");
		return;
	}

	if (ent->client->pers.inventory[power_cube_index] >= cost || level.time < pregame_time->value) // pregame.
	{
		ent->client->thrustdrain ++;
		if (ent->client->thrustdrain == JETPACK_DRAIN)
		{
			if (level.time > pregame_time->value) // not pregame
				ent->client->pers.inventory[power_cube_index] -= cost;
			ent->client->thrustdrain = 0;
		}
	}
	else
	{
		ent->client->thrusting=0;
		return;
	}

	if (ent->velocity[2] < 350)
	{
		if (ent->groundentity)
			ent->velocity[2] = 150;
		ent->velocity[2] += 150;
	}

    AngleVectors(ent->client->v_angle, forward, right, NULL);
    VectorScale (forward, -7, pack_pos);
    VectorAdd (pack_pos, ent->s.origin, pack_pos);
    pack_pos[2] += (ent->viewheight);

    VectorScale (forward, -50, jet_vector);

    if (ent->client->next_thrust_sound < level.time)
    {
		// wow this check is stupid.
		/*if (ent->client) */
            gi.sound (ent, CHAN_BODY, gi.soundindex("weapons/rockfly.wav"), 1, ATTN_NORM, 0);
            ent->client->next_thrust_sound=level.time+1.0;
    }

	ent->lastsound = level.framenum;
}
Пример #17
0
void Cmd_Deflect_f(edict_t *ent)
{
	float duration;
	edict_t *target = ent; // default target is self

	if (!V_CanUseAbilities(ent, DEFLECT, DEFLECT_COST, true))
		return;

	duration = DEFLECT_INITIAL_DURATION + DEFLECT_ADDON_DURATION * ent->myskills.abilities[DEFLECT].current_level;

	// bless the tank instead of the noclipped player
	if (PM_PlayerHasMonster(ent))
		target = target->owner;

	//Blessing self?
	if (Q_strcasecmp(gi.argv(1), "self") == 0)
	{
		if (!curse_add(target, ent, DEFLECT, 0, duration))
		{
			gi.cprintf(ent, PRINT_HIGH, "Unable to bless self.\n");
			return;
		}
		//target = ent;
	}
	else
	{
		target = curse_Attack(ent, DEFLECT, 512.0, duration, false);
	}

	if (target != NULL)
	{
		que_t *slot = NULL;

		//Finish casting the spell
		ent->client->ability_delay = level.time + DEFLECT_DELAY;
		ent->client->pers.inventory[power_cube_index] -= DEFLECT_COST;
	//	ent->myskills.abilities[DEFLECT].delay = level.time + duration + DEFLECT_DELAY;

		//Change the curse think to the deflect think
		slot = que_findtype(target->curses, NULL, DEFLECT);
		if (slot)
		{
			slot->ent->think = deflect_think;
			slot->ent->nextthink = level.time + FRAMETIME;
			slot->ent->random = DEFLECT_INITIAL_PROJECTILE_CHANCE+DEFLECT_ADDON_HITSCAN_CHANCE*ent->myskills.abilities[DEFLECT].current_level;
			if (slot->ent->random > DEFLECT_MAX_PROJECTILE_CHANCE)
				slot->ent->random = DEFLECT_MAX_PROJECTILE_CHANCE;
		}

		//Notify the target
		if (target == ent)
		{
			gi.cprintf(target, PRINT_HIGH, "You have been blessed with deflect for %0.1f seconds!\n", duration);
		}
		else if ((target->client) && !(target->svflags & SVF_MONSTER))
		{
			gi.cprintf(target, PRINT_HIGH, "You have been blessed with deflect for %0.1f seconds!\n\n", duration);
			gi.cprintf(ent, PRINT_HIGH, "Blessed %s with deflect for %0.1f seconds.\n", target->myskills.player_name, duration);
		}
		else
		{
			gi.cprintf(ent, PRINT_HIGH, "Blessed %s with deflect for %0.1f seconds.\n", V_GetMonsterName(target), duration);
		}

		//Play the spell sound!
		gi.sound(target, CHAN_ITEM, gi.soundindex("curses/prayer.wav"), 1, ATTN_NORM, 0);
	}
}