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

}
Пример #3
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
}
Пример #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 bombperson_think (edict_t *self)
{
	int		height, max_height;
	float	bombtime, thinktime;
	vec3_t	start;
	trace_t	tr;

	// calculate drop rate
	bombtime = self->delay - 8; // max rate achieved 2 seconds after casting
	if (bombtime < level.time)
		bombtime = level.time;
	thinktime = level.time + 0.25 * ((bombtime + 1) - level.time); // max 1 bomb per 0.25 seconds

	// bomb self-terminates if the enemy dies or owner teleports away
	if (!G_EntIsAlive(self->owner) || !G_EntIsAlive(self->enemy)
		|| (level.time > self->delay)
		|| (self->owner->client->tball_delay > level.time))
	{
		//RemoveCurse(self->enemy, self);
		que_removeent(self->enemy->curses, self, true);
		return;
	}

	VectorCopy(self->enemy->s.origin, self->s.origin);
//	gi.linkentity(self);
	/*
	// if the caster can't see his target, then pause the spell
	if (!visible(self->orb, self->owner))
	{
		self->nextthink = thinktime;
		return;
	}
	*/
	// get random drop height
	max_height = 250 - (20 * self->owner->myskills.abilities[BOMB_SPELL].current_level);
	if (max_height < 150)
		max_height = 150;
	height = GetRandom(50, max_height) + self->enemy->maxs[2];
	// drop bombs above target
    VectorCopy(self->s.origin, start);
	start[2] += height;
    tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self->owner, MASK_SHOT);
	VectorCopy(tr.endpos, start);
	start[2]--;
	// spread randomly around target
	start[0] += (BOMBPERSON_WIDTH/2)*crandom();
	start[1] += (BOMBPERSON_WIDTH/2)*crandom();
	spawn_grenades(self->owner, start, (0.5+2*random()), self->dmg, 1);
	self->nextthink = thinktime;
}
Пример #6
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);
	}
}
Пример #7
0
void LifeDrain (edict_t *curse)
{
	int		take;
	edict_t *caster=curse->owner;

	if (curse->atype != LIFE_DRAIN)
		return;

	if (level.time < curse->wait)
		return;

	if (!G_ValidTarget(caster, curse->enemy, false))
	{
		// remove the curse if the target dies
		que_removeent(curse->enemy->curses, curse, true);
		return;
	}

	take = LIFE_DRAIN_HEALTH;
	// more effective on non-clients (because they have more health)
	if (!curse->enemy->client)
		take *= 2;

	// give caster health
	if (caster->health < caster->max_health)
	{
		caster->health += take;
		if (caster->health > caster->max_health)
			caster->health = caster->max_health;
	}

	// take it away from curse's target
	T_Damage(curse->enemy, caster, caster, vec3_origin, vec3_origin, 
		vec3_origin, take, 0, DAMAGE_NO_ABILITIES, MOD_LIFE_DRAIN);

	curse->wait = level.time + LIFE_DRAIN_UPDATETIME;
}
Пример #8
0
void Bleed (edict_t *curse)
{
	int		take;
	edict_t *caster=curse->owner;

	if (curse->atype != BLEEDING)
		return;

	if (level.time < curse->wait)
		return;

	if (!G_ValidTarget(caster, curse->enemy, false))
	{
		// remove the curse if the target dies
		que_removeent(curse->enemy->curses, curse, true);
		return;
	}

	// 33-99% health taken over duration of curse
	take = (curse->enemy->max_health * (0.033 * curse->monsterinfo.level)) / curse->monsterinfo.selected_time;

	//gi.dprintf("target %s take %d health %d/%d level %d time %.1f\n", 
	//	curse->enemy->classname, take, curse->enemy->health, curse->enemy->max_health,
	//	curse->monsterinfo.level, curse->monsterinfo.selected_time);

	// damage limits
	if (take < 1)
		take = 1;
	if (take > 100)
		take = 100;

	T_Damage(curse->enemy, caster, caster, vec3_origin, vec3_origin, 
		vec3_origin, take, 0, DAMAGE_NO_ABILITIES, MOD_LIFE_DRAIN);

	curse->wait = level.time + (GetRandom(3, 10) * FRAMETIME);
}
Пример #9
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);
	}
}
Пример #10
0
void fire_think (edict_t *self)
{
	edict_t *ed=NULL;
	qboolean quench = false;
	int i;
	int damage;

	// fire self-terminates if
	if (!G_EntIsAlive(self->enemy)
		|| !G_EntIsAlive(self->owner)//owner dies
		|| (level.time > self->delay))	// enemy dies								//duration expires
		//|| que_findtype(self->enemy->curses, NULL, HEALING) != NULL)	//3.0 when player is blessed with healing
	{
		que_removeent(self->enemy->curses, self, true);
		return;
	}

	//3.0 quench the flames if the player is in possesion of a flame stopping item
	if (!(self->enemy->waterlevel || self->waterlevel))
	{
		for (i = 3; i < MAX_VRXITEMS; ++i)
		{
			if (self->enemy->myskills.items[i].itemtype & ITEM_FIRE_RESIST)
			{
				quench = true;
				break;
			}
		}
	}

	if (self->enemy->waterlevel || self->waterlevel || quench)
	{
		//if item and not water stopped the fire
		if (quench)
		{
			//Consume an item charge
			if (!(self->enemy->myskills.items[i].itemtype & ITEM_UNIQUE))
				self->enemy->myskills.items[i].quantity -= 1;
			if(self->enemy->myskills.items[i].quantity == 0)
			{
				int count = 0;
				gi.cprintf(self->enemy, PRINT_HIGH, "Your burn resistant clothing has been destroyed!\n");
				//erase the item
				V_ItemClear(&self->enemy->myskills.items[i]);
				//Tell the user if they have any left
				for (i = 3; i < MAX_VRXITEMS; ++i)
					if (self->enemy->myskills.items[i].itemtype & ITEM_FIRE_RESIST)
						count++;
				if (count) gi.cprintf(self->enemy, PRINT_HIGH, "You have %d left.\n", count);
			}
		}
		//water did it, so play a hissing dound
		else gi.sound (self->enemy, CHAN_WEAPON, gi.soundindex ("world/airhiss1.wav"), 1, ATTN_NORM, 0);

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

	damage = self->dmg;	

	VectorCopy(self->enemy->s.origin,self->s.origin);
	if (self->PlasmaDelay < level.time)
	{
		T_Damage (self->enemy, self, self->owner, vec3_origin, self->enemy->s.origin, 
			vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_BURN);
		self->PlasmaDelay = level.time + 1;
	}
	self->nextthink = level.time + FRAMETIME;
}
Пример #11
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);
		}
	}
}