CharString GadgetBeamWeapon::useTip( Noun * pTarget, bool shift ) const
{
	if ( shift )
		return "Toggle Point Defense.";
	
	// usage information
	CharString tip;
	float fEnergyMod = calculateModifier( MT_BEAM_ENERGY );
	float fChargeScale = damageRatioInv() * fEnergyMod;
	tip += CharString().format("\nRecharge Time:   <X;100>%.1fs", energyCost() / ( ( energyCharge() * fChargeScale ) * TICKS_PER_SECOND ) );
	tip += CharString().format("\nEnergy Cost:<X;100>%.1f", energyCost() / 1000.0f );
	float fLength = length() * calculateModifier( MT_BEAM_RANGE );
	tip += CharString().format("\nMax Range:<X;100>%.1fgu", fLength );
	
	// direct damage
	float fDamageMod = calculateModifier( MT_BEAM_DAMAGE );
	float fDamage = damage() * fDamageMod;
	if ( damageRandom() > 0 )
	{
		float fMaxDamage = fDamage + (damageRandom() * fDamageMod);
		tip += CharString().format( "\nDamage:<X;100>%.0f-%.0f", fDamage * duration(), fMaxDamage * duration() );
	}
	else
		tip += CharString().format( "\nDamage:<X;100>%.1f", fDamage * duration() );

	return tip;
}
Beispiel #2
0
CharString GadgetArmor::useTip( Noun * pTarget, bool shift ) const
{
	CharString tip;
	
	// usage information
	tip += CharString().format("\nCurrent HP:<X;100>%d/%d", m_Armor, maxArmor() );
	float fMod = ( calculateModifier( MT_DEFENSE ) * 100 ) - 100;
	if ( fMod > 0 )
		tip += CharString().format("\nDamage Reduction:<X;100>%.0f%%", fMod );
	fMod = calculateModifier( MT_DEFENSE_RECHARGE );

	return tip;
}
int GadgetBeamWeapon::useEnergy( dword nTick, int energy )
{
	if ( m_Energy < energyCost() )
	{
		int nElapsed = nTick - m_nEnergyTick;
		m_nEnergyTick = nTick;
		if ( nElapsed < 0 )
			return energy;		// currently firing

		// energy modifier makes weapons charge faster by using more energy.. cooldown gives the same effect 
		float fEnergyMod = calculateModifier( MT_BEAM_ENERGY );
		float fChargeScale = damageRatioInv() * fEnergyMod;

		m_fChargeRate += (fChargeScale * energyCharge()) * nElapsed;
		int chargeRate = floor( m_fChargeRate );
		m_fChargeRate -= chargeRate;		// leave fractional amount in the float for next update..
		int charge = Min( Min( energyCost() - m_Energy, chargeRate ), energy );

		// reduce ship energy
		energy -= charge;
		m_Energy += charge;

		// calculate the signature
		m_Signature = 0.1f * charge;
	}
	else
	{
		m_Signature = 0.0f;
	}
    
	return energy;
}
bool GadgetBeamWeapon::usable( Noun * pTarget, bool shift ) const
{
	if ( shift && allowPointDefense() )
		return true;		// allow point defense to be toggled
	if (! NounGadget::usable( pTarget, shift ) )
		return false;
	if ( pointDefense() && WidgetCast<NounShip>( pTarget ) )
		return false;		// don't waste beams on ships
	if ( WidgetCast<NounShip>( parent() ) )
		if ( ((NounShip *)parent())->testFlags( NounShip::FLAG_CLOAKED|NounShip::FLAG_IN_SAFE_ZONE ) )
			return false;			// weapons are disabled
	if ( pTarget == NULL )
		return false;
	if ( destroyed() )
		return false;
	if ( m_Energy < energyCost() )
		return false;

	Vector3 position( pTarget->worldPosition() );
	float fLength = length() * calculateModifier( MT_BEAM_RANGE );
	if ( ((position - worldPosition()).magnitude() - pTarget->radius()) > fLength )
		return false;

	// finally check the facing of the weapon
	return( checkFacing( position ) );
}
Beispiel #5
0
void NounShip::update()
{
	NounBody::update();

	// reduce signature if any modifiers are attached to do so..
	m_LastSignature *= calculateModifier( MT_SIGNATURE, true );
	// reset repaired damage
	m_nRepairedDamage = 0;
}
Beispiel #6
0
//----------------------------------------------------------------------------
// TODO: add in enhancement data here
void NounShip::updateCharacter()
{
	PROFILE_FUNCTION();

	float m = mass();
	m *=  calculateModifier( MT_MASS );
	if ( m < 1.0f )
		m = 1.0f;

	m_Sensor = baseSensor();
	m_View = baseView();
	m_MaxDamage = baseDamage();
	m_MaxEnergy = baseEnergy();
	m_MaxVelocity = baseVelocity();
	m_MaxCargo = baseCargo();
	m_MaxThrust = baseThrust();

	for(int i=0;i<m_Gadgets.size();i++)
	{
		NounGadget * pGadget = m_Gadgets[i];

		m				+= pGadget->addMass();
		m_Sensor		+= pGadget->addSensor();
		m_MaxVelocity	+= pGadget->addMaxVelocity() * velocityModifier();
		m_MaxDamage		+= pGadget->addMaxDamage();
		m_MaxEnergy		+= pGadget->addMaxEnergy();
		m_MaxCargo		+= pGadget->addCargo();
		m_MaxThrust		+= pGadget->addThrust();
	}

	//calculate the acceleration by taking the thrust and dividing by the mass of the ship
	m_MaxAcceleration = m_MaxThrust / m;
	
	//calculate the turn rate (yaw) by taking the baseYaw(), dividing by the mass of the ship and adding a fraction of m_MaxAcceleration
	m_MaxYaw = (baseYaw() / m) + (m_MaxAcceleration / 10);

	//apply enhancements to ships, including gadget effects
	m_MaxVelocity *=  calculateModifier( MT_DRIVE_VELOCITY );
	m_MaxThrust	*= calculateModifier( MT_DRIVE_THRUST );
	m_MaxYaw *= calculateModifier( MT_TURNRATE );
	m_MaxEnergy *= calculateModifier( MT_SHIPENERGY );
}
Beispiel #7
0
//Проверка отсутствия слишком низких характеристик
bool MainWindow::checkForLowerAbility(QLabel * labelAbility1, QLabel * labelAbility2,
                                      QLabel * labelAbility3, QLabel * labelAbility4,
                                      QLabel * labelAbility5, QLabel * labelAbility6)
{

    if ((calculateModifier(labelAbility1->text().toInt()) + calculateModifier(labelAbility2->text().toInt()) +
         calculateModifier(labelAbility3->text().toInt()) + calculateModifier(labelAbility4->text().toInt()) +
         calculateModifier(labelAbility5->text().toInt()) + calculateModifier(labelAbility6->text().toInt()) > 0) &&
            ((labelAbility1->text().toInt() >= lowerThresholdAbility) || (labelAbility2->text().toInt() >= lowerThresholdAbility) ||
             (labelAbility3->text().toInt() >= lowerThresholdAbility) || (labelAbility4->text().toInt() >= lowerThresholdAbility) ||
             (labelAbility5->text().toInt() >= lowerThresholdAbility) || (labelAbility6->text().toInt() >= lowerThresholdAbility)))
        return true;
    else return false;
}
Beispiel #8
0
int GadgetArmor::deflect( dword nType, int damage, Facing nFacing )
{
	if ( !canDeflect( nType ) )
		return damage;	// doesn't deflect this type of damage
	if ( (facingMountFlags( nFacing ) & mountFlags()) == 0 )
		return damage;	// wrong facing

	float fMod = damageModifier( nType ) * calculateModifier( MT_DEFENSE, true );
	if ( fMod <= 0.0f )
		return 0;		// full damage reflected!	

	int nModifiedDamage = fMod * damage;
	int nDeflected = Min( nModifiedDamage, m_Armor );
	m_Armor -= nDeflected;
	if ( m_Armor > 0 )
		return 0;		// full damage is deflected...

	// return the un-modified damage value..
	return damage - (nDeflected / fMod);
}
Beispiel #9
0
void GadgetArmor::simulate( dword nTick )
{
	if ( nTick >= m_nArmorTick )
	{
		m_nArmorTick = nTick + TICKS_PER_SECOND;
		// repair the armor
		int nMax = maxArmor();
		if ( m_Armor < nMax )
		{
			float fMod = calculateModifier( MT_DEFENSE_RECHARGE );
			m_Armor = Clamp<int>( m_Armor + (repairRate() * fMod), 0, nMax );
		}
	}
	
	if ( nTick >= m_nTipArmorTick )
	{
		m_nTipArmorTick = nTick + ( TICKS_PER_SECOND * 5 );
		m_nDamageRepaired = 0;
	}

	NounGadget::simulate( nTick );
}
Beispiel #10
0
void NounShip::inflictDamage( dword nWhen, Noun * pFrom, int damage, dword type, const Vector3 & direction )
{
	if ( isDestroyed() )		// don't bother if ship is already destroyed!
		return;

	// only increase timer if an enemy is attacking us - we don't want to promote griefing
	if ( isEnemy( pFrom ) )
		setOutOfCombat(); // update combat timer

	// if we are not the server, then halve the damage applied to avoid over estimatation the damage we are
	// inflicting on another ship.. 
	if (! isServer() )
		damage = damage * CLIENT_SIDE_DAMAGE;

	Facing eFacing = getFacing( atan2( direction.x, direction.z ), false );

	// apply any damage modifiers
	damage = damage * calculateModifier( MT_DAMAGE_REDUCTION, true );

	LOG_DEBUG_LOW( "NounShip", CharString().format("Damaged inflicted, When: %u, From: %s, Damage: %d, Type: 0x%X, Facing: %u", 
		nWhen, pFrom != NULL ? pFrom->name() : "NULL", damage, type, eFacing) );

	// callback so AI controlled ships can receive notification that they have been damaged by someone
	onAttacked( pFrom, damage, type );

	// calculate the points we're going to award to the attacker now before shields/armor reduce 
	// the damage applied to the hull.
	float fDamagePoints = float( damage ) / DAMAGE_POINTS_DIV; 

	// check shields
	if( damage > 0 )
	{	
		for(int i=0;i<m_Shields.size();i++)
			damage = m_Shields[i]->deflect( type, damage, eFacing, direction );
	}

	// check armor
	if ( damage > 0 )
	{
		for(int i=0;i<m_Armor.size();i++)
			damage = m_Armor[i]->deflect( type, damage, eFacing );
	}

	int internalDamage = damage;

	// inflict internal damage if hull is 50% or less
	int halfHull = maxDamage() >> 1;
	if ( damage > 0 && m_Damage > halfHull && (type & DAMAGE_EMP) == 0 )
	{
		// once hull is under 50%, start causing internal damage
		type |= DAMAGE_EMP;
		// scale internal damage up based on how much under 50% the hull 
		internalDamage = (damage * (m_Damage - halfHull)) / halfHull;
	}

	if ( damage > 0 && (type & (DAMAGE_EMP|DAMAGE_ELF)) )
	{
		// get the radius of this ship
		float myRadius = radius();
		ASSERT( myRadius > 0.0f );

		// calculate the hit position in object space of this ship
		Vector3 hitPosition( direction );
		hitPosition.normalize();				// direction is not normalized, it's the delta from the projectile/explosion, to the center of the ship
		hitPosition *= -(myRadius * 0.5f);		// flip the direction so it goes away from the center of the ship

		if ( isServer() && m_Gadgets.size() > 0 )
		{
			// seed with the time-stamp of the damage so we get the same gadget damaged
			// on all clients.
			srand( nWhen );
			int nPicked = rand() % m_Gadgets.size();

			NounGadget * pDamageGadget = m_Gadgets[ nPicked ];
			if ( pDamageGadget != NULL )
			{
				float fDistance = (pDamageGadget->position() - hitPosition).magnitude();
				float fScale = (1.0f - (fDistance / myRadius));

				if ( fScale > 0.0f )
					pDamageGadget->inflictDamage( nWhen, pFrom, fScale * internalDamage, type, direction );
			}
		}
	}

	if ( damage > 0 && (type & DAMAGE_ELF) )
	{
		// drain energy from main energy bank
		int drained = Min( energy(), damage );
		setEnergy( energy() - drained );

		// give energy to attacking ship
		if ( WidgetCast<NounShip>( pFrom ) )
			((NounShip *)pFrom)->setEnergy( ((NounShip *)pFrom)->energy() + drained );
	}

	// update the stats if it is another ship - NOTE this needs to happen before the DestroyShip
	// code below otherwise a player who is damaging this ship may not get credit/loot.
	if ( WidgetCast<NounShip>( pFrom ) )
	{
		NounShip * pFromShip = (NounShip *)pFrom;
		ASSERT( pFromShip );

		// set combat timer on attacking ship
		pFromShip->setOutOfCombat();

		// non-hull damages gives a lessor percentage of points..
		if ( damage <= 0 )
			fDamagePoints *= NOHULL_DAMAGE_POINTS_SCALE;

		if (! isFriend( pFrom ) )
		{
			// if the attacking ship is destroyed, then treat this as kamikaze points
			if ( pFromShip->isDestroyed() )
				gameContext()->gameUser()->onKamikaze( pFrom, 1.0f );
			else
				gameContext()->gameUser()->onDamageShip( pFrom, fDamagePoints, this);
		}
		else
		{
			gameContext()->gameUser()->onFriendlyFire( pFrom, fDamagePoints );
		}
	}

	if ( damage > 0 && (type & (DAMAGE_KINETIC|DAMAGE_ENERGY)) )
	{
		ASSERT( context() );

		// cap the damage, 
		damage = Min( maxDamage() - m_Damage, damage );

		// add the damage to the hull
		m_Damage = Min( m_Damage + damage, maxDamage() );
		// update the damage bits
		updateDamageBits();

		// check if the ship was destroyed
		if ( isServer() && isDestroyed() )
		{
			// ship is destroyed, send out verb to destroy this ship to all local clients
			Verb::Ref( new VerbDestroyShip( this, pFrom, false ) );
		}
	}
}
Beispiel #11
0
//Процедура отображения полученных вычислений пользователю
void MainWindow::setupAbilites(QLabel * labelAbility, QLabel * labelAbilityModifier)
{
    labelAbility->setText(QString::number(calculateCandidatToBecomeAbility()));
    labelAbilityModifier->setText(QString::number(calculateModifier(labelAbility->text().toInt())));
}
void GadgetBeamWeapon::render( RenderContext &context, 
					const Matrix33 & frame, 
					const Vector3 & position )
{
	NounGadget::render( context, frame, position );

	// render the beam
	if ( useActive() && m_Target.valid() && m_Duration > 0 )
	{
		Vector3 positionVS( context.worldToView( position ) );
		float fLength = length() * calculateModifier( MT_BEAM_RANGE );
		if (! context.sphereVisible( positionVS, fLength ) )
			return;

		Noun * pTarget = m_Target;
		Vector3 position2( pTarget->worldPosition() );			
		
		if ( ( ( position2 - worldPosition() ).magnitude() - pTarget->radius() ) > fLength )
			return;		
		
		if ( !checkFacing( position2 ) )
			return;

		int tailAlpha = 32;

		if ( m_Hit.valid() )
			tailAlpha = 128;

		Vector3 direction( pTarget->worldPosition() - position );
		Vector3 head( position );
		Vector3 tail( head + direction );

		// calculate the material wrap
		float h = 0.05f;
		float w = 10.0f;

		Material * pTracerMaterial = tracerMaterial();
		if ( pTracerMaterial != NULL )
		{
			h = pTracerMaterial->height();
			w = pTracerMaterial->width();
			Material::push( context, pTracerMaterial );
		}
		else
			Material::push( context, Color(255,0,0), true, PrimitiveMaterial::ADDITIVE );

		float u = (head - tail).magnitude() / w;

		const Vector3	N( 0,0, 0);
		const Vector3	Y( 0, h, 0 );
		const Vector3	X( h, 0, 0 );
		const Color		HC( 255,255,255,255 );
		const Color		TC( 255,255,255,tailAlpha );

		VertexL beamY[4] = 
		{
			VertexL( head + Y, N, HC, u, 0.0f ),
			VertexL( tail + Y, N, TC, 0.0f, 0.0f ),
			VertexL( tail - Y, N, TC, 0.0f, 1.0f ),
			VertexL( head - Y, N, HC, u, 1.0f ),
		};
		VertexL beamX[4] = 
		{
			VertexL( head + X, N, HC, u, 0.0f ),
			VertexL( tail + X, N, TC, 0.0f, 0.0f ),
			VertexL( tail - X, N, TC, 0.0f, 1.0f ),
			VertexL( head - X, N, HC, u, 1.0f ),
		};
		
		DisplayDevice * pDisplay = context.device();
		ASSERT( pDisplay );

		context.pushIdentity();
		PrimitiveTriangleFanDL::push( pDisplay, 4, beamY );
		PrimitiveTriangleFanDL::push( pDisplay, 4, beamX );
	}
}
void GadgetBeamWeapon::simulate( dword nTick )
{
	if ( m_Duration > 0 )
	{
		// reduce the beam duration
		m_Duration--;

		// validate the target
		bool targetValid = false;
		if ( WidgetCast<NounTarget>( m_Target.pointer() ) != NULL )
			targetValid = true;
		else if ( m_Target.valid() && m_Target->zone() != NULL )
			targetValid = true;

		if ( targetValid )
		{
			float fLength = length() * calculateModifier( MT_BEAM_RANGE );
			Vector3 beamOrigin( worldPosition() );
			Vector3 beamEnd( m_Target->worldPosition() );
			Vector3 direction( beamEnd - beamOrigin );
			direction.normalize();
			direction *= fLength;

			// check for collision
			Array< GameContext::NounCollision > check;
			if ( context()->proximityCheck( beamOrigin, fLength, check ) )
			{
				NounGame *		pCollide = NULL;
				float			maxDistance = fLength;
				float			collideDistance = maxDistance;
				Vector3			collidePosition = beamEnd;

				for(int i=0;i<check.size();i++)
				{
					NounGame * pCheck = WidgetCast<NounGame>( check[ i ].pNoun );
					if ( pCheck == NULL )
						continue;		
					if ( pCheck == (Noun *)parent() )
						continue;		// don't collide with our own ship!

					if ( WidgetCast<NounProjectile>( pCheck ) )
						if ( pCheck != m_Target )
							continue;		// don't destroy projectiles that are not our target!
					if ( WidgetCast<NounNebula>( pCheck ) || WidgetCast<NounField>( pCheck ) )
						continue;			// don't collide with nebula or fields

					// object is close, final check
					Vector3 intersect;
					if ( pCheck->intersect( beamOrigin, direction, intersect ) )
					{
						float distance = (beamOrigin - intersect).magnitude();
						if ( distance < collideDistance )
						{
							pCollide = pCheck;
							collideDistance = distance;
							collidePosition = intersect;
						}
					}
				}

				// does the projectile have a valid collision
				if ( pCollide != NULL )
				{
					// create the hit effect
					if ( context()->isClient() )
					{
						if (! m_Hit.valid() )
						{
							// create the hit effect
							SceneryEffect * pHit = new SceneryEffect;
							pHit->setNounContext( new NounContext( hitEffect() ) );
							pHit->setContext( context() );
							pHit->setPosition( collidePosition );
							pHit->setFrame( Matrix33( direction ) );
							pHit->setLife( m_Duration * TICK_DURATION_S );
							context()->attachNoun( pHit );

							// track the current hit effect
							m_Hit = pHit;
						}
						else
						{
							// update the current hit effect position
							m_Hit->setWorldPosition( collidePosition );
						}
					}

					if ( pCollide->canDamage( damageType() ) )
					{
						float fDamageMod = calculateModifier( MT_BEAM_DAMAGE );

						int inflict = damage() * fDamageMod;
						if ( damageFalloff() <= 1 )
						{
							if ( !reverseFalloff() )
							{
								// damage is less with range							
								int falloff = inflict * ( 1.0f - damageFalloff() );
								float scale = 1.0f - ( collideDistance / maxDistance );
								inflict -= scale * falloff;
							}
							else
							{
								// damage is more with range
								int falloff = inflict * damageFalloff();								
								float scale = collideDistance / maxDistance;
								inflict += scale * falloff;
							}
						}

						if ( damageRandom() > 0 )
						{
							int nRandomDamage = (int)(damageRandom() * fDamageMod);
							if ( nRandomDamage > 0 )
								inflict += rand() % nRandomDamage;
						}

						if ( inflict > 0 )		// make sure the falloff didn't negate the damage
						{
							pCollide->inflictDamage( tick(), parentBody(), inflict, damageType(), 
								pCollide->worldFrame() * (collidePosition - pCollide->worldPosition()) );
						}
					}
					else if ( WidgetCast<NounProjectile>( pCollide ) )
					{
						// explode the projectile
						((NounProjectile *)pCollide)->explode();
					}
				}
				else if ( m_Hit.valid() )
				{
					// stop the hit effect
					if ( m_bDetachHitEffect )
						((SceneryEffect *)m_Hit.pointer())->setLife( 0.0f );
					m_Hit = NULL;
				}
			}
		}

		// has the beam finished
		if ( m_Duration <= 0 )
		{
			// stop any hit effect
			if ( m_Hit.valid() )
			{
				if ( m_bDetachHitEffect )
					((SceneryEffect *)m_Hit.pointer())->setLife( 0.0f );
				m_Hit = NULL;
			}
			m_Target = NULL;
		}
	}

	NounGadget::simulate( nTick );
}
Beispiel #14
0
float GadgetScanner::addSensor() const
{
	return active() ? (damageRatioInv() * sensor() * calculateModifier( MT_SCANNER ) ) : 0.0f;
}