Skip to content

Commit

Permalink
Make the minimum damage that a weapon causes configurable, so that va…
Browse files Browse the repository at this point in the history
…rying

degrees of 'armour penetration' ability can be set for each weapon.
  • Loading branch information
perim committed May 25, 2013
1 parent d4ebc6a commit 889ed77
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 24 deletions.
92 changes: 92 additions & 0 deletions data/base/stats/weapons.ini

Large diffs are not rendered by default.

111 changes: 111 additions & 0 deletions data/mp/stats/weapons.ini

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/combat.cpp
Expand Up @@ -369,7 +369,7 @@ int objArmour(BASE_OBJECT *psObj, WEAPON_CLASS weaponClass)
* \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)
int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond, int minDamage)
{
int actualDamage, level = 1, lastHit = psObj->timeLastHit;
int armour = objArmour(psObj, weaponClass);
Expand Down Expand Up @@ -416,8 +416,8 @@ int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAP
// 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);
// Apply at least the minimum damage amount
actualDamage = MAX(actualDamage - armour, actualDamage * minDamage / 100);

// And at least MIN_WEAPON_DAMAGE points
actualDamage = MAX(actualDamage, MIN_WEAPON_DAMAGE);
Expand Down Expand Up @@ -497,7 +497,7 @@ unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BA
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);
actualDamage = MAX(actualDamage - armour, actualDamage * psStats->upgrade[player].minimumDamage / 100);

// And at least MIN_WEAPON_DAMAGE points
actualDamage = MAX(actualDamage, MIN_WEAPON_DAMAGE);
Expand Down
2 changes: 1 addition & 1 deletion src/combat.h
Expand Up @@ -48,7 +48,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
if any support a counter battery sensor*/
void counterBatteryFire(BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget);

int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond);
int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond, int minDamage);

unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BASE_OBJECT *psTarget);

Expand Down
6 changes: 3 additions & 3 deletions src/droid.cpp
Expand Up @@ -210,7 +210,7 @@ int droidReloadBar(BASE_OBJECT *psObj, WEAPON *psWeap, int weapon_slot)
*
* NOTE: This function will damage but _never_ destroy transports when in single player (campaign) mode
*/
int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond)
int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage)
{
int32_t relativeDamage;

Expand All @@ -222,7 +222,7 @@ int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, W
damage *= 3;
}

relativeDamage = objDamage(psDroid, damage, psDroid->originalBody, weaponClass, weaponSubClass, isDamagePerSecond);
relativeDamage = objDamage(psDroid, damage, psDroid->originalBody, weaponClass, weaponSubClass, isDamagePerSecond, minDamage);

if (relativeDamage > 0)
{
Expand Down Expand Up @@ -934,7 +934,7 @@ void droidUpdate(DROID *psDroid)
else
{
// do hardcoded burn damage (this damage automatically applied after periodical damage finished)
droidDamage(psDroid, BURN_DAMAGE, WC_HEAT, WSC_FLAME, gameTime - deltaGameTime/2 + 1, true);
droidDamage(psDroid, BURN_DAMAGE, WC_HEAT, WSC_FLAME, gameTime - deltaGameTime/2 + 1, true, BURN_MIN_DAMAGE);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/droid.h
Expand Up @@ -110,7 +110,7 @@ extern UDWORD calcTemplatePower(DROID_TEMPLATE *psTemplate);
bool idfDroid(DROID *psDroid);

/* Do damage to a droid */
int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond);
int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage);

