Code Search for Developers
 
 
  

Napalm.cpp from Scorched 3D at Krugle


Show Napalm.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 <engine/ScorchedContext.h>
#include <engine/ActionController.h>
#include <target/TargetContainer.h>
#include <target/TargetDamageCalc.h>
#include <target/TargetRenderer.h>
#include <target/TargetState.h>
#include <target/TargetSpace.h>
#include <actions/Napalm.h>
#include <actions/CameraPositionAction.h>
#ifndef S3D_SERVER
	#include <sprites/ExplosionTextures.h>
	#include <sprites/NapalmRenderer.h>
	#include <GLEXT/GLStateExtension.h>
	#include <landscape/Landscape.h>
	#include <landscape/DeformTextures.h>
	#include <landscape/Smoke.h>
#endif
#include <landscapemap/LandscapeMaps.h>
#include <landscapedef/LandscapeDefinition.h>
#include <landscapedef/LandscapeTex.h>
#include <weapons/AccessoryStore.h>
#include <common/Defines.h>
#include <client/ScorchedClient.h>

static const int deformSize = 3;

Napalm::Napalm(int x, int y, Weapon *weapon, 
	WeaponFireContext &weaponContext) :
	x_(x), y_(y), napalmTime_(0.0f), 
	weapon_((WeaponNapalm *) weapon), 
	weaponContext_(weaponContext), hitWater_(false),
	totalTime_(0.0f), hurtTime_(0.0f),
	counter_(0.1f, 0.1f), set_(0)
{
}

Napalm::~Napalm()
{
}

void Napalm::init()
{
	// Get the NumberParser variables 
	allowedNapalmTime_ = getWeapon()->getNapalmTime(*context_);
	napalmHeight_ = getWeapon()->getNaplamHeight(*context_);
	stepTime_ = getWeapon()->getStepTime(*context_);
	hurtStepTime_ = getWeapon()->getHurtStepTime(*context_);
	hurtPerSecond_ = getWeapon()->getHurtPerSecond(*context_);
	groundScorchPer_ = getWeapon()->getGroundScorchPer(*context_);


	const float ShowTime = 5.0f;
	Vector position((float) x_, (float) y_, context_->landscapeMaps->
		getGroundMaps().getHeight(x_, y_));
#ifndef S3D_SERVER
	if (!context_->serverMode)
	{
		CameraPositionAction *pos = new CameraPositionAction(
			position, ShowTime, 5);
	context_->actionController->addAction(pos);
	}
#endif

#ifndef S3D_SERVER
	if (!context_->serverMode) 
	{
		set_ = ExplosionTextures::instance()->getTextureSetByName(
			weapon_->getNapalmTexture());
	}
#endif // #ifndef S3D_SERVER
}

void Napalm::simulate(float frameTime, bool &remove)
{
#ifndef S3D_SERVER
	if (!context_->serverMode)
	{
		if (!weapon_->getNoSmoke() &&
			counter_.nextDraw(frameTime))
		{
			int count = int(RAND * float(napalmPoints_.size()));

			std::list<Napalm::NapalmEntry *>::iterator itor;
			std::list<Napalm::NapalmEntry *>::iterator endItor = 
				napalmPoints_.end();
			for (itor = napalmPoints_.begin();
					itor != endItor;
					itor++, count--)
			{
				NapalmEntry *entry = (*itor);
				if (count == 0)
				{
					float posZ = 
						ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeight(
						entry->posX, entry->posY);
					Landscape::instance()->getSmoke().
						addSmoke(float(entry->posX), float(entry->posY), posZ);
					break;
				}
			}
		}
	}
#endif // #ifndef S3D_SERVER

	// Add napalm for the period of the time interval
	// once the time interval has expired then start taking it away
	// Once all napalm has disapeared the simulation is over
	totalTime_ += frameTime;
	while (totalTime_ > stepTime_)
	{
		totalTime_ -= stepTime_;
		napalmTime_ += stepTime_;
		if (napalmTime_ < allowedNapalmTime_)
		{
			// Still within the time period, add more napalm
			simulateAddStep();

			// Check for the case where we land in water
			if (napalmPoints_.empty())
			{
				remove = true;
				break;
			}
		}
		else
		{
			// Not within the time period remove napalm
			if (!napalmPoints_.empty())
			{
				simulateRmStep();
			}
			else
			{
				remove = true;
				break;
			}
		}
	}

	// Calculate how much damage to make to the tanks
	hurtTime_ += frameTime;
	while (hurtTime_ > hurtStepTime_)
	{
		hurtTime_ -= hurtStepTime_;

		simulateDamage();
	}

	Action::simulate(frameTime, remove);
}

