示例#1
0
void depot_give_inventory (edict_t *self, edict_t *other)
{
	int result = 0;

	if ((self->sentrydelay > level.time) || !G_EntIsAlive(self) || !G_EntIsAlive(other) || !other->client || OnSameTeam(self, other) < 2)
		return;

	result += depot_give_item(self, other, body_armor_index);
	result += depot_give_item(self, other, bullet_index);
	result += depot_give_item(self, other, cell_index);
	result += depot_give_item(self, other, shell_index);
	result += depot_give_item(self, other, grenade_index);
	result += depot_give_item(self, other, rocket_index);
	result += depot_give_item(self, other, slug_index);

	safe_cprintf(other, PRINT_HIGH, "Depot has %d armor, %d bullets, %d cells, %d shells, %d grenades, %d rockets, %d slugs\n", 
		self->packitems[body_armor_index], self->packitems[bullet_index], self->packitems[cell_index], 
		self->packitems[shell_index], self->packitems[grenade_index], self->packitems[rocket_index], 
		self->packitems[slug_index]);

	// delay before depot can be used again
	self->sentrydelay = level.time + 2.0;

	if (result > 0)
		gi.sound(self, CHAN_ITEM, gi.soundindex("misc/w_pkup.wav"), 1, ATTN_STATIC, 0);
}
示例#2
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;

}
示例#3
0
文件: bombspell.c 项目: zardoru/vrxcl
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;
}
示例#4
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;
}
示例#5
0
文件: pvb.c 项目: zardoru/vrxcl
void CreateBoss (edict_t *ent)
{
	edict_t *boss;
	//gi.dprintf("DEBUG: Waiting for player to become valid...\n");
	
	boss = Boss_CreateTank(); // create the boss entity

	// ready the player and boss if the player is alive and there
	// is enough room to spawn the boss
	if (G_EntIsAlive(ent) 
		&& Boss_CanFit(ent, boss->mins, boss->maxs))
	{
		Boss_ReadyPlayer(ent, boss);
		SelectedBossPlayer = NULL; // reset pointer so someone else can have a turn
	}
	else
	{
		if (level.time > boss_timeout)
			SelectedBossPlayer = NULL;
	//	gi.dprintf("Waiting for the player to be valid...\n");
		// remove the boss entity
		G_FreeEdict(boss);
		return;
	}
}
示例#6
0
void CurseEffects (edict_t *self, int num, int color)
{
	vec3_t start, up, angle;

	if ((level.framenum % 5) != 0)
		return;
	if (!G_EntIsAlive(self))
		return;

	VectorCopy(self->s.angles, angle);
	angle[ROLL] = GetRandom(0, 20) - 10;
	angle[PITCH] = GetRandom(0, 20) - 10;
	AngleCheck(&angle[ROLL]);
	AngleCheck(&angle[PITCH]);

	AngleVectors(angle, NULL, NULL, up);

	// upside-down minisentry
	if (self->owner && (self->mtype == M_MINISENTRY) 
		&& (self->owner->style == SENTRY_FLIPPED))
		VectorMA(self->s.origin, self->mins[2]-16, up, start);
	else
		VectorMA(self->s.origin, self->maxs[2]+16, up, start);

	gi.WriteByte(svc_temp_entity);
	gi.WriteByte(TE_LASER_SPARKS);
	gi.WriteByte(num); // number of sparks
	gi.WritePosition(start);
	gi.WriteDir(up);
	gi.WriteByte(color); // 242 = red, 210 = green, 2 = black
	gi.multicast(start, MULTICAST_PVS);
}
示例#7
0
void forcewall_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	V_Touch(self, other, plane, surf);

	// let teammates pass thru
	if (/*(other != self->activator) &&*/ G_EntIsAlive(other)) 
	{
		
		if (OnSameTeam(self->activator, other) && (other->movetype == MOVETYPE_STEP || other->movetype == MOVETYPE_WALK))
		{
			//gi.dprintf("%s touching %d \n",other->classname, other->movetype);
			self->solid = SOLID_NOT;
			self->wait = level.time + 0.2; // small buffer so monsters can get thru
		}
		else if (level.time > self->random)
		{
			// dont allow solid force wall to trap people
			if (level.framenum == self->count-900)
			{
				G_FreeEdict(self);
				return;
			}
			forcewall_knockback(self, other); // knock them back
			gi.sound(other, CHAN_ITEM, gi.soundindex("world/force2.wav"), 1, ATTN_NORM, 0);
			self->random = level.time + 0.5; // dont spam the sound
		}
	}
}
示例#8
0
qboolean que_valident (que_t *que)
{
	// 3.5 aura/curse is no longer valid if the owner dies
	return (que->ent && que->ent->inuse && (que->time > level.time)
		&& G_EntIsAlive(que->ent->owner));
	/*
	return (que->ent && que->ent->inuse && que->ent->owner 
		&& que->ent->owner->inuse && (que->time > level.time));
	*/
}
示例#9
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);
}
示例#10
0
void mybrain_jumpattack_landing (edict_t *self)
{
	// expand the bbox again, we're standing up
	self->maxs[2] = 32;
	self->takedamage = DAMAGE_AIM;
	gi.linkentity (self);

	// attack right away if enemy is valid, visible, infront, and is moving
	if (G_EntIsAlive(self->enemy) && visible(self, self->enemy) 
		&& infront(self, self->enemy) && self->enemy->movetype)
		mybrain_attack3(self);
}
示例#11
0
void depot_think (edict_t *self)
{
	if (!G_EntIsAlive(self->creator))
	{
		depot_remove(self, NULL, false);
		return;
	}

	depot_effects(self);
	depot_add_inventory(self, qf2sf(100));

	self->nextthink = level.time + FRAMETIME;
}
示例#12
0
// returns true if there is a nearby, visible player boss
qboolean findNearbyBoss (edict_t *self)
{
	edict_t *other=NULL;

	while ((other = findradius(other, self->s.origin, BOSS_ALLY_BONUS_RANGE)) != NULL)
	{
		if (!IsABoss(other))
			continue;
		if (!G_EntIsAlive(other))
			continue;
		return true;
	}
	return false;
}
示例#13
0
void mybrain_jump_hold (edict_t *self)
{
	vec3_t	v;

	if (G_EntIsAlive(self->monsterinfo.attacker))
	{
		// face the attacker
		VectorSubtract(self->monsterinfo.attacker->s.origin, self->s.origin, v);
		self->ideal_yaw = vectoyaw(v);
		M_ChangeYaw(self);
	}

	// check for landing or jump timeout
	if (self->waterlevel || self->groundentity || (level.time > self->monsterinfo.pausetime))
		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
	else
		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
示例#14
0
void laser_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	//gi.dprintf("laser_touch\n");
	//gi.dprintf("%s %s %s\n", OnSameTeam(ent, other)?"y":"n", ent->health<ent->max_health?"y":"n", level.framenum>ent->monsterinfo.regen_delay1?"y":"n");

	if (G_EntIsAlive(other) && other->client && OnSameTeam(ent, other) // a player on our team
		&& other->client->pers.inventory[power_cube_index] >= 5 // has power cubes
		&& ent->creator->health < 0.5*ent->creator->max_health // only repair below 50% health (to prevent excessive cube use/repair noise)
		&& level.framenum > ent->creator->monsterinfo.regen_delay1) // check delay
	{
		ent->creator->health = ent->creator->max_health;
		other->client->pers.inventory[power_cube_index] -= 5;
		ent->creator->monsterinfo.regen_delay1 = level.framenum + 20;
		gi.sound(other, CHAN_VOICE, gi.soundindex("weapons/repair.wav"), 1, ATTN_NORM, 0);
		gi.cprintf(other, PRINT_HIGH, "Emitter repaired. Maximum output: %d/%d damage.\n", ent->creator->health, ent->creator->max_health);
	}

}
示例#15
0
void mymedic_heal (edict_t *self)
{
	// stop healing our target died, if they are fully healed, or
	// they have gone out of range while we are standing ground (can't reach them)
	if (!G_EntIsAlive(self->enemy) || !M_NeedRegen(self->enemy)
		|| ((self->monsterinfo.aiflags & AI_STAND_GROUND) 
		&& (entdist(self, self->enemy) > 256)))
	{
		self->enemy = NULL;
		mymedic_stand(self);
		return;
	}

	// continue healing if our target is still in range and
	// there are no enemies around
	if (OnSameTeam(self, self->enemy) && (entdist(self, self->enemy) <= 256)
		&& !mymedic_findenemy(self))
		self->monsterinfo.currentmove = &mymedic_move_attackCable;
	else
		mymedic_run(self);
}
示例#16
0
void mymedic_dodge (edict_t *self, edict_t *attacker, vec3_t dir, int radius)
{
	if (random() > 0.9)
		return;
	if (level.time < self->monsterinfo.dodge_time)
		return;
	if (OnSameTeam(self, attacker))
		return;

	if (!self->enemy && G_EntIsAlive(attacker))
		self->enemy = attacker;
	if (!radius)
	{
		self->monsterinfo.currentmove = &mymedic_move_duck;
		self->monsterinfo.dodge_time = level.time + 2.0;
	}
	else
	{
		mymedic_leap(self);
		self->monsterinfo.dodge_time = level.time + 3.0;
	}
}
示例#17
0
文件: bombspell.c 项目: zardoru/vrxcl
void bombarea_think (edict_t *self)
{
	float	thinktime, bombtime;
	vec3_t	start;
	trace_t	tr;

	if (!G_EntIsAlive(self->owner) || (level.time>self->delay))
	{
		G_FreeEdict(self);
		return;
	}
	VectorCopy(self->s.origin, start);

	thinktime = 0.2 * ((self->delay-6)-level.time);
	if (thinktime < 0.2)
		thinktime = 0.2;
	// if the caster can't see his target, then pause the spell
	/*
	if (!visible(self, self->owner))
	{
		self->nextthink = thinktime;
		return;
	}
	*/

	// spread randomly around target
	start[0] += GetRandom(0, BOMBAREA_WIDTH/2)*crandom();
	start[1] += GetRandom(0, BOMBAREA_WIDTH/2)*crandom();	
	tr = gi.trace(self->s.origin, NULL, NULL, start, self, MASK_SHOT);
	if (self->s.angles[PITCH] == 90)
		bombtime = 1 + 2*random();
	else
		bombtime = 0.5 + 2*random();
	spawn_grenades(self->owner, tr.endpos, bombtime, self->dmg, 1);
	self->nextthink = level.time + thinktime;
}
示例#18
0
void mybrain_jumpattack_hold (edict_t *self)
{
	int value=0;

	// we are on ground
	if (self->groundentity)
		value = 1;
	// we are in the water or passed jump timeout value
	else if (self->waterlevel || level.time > self->monsterinfo.pausetime)
		value = 2;

	// discontinue holding this frame
	if (value)
	{
		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;

		if (value == 1)
			gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
	}
	
	else
	{
		vec3_t v;

		// hold this frame
		self->monsterinfo.aiflags |= AI_HOLD_FRAME;

		// face the enemy if he's alive and visible
		if (G_EntIsAlive(self->enemy) && visible(self, self->enemy))
		{
			VectorSubtract(self->enemy->s.origin, self->s.origin, v);
			self->ideal_yaw = vectoyaw(v);
			M_ChangeYaw(self);
		}
	}
}
示例#19
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;
}
示例#20
0
void totem_general_think(edict_t *self)
{
	edict_t *caster = self->activator;

	// Die if caster is not alive, or is not a valid ent
	if (!caster || !caster->client || !G_EntIsAlive(caster) || caster->flags & FL_CHATPROTECT)
	{
		RemoveTotem(self);
		return;
	}

	//Some players can have two totems out (with talent). Take cubes away from them every 5 seconds.
	if(level.framenum % 50 == 0 && caster->client && caster->totem2 == self)
	{
		int *cubes = &caster->client->pers.inventory[ITEM_INDEX(Fdi_POWERCUBE)];

		//Talent: Totemic Focus.
		int cost = 10;//30 - getTalentLevel(caster, TALENT_TOTEM) * 5;
        if(*cubes < cost)
		{
			*cubes = 0;
			RemoveTotem(self);
			return;
		}
		*cubes -= cost;
	}

	if(self->delay < level.time)
	{
		switch(self->mtype)
		{
		case TOTEM_FIRE:			FireTotem_think(self, caster);			break;
		case TOTEM_WATER:			WaterTotem_think(self, caster);			break;
		case TOTEM_NATURE:			NatureTotem_think(self, caster);		break;
		default:					break;
		}
	}
	
	// totem mastery allows regeneration
	if (level.time > self->lasthurt + 1.0 && !caster->myskills.abilities[TOTEM_MASTERY].disable 
		&& caster->myskills.abilities[TOTEM_MASTERY].current_level > 0)
		M_Regenerate(self, TOTEM_REGEN_FRAMES, TOTEM_REGEN_DELAY, 1.0, true, false, false, &self->monsterinfo.regen_delay1);

	//Rotate a little.
	self->s.angles[YAW] += 5;
	if(self->s.angles[YAW] == 360)
		self->s.angles[YAW] = 0;
//GHz 4.32
	// if position has been updated, check for ground entity
	if (self->linkcount != self->monsterinfo.linkcount)
	{
		self->monsterinfo.linkcount = self->linkcount;
		M_CheckGround (self);
	}

	// don't slide
	if (self->groundentity)
		VectorClear(self->velocity);
	
	M_CatagorizePosition (self);
	M_WorldEffects (self);
//GHz
	totem_effects(self);

	self->nextthink = level.time + FRAMETIME;
}
示例#21
0
void forcewall_think(edict_t *self)
{
	int		dmg;
	vec3_t	zvec={0,0,0};
	trace_t	tr;

	CTF_SummonableCheck(self);

	// wall will auto-remove if it is asked to
	if ((self->removetime > 0) && (level.time > self->removetime))
	{
		if (self->activator && self->activator->inuse)
			safe_cprintf(self->activator, PRINT_HIGH, "Your wall was removed from enemy territory.\n");
		self->think = BecomeTE;
		self->nextthink = level.time + FRAMETIME;
		return;
	}

	// wall must have an owner
	if (!G_EntIsAlive(self->activator) || (level.framenum > self->count))
	{
		if (G_EntExists(self->activator))
			safe_cprintf(self->activator, PRINT_HIGH, "Your wall faded away.\n");
		BecomeTE(self);
		return;
	}
	
	forcewall_seteffects(self);

	// is this a solid wall?
	if (self->takedamage)
	{
		forcewall_regenerate(self);
		tr = gi.trace (self->s.origin, self->mins, self->maxs, self->s.origin, self, (MASK_PLAYERSOLID|MASK_MONSTERSOLID));
		// reset solid state if nobody is in the wall
		if ((self->solid == SOLID_NOT) && !G_EntIsAlive(tr.ent) && (level.time > self->wait))
			self->solid = SOLID_BBOX;
	}
	else
	{

		// find something to burn
		tr = gi.trace (self->s.origin, self->mins, self->maxs, self->s.origin, self, (MASK_PLAYERSOLID|MASK_MONSTERSOLID));
		if (G_EntExists(tr.ent) && !OnSameTeam(self, tr.ent))
		{
			if (tr.ent->client && (tr.ent->client->respawn_time == level.time))
			{
				safe_cprintf(self->activator, PRINT_HIGH, "Your wall faded away because it was too close to a spawnpoint!\n");
				BecomeTE(self);
				return;
			}

			dmg = 10 + 4*self->activator->myskills.abilities[FORCE_WALL].current_level;
			burn_person(tr.ent, self->activator, dmg);
			T_Damage (tr.ent, self, self->activator, zvec, tr.ent->s.origin, NULL, dmg, 1, DAMAGE_ENERGY, MOD_BURN);
			
			// wall can only deal so much damage before self-destructing
			self->health -= dmg;
			if (self->health < 0)
			{
				safe_cprintf(self->activator, PRINT_HIGH, "Your wall has expired.\n");
				self->think = BecomeTE;
				self->nextthink = level.time + FRAMETIME;
				return;
			}
			
		}
		//gi.dprintf("found %s\n", tr.ent->classname);
	}

	if (self->delay-10 == level.time)
		safe_cprintf(self->activator, PRINT_HIGH, "Your wall will time-out in 10 seconds.\n");

	self->nextthink = level.time + FRAMETIME;
}
示例#22
0
// modified SV_movestep for use with player-controlled monsters
qboolean M_Move (edict_t *ent, vec3_t move, qboolean relink)
{
	vec3_t		oldorg, neworg, end;
	trace_t		trace;//, tr;
	float		stepsize=STEPSIZE;

// try the move	
	VectorCopy (ent->s.origin, oldorg);
	VectorAdd (ent->s.origin, move, neworg);

	neworg[2] += stepsize;
	VectorCopy (neworg, end);
	end[2] -= stepsize*2;

	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);

	if (trace.allsolid)
	{
		// if we would have collided with a live entity, call its touch function
		// this prevents player-monsters from being invulnerable to obstacles
		if (G_EntIsAlive(trace.ent) && trace.ent->touch)
			trace.ent->touch(trace.ent, ent, &trace.plane, trace.surface);
		return false;
	}

	if (trace.startsolid)
	{
		neworg[2] -= stepsize;
		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
		if (trace.allsolid || trace.startsolid)
			return false;
	}

	if (trace.fraction == 1)
	{
	//	gi.dprintf("going to fall\n");
	// if monster had the ground pulled out, go ahead and fall
	//	VectorSubtract(trace.endpos, oldorg, forward);
	//	VectorMA(oldorg, 64, forward, end);
	
		if ( ent->flags & FL_PARTIALGROUND )
		{
			VectorAdd (ent->s.origin, move, ent->s.origin);
			if (relink)
			{
				gi.linkentity (ent);
				G_TouchTriggers (ent);
			}
			ent->groundentity = NULL;
			return true;
		}
	}