/* The main update routine for all droids */
extern void droidUpdate(DROID *psDroid);
Expand Down
4 changes: 2 additions & 2 deletions src/feature.cpp
Expand Up @@ -130,7 +130,7 @@ void featureStatsShutDown(void)
* \param weaponClass,weaponSubClass the class and subclass of the weapon that deals the damage
* \return < 0 never, >= 0 always
*/
int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond)
int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage)
{
int32_t relativeDamage;

Expand All @@ -139,7 +139,7 @@ int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponCl
debug(LOG_ATTACK, "feature (id %d): body %d armour %d damage: %d",
psFeature->id, psFeature->body, psFeature->psStats->armourValue, damage);

relativeDamage = objDamage(psFeature, damage, psFeature->psStats->body, weaponClass, weaponSubClass, isDamagePerSecond);
relativeDamage = objDamage(psFeature, damage, psFeature->psStats->body, weaponClass, weaponSubClass, isDamagePerSecond, minDamage);

// If the shell did sufficient damage to destroy the feature
if (relativeDamage < 0)
Expand Down
2 changes: 1 addition & 1 deletion src/feature.h
Expand Up @@ -54,7 +54,7 @@ bool destroyFeature(FEATURE *psDel, unsigned impactTime);
/* get a feature stat id from its name */
extern SDWORD getFeatureStatFromName(const char *pName);

int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond);
int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage);

extern void featureInitVars(void);

Expand Down
20 changes: 12 additions & 8 deletions src/projectile.cpp
Expand Up @@ -111,7 +111,7 @@ static void proj_ImpactFunc( PROJECTILE *psObj );
static void proj_PostImpactFunc( PROJECTILE *psObj );
static void proj_checkPeriodicalDamage(PROJECTILE *psProj);

static int32_t objectDamage(BASE_OBJECT *psObj, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond);
static int32_t objectDamage(BASE_OBJECT *psObj, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage);


static inline void setProjectileDestination(PROJECTILE *psProj, BASE_OBJECT *psObj)
Expand Down Expand Up @@ -1125,7 +1125,8 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
psObj->psDest->id, psObj->psDest->player);

// Damage the object
relativeDamage = objectDamage(psObj->psDest, damage, psStats->weaponClass, psStats->weaponSubClass, psObj->time, false);
relativeDamage = objectDamage(psObj->psDest, damage, psStats->weaponClass, psStats->weaponSubClass,
psObj->time, false, psStats->upgrade[psObj->player].minimumDamage);

proj_UpdateKills(psObj, relativeDamage);

Expand Down Expand Up @@ -1209,7 +1210,8 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
{
updateMultiStatsDamage(psObj->psSource->player, psCurr->player, damage);
}
int relativeDamage = objectDamage(psCurr, damage, psStats->weaponClass, psStats->weaponSubClass, psObj->time, false);
int relativeDamage = objectDamage(psCurr, damage, psStats->weaponClass, psStats->weaponSubClass,
psObj->time, false, psStats->upgrade[psObj->player].minimumDamage);
proj_UpdateKills(psObj, relativeDamage);
}
}
Expand Down Expand Up @@ -1373,7 +1375,9 @@ static void proj_checkPeriodicalDamage(PROJECTILE *psProj)
unsigned damageRate = calcDamage(weaponPeriodicalDamage(psStats,psProj->player), psStats->periodicalDamageWeaponEffect, psCurr);
debug(LOG_NEVER, "Periodical damage of %d per second to object %d, player %d\n", damageRate, psCurr->id, psCurr->player);

