function gangUp(attacker, target) {
  const debug_flag=true;

  let itemRange=1; // dist 1''
  let enemies;
  let allies;
  let modifier=0;
  
  let withinRangeOfToken;
  let alliedWithinRangeOfToken;
  let alliedWithinRangeOfTargetAndAttacker;
  
  if (attacker.data.disposition===-1) { // NPC (hostile) is attacking PCs (friendly)
    withinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== attacker.id 
      && t.data.disposition === -1 
      && t.actor.data.data.status.isStunned === false 
      && t.visible 
      && withinRange(target, t, itemRange)
    );    
    alliedWithinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== target.id 
      && t.data.disposition === 1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(target, t, itemRange)
    );    
    //alliedWithinRangeOfTargetAndAttacker intersection with attacker and target
    alliedWithinRangeOfTargetAndAttacker = alliedWithinRangeOfToken.filter(t => 
      t.data.disposition === 1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(attacker, t, itemRange)
    );    
  } else if (attacker.data.disposition===1) { // PCs (friendly) is attacking NPC (hostile)
    withinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== attacker.id 
      && t.data.disposition === 1 
      && t.actor.data.data.status.isStunned === false 
      && t.visible 
      && withinRange(target, t, itemRange)
    );    
    alliedWithinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== target.id 
      && t.data.disposition === -1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(target, t, itemRange)
    );    
    //alliedWithinRangeOfTargetAndAttacker intersection with attacker and target
    alliedWithinRangeOfTargetAndAttacker = alliedWithinRangeOfToken.filter(t => 
      t.data.disposition === -1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(attacker, t, itemRange)
    ); 
  }

  enemies = withinRangeOfToken.length;   
  allies = alliedWithinRangeOfTargetAndAttacker.length;
  modifier = Math.max(0, (enemies-allies) );  

  //debug
  if (debug_flag) {
    console.log('-----------------------');
    console.log('Enemies: ' + withinRangeOfToken.length);
    console.log('Allies: ' + alliedWithinRangeOfToken.length);
    console.log('Allies Adjacent to Both: ' + alliedWithinRangeOfTargetAndAttacker.length);
    console.log('Modifier: ' + modifier);
    console.log('-----------------------');
  }
  return Math.min( 4, modifier );
}
// - Each ally adjacent to the defender cancels out one point of Gang Up bonus from an attacker adjacent to both.
Each ally adjacent to the defender cancels out one point of Gang Up bonus from an attacker adjacent to both.
Each ally adjacent to the defender cancels out one point of Gang Up bonus from an attacker adjacent to both .
function gangUp(attacker, target) {
  const debug_flag=true;
  let itemRange=1; 
  let enemies;
  let allies;
  let modifier=0;
  let withinRangeOfToken;
  let alliedWithinRangeOfToken;
  let alliedWithinRangeOfTargetAndAttacker;
  if (attacker.data.disposition===-1) { 
    withinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== attacker.id 
      && t.data.disposition === -1 
      && t.actor.data.data.status.isStunned === false 
      && t.visible 
      && withinRange(target, t, itemRange)
    );    
    alliedWithinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== target.id 
      && t.data.disposition === 1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(target, t, itemRange)
    );    
    alliedWithinRangeOfTargetAndAttacker = alliedWithinRangeOfToken.filter(t => 
      t.data.disposition === 1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(attacker, t, itemRange)
    );    
  } else if (attacker.data.disposition===1) { 
    withinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== attacker.id 
      && t.data.disposition === 1 
      && t.actor.data.data.status.isStunned === false 
      && t.visible 
      && withinRange(target, t, itemRange)
    );    
    alliedWithinRangeOfToken = canvas.tokens.placeables.filter(t => 
      t.id !== target.id 
      && t.data.disposition === -1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(target, t, itemRange)
    );    
    alliedWithinRangeOfTargetAndAttacker = alliedWithinRangeOfToken.filter(t => 
      t.data.disposition === -1 
      && t.actor.data.data.status.isStunned === false 
      && withinRange(attacker, t, itemRange)
    ); 
  }
  enemies = withinRangeOfToken.length;   
  allies = alliedWithinRangeOfTargetAndAttacker.length;
  modifier = Math.max(0, (enemies-allies) );  
  if (debug_flag) {
    console.log('-----------------------');
    console.log('Enemies: ' + withinRangeOfToken.length);
    console.log('Allies: ' + alliedWithinRangeOfToken.length);
    console.log('Allies Adjacent to Both: ' + alliedWithinRangeOfTargetAndAttacker.length);
    console.log('Modifier: ' + modifier);
    console.log('-----------------------');
  }
  return Math.min( 4, modifier );
}
function gangUp ( attacker , target ) { const debug_flag = true ; let itemRange = 1 ; let enemies ; let allies ; let modifier = 0 ; let withinRangeOfToken ; let alliedWithinRangeOfToken ; let alliedWithinRangeOfTargetAndAttacker ; if ( attacker . data . disposition === - 1 ) { withinRangeOfToken = canvas . tokens . placeables . filter ( t => t . id !== attacker . id && t . data . disposition === - 1 && t . actor . data . data . status . isStunned === false && t . visible && withinRange ( target , t , itemRange ) ) ; alliedWithinRangeOfToken = canvas . tokens . placeables . filter ( t => t . id !== target . id && t . data . disposition === 1 && t . actor . data . data . status . isStunned === false && withinRange ( target , t , itemRange ) ) ; alliedWithinRangeOfTargetAndAttacker = alliedWithinRangeOfToken . filter ( t => t . data . disposition === 1 && t . actor . data . data . status . isStunned === false && withinRange ( attacker , t , itemRange ) ) ; } else if ( attacker . data . disposition === 1 ) { withinRangeOfToken = canvas . tokens . placeables . filter ( t => t . id !== attacker . id && t . data . disposition === 1 && t . actor . data . data . status . isStunned === false && t . visible && withinRange ( target , t , itemRange ) ) ; alliedWithinRangeOfToken = canvas . tokens . placeables . filter ( t => t . id !== target . id && t . data . disposition === - 1 && t . actor . data . data . status . isStunned === false && withinRange ( target , t , itemRange ) ) ; alliedWithinRangeOfTargetAndAttacker = alliedWithinRangeOfToken . filter ( t => t . data . disposition === - 1 && t . actor . data . data . status . isStunned === false && withinRange ( attacker , t , itemRange ) ) ; } enemies = withinRangeOfToken . length ; allies = alliedWithinRangeOfTargetAndAttacker . length ; modifier = Math . max ( 0 , ( enemies - allies ) ) ; if ( debug_flag ) { console . log ( '-----------------------' ) ; console . log ( 'Enemies: ' + withinRangeOfToken . length ) ; console . log ( 'Allies: ' + alliedWithinRangeOfToken . length ) ; console . log ( 'Allies Adjacent to Both: ' + alliedWithinRangeOfTargetAndAttacker . length ) ; console . log ( 'Modifier: ' + modifier ) ; console . log ( '-----------------------' ) ; } return Math . min ( 4 , modifier ) ; }
Each ally adjacent to the defender cancels out one point of Gang Up bonus from an attacker adjacent to both.
Each ally adjacent to the defender cancels out one point of Gang Up bonus from an attacker adjacent to both .
// dist 1'' // NPC (hostile) is attacking PCs (friendly) //alliedWithinRangeOfTargetAndAttacker intersection with attacker and target // PCs (friendly) is attacking NPC (hostile) //alliedWithinRangeOfTargetAndAttacker intersection with attacker and target //debug