// check point traces down for dangling corners
	VectorCopy (trace.endpos, ent->s.origin);
	
	if (!M_CheckBottom (ent))
	{
		if (ent->flags & FL_PARTIALGROUND)
		{	// entity had floor mostly pulled out from underneath it
			// and is trying to correct
			if (relink)
			{
				gi.linkentity (ent);
				G_TouchTriggers (ent);
			}
			return true;
		}
	}
	
	if (ent->flags & FL_PARTIALGROUND)
		ent->flags &= ~FL_PARTIALGROUND;

	ent->groundentity = trace.ent;
	if (trace.ent)
		ent->groundentity_linkcount = trace.ent->linkcount;

// the move is ok
	if (relink)
	{
		gi.linkentity (ent);
		G_TouchTriggers (ent);
	}

	return true;
}
示例#23
0
//FIXME since we need to test end position contents here, can we avoid doing
//it again later in catagorize position?
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
{
	float		dz;
	vec3_t		oldorg, neworg, end;
	trace_t		trace;//, tr;
	int			i;
	float		stepsize;
	vec3_t		test;
	int			contents;
	int			jump=0;

// try the move	
	VectorCopy (ent->s.origin, oldorg);
	VectorAdd (ent->s.origin, move, neworg);

// flying monsters don't step up
	if ((ent->flags & (FL_SWIM|FL_FLY)) || (ent->waterlevel > 1))
	{
	//	gi.dprintf("trying to swim\n");
	// try one move with vertical motion, then one without
		for (i=0 ; i<2 ; i++)
		{
			VectorAdd (ent->s.origin, move, neworg);
			if (i == 0 && ent->enemy)
			{
				if (!ent->goalentity)
					ent->goalentity = ent->enemy;
				dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
				if (ent->goalentity->client)
				{
					if (dz > 40)
						neworg[2] -= 8;
					if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
						if (dz < 30)
							neworg[2] += 8;
				}
				else
				{
					if (dz > 8)
						neworg[2] -= 8;
					else if (dz > 0)
						neworg[2] -= dz;
					else if (dz < -8)
						neworg[2] += 8;
					else
						neworg[2] += dz;
				}
			}
			trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
	
			// fly monsters don't enter water voluntarily
			if (ent->flags & FL_FLY)
			{
				if (!ent->waterlevel)
				{
					test[0] = trace.endpos[0];
					test[1] = trace.endpos[1];
					test[2] = trace.endpos[2] + ent->mins[2] + 1;
					contents = gi.pointcontents(test);
					if (contents & MASK_WATER)
						return false;
				}
			}

			// swim monsters don't exit water voluntarily
			if (ent->flags & FL_SWIM)
			{
				if (ent->waterlevel < 2)
				{
					test[0] = trace.endpos[0];
					test[1] = trace.endpos[1];
					test[2] = trace.endpos[2] + ent->mins[2] + 1;
					contents = gi.pointcontents(test);
					if (!(contents & MASK_WATER))
						return false;
				}
			}

			if (trace.fraction == 1)
			{
				VectorCopy (trace.endpos, ent->s.origin);
				if (relink)
				{
					gi.linkentity (ent);
					G_TouchTriggers (ent);
				}
				return true;
			}
			//gi.dprintf("swim move failed\n");
			
			if (!ent->enemy)
				break;
		}
		
		return false;
	}

// push down from a step height above the wished position
	if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
		stepsize = STEPSIZE;
	else
		stepsize = 1;

	neworg[2] += stepsize;
	VectorCopy (neworg, end);
	end[2] -= stepsize*2;
 
	// this trace checks from a position one step above the entity (at top of bbox)
	// to one step below the entity (bottom of bbox)
	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);

	// there is an obstruction bigger than a step
	if (trace.allsolid)