int relativeDamage = objectDamage(psCurr, damageRate, psStats->periodicalDamageWeaponClass, psStats->periodicalDamageWeaponSubClass, gameTime - deltaGameTime/2 + 1, true);
int relativeDamage = objectDamage(psCurr, damageRate, psStats->periodicalDamageWeaponClass,
psStats->periodicalDamageWeaponSubClass, gameTime - deltaGameTime/2 + 1, true,
psStats->upgrade[psProj->player].minimumDamage);
proj_UpdateKills(psProj, relativeDamage);
}
}
Expand Down Expand Up @@ -1494,20 +1498,20 @@ UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *ps
* multiplied by -1, resulting in a negative number. Killed features do not
* result in negative numbers.
*/
static int32_t objectDamage(BASE_OBJECT *psObj, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond)
static int32_t objectDamage(BASE_OBJECT *psObj, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage)
{
switch (psObj->type)
{
case OBJ_DROID:
return droidDamage((DROID *)psObj, damage, weaponClass, weaponSubClass, impactTime, isDamagePerSecond);
return droidDamage((DROID *)psObj, damage, weaponClass, weaponSubClass, impactTime, isDamagePerSecond, minDamage);
break;

case OBJ_STRUCTURE:
return structureDamage((STRUCTURE *)psObj, damage, weaponClass, weaponSubClass, impactTime, isDamagePerSecond);
return structureDamage((STRUCTURE *)psObj, damage, weaponClass, weaponSubClass, impactTime, isDamagePerSecond, minDamage);
break;

case OBJ_FEATURE:
return featureDamage((FEATURE *)psObj, damage, weaponClass, weaponSubClass, impactTime, isDamagePerSecond);
return featureDamage((FEATURE *)psObj, damage, weaponClass, weaponSubClass, impactTime, isDamagePerSecond, minDamage);
break;

case OBJ_PROJECTILE:
Expand Down
3 changes: 2 additions & 1 deletion src/projectile.h
Expand Up @@ -39,7 +39,8 @@ extern BASE_OBJECT *g_pProjLastAttacker; ///< The last unit that did damage - us
#define PROJ_ULTIMATE_PITCH 80

#define BURN_TIME 10000 ///< How long an object burns for after leaving a fire.
#define BURN_DAMAGE 15 ///< How much damaga a second an object takes when it is burning.
#define BURN_DAMAGE 15 ///< How much damage per second an object takes when it is burning.
#define BURN_MIN_DAMAGE 30 ///< Least percentage of damage an object takes when burning.
#define ACC_GRAVITY 1000 ///< Downward force against projectiles.

/** How long to display a single electronic warfare shimmmer. */
Expand Down
4 changes: 4 additions & 0 deletions src/qtscriptfuncs.cpp
Expand Up @@ -3946,6 +3946,7 @@ QScriptValue js_stats(QScriptContext *context, QScriptEngine *engine)
else if (name == "Rounds") psStats->upgrade[player].numRounds = value;
else if (name == "ReloadTime") psStats->upgrade[player].reloadTime = value;
else if (name == "Damage") psStats->upgrade[player].damage = value;
else if (name == "MinimumDamage") psStats->upgrade[player].minimumDamage = value;
else if (name == "Radius") psStats->upgrade[player].radius = value;
else if (name == "RadiusDamage") psStats->upgrade[player].radiusDamage = value;
else if (name == "RepeatDamage") psStats->upgrade[player].periodicalDamage = value;
Expand Down Expand Up @@ -4051,6 +4052,7 @@ QScriptValue js_stats(QScriptContext *context, QScriptEngine *engine)
else if (name == "Rounds") return psStats->upgrade[player].numRounds;
else if (name == "ReloadTime") return psStats->upgrade[player].reloadTime;
else if (name == "Damage") return psStats->upgrade[player].damage;
else if (name == "MinimumDamage") return psStats->upgrade[player].minimumDamage;
else if (name == "Radius") return psStats->upgrade[player].radius;
else if (name == "RadiusDamage") return psStats->upgrade[player].radiusDamage;
else if (name == "RepeatDamage") return psStats->upgrade[player].periodicalDamage;
Expand Down Expand Up @@ -4203,6 +4205,7 @@ bool registerFunctions(QScriptEngine *engine, QString scriptName)
weap.setProperty("ReloadTime", psStats->base.reloadTime, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("Rounds", psStats->base.numRounds, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("Damage", psStats->base.damage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("MinimumDamage", psStats->base.minimumDamage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RadiusDamage", psStats->base.radiusDamage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatDamage", psStats->base.periodicalDamage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatRadius", psStats->base.periodicalDamageRadius, QScriptValue::ReadOnly | QScriptValue::Undeletable);
Expand Down Expand Up @@ -4340,6 +4343,7 @@ bool registerFunctions(QScriptEngine *engine, QString scriptName)
setStatsFunc(weap, engine, "Rounds", i, COMP_WEAPON, j, psStats->upgrade[i].numRounds);
setStatsFunc(weap, engine, "Radius", i, COMP_WEAPON, j, psStats->upgrade[i].radius);
setStatsFunc(weap, engine, "Damage", i, COMP_WEAPON, j, psStats->upgrade[i].damage);
setStatsFunc(weap, engine, "MinimumDamage", i, COMP_WEAPON, j, psStats->upgrade[i].minimumDamage);
setStatsFunc(weap, engine, "RadiusDamage", i, COMP_WEAPON, j, psStats->upgrade[i].radiusDamage);
setStatsFunc(weap, engine, "RepeatDamage", i, COMP_WEAPON, j, psStats->upgrade[i].periodicalDamage);
setStatsFunc(weap, engine, "RepeatTime", i, COMP_WEAPON, j, psStats->upgrade[i].periodicalDamageTime);
Expand Down
1 change: 1 addition & 0 deletions src/stats.cpp
Expand Up @@ -315,6 +315,7 @@ bool loadWeaponStats(const char *pFileName)
psStats->base.numRounds = ini.value("numRounds").toUInt();
psStats->base.reloadTime = ini.value("reloadTime").toUInt();
psStats->base.damage = ini.value("damage").toUInt();
psStats->base.minimumDamage = ini.value("minimumDamage", 0).toInt();
psStats->base.radius = ini.value("radius", 0).toUInt();
psStats->base.radiusDamage = ini.value("radiusDamage", 0).toUInt();
psStats->base.periodicalDamageTime = ini.value("periodicalDamageTime", 0).toUInt();
Expand Down
1 change: 1 addition & 0 deletions src/statsdef.h
Expand Up @@ -357,6 +357,7 @@ struct WEAPON_STATS : public COMPONENT_STATS
short periodicalDamage; ///< Repeat damage each second after hit
short periodicalDamageRadius; ///< Repeat damage radius
short periodicalDamageTime; ///< How long the round keeps damaging
short minimumDamage; ///< Minimum amount of damage done, in percentage of damage
} base, upgrade[MAX_PLAYERS];

WEAPON_CLASS periodicalDamageWeaponClass; ///< Periodical damage weapon class by damage type (KINETIC, HEAT)
Expand Down
4 changes: 2 additions & 2 deletions src/structure.cpp
Expand Up @@ -729,7 +729,7 @@ void handleAbandonedStructures()
* \param weaponSubClass the subclass of the weapon that deals the damage
* \return < 0 when the dealt damage destroys the structure, > 0 when the structure survives
*/
int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond)
int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage)
{
int32_t relativeDamage;

Expand All @@ -738,7 +738,7 @@ int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS we
debug(LOG_ATTACK, "structure id %d, body %d, armour %d, damage: %d",
psStructure->id, psStructure->body, objArmour(psStructure, weaponClass), damage);

relativeDamage = objDamage(psStructure, damage, structureBody(psStructure), weaponClass, weaponSubClass, isDamagePerSecond);
relativeDamage = objDamage(psStructure, damage, structureBody(psStructure), weaponClass, weaponSubClass, isDamagePerSecond, minDamage);

// If the shell did sufficient damage to destroy the structure
if (relativeDamage < 0)
Expand Down
2 changes: 1 addition & 1 deletion src/structure.h
Expand Up @@ -90,7 +90,7 @@ extern bool structureStatsShutDown(void);
int requestOpenGate(STRUCTURE *psStructure);
int gateCurrentOpenHeight(STRUCTURE const *psStructure, uint32_t time, int minimumStub); ///< Returns how far open the gate is, or 0 if the structure is not a gate.

int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond);
int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage);
extern void structureBuild(STRUCTURE *psStructure, DROID *psDroid, int buildPoints, int buildRate = 1);
extern void structureDemolish(STRUCTURE *psStructure, DROID *psDroid, int buildPoints);
void structureRepair(STRUCTURE *psStruct, DROID *psDroid, int buildRate);
Expand Down

0 comments on commit 889ed77

Please sign in to comment.