예제 #1
0
static void DoDamageCharacter(
	const Vec2i hitVector,
	const int power,
	const int flags,
	const int playerUID,
	const int uid,
	TActor *actor,
	const special_damage_e special)
{
	// Create events: hit, damage, score
	CASSERT(actor->isInUse, "Cannot damage nonexistent player");
	CASSERT(CanHitCharacter(flags, uid, actor), "damaging undamageable actor");

	if (ConfigGetBool(&gConfig, "Game.ShotsPushback"))
	{
		GameEvent ei = GameEventNew(GAME_EVENT_ACTOR_IMPULSE);
		ei.u.ActorImpulse.UID = actor->uid;
		ei.u.ActorImpulse.Vel = Vec2i2Net(Vec2iScaleDiv(
			Vec2iScale(hitVector, power), SHOT_IMPULSE_DIVISOR));
		ei.u.ActorImpulse.Pos = Vec2i2Net(actor->Pos);
		GameEventsEnqueue(&gGameEvents, ei);
	}

	const bool canDamage =
		CanDamageCharacter(flags, playerUID, uid, actor, special);

	GameEvent e = GameEventNew(GAME_EVENT_ACTOR_HIT);
	e.u.ActorHit.UID = actor->uid;
	e.u.ActorHit.PlayerUID = actor->PlayerUID;
	e.u.ActorHit.HitterPlayerUID = playerUID;
	e.u.ActorHit.Special = special;
	e.u.ActorHit.Power = canDamage ? power : 0;
	e.u.ActorHit.Vel = Vec2i2Net(hitVector);
	GameEventsEnqueue(&gGameEvents, e);

	if (canDamage)
	{
		// Don't score for friendly or player hits
		const bool isFriendly =
			(actor->flags & FLAGS_GOOD_GUY) ||
			(!IsPVP(gCampaign.Entry.Mode) && actor->PlayerUID >= 0);
		if (playerUID >= 0 && power != 0 && !isFriendly)
		{
			// Calculate score based on
			// if they hit a penalty character
			e = GameEventNew(GAME_EVENT_SCORE);
			e.u.Score.PlayerUID = playerUID;
			if (actor->flags & FLAGS_PENALTY)
			{
				e.u.Score.Score = PENALTY_MULTIPLIER * power;
			}
			else
			{
				e.u.Score.Score = power;
			}
			GameEventsEnqueue(&gGameEvents, e);
		}
	}
}
예제 #2
0
파일: damage.c 프로젝트: evktalo/cdogs-sdl
bool CanDamageCharacter(
	const int flags, const int player, const int uid,
	const TActor *actor, const special_damage_e special)
{
	if (!CanHitCharacter(flags, uid, actor))
	{
		return false;
	}
	if (ActorIsImmune(actor, special))
	{
		return false;
	}
	return !ActorIsInvulnerable(actor, flags, player, gCampaign.Entry.Mode);
}
예제 #3
0
bool CanHit(const int flags, const int uid, const TTileItem *target)
{
	switch (target->kind)
	{
	case KIND_CHARACTER:
		return CanHitCharacter(flags, uid, CArrayGet(&gActors, target->id));
	case KIND_OBJECT:
		return true;
	default:
		CASSERT(false, "cannot damage tile item kind");
		break;
	}
	return false;
}
예제 #4
0
파일: objs.c 프로젝트: evktalo/cdogs-sdl
static bool DoDamageCharacter(
	const Vec2i pos,
	const Vec2i hitVector,
	const int power,
	const int flags,
	const int player,
	const int uid,
	const TTileItem *target,
	const special_damage_e special,
	const HitSounds *hitSounds,
	const bool allowFriendlyHitSound)
{
	// Create events: hit, damage, score
	TActor *actor = CArrayGet(&gActors, target->id);
	CASSERT(actor->isInUse, "Cannot damage nonexistent player");
	bool canHit = CanHitCharacter(flags, uid, actor);
	if (canHit)
	{
		GameEvent e;
		e.Type = GAME_EVENT_HIT_CHARACTER;
		e.u.HitCharacter.TargetId = actor->tileItem.id;
		e.u.HitCharacter.Special = special;
		GameEventsEnqueue(&gGameEvents, e);
		if (gConfig.Sound.Hits && hitSounds != NULL &&
			!ActorIsImmune(actor, special) &&
			(allowFriendlyHitSound || !ActorIsInvulnerable(
			actor, flags, player, gCampaign.Entry.Mode)))
		{
			GameEvent es;
			es.Type = GAME_EVENT_SOUND_AT;
			es.u.SoundAt.Sound = hitSounds->Flesh;
			es.u.SoundAt.Pos = pos;
			GameEventsEnqueue(&gGameEvents, es);
		}
		if (gConfig.Game.ShotsPushback)
		{
			GameEvent ei;
			ei.Type = GAME_EVENT_ACTOR_IMPULSE;
			ei.u.ActorImpulse.Id = actor->tileItem.id;
			ei.u.ActorImpulse.Vel = Vec2iScaleDiv(
				Vec2iScale(hitVector, power), SHOT_IMPULSE_DIVISOR);
			GameEventsEnqueue(&gGameEvents, ei);
		}
		if (CanDamageCharacter(flags, player, uid, actor, special))
		{
			GameEvent e1;
			e1.Type = GAME_EVENT_DAMAGE_CHARACTER;
			e1.u.DamageCharacter.Power = power;
			e1.u.DamageCharacter.PlayerIndex = player;
			e1.u.DamageCharacter.TargetId = actor->tileItem.id;
			e1.u.DamageCharacter.TargetPlayerIndex = -1;
			if (actor->pData)
			{
				e1.u.DamageCharacter.TargetPlayerIndex =
					actor->pData->playerIndex;
			}
			GameEventsEnqueue(&gGameEvents, e1);

			if (gConfig.Game.Gore != GORE_NONE)
			{
				GameEvent eb;
				memset(&eb, 0, sizeof eb);
				eb.Type = GAME_EVENT_ADD_PARTICLE;
				eb.u.AddParticle.FullPos = Vec2iReal2Full(pos);
				eb.u.AddParticle.Z = 10 * Z_FACTOR;
				int bloodPower = power * 2;
				int bloodSize = 1;
				while (bloodPower > 0)
				{
					switch (bloodSize)
					{
					case 1:
						eb.u.AddParticle.Class =
							StrParticleClass(&gParticleClasses, "blood1");
						break;
					case 2:
						eb.u.AddParticle.Class =
							StrParticleClass(&gParticleClasses, "blood2");
						break;
					default:
						eb.u.AddParticle.Class =
							StrParticleClass(&gParticleClasses, "blood3");
						break;
					}
					bloodSize++;
					if (bloodSize > 3)
					{
						bloodSize = 1;
					}
					if (gConfig.Game.ShotsPushback)
					{
						eb.u.AddParticle.Vel = Vec2iScaleDiv(
							Vec2iScale(hitVector, (rand() % 8 + 8) * power),
							15 * SHOT_IMPULSE_DIVISOR);
					}
					else
					{
						eb.u.AddParticle.Vel = Vec2iScaleDiv(
							Vec2iScale(hitVector, rand() % 8 + 8), 20);
					}
					eb.u.AddParticle.Vel.x += (rand() % 128) - 64;
					eb.u.AddParticle.Vel.y += (rand() % 128) - 64;
					eb.u.AddParticle.Angle = RAND_DOUBLE(0, PI * 2);
					eb.u.AddParticle.DZ = (rand() % 6) + 6;
					eb.u.AddParticle.Spin = RAND_DOUBLE(-0.1, 0.1);
					GameEventsEnqueue(&gGameEvents, eb);
					switch (gConfig.Game.Gore)
					{
					case GORE_LOW:
						bloodPower /= 8;
						break;
					case GORE_MEDIUM:
						bloodPower /= 2;
						break;
					default:
						bloodPower = bloodPower * 7 / 8;
						break;
					}
				}
			}

			if (player >= 0 && power != 0)
			{
				// Calculate score based on
				// if they hit a penalty character
				GameEvent e2;
				e2.Type = GAME_EVENT_SCORE;
				e2.u.Score.PlayerIndex = player;
				if (actor->flags & FLAGS_PENALTY)
				{
					e2.u.Score.Score = PENALTY_MULTIPLIER * power;
				}
				else
				{
					e2.u.Score.Score = power;
				}
				GameEventsEnqueue(&gGameEvents, e2);
			}
		}
	}
	return canHit;
}