//GHz START
	{
		// az: Regular monsters: don't jump on invasion mode...
		if (!G_GetClient(ent) && invasion->value) 
			return false;

		// try to jump over it
		if (G_EntIsAlive(trace.ent) || !CanJumpUp(ent, neworg, end))
			return false;
		else
		{
			jump = 1;
		}
	}
//GHz END

	// not enough room at this height--head of bbox intersects something solid
	// so push down and just try to walk forward at floor height
	else if (trace.startsolid)
	{
		neworg[2] -= stepsize;
		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
		if (trace.allsolid || trace.startsolid)
			return false;
	}

	// don't go in to water
	if (ent->waterlevel == 0)
	{
		test[0] = trace.endpos[0];
		test[1] = trace.endpos[1];
		test[2] = trace.endpos[2] + ent->mins[2] + 1;	
		contents = gi.pointcontents(test);

		if (contents & (CONTENTS_LAVA|CONTENTS_SLIME))
			return false;
	}

//GHz 5/8/2010 - don't get stuck on steep little ramps
	if (trace.fraction < 1 && trace.plane.normal[2] < 0.7) // too steep
		return false;

//GHz START
//	if (CanJumpDown(ent, trace.endpos))
//		jump = -1;
//GHz END

//	VectorSubtract(trace.endpos, oldorg, forward);
//	VectorNormalize(forward);
//	VectorMA(oldorg, 32, forward, end);