float Napalm::getHeight(int x, int y)
{
	LandscapeMaps *hmap = context_->landscapeMaps;
	if (x < 0 || y < 0 ||
		x > hmap->getGroundMaps().getMapWidth() ||
		y > hmap->getGroundMaps().getMapHeight())
	{
		// The height at the sides of the landscape is huge
		// so we will never go there with the napalm
		return 9999999.0f;
	}

	// Return the correct height the square + the
	// height of all the napalm on this square
	// the napalm builds up and get higher so
	// we can go over small bumps
	return hmap->getGroundMaps().getHeight(x, y) +
		hmap->getGroundMaps().getNapalmHeight(x, y);
}

void Napalm::simulateRmStep()
{
	// Remove the first napalm point from the list
	// and remove the height from the landscape
	NapalmEntry *entry = napalmPoints_.front();
	napalmPoints_.pop_front();
	int x = entry->posX;
	int y = entry->posY;
	delete entry;

	context_->landscapeMaps->getGroundMaps().getNapalmHeight(x, y) -= napalmHeight_;
}

void Napalm::simulateAddStep()
{
	// Get the height of this point
	float height = getHeight(x_, y_);

	if (!weapon_->getAllowUnderWater())
	{
		// Napalm does not go under water (for now)
		// Perhaps we could add a boiling water sound at some point
		float waterHeight = -10.0f;
		LandscapeTex &tex = *context_->landscapeMaps->getDefinitions().getTex();
		if (tex.border->getType() == LandscapeTexType::eWater)
		{
			LandscapeTexBorderWater *water = 
				(LandscapeTexBorderWater *) tex.border;
       	 	waterHeight = water->height;
		}

		if (height < waterHeight) // Water height
		{
			if (!hitWater_)
			{
				// This is the first time we have hit the water
				hitWater_ = true;
			}
			return;
		}
	} 

	// Add this current point to the napalm map
	RandomGenerator &random = context_->actionController->getRandom();
	int offset = int(random.getRandFloat() * 31.0f);
	NapalmEntry *newEntry = new NapalmEntry(x_, y_, offset);
	napalmPoints_.push_back(newEntry);
#ifndef S3D_SERVER
	if (!context_->serverMode)
	{
		ParticleEmitter emitter;
		emitter.setAttributes(
			allowedNapalmTime_, allowedNapalmTime_,
			0.5f, 1.0f, // Mass
			0.01f, 0.02f, // Friction
			Vector(0.0f, 0.0f, 0.0f), Vector(0.0f, 0.0f, 0.0f), // Velocity
			Vector(1.0f, 1.0f, 1.0f), 0.9f, // StartColor1
			Vector(1.0f, 1.0f, 1.0f), 0.6f, // StartColor2
			Vector(1.0f, 1.0f, 1.0f), 0.0f, // EndColor1
			Vector(1.0f, 1.0f, 1.0f), 0.1f, // EndColor2
			1.5f, 1.5f, 1.5f, 1.5f, // Start Size
			1.5f, 1.5f, 1.5f, 1.5f, // EndSize
			Vector(0.0f, 0.0f, 0.0f), // Gravity
			weapon_->getLuminance(),
			false);
		Vector position1(float(x_) + 0.5f, float(y_) - 0.2f, 0.0f);
		Vector position2(float(x_) - 0.5f, float(y_) - 0.2f, 0.0f);
		Vector position3(float(x_) + 0.0f, float(y_) + 0.5f, 0.0f);
		emitter.emitNapalm(
			position1, 
			ScorchedClient::instance()->getParticleEngine(),
			set_);
		emitter.emitNapalm(
			position2, 
			ScorchedClient::instance()->getParticleEngine(),
			set_);
		emitter.emitNapalm(
			position3, 
			ScorchedClient::instance()->getParticleEngine(),
			set_);
	}
#endif // #ifndef S3D_SERVER

	/*
	if (!weapon_->getNoObjectDamage())
	{
		context_->landscapeMaps->getGroundMaps().getObjects().burnObjects(
			*context_,
			(unsigned int) x_, (unsigned int) y_,
			playerId_);
		context_->landscapeMaps->getGroundMaps().getObjects().burnObjects(
			*context_,
			(unsigned int) x_ + 1, (unsigned int) y_ + 1,
			playerId_);
		context_->landscapeMaps->getGroundMaps().getObjects().burnObjects(
			*context_,
			(unsigned int) x_ - 1, (unsigned int) y_ - 1,
			playerId_);
	}
	*/

	context_->landscapeMaps->getGroundMaps().getNapalmHeight(x_, y_) += napalmHeight_;
	height += napalmHeight_;

#ifndef S3D_SERVER
	if (!context_->serverMode)
	{
		static DeformLandscape::DeformPoints deformMap;
		static bool deformCreated = false;
		if (!deformCreated)
		{
			deformCreated = true;

			Vector center(deformSize + 1, deformSize + 1);
			for (int x=0; x<(deformSize + 1) * 2; x++)
			{
				for (int y=0; y<(deformSize + 1) * 2; y++)
				{
					Vector pos(x, y);
					float dist = (center - pos).Magnitude();
					dist /= deformSize;
					dist = 1.0f - MIN(1.0f, dist);
					deformMap.map[x][y] = dist;
				}
			}
		}

		// Add the ground scorch
		if (!GLStateExtension::getNoTexSubImage())
		{
			if (RAND < groundScorchPer_)
			{
				Vector pos(x_, y_);
				DeformTextures::deformLandscape(pos, 
					(int) (deformSize + 1),
					ExplosionTextures::instance()->getScorchBitmap(
						weapon_->getDeformTexture()),
					deformMap);
			}
		}
	}
#endif // #ifndef S3D_SERVER

	// Calculate every time as the landscape may change
	// due to other actions
	float heightL = getHeight(x_-1, y_);
	float heightR = getHeight(x_+1, y_);
	float heightU = getHeight(x_, y_+1);
	float heightD = getHeight(x_, y_-1);

	// Find the new point to move to (if any)
	// This point must be lower than the current point
	if (heightL < height &&
		heightL < heightR &&
		heightL < heightU &&
		heightL < heightD)
	{
		// Move left
		x_ -= 1;
	}
	else if (heightR < height &&
		heightR < heightL &&
		heightR < heightU &&
		heightR < heightD)
	{
		// Move right
		x_ += 1;
	}
	else if (heightU < height &&
		heightU < heightL &&
		heightU < heightR &&
		heightU < heightD)
	{
		// Move up
		y_ += 1;
	}
	else if (heightD < height)
	{
		// Move down
		y_ -= 1;
	}
	else
	{
		// None of the landscape is currently lower than the current point
		// Just wait, as this point will be now be covered in napalm
		// and may get higher and higher until it is
	}
}

