示例#1
0
void BattleHazard::applyEffect(GameState &state)
{
	auto tile = tileObject->getOwningTile();

	auto set = tile->ownedObjects;
	for (auto &obj : set)
	{
		if (tile->ownedObjects.find(obj) == tile->ownedObjects.end())
		{
			continue;
		}
		if (obj->getType() == TileObject::Type::Ground ||
		    obj->getType() == TileObject::Type::Feature ||
		    obj->getType() == TileObject::Type::LeftWall ||
		    obj->getType() == TileObject::Type::RightWall)
		{
			auto mp = std::static_pointer_cast<TileObjectBattleMapPart>(obj)->getOwner();
			switch (damageType->effectType)
			{
				case DamageType::EffectType::Fire:
					if (mp->applyBurning(state, age))
					{
						// Map part burned and provided fuel for our fire, keep the fire raging
						if (power < 0 && age > 10)
						{
							power = -power;
						}
					}
					break;
				default:
					switch (damageType->blockType)
					{
						case DamageType::BlockType::Gas:
						case DamageType::BlockType::Psionic:
							break;
						default:
							mp->applyDamage(state, power, damageType);
							break;
					}
					break;
			}
		}
		else if (obj->getType() == TileObject::Type::Item)
		{
			if (damageType->effectType == DamageType::EffectType::Fire)
			{
				// It was observed that armor resists fire damage deal to it
				// It also appears that damage is applied gradually at a rate of around 1 damage per
				// second
				// In tests, marsec armor (20% modifier) was hurt by fire but X-Com armor (10%
				// modifier) was not
				// If we apply damage once per turn, we apply 4 at once. Since we round down, 4 *
				// 20% will be rounded to 0
				// while it should be 1. So we add 1 here
				auto i = std::static_pointer_cast<TileObjectBattleItem>(obj)->getItem();
				i->applyDamage(state, 2 * TICKS_PER_HAZARD_UPDATE / TICKS_PER_SECOND + 1,
				               damageType);
			}
		}
		else if (obj->getType() == TileObject::Type::Unit)
		{
			StateRef<BattleUnit> u = {
			    &state, std::static_pointer_cast<TileObjectBattleUnit>(obj)->getUnit()->id};
			// Determine direction of hit
			Vec3<float> velocity = -position;
			velocity -= Vec3<float>{0.5f, 0.5f, 0.5f};
			velocity += u->position;
			if (velocity.x == 0.0f && velocity.y == 0.0f)
			{
				velocity.z = 1.0f;
			}
			// Determine wether to hit head, legs or torso
			auto cposition = u->position;
			// Hit torso
			if (sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) > std::abs(velocity.z))
			{
				cposition.z += (float)u->getCurrentHeight() / 2.0f / 40.0f;
			}
			// Hit head
			else if (velocity.z < 0)
			{
				cposition.z += (float)u->getCurrentHeight() / 40.0f;
			}
			else
			{
				// Legs are defeault already
			}
			// Apply
			u->applyDamage(state, power, damageType,
			               u->determineBodyPartHit(damageType, cposition, velocity),
			               DamageSource::Hazard);
		}
	}
}
示例#2
0
void BattleHazard::applyEffect(GameState &state)
{
	auto tile = tileObject->getOwningTile();

	auto set = tile->ownedObjects;
	for (auto obj : set)
	{
		if (tile->ownedObjects.find(obj) == tile->ownedObjects.end())
		{
			continue;
		}
		if (obj->getType() == TileObject::Type::Ground ||
		    obj->getType() == TileObject::Type::Feature ||
		    obj->getType() == TileObject::Type::LeftWall ||
		    obj->getType() == TileObject::Type::RightWall)
		{
			auto mp = std::static_pointer_cast<TileObjectBattleMapPart>(obj)->getOwner();
			switch (damageType->effectType)
			{
				case DamageType::EffectType::Fire:
					LogWarning("Set map part on fire!");
					break;
				default:
					mp->applyDamage(state, power, damageType);
					break;
			}
		}
		else if (obj->getType() == TileObject::Type::Unit)
		{
			StateRef<BattleUnit> u = {
			    &state, std::static_pointer_cast<TileObjectBattleUnit>(obj)->getUnit()->id};
			switch (damageType->effectType)
			{
				case DamageType::EffectType::Fire:
					LogWarning("Set unit on fire!");
					break;
				default:
				{
					// Determine direction of hit
					Vec3<float> velocity = -position;
					velocity -= Vec3<float>{0.5f, 0.5f, 0.5f};
					velocity += u->position;
					if (velocity.x == 0.0f && velocity.y == 0.0f)
					{
						velocity.z = 1.0f;
					}
					// Determine wether to hit head, legs or torso
					auto cposition = u->position;
					// Hit torso
					if (sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) >
					    std::abs(velocity.z))
					{
						cposition.z += (float)u->getCurrentHeight() / 2.0f / 40.0f;
					}
					// Hit head
					else if (velocity.z < 0)
					{
						cposition.z += (float)u->getCurrentHeight() / 40.0f;
					}
					else
					{
						// Legs are defeault already
					}
					// Apply
					u->applyDamage(state, power, damageType,
					               u->determineBodyPartHit(damageType, cposition, velocity));
				}
				break;
			}
		}
	}
}
示例#3
0
void BattleExplosion::damage(GameState &state, const TileMap &map, Vec3<int> pos, int damage)
{
	auto tile = map.getTile(pos);
	// Explosions with no hazard spawn smoke with half ttl
	if (!damageType->hazardType)
	{
		StateRef<DamageType> dtSmoke = {&state, "DAMAGETYPE_SMOKE"};
		state.current_battle->placeHazard(state, ownerOrganisation, ownerUnit, dtSmoke, pos,
		                                  dtSmoke->hazardType->getLifetime(state), damage, 2,
		                                  false);
	}
	// Explosions with no custom explosion doodad spawn hazards when dealing damage
	else if (!damageType->explosionDoodad)
	{
		state.current_battle->placeHazard(state, ownerOrganisation, ownerUnit, damageType, pos,
		                                  damageType->hazardType->getLifetime(state), damage, 1,
		                                  false);
	}
	// Gas does no direct damage
	if (damageType->doesImpactDamage())
	{
		auto set = tile->ownedObjects;
		for (auto &obj : set)
		{
			if (tile->ownedObjects.find(obj) == tile->ownedObjects.end())
			{
				continue;
			}
			if (obj->getType() == TileObject::Type::Ground ||
			    obj->getType() == TileObject::Type::Feature ||
			    obj->getType() == TileObject::Type::LeftWall ||
			    obj->getType() == TileObject::Type::RightWall)
			{
				auto mp = std::static_pointer_cast<TileObjectBattleMapPart>(obj)->getOwner();
				switch (damageType->effectType)
				{
					case DamageType::EffectType::Fire:
						// Nothing, map parts are not damaged by fire at explosion time
						break;
					default:
						mp->applyDamage(state, damage, damageType);
						break;
				}
			}
			else if (obj->getType() == TileObject::Type::Unit)
			{
				StateRef<BattleUnit> u = {
				    &state, std::static_pointer_cast<TileObjectBattleUnit>(obj)->getUnit()->id};
				if (affectedUnits.find(u) != affectedUnits.end())
				{
					continue;
				}
				affectedUnits.insert(u);
				// Determine direction of hit
				Vec3<float> velocity = -position;
				velocity -= Vec3<float>{0.5f, 0.5f, 0.5f};
				velocity += u->position;
				if (velocity.x == 0.0f && velocity.y == 0.0f)
				{
					velocity.z = 1.0f;
				}
				// Determine wether to hit head, legs or torso
				auto cposition = u->position;
				// Hit torso if coming from the side, not from above or below
				if (sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) > std::abs(velocity.z))
				{
					cposition.z += (float)u->getCurrentHeight() / 2.0f / 40.0f;
				}
				// Hit head if coming from above
				else if (velocity.z < 0)
				{
					cposition.z += (float)u->getCurrentHeight() / 40.0f;
				}
				// Hit legs if coming from below
				else
				{
					// Legs are defeault already
				}
				// Apply
				u->applyDamage(state, damage, damageType,
				               u->determineBodyPartHit(damageType, cposition, velocity),
				               DamageSource::Impact, ownerUnit);
			}
			else if (obj->getType() == TileObject::Type::Item)
			{
				// Special effects do not damage items, fire damages items differently and not on
				// explosion impact
				if (damageType->effectType == DamageType::EffectType::None)
				{
					auto i = std::static_pointer_cast<TileObjectBattleItem>(obj)->getItem();
					i->applyDamage(state, damage, damageType);
				}
			}
		}
	}
}