//	VectorAdd(trace.endpos, move, end);
//	VectorAdd(end, move, end);

	if ((trace.fraction == 1) && (jump != 1))
	{
		//gi.dprintf("going to fall\n");
	// if monster had the ground pulled out, go ahead and fall
	//	VectorSubtract(trace.endpos, oldorg, forward);
	//	VectorMA(oldorg, 64, forward, end);
		if (!CanJumpDown(ent, trace.endpos))
		{
			if ( ent->flags & FL_PARTIALGROUND )
			{
				VectorAdd (ent->s.origin, move, ent->s.origin);
				if (relink)
				{
					gi.linkentity (ent);
					G_TouchTriggers (ent);
				}
				ent->groundentity = NULL;
				return true;
			}
			return false;		// walked off an edge
		}
		else
			jump = -1;
	}

// check point traces down for dangling corners
	//GHz START
	/*
	// fix for monsters walking thru walls
	tr = gi.trace(trace.endpos, ent->mins, ent->maxs, trace.endpos, ent, MASK_SOLID);
	if (tr.contents & MASK_SOLID)
		return false;
	*/
	//GHz END
	
	if (jump != 1)
		VectorCopy (trace.endpos, ent->s.origin);
	
	if (!M_CheckBottom (ent))
	{
		//gi.dprintf("partial ground\n");
		if (ent->flags & FL_PARTIALGROUND)
		{	// entity had floor mostly pulled out from underneath it
			// and is trying to correct
			if (relink)
			{
				gi.linkentity (ent);
				G_TouchTriggers (ent);
			}
			return true;
		}
		if (CanJumpDown(ent, trace.endpos))
			jump = -1;
		if (!jump)
		{
			VectorCopy (oldorg, ent->s.origin);
			return false;
		}
	}
	else if (jump == -1)
		jump = 0;
