Compare commits

..

6 Commits

14 changed files with 197 additions and 31 deletions

View File

@ -1,3 +1,9 @@
# v10.4.0
- Ajout de la gestion d'effets
- Aide intégré
- Intégration du PDF de la bougette
# v10.3.3 # v10.3.3
- Nouvelles clés de traduction - Nouvelles clés de traduction

View File

@ -59,8 +59,6 @@ a:hover {
top: -50px; top: -50px;
left: calc(50% - 100px); left: calc(50% - 100px);
opacity: 0.7; opacity: 0.7;
-webkit-animation: rotation 10s infinite linear;
animation: rotation 10s infinite linear;
} }
#pause h3 { #pause h3 {
font-family: "IMFellDWPicaSC-Regular", serif; font-family: "IMFellDWPicaSC-Regular", serif;
@ -444,12 +442,16 @@ ul.no-bullets {
.bol .inc-dec-btns { .bol .inc-dec-btns {
color: #4b4a44; color: #4b4a44;
} }
.summmary-number {
padding-left: 4rem;
}
/* Items List */ /* Items List */
.items-list { .items-list {
list-style: none; list-style: none;
margin: 7px 0; margin: 7px 0;
padding: 0; padding: 0;
overflow-y: auto; overflow-y:hidden;
/*overflow-y: auto;*/
} }
.items-list .item-header { .items-list .item-header {
font-family: 'Signika', sans-serif; font-family: 'Signika', sans-serif;
@ -520,7 +522,10 @@ ul.no-bullets {
.items-list .item .item-control { .items-list .item .item-control {
color: #4b4a44; color: #4b4a44;
} }
.items-list .item-name-fixed-medium {
min-width: 8rem;
width: 8rem;
}
/* ----------------------------------------- */ /* ----------------------------------------- */
/* Premade colors */ /* Premade colors */
/* ----------------------------------------- */ /* ----------------------------------------- */
@ -1054,4 +1059,7 @@ body.system-bol img#logo {
.bol-margin-tb-2 { .bol-margin-tb-2 {
margin-top: 2px; margin-top: 2px;
margin-bottom: 2px; margin-bottom: 2px;
} }
.character-summary-container {
  opacity: 0.95;
}

View File

@ -171,6 +171,7 @@
"BOL.ui.effectbonusmalus": "Bonus ou Malus à appliquer", "BOL.ui.effectbonusmalus": "Bonus ou Malus à appliquer",
"BOL.ui.boleffects": "Effets (automatiques)", "BOL.ui.boleffects": "Effets (automatiques)",
"BOL.ui.modifier": "Modificateur", "BOL.ui.modifier": "Modificateur",
"BOL.ui.effects": "Effets en cours",
"BOL.featureCategory.origins": "Origines", "BOL.featureCategory.origins": "Origines",
"BOL.featureCategory.races": "Races", "BOL.featureCategory.races": "Races",

View File

@ -28,6 +28,7 @@ export class BoLActor extends Actor {
} }
return this.system.chartype return this.system.chartype
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getVillainy() { getVillainy() {
if (this.type === 'character') { if (this.type === 'character') {
@ -52,7 +53,7 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
prepareDerivedData() { prepareDerivedData() {
if ( this.type == "vehicle") { if (this.type == "vehicle") {
} else { } else {
super.prepareDerivedData() super.prepareDerivedData()
@ -102,6 +103,13 @@ export class BoLActor extends Actor {
if (fo && fo.system.properties.fightoptiontype == "attack") { if (fo && fo.system.properties.fightoptiontype == "attack") {
defMod += -1 defMod += -1
} }
// Apply defense effects
for (let i of this.items) {
if (i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier.includes("aptitudes.def") ) {
defMod += Number(i.system.properties.modifier)
}
}
console.log("Defense : ", defMod)
return this.system.aptitudes.def.value + defMod return this.system.aptitudes.def.value + defMod
} }
@ -216,7 +224,7 @@ export class BoLActor extends Actor {
return duplicate(this.items.filter(i => i.type === "feature" && i.system.subtype === "flaw") || []); return duplicate(this.items.filter(i => i.type === "feature" && i.system.subtype === "flaw") || []);
} }
get careers() { get careers() {
return duplicate( this.items.filter(i => i.type === "feature" && i.system.subtype === "career") || []) return duplicate(this.items.filter(i => i.type === "feature" && i.system.subtype === "career") || [])
} }
get origins() { get origins() {
return this.items.filter(i => i.type === "feature" && i.system.subtype === "origin"); return this.items.filter(i => i.type === "feature" && i.system.subtype === "origin");
@ -240,7 +248,7 @@ export class BoLActor extends Actor {
return this.items.filter(i => i.type === "item") return this.items.filter(i => i.type === "item")
} }
get equipmentCreature() { get equipmentCreature() {
return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && (( i.system.subtype === "weapon" && i.system.properties.natural === true) || (i.system.subtype === "armor")) ) return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && ((i.system.subtype === "weapon" && i.system.properties.natural === true) || (i.system.subtype === "armor")))
} }
get armors() { get armors() {
return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && i.system.subtype === "armor"); return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && i.system.subtype === "armor");
@ -252,7 +260,7 @@ export class BoLActor extends Actor {
return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && i.system.subtype === "shield"); return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && i.system.subtype === "shield");
} }
get vehicleWeapons() { get vehicleWeapons() {
return this.items.filter(i => i.type === "item" && i.system.category === "vehicleweapon" ) return this.items.filter(i => i.type === "item" && i.system.category === "vehicleweapon")
} }
get weapons() { get weapons() {
return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && i.system.subtype === "weapon") return this.items.filter(i => i.type === "item" && i.system.category === "equipment" && i.system.subtype === "weapon")
@ -298,10 +306,10 @@ export class BoLActor extends Actor {
get bonusBoons() { get bonusBoons() {
let boons = this.items.filter(i => i.type === "feature" && i.system.subtype === "boon" && i.system.properties.isbonusdice) let boons = this.items.filter(i => i.type === "feature" && i.system.subtype === "boon" && i.system.properties.isbonusdice)
return duplicate( boons || []) return duplicate(boons || [])
} }
get malusFlaws() { get malusFlaws() {
return duplicate( this.items.filter(i => i.type === "feature" && i.system.subtype === "flaw" && i.system.properties.ismalusdice) || []); return duplicate(this.items.filter(i => i.type === "feature" && i.system.subtype === "flaw" && i.system.properties.ismalusdice) || []);
} }
isSorcerer() { isSorcerer() {
@ -332,6 +340,23 @@ export class BoLActor extends Actor {
return ppCostArmor return ppCostArmor
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
getDamageAttributeValue(attrDamage) {
let attrDamageValue = 0
if (attrDamage.includes("vigor")) {
attrDamageValue = actor.system.attributes.vigor.value
if (attrDamage.includes("half")) {
attrDamageValue = Math.floor(attrDamageValue / 2)
}
// Apply vigor effects
for (let i of this.items) {
if (i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier.includes("vigor") ) {
attrDamageValue += Number(i.system.properties.modifier)
}
}
}
return attrDamageValue
}
/*-------------------------------------------- */
getArmorAgiMalus() { getArmorAgiMalus() {
let malusAgi = 0 let malusAgi = 0
for (let armor of this.protections) { for (let armor of this.protections) {
@ -568,7 +593,7 @@ export class BoLActor extends Actor {
async manageHealthState() { async manageHealthState() {
let hpID = "lastHP" + this.id let hpID = "lastHP" + this.id
let lastHP = await this.getFlag("world", hpID) let lastHP = await this.getFlag("world", hpID)
if (lastHP != this.system.resources.hp.value && game.user.isGM ) { // Only GM sends this if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
await this.setFlag("world", hpID, this.system.resources.hp.value) await this.setFlag("world", hpID, this.system.resources.hp.value)
if (this.system.resources.hp.value <= 0) { if (this.system.resources.hp.value <= 0) {
ChatMessage.create({ ChatMessage.create({
@ -600,7 +625,7 @@ export class BoLActor extends Actor {
/*-------------------------------------------- */ /*-------------------------------------------- */
async sufferDamage(damage) { async sufferDamage(damage) {
let newHP = this.system.resources.hp.value - damage let newHP = this.system.resources.hp.value - damage
await this.update({ 'system.resources.hp.value': newHP }) await this.update({ 'system.resources.hp.value': newHP })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -615,7 +640,7 @@ export class BoLActor extends Actor {
if (!protect.system.properties.soak.formula || protect.system.properties.soak.formula == "") { if (!protect.system.properties.soak.formula || protect.system.properties.soak.formula == "") {
ui.notifications.warn(`L'armure ${protect.name} n'a pas de formule pour la protection !`) ui.notifications.warn(`L'armure ${protect.name} n'a pas de formule pour la protection !`)
} else { } else {
formula += "+" + " max(" + protect.system.properties.soak.formula +",0)" formula += "+" + " max(" + protect.system.properties.soak.formula + ",0)"
} }
} else { } else {
if (protect.system.properties.soak.value == undefined) { if (protect.system.properties.soak.value == undefined) {
@ -634,7 +659,7 @@ export class BoLActor extends Actor {
rollProtection(itemId) { rollProtection(itemId) {
let armor = duplicate(this.items.get(itemId)) let armor = duplicate(this.items.get(itemId))
if (armor) { if (armor) {
let armorFormula = "max("+armor.system.properties.soak.formula + ", 0)" let armorFormula = "max(" + armor.system.properties.soak.formula + ", 0)"
let rollArmor = new Roll(armorFormula) let rollArmor = new Roll(armorFormula)
rollArmor.roll({ async: false }).toMessage() rollArmor.roll({ async: false }).toMessage()
} }

View File

@ -498,7 +498,7 @@ export class BoLRoll {
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ? $('#register-init').is(":checked") : false; rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ? $('#register-init').is(":checked") : false;
const isMalus = rollData.nbFlaws > rollData.nbBoons const isMalus = (rollData.bmDice < 0)
//rollData.nbDice += (rollData.attackBonusDice) ? 1 : 0 //rollData.nbDice += (rollData.attackBonusDice) ? 1 : 0
let rollbase = rollData.attrValue + rollData.aptValue let rollbase = rollData.attrValue + rollData.aptValue
@ -645,16 +645,8 @@ export class BoLDefaultRoll {
/* -------------------------------------------- */ /* -------------------------------------------- */
getDamageAttributeValue(attrDamage, actorId = undefined) { getDamageAttributeValue(attrDamage, actorId = undefined) {
let attrDamageValue = 0
let actor = game.actors.get( (actorId) ? actorId: this.rollData.actorId) let actor = game.actors.get( (actorId) ? actorId: this.rollData.actorId)
if (attrDamage.includes("vigor")) { return actor.getDamageAttributeValue( attrDamage )
attrDamageValue = actor.system.attributes.vigor.value
if (attrDamage.includes("half")) {
attrDamageValue = Math.floor(attrDamageValue / 2)
}
}
return attrDamageValue
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -40,7 +40,7 @@ export class BoLCalendar extends Application {
constructor() { constructor() {
super(); super();
// position // position
this.calendarPos = duplicate(game.settings.get(SYSTEM_RDD, "calendar-pos")); this.calendarPos = duplicate(game.settings.get("bol", "calendar-pos"));
if (this.calendarPos == undefined || this.calendarPos.top == undefined) { if (this.calendarPos == undefined || this.calendarPos.top == undefined) {
this.calendrierPos = BoLCalendar.createCalendarPos() this.calendrierPos = BoLCalendar.createCalendarPos()
game.settings.set("bol", "calendar-pos", this.calendarPos) game.settings.set("bol", "calendar-pos", this.calendarPos)

View File

@ -0,0 +1,66 @@
/* -------------------------------------------- */
import { BoLUtility } from "./bol-utility.js";
import { BoLRoll } from "../controllers/bol-rolls.js";
/* -------------------------------------------- */
export class BoLCharacterSummary extends Application {
/* -------------------------------------------- */
static displayPCSummary(){
let pcList = new BoLCharacterSummary()
pcList.render(true)
}
/* -------------------------------------------- */
static createSummaryPos() {
return { top: 200, left: 200 };
}
/* -------------------------------------------- */
constructor() {
if ( !game.user.isGM ) { // Uniquement si GM
return;
}
super();
}
/* -------------------------------------------- */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
template: "systems/bol/templates/apps/character-summary-template.html",
popOut: true,
resizable: true,
classes: ["bol", "dialog"], width: 820, height: 'fit-content'
})
}
/* -------------------------------------------- */
getData() {
let formData = super.getData();
formData.pcs = game.actors.filter( ac => ac.type == "character" && ac.hasPlayerOwner )
formData.config = game.bol.config
return formData
}
/* -------------------------------------------- */
/** @override */
async activateListeners(html) {
super.activateListeners(html);
html.find('.summary-roll').click((event) => {
const li = $(event.currentTarget).parents(".item")
const actor = game.actors.get(li.data("actor-id"))
let type = $(event.currentTarget).data("type")
let key = $(event.currentTarget).data("key")
if ( type == "attribute") {
BoLRoll.attributeCheck(actor, key, event)
} else if (type == "aptitude") {
BoLRoll.aptitudeCheck(actor, key, event)
}
})
}
}

View File

@ -1,5 +1,6 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { BoLAdventureGenerator } from "./bol-adventure-generator.js" import { BoLAdventureGenerator } from "./bol-adventure-generator.js"
import { BoLCharacterSummary } from "./bol-character-summary.js"
/* -------------------------------------------- */ /* -------------------------------------------- */
export class BoLCommands { export class BoLCommands {
@ -8,6 +9,7 @@ export class BoLCommands {
if (!game.bol.commands) { if (!game.bol.commands) {
const bolCommands = new BoLCommands() const bolCommands = new BoLCommands()
bolCommands.registerCommand({ path: ["/adventure"], func: (content, msg, params) => BoLAdventureGenerator.createAdventure(), descr: "Nouvelle idée d'aventure!" }); bolCommands.registerCommand({ path: ["/adventure"], func: (content, msg, params) => BoLAdventureGenerator.createAdventure(), descr: "Nouvelle idée d'aventure!" });
bolCommands.registerCommand({ path: ["/pcview"], func: (content, msg, params) => BoLCharacterSummary.displayPCSummary(), descr: "Affiche la liste des PJs!" });
game.bol.commands = bolCommands game.bol.commands = bolCommands
} }

View File

@ -115,6 +115,14 @@ BOL.aptitudes = {
"def" : "BOL.aptitudes.def" "def" : "BOL.aptitudes.def"
} }
BOL.resources = {
"hp" : "BOL.resources.hp",
"hero" : "BOL.resources.hero",
"faith" : "BOL.resources.faith",
"power" : "BOL.resources.power",
"alchemypoints" : "BOL.resources.alchemypoints"
}
BOL.weaponSizes = { BOL.weaponSizes = {
"unarmed" : "BOL.weaponSize.unarmed", "unarmed" : "BOL.weaponSize.unarmed",
"improvised" : "BOL.weaponSize.improvised", "improvised" : "BOL.weaponSize.improvised",

View File

@ -103,6 +103,12 @@ export const registerHandlebarsHelpers = function () {
Handlebars.registerHelper('sub', function (a, b) { Handlebars.registerHelper('sub', function (a, b) {
return parseInt(a) - parseInt(b); return parseInt(a) - parseInt(b);
}) })
Handlebars.registerHelper('abbrev2', function (a) {
return a.substring(0,2);
})
Handlebars.registerHelper('abbrev3', function (a) {
return a.substring(0,3);
})
Handlebars.registerHelper('valueAtIndex', function (arr, idx) { Handlebars.registerHelper('valueAtIndex', function (arr, idx) {
return arr[idx]; return arr[idx];
}) })

View File

@ -14,7 +14,7 @@
], ],
"url": "https://www.uberwald.me/gitea/public/bol", "url": "https://www.uberwald.me/gitea/public/bol",
"license": "LICENSE.txt", "license": "LICENSE.txt",
"version": "10.4.0", "version": "10.4.3",
"compatibility": { "compatibility": {
"minimum": "10", "minimum": "10",
"verified": "10", "verified": "10",
@ -203,7 +203,7 @@
], ],
"socket": true, "socket": true,
"manifest": "https://www.uberwald.me/gitea/public/bol/raw/v10/system.json", "manifest": "https://www.uberwald.me/gitea/public/bol/raw/v10/system.json",
"download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v10.4.0.zip", "download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v10.4.3.zip",
"background": "systems/images/map_lemurie.webp", "background": "systems/images/map_lemurie.webp",
"gridDistance": 1.5, "gridDistance": 1.5,
"gridUnits": "m", "gridUnits": "m",

View File

@ -102,10 +102,10 @@
"hp": { "hp": {
"key": "hp", "key": "hp",
"label": "BOL.resources.hp", "label": "BOL.resources.hp",
"base": 0, "base": 1,
"value": 0, "value": 1,
"bonus": 0, "bonus": 0,
"max": 0 "max": 1
}, },
"hero": { "hero": {
"key": "hero", "key": "hero",

View File

@ -7,6 +7,23 @@
<div class="sidebar flex0 bol-actor-sidebar"> <div class="sidebar flex0 bol-actor-sidebar">
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100" <img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100"
style="border:1px outset lightgray; box-shadow: 5px 5px 5px gray" /> style="border:1px outset lightgray; box-shadow: 5px 5px 5px gray" />
<div></div>
{{#if (count boleffects)}}
<ol class="items-list">
<li class="item flexrow item-header">
<div class="item-name flex2">{{localize "BOL.ui.effects"}}</div>
</li>
{{#each boleffects as |effect keyEffect|}}
<li class="item flexrow" data-item-id="{{effect.id}}">
<div class="item-image"><img src="{{effect.img}}" title="{{effect.name}}"/></div>
<h4 class="item-name flex2"><a class="item-edit">{{effect.name}}</a></h4>
</li>
{{/each}}
</ol>
{{/if}}
</div> </div>
<div class="main flex1"> <div class="main flex1">

View File

@ -0,0 +1,35 @@
<form class="{{cssClass}} flexcol character-summary-container" autocomplete="off">
<ol class="items-list">
<li class="item flexrow item-header">
<div class="item-field item-name item-name-fixed-medium">{{localize "BOL.ui.name"}}</div>
{{#each config.attackAttributes as |attr key|}}
<div class="item-field flex2">{{abbrev3 (localize attr)}}</div>
{{/each}}
{{#each config.aptitudes as |apt key|}}
<div class="item-field flex2">{{abbrev3 (localize apt)}}</div>
{{/each}}
{{#each config.resources as |res key|}}
<div class="item-field flex2">{{abbrev3 (localize res)}}</div>
{{/each}}
</li>
{{#each pcs as |pc key|}}
<li class="item flexrow" data-actor-id="{{pc.id}}">
<div class="item-field item-name item-name-fixed-medium">{{pc.name}}</div>
{{#each pc.system.attributes as |attr key|}}
<div class="item-field flex2 "><a class="summary-roll" data-type="attribute" data-key="{{key}}">{{attr.value}}</a></div>
{{/each}}
{{#each pc.system.aptitudes as |apt key|}}
<div class="item-field flex2 "><a class="summary-roll" data-type="aptitude" data-key="{{key}}">{{apt.value}}</a></div>
{{/each}}
{{#each pc.system.resources as |res key|}}
<div class="item-field flex2 ">{{res.value}}/{{res.max}}</div>
{{/each}}
</li>
{{/each}}
</ol>
</form>