scripts/opposed-wng.js
/**
   * Main Opposed test evaluation logic. Takes attacker and defender test data and 
   * determines who won, by how much, etc. Displays who won accordingly, with different
   * logic for manual and targeted opposed tests
   * 
   * @param {Object} attacker Attacker data
   * @param {Object} defender Defender Data
   * @param {Object} options Targeted?
   */
Main Opposed test evaluation logic. Takes attacker and defender test data and
determines who won, by how much, etc. Displays who won accordingly, with different
logic for manual and targeted opposed tests


Main Opposed test evaluation logic . Takes attacker and defender test data and determines who won by how much etc . Displays who won accordingly with different logic for manual and targeted opposed tests
static evaluateOpposedTest(attacker, defender, options = {})
  {
    try
    {
      let opposeResult = {};
      let attackerSL = parseInt(attacker.testResult.SL);
      let defenderSL = parseInt(defender.testResult.SL);
      let differenceSL = 0;
      if (attackerSL > defenderSL || (attackerSL == defenderSL && attacker.testResult.target > defender.testResult.target))
      {
        opposeResult.winner = "attacker"
        differenceSL = attackerSL - defenderSL;
        opposeResult.result =                                                               
          `<b>${attacker.speaker.alias}</b> ${game.i18n.localize("CHAT.OpposedWonAgainst")} <b>${defender.speaker.alias}</b> ${game.i18n.localize("CHAT.By")} ${differenceSL} ${game.i18n.localize("SL")}`
        opposeResult.img = attacker.img;
        opposeResult.speakerAttack = attacker.speaker
        opposeResult.speakerDefend = defender.speaker
        opposeResult.attackerTestResult = duplicate(attacker.testResult);
        opposeResult.defenderTestResult = duplicate(defender.testResult);
        if (!isNaN(opposeResult.attackerTestResult.damage))
        {
          let damageMultiplier = 1;
          let sizeDiff = WNG.actorSizeNums[opposeResult.attackerTestResult.size] - WNG.actorSizeNums[opposeResult.defenderTestResult.size]
          damageMultiplier = sizeDiff >= 2 ? sizeDiff : 1
          if (opposeResult.attackerTestResult.trait)
          {
            if (sizeDiff >= 1)
            {
              let SL = Number(opposeResult.attackerTestResult.SL)
              let unitValue = Number(opposeResult.attackerTestResult.roll.toString().split("").pop())
              if (unitValue == 0)
                unitValue = 10;
              let damageToAdd = unitValue - SL
              if (damageToAdd > 0)
                opposeResult.attackerTestResult.damage += damageToAdd
            }
            if (sizeDiff >= 2)
            {
              let unitValue = Number(opposeResult.attackerTestResult.roll.toString().split("").pop())
              opposeResult.attackerTestResult.damage += unitValue
            }
          }
          opposeResult.damage = {
            description: `<b>${game.i18n.localize("Damage")}</b>: ${(opposeResult.attackerTestResult.damage - defenderSL) * damageMultiplier}`,
            value: (opposeResult.attackerTestResult.damage - defenderSL) * damageMultiplier
          };
        }
        else if (opposeResult.attackerTestResult.weapon || opposeResult.attackerTestResult.trait)
        {
          opposeResult.damage = {
            description: `<b>${game.i18n.localize("Damage")}</b>: ?`,
            value: null
          };
        }
        if (opposeResult.attackerTestResult.hitloc)
          opposeResult.hitloc = {
            description: `<b>${game.i18n.localize("ROLL.HitLocation")}</b>: ${opposeResult.attackerTestResult.hitloc.description}`,
            value: opposeResult.attackerTestResult.hitloc.result
          };
      }
      else 
      {
        opposeResult.winner = "defender"
        differenceSL = defenderSL - attackerSL;   
        opposeResult.result = `<b>${defender.speaker.alias}</b> ${game.i18n.localize("CHAT.OpposedWonAgainst")} <b>${attacker.speaker.alias}</b> ${game.i18n.localize("CHAT.By")} ${differenceSL} ${game.i18n.localize("SL")}`
        opposeResult.img = defender.img
      }
      if (options.target)
      {
        opposeResult.hideData = true;
        renderTemplate("systems/wng/templates/chat/opposed-result.html", opposeResult).then(html =>
        {
          let chatOptions = {
            user: game.user.id,
            content: html,
            "flags.opposeData": opposeResult,
            "flags.startMessageId": options.startMessageId,
          }
          ChatMessage.create(chatOptions)
        })
      }
      else 
      {
        opposeResult.hideData = true;
        renderTemplate("systems/wng/templates/chat/opposed-result.html", opposeResult).then(html =>
        {
          let chatOptions = {
            user: game.user.id,
            content: html,
            "flags.opposeData": opposeResult
          }
          try
          {
            this.startMessage.update(chatOptions).then(resultMsg =>
            {
              ui.chat.updateMessage(resultMsg)
              this.clearOpposed();
            })
          }
          catch
          {
            ChatMessage.create(chatOptions)
            this.clearOpposed();
          }
        })
      }
    }
    catch (err)
    {
      ui.notifications.error(`${game.i18n.localize("Error.Opposed")}: ` + err)
      console.error("Could not complete opposed test: " + err)
      this.clearOpposed()
    }
  }
