Index: binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/Attack.js +++ binaries/data/mods/public/simulation/components/Attack.js @@ -400,10 +400,10 @@ if (isTargetClass("Domestic") && this.template.Slaughter) return "Slaughter"; - let types = this.GetAttackTypes().filter(type => !this.GetRestrictedClasses(type).some(isTargetClass)); + let attackTypes = this.GetAttackTypes().filter(type => !this.GetRestrictedClasses(type).some(isTargetClass)); // check if the target is capturable - let captureIndex = types.indexOf("Capture"); + let captureIndex = attackTypes.indexOf("Capture"); if (captureIndex != -1) { let cmpCapturable = QueryMiragedInterface(target, IID_Capturable); @@ -412,14 +412,55 @@ if (allowCapture && cmpPlayer && cmpCapturable && cmpCapturable.CanCapture(cmpPlayer.GetPlayerID())) return "Capture"; // not capturable, so remove this attack - types.splice(captureIndex, 1); + attackTypes.splice(captureIndex, 1); } + // Check damage corrected for armour and range. + + let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); + if (!cmpPosition || !cmpPosition.IsInWorld()) + return; + let selfPosition = cmpPosition.GetPosition(); + let cmpTargetPosition = Engine.QueryInterface(target, IID_Position); + if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) + return; + let targetPosition = cmpTargetPosition.GetPosition(); + + let distance = targetPosition.horizDistanceTo(selfPosition); + + let expectedDPSPerType = {}; + let armourStrengths; + let cmpTargetArmour = Engine.QueryInterface(target, IID_DamageReceiver); + if (cmpTargetArmour) + armourStrengths = cmpTargetArmour.GetArmourStrengths(); + + for (let attackType of attackTypes) + { + let expectedDamage = 0; + let damage = this.GetAttackStrengths(attackType); + let damageBonus = GetDamageBonus(this.entity, target, attackType, this.GetBonusTemplate(attackType)) + let maxRange = this.GetRange(attackType)["max"]; + let rangeBonus = Math.min(maxRange, distance); + + for (let damageType in damage) + expectedDamage += damage[damageType] * rangeBonus * damageBonus * Math.pow(0.9, armourStrengths[damageType] || 0); + + expectedDPSPerType[attackType] = expectedDamage / this.GetTimers(attackType)["repeat"]; + } +warn(uneval(expectedDPSPerType)); + let typesDPSSorted = Object.keys(expectedDPSPerType).sort(function(a,b){ + return expectedDPSPerType[a] - expectedDPSPerType[b] + }); +warn(uneval(typesDPSSorted)); + let isPreferred = className => this.GetPreferredClasses(className).some(isTargetClass); - return types.sort((a, b) => - (types.indexOf(a) + (isPreferred(a) ? types.length : 0)) - - (types.indexOf(b) + (isPreferred(b) ? types.length : 0))).pop(); + let chosenType = attackTypes.sort((a, b) => + (attackTypes.indexOf(a) + (isPreferred(a) ? attackTypes.length : 0)) - + (attackTypes.indexOf(b) + (isPreferred(b) ? attackTypes.length : 0))).pop(); +warn(uneval(chosenType)); + + return chosenType; }; Attack.prototype.CompareEntitiesByPreference = function(a, b)