void Napalm::simulateDamage()
{
	const int EffectRadius = weapon_->getEffectRadius();

	// Store how much each tank is damaged
	// Keep in a map so we don't need to create multiple
	// damage actions.  Now we only create one per tank
	static std::map<unsigned int, float> TargetDamageCalc;

	// Add damage into the damage map for each napalm point that is near to
	// the tanks
	std::list<NapalmEntry *>::iterator itor;
	std::list<NapalmEntry *>::iterator endItor = 
		napalmPoints_.end();
	for (itor = napalmPoints_.begin();
		itor != endItor;
		itor++)
	{
		NapalmEntry *entry = (*itor);

		float height = context_->landscapeMaps->getGroundMaps().
			getHeight(entry->posX, entry->posY);
		Vector position(
			float(entry->posX), 
			float(entry->posY),
			height);

		std::map<unsigned int, Target *> collisionTargets;
		context_->targetSpace->getCollisionSet(position, 
			float(EffectRadius), collisionTargets);
		std::map<unsigned int, Target *>::iterator itor;
		for (itor = collisionTargets.begin();
			itor != collisionTargets.end();
			itor++)
		{
			Target *target = (*itor).second;
			if (target->getAlive())
			{
				std::map<unsigned int, float>::iterator damageItor = 
					TargetDamageCalc.find(target->getPlayerId());
				if (damageItor == TargetDamageCalc.end())
				{
					TargetDamageCalc[target->getPlayerId()] = hurtPerSecond_;
				}
				else
				{
					TargetDamageCalc[target->getPlayerId()] += hurtPerSecond_;
				}
			}
		}
	}

	// Add all the damage to the tanks (if any)
	if (!TargetDamageCalc.empty())
	{
		std::map<unsigned int, float>::iterator damageItor;
		for (damageItor = TargetDamageCalc.begin();
			damageItor != TargetDamageCalc.end();
			damageItor++)
		{
			unsigned int playerId = (*damageItor).first;
			float damage = (*damageItor).second;

			Target *target = context_->targetContainer->getTargetById(playerId);
			if (!target) continue;

			// Add damage to the tank
			// If allowed for this target type (mainly for trees)
			if (!target->getTargetState().getNoDamageBurn())
			{
				TargetDamageCalc::damageTarget(*context_, target, weapon_, 
					weaponContext_, damage, true, false, false);
			}

			// Set this target to burnt
			if (target->getRenderer() &&
				!weapon_->getNoObjectDamage())
			{
				target->getRenderer()->targetBurnt();
			}
		}
		TargetDamageCalc.clear();
	}
}




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