Code Search for Developers
 
 
  

TankDamage.cpp from Scorched 3D at Krugle


Show TankDamage.cpp syntax highlighted

////////////////////////////////////////////////////////////////////////////////
//    Scorched3D (c) 2000-2003
//
//    This file is part of Scorched3D.
//
//    Scorched3D is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    Scorched3D is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with Scorched3D; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
////////////////////////////////////////////////////////////////////////////////

#include <actions/TankDamage.h>
#include <actions/TankFalling.h>
#include <actions/TankSay.h>
#include <actions/CameraPositionAction.h>
#include <sprites/TextActionRenderer.h>
#include <common/OptionsScorched.h>
#include <common/Defines.h>
#include <common/ChannelManager.h>
#include <common/StatsLogger.h>
#include <weapons/AccessoryStore.h>
#include <weapons/Shield.h>
#include <landscapemap/LandscapeMaps.h>
#include <engine/ScorchedContext.h>
#include <engine/ActionController.h>
#include <tank/TankContainer.h>
#include <tank/TankTeamScore.h>
#include <tank/TankScore.h>
#include <tank/TankState.h>
#include <tank/TankPosition.h>
#include <tankai/TankAI.h>
#include <target/TargetShield.h>
#include <target/TargetLife.h>
#include <target/TargetParachute.h>
#include <target/TargetState.h>
#include <tankai/TankAIStrings.h>
#include <tankgraph/TargetRendererImplTarget.h>

TankDamage::TankDamage(Weapon *weapon, 
		unsigned int damagedPlayerId, WeaponFireContext &weaponContext,
		float damage, bool useShieldDamage, bool checkFall,
		bool shieldOnlyDamage) :
	weapon_(weapon), firstTime_(true),
	damagedPlayerId_(damagedPlayerId), weaponContext_(weaponContext),
	damage_(damage), useShieldDamage_(useShieldDamage), checkFall_(checkFall),
	shieldOnlyDamage_(shieldOnlyDamage)
{
}

TankDamage::~TankDamage()
{
}

void TankDamage::init()
{
	Target *damagedTarget = 
		context_->targetContainer->getTargetById(damagedPlayerId_);
	if (damagedTarget)
	{
		const float ShowTime = 4.0f;
#ifndef S3D_SERVER
        	if (!context_->serverMode)
        	{
			CameraPositionAction *pos = new CameraPositionAction(
				damagedTarget->getLife().getTargetPosition(), ShowTime,
				15);
			context_->actionController->addAction(pos);
		}
#endif
	}

}

void TankDamage::simulate(float frameTime, bool &remove)
{
	if (firstTime_)
	{
		firstTime_ = false;
		calculateDamage();
	}

	remove = true;
	Action::simulate(frameTime, remove);
}