static evaluateOpposedTest ( attacker , defender , options = { } ) { try { let opposeResult = { } ; let attackerSL = parseInt ( attacker . testResult . SL ) ; let defenderSL = parseInt ( defender . testResult . SL ) ; let differenceSL = 0 ; if ( attackerSL > defenderSL || ( attackerSL == defenderSL && attacker . testResult . target > defender . testResult . target ) ) { opposeResult . winner = "attacker" differenceSL = attackerSL - defenderSL ; opposeResult . result = ` ${ attacker . speaker . alias } ${ game . i18n . localize ( "CHAT.OpposedWonAgainst" ) } ${ defender . speaker . alias } ${ game . i18n . localize ( "CHAT.By" ) } ${ differenceSL } ${ game . i18n . localize ( "SL" ) } ` opposeResult . img = attacker . img ; opposeResult . speakerAttack = attacker . speaker opposeResult . speakerDefend = defender . speaker opposeResult . attackerTestResult = duplicate ( attacker . testResult ) ; opposeResult . defenderTestResult = duplicate ( defender . testResult ) ; if ( ! isNaN ( opposeResult . attackerTestResult . damage ) ) { let damageMultiplier = 1 ; let sizeDiff = WNG . actorSizeNums [ opposeResult . attackerTestResult . size ] - WNG . actorSizeNums [ opposeResult . defenderTestResult . size ] damageMultiplier = sizeDiff >= 2 ? sizeDiff : 1 if ( opposeResult . attackerTestResult . trait ) { if ( sizeDiff >= 1 ) { let SL = Number ( opposeResult . attackerTestResult . SL ) let unitValue = Number ( opposeResult . attackerTestResult . roll . toString ( ) . split ( "" ) . pop ( ) ) if ( unitValue == 0 ) unitValue = 10 ; let damageToAdd = unitValue - SL if ( damageToAdd > 0 ) opposeResult . attackerTestResult . damage += damageToAdd } if ( sizeDiff >= 2 ) { let unitValue = Number ( opposeResult . attackerTestResult . roll . toString ( ) . split ( "" ) . pop ( ) ) opposeResult . attackerTestResult . damage += unitValue } } opposeResult . damage = { description : ` ${ game . i18n . localize ( "Damage" ) } ${ ( opposeResult . attackerTestResult . damage - defenderSL ) * damageMultiplier } ` , value : ( opposeResult . attackerTestResult . damage - defenderSL ) * damageMultiplier } ; } else if ( opposeResult . attackerTestResult . weapon || opposeResult . attackerTestResult . trait ) { opposeResult . damage = { description : ` ${ game . i18n . localize ( "Damage" ) } ` , value : null } ; } if ( opposeResult . attackerTestResult . hitloc ) opposeResult . hitloc = { description : ` ${ game . i18n . localize ( "ROLL.HitLocation" ) } ${ opposeResult . attackerTestResult . hitloc . description } ` , value : opposeResult . attackerTestResult . hitloc . result } ; } else { opposeResult . winner = "defender" differenceSL = defenderSL - attackerSL ; opposeResult . result = ` ${ defender . speaker . alias } ${ game . i18n . localize ( "CHAT.OpposedWonAgainst" ) } ${ attacker . speaker . alias } ${ game . i18n . localize ( "CHAT.By" ) } ${ differenceSL } ${ game . i18n . localize ( "SL" ) } ` opposeResult . img = defender . img } if ( options . target ) { opposeResult . hideData = true ; renderTemplate ( "systems/wng/templates/chat/opposed-result.html" , opposeResult ) . then ( html => { let chatOptions = { user : game . user . id , content : html , "flags.opposeData" : opposeResult , "flags.startMessageId" : options . startMessageId , } ChatMessage . create ( chatOptions ) } ) } else { opposeResult . hideData = true ; renderTemplate ( "systems/wng/templates/chat/opposed-result.html" , opposeResult ) . then ( html => { let chatOptions = { user : game . user . id , content : html , "flags.opposeData" : opposeResult } try { this . startMessage . update ( chatOptions ) . then ( resultMsg => { ui . chat . updateMessage ( resultMsg ) this . clearOpposed ( ) ; } ) } catch { ChatMessage . create ( chatOptions ) this . clearOpposed ( ) ; } } ) } } catch ( err ) { ui . notifications . error ( ` ${ game . i18n . localize ( "Error.Opposed" ) } ` + err ) console . error ( "Could not complete opposed test: " + err ) this . clearOpposed ( ) } }
Main Opposed test evaluation logic.
Main Opposed test evaluation logic .
// If attacker has more SL OR the SLs are equal and the attacker's target number is greater than the defender's, then attacker wins.  // Note: I know this isn't technically correct by the book, where it states you use the tested characteristic/skill, not the target number, i'll be honest, I don't really care. // Update message // A bit of a localization mess - "Attacker won against Defender by X SL" // If Damage is a numerical value // Calculate size damage multiplier  // If the attacker is using a Trait0 to do damage, calculate damaging and impact if necessary // If attacker is using a weapon or trait but there wasn't a numerical damage value, output unknown // Defender won // A bit of a localization mess - "Defender won against attacker by X SL" // If targeting, Create a new result message // If manual - update start message and clear opposed data