Implements #77
This commit is contained in:
		| @@ -237,6 +237,95 @@ export class PegasusActor extends Actor { | |||||||
|     let role = this.items.filter(item => item.type == 'role') |     let role = this.items.filter(item => item.type == 'role') | ||||||
|     return role[0] ?? []; |     return role[0] ?? []; | ||||||
|   } |   } | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   getRoleLevel() { | ||||||
|  |     let role = this.items.find(item => item.type == 'role') | ||||||
|  |     if (role ) { | ||||||
|  |       console.log("Role", role) | ||||||
|  |       return role.system.rolelevel | ||||||
|  |     } | ||||||
|  |     return 0 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   isTactician() { | ||||||
|  |     let role = this.items.find(item => item.type == 'role') | ||||||
|  |     return role && role.system.perksrole == "tactician" | ||||||
|  |   } | ||||||
|  |   hasTacticianBonus() { | ||||||
|  |     let effect = this.items.find( item => item.name.toLowerCase().includes("tactician bonus dice") ) | ||||||
|  |     return effect | ||||||
|  |   } | ||||||
|  |   async addTacticianEffect(name, level) { | ||||||
|  |     let effect = duplicate(__bonusEffect) | ||||||
|  |     effect.name = `${name} Tactician Bonus Dice` | ||||||
|  |     effect.system.effectlevel = level  | ||||||
|  |     effect.system.stataffected = "all" | ||||||
|  |     effect.system.bonusdice = true | ||||||
|  |     await this.createEmbeddedDocuments('Item', [effect]) | ||||||
|  |     ChatMessage.create({ content: `Tactician Bonus Dice has been added to ${this.name} (${level})` }) | ||||||
|  |   } | ||||||
|  |   async removeTacticianEffect() { | ||||||
|  |     let effect = this.items.find( item => item.name.toLowerCase().includes("tactician bonus dice") ) | ||||||
|  |     if (effect) { | ||||||
|  |       await this.deleteEmbeddedDocuments('Item', [effect.id]) | ||||||
|  |       ChatMessage.create({ content: `Tactician Bonus Dice has been removed to ${this.name}` })   | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   isEnhancer() { | ||||||
|  |     let role = this.items.find(item => item.type == 'role') | ||||||
|  |     return role && role.system.perksrole == "enhancer" | ||||||
|  |   } | ||||||
|  |   hasEnhancerBonus() { | ||||||
|  |     let effect = this.items.find( item => item.name.toLowerCase().includes("enhancer bonus dice") ) | ||||||
|  |     return effect | ||||||
|  |   } | ||||||
|  |   async addEnhancerEffect( name, level) { | ||||||
|  |     let effect = duplicate(__bonusEffect) | ||||||
|  |     effect.name = `${name} Enhancer Bonus Dice ALL` | ||||||
|  |     effect.system.effectlevel = level  | ||||||
|  |     effect.system.stataffected = "all" | ||||||
|  |     effect.system.bonusdice = true | ||||||
|  |     await this.createEmbeddedDocuments('Item', [effect]) | ||||||
|  |     ChatMessage.create({ content: `Enhancer Bonus Dice has been added to ${this.name} (${level})` }) | ||||||
|  |   } | ||||||
|  |   async removeEnhancerEffect() { | ||||||
|  |     let effect = this.items.find( item => item.name.toLowerCase().includes("enhancer bonus dice") ) | ||||||
|  |     if (effect) { | ||||||
|  |       await this.deleteEmbeddedDocuments('Item', [effect.id]) | ||||||
|  |       ChatMessage.create({ content: `Enhancer Bonus Dice has been removed to ${this.name}` })   | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   isAgitator() { | ||||||
|  |     let role = this.items.find(item => item.type == 'role') | ||||||
|  |     return role && role.system.perksrole == "agitator" | ||||||
|  |   } | ||||||
|  |   hasAgitatorHindrance() { | ||||||
|  |     let effect = this.items.find( item => item.name.toLowerCase().includes("hindered by agitator") ) | ||||||
|  |     return effect | ||||||
|  |   } | ||||||
|  |   async addAgitatorHindrance(name, level) { | ||||||
|  |     let effect = duplicate(__bonusEffect) | ||||||
|  |     effect.name = `Hindered by Agitator ${name}` | ||||||
|  |     effect.system.effectlevel = level  | ||||||
|  |     effect.system.stataffected = "all" | ||||||
|  |     effect.system.genre = "negative" | ||||||
|  |     effect.system.hindrance = true | ||||||
|  |     await this.createEmbeddedDocuments('Item', [effect]) | ||||||
|  |     ChatMessage.create({ content: `Agitator Hindrance has been added to ${this.name} (${level})` }) | ||||||
|  |   } | ||||||
|  |   async removeAgitatorHindrance() { | ||||||
|  |     let effect = this.items.find( item => item.name.toLowerCase().includes("hindered by agitator") ) | ||||||
|  |     if (effect) { | ||||||
|  |       await this.deleteEmbeddedDocuments('Item', [effect.id]) | ||||||
|  |       ChatMessage.create({ content: `Agitator Hindrance has been removed to ${this.name}` })   | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   checkAndPrepareEquipment(item) { |   checkAndPrepareEquipment(item) { | ||||||
|     if (item.system.resistance) { |     if (item.system.resistance) { | ||||||
| @@ -379,13 +468,13 @@ export class PegasusActor extends Actor { | |||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   updateSize() { |   updateSize() { | ||||||
|     let sizeBonus = 0 |     let sizeBonus = 0 | ||||||
|     for(let effect of this.items) { |     for (let effect of this.items) { | ||||||
|       if (effect.type == "effect" && effect.system.effectlevel > 0 &&  effect.system.affectsize) { |       if (effect.type == "effect" && effect.system.effectlevel > 0 && effect.system.affectsize) { | ||||||
|         sizeBonus += effect.system.effectlevel |         sizeBonus += effect.system.effectlevel | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (sizeBonus != this.system.biodata.sizebonus) { |     if (sizeBonus != this.system.biodata.sizebonus) { | ||||||
|       this.update( {'system.biodata.sizebonus': sizeBonus}) |       this.update({ 'system.biodata.sizebonus': sizeBonus }) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -1353,7 +1442,7 @@ export class PegasusActor extends Actor { | |||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   parseStatEffects() { |   parseStatEffects() { | ||||||
|     let effects = this.items.filter(effect => effect.type == "effect" && effect.system.genre == "positive" && effect.system.statdice ) |     let effects = this.items.filter(effect => effect.type == "effect" && effect.system.genre == "positive" && effect.system.statdice) | ||||||
|     for (let statKey in this.system.statistics) { |     for (let statKey in this.system.statistics) { | ||||||
|       let stat = duplicate(this.system.statistics[statKey]) |       let stat = duplicate(this.system.statistics[statKey]) | ||||||
|       let bonus = 0 |       let bonus = 0 | ||||||
| @@ -1362,40 +1451,40 @@ export class PegasusActor extends Actor { | |||||||
|           bonus += Number(effect.system.effectlevel) |           bonus += Number(effect.system.effectlevel) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if ( bonus != stat.bonuseffect) { |       if (bonus != stat.bonuseffect) { | ||||||
|         stat.bonuseffect = bonus |         stat.bonuseffect = bonus | ||||||
|         this.update( { [`system.statistics.${statKey}`]: stat} ) |         this.update({ [`system.statistics.${statKey}`]: stat }) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   parseStatusEffects() { |   parseStatusEffects() { | ||||||
|     let effects = this.items.filter(effect => effect.type == "effect" && effect.system.affectstatus && (Number(effect.system.effectlevel) > 0) ) |     let effects = this.items.filter(effect => effect.type == "effect" && effect.system.affectstatus && (Number(effect.system.effectlevel) > 0)) | ||||||
|     for (let statusKey in this.system.secondary) { |     for (let statusKey in this.system.secondary) { | ||||||
|       let status = duplicate(this.system.secondary[statusKey]) |       let status = duplicate(this.system.secondary[statusKey]) | ||||||
|       let bonus = 0 |       let bonus = 0 | ||||||
|       for (let effect of effects) {  |       for (let effect of effects) { | ||||||
|         if ( effect.system.affectedstatus && effect.system.affectedstatus == statusKey) { |         if (effect.system.affectedstatus && effect.system.affectedstatus == statusKey) { | ||||||
|           bonus += Number(effect.system.effectlevel) |           bonus += Number(effect.system.effectlevel) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if ( bonus != status.bonus) { |       if (bonus != status.bonus) { | ||||||
|         status.bonus = bonus |         status.bonus = bonus | ||||||
|         this.update( { [`system.secondary.${statusKey}`]: status} ) |         this.update({ [`system.secondary.${statusKey}`]: status }) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     let nrg = duplicate(this.system.nrg) |     let nrg = duplicate(this.system.nrg) | ||||||
|     let bonus = 0 |     let bonus = 0 | ||||||
|     for (let effect of effects) {  |     for (let effect of effects) { | ||||||
|       if ( effect.system.affectedstatus && effect.system.affectedstatus == "nrg") { |       if (effect.system.affectedstatus && effect.system.affectedstatus == "nrg") { | ||||||
|         bonus += Number(effect.system.effectlevel) |         bonus += Number(effect.system.effectlevel) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if ( bonus != nrg.mod) { |     if (bonus != nrg.mod) { | ||||||
|       nrg.mod = bonus |       nrg.mod = bonus | ||||||
|       this.update( { [`system.nrg`]: nrg} ) |       this.update({ [`system.nrg`]: nrg }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   } |   } | ||||||
| @@ -1635,7 +1724,7 @@ export class PegasusActor extends Actor { | |||||||
|     let effects = this.items.filter(item => item.type == 'effect') |     let effects = this.items.filter(item => item.type == 'effect') | ||||||
|     for (let effect of effects) { |     for (let effect of effects) { | ||||||
|       effect = duplicate(effect) |       effect = duplicate(effect) | ||||||
|       if (!effect.system.hindrance && !effect.system.statdice  |       if (!effect.system.hindrance && !effect.system.statdice | ||||||
|         && (effect.system.stataffected != "notapplicable" || effect.system.specaffected.length > 0) |         && (effect.system.stataffected != "notapplicable" || effect.system.specaffected.length > 0) | ||||||
|         && effect.system.stataffected != "special" |         && effect.system.stataffected != "special" | ||||||
|         && effect.system.stataffected != "powerroll" |         && effect.system.stataffected != "powerroll" | ||||||
| @@ -1728,7 +1817,7 @@ export class PegasusActor extends Actor { | |||||||
|     if (statKey) { |     if (statKey) { | ||||||
|       rollData.statKey = statKey |       rollData.statKey = statKey | ||||||
|       rollData.stat = this.getStat(statKey) |       rollData.stat = this.getStat(statKey) | ||||||
|       if ( rollData.stat.value != undefined ) { |       if (rollData.stat.value != undefined) { | ||||||
|         rollData.stat.level = rollData.stat.value // Normalize |         rollData.stat.level = rollData.stat.value // Normalize | ||||||
|       } |       } | ||||||
|       rollData.statDicesLevel = rollData.stat.level + rollData.stat.bonuseffect |       rollData.statDicesLevel = rollData.stat.level + rollData.stat.bonuseffect | ||||||
| @@ -1790,30 +1879,30 @@ export class PegasusActor extends Actor { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   processSizeBonus( rollData) {  |   processSizeBonus(rollData) { | ||||||
|     if ( rollData.defenderTokenId) { |     if (rollData.defenderTokenId) { | ||||||
|       let diffSize = rollData.defenderSize - this.system.biodata.sizenum+this.system.biodata.sizebonus |       let diffSize = rollData.defenderSize - this.system.biodata.sizenum + this.system.biodata.sizebonus | ||||||
|       //console.log("Diffsize", diffSize) |       //console.log("Diffsize", diffSize) | ||||||
|       if( rollData.subKey == "melee-atk" || rollData.subKey == "ranged-atk")  { |       if (rollData.subKey == "melee-atk" || rollData.subKey == "ranged-atk") { | ||||||
|         if ( diffSize > 0) { |         if (diffSize > 0) { | ||||||
|           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: diffSize }) |           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: diffSize }) | ||||||
|         } |         } | ||||||
|       }  |       } | ||||||
|       if( rollData.subKey == "dmg-res" )  { |       if (rollData.subKey == "dmg-res") { | ||||||
|         if ( diffSize < 0) { |         if (diffSize < 0) { | ||||||
|           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: Math.abs(diffSize) }) |           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: Math.abs(diffSize) }) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if( rollData.subKey == "defence" )  { |       if (rollData.subKey == "defence") { | ||||||
|         if ( diffSize > 0) { |         if (diffSize > 0) { | ||||||
|           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: Math.abs(diffSize) }) |           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: Math.abs(diffSize) }) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       if( rollData.subKey == "melee-dmg" || rollData.subKey == "ranged-dmg" || rollData.subKey == "power-dmg")  { |       if (rollData.subKey == "melee-dmg" || rollData.subKey == "ranged-dmg" || rollData.subKey == "power-dmg") { | ||||||
|         if ( diffSize < 0) { |         if (diffSize < 0) { | ||||||
|           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: Math.abs(diffSize) }) |           rollData.effectsList.push({ label: "Size Bonus", type: "effect", applied: false, isdynamic: true, value: Math.abs(diffSize) }) | ||||||
|         } |         } | ||||||
|       }  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -1922,8 +2011,8 @@ export class PegasusActor extends Actor { | |||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   async rollMR(isInit = false, combatId = 0, combatantId = 0) { |   async rollMR(isInit = false, combatId = 0, combatantId = 0) { | ||||||
|      |  | ||||||
|     let mr = duplicate((this.type =="vehicle") ? this.system.statistics.mr : this.system.mr) |     let mr = duplicate((this.type == "vehicle") ? this.system.statistics.mr : this.system.mr) | ||||||
|     if (mr) { |     if (mr) { | ||||||
|       mr.dice = PegasusUtility.getDiceFromLevel(mr.value); |       mr.dice = PegasusUtility.getDiceFromLevel(mr.value); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -57,8 +57,9 @@ Hooks.once("init", async function () { | |||||||
|   CONFIG.Combat.documentClass = PegasusCombat |   CONFIG.Combat.documentClass = PegasusCombat | ||||||
|   CONFIG.Actor.documentClass = PegasusActor |   CONFIG.Actor.documentClass = PegasusActor | ||||||
|   CONFIG.Item.documentClass = PegasusItem |   CONFIG.Item.documentClass = PegasusItem | ||||||
|   //CONFIG.Token.objectClass = PegasusToken |   game.system.pegasus = {  | ||||||
|   game.system.pegasus = { }; |     utility: PegasusUtility | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
|   // Register sheet application classes |   // Register sheet application classes | ||||||
| @@ -69,8 +70,9 @@ Hooks.once("init", async function () { | |||||||
|   Items.unregisterSheet("core", ItemSheet); |   Items.unregisterSheet("core", ItemSheet); | ||||||
|   Items.registerSheet("fvtt-pegasus", PegasusItemSheet, { makeDefault: true }); |   Items.registerSheet("fvtt-pegasus", PegasusItemSheet, { makeDefault: true }); | ||||||
|  |  | ||||||
|   PegasusUtility.init(); |   PegasusUtility.init() | ||||||
|    |  | ||||||
|  |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
| /* -------------------------------------------- */ | /* -------------------------------------------- */ | ||||||
|   | |||||||
| @@ -23,7 +23,6 @@ export class PegasusUtility { | |||||||
|     Hooks.on('renderChatLog', (log, html, data) => PegasusUtility.chatListeners(html)) |     Hooks.on('renderChatLog', (log, html, data) => PegasusUtility.chatListeners(html)) | ||||||
|     Hooks.on('targetToken', (user, token, flag) => PegasusUtility.targetToken(user, token, flag)) |     Hooks.on('targetToken', (user, token, flag) => PegasusUtility.targetToken(user, token, flag)) | ||||||
|     Hooks.on('renderSidebarTab', (app, html, data) => PegasusUtility.addDiceRollButton(app, html, data)) |     Hooks.on('renderSidebarTab', (app, html, data) => PegasusUtility.addDiceRollButton(app, html, data)) | ||||||
|  |  | ||||||
|     Hooks.on("getCombatTrackerEntryContext", (html, options) => { |     Hooks.on("getCombatTrackerEntryContext", (html, options) => { | ||||||
|       PegasusUtility.pushInitiativeOptions(html, options); |       PegasusUtility.pushInitiativeOptions(html, options); | ||||||
|     }); |     }); | ||||||
| @@ -35,9 +34,10 @@ export class PegasusUtility { | |||||||
|     this.defenderStore = {} |     this.defenderStore = {} | ||||||
|     this.diceList = []; |     this.diceList = []; | ||||||
|     this.diceFoundryList = []; |     this.diceFoundryList = []; | ||||||
|     this.optionsDiceList = ""; |     this.optionsDiceList = "" | ||||||
|     this.buildDiceLists(); |     this.lastRoleEffectProcess = Date.now() | ||||||
|     PegasusCommands.init(); |     this.buildDiceLists() | ||||||
|  |     PegasusCommands.init() | ||||||
|  |  | ||||||
|     Handlebars.registerHelper('count', function (list) { |     Handlebars.registerHelper('count', function (list) { | ||||||
|       return (list) ? list.length : 0; |       return (list) ? list.length : 0; | ||||||
| @@ -269,6 +269,10 @@ export class PegasusUtility { | |||||||
|   static async ready() { |   static async ready() { | ||||||
|     const specs = await PegasusUtility.loadCompendium("fvtt-pegasus-rpg.specialisations"); |     const specs = await PegasusUtility.loadCompendium("fvtt-pegasus-rpg.specialisations"); | ||||||
|     this.specs = specs.map(i => i.toObject()); |     this.specs = specs.map(i => i.toObject()); | ||||||
|  |  | ||||||
|  |     if (game.user.isGM) { | ||||||
|  |       Hooks.on('sightRefresh', (app, html, data) => PegasusUtility.refreshSightForEffect(app, html, data)) | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* -------------------------------------------- */ |   /* -------------------------------------------- */ | ||||||
| @@ -1062,4 +1066,206 @@ export class PegasusUtility { | |||||||
|     d.render(true); |     d.render(true); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static glowToken(token) { | ||||||
|  |     let params = | ||||||
|  |       [{ | ||||||
|  |         filterType: "glow", | ||||||
|  |         filterId: "superSpookyGlow", | ||||||
|  |         outerStrength: 15, | ||||||
|  |         innerStrength: 0, | ||||||
|  |         color: 0x6AAB8E, | ||||||
|  |         quality: 0.5, | ||||||
|  |         padding: 40, | ||||||
|  |         autoDestroy: true, | ||||||
|  |         animated: | ||||||
|  |         { | ||||||
|  |           color: | ||||||
|  |           { | ||||||
|  |             active: true, | ||||||
|  |             loopDuration: 3000, | ||||||
|  |             loops: 2, | ||||||
|  |             animType: "colorOscillation", | ||||||
|  |             val1: 0x6AAB8E, | ||||||
|  |             val2: 0x66FF33 | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }] | ||||||
|  |     TokenMagic.addUpdateFilters(token, params) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static async getRelevantTokens() { | ||||||
|  |     if (!_token) { return } | ||||||
|  |     let tokens = canvas.tokens.placeables.filter(token => token.document.disposition == 1) | ||||||
|  |     for (let token of tokens) { | ||||||
|  |       console.log("Parsing tokens", token.name) | ||||||
|  |       let dist = canvas.grid.measureDistances( | ||||||
|  |         [{ ray: new Ray(_token.center, token.center) }], { gridSpaces: false }) | ||||||
|  |       if (dist && dist[0] && dist[0] > 0) { | ||||||
|  |         console.log("    Friendly Tokens at : ", token.name, dist / canvas.grid.grid.options.dimensions.distance) | ||||||
|  |       } | ||||||
|  |       let visible = canvas.effects.visibility.testVisibility(token.center, { object: _token }) | ||||||
|  |       if (visible && dist[0] > 0) { | ||||||
|  |         this.glowToken(token) | ||||||
|  |       } | ||||||
|  |       console.log("    Visible!", visible) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static async processTactician(friends) { | ||||||
|  |     // Tactician management | ||||||
|  |     let toApply = {} | ||||||
|  |     let tacticianTokens = canvas.tokens.placeables.filter(token => token.actor.isTactician()) | ||||||
|  |     for (let token of tacticianTokens) { | ||||||
|  |       token.refresh() | ||||||
|  |       for (let friend of friends) { | ||||||
|  |         if (friend.actor.id != token.actor.id) { | ||||||
|  |           let existing = toApply[friend.actor.id] || { actor: friend.actor, add: false, level: 0, names: [] } | ||||||
|  |           let visible = canvas.effects.visibility.testVisibility(friend.center, { object: token }) | ||||||
|  |           console.log("parse visible TACTICIAN : ", visible, token.name, friend.name) | ||||||
|  |           if (visible) { | ||||||
|  |             existing.add = true | ||||||
|  |             existing.level += token.actor.getRoleLevel() | ||||||
|  |             existing.names.push(token.actor.name) | ||||||
|  |           } | ||||||
|  |           toApply[friend.actor.id] = existing | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for (let id in toApply) { | ||||||
|  |       let applyDef = toApply[id] | ||||||
|  |       let hasBonus = applyDef.actor.hasTacticianBonus() | ||||||
|  |       if (applyDef.add) { | ||||||
|  |         if (!hasBonus) { | ||||||
|  |           applyDef.actor.addTacticianEffect(applyDef.names.toString(), applyDef.level) | ||||||
|  |         } else if (applyDef.level != hasBonus.system.effectlevel) { | ||||||
|  |           await applyDef.actor.removeTacticianEffect() | ||||||
|  |           applyDef.actor.addTacticianEffect(applyDef.names.toString(), applyDef.level) | ||||||
|  |         } | ||||||
|  |       } else if (hasBonus) { | ||||||
|  |         applyDef.actor.removeTacticianEffect() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static async processEnhancer(friends) { | ||||||
|  |     // Enhancer management | ||||||
|  |     let toApply = {} | ||||||
|  |     let enhancerTokens = canvas.tokens.placeables.filter(token => token.actor.isEnhancer()) | ||||||
|  |     for (let token of enhancerTokens) { | ||||||
|  |       token.refresh() | ||||||
|  |       for (let friend of friends) { | ||||||
|  |         if (friend.actor.id != token.actor.id) { | ||||||
|  |           let existing = toApply[friend.actor.id] || { actor: friend.actor, add: false, level: 0, names: [] } | ||||||
|  |           let visible = canvas.effects.visibility.testVisibility(friend.center, { object: token }) | ||||||
|  |           console.log("parse visible ENHANCER: ", visible, token.name, friend.name) | ||||||
|  |           if (visible) { | ||||||
|  |             let dist = canvas.grid.measureDistances([{ ray: new Ray(token.center, friend.center) }], { gridSpaces: false }) | ||||||
|  |             if (dist && dist[0] && (dist[0] / canvas.grid.grid.options.dimensions.distance) <= 5) { | ||||||
|  |               existing.add = true | ||||||
|  |               existing.level += token.actor.getRoleLevel() | ||||||
|  |               existing.names.push(token.actor.name) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           toApply[friend.actor.id] = existing | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for (let id in toApply) { | ||||||
|  |       let applyDef = toApply[id] | ||||||
|  |       let hasBonus = applyDef.actor.hasEnhancerBonus() | ||||||
|  |       if (applyDef.add) { | ||||||
|  |         if (!hasBonus) { | ||||||
|  |           applyDef.actor.addEnhancerEffect(applyDef.names.toString(), applyDef.level) | ||||||
|  |         } else if (applyDef.level != hasBonus.system.effectlevel) { | ||||||
|  |           await applyDef.actor.removeEnhancerEffect() | ||||||
|  |           applyDef.actor.addEnhancerEffect(applyDef.names.toString(), applyDef.level) | ||||||
|  |         } | ||||||
|  |       } else if (hasBonus) { | ||||||
|  |         applyDef.actor.removeEnhancerEffect() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static async processAgitator(ennemies) { | ||||||
|  |     // Agitator management | ||||||
|  |     let toApply = {} | ||||||
|  |     let agitatorTokens = canvas.tokens.placeables.filter(token => token.actor.isAgitator()) | ||||||
|  |     for (let token of agitatorTokens) { | ||||||
|  |       token.refresh() | ||||||
|  |       for (let ennemy of ennemies) { | ||||||
|  |         if (ennemy.actor.id != token.actor.id) { | ||||||
|  |           let existing = toApply[ennemy.actor.id] || { actor: ennemy.actor, add: false, level: 0, names: [] } | ||||||
|  |           let visible = canvas.effects.visibility.testVisibility(ennemy.center, { object: token }) | ||||||
|  |           if (visible) { | ||||||
|  |             let dist = canvas.grid.measureDistances([{ ray: new Ray(token.center, ennemy.center) }], { gridSpaces: false }) | ||||||
|  |             if (dist && dist[0] && (dist[0] / canvas.grid.grid.options.dimensions.distance) <= 5) { | ||||||
|  |               existing.add = true | ||||||
|  |               existing.level += token.actor.getRoleLevel() | ||||||
|  |               existing.names.push(token.actor.name) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           toApply[ennemy.actor.id] = existing | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for (let id in toApply) { | ||||||
|  |       let applyDef = toApply[id] | ||||||
|  |       let hasHindrance = applyDef.actor.hasAgitatorHindrance() | ||||||
|  |       if (applyDef.add) { | ||||||
|  |         if (!hasHindrance) { | ||||||
|  |           applyDef.actor.addAgitatorHindrance(applyDef.names.toString(), applyDef.level) | ||||||
|  |         } else if (applyDef.level != hasHindrance.system.effectlevel) { | ||||||
|  |           await applyDef.actor.removeAgitatorHindrance() | ||||||
|  |           applyDef.actor.addAgitatorHindrance(applyDef.names.toString(), applyDef.level) | ||||||
|  |         } | ||||||
|  |       } else if (hasHindrance) { | ||||||
|  |         applyDef.actor.removeAgitatorHindrance() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static async processRoleEffects() { | ||||||
|  |  | ||||||
|  |     // Small optimization | ||||||
|  |     let now = Date.now() | ||||||
|  |     if ( now - this.lastRoleEffectProcess < 300  ) { | ||||||
|  |       return // Save some processing | ||||||
|  |     } | ||||||
|  |     this.lastRoleEffectProcess = now | ||||||
|  |     console.log("=========================+> Searching/Processing roles effects") | ||||||
|  |  | ||||||
|  |     let friends = canvas.tokens.placeables.filter(token => token.actor.type == "character" && token.document.disposition == 1) | ||||||
|  |     let ennemies = canvas.tokens.placeables.filter(token => token.actor.type == "character" && token.document.disposition == -1) | ||||||
|  |  | ||||||
|  |     await this.processTactician(friends) | ||||||
|  |     await this.processEnhancer(friends) | ||||||
|  |     await this.processAgitator(ennemies) | ||||||
|  |  | ||||||
|  |     // Cleanup if disposition has changed | ||||||
|  |     let allTokens = canvas.tokens.placeables.filter(token => token.actor.type == "character") | ||||||
|  |     for (let token of allTokens) { | ||||||
|  |       if (token.document.disposition != -1 && token.actor.hasAgitatorHindrance()) { | ||||||
|  |         token.actor.removeAgitatorHindrance() | ||||||
|  |       } | ||||||
|  |       if (token.document.disposition != 1 && token.actor.hasTacticianBonus()) { | ||||||
|  |         token.actor.removeTacticianEffect() | ||||||
|  |       } | ||||||
|  |       if (token.document.disposition != 1 && token.actor.hasEnhancerBonus()) { | ||||||
|  |         token.actor.removeEnhancerEffect() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* -------------------------------------------- */ | ||||||
|  |   static async refreshSightForEffect() { | ||||||
|  |     setTimeout(500, this.processRoleEffects()) | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -253,7 +253,7 @@ | |||||||
|   ], |   ], | ||||||
|   "title": "Pegasus RPG", |   "title": "Pegasus RPG", | ||||||
|   "url": "https://www.uberwald.me/data/files/fvtt-pegasus-rpg", |   "url": "https://www.uberwald.me/data/files/fvtt-pegasus-rpg", | ||||||
|   "version": "10.0.28", |   "version": "10.0.29", | ||||||
|   "download": "https://www.uberwald.me/gitea/uberwald/fvtt-pegasus-rpg/archive/fvtt-pegasus-rpg-v10.0.28.zip", |   "download": "https://www.uberwald.me/gitea/uberwald/fvtt-pegasus-rpg/archive/fvtt-pegasus-rpg-v10.0.29.zip", | ||||||
|   "background": "systems/fvtt-pegasus-rpg/images/ui/pegasus_welcome_page.webp" |   "background": "systems/fvtt-pegasus-rpg/images/ui/pegasus_welcome_page.webp" | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user