Ticket #4421: spread_alpha21.diff
File spread_alpha21.diff, 8.1 KB (added by , 7 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Templates.js
120 120 "hack": getAttackStat("Hack"), 121 121 "pierce": getAttackStat("Pierce"), 122 122 "crush": getAttackStat("Crush"), 123 123 "minRange": getAttackStat("MinRange"), 124 124 "maxRange": getAttackStat("MaxRange"), 125 "elevationBonus": getAttackStat("ElevationBonus") 125 "elevationBonus": getAttackStat("ElevationBonus"), 126 "spread": getAttackStat("Spread") 126 127 }; 127 128 ret.attack[type].elevationAdaptedRange = Math.sqrt(ret.attack[type].maxRange * 128 129 (2 * ret.attack[type].elevationBonus + ret.attack[type].maxRange)); 129 130 } 130 131 ret.attack[type].repeatTime = getAttackStat("RepeatTime"); -
binaries/data/mods/public/gui/common/tooltips.js
15 15 "hack": translate("Hack"), 16 16 "pierce": translate("Pierce"), 17 17 "crush": translate("Crush"), 18 18 }; 19 19 20 const g_RangeTooltipString = { 21 "relative": { 22 "minRange": translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(minRange)s to %(maxRange)s (%(relativeRange)s) %(rangeUnit)s, %(spread)s, %(rate)s"), 23 "no-minRange": translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(maxRange)s (%(relativeRange)s) %(rangeUnit)s, %(spread)s, %(rate)s"), 24 }, 25 "non-relative": { 26 "minRange": translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(minRange)s to %(maxRange)s %(rangeUnit)s, %(spread)s, %(rate)s"), 27 "no-minRange": translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(maxRange)s %(rangeUnit)s, %(spread)s, %(rate)s"), 28 } 29 }; 30 20 31 function costIcon(resource) 21 32 { 22 33 return '[icon="icon_' + resource + '"]'; 23 34 } 24 35 … … 130 141 "damage": dmg[dmgType].toFixed(1), 131 142 "damageType": unitFont(g_DamageTypes[dmgType]) 132 143 })).join(commaFont(translate(", "))); 133 144 } 134 145 135 // TODO: should also show minRange136 146 function getAttackTooltip(template) 137 147 { 138 148 if (!template.attack) 139 149 return ""; 140 150 141 let attacks = [];151 let tooltips = []; 142 152 for (let type in template.attack) 143 153 { 144 154 if (type == "Slaughter") 145 155 continue; // Slaughter is used to kill animals, so do not show it. 146 156 … … 154 164 }); 155 165 156 166 let attackLabel = headerFont(g_AttackTypes[type]); 157 167 if (type == "Capture" || type != "Ranged") 158 168 { 159 attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), {169 tooltips.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), { 160 170 "attackLabel": attackLabel, 161 171 "details": 162 172 type == "Capture" ? 163 173 template.attack.Capture.value : 164 174 damageTypesToText(template.attack[type]), 165 175 "rate": rate 166 176 })); 167 177 continue; 168 178 } 169 179 180 let minRange = Math.round(template.attack[type].minRange); 181 let maxRange = Math.round(template.attack[type].maxRange); 170 182 let realRange = template.attack[type].elevationAdaptedRange; 171 let range = Math.round(template.attack[type].maxRange); 172 let relativeRange = realRange ? Math.round(realRange - range) : 0; 183 let relativeRange = realRange ? Math.round(realRange - maxRange) : 0; 173 184 174 let rangeString = relativeRange ? 175 translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(rangeString)s (%(relative)s), %(rate)s") : 176 translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(rangeString)s, %(rate)s"); 185 // Compare spread at a defined distance 186 let spread = +(+template.attack[type].spread / maxRange * 100).toFixed(1); 177 187 178 attacks.push(sprintf(rangeString, {188 tooltips.push(sprintf(g_RangeTooltipString[relativeRange ? "relative" : "non-relative"][minRange ? "minRange" : "no-minRange"], { 179 189 "attackLabel": attackLabel, 180 190 "damageTypes": damageTypesToText(template.attack[type]), 181 "rangeLabel": translate("Range:"), 182 "rangeString": sprintf( 183 translatePlural("%(range)s %(meters)s", "%(range)s %(meters)s", range), { 184 "range": range, 185 "meters": unitFont(translatePlural("meter", "meters", range)) 186 }), 191 "rangeLabel": headerFont(translate("Range:")), 192 "minRange": minRange, 193 "maxRange": maxRange, 194 "relativeRange": relativeRange > 0 ? "+" + relativeRange : relativeRange, 195 "rangeUnit": 196 unitFont(minRange || relativeRange ? 197 // Translation: For example "0.5 to 1 meters", "1 (+1) meters" or "1 to 2 (+3) meters" 198 translate("meters") : 199 translatePlural("meter", "meters", maxRange)), 187 200 "rate": rate, 188 "relative": relativeRange > 0 ? "+" + relativeRange : relativeRange, 201 "spread": sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", spread), { 202 "label": headerFont(translate("Spread:")), 203 "val": spread, 204 "unit": unitFont(translatePlural("meter", "meters", spread)) 205 }) 189 206 })); 190 207 } 191 return attacks.join("\n");208 return tooltips.join("\n"); 192 209 } 193 210 194 211 function getSplashDamageTooltip(template) 195 212 { 196 213 if (!template.attack) -
binaries/data/mods/public/simulation/components/Attack.js
379 379 "pierce": applyMods("Pierce"), 380 380 "crush": applyMods("Crush") 381 381 }; 382 382 }; 383 383 384 Attack.prototype.GetSpread = function(type) 385 { 386 if (type != "Ranged" || !this.template[type]) 387 return 0; 388 389 let spread = +this.template[type].Spread; 390 return ApplyValueModificationsToEntity("Attack/" + type + "/Spread", spread, this.entity); 391 } 392 384 393 Attack.prototype.GetSplashDamage = function(type) 385 394 { 386 395 if (!this.template[type].Splash) 387 396 return false; 388 397 … … 439 448 return attackBonus; 440 449 }; 441 450 442 451 // Returns a 2d random distribution scaled for a spread of scale 1. 443 452 // The current implementation is a 2d gaussian with sigma = 1 444 Attack.prototype.GetNormalDistribution = function(){ 453 Attack.prototype.GetNormalDistribution = function() 454 { 445 455 446 456 // Use the Box-Muller transform to get a gaussian distribution 447 457 let a = Math.random(); 448 458 let b = Math.random(); 449 459 … … 474 484 475 485 // Get some data about the entity 476 486 let horizSpeed = +this.template[type].ProjectileSpeed; 477 487 let gravity = 9.81; // this affects the shape of the curve; assume it's constant for now 478 488 479 let spread = +this.template.Ranged.Spread;480 spread = ApplyValueModificationsToEntity("Attack/Ranged/Spread", spread, this.entity);481 482 489 //horizSpeed /= 2; gravity /= 2; // slow it down for testing 483 490 484 491 let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 485 492 if (!cmpPosition || !cmpPosition.IsInWorld()) 486 493 return; … … 510 517 511 518 // Compute the real target point (based on spread and target speed) 512 519 let range = this.GetRange(type); 513 520 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 514 521 let elevationAdaptedMaxRange = cmpRangeManager.GetElevationAdaptedRange(selfPosition, cmpPosition.GetRotation(), range.max, range.elevationBonus, 0); 515 let distanceModifiedSpread = spread* horizDistance/elevationAdaptedMaxRange;522 let distanceModifiedSpread = this.GetSpread(type) * horizDistance/elevationAdaptedMaxRange; 516 523 517 524 let randNorm = this.GetNormalDistribution(); 518 525 let offsetX = randNorm[0] * distanceModifiedSpread * (1 + targetVelocity.length() / 20); 519 526 let offsetZ = randNorm[1] * distanceModifiedSpread * (1 + targetVelocity.length() / 20); 520 527 -
binaries/data/mods/public/simulation/components/GuiInterface.js
442 442 if (types.length) 443 443 ret.attack = {}; 444 444 for (let type of types) 445 445 { 446 446 ret.attack[type] = cmpAttack.GetAttackStrengths(type); 447 ret.attack[type].spread = cmpAttack.GetSpread(type); 447 448 ret.attack[type].splash = cmpAttack.GetSplashDamage(type); 448 449 449 450 let range = cmpAttack.GetRange(type); 450 451 ret.attack[type].minRange = range.min; 451 452 ret.attack[type].maxRange = range.max;