forked from public/bol
Add new features
This commit is contained in:
parent
9e5e07b227
commit
38025666e9
4998
images/icone_parchement_vierge.svg
Normal file
4998
images/icone_parchement_vierge.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 372 KiB |
@ -14,6 +14,7 @@ export class BoLActorSheet extends ActorSheet {
|
||||
template: "systems/bol/templates/actor/actor-sheet.hbs",
|
||||
width: 600,
|
||||
height: 600,
|
||||
dragDrop: [{ dragSelector: ".items-list .item", dropSelector: null }],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }]
|
||||
});
|
||||
}
|
||||
|
@ -304,23 +304,17 @@ export class BoLActor extends Actor {
|
||||
/*-------------------------------------------- */
|
||||
getArmorAgiMalus() {
|
||||
let malusAgi = 0
|
||||
for (let armor of this.armors) {
|
||||
for (let armor of this.protections) {
|
||||
if (armor.data.worn) {
|
||||
malusAgi += Number(armor.data.properties.modifiers.agility) || 0
|
||||
}
|
||||
}
|
||||
for (let shield of this.shields) {
|
||||
if (shield.data.worn) {
|
||||
malusAgi += Number(shield.data.properties.modifiers.agility) || 0
|
||||
}
|
||||
}
|
||||
return malusAgi
|
||||
}
|
||||
/*-------------------------------------------- */
|
||||
getArmorInitMalus() {
|
||||
let armors = this.armors
|
||||
let malusInit = 0
|
||||
for (let armor of armors) {
|
||||
for (let armor of this.protections) {
|
||||
if (armor.data.worn) {
|
||||
malusInit += Number(armor.data.properties.modifiers.init) || 0
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import { Macros } from "./system/macros.js"
|
||||
import { BoLUtility } from "./system/bol-utility.js"
|
||||
import { BoLCombatManager } from "./system/bol-combat.js"
|
||||
import { BoLTokenHud } from "./system/bol-action-hud.js"
|
||||
import { BoLHotbar } from "./system/bol-hotbar.js"
|
||||
|
||||
/* -------------------------------------------- */
|
||||
Hooks.once('init', async function () {
|
||||
@ -19,6 +20,7 @@ Hooks.once('init', async function () {
|
||||
game.bol = {
|
||||
BoLActor,
|
||||
BoLItem,
|
||||
BoLHotbar,
|
||||
macros: Macros,
|
||||
config: BOL
|
||||
};
|
||||
@ -52,6 +54,7 @@ Hooks.once('init', async function () {
|
||||
// Inot useful stuff
|
||||
BoLUtility.init()
|
||||
BoLTokenHud.init()
|
||||
BoLHotbar.init()
|
||||
|
||||
// Preload Handlebars Templates
|
||||
await preloadHandlebarsTemplates();
|
||||
|
@ -32,7 +32,7 @@ export class BoLRoll {
|
||||
careerBonus: 0,
|
||||
description: description,
|
||||
armorAgiMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorInitMalus(),
|
||||
mod: 0
|
||||
}
|
||||
return this.displayRollDialog(rollData)
|
||||
@ -56,12 +56,12 @@ export class BoLRoll {
|
||||
attrValue: attribute.value,
|
||||
aptValue: aptitude.value,
|
||||
armorAgiMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorInitMalus(),
|
||||
label: label,
|
||||
careerBonus: 0,
|
||||
description: description,
|
||||
mod: 0
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -94,7 +94,7 @@ export class BoLRoll {
|
||||
attrValue: attribute.value,
|
||||
aptValue: aptitude.value,
|
||||
armorAgiMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorInitMalus(),
|
||||
mod: 0,
|
||||
modRanged: 0,
|
||||
label: (weapon.name) ? weapon.name : game.i18n.localize('BOL.ui.noWeaponName'),
|
||||
@ -139,7 +139,7 @@ export class BoLRoll {
|
||||
pcCostCurrent: Number(alchemyData.properties.pccurrent),
|
||||
mod: Number(alchemyData.properties.difficulty),
|
||||
armorAgiMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorInitMalus(),
|
||||
label: alchemy.name,
|
||||
description: game.i18n.localize('BOL.ui.makeAlchemy') + "+" + alchemy.name,
|
||||
}
|
||||
@ -147,20 +147,9 @@ export class BoLRoll {
|
||||
return this.displayRollDialog(alchemyDef);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static spellCheck(actor, event) {
|
||||
if (actor.data.data.resources.power.value <= 0) {
|
||||
ui.notifications.warn("Plus assez de points de Pouvoir !")
|
||||
return
|
||||
}
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const spell = actor.items.get(li.data("item-id"));
|
||||
if (!spell) {
|
||||
ui.notifications.warn("Unable to find spell !");
|
||||
return;
|
||||
}
|
||||
let spellData = spell.data.data;
|
||||
static spellCheckWithSpell( actor, spell ) {
|
||||
let spellData = spell.data.data
|
||||
let spellDef = {
|
||||
mode: "spell",
|
||||
actor: actor,
|
||||
@ -174,12 +163,27 @@ export class BoLRoll {
|
||||
ppCost: Number(spell.data.data.properties.ppcost),
|
||||
mod: Number(spellData.properties.difficulty),
|
||||
armorAgiMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorAgiMalus(),
|
||||
armorInitMalus: actor.getArmorInitMalus(),
|
||||
label: spell.name,
|
||||
description: game.i18n.localize('BOL.ui.focusSpell') + " : " + spell.name,
|
||||
}
|
||||
console.log("SPELL!", spellDef);
|
||||
return this.displayRollDialog(spellDef);
|
||||
console.log("SPELL!", spellDef)
|
||||
return this.displayRollDialog(spellDef)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static spellCheck(actor, event) {
|
||||
if (actor.data.data.resources.power.value <= 0) {
|
||||
ui.notifications.warn("Plus assez de points de Pouvoir !")
|
||||
return
|
||||
}
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
const spell = actor.items.get(li.data("item-id"))
|
||||
if (!spell) {
|
||||
ui.notifications.warn("Impossible de trouver ce sort !")
|
||||
return
|
||||
}
|
||||
return this.spellCheckWithSpell( actor, spell)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -347,6 +351,7 @@ export class BoLRoll {
|
||||
rollData.careers = rollData.actor.careers
|
||||
rollData.boons = rollData.actor.bonusBoons
|
||||
rollData.flaws = rollData.actor.malusFlaws
|
||||
rollData.rollOwnerID = rollData.actor.id
|
||||
rollData.defence = 0
|
||||
rollData.attackModifier = 0 // Used for fight options
|
||||
rollData.modArmorMalus = 0 // Used for fight options
|
||||
@ -455,6 +460,8 @@ export class BoLDefaultRoll {
|
||||
this.rollData.isSuccess = (r.total >= 9)
|
||||
this.rollData.isCritical = (diceTotal === 12)
|
||||
this.rollData.isRealCritical = (diceTotal === 12)
|
||||
this.rollData.isHeroic = (diceTotal === 12)
|
||||
this.rollData.isLegendary = false
|
||||
this.rollData.isFumble = (diceTotal === 2)
|
||||
this.rollData.isFailure = !this.rollData.isSuccess
|
||||
if (this.rollData.reroll == undefined) {
|
||||
@ -479,21 +486,36 @@ export class BoLDefaultRoll {
|
||||
this._buildChatMessage(this.rollData).then(msgFlavor => {
|
||||
this.rollData.roll.toMessage({
|
||||
user: game.user.id,
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
//whisper: BoLUtility.getWhisperRecipientsAndGMs(this.rollData.actor.name),
|
||||
flavor: msgFlavor,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.rollData.actor }),
|
||||
flags: { msgType: "default" }
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
upgradeToCritical() {
|
||||
upgradeToLegendary() {
|
||||
// Force to Critical roll
|
||||
this.rollData.isCritical = true
|
||||
this.rollData.isLegendary = true
|
||||
this.rollData.isRealCritical = false
|
||||
this.rollData.isSuccess = true
|
||||
this.rollData.isFailure = false
|
||||
this.rollData.roll = new Roll("12+" + this.rollData.modifiers)
|
||||
this.rollData.reroll = false
|
||||
this.sendChatMessage()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
upgradeToHeroic() {
|
||||
// Force to Critical roll
|
||||
this.rollData.isCritical = true
|
||||
this.rollData.isHeroic = true
|
||||
this.rollData.isLegendary = false
|
||||
this.rollData.isRealCritical = false
|
||||
this.rollData.isSuccess = true
|
||||
this.rollData.isFailure = false
|
||||
this.rollData.roll = new Roll("12+" + this.rollData.modifiers)
|
||||
this.rollData.reroll = false
|
||||
this.sendChatMessage()
|
||||
@ -510,7 +532,7 @@ export class BoLDefaultRoll {
|
||||
this.rollData.damageRoll.toMessage({
|
||||
user: game.user.id,
|
||||
flavor: msgFlavor,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.rollData.actor }),
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.rollData.actors }),
|
||||
flags: { msgType: "default" }
|
||||
})
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ export class BoLItemSheet extends ItemSheet {
|
||||
classes: ["bol", "sheet", "item"],
|
||||
template: "systems/bol/templates/item/item-sheet.hbs",
|
||||
width: 650,
|
||||
height: 750,
|
||||
height: 780,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
|
||||
});
|
||||
}
|
||||
|
87
module/system/bol-hotbar.js
Normal file
87
module/system/bol-hotbar.js
Normal file
@ -0,0 +1,87 @@
|
||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||
|
||||
export class BoLHotbar {
|
||||
|
||||
/**
|
||||
* Create a macro when dropping an entity on the hotbar
|
||||
* Item - open roll dialog for item
|
||||
* Actor - open actor sheet
|
||||
* Journal - open journal sheet
|
||||
*/
|
||||
static init( ) {
|
||||
|
||||
Hooks.on("hotbarDrop", async (bar, documentData, slot) => {
|
||||
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill
|
||||
if (documentData.type == "Item") {
|
||||
console.log("Drop done !!!", bar, documentData, slot)
|
||||
let item = documentData.data
|
||||
let command = `game.bol.BoLHotbar.rollMacro("${item.name}", "${item.type}");`
|
||||
let macro = game.macros.contents.find(m => (m.name === item.name) && (m.command === command))
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: item.name,
|
||||
type: "script",
|
||||
img: item.img,
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
}
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
// Create a macro to open the actor sheet of the actor dropped on the hotbar
|
||||
else if (documentData.type == "Actor") {
|
||||
let actor = game.actors.get(documentData.id);
|
||||
let command = `game.actors.get("${documentData.id}").sheet.render(true)`
|
||||
let macro = game.macros.contents.find(m => (m.name === actor.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: actor.data.name,
|
||||
type: "script",
|
||||
img: actor.data.img,
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
}
|
||||
// Create a macro to open the journal sheet of the journal dropped on the hotbar
|
||||
else if (documentData.type == "JournalEntry") {
|
||||
let journal = game.journal.get(documentData.id);
|
||||
let command = `game.journal.get("${documentData.id}").sheet.render(true)`
|
||||
let macro = game.macros.contents.find(m => (m.name === journal.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: journal.data.name,
|
||||
type: "script",
|
||||
img: "systems/bol/icons/images/icone_parchement_vierge.webp",
|
||||
command: command
|
||||
}, { displaySheet: false })
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/** Roll macro */
|
||||
static rollMacro(itemName, itemType, bypassData) {
|
||||
const speaker = ChatMessage.getSpeaker()
|
||||
let actor
|
||||
if (speaker.token) actor = game.actors.tokens[speaker.token]
|
||||
if (!actor) actor = game.actors.get(speaker.actor)
|
||||
if (!actor) {
|
||||
return ui.notifications.warn(`Selectionnez votre personnage pour utiliser la macro`)
|
||||
}
|
||||
|
||||
let item = actor.items.find(it => it.name === itemName && it.type == itemType)
|
||||
if (!item ) {
|
||||
return ui.notifications.warn(`Impossible de trouver l'objet de cette macro`)
|
||||
}
|
||||
// Trigger the item roll
|
||||
if (item.data.data.category === "equipment" && item.data.data.subtype === "weapon") {
|
||||
return BoLRoll.weaponCheckWithWeapon( actor, item)
|
||||
}
|
||||
if (item.data.data.category === "spell") {
|
||||
return BoLRoll.spellCheckWithSpell( actor, item)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,6 @@ export class BoLUtility {
|
||||
this.rollArmor = game.settings.get("bol", "rollArmor") // Roll armor or not
|
||||
this.useBougette = game.settings.get("bol", "useBougette") // Use optionnal bougette rules
|
||||
|
||||
console.log("UTIL", this)
|
||||
}
|
||||
|
||||
|
||||
@ -127,6 +126,17 @@ export class BoLUtility {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getOtherWhisperRecipients( name) {
|
||||
let users = []
|
||||
for( let user of game.users) {
|
||||
if ( !user.isGM && user.name != name) {
|
||||
users.push( user.data._id)
|
||||
}
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipientsAndGMs(name) {
|
||||
let recep1 = ChatMessage.getWhisperRecipients(name) || [];
|
||||
@ -154,6 +164,22 @@ export class BoLUtility {
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async chatMessageHandler(message, html, data) {
|
||||
const chatCard = html.find('.flavor-text')
|
||||
if (chatCard.length > 0) {
|
||||
// If the user is the message author or the actor owner, proceed
|
||||
const actor = game.actors.get(data.message.speaker.actor)
|
||||
console.log("FOUND 1!!! ", actor)
|
||||
if (actor && actor.isOwner) return
|
||||
else if (game.user.isGM || data.author.id === game.user.id) return
|
||||
|
||||
const divButtons = chatCard.find('.actions-section')
|
||||
console.log("FOUND 2!! ", divButtons)
|
||||
divButtons.hide()
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async chatListeners(html) {
|
||||
|
||||
@ -172,13 +198,21 @@ export class BoLUtility {
|
||||
bolRoll.rollDamage()
|
||||
});
|
||||
|
||||
html.on("click", '.transform-legendary-roll', event => {
|
||||
event.preventDefault();
|
||||
let rollData = BoLUtility.getLastRoll()
|
||||
rollData.actor.subHeroPoints(1)
|
||||
let r = new BoLDefaultRoll(rollData)
|
||||
r.upgradeToLegendary()
|
||||
})
|
||||
|
||||
html.on("click", '.transform-heroic-roll', event => {
|
||||
event.preventDefault();
|
||||
let rollData = BoLUtility.getLastRoll()
|
||||
rollData.actor.subHeroPoints(1)
|
||||
let r = new BoLDefaultRoll(rollData)
|
||||
r.upgradeToCritical();
|
||||
});
|
||||
r.upgradeToHeroic()
|
||||
})
|
||||
|
||||
html.on("click", '.hero-reroll', event => {
|
||||
event.preventDefault();
|
||||
|
@ -116,7 +116,13 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('eval', function (expr) {
|
||||
return eval(expr);
|
||||
})
|
||||
|
||||
Handlebars.registerHelper('isOwnerOrGM', function (actor) {
|
||||
console.log("Testing actor", actor.isOwner, game.userId)
|
||||
if (actor.isOwner || game.isGM) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,8 @@ export default function registerHooks() {
|
||||
html.find("img").attr("src", "systems/bol/ui/pause2.webp")
|
||||
}))
|
||||
|
||||
Hooks.on('renderChatLog', (log, html, data) => BoLUtility.chatListeners(html));
|
||||
Hooks.on('renderChatLog', (log, html, data) => BoLUtility.chatListeners(html))
|
||||
Hooks.on('renderChatMessage', (message, html, data) => BoLUtility.chatMessageHandler(message, html, data))
|
||||
|
||||
/**
|
||||
* Create a macro when dropping an entity on the hotbar
|
||||
|
@ -14,7 +14,7 @@
|
||||
"url": "https://github.com/ZigmundKreud/bol",
|
||||
"license": "LICENSE.txt",
|
||||
"flags": {},
|
||||
"version": "1.2.7",
|
||||
"version": "1.3.0",
|
||||
"minimumCoreVersion": "0.8.6",
|
||||
"compatibleCoreVersion": "9",
|
||||
"scripts": [],
|
||||
|
@ -1,9 +1,14 @@
|
||||
<img class="chat-icon" src="{{weapon.img}}" alt="{{weapon.name}}"/>
|
||||
<h3><strong>Dommages de {{weapon.name}} : {{damageRoll.total}}</strong></h3>
|
||||
{{#if defender}}
|
||||
<h3><strong>Cible : {{defender.name}}</strong></h3>
|
||||
{{/if}}
|
||||
|
||||
<div class="actions-section">
|
||||
{{#if target}}
|
||||
<div id="{{applyId}}">
|
||||
<button class="chat-damage-apply" data-attack-id="{{id}}">Appliquer les dommages à la cible</button>
|
||||
</div>
|
||||
<br>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
<h3><strong>{{description}}</strong></h3>
|
||||
|
||||
<div class="actions-section">
|
||||
{{#if fightOption}}
|
||||
<div>
|
||||
Option de combat : {{fightOption.name}}
|
||||
@ -39,8 +40,14 @@
|
||||
{{#if reroll}}
|
||||
<button class="chat-button button hero-reroll" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">Relancer (1 P. Heroisme)</button>
|
||||
{{/if}}
|
||||
{{#if (and isSuccess (not isCritical))}}
|
||||
<button class="chat-button button transform-heroic-roll" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">Transformer en succés Héroïque (1 P. Héroisme)</button>
|
||||
{{/if}}
|
||||
|
||||
{{#if isRealCritical}}
|
||||
<button class="chat-button button transform-heroic-roll" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">Transformer en succes héroique (1 P. Heroisme)</button>
|
||||
<button class="chat-button button transform-legendary-roll" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">Transformer en succes Légendaire (1 P. Heroisme)</button>
|
||||
{{/if}}
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<img class="chat-icon" src="{{defender.img}}" alt="{{defender.name}}"/>
|
||||
Va encaisser {{damageTotal}} dégats !
|
||||
{{defender.name}} va encaisser {{damageTotal}} dégats !
|
||||
|
||||
{{#if damagesIgnoresArmor}}
|
||||
<br>C'est une attaque au défaut de l'armure : vous devez encaisser SANS la protection de l'armure !
|
||||
|
Loading…
Reference in New Issue
Block a user