void TankDamage::calculateDamage()
{
	unsigned int firedPlayerId = weaponContext_.getPlayerId();

	// Find the tank that has been damaged
	Target *damagedTarget = 
		context_->targetContainer->getTargetById(damagedPlayerId_);
	if (!damagedTarget || !damagedTarget->getAlive()) return;

	// Tell this tanks ai that is has been hurt by another tank
	if (!damagedTarget->isTarget())
	{
		// Tell all AIs about this collision
		std::map<unsigned int, Tank *> tanks = 
			context_->tankContainer->getAllTanks();
		std::map<unsigned int, Tank *>::iterator itor;
		for (itor = tanks.begin();
			itor != tanks.end();
			itor++)
		{
			Tank *tank = (*itor).second;
			TankAI *ai = tank->getTankAI();
			if (ai)
			{		
				if (tank->getState().getState() == TankState::sNormal &&
					!tank->getState().getSpectator())
				{
					ai->tankHurt(weapon_, damage_,
						damagedTarget->getPlayerId(), 
						firedPlayerId);
				}
			}
		}
	}

	// Remove any damage from shield first
	if (damage_ > 0.0f)
	{
		float shieldDamage = 0.0f;
		Accessory *sh = damagedTarget->getShield().getCurrentShield();
		if (sh && useShieldDamage_)
		{
			Shield *shield = (Shield *) sh->getAction();
			float shieldPowerRequired = 
				damage_ * shield->getHitPenetration();
			float shieldPower = 
				damagedTarget->getShield().getShieldPower();
			if (shieldPower > shieldPowerRequired)
			{
				shieldPower -= shieldPowerRequired;
				damage_ = 0.0f;
			}
			else
			{
				float p = shieldPower / shield->getHitPenetration();
				shieldPower = 0.0f;
				damage_ -= p;
			}

			damagedTarget->getShield().setShieldPower(shieldPower);
		}
	}

	// Remove the remaining damage from the tank
	if (damage_ > 0.0f && !shieldOnlyDamage_)
	{
#ifndef S3D_SERVER
		if (!context_->serverMode &&
			damagedTarget->getTargetState().getDisplayDamage())
		{
			Vector position = damagedTarget->getLife().getTargetPosition();
			position[0] += RAND * 5.0f - 2.5f;
			position[1] += RAND * 5.0f - 2.5f;
			position[2] += RAND * 5.0f - 2.5f;

			Vector redColor(0.75f, 0.0f, 0.0f);
			context_->actionController->addAction(
				new SpriteAction(
					new TextActionRenderer(
						position,
						redColor,
						formatString("%.0f", damage_))));
		}
#endif // #ifndef S3D_SERVER

		// Remove the life
		if (damage_ > damagedTarget->getLife().getLife()) damage_ = 
			damagedTarget->getLife().getLife();
		damagedTarget->getLife().setLife(damagedTarget->getLife().getLife() - damage_);
		if (context_->optionsGame->getLimitPowerByHealth() &&
			!damagedTarget->isTarget())
		{
			Tank *damagedTank = (Tank *) damagedTarget;
			damagedTank->getPosition().changePower(0.0f, true);
		}

		// Check if the tank is dead
		bool killedTank = (damagedTarget->getLife().getLife() == 0.0f);

		// Add any score got from this endevour
		// Should always be a tank that has fired
		Tank *firedTank = 
			context_->tankContainer->getTankById(firedPlayerId);
		if (firedTank && !damagedTarget->isTarget())
		{	
			Tank *damagedTank = (Tank *) damagedTarget;

			// Add this tank as a tank that assisted in the kill
			damagedTank->getScore().getHurtBy().insert(firedTank->getPlayerId());

			// Calculate team kills
			bool selfKill = (damagedPlayerId_ ==  firedPlayerId);
			bool teamKill = ((context_->optionsGame->getTeams() > 1) &&
				(firedTank->getTeam() == damagedTank->getTeam()));

			if (!killedTank)
			{
				// Calculate money won for not killing this tank
				int moneyPerHit = 
					context_->optionsGame->getMoneyWonPerHitPoint() *
						weapon_->getArmsLevel();
				if (context_->optionsGame->getMoneyPerHealthPoint()) 
					moneyPerHit = (moneyPerHit * int(damage_)) / 100;
				if (selfKill || teamKill) moneyPerHit *= -1;

				firedTank->getScore().setMoney(
					firedTank->getScore().getMoney() + moneyPerHit);
			}
			else 
			{
				int moneyPerKill = 
					context_->optionsGame->getMoneyWonPerKillPoint() *
						weapon_->getArmsLevel();
				if (!selfKill && !teamKill)
				{
					// Note this is done before turn kills is updated
					// so for the first kill turn kills will be 0
					// i.e. no multikill bonus for 1st kill
					moneyPerKill +=
						context_->optionsGame->getMoneyWonPerMultiKillPoint() *
							weapon_->getArmsLevel() *
							firedTank->getScore().getTurnKills();
				}
				if (context_->optionsGame->getMoneyPerHealthPoint()) 
					moneyPerKill = (moneyPerKill * int(damage_)) / 100;
				int scorePerKill = context_->optionsGame->getScorePerKill();

				int moneyPerAssist = 
					context_->optionsGame->getMoneyWonPerAssistPoint() *
						weapon_->getArmsLevel();
				int scorePerAssist = context_->optionsGame->getScorePerAssist();

				// Update kills and score
				if (selfKill || teamKill)
				{
					firedTank->getScore().setKills(
						firedTank->getScore().getKills() - 1);
					firedTank->getScore().setMoney(
						firedTank->getScore().getMoney() - moneyPerKill);
					firedTank->getScore().setScore(
						firedTank->getScore().getScore() - scorePerKill);

					if (firedTank->getTeam() > 0)
					{
						context_->tankTeamScore->addScore(
							-scorePerKill, firedTank->getTeam());
					}
				}
				else
				{
					firedTank->getScore().setKills(
						firedTank->getScore().getKills() + 1);
					firedTank->getScore().setTurnKills(
						firedTank->getScore().getTurnKills() + 1);
					firedTank->getScore().setMoney(
						firedTank->getScore().getMoney() + moneyPerKill);
					firedTank->getScore().setScore(
						firedTank->getScore().getScore() + scorePerKill);

					if (firedTank->getTeam() > 0)
					{
						context_->tankTeamScore->addScore(
							scorePerKill, firedTank->getTeam());
					}
				}

				// Update assists
				std::set<unsigned int> &hurtBy = 
					damagedTank->getScore().getHurtBy();
				std::set<unsigned int>::iterator itor;
				for (itor = hurtBy.begin();
					itor != hurtBy.end();
					itor++)
				{
					unsigned int hurtByPlayer = (*itor);
					Tank *hurtByTank = 
						context_->tankContainer->getTankById(hurtByPlayer);
					if (!hurtByTank) continue;

					// Only score when the tank does not hurt itself
					if (hurtByTank == damagedTank) continue;

					// You don't get an assist for your kill
					if (hurtByTank == firedTank) continue;

					// or a team member
					if ((context_->optionsGame->getTeams() > 1) &&
						(hurtByTank->getTeam() == damagedTank->getTeam())) continue;

					// Update assist score
					hurtByTank->getScore().setAssists(
						hurtByTank->getScore().getAssists() + 1);
					hurtByTank->getScore().setMoney(
						hurtByTank->getScore().getMoney() + moneyPerAssist);
					hurtByTank->getScore().setScore(
						hurtByTank->getScore().getScore() + scorePerAssist);

					if (hurtByTank->getTeam() > 0)
					{
						context_->tankTeamScore->addScore(
							scorePerAssist, hurtByTank->getTeam());
					}
				}
			}
		}

		if (killedTank)
		{
			// The tank has died, make it blow up etc.
			calculateDeath();

			if (!damagedTarget->isTarget())
			{
				// The tank is now dead
				Tank *damagedTank = (Tank *) damagedTarget;
				damagedTank->getState().setState(TankState::sDead);

				// This tank has lost a life
				if (damagedTank->getState().getMaxLives() > 0)
				{
					damagedTank->getState().setLives(
						damagedTank->getState().getLives() - 1);
				}
			}
		}
	}

	// Check if the tank needs to fall
	if (checkFall_ && damagedTarget->getAlive())
	{
		// The tank is not dead check if it needs to fall
		Vector &position = damagedTarget->getLife().getTargetPosition();
		if (context_->landscapeMaps->getGroundMaps().
			getInterpHeight(position[0], position[1]) < position[2])
		{
			// Check this tank is not already falling
			if (!damagedTarget->getTargetState().getFalling())
			{
				Parachute *parachute = 0;
				Accessory *paraAccessory = 
					damagedTarget->getParachute().getCurrentParachute();
				if (paraAccessory)
				{
					parachute = (Parachute *) paraAccessory->getAction();
				}

				// Tank falling
				context_->actionController->addAction(
					new TankFalling(weapon_, damagedPlayerId_, weaponContext_,
						parachute));
			}
		}
	}

	if (!damagedTarget->getAlive())
	{
		// Remove from groups
		context_->landscapeMaps->getGroundMaps().getGroups().
			removeFromGroups(&damagedTarget->getGroup());	
	}

	// DO LAST
	// If the tank is a target, remove the target
	if (!damagedTarget->getAlive() &&
		damagedTarget->isTarget())
	{
		Target *removedTarget = 
			context_->targetContainer->
				removeTarget(damagedTarget->getPlayerId());
		delete removedTarget;
	}
}

