diff --git a/data/mp/stats/weapons.json b/data/mp/stats/weapons.json index 95105c31e08..ae118ea66c0 100644 --- a/data/mp/stats/weapons.json +++ b/data/mp/stats/weapons.json @@ -641,8 +641,10 @@ "Bomb6-VTOL-EMP": { "buildPoints": 1000, "buildPower": 225, + "damage": 200, "designable": 1, "effectSize": 100, + "empRadius": 512, "facePlayer": 1, "firePause": 10, "flightGfx": "FXLBMBE2.PIE", @@ -662,7 +664,8 @@ "name": "VTOL EMP Missile Launcher", "numAttackRuns": 1, "numExplosions": 1, - "radius": 512, + "radius": 256, + "radiusDamage": 200, "radiusLife": 10, "recoilValue": 10, "rotate": 180, @@ -1867,6 +1870,7 @@ "damage": 70, "designable": 1, "effectSize": 100, + "empRadius": 192, "facePlayer": 1, "firePause": 130, "flightGfx": "FXBeam.PIE", @@ -1887,7 +1891,8 @@ "muzzleGfx": "FXHBLas.PIE", "name": "EMP Cannon", "numExplosions": 1, - "radius": 192, + "radius": 128, + "radiusDamage": 20, "recoilValue": 150, "rotate": 180, "shortHit": 70, @@ -3463,9 +3468,10 @@ "MortarEMP": { "buildPoints": 1000, "buildPower": 200, - "damage": 60, + "damage": 40, "designable": 1, "effectSize": 100, + "empRadius": 160, "facePlayer": 1, "fireOnMove": 0, "firePause": 90, @@ -3488,7 +3494,7 @@ "name": "EMP Mortar", "numExplosions": 1, "radius": 160, - "radiusDamage": 60, + "radiusDamage": 30, "radiusLife": 10, "recoilValue": 150, "shortHit": 40, diff --git a/src/combat.cpp b/src/combat.cpp index d84cb3a9f44..193cd0e0eb3 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -400,7 +400,7 @@ int objArmour(const 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, int minDamage) +int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond, int minDamage, bool empRadiusHit) { int level = 1; int armour = objArmour(psObj, weaponClass); @@ -415,8 +415,8 @@ int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAP psObj->lastHitWeapon = weaponSubClass; } - // EMP cannons do no damage, if we are one return now - if (weaponSubClass == WSC_EMP) + // EMP weapon radius should not do actual damage + if (weaponSubClass == WSC_EMP && empRadiusHit) { return 0; } @@ -508,12 +508,6 @@ unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BA 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); armour = objArmour(psTarget, psStats->weaponClass); diff --git a/src/combat.h b/src/combat.h index f2faede22f2..da45e87bd8e 100644 --- a/src/combat.h +++ b/src/combat.h @@ -33,7 +33,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, int minDamage); +int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond, int minDamage, bool empRadiusHit); unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BASE_OBJECT *psTarget); diff --git a/src/droid.cpp b/src/droid.cpp index 0c4c28eba9c..31f0b3ec014 100644 --- a/src/droid.cpp +++ b/src/droid.cpp @@ -274,7 +274,7 @@ void addDroidDeathAnimationEffect(DROID *psDroid) * \return > 0 when the dealt damage destroys the droid, < 0 when the droid survives * */ -int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage) +int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage, bool empRadiusHit) { int32_t relativeDamage; @@ -286,7 +286,7 @@ int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, W damage *= 3; } - relativeDamage = objDamage(psDroid, damage, psDroid->originalBody, weaponClass, weaponSubClass, isDamagePerSecond, minDamage); + relativeDamage = objDamage(psDroid, damage, psDroid->originalBody, weaponClass, weaponSubClass, isDamagePerSecond, minDamage, empRadiusHit); if (relativeDamage > 0) { @@ -862,7 +862,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, BURN_MIN_DAMAGE); + droidDamage(psDroid, BURN_DAMAGE, WC_HEAT, WSC_FLAME, gameTime - deltaGameTime / 2 + 1, true, BURN_MIN_DAMAGE, false); } } diff --git a/src/droid.h b/src/droid.h index 44fe25253d1..bdc974e42e0 100644 --- a/src/droid.h +++ b/src/droid.h @@ -115,7 +115,7 @@ UDWORD calcTemplatePower(const 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, int minDamage); +int32_t droidDamage(DROID *psDroid, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage, bool empRadiusHit); /* The main update routine for all droids */ void droidUpdate(DROID *psDroid); diff --git a/src/feature.cpp b/src/feature.cpp index ef0d207b9e4..b66c75c32ad 100644 --- a/src/feature.cpp +++ b/src/feature.cpp @@ -155,7 +155,7 @@ void featureStatsShutDown() * \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, int minDamage) +int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage, bool empRadiusHit) { int32_t relativeDamage; @@ -164,7 +164,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, minDamage); + relativeDamage = objDamage(psFeature, damage, psFeature->psStats->body, weaponClass, weaponSubClass, isDamagePerSecond, minDamage, empRadiusHit); // If the shell did sufficient damage to destroy the feature if (relativeDamage < 0) diff --git a/src/feature.h b/src/feature.h index 0c0251b3160..66fff893440 100644 --- a/src/feature.h +++ b/src/feature.h @@ -56,7 +56,7 @@ bool destroyFeature(FEATURE *psDel, unsigned impactTime); /* get a feature stat id from its name */ SDWORD getFeatureStatFromName(const WzString &name); -int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage); +int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage, bool empRadiusHit); void featureInitVars(); diff --git a/src/projectile.cpp b/src/projectile.cpp index 593623ea75d..a4f774faae0 100644 --- a/src/projectile.cpp +++ b/src/projectile.cpp @@ -88,6 +88,7 @@ struct DAMAGE unsigned impactTime; bool isDamagePerSecond; int minDamage; + bool empRadiusHit; }; // Watermelon:they are from droid.c @@ -962,6 +963,86 @@ static void proj_InFlightFunc(PROJECTILE *psProj) /***************************************************************************/ +static void proj_radiusSweep(PROJECTILE *psObj, WEAPON_STATS *psStats, DROID *destDroid, Vector3i &targetPos, bool empRadius) +{ + static GridList gridList; // static to avoid allocations. + gridList = gridStartIterate(targetPos.x, targetPos.y, (empRadius) ? psStats->upgrade[psObj->player].empRadius : psStats->upgrade[psObj->player].radius); + + for (GridIterator gi = gridList.begin(); gi != gridList.end(); ++gi) + { + BASE_OBJECT *psCurr = *gi; + if (psCurr->died) + { + ASSERT(psCurr->type < OBJ_NUM_TYPES, "Bad pointer! type=%u", psCurr->type); + continue; // Do not damage dead objects further. + } + + if (psCurr == psObj->psDest) + { + continue; // Don't hit main target twice. + } + + if (psObj->psSource && psObj->psSource->player == psCurr->player && psStats->flags.test(WEAPON_FLAG_NO_FRIENDLY_FIRE)) + { + continue; // this weapon does not do friendly damage + } + + bool bTargetInAir = false; + bool useSphere = false; + bool damageable = true; + switch (psCurr->type) + { + case OBJ_DROID: + bTargetInAir = asPropulsionTypes[asPropulsionStats[((DROID *)psCurr)->asBits[COMP_PROPULSION]].propulsionType].travel == AIR && ((DROID *)psCurr)->sMove.Status != MOVEINACTIVE; + useSphere = true; + break; + case OBJ_STRUCTURE: + break; + case OBJ_FEATURE: + damageable = ((FEATURE *)psCurr)->psStats->damageable; + break; + default: ASSERT(false, "Bad type."); continue; + } + + if (!damageable) + { + continue; // Ignore features that are not damageable. + } + unsigned targetInFlag = bTargetInAir ? SHOOT_IN_AIR : SHOOT_ON_GROUND; + if ((psStats->surfaceToAir & targetInFlag) == 0) + { + continue; // Target in air, and can't shoot at air, or target on ground, and can't shoot at ground. + } + if (useSphere && !Vector3i_InSphere(psCurr->pos, targetPos, (empRadius) ? psStats->upgrade[psObj->player].empRadius : psStats->upgrade[psObj->player].radius)) + { + continue; // Target out of range. + } + // The psCurr will get damaged, at this point. + unsigned damage = calcDamage(weaponRadDamage(psStats, psObj->player), psStats->weaponEffect, psCurr); + debug(LOG_ATTACK, "Damage to object %d, player %d : %u", psCurr->id, psCurr->player, damage); + if (bMultiPlayer && psObj->psSource != nullptr && psCurr->type != OBJ_FEATURE) + { + updateMultiStatsDamage(psObj->psSource->player, psCurr->player, damage); + } + + struct DAMAGE sDamage = { + psObj, + psCurr, + damage, + psStats->weaponClass, + psStats->weaponSubClass, + psObj->time, + false, + (int)psStats->upgrade[psObj->player].minimumDamage, + empRadius + }; + + objectDamage(&sDamage); + } +} + +/***************************************************************************/ + static void proj_ImpactFunc(PROJECTILE *psObj) { WEAPON_STATS *psStats; @@ -970,6 +1051,7 @@ static void proj_ImpactFunc(PROJECTILE *psObj) Vector3i position, scatter; iIMDShape *imd; BASE_OBJECT *temp; + bool hasRadius, hasEMPRadius; ASSERT_OR_RETURN(, psObj != nullptr, "Invalid pointer"); CHECK_PROJECTILE(psObj); @@ -1152,7 +1234,8 @@ static void proj_ImpactFunc(PROJECTILE *psObj) psStats->weaponSubClass, psObj->time, false, - (int)psStats->upgrade[psObj->player].minimumDamage + (int)psStats->upgrade[psObj->player].minimumDamage, + false }; // Damage the object @@ -1178,7 +1261,9 @@ static void proj_ImpactFunc(PROJECTILE *psObj) return; } - if (psStats->upgrade[psObj->player].radius != 0) + hasRadius = psStats->upgrade[psObj->player].radius != 0; + hasEMPRadius = psStats->upgrade[psObj->player].empRadius != 0; + if (hasRadius || hasEMPRadius) { /* An area effect bullet */ psObj->state = PROJ_POSTIMPACT; @@ -1187,81 +1272,16 @@ static void proj_ImpactFunc(PROJECTILE *psObj) psObj->born = gameTime; // If projectile impacts a droid start the splash damage from the center of it, else use whatever location the projectile impacts at as the splash center. - auto destDroid = castDroid(psObj->psDest); + DROID *destDroid = castDroid(psObj->psDest); Vector3i targetPos = (destDroid != nullptr) ? destDroid->pos : psObj->pos; - static GridList gridList; // static to avoid allocations. - gridList = gridStartIterate(targetPos.x, targetPos.y, psStats->upgrade[psObj->player].radius); - - for (GridIterator gi = gridList.begin(); gi != gridList.end(); ++gi) + if (hasEMPRadius && psStats->weaponSubClass == WSC_EMP) { - BASE_OBJECT *psCurr = *gi; - if (psCurr->died) - { - ASSERT(psCurr->type < OBJ_NUM_TYPES, "Bad pointer! type=%u", psCurr->type); - continue; // Do not damage dead objects further. - } - - if (psCurr == psObj->psDest) - { - continue; // Don't hit main target twice. - } - - if (psObj->psSource && psObj->psSource->player == psCurr->player && psStats->flags.test(WEAPON_FLAG_NO_FRIENDLY_FIRE)) - { - continue; // this weapon does not do friendly damage - } - - bool bTargetInAir = false; - bool useSphere = false; - bool damageable = true; - switch (psCurr->type) - { - case OBJ_DROID: - bTargetInAir = asPropulsionTypes[asPropulsionStats[((DROID *)psCurr)->asBits[COMP_PROPULSION]].propulsionType].travel == AIR && ((DROID *)psCurr)->sMove.Status != MOVEINACTIVE; - useSphere = true; - break; - case OBJ_STRUCTURE: - break; - case OBJ_FEATURE: - damageable = ((FEATURE *)psCurr)->psStats->damageable; - break; - default: ASSERT(false, "Bad type."); continue; - } - - if (!damageable) - { - continue; // Ignore features that are not damageable. - } - unsigned targetInFlag = bTargetInAir ? SHOOT_IN_AIR : SHOOT_ON_GROUND; - if ((psStats->surfaceToAir & targetInFlag) == 0) - { - continue; // Target in air, and can't shoot at air, or target on ground, and can't shoot at ground. - } - if (useSphere && !Vector3i_InSphere(psCurr->pos, targetPos, psStats->upgrade[psObj->player].radius)) - { - continue; // Target out of range. - } - // The psCurr will get damaged, at this point. - unsigned damage = calcDamage(weaponRadDamage(psStats, psObj->player), psStats->weaponEffect, psCurr); - debug(LOG_ATTACK, "Damage to object %d, player %d : %u", psCurr->id, psCurr->player, damage); - if (bMultiPlayer && psObj->psSource != nullptr && psCurr->type != OBJ_FEATURE) - { - updateMultiStatsDamage(psObj->psSource->player, psCurr->player, damage); - } - - struct DAMAGE sDamage = { - psObj, - psCurr, - damage, - psStats->weaponClass, - psStats->weaponSubClass, - psObj->time, - false, - (int)psStats->upgrade[psObj->player].minimumDamage - }; - - objectDamage(&sDamage); + proj_radiusSweep(psObj, psStats, destDroid, targetPos, true); + } + if (hasRadius) + { + proj_radiusSweep(psObj, psStats, destDroid, targetPos, false); } } @@ -1436,7 +1456,8 @@ static void proj_checkPeriodicalDamage(PROJECTILE *psProj) psStats->periodicalDamageWeaponSubClass, gameTime - deltaGameTime / 2 + 1, true, - (int)psStats->upgrade[psProj->player].minimumDamage + (int)psStats->upgrade[psProj->player].minimumDamage, + false }; objectDamage(&sDamage); @@ -1581,15 +1602,15 @@ static int32_t objectDamageDispatch(DAMAGE *psDamage) switch (psDamage->psDest->type) { case OBJ_DROID: - return droidDamage((DROID *)psDamage->psDest, psDamage->damage, psDamage->weaponClass, psDamage->weaponSubClass, psDamage->impactTime, psDamage->isDamagePerSecond, psDamage->minDamage); + return droidDamage((DROID *)psDamage->psDest, psDamage->damage, psDamage->weaponClass, psDamage->weaponSubClass, psDamage->impactTime, psDamage->isDamagePerSecond, psDamage->minDamage, psDamage->empRadiusHit); break; case OBJ_STRUCTURE: - return structureDamage((STRUCTURE *)psDamage->psDest, psDamage->damage, psDamage->weaponClass, psDamage->weaponSubClass, psDamage->impactTime, psDamage->isDamagePerSecond, psDamage->minDamage); + return structureDamage((STRUCTURE *)psDamage->psDest, psDamage->damage, psDamage->weaponClass, psDamage->weaponSubClass, psDamage->impactTime, psDamage->isDamagePerSecond, psDamage->minDamage, psDamage->empRadiusHit); break; case OBJ_FEATURE: - return featureDamage((FEATURE *)psDamage->psDest, psDamage->damage, psDamage->weaponClass, psDamage->weaponSubClass, psDamage->impactTime, psDamage->isDamagePerSecond, psDamage->minDamage); + return featureDamage((FEATURE *)psDamage->psDest, psDamage->damage, psDamage->weaponClass, psDamage->weaponSubClass, psDamage->impactTime, psDamage->isDamagePerSecond, psDamage->minDamage, psDamage->empRadiusHit); break; case OBJ_PROJECTILE: diff --git a/src/stats.cpp b/src/stats.cpp index 2408597c712..2583b9eb89c 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -415,6 +415,7 @@ bool loadWeaponStats(WzConfig &ini) psStats->base.reloadTime = ini.value("reloadTime").toUInt(); psStats->base.damage = ini.value("damage").toUInt(); psStats->base.minimumDamage = ini.value("minimumDamage", 0).toInt(); + psStats->base.empRadius = ini.value("empRadius", 0).toUInt(); psStats->base.radius = ini.value("radius", 0).toUInt(); psStats->base.radiusDamage = ini.value("radiusDamage", 0).toUInt(); psStats->base.periodicalDamageTime = ini.value("periodicalDamageTime", 0).toUInt(); diff --git a/src/statsdef.h b/src/statsdef.h index 638957d370d..29bfa8c943f 100644 --- a/src/statsdef.h +++ b/src/statsdef.h @@ -405,6 +405,7 @@ struct WEAPON_STATS : public COMPONENT_STATS uint8_t numRounds = 0; ///< The number of rounds per salvo unsigned reloadTime = 0; ///< Time to reload the round of ammo unsigned damage = 0; + unsigned empRadius = 0; ///< EMP blast radius -- does no damage unsigned radius = 0; ///< Basic blast radius of weapon unsigned radiusDamage = 0; ///< "Splash damage" unsigned periodicalDamage = 0; ///< Repeat damage each second after hit diff --git a/src/structure.cpp b/src/structure.cpp index 31b2fb7e720..9647b5c4d58 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -758,7 +758,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, int minDamage) +int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage, bool empRadiusHit) { int32_t relativeDamage; @@ -767,7 +767,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, minDamage); + relativeDamage = objDamage(psStructure, damage, structureBody(psStructure), weaponClass, weaponSubClass, isDamagePerSecond, minDamage, empRadiusHit); // If the shell did sufficient damage to destroy the structure if (relativeDamage < 0) diff --git a/src/structure.h b/src/structure.h index 7f0e3932557..711de4b5aaa 100644 --- a/src/structure.h +++ b/src/structure.h @@ -92,7 +92,7 @@ bool structureStatsShutDown(); int requestOpenGate(STRUCTURE *psStructure); int gateCurrentOpenHeight(const STRUCTURE *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, int minDamage); +int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, unsigned impactTime, bool isDamagePerSecond, int minDamage, bool empRadiusHit); void structureBuild(STRUCTURE *psStructure, DROID *psDroid, int buildPoints, int buildRate = 1); void structureDemolish(STRUCTURE *psStructure, DROID *psDroid, int buildPoints); void structureRepair(STRUCTURE *psStruct, DROID *psDroid, int buildRate); diff --git a/src/wzapi.cpp b/src/wzapi.cpp index 802c5d61504..39d14647adb 100644 --- a/src/wzapi.cpp +++ b/src/wzapi.cpp @@ -3606,6 +3606,10 @@ bool wzapi::setUpgradeStats(WZAPI_BASE_PARAMS(int player, const std::string& nam { psStats->upgrade[player].minimumDamage = value; } + else if (name == "EmpRadius") + { + psStats->upgrade[player].empRadius = value; + } else if (name == "Radius") { psStats->upgrade[player].radius = value; @@ -3927,6 +3931,10 @@ nlohmann::json wzapi::getUpgradeStats(WZAPI_BASE_PARAMS(int player, const std::s { return psStats->upgrade[player].minimumDamage; } + else if (name == "EmpRadius") + { + return psStats->upgrade[player].empRadius; + } else if (name == "Radius") { return psStats->upgrade[player].radius; @@ -4153,6 +4161,7 @@ std::vector wzapi::getUpgradesObject() {"RepeatRadius", COMP_WEAPON}, {"HitPoints", COMP_WEAPON}, {"HitPointPct", COMP_WEAPON}, + {"EmpRadius", COMP_WEAPON}, }); wbase.addRules(psStats->name.toUtf8(), std::move(weap)); } @@ -4330,6 +4339,7 @@ nlohmann::json wzapi::constructStatsObject() weap["RepeatRadius"] = psStats->base.periodicalDamageRadius; weap["RepeatTime"] = psStats->base.periodicalDamageTime; weap["Radius"] = psStats->base.radius; + weap["EmpRadius"] = psStats->base.empRadius; weap["ImpactType"] = psStats->weaponClass == WC_KINETIC ? "KINETIC" : "HEAT"; weap["RepeatType"] = psStats->periodicalDamageWeaponClass == WC_KINETIC ? "KINETIC" : "HEAT"; weap["ImpactClass"] = getWeaponSubClass(psStats->weaponSubClass); diff --git a/src/wzscriptdebug.cpp b/src/wzscriptdebug.cpp index b1c62b33e26..4bca069dbaf 100644 --- a/src/wzscriptdebug.cpp +++ b/src/wzscriptdebug.cpp @@ -444,6 +444,7 @@ nlohmann::ordered_json componentToString(const COMPONENT_STATS *psStats, int pla const WEAPON_STATS *psWeap = (const WEAPON_STATS *)psStats; key["Max range"] = psWeap->upgrade[player].maxRange; key["Min range"] = psWeap->upgrade[player].minRange; + key["EMP Radius"] = psWeap->upgrade[player].empRadius; key["Radius"] = psWeap->upgrade[player].radius; key["Number of Rounds"] = psWeap->upgrade[player].numRounds; key["Damage"] = psWeap->upgrade[player].damage;