Add fight options
This commit is contained in:
parent
eacd32927c
commit
02b3dd5e0f
11
css/bol.css
11
css/bol.css
@ -617,6 +617,14 @@ a:hover {
|
||||
color: darkred;
|
||||
font-weight: bold;
|
||||
}
|
||||
h2.good {
|
||||
color: darkgreen;
|
||||
font-weight: bold;
|
||||
}
|
||||
h2.bad {
|
||||
color: darkred;
|
||||
font-weight: bold;
|
||||
}
|
||||
.message-header h2.roll {
|
||||
color: darkslategrey;
|
||||
font-weight: bold;
|
||||
@ -935,3 +943,6 @@ body.system-bol img#logo {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
.dialog-button {
|
||||
max-height: 2rem;
|
||||
}
|
19
lang/en.json
19
lang/en.json
@ -140,6 +140,14 @@
|
||||
"BOL.ui.rangeModifiers": "Range modifier",
|
||||
"BOL.ui.money": "Bougette",
|
||||
"BOL.ui.moneyTitle": "Gold & Treasure",
|
||||
"BOL.ui.fightOption": "Fight Options",
|
||||
"BOL.ui.none": "None",
|
||||
"BOL.ui.fightOptionType": "Fight Options types",
|
||||
"BOL.ui.activated": "Activated",
|
||||
"BOL.ui.deactivated": "Deactivated",
|
||||
"BOL.ui.status": "Status",
|
||||
"BOL.ui.toactivated": "Active (>Désactiver)",
|
||||
"BOL.ui.todeactivated": "Inactive (>Activer)",
|
||||
|
||||
"BOL.featureCategory.origins": "Origines",
|
||||
"BOL.featureCategory.races": "Races",
|
||||
@ -147,6 +155,7 @@
|
||||
"BOL.featureCategory.boons": "Avantages",
|
||||
"BOL.featureCategory.flaws": "Désavantages",
|
||||
"BOL.featureCategory.languages": "Langages",
|
||||
"BOL.featureCategory.fightoptions": "Fight Options",
|
||||
|
||||
"BOL.featureSubtypes.origin": "Origine",
|
||||
"BOL.featureSubtypes.race": "Race",
|
||||
@ -155,6 +164,7 @@
|
||||
"BOL.featureSubtypes.flaw": "Désavantage",
|
||||
"BOL.featureSubtypes.language": "Langage",
|
||||
"BOL.featureSubtypes.gods": "Faith & Gods",
|
||||
"BOL.featureSubtypes.fightOption": "Combat Option",
|
||||
|
||||
"BOL.bougette.nomoney": "Nothing",
|
||||
"BOL.bougette.tolive": "To live",
|
||||
@ -162,6 +172,14 @@
|
||||
"BOL.bougette.luxury" : "Luxury life",
|
||||
"BOL.bougette.rich": "Rich!",
|
||||
|
||||
"BOL.fightOptionTypes.armor": "Attaque au défaut d'armure",
|
||||
"BOL.fightOptionTypes.intrepid": "Attaque intrépide",
|
||||
"BOL.fightOptionTypes.twoweaponsdef": "Combat à 2 armes (Défense)",
|
||||
"BOL.fightOptionTypes.twoweaponsatt": "Combat à 2 armes (Attaque)",
|
||||
"BOL.fightOptionTypes.fulldefense": "Défense totale",
|
||||
"BOL.fightOptionTypes.defense": "Posture défensive",
|
||||
"BOL.fightOptionTypes.attack": "Posture offensive",
|
||||
|
||||
"BOL.itemCategory.object": "Objet",
|
||||
"BOL.itemCategory.equipment": "Équipement",
|
||||
"BOL.itemCategory.consumable": "Consommable",
|
||||
@ -175,6 +193,7 @@
|
||||
"BOL.combatCategory.shields": "Boucliers",
|
||||
"BOL.combatCategory.melee": "Armes de contact",
|
||||
"BOL.combatCategory.ranged": "Armes à distance",
|
||||
"BOL.combatCategory.fightOptions": "Fight options",
|
||||
|
||||
"BOL.equipmentCategory.weapon": "Arme",
|
||||
"BOL.equipmentCategory.armor": "Armure",
|
||||
|
19
lang/fr.json
19
lang/fr.json
@ -142,6 +142,14 @@
|
||||
"BOL.ui.rangeModifiers": "Mod. de Portée",
|
||||
"BOL.ui.money": "Bougette",
|
||||
"BOL.ui.moneyTitle": "Or et Piecettes",
|
||||
"BOL.ui.fightOption": "Options de Combat",
|
||||
"BOL.ui.none": "Aucune",
|
||||
"BOL.ui.fightOptionType": "Types d'options de Combat",
|
||||
"BOL.ui.activated": "Active",
|
||||
"BOL.ui.deactivated": "Inactive",
|
||||
"BOL.ui.toactivated": "Active (>Désactiver)",
|
||||
"BOL.ui.todeactivated": "Inactive (>Activer)",
|
||||
"BOL.ui.status": "Statut",
|
||||
|
||||
"BOL.featureCategory.origins": "Origines",
|
||||
"BOL.featureCategory.races": "Races",
|
||||
@ -149,6 +157,7 @@
|
||||
"BOL.featureCategory.boons": "Avantages",
|
||||
"BOL.featureCategory.flaws": "Désavantages",
|
||||
"BOL.featureCategory.languages": "Langues",
|
||||
"BOL.featureCategory.fightoptions": "Options de Combat",
|
||||
|
||||
"BOL.bougette.nomoney": "A sec",
|
||||
"BOL.bougette.tolive": "De quoi vivre",
|
||||
@ -163,6 +172,15 @@
|
||||
"BOL.featureSubtypes.flaw": "Désavantage",
|
||||
"BOL.featureSubtypes.language": "Langue",
|
||||
"BOL.featureSubtypes.gods": "Dieux & Foi",
|
||||
"BOL.featureSubtypes.fightOption": "Option de Combat",
|
||||
|
||||
"BOL.fightOptionTypes.armor": "Attaque au défaut d'armure",
|
||||
"BOL.fightOptionTypes.intrepid": "Attaque intrépide",
|
||||
"BOL.fightOptionTypes.twoweaponsdef": "Combat à 2 armes (Défense)",
|
||||
"BOL.fightOptionTypes.twoweaponsatt": "Combat à 2 armes (Attaque)",
|
||||
"BOL.fightOptionTypes.fulldefense": "Défense totale",
|
||||
"BOL.fightOptionTypes.defense": "Posture défensive",
|
||||
"BOL.fightOptionTypes.attack": "Posture offensive",
|
||||
|
||||
"BOL.itemCategory.object": "Objet",
|
||||
"BOL.itemCategory.equipment": "Équipement",
|
||||
@ -177,6 +195,7 @@
|
||||
"BOL.combatCategory.shields": "Boucliers",
|
||||
"BOL.combatCategory.melee": "Armes de contact",
|
||||
"BOL.combatCategory.ranged": "Armes à distance",
|
||||
"BOL.combatCategory.fightOptions": "Options de combat",
|
||||
|
||||
"BOL.equipmentCategory.weapon": "Arme",
|
||||
"BOL.equipmentCategory.armor": "Armure",
|
||||
|
@ -43,6 +43,11 @@ export class BoLActorSheet extends ActorSheet {
|
||||
this.actor.createEmbeddedDocuments('Item', [{ name: "Nouvel Equipement", type: "item" }], { renderSheet: true });
|
||||
});
|
||||
|
||||
html.find(".toggle-fight-option").click((ev) => {
|
||||
const li = $(ev.currentTarget).parents(".item")
|
||||
this.actor.toggleFightOption( li.data("itemId") )
|
||||
})
|
||||
|
||||
html.find(".inc-dec-btns-alchemy").click((ev) => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.spendAlchemyPoint( li.data("itemId"), 1)
|
||||
@ -97,17 +102,6 @@ export class BoLActorSheet extends ActorSheet {
|
||||
// Rollable abilities.
|
||||
html.find('.rollable').click(this._onRoll.bind(this));
|
||||
|
||||
// html.find('.roll-attribute').click(ev => {
|
||||
// this.actor.rollAttributeAptitude( $(ev.currentTarget).data("attr-key") );
|
||||
// });
|
||||
// html.find('.roll-career').click(ev => {
|
||||
// const li = $(ev.currentTarget).parents(".item");
|
||||
// this.actor.rollCareer( li.data("itemId") );
|
||||
// });
|
||||
// html.find('.roll-weapon').click(ev => {
|
||||
// const li = $(ev.currentTarget).parents(".item");
|
||||
// this.actor.rollWeapon( li.data("itemId") );
|
||||
// });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -131,11 +125,11 @@ export class BoLActorSheet extends ActorSheet {
|
||||
formData.alchemy = this.actor.alchemy
|
||||
formData.containers = this.actor.containers
|
||||
formData.treasure = this.actor.treasure
|
||||
formData.treasure = this.actor.treasure
|
||||
formData.treasure = this.actor.alchemyrecipe
|
||||
formData.vehicles = this.actor.vehicles;
|
||||
formData.ammos = this.actor.ammos;
|
||||
formData.misc = this.actor.misc;
|
||||
formData.alchemyrecipe = this.actor.alchemyrecipe
|
||||
formData.vehicles = this.actor.vehicles
|
||||
formData.fightoptions = this.actor.fightoptions
|
||||
formData.ammos = this.actor.ammos
|
||||
formData.misc = this.actor.misc
|
||||
formData.combat = this.actor.buildCombat()
|
||||
formData.features = this.actor.buildFeatures()
|
||||
formData.isGM = game.user.isGM
|
||||
@ -148,9 +142,9 @@ export class BoLActorSheet extends ActorSheet {
|
||||
formData.isAlchemist = this.actor.isAlchemist()
|
||||
formData.isPriest = this.actor.isPriest()
|
||||
|
||||
formData.isGM= game.user.isGM
|
||||
formData.isGM = game.user.isGM
|
||||
|
||||
console.log("ACTORDATA", formData);
|
||||
console.log("ACTORDATA", formData)
|
||||
return formData;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
|
@ -22,11 +22,6 @@ export class BoLActor extends Actor {
|
||||
super.prepareData();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
//_onUpdate(changed, options, user) {
|
||||
//
|
||||
//}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateResourcesData( ) {
|
||||
if ( this.type == 'character') {
|
||||
@ -50,22 +45,92 @@ export class BoLActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get itemData(){
|
||||
return Array.from(this.data.items.values()).map(i => i.data);
|
||||
return Array.from(this.data.items.values()).map(i => i.data)
|
||||
}
|
||||
get details() {
|
||||
return this.data.data.details;
|
||||
return this.data.data.details
|
||||
}
|
||||
get attributes() {
|
||||
return Object.values(this.data.data.attributes);
|
||||
return Object.values(this.data.data.attributes)
|
||||
}
|
||||
get aptitudes() {
|
||||
return Object.values(this.data.data.aptitudes);
|
||||
return Object.values(this.data.data.aptitudes)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
get defenseValue() {
|
||||
return this.data.data.aptitudes.def.value;
|
||||
let defMod = 0
|
||||
let fo = this.getActiveFightOption()
|
||||
if (fo && fo.data.properties.fightoptiontype == "intrepid" ) {
|
||||
defMod += -2
|
||||
}
|
||||
if (fo && fo.data.properties.fightoptiontype == "fulldefense" ) {
|
||||
defMod += 2
|
||||
}
|
||||
if (fo && fo.data.properties.fightoptiontype == "twoweaponsdef" && !fo.data.properties.used) {
|
||||
defMod += 1
|
||||
this.updateEmbeddedDocuments("Item", [ {_id: fo._id, 'data.properties.used': true}] )
|
||||
}
|
||||
if (fo && fo.data.properties.fightoptiontype == "defense" ) {
|
||||
defMod += 1
|
||||
}
|
||||
if (fo && fo.data.properties.fightoptiontype == "attack" ) {
|
||||
defMod += -1
|
||||
}
|
||||
return this.data.data.aptitudes.def.value + defMod
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getActiveFightOption( ) {
|
||||
let it = this.itemData.find(i => i.type === "feature" && i.data.subtype === "fightoption" && i.data.properties.activated)
|
||||
if (it) {
|
||||
return duplicate(it)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async toggleFightOption( itemId) {
|
||||
let fightOption = this.data.items.get(itemId)
|
||||
let state
|
||||
let updates = []
|
||||
|
||||
if ( fightOption) {
|
||||
fightOption = duplicate(fightOption)
|
||||
if (fightOption.data.properties.activated) {
|
||||
state = false
|
||||
} else {
|
||||
state = true
|
||||
}
|
||||
updates.push( {_id: fightOption._id, 'data.properties.activated': state} ) // Update the selected one
|
||||
await this.updateEmbeddedDocuments("Item", updates) // Apply all changes
|
||||
// Then notify
|
||||
ChatMessage.create({
|
||||
alias: this.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state} )
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get armorMalusValue() { // used for Fight Options
|
||||
for(let armor of this.armors) {
|
||||
if (armor.data.properties.armorQuality.includes("light")) {
|
||||
return 1
|
||||
}
|
||||
if (armor.data.properties.armorQuality.includes("medium")) {
|
||||
return 2
|
||||
}
|
||||
if (armor.data.properties.armorQuality.includes("heavy")) {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
get resources() {
|
||||
return Object.values(this.data.data.resources);
|
||||
return Object.values(this.data.data.resources)
|
||||
}
|
||||
get boons() {
|
||||
return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "boon");
|
||||
@ -83,13 +148,16 @@ export class BoLActor extends Actor {
|
||||
return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "race");
|
||||
}
|
||||
get languages() {
|
||||
return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "language");
|
||||
return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "language")
|
||||
}
|
||||
get fightoptions() {
|
||||
return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "fightoption")
|
||||
}
|
||||
get features() {
|
||||
return this.itemData.filter(i => i.type === "feature");
|
||||
return this.itemData.filter(i => i.type === "feature")
|
||||
}
|
||||
get equipment() {
|
||||
return this.itemData.filter(i => i.type === "item");
|
||||
return this.itemData.filter(i => i.type === "item")
|
||||
}
|
||||
get armors() {
|
||||
return this.itemData.filter(i => i.type === "item" && i.data.category === "equipment" && i.data.subtype === "armor");
|
||||
@ -267,9 +335,15 @@ export class BoLActor extends Actor {
|
||||
"label": "BOL.featureCategory.languages",
|
||||
"ranked": false,
|
||||
"items": this.languages
|
||||
},
|
||||
"fightoptions": {
|
||||
"label": "BOL.featureCategory.fightoptions",
|
||||
"ranked": false,
|
||||
"items": this.fightoptions
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
buildCombat(){
|
||||
return {
|
||||
"melee" : {
|
||||
@ -278,6 +352,7 @@ export class BoLActor extends Actor {
|
||||
"protection" : false,
|
||||
"blocking" : false,
|
||||
"ranged" : false,
|
||||
"options": false,
|
||||
"items" : this.melee
|
||||
},
|
||||
"ranged" : {
|
||||
@ -286,6 +361,7 @@ export class BoLActor extends Actor {
|
||||
"protection" : false,
|
||||
"blocking" : false,
|
||||
"ranged" : true,
|
||||
"options": false,
|
||||
"items" : this.ranged
|
||||
},
|
||||
"protections" : {
|
||||
@ -294,6 +370,7 @@ export class BoLActor extends Actor {
|
||||
"protection" : true,
|
||||
"blocking" : false,
|
||||
"ranged" : false,
|
||||
"options": false,
|
||||
"items" : this.protections
|
||||
},
|
||||
"shields" : {
|
||||
@ -302,9 +379,19 @@ export class BoLActor extends Actor {
|
||||
"protection" : false,
|
||||
"blocking" : true,
|
||||
"ranged" : false,
|
||||
"options": false,
|
||||
"items" : this.shields
|
||||
},
|
||||
"fightoptions" : {
|
||||
"label" : "BOL.combatCategory.fightOptions",
|
||||
"weapon" : false,
|
||||
"protection" : false,
|
||||
"blocking" : false,
|
||||
"ranged" : false,
|
||||
"options": true,
|
||||
"items" : this.fightoptions
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------- */
|
||||
|
@ -3,39 +3,47 @@ import { BoLUtility } from "../system/bol-utility.js";
|
||||
const __adv2dice = { ["1B"]: 3, ["2B"]: 4, ["2"]: 2, ["1M"]: 3, ["2M"]: 4 }
|
||||
const _apt2attr = { init: "mind", melee: "agility", ranged: "agility", def: "vigor" }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class BoLRoll {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static options() {
|
||||
return { classes: ["bol", "dialog"], width: 480, height: 540 };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static convertToAdv(adv) {
|
||||
if (adv == 0) return "2"
|
||||
return Math.abs(adv) + (adv < 0) ? 'M' : 'B';
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getDefaultAttribute(key) {
|
||||
return _apt2attr[key]
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static attributeCheck(actor, actorData, dataset, event) {
|
||||
const key = dataset.key;
|
||||
const adv = dataset.adv;
|
||||
let attribute = eval(`actor.data.data.attributes.${key}`);
|
||||
let label = (attribute.label) ? game.i18n.localize(attribute.label) : null;
|
||||
let description = actor.name + " - " + game.i18n.localize('BOL.ui.attributeCheck') + " - " + game.i18n.localize(attribute.label);
|
||||
return this.displayRollDialog(
|
||||
{
|
||||
mode: "attribute",
|
||||
actor: actor,
|
||||
actorData: actorData,
|
||||
attribute: attribute,
|
||||
attrValue: attribute.value,
|
||||
aptValue: 0,
|
||||
label: label,
|
||||
careerBonus: 0,
|
||||
description: description,
|
||||
adv: this.convertToAdv(adv),
|
||||
mod: 0
|
||||
});
|
||||
const key = dataset.key
|
||||
const adv = dataset.adv
|
||||
|
||||
let attribute = eval(`actor.data.data.attributes.${key}`)
|
||||
let label = (attribute.label) ? game.i18n.localize(attribute.label) : null
|
||||
let description = actor.name + " - " + game.i18n.localize('BOL.ui.attributeCheck') + " - " + game.i18n.localize(attribute.label)
|
||||
|
||||
let rollData = {
|
||||
mode: "attribute",
|
||||
actor: actor,
|
||||
actorData: actorData,
|
||||
attribute: attribute,
|
||||
attrValue: attribute.value,
|
||||
aptValue: 0,
|
||||
label: label,
|
||||
careerBonus: 0,
|
||||
description: description,
|
||||
adv: this.convertToAdv(adv),
|
||||
mod: 0
|
||||
}
|
||||
return this.displayRollDialog( rollData )
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -69,24 +77,31 @@ export class BoLRoll {
|
||||
/* -------------------------------------------- */
|
||||
static weaponCheck(actor, actorData, dataset, event) {
|
||||
let target = BoLUtility.getTarget()
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const weapon = actor.items.get(li.data("item-id"));
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
const weapon = actor.items.get(li.data("item-id"))
|
||||
if (!weapon) {
|
||||
ui.notifications.warn("Unable to find weapon !");
|
||||
ui.notifications.warn("Unable to find weapon !")
|
||||
return;
|
||||
}
|
||||
let weaponData = weapon.data.data
|
||||
let attribute = eval(`actor.data.data.attributes.${weaponData.properties.attackAttribute}`)
|
||||
let aptitude = eval(`actor.data.data.aptitudes.${weaponData.properties.attackAptitude}`)
|
||||
|
||||
console.debug("WEAPON!", weaponData)
|
||||
let attackDef = {
|
||||
// Manage specific case
|
||||
let fightOption= actor.getActiveFightOption()
|
||||
if ( fightOption && fightOption.data.fightoptiontype == "fulldefense") {
|
||||
ui.notifications.warn(`{{actor.name}} est en Défense Totale ! Il ne peut pas attaquer ce round.`)
|
||||
return
|
||||
}
|
||||
// Build the roll structure
|
||||
let rolldata = {
|
||||
mode: "weapon",
|
||||
actor: actor,
|
||||
actorData: actorData,
|
||||
weapon: weapon,
|
||||
isRanged: weaponData.properties.ranged || weaponData.properties.throwing,
|
||||
target: target,
|
||||
fightOption: fightOption,
|
||||
careerBonus: 0,
|
||||
defender: (target) ? game.actors.get(target.data.actorId) : undefined,
|
||||
attribute: attribute,
|
||||
@ -98,7 +113,7 @@ export class BoLRoll {
|
||||
label: (weapon.name) ? weapon.name : game.i18n.localize('BOL.ui.noWeaponName'),
|
||||
description: actor.name + " - " + game.i18n.localize('BOL.ui.weaponAttack'),
|
||||
}
|
||||
return this.displayRollDialog(attackDef);
|
||||
return this.displayRollDialog(rolldata)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -179,7 +194,36 @@ export class BoLRoll {
|
||||
}
|
||||
|
||||
$('#roll-modifier').val( this.rollData.attrValue + "+" + this.rollData.aptValue + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
||||
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "+" + this.rollData.shieldMalus )
|
||||
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "-" + this.rollData.modArmorMalus + "-" +
|
||||
this.rollData.shieldMalus + "+" + this.rollData.attackModifier )
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static preProcessFightOption( rollData) {
|
||||
rollData.damagesIgnoresArmor = false // Always reset flags
|
||||
rollData.modArmorMalus = 0
|
||||
rollData.attackModifier = 0
|
||||
|
||||
let fgItem = rollData.fightOption
|
||||
if (fgItem ) {
|
||||
console.log(fgItem)
|
||||
if (fgItem.data.properties.fightoptiontype == "armordefault") {
|
||||
rollData.modArmorMalus = rollData.armorMalus // Activate the armor malus
|
||||
rollData.damagesIgnoresArmor = true
|
||||
}
|
||||
if (fgItem.data.properties.fightoptiontype == "intrepid") {
|
||||
rollData.attackModifier += 2
|
||||
}
|
||||
if (fgItem.data.properties.fightoptiontype == "defense") {
|
||||
rollData.attackModifier += -1
|
||||
}
|
||||
if (fgItem.data.properties.fightoptiontype == "attack") {
|
||||
rollData.attackModifier += 1
|
||||
}
|
||||
if (fgItem.data.properties.fightoptiontype == "twoweaponsdef" || fgItem.data.properties.fightoptiontype == "twoweaponsatt") {
|
||||
rollData.attackModifier += -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -250,15 +294,37 @@ export class BoLRoll {
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static preProcessWeapon( rollData) {
|
||||
if (rollData.mode == "weapon") {
|
||||
rollData.weaponModifier = rollData.weapon.data.data.properties.attackModifiers ?? 0;
|
||||
rollData.attackBonusDice = rollData.weapon.data.data.properties.attackBonusDice
|
||||
if (rollData.defender) { // If target is selected
|
||||
rollData.defence = rollData.defender.defenseValue
|
||||
rollData.armorMalus = rollData.defender.armorMalusValue
|
||||
rollData.shieldBlock = 'none'
|
||||
let shields = rollData.defender.shields
|
||||
for (let shield of shields) {
|
||||
rollData.shieldBlock = (shield.data.properties.blocking.blockingAll) ? 'blockall' : 'blockone';
|
||||
rollData.shieldAttackMalus = (shield.data.properties.blocking.malus) ? shield.data.properties.blocking.malus : 1;
|
||||
rollData.applyShieldMalus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ROLL DIALOGS */
|
||||
/* -------------------------------------------- */
|
||||
static async displayRollDialog(rollData, onEnter = "submit") {
|
||||
|
||||
// initialize default flags/values
|
||||
const rollOptionTpl = `systems/bol/templates/dialogs/${rollData.mode}-roll-dialog.hbs`
|
||||
rollData.careers = rollData.actorData.features.careers
|
||||
rollData.boons = rollData.actor.bonusBoons
|
||||
rollData.flaws = rollData.actor.malusFlaws
|
||||
rollData.defence = 0
|
||||
rollData.attackModifier = 0 // Used for fight options
|
||||
rollData.modArmorMalus = 0 // Used for fight options
|
||||
rollData.bDice = 0
|
||||
rollData.mDice = 0
|
||||
rollData.nbBoons = 0
|
||||
@ -273,31 +339,17 @@ export class BoLRoll {
|
||||
rollData.modRanged = rollData.modRanged ?? 0
|
||||
rollData.mod = rollData.mod ?? 0
|
||||
rollData.id = randomID(16)
|
||||
|
||||
// Weapon mode specific management
|
||||
rollData.weaponModifier = 0
|
||||
rollData.attackBonusDice = false
|
||||
|
||||
// Saves
|
||||
rollData.armorMalus = 0
|
||||
// Specific stuff
|
||||
this.preProcessWeapon(rollData)
|
||||
this.preProcessFightOption(rollData)
|
||||
// Save
|
||||
this.rollData = rollData
|
||||
console.log("ROLLDATA", rollData)
|
||||
|
||||
if (rollData.mode == "weapon") {
|
||||
rollData.weaponModifier = rollData.weapon.data.data.properties.attackModifiers ?? 0;
|
||||
rollData.attackBonusDice = rollData.weapon.data.data.properties.attackBonusDice
|
||||
if (rollData.defender) { // If target is selected
|
||||
rollData.defence = rollData.defender.defenseValue
|
||||
rollData.shieldBlock = 'none'
|
||||
let shields = rollData.defender.shields
|
||||
//console.log("Shields", shields)
|
||||
for (let shield of shields) {
|
||||
rollData.shieldBlock = (shield.data.properties.blocking.blockingAll) ? 'blockall' : 'blockone';
|
||||
rollData.shieldAttackMalus = (shield.data.properties.blocking.malus) ? shield.data.properties.blocking.malus : 1;
|
||||
rollData.applyShieldMalus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then display+process the dialog
|
||||
const rollOptionContent = await renderTemplate(rollOptionTpl, rollData);
|
||||
let d = new Dialog({
|
||||
title: rollData.label,
|
||||
@ -325,7 +377,7 @@ export class BoLRoll {
|
||||
const isMalus = rollData.mDice > 0
|
||||
rollData.nbDice += (rollData.attackBonusDice) ? 1 : 0
|
||||
|
||||
const modifiers = rollData.attrValue + rollData.aptValue + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence + rollData.shieldMalus
|
||||
const modifiers = rollData.attrValue + rollData.aptValue + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier
|
||||
const formula = (isMalus) ? rollData.nbDice + "d6kl2 + " + modifiers : rollData.nbDice + "d6kh2 + " + modifiers
|
||||
rollData.formula = formula
|
||||
rollData.modifiers = modifiers
|
||||
@ -365,15 +417,16 @@ export class BoLDefaultRoll {
|
||||
|
||||
async roll() {
|
||||
|
||||
const r = new Roll(this.rollData.formula);
|
||||
await r.roll({ "async": false });
|
||||
const activeDice = r.terms[0].results.filter(r => r.active);
|
||||
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b);
|
||||
const r = new Roll(this.rollData.formula)
|
||||
// console.log("Roll formula", this.rollData.formula)
|
||||
await r.roll({ "async": false })
|
||||
const activeDice = r.terms[0].results.filter(r => r.active)
|
||||
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b)
|
||||
this.rollData.roll = r
|
||||
this.rollData.isSuccess = (r.total >= 9);
|
||||
this.rollData.isSuccess = (r.total >= 9)
|
||||
this.rollData.isCritical = (diceTotal === 12)
|
||||
this.rollData.isRealCritical = (diceTotal === 12)
|
||||
this.rollData.isFumble = (diceTotal === 2);
|
||||
this.rollData.isFumble = (diceTotal === 2)
|
||||
this.rollData.isFailure = !this.rollData.isSuccess
|
||||
if (this.rollData.reroll == undefined) {
|
||||
this.rollData.reroll = this.rollData.actor.heroReroll()
|
||||
@ -456,10 +509,10 @@ export class BoLDefaultRoll {
|
||||
bonusDmg = 12
|
||||
}
|
||||
let attrDamageValue = this.getDamageAttributeValue(this.rollData.weapon.data.data.properties.damageAttribute)
|
||||
let weaponFormula = BoLUtility.getDamageFormula(this.rollData.weapon.data.data)
|
||||
let weaponFormula = BoLUtility.getDamageFormula(this.rollData.weapon.data.data, this.rollData.fightOption )
|
||||
|
||||
let damageFormula = weaponFormula + "+" + bonusDmg + "+" + attrDamageValue
|
||||
console.log("DAMAGE !!!", damageFormula, attrDamageValue)
|
||||
console.log("DAMAGE !!!", damageFormula, attrDamageValue, this.rollData)
|
||||
|
||||
//console.log("Formula", weaponFormula, damageFormula, this.rollData.weapon.data.data.properties.damage)
|
||||
this.rollData.damageFormula = damageFormula
|
||||
@ -474,7 +527,7 @@ export class BoLDefaultRoll {
|
||||
|
||||
_buildDamageChatMessage(rollData) {
|
||||
const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs';
|
||||
return renderTemplate(rollMessageTpl, rollData);
|
||||
return renderTemplate(rollMessageTpl, rollData)
|
||||
}
|
||||
|
||||
_buildChatMessage(rollData) {
|
||||
|
@ -48,7 +48,18 @@ export class BoLCombatManager extends Combat {
|
||||
fvttInit += (cId / 100)
|
||||
await this.updateEmbeddedDocuments("Combatant", [{ _id: ids[cId], initiative: fvttInit }]);
|
||||
}
|
||||
console.log("TODO : Compute init for actor");
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
nextRound() {
|
||||
let combatants = this.combatants.contents
|
||||
for (let c of combatants) {
|
||||
let actor = game.actors.get( c.data.actorId )
|
||||
//actor.clearRoundModifiers()
|
||||
}
|
||||
super.nextRound()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ export class BoLUtility {
|
||||
chatGM.whisper = this.getUsers(user => user.isGM);
|
||||
chatGM.content = "Blind message of " + game.user.name + "<br>" + chatOptions.content;
|
||||
console.log("blindMessageToGM", chatGM);
|
||||
game.socket.emit("system.fvtt-fragged-kingdom", { msg: "msg_gm_chat_message", data: chatGM });
|
||||
game.socket.emit("system.bol", { msg: "msg_gm_chat_message", data: chatGM });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -335,53 +335,6 @@ export class BoLUtility {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rollBoL(rollData) {
|
||||
|
||||
// Dice bonus/malus selection
|
||||
let nbDice = 2;
|
||||
let d6BM = 0;
|
||||
let mode = "";
|
||||
if (rollData.d6Malus > rollData.d6Bonus) {
|
||||
d6BM = rollData.d6Malus - rollData.d6Bonus;
|
||||
mode = "kl2";
|
||||
}
|
||||
if (rollData.d6Bonus > rollData.d6Malus) {
|
||||
d6BM = rollData.d6Bonus - rollData.d6Malus;
|
||||
mode = "kh2";
|
||||
}
|
||||
nbDice += d6BM;
|
||||
|
||||
// Final modifier
|
||||
let modifier = Number(rollData.bonusMalus);
|
||||
if (rollData.mode == 'career') {
|
||||
modifier += Number(rollData.attributes[rollData.rollAttribute].value) + Number(rollData.career.data.rank);
|
||||
} else if (rollData.mode == 'attribute') {
|
||||
modifier += rollData.attribute.value;
|
||||
} else if (rollData.mode == 'weapon') {
|
||||
modifier += Number(rollData.attributes[rollData.rollAttribute].value) + Number(rollData.aptitude.value) + Number(rollData.rangeModifier);
|
||||
modifier -= rollData.defender.data.aptitudes.def.value;
|
||||
}
|
||||
|
||||
let formula = nbDice + "d6" + mode + "+" + modifier;
|
||||
|
||||
console.log("Going to roll ", formula, rollData.attributes, rollData.rollAttribute);
|
||||
let myRoll = new Roll(formula).roll({ async: false });
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"));
|
||||
rollData.roll = myRoll;
|
||||
rollData.formula = formula;
|
||||
rollData.modifier = modifier;
|
||||
rollData.nbDice = nbDice;
|
||||
rollData.finalScore = myRoll.total;
|
||||
|
||||
let actor = game.actors.get(rollData.actorId);
|
||||
actor.saveRollData(rollData);
|
||||
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/bol/templates/chat/chat-generic-result.hbs`, rollData)
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async processAttackSuccess(attackDef) {
|
||||
if (!game.user.isGM) { // Only GM process this
|
||||
@ -399,9 +352,10 @@ export class BoLUtility {
|
||||
attacker: attackDef.attacker,
|
||||
defender: attackDef.defender,
|
||||
defenderWeapons: defenderWeapons,
|
||||
damageTotal: attackDef.damageRoll.total
|
||||
damageTotal: attackDef.damageRoll.total,
|
||||
damagesIgnoresArmor: attackDef.damagesIgnoresArmor,
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -423,7 +377,8 @@ export class BoLUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDamageFormula(weaponData) {
|
||||
static getDamageFormula(weaponData, fightOption) {
|
||||
let upgradeDamage = (fightOption && fightOption.data.properties.fightoptiontype == "twoweaponsatt")
|
||||
let damageString = weaponData.properties.damage
|
||||
let modifier = weaponData.properties.damageModifiers ?? 0
|
||||
let multiplier = weaponData.properties.damageMultiplier ?? 1
|
||||
@ -435,26 +390,33 @@ export class BoLUtility {
|
||||
|
||||
let formula = damageString
|
||||
if (damageString.includes("d") || damageString.includes("D")) {
|
||||
var myReg = new RegExp('(\\d+)[dD]([\\d]+)([MB]*)?([\\+\\d]*)?', 'g');
|
||||
let res = myReg.exec(damageString);
|
||||
let nbDice = parseInt(res[1]);
|
||||
let postForm = 'kh' + nbDice;
|
||||
let modIndex = 3;
|
||||
var myReg = new RegExp('(\\d+)[dD]([\\d]+)([MB]*)?([\\+\\d]*)?', 'g')
|
||||
let res = myReg.exec(damageString)
|
||||
let nbDice = parseInt(res[1])
|
||||
let postForm = 'kh' + nbDice
|
||||
let modIndex = 3
|
||||
// Upgrade damage if needed
|
||||
if ( upgradeDamage && ( !res[3] || res[3]=="") ) {
|
||||
res[3] = "B" // Upgrade to bonus
|
||||
}
|
||||
if (res[3]) {
|
||||
if ( upgradeDamage && res[3] == 'M') {
|
||||
res[3] = "" // Disable lamlus for upgradeDamage
|
||||
}
|
||||
if (res[3] == 'M') {
|
||||
postForm = 'kl' + nbDice;
|
||||
nbDice++;
|
||||
modIndex = 4;
|
||||
postForm = 'kl' + nbDice
|
||||
nbDice++
|
||||
modIndex = 4
|
||||
}
|
||||
if (res[3] == 'B') {
|
||||
postForm = 'kh' + nbDice;
|
||||
nbDice++;
|
||||
modIndex = 4;
|
||||
postForm = 'kh' + nbDice
|
||||
nbDice++
|
||||
modIndex = 4
|
||||
}
|
||||
}
|
||||
formula = "(" + nbDice + "d" + res[2] + reroll + postForm + "+" + modifier + ") *" + multiplier;
|
||||
formula = "(" + nbDice + "d" + res[2] + reroll + postForm + "+" + modifier + ") *" + multiplier
|
||||
}
|
||||
return formula;
|
||||
return formula
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -254,7 +254,18 @@ BOL.featureSubtypes = {
|
||||
"boon" : "BOL.featureSubtypes.boon",
|
||||
"flaw" : "BOL.featureSubtypes.flaw",
|
||||
"language" : "BOL.featureSubtypes.language",
|
||||
"godsfaith" : "BOL.featureSubtypes.gods"
|
||||
"godsfaith" : "BOL.featureSubtypes.gods",
|
||||
"fightoption" : "BOL.featureSubtypes.fightOption"
|
||||
}
|
||||
|
||||
BOL.fightOptionTypes = {
|
||||
"armordefault": "BOL.fightOptionTypes.armor",
|
||||
"intrepid": "BOL.fightOptionTypes.intrepid",
|
||||
"twoweaponsdef": "BOL.fightOptionTypes.twoweaponsdef",
|
||||
"twoweaponsatt": "BOL.fightOptionTypes.twoweaponsatt",
|
||||
"fulldefense": "BOL.fightOptionTypes.fulldefense",
|
||||
"defense": "BOL.fightOptionTypes.defense",
|
||||
"attack": "BOL.fightOptionTypes.attack",
|
||||
}
|
||||
|
||||
BOL.itemIcons = {
|
||||
|
@ -33,6 +33,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||
"systems/bol/templates/item/parts/properties/feature/flaw-properties.hbs",
|
||||
"systems/bol/templates/item/parts/properties/feature/origin-properties.hbs",
|
||||
"systems/bol/templates/item/parts/properties/feature/race-properties.hbs",
|
||||
"systems/bol/templates/item/parts/properties/feature/fightoption-properties.hbs",
|
||||
|
||||
// DIALOGS
|
||||
"systems/bol/templates/chat/rolls/attack-damage-card.hbs",
|
||||
@ -48,6 +49,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||
"systems/bol/templates/dialogs/boons-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/flaws-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/total-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/fightoptions-roll-part.hbs",
|
||||
];
|
||||
|
||||
// Load the template parts
|
||||
|
7
packs/fightoptions.db
Normal file
7
packs/fightoptions.db
Normal file
@ -0,0 +1,7 @@
|
||||
{"_id":"4VsEmcj4YpdAaaZY","name":"Attaque au Défaut d'armure","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous visez une zone du corps non protégée ou un point faible de l’armure de votre adversaire.</p>\n<p>Appliquez la valeur de protection fixe de l’armure comme malus à votre jet d’attaque (-1 pour une armure légère, -2 pour une armure moyenne et -3 pour une armure lourde). Si votre attaque passe malgré ce malus, les dégâts de votre coup ignorent la protection de l’armure.</p>\n<p>Si le MJ l’accepte, cette option de combat pourra également permettre de trouver le défaut de l’armure naturelle d’une créature.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"armordefault","activated":false},"rank":0,"fightoptiontype":"armordefault"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.3nzfQvMvkK4ujRqI"}}}
|
||||
{"name":"Posture Défensive","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous choisissez d’adopter une attitude prudente, en restant toujours prêt à parer ou à esquiver l’attaque de votre adversaire. Combattre en posture défensive vous confère un bonus de +1 en défense, mais vous subissez un malus de -1 à votre jet d’attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"defense","activated":false},"rank":0,"fightoptiontype":"defense"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.CS1fCtHTxp5v1krr"}},"_id":"FQPqaB86ZkRzsKwG"}
|
||||
{"name":"Défense Totale","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous consacrez votre round à esquiver, parer et vous protéger des coups. Vous n’ effectuez pas d’attaque durant le round, mais bénéficiez d’un bonus de +2 en défense, qui s’ajoute éventuellement à celui que pourrait vous apporter un bouclier ou une arme secondaire de parade.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"fulldefense","activated":false},"rank":0,"fightoptiontype":"fulldefense"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.t8v7isBpnFzAbmUI"}},"_id":"JRboSn5RuGILpH0B"}
|
||||
{"name":"Combat à Deux Armes (Défensif)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes légères ou moyennes.</p>\n<p>Vous attaquez avec une arme et parez avec l’autre. Vous considérez l’arme de parade comme l’équivalent d’un petit bouclier (+1 en défense contre une attaque), mais vous subissez un malus de -1 sur votre jet d’attaque avec votre autre arme.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"twoweaponsdef","activated":false},"rank":0,"fightoptiontype":"twoweapons"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"_id":"JtU8EmKuda0M4Onv"}
|
||||
{"_id":"a3Ev9xm8aM9kAmi3","name":"Attaque Intrépide","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous attaquez avec la plus extrême témérité.</p>\n<p>Vous ne bénéficiez pas de l’éventuel bonus d’un bouclier ou d’une arme secondaire de parade et subissez un malus de -2 à la défense. En revanche, vous bénéficiez d’un bonus de +2 au jet d’attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"intrepid","activated":false},"rank":0,"fightoptiontype":"intrepid"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.589BS9KBGnUazrFA"}}}
|
||||
{"name":"Posture Offensive","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous vous concentrez sur l’attaque, au détriment de votre défense. Cette option vous confère un bonus de +1 au jet d’attaque, mais vous subissez un malus de -1 en défense.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"attack","activated":false},"rank":0,"fightoptiontype":"attack"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.BF7F5WvL1pbWVHNq"}},"_id":"hgUHJP6JFxbeiRQL"}
|
||||
{"name":"Combat à Deux Armes (Offensif)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes légères ou moyennes.</p>\n<p><span style=\"font-family: var(--font-primary); font-size: var(--font-size-14);\">Vous attaquez avec vos deux armes. </span><span style=\"font-family: var(--font-primary); font-size: var(--font-size-14);\">Vous n’effectuez qu’un seul jet d’attaque avec un </span>malus de -1, mais vous infligez des dégâts comme si vous maniez une arme moyenne (si vous utilisez deux armes légères) ou une arme lourde (si vous utilisez une arme moyenne et une arme légère, ou deux armes moyennes).</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"twoweaponsatt","activated":false},"rank":0,"fightoptiontype":"twoweapons"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"_id":"wM4ZIVSSKApgzEmN"}
|
13
system.json
13
system.json
@ -7,8 +7,8 @@
|
||||
"url": "https://github.com/ZigmundKreud/bol",
|
||||
"license": "LICENSE.txt",
|
||||
"flags": {},
|
||||
"version": "1.1.0",
|
||||
"templateVersion": 21,
|
||||
"version": "1.2.0",
|
||||
"templateVersion": 22,
|
||||
"minimumCoreVersion": "0.8.6",
|
||||
"compatibleCoreVersion": "9",
|
||||
"scripts": [],
|
||||
@ -135,6 +135,15 @@
|
||||
"system": "bol",
|
||||
"entity": "Item",
|
||||
"private": false
|
||||
},
|
||||
{
|
||||
"label": "Options de Combat",
|
||||
"type": "Item",
|
||||
"name": "fightoptions",
|
||||
"path": "packs/fightoptions.db",
|
||||
"system": "bol",
|
||||
"entity": "Item",
|
||||
"private": false
|
||||
}
|
||||
],
|
||||
"system": [],
|
||||
|
@ -26,13 +26,17 @@
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
<div class="tab stats" data-group="primary" data-tab="stats">{{>
|
||||
"systems/bol/templates/actor/parts/tabs/actor-stats.hbs"}}</div>
|
||||
"systems/bol/templates/actor/parts/tabs/actor-stats.hbs"}}
|
||||
</div>
|
||||
|
||||
<div class="tab actions" data-group="primary" data-tab="actions">
|
||||
{{> "systems/bol/templates/actor/parts/tabs/actor-actions.hbs"}}
|
||||
</div>
|
||||
|
||||
<div class="tab combat" data-group="primary" data-tab="combat">
|
||||
{{> "systems/bol/templates/actor/parts/tabs/actor-combat.hbs"}}
|
||||
</div>
|
||||
|
||||
<div class="tab features" data-group="primary" data-tab="features">
|
||||
{{> "systems/bol/templates/actor/parts/tabs/actor-features.hbs"}}
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@
|
||||
{{#if blocking}}<div class="item-field">{{localize "BOL.ui.blocking"}}</div>{{/if}}
|
||||
{{#if weapon}}<div class="item-field">{{localize "BOL.ui.damages"}}</div>{{/if}}
|
||||
{{#if ranged}}<div class="item-field">{{localize "BOL.ui.range"}}</div>{{else}}<div class="item-field"></div>{{/if}}
|
||||
{{#if options}}<div class="item-field">{{localize "BOL.ui.status"}}</div>{{else}}<div class="item-field"></div>{{/if}}
|
||||
</li>
|
||||
{{#each combatType.items as |item id|}}
|
||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||
@ -15,6 +16,15 @@
|
||||
{{#if ../blocking}}<div class="item-field">{{item.data.properties.blocking.malus}}</div>{{/if}}
|
||||
{{#if ../weapon}}<div class="item-field"><a class="rollable" data-roll-type="damage">{{item.data.properties.damage}}</a></div>{{/if}}
|
||||
{{#if ../ranged}}<div class="item-field">{{item.data.properties.range}}</div>{{else}}<div class="item-field"></div>{{/if}}
|
||||
{{#if ../options}}<div class="item-field">
|
||||
{{#if item.data.properties.activated}}
|
||||
<a class="toggle-fight-option">{{localize "BOL.ui.toactivated"}}</a>
|
||||
{{else}}
|
||||
<a class="toggle-fight-option">{{localize "BOL.ui.todeactivated"}}</a>
|
||||
{{/if}}
|
||||
</div>{{else}}
|
||||
<div class="item-field"></div>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
|
14
templates/chat/chat-activate-fight-option.hbs
Normal file
14
templates/chat/chat-activate-fight-option.hbs
Normal file
@ -0,0 +1,14 @@
|
||||
<div>
|
||||
<img class="chat-icon" src="{{img}}" alt="{{name}}"/>
|
||||
<h2 class="good"><strong>{{name}}</strong></h2>
|
||||
</div>
|
||||
|
||||
<div class="flexrow">
|
||||
{{#if state}}
|
||||
{{name}} active son option de combat {{foName}} pour ce round !
|
||||
{{else}}
|
||||
{{name}} désactive son option de combat {{foName}} pour ce round !
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
|
@ -1,41 +0,0 @@
|
||||
<div class="chat-message-header flexrow">
|
||||
<img class="chat-icon" src="{{actorImg}}" alt="{{alias}}"/>
|
||||
<h4 class=chat-actor-name>{{alias}}</h4>
|
||||
</div>
|
||||
<div class="flexrow">
|
||||
<h3>
|
||||
{{#if (eq mode "attribute")}}
|
||||
{{localize attribute.label}}
|
||||
{{else}}
|
||||
{{#if (eq mode "career")}}
|
||||
{{localize "Career"}} : {{career.name}}
|
||||
{{else}}
|
||||
{{#if (eq mode "weapon")}}
|
||||
{{localize "Attack with"}} {{weapon.name}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="dice-roll">
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{formula}}</div>
|
||||
<div class="dice-formula">{{modifier}}</div>
|
||||
<div class="dice-tooltip" style="display: none;">
|
||||
<section class="tooltip-part">
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">{{formula}}</span>
|
||||
<span class="part-total">{{finalScore}}</span>
|
||||
</header>
|
||||
<ol class="dice-rolls">
|
||||
<li class="roll die d6 discarded min">1</li>
|
||||
<li class="roll die d6">2</li>
|
||||
<li class="roll die d6">3</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<h4 class="dice-total">{{finalScore}}</h4>
|
||||
</div>
|
||||
</div>
|
@ -1,5 +1,7 @@
|
||||
<img class="chat-icon" src="{{img}}" alt="{{name}}"/>
|
||||
<h3><strong>{{name}}</strong></h3>
|
||||
<div>
|
||||
<img class="chat-icon" src="{{img}}" alt="{{name}}"/>
|
||||
<h2 class="bad"><strong>{{name}}</strong></h2>
|
||||
</div>
|
||||
|
||||
<div class="flexrow">
|
||||
|
||||
|
@ -5,4 +5,5 @@
|
||||
<div id="{{applyId}}">
|
||||
<button class="chat-damage-apply" data-attack-id="{{id}}">Appliquer les dommages à la cible</button>
|
||||
</div>
|
||||
<br>
|
||||
{{/if}}
|
||||
|
@ -1,21 +1,30 @@
|
||||
<img class="chat-icon" src="{{actor.img}}" alt="{{actor.name}}"/>
|
||||
{{#if isSuccess}}
|
||||
{{#if isCritical}}
|
||||
<h2 class="success critical"><i class="fas fa-check-double"></i> {{localize "BOL.ui.critical"}}...</h2>
|
||||
{{else}}
|
||||
<h2 class="success"><i class="fas fa-check"></i> {{localize "BOL.ui.success"}}...</h2>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if isFailure}}
|
||||
{{#if isFumble}}
|
||||
<h2 class="failure fumble"><i class="fas fa-skull-crossbones"></i> {{localize "BOL.ui.fumble"}}...</h2>
|
||||
{{else}}
|
||||
<h2 class="failure"><i class="fas fa-times"></i> {{localize "BOL.ui.failure"}}...</h2>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div>
|
||||
{{#if isSuccess}}
|
||||
{{#if isCritical}}
|
||||
<h2 class="success critical"><i class="fas fa-check-double"></i> {{localize "BOL.ui.critical"}}...
|
||||
{{else}}
|
||||
<h2 class="success"><i class="fas fa-check"></i> {{localize "BOL.ui.success"}}...
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if isFailure}}
|
||||
{{#if isFumble}}
|
||||
<h2 class="failure fumble"><i class="fas fa-skull-crossbones"></i> {{localize "BOL.ui.fumble"}}...
|
||||
{{else}}
|
||||
<h2 class="failure"><i class="fas fa-times"></i> {{localize "BOL.ui.failure"}}...
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<img class="chat-icon" src="{{actor.img}}" alt="{{actor.name}}"/>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<h3><strong>{{description}}</strong></h3>
|
||||
|
||||
{{#if fightOption}}
|
||||
<div>
|
||||
Option de combat : {{fightOption.name}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div id="{{optionsId}}">
|
||||
{{#if (and isSuccess weapon)}}
|
||||
{{> "systems/bol/templates/chat/rolls/attack-damage-card.hbs"}}
|
||||
@ -33,4 +42,5 @@
|
||||
{{#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>
|
||||
{{/if}}
|
||||
<br>
|
||||
</div>
|
@ -1,6 +1,10 @@
|
||||
<img class="chat-icon" src="{{defender.img}}" alt="{{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 !
|
||||
{{/if}}
|
||||
|
||||
<button class="damage-handling" data-defense-mode="damage-with-armor" data-attack-id="{{attackId}}">Encaisser avec la protection de l'armure</button>
|
||||
<button class="damage-handling" data-defense-mode="damage-without-armor" data-attack-id="{{attackId}}">Encaisser sans la protection de l'armure</button>
|
||||
|
||||
|
10
templates/dialogs/fightoptions-roll-part.hbs
Normal file
10
templates/dialogs/fightoptions-roll-part.hbs
Normal file
@ -0,0 +1,10 @@
|
||||
{{#if fightOption}}
|
||||
<div class="flexrow" style="margin-bottom: 1px;">
|
||||
<div class="flex1 center bg-darkred">
|
||||
<label for="fg">{{localize 'BOL.ui.fightOption'}}</label>
|
||||
</div>
|
||||
<div class="flex1 center cell">
|
||||
{{fightOption.name}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
@ -45,6 +45,8 @@
|
||||
|
||||
{{> "systems/bol/templates/dialogs/flaws-roll-part.hbs"}}
|
||||
|
||||
{{> "systems/bol/templates/dialogs/fightoptions-roll-part.hbs"}}
|
||||
|
||||
{{> "systems/bol/templates/dialogs/adv-roll-part.hbs"}}
|
||||
|
||||
{{> "systems/bol/templates/dialogs/mod-roll-part.hbs"}}
|
||||
|
@ -12,9 +12,9 @@
|
||||
{{#if (equals data.subtype "career")}}
|
||||
{{> "systems/bol/templates/item/parts/properties/feature/career-properties.hbs"}}
|
||||
{{/if}}
|
||||
{{!#if (equals data.subtype "origin")}}
|
||||
{{!> "systems/bol/templates/item/parts/properties/feature/origin-properties.hbs"}}
|
||||
{{!/if}}
|
||||
{{#if (equals data.subtype "fightoption")}}
|
||||
{{> "systems/bol/templates/item/parts/properties/feature/fightoption-properties.hbs"}}
|
||||
{{/if}}
|
||||
{{!#if (equals data.subtype "race")}}
|
||||
{{!> "systems/bol/templates/item/parts/properties/feature/race-properties.hbs"}}
|
||||
{{!/if}}
|
||||
|
@ -0,0 +1,19 @@
|
||||
<h3 class="form-header">{{localize "BOL.ui.fightOption"}}</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="property-label">{{localize "BOL.ui.fightOptionType"}}</label>
|
||||
<div class="form-fields">
|
||||
<select name="data.properties.fightoptiontype" data-dtype="String">
|
||||
{{#select data.properties.fightoptiontype}}
|
||||
{{#each config.fightOptionTypes as |item id|}}
|
||||
<option value="{{id}}">{{localize item}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="property flexrow">
|
||||
<label class="property-label">{{localize "BOL.ui.activated"}}</label>
|
||||
<input class="field-value" type="checkbox" name="data.properties.activated" {{checked data.properties.activated}}>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user