/*
	if (jump)
	{
		VectorCopy(oldorg, ent->s.origin);
		CanJumpDown(ent, trace.endpos, true);
		VectorCopy(trace.endpos, ent->s.origin);
	}
*/
	
	if ( ent->flags & FL_PARTIALGROUND )
	{
		ent->flags &= ~FL_PARTIALGROUND;
	}

	ent->groundentity = trace.ent;
	if (trace.ent)
		ent->groundentity_linkcount = trace.ent->linkcount;

	if (jump == -1)
	{
		/*
		gi.WriteByte (svc_temp_entity);
		gi.WriteByte (TE_DEBUGTRAIL);
		gi.WritePosition (oldorg);
		gi.WritePosition (end);
		gi.multicast (end, MULTICAST_ALL);
		*/

		//VectorScale(move, 10, ent->velocity);
		//ent->velocity[2] = 200;
	}
	else if (jump == 1)
	{
		ent->velocity[2] = 200;
		//gi.dprintf("jumped at %d\n",level.framenum);
	}

// the move is ok
	if (relink)
	{
		gi.linkentity (ent);
		G_TouchTriggers (ent);
	}
	//gi.dprintf("moved successfully at %d\n", level.framenum);
	return true;
}
示例#24
0
/*
=============
CheckAuraOwner

Returns true if the owner is allowed to maintain an aura
=============
*/
qboolean CheckAuraOwner (edict_t *self, int aura_cost)
{
	return (G_EntIsAlive(self->owner) && self->owner->client 
		&& (self->owner->client->pers.inventory[power_cube_index] >= aura_cost)
		&& !self->owner->client->cloaking);
}
示例#25
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);

}
示例#26
0
文件: invasion.c 项目: mylemans/vrxcl
void inv_defenderspawn_think (edict_t *self)
{
	//int		num=G_GetEntityIndex(self); // FOR DEBUGGING ONLY
	vec3_t	start;
	trace_t	tr;
	edict_t *monster=NULL;

	//FIXME: this isn't a good enough check if monster is dead or not
	// did our monster die?
	if (!G_EntIsAlive(self->enemy))
	{
		if (self->orders == MONSTERSPAWN_STATUS_IDLE)
		{
			// wait some time before spawning another monster
			self->wait = level.time + 30;
			self->orders = MONSTERSPAWN_STATUS_WORKING;
			//gi.dprintf("%d: monster died, waiting to build monster...\n", num);
		}

		// try to spawn another
		if ((level.time > self->wait) 
			&& (monster = SpawnDrone(self, self->sounds, true)) != NULL)
		{
			//gi.dprintf("%d: attempting to spawn a monster\n", num);
			// get starting position
			VectorCopy(self->s.origin, start);
			start[2] = self->absmax[2] + 1 + abs(monster->mins[2]);

			tr = gi.trace(start, monster->mins, monster->maxs, start, NULL, MASK_SHOT);
			
			// kill dead bodies
			if (tr.ent && tr.ent->takedamage && (tr.ent->deadflag == DEAD_DEAD || tr.ent->health < 1))
				T_Damage(tr.ent, self, self, vec3_origin, tr.ent->s.origin, vec3_origin, 10000, 0, 0, 0);
			// spawn is blocked, try again later
			 else if (tr.fraction < 1)
			{
				//gi.dprintf("%d: spawn is blocked, will try again\n", num);
				G_FreeEdict(monster);
				self->nextthink = level.time + 1.0;
				return;
			}

			// should this monster stand ground?
			if (self->style)
				monster->monsterinfo.aiflags |= AI_STAND_GROUND;

			monster->s.angles[YAW] = self->s.angles[YAW];
			// move the monster onto the spawn pad
			VectorCopy(start, monster->s.origin);
			VectorCopy(start, monster->s.old_origin);
			monster->s.event = EV_OTHER_TELEPORT;

			// give them quad/invuln to prevent spawn-camping
			if (self->count)
				monster->monsterinfo.inv_framenum = level.framenum + self->count;
			else
				monster->monsterinfo.inv_framenum = level.framenum + 60; 

			gi.linkentity(monster);

			self->enemy = monster; // keep track of this monster
			//gi.dprintf("%d: spawned a monster successfully\n", num);
		}
		else
		{
			//if (level.time > self->wait)
			//	gi.dprintf("%d: spawndrone() failed to spawn a monster\n", num);
			//else if (!(level.framenum%10))
			//	gi.dprintf("%d: waiting...\n", num);
		}
	}
	else
	{
		//if (self->orders == MONSTERSPAWN_STATUS_WORKING)
		//	gi.dprintf("%d: spawn is now idle\n", num);
		self->orders = MONSTERSPAWN_STATUS_IDLE;
	}

	self->nextthink = level.time + FRAMETIME;
}
示例#27
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;
}
示例#28
0
void boss_update (edict_t *ent, usercmd_t *ucmd)
{
	int		div=15, forwardspeed, sidespeed, maxspeed;
	int		frames=0;
	vec3_t	forward, right, angles;
	edict_t *boss;

	boss = ent->owner;
	// make sure this is a valid boss entity
	if (!G_EntIsAlive(boss))
		return;
	if (!IsABoss(boss) && (boss->mtype != P_TANK))
		return;

	VectorCopy(ent->s.origin, ent->s.old_origin);
	// update player state
	//ent->client->ps.pmove.pm_type = PM_FREEZE;
	ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
	//ent->client->ability_delay = level.time + FRAMETIME;
	// copy player angles to boss
	boss->s.angles[YAW] = ent->s.angles[YAW];
	boss->s.angles[PITCH] = 0;
	boss->s.angles[ROLL] = 0;
	AngleVectors(boss->s.angles, forward, right, NULL);
	vectoangles(right, angles);

	// move player into position
	boss_position_player(ent, boss);

	// speed divider, lower is faster (ucmd is 400)
	if (boss->mtype == BOSS_TANK)
		div = 20;
	else if (boss->mtype == BOSS_MAKRON)
		div = 10;
	else
		div = 26;

	// speed limiter, dont allow client to speed cheat using higher cl_speeds
	
	maxspeed = 400;
	forwardspeed = ucmd->forwardmove;
	sidespeed = ucmd->sidemove;
	//gi.dprintf("%d %d\n", forwardspeed, sidespeed);

	if ((forwardspeed > 0) && forwardspeed > maxspeed)
		forwardspeed = maxspeed;
	else if (forwardspeed < -maxspeed)
		forwardspeed = -maxspeed;
	
	if ((sidespeed > 0) && sidespeed > maxspeed)
		sidespeed = maxspeed;
	else if (sidespeed < -maxspeed)
		sidespeed = -maxspeed;
	
	//4.2 allow superspeed
	if (ent->superspeed && (level.time > ent->lasthurt + DAMAGE_ESCAPE_DELAY))
	{
		forwardspeed *= 3;
		sidespeed *= 3;
		maxspeed = 3*BOSS_MAXVELOCITY;
	}

	else if (boss->monsterinfo.air_frames)// used for boost
		maxspeed = 9999;
	else
		maxspeed = BOSS_MAXVELOCITY;

	if (level.framenum >= boss->count)
	{
		if (!(ent->client->buttons & BUTTON_ATTACK))
		{
			if (forwardspeed > 0)
			{
				M_walkmove(boss, boss->s.angles[YAW], forwardspeed/div);
				frames = FRAMES_RUN_FORWARD;
			}
			else if (forwardspeed < 0)
			{
				M_walkmove(boss, boss->s.angles[YAW], forwardspeed/div);
				frames = FRAMES_RUN_BACKWARD;
			}

			if (sidespeed > 0)
			{
				M_walkmove(boss, angles[YAW], sidespeed/div);
				frames = FRAMES_RUN_FORWARD;
			}
			else if (sidespeed < 0)
			{
				M_walkmove(boss, angles[YAW], sidespeed/div);
				frames = FRAMES_RUN_FORWARD;
			}
		}
		else
		{
			frames = FRAMES_ATTACK;
		}

		if (boss->groundentity)
		{
			boss->monsterinfo.air_frames = 0;//we're done boosting
			VectorClear(boss->velocity);
			if (ucmd->upmove > 0 && !ent->client->jump)
			{
				//gi.sound (ent, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0);
				// jump in the direction we are trying to move
				boss->velocity[0] = 0.1*((forwardspeed*forward[0])+(sidespeed*right[0]));
				boss->velocity[1] = 0.1*((forwardspeed*forward[1])+(sidespeed*right[1]));
				boss->velocity[2] = 350;
				
				ent->client->jump = true;
			}
			
			boss->v_flags &= ~SFLG_DOUBLEJUMP;
		}
		else
		{
			if (ucmd->upmove < 1)
				ent->client->jump = false;

			if (CanDoubleJump(boss, ucmd))
			{
				boss->velocity[2] += 350;
				boss->v_flags |= SFLG_DOUBLEJUMP;
			}

			// steer in the direction we are trying to move
			boss->velocity[0] += 0.1*((forwardspeed*forward[0])+(sidespeed*right[0]));
			boss->velocity[1] += 0.1*((forwardspeed*forward[1])+(sidespeed*right[1]));
			
			if (ucmd->upmove && (boss->waterlevel > 1))
			{
				if (ucmd->upmove > 0)
				{
					if (boss->waterlevel == 2)
						boss->velocity[2] = 200;
					else if (boss->velocity[2] < 50)
						boss->velocity[2] = 50;
				}
				else
				{
					if (boss->velocity[2] > -50)
						boss->velocity[2] = -50;
				}
			}

			// don't move too fast
			if (boss->velocity[0] > maxspeed)
				boss->velocity[0] = maxspeed;
			if (boss->velocity[0] < -maxspeed)
				boss->velocity[0] = -maxspeed;
			if (boss->velocity[1] > maxspeed)
				boss->velocity[1] = maxspeed;
			if (boss->velocity[1] < -maxspeed)
				boss->velocity[1] = -maxspeed;
		}
		
		boss->style = frames; // set frame set boss should use
		gi.linkentity(boss);
		boss->count = level.framenum+1;
	}
	
	// move player into position
	//boss_position_player(ent, boss);

	// if we are standing on a live entity, call its touch function
	// this prevents player-bosses from being invulnerable to obstacles
	//FIXME: it may be dangerous to call a touch function without a NULL plane or surf
	/*
	if (boss->groundentity && G_EntIsAlive(boss->groundentity) && boss->groundentity->touch)
		boss->groundentity->touch(boss->groundentity, boss, NULL, NULL);
		*/
}
示例#29
0
void base_createturret (edict_t *self)
{
	edict_t		*sentry;
	vec3_t		end;
	trace_t		tr;
	int			casterlevel, talentLevel;
	float		ammo_mult=1.0;

	// make sure sentry has settled down
	if (!G_EntIsAlive(self->creator) || !minisentry_checkposition(self))
	{
		if (self->creator)
		{
			self->creator->num_sentries--;
			if (self->creator->num_sentries < 0)
				self->creator->num_sentries = 0;
		}
		BecomeExplosion1(self);
		return;
	}
	self->movetype = MOVETYPE_NONE; // lock down base
	self->takedamage = DAMAGE_NO; // the base is invulnerable

	// 3.8 base bbox no longer necessary, turret takes over
	VectorClear(self->mins);
	VectorClear(self->maxs);
	self->solid = SOLID_NOT;

	// create basic ent for sentry
	sentry = G_Spawn();
	sentry->creator = self->creator;
	sentry->owner = self; // the base becomes the owner
	VectorCopy(self->s.angles, sentry->s.angles);
	sentry->think = minisentry_think;
	sentry->nextthink = level.time + FRAMETIME;
	sentry->s.modelindex = gi.modelindex ("models/weapons/g_bfg/tris.md2");
	sentry->s.renderfx |= RF_IR_VISIBLE;
	// who really wanted to chase sentries anyway
	// sentry->flags |= FL_CHASEABLE; // 3.65 indicates entity can be chase cammed
	sentry->solid = SOLID_BBOX;
	sentry->movetype = MOVETYPE_NONE;
	sentry->clipmask = MASK_MONSTERSOLID;
	sentry->mass = 100;
	sentry->classname = "msentrygun";
	//sentry->viewheight = 16;
	sentry->takedamage = DAMAGE_AIM;
	sentry->mtype = M_MINISENTRY;
	sentry->touch = minisentry_touch;
	
	sentry->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;

	//Talent: Storage Upgrade
	talentLevel = getTalentLevel(self->creator, TALENT_STORAGE_UPGRADE);
	ammo_mult += 0.2 * talentLevel;

	// set ammo
	sentry->monsterinfo.jumpdn = SENTRY_MAX_AMMO * ammo_mult; // max ammo
	sentry->light_level = sentry->monsterinfo.jumpdn; // current ammo

	//get player's current_level for BUILD_SENTRY
	casterlevel = self->monsterinfo.level;
	sentry->monsterinfo.level = casterlevel; // used for adding monster exp
	sentry->monsterinfo.control_cost = 20; // used for adding monster exp

	//set health
	sentry->health = MINISENTRY_INITIAL_HEALTH + (MINISENTRY_ADDON_HEALTH * casterlevel);
	sentry->monsterinfo.power_armor_power = MINISENTRY_INITIAL_ARMOR + (MINISENTRY_ADDON_ARMOR * casterlevel);
//	if (sentry->health > MINISENTRY_MAX_HEALTH)
//		sentry->health = MINISENTRY_MAX_HEALTH;
	//if (sentry->monsterinfo.power_armor_power > MINISENTRY_MAX_ARMOR)
	//	sentry->monsterinfo.power_armor_power = MINISENTRY_MAX_ARMOR;
	sentry->max_health = sentry->health;
	sentry->monsterinfo.max_armor = sentry->monsterinfo.power_armor_power;

	//set damage
	sentry->dmg = MINISENTRY_INITIAL_BULLET + (MINISENTRY_ADDON_BULLET * casterlevel);// bullet damage
	sentry->radius_dmg = MINISENTRY_INITIAL_ROCKET + (MINISENTRY_ADDON_ROCKET * casterlevel); // rocket damage
	if (sentry->dmg > MINISENTRY_MAX_BULLET)
		sentry->dmg = MINISENTRY_MAX_BULLET;
	if (sentry->radius_dmg > MINISENTRY_MAX_ROCKET)
		sentry->radius_dmg = MINISENTRY_MAX_ROCKET;

	sentry->die = minisentry_die;
	sentry->pain = minisentry_pain;
	sentry->yaw_speed = 5;

	if (self->style == SENTRY_UPRIGHT)
	{
		VectorSet(sentry->mins, -28, -28, -12);
		VectorSet(sentry->maxs, 28, 28, 24);
		VectorCopy(self->s.origin, end);
		//end[2] += self->maxs[2] + sentry->mins[2] + 1;
		end[2] += abs(sentry->mins[2])+1;
	}
	else
	{
		VectorSet(sentry->mins, -28, -28, -24);
		VectorSet(sentry->maxs, 28, 28, 12);
		VectorCopy(self->s.origin, end);
		//end[2] -= abs(self->mins[2]) + sentry->maxs[2] + 1;
		end[2] -= sentry->maxs[2]+1;
	}

	// make sure position is valid
	tr = gi.trace(end, sentry->mins, sentry->maxs, end, sentry, MASK_SHOT);
	if (tr.contents & MASK_SHOT)
	{
		if (self->creator)
		{
			self->creator->num_sentries--;
			if (self->creator->num_sentries < 0)
				self->creator->num_sentries = 0;
		}
		//gi.dprintf("%s\n", tr.ent?tr.ent->classname:"null");
		BecomeExplosion1(self);
		BecomeExplosion1(sentry);
		return;
	}
	VectorCopy(tr.endpos, sentry->s.origin);
	VectorCopy(sentry->s.angles, sentry->move_angles);// save for idle animation
	gi.linkentity(sentry);
	
	gi.sound(sentry, CHAN_VOICE, gi.soundindex("weapons/turrset.wav"), 1, ATTN_NORM, 0);
	self->think = base_think; // base is done creating gun
	self->nextthink = level.time + FRAMETIME;
}
示例#30
0
文件: bombspell.c 项目: zardoru/vrxcl
void carpetbomb_think (edict_t *self)
{
	float		ceil;
	qboolean	failed = false;
	vec3_t		forward, right, start, end;
	trace_t		tr, tr1;

	if (!G_EntIsAlive(self->owner) || (level.time>self->delay))
	{
		G_FreeEdict(self);
		return;
	}

	// move forward
	AngleVectors(self->s.angles, forward, NULL, NULL);
	VectorMA(self->s.origin, GetRandom(CARPETBOMB_DAMAGE_RADIUS/2, CARPETBOMB_DAMAGE_RADIUS+1), forward, start);
	tr = gi.trace(self->s.origin, NULL, NULL, start, NULL, MASK_SOLID);
	VectorCopy(start, end);
	start[2]++;
	end[2] -= 8192;
	tr1 = gi.trace(start, NULL, NULL, end, NULL, MASK_SOLID);
	start[2]--;

	if ((tr.fraction < 1) || (start[2] != tr1.endpos[2]))
	{
		//gi.dprintf("will step down, start[2] %f tr1.endpos[2] %f\n", start[2], tr1.endpos[2]);
		// get current ceiling height
		VectorCopy(start, end);
		end[2] += 8192;
		tr = gi.trace(self->s.origin, NULL, NULL, end, NULL, MASK_SOLID);
		ceil = tr.endpos[2];

		// push down from above desired position
		start[2] += CARPETBOMB_STEP_SIZE;
		if ((start[2] > ceil)) // dont go thru ceiling
			start[2] = ceil;
		VectorCopy(start, end);
		end[2] -= 8192;
		tr = gi.trace(start, NULL, NULL, end, NULL, MASK_SOLID);

		// dont go thru walls
		if (tr.allsolid)
			failed = true;
		// try a bit lower
		if (tr.startsolid)
		{
			start[2] -= CARPETBOMB_STEP_SIZE;
			tr = gi.trace(start, NULL, NULL, end, NULL, MASK_SOLID);
			if (tr.startsolid || tr.allsolid)
				failed = true;
		}

		// dont go into water if we aren't already submerged
		VectorCopy(tr.endpos, start);
		start[2] += 8;
		if (!self->waterlevel && (gi.pointcontents(start) & MASK_WATER))
			failed = true;
	}

	// save position
	VectorCopy(tr.endpos, self->s.origin);
	VectorCopy(tr.endpos, start);
	// spawn explosions on either side
	// FIXME: step down from these positions, otherwise we get mid-air explosions!
	AngleVectors(self->s.angles, NULL, right, NULL);
	VectorMA(self->s.origin, (crandom()*GetRandom(CARPETBOMB_CARPET_WIDTH/4, CARPETBOMB_CARPET_WIDTH/2)), right, end);
	// make sure path is wide enough
	tr = gi.trace(self->s.origin, NULL, NULL, end, self, MASK_SHOT);
	VectorCopy(tr.endpos, self->s.origin);
	self->s.origin[2] += 32;

	//4.08 make sure the caster can see this spot
	//if (!visible(self->owner, self))
	if (!G_IsClearPath(self, MASK_SOLID, self->move_origin, self->s.origin))
		failed = true;

	// make sure bombspell is in a valid location
	if ((gi.pointcontents(self->s.origin) & CONTENTS_SOLID) || failed)
	{
		G_FreeEdict(self);
		return;
	}
	T_RadiusDamage(self, self->owner, self->dmg, NULL, self->dmg_radius, MOD_BOMBS);
	// write explosion effects
	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_EXPLOSION1);
	gi.WritePosition (self->s.origin);
	gi.multicast (self->s.origin, MULTICAST_PVS);

	VectorCopy(start, self->s.origin); // retrieve starting position
	self->nextthink = level.time + FRAMETIME;

	gi.linkentity(self);
}