void TankDamage::calculateDeath()
{
	Target *killedTarget = 
		context_->targetContainer->getTargetById(damagedPlayerId_);
	if (!killedTarget) return;

	// Log the death
	logDeath();

	// Add the tank death explosion
	// Make the tank explode in one of many ways
	Weapon *weapon = killedTarget->getDeathAction();
	if (weapon)
	{
		Vector position = killedTarget->getLife().getTargetPosition();
		Vector velocity;
		WeaponFireContext weaponContext(weaponContext_.getPlayerId(), 
			Weapon::eDataDeathAnimation);
		weapon->fireWeapon(*context_, weaponContext, 
			position, velocity);
		StatsLogger::instance()->weaponFired(weapon, true);
	}
}

void TankDamage::logDeath()
{
	unsigned int firedPlayerId = weaponContext_.getPlayerId();

	Target *killedTarget = 
		context_->targetContainer->getTargetById(damagedPlayerId_);
	if (killedTarget->isTarget()) return;

	// Print the banner on who killed who
	GLTexture *weaponTexture = 0;
#ifndef S3D_SERVER
	if (!context_->serverMode)
	{
		Accessory *accessory = 
			context_->accessoryStore->
			findByAccessoryId(weapon_->getParent()->getAccessoryId());
		if (accessory)
		{
			weaponTexture = accessory->getTexture();
		}
	}
#endif // #ifndef S3D_SERVER

	Tank *killedTank = (Tank *) killedTarget;

	if (killedTank->getDestinationId() == 0)
	{
		const char *line = TankAIStrings::instance()->getDeathLine(
			context_->actionController->getRandom());
		if (line)
		{
			context_->actionController->addAction(
				new TankSay(killedTank->getPlayerId(), line));
		}
	}

	Tank *firedTank = 
		context_->tankContainer->getTankById(firedPlayerId);
	if (firedTank)
	{
		if (damagedPlayerId_ == firedPlayerId)
		{
			StatsLogger::instance()->
				tankSelfKilled(firedTank, weapon_);
			StatsLogger::instance()->
				weaponKilled(weapon_, (weaponContext_.getData() & Weapon::eDataDeathAnimation));
			if (!context_->serverMode)
			{
				ChannelText text("combat", 
					formatString("[p:%s] killed self with a [w:%s]",
						killedTank->getName(),
						weapon_->getParent()->getName()));
				//info.setPlayerId(firedPlayerId);
				//info.setOtherPlayerId(damagedPlayerId_);
				//info.setIcon(weaponTexture);
				ChannelManager::showText(text);
			}
		}
		else if ((context_->optionsGame->getTeams() > 1) &&
				(firedTank->getTeam() == killedTank->getTeam())) 
		{
			StatsLogger::instance()->
				tankTeamKilled(firedTank, killedTank, weapon_);
			StatsLogger::instance()->
				weaponKilled(weapon_, (weaponContext_.getData() & Weapon::eDataDeathAnimation));
			if (!context_->serverMode)
			{
				ChannelText text("combat", 
					formatString("[p:%s] team killed [p:%s] with a [w:%s]",
						firedTank->getName(),
						killedTank->getName(),
						weapon_->getParent()->getName()));
				//info.setPlayerId(firedPlayerId);
				//info.setOtherPlayerId(damagedPlayerId_);
				//info.setIcon(weaponTexture);
				ChannelManager::showText(text);
			}
		}
		else
		{
			StatsLogger::instance()->
				tankKilled(firedTank, killedTank, weapon_);
			StatsLogger::instance()->
				weaponKilled(weapon_, (weaponContext_.getData() & Weapon::eDataDeathAnimation));
			if (!context_->serverMode)
			{
				ChannelText text("combat", 
					formatString("[p:%s] %skilled [p:%s] with a [w:%s]",
					firedTank->getName(),
					((firedTank->getScore().getTurnKills() > 1)?"multi-":""),
					killedTank->getName(),
					weapon_->getParent()->getName()));
				//info.setPlayerId(firedPlayerId);
				//info.setOtherPlayerId(damagedPlayerId_);
				//info.setIcon(weaponTexture);
				ChannelManager::showText(text);
			}
		}
	}
	else if (firedPlayerId == 0)
	{
		static Tank firedTank(*context_, 0, 0, "Environment", 
			Vector::nullVector, "", "");
		firedTank.setUniqueId("Environment");
		StatsLogger::instance()->
			tankKilled(&firedTank, killedTank, weapon_); 
		StatsLogger::instance()->
			weaponKilled(weapon_, (weaponContext_.getData() & Weapon::eDataDeathAnimation));
		if (!context_->serverMode)
		{
			ChannelText text("combat", 
					formatString("[p:%s] %skilled [p:%s] with a [w:%s]",
				firedTank.getName(),
				((firedTank.getScore().getTurnKills() > 1)?"multi-":""),
				killedTank->getName(),
				weapon_->getParent()->getName()));
			//info.setPlayerId(firedPlayerId);
			//info.setOtherPlayerId(damagedPlayerId_);
			//info.setIcon(weaponTexture);
			ChannelManager::showText(text);
		}
	}
}




See more files for this project here

Scorched 3D

Scorched3D is a 3D remake of the popular 2D artillery game Scorched Earth.\r\nScorched3D can be played against the computer, other players and remotely across the internet or LAN.

Project homepage: http://sourceforge.net/projects/scorched3d
Programming language(s): C,C++,XML
License: gpl2

  AddTarget.cpp
  AddTarget.h
  Animation.cpp
  Animation.h
  CallbackWeapon.cpp
  CallbackWeapon.h
  CameraPositionAction.cpp
  CameraPositionAction.h
  Explosion.cpp
  Explosion.h
  Laser.cpp
  Laser.h
  Lightning.cpp
  Lightning.h
  Napalm.cpp
  Napalm.h
  Resurrection.cpp
  Resurrection.h
  ShieldHit.cpp
  ShieldHit.h
  ShotBounce.cpp
  ShotBounce.h
  ShotProjectile.cpp
  ShotProjectile.h
  SkyFlash.cpp
  SkyFlash.h
  SoundAction.cpp
  SoundAction.h
  TankDamage.cpp
  TankDamage.h
  TankFalling.cpp
  TankFalling.h
  TankFired.cpp
  TankFired.h
  TankMovement.cpp
  TankMovement.h
  TankResign.cpp
  TankResign.h
  TankSay.cpp
  TankSay.h
  Teleport.cpp
  Teleport.h