Beispiel #1
0
/* Guesses how damage a shot might do.
 * \param psObj object that might be hit
 * \param damage amount of damage to deal
 * \param weaponClass the class of the weapon that deals the damage
 * \param weaponSubClass the subclass of the weapon that deals the damage
 * \param angle angle of impact (from the damage dealing projectile in relation to this object)
 * \return guess at amount of damage
 */
unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BASE_OBJECT *psTarget, HIT_SIDE i)
{
	unsigned int damage;
	int impactSide;
	int	actualDamage, armour = 0, level = 1;

	if (psTarget == NULL)
		return 0;  // Hard to destroy the ground. The armour on the mud is very strong and blocks all damage.

	damage = calcDamage(weaponDamage(psStats, player), psStats->weaponEffect, psTarget);

	// EMP cannons do no damage, if we are one return now
	if (psStats->weaponSubClass == WSC_EMP)
	{
		return 0;
	}


	// apply game difficulty setting
	damage = modifyForDifficultyLevel(damage, psTarget->player != selectedPlayer);

	for (impactSide = 0; impactSide != NUM_HIT_SIDES; ++impactSide)
		armour = MAX(armour, psTarget->armour[impactSide][psStats->weaponClass]);

	//debug(LOG_ATTACK, "objGuessFutureDamage(%d): body %d armour %d damage: %d", psObj->id, psObj->body, armour, damage);

	if (psTarget->type == OBJ_DROID)
	{
		DROID *psDroid = (DROID *)psTarget;

		// Retrieve highest, applicable, experience level
		level = getDroidEffectiveLevel(psDroid);
	}

	// Reduce damage taken by EXP_REDUCE_DAMAGE % for each experience level
	actualDamage = (damage * (100 - EXP_REDUCE_DAMAGE * level)) / 100;

	// You always do at least a third of the experience modified damage
	actualDamage = MAX(actualDamage - armour, actualDamage / 3);

	// And at least MIN_WEAPON_DAMAGE points
	actualDamage = MAX(actualDamage, MIN_WEAPON_DAMAGE);

	//objTrace(psObj->id, "objGuessFutureDamage: Would penetrate %d", actualDamage);

	return actualDamage;
}
Beispiel #2
0
/* Deals damage to an object
 * \param psObj object to deal damage to
 * \param damage amount of damage to deal
 * \param weaponClass the class of the weapon that deals the damage
 * \param weaponSubClass the subclass of the weapon that deals the damage
 * \param angle angle of impact (from the damage dealing projectile in relation to this object)
 * \return < 0 when the dealt damage destroys the object, > 0 when the object survives
 */
int32_t objDamage(BASE_OBJECT *psObj, UDWORD damage, UDWORD originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, HIT_SIDE impactSide)
{
	int	actualDamage, armour, level = 1;

	// If the previous hit was by an EMP cannon and this one is not:
	// don't reset the weapon class and hit time
	// (Giel: I guess we need this to determine when the EMP-"shock" is over)
	if (psObj->lastHitWeapon != WSC_EMP || weaponSubClass == WSC_EMP)
	{
		psObj->timeLastHit = gameTime;
		psObj->lastHitWeapon = weaponSubClass;
	}

	// EMP cannons do no damage, if we are one return now
	if (weaponSubClass == WSC_EMP)
	{
		return 0;
	}


	// apply game difficulty setting
	damage = modifyForDifficultyLevel(damage, psObj->player != selectedPlayer);

	armour = psObj->armour[impactSide][weaponClass];

	debug(LOG_ATTACK, "objDamage(%d): body %d armour %d damage: %d", psObj->id, psObj->body, armour, damage);

	if (psObj->type == OBJ_STRUCTURE || psObj->type == OBJ_DROID)
	{
		// Force sending messages, even if messages were turned off, since a non-synchronised script will execute here. (Aaargh!)
		bool bMultiMessagesBackup = bMultiMessages;
		bMultiMessages = bMultiPlayer;

		clustObjectAttacked((BASE_OBJECT *)psObj);

		bMultiMessages = bMultiMessagesBackup;
	}


	if (psObj->type == OBJ_DROID)
	{
		DROID *psDroid = (DROID *)psObj;

		// Retrieve highest, applicable, experience level
		level = getDroidEffectiveLevel(psDroid);
	}

	// Reduce damage taken by EXP_REDUCE_DAMAGE % for each experience level
	actualDamage = (damage * (100 - EXP_REDUCE_DAMAGE * level)) / 100;

	// You always do at least a third of the experience modified damage
	actualDamage = MAX(actualDamage - armour, actualDamage / 3);

	// And at least MIN_WEAPON_DAMAGE points
	actualDamage = MAX(actualDamage, MIN_WEAPON_DAMAGE);

	objTrace(psObj->id, "objDamage: Penetrated %d", actualDamage);

	// for some odd reason, we have 0 hitpoints.
	if (!originalhp)
	{
		ASSERT(originalhp, "original hitpoints are 0 ?");
		return -65536;  // it is dead
	}

	// If the shell did sufficient damage to destroy the object, deal with it and return
	if (actualDamage >= psObj->body)
	{
		return -(int64_t)65536 * psObj->body / originalhp;
	}

	// Subtract the dealt damage from the droid's remaining body points
	psObj->body -= actualDamage;

	return (int64_t)65536 * actualDamage / originalhp;
}
Beispiel #3
0
/* Deals damage to an object
 * \param psObj object to deal damage to
 * \param damage amount of damage to deal
 * \param weaponClass the class of the weapon that deals the damage
 * \param weaponSubClass the subclass of the weapon that deals the damage
 * \return < 0 when the dealt damage destroys the object, > 0 when the object survives
 */
int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond)
{
	int	actualDamage, armour, level = 1, lastHit = psObj->timeLastHit;

	// If the previous hit was by an EMP cannon and this one is not:
	// don't reset the weapon class and hit time
	// (Giel: I guess we need this to determine when the EMP-"shock" is over)
	if (psObj->lastHitWeapon != WSC_EMP || weaponSubClass == WSC_EMP)
	{
		psObj->timeLastHit = gameTime;
		psObj->lastHitWeapon = weaponSubClass;
	}

	// EMP cannons do no damage, if we are one return now
	if (weaponSubClass == WSC_EMP)
	{
		return 0;
	}

	// apply game difficulty setting
	damage = modifyForDifficultyLevel(damage, psObj->player != selectedPlayer);

	armour = psObj->armour[weaponClass];

	if (psObj->type == OBJ_STRUCTURE || psObj->type == OBJ_DROID)
	{
		if (psObj->type == OBJ_STRUCTURE && ((STRUCTURE *)psObj)->status == SS_BEING_BUILT)
		{
			armour = 0;
		}
		// Force sending messages, even if messages were turned off, since a non-synchronised script will execute here. (Aaargh!)
		bool bMultiMessagesBackup = bMultiMessages;
		bMultiMessages = bMultiPlayer;

		clustObjectAttacked((BASE_OBJECT *)psObj);
		triggerEventAttacked(psObj, g_pProjLastAttacker, lastHit);

		bMultiMessages = bMultiMessagesBackup;
	}
	debug(LOG_ATTACK, "objDamage(%d): body %d armour %d damage: %d", psObj->id, psObj->body, armour, damage);

	if (psObj->type == OBJ_DROID)
	{
		DROID *psDroid = (DROID *)psObj;

		// Retrieve highest, applicable, experience level
		level = getDroidEffectiveLevel(psDroid);
	}

	// Reduce damage taken by EXP_REDUCE_DAMAGE % for each experience level
	actualDamage = (damage * (100 - EXP_REDUCE_DAMAGE * level)) / 100;

	// You always do at least a third of the experience modified damage
	actualDamage = MAX(actualDamage - armour, actualDamage / 3);

	// And at least MIN_WEAPON_DAMAGE points
	actualDamage = MAX(actualDamage, MIN_WEAPON_DAMAGE);

	if (isDamagePerSecond)
	{
		int deltaDamageRate = actualDamage - psObj->burnDamage;
		if (deltaDamageRate <= 0)
		{
			return 0;  // Did this much damage already, this tick, so don't do more.
		}
		actualDamage = gameTimeAdjustedAverage(deltaDamageRate);
		psObj->burnDamage += deltaDamageRate;
	}

	objTrace(psObj->id, "objDamage: Penetrated %d", actualDamage);
	syncDebug("damage%u dam%u,o%u,wc%d.%d,ar%d,lev%d,aDam%d,isDps%d", psObj->id, damage, originalhp, weaponClass, weaponSubClass, armour, level, actualDamage, isDamagePerSecond);

	// for some odd reason, we have 0 hitpoints.
	if (!originalhp)
	{
		ASSERT(originalhp, "original hitpoints are 0 ?");
		return -65536;  // it is dead
	}

	// If the shell did sufficient damage to destroy the object, deal with it and return
	if (actualDamage >= psObj->body)
	{
		return -(int64_t)65536 * psObj->body / originalhp;
	}

	// Subtract the dealt damage from the droid's remaining body points
	psObj->body -= actualDamage;

	syncDebugObject(psObj, 'D');

	return (int64_t)65536 * actualDamage / originalhp;
}