From 3b612b54279323a4d95a5dec07090a2d207b01c3 Mon Sep 17 00:00:00 2001 From: HavelockV Date: Tue, 18 Aug 2020 21:28:36 +0200 Subject: [PATCH 01/11] difficulty switch imple --- lang/en.json | 10 ++++++- module/apps/roll-dialog.js | 3 +- module/chat.js | 6 +++- module/check.js | 49 +++++++++++++++++++++++++++++---- module/coc7.js | 14 ++++++++++ templates/apps/bonus.html | 4 +-- templates/chat/roll-result.html | 32 +++++++++++++++++++++ 7 files changed, 108 insertions(+), 10 deletions(-) diff --git a/lang/en.json b/lang/en.json index 8c6acb71..bbb7b6de 100644 --- a/lang/en.json +++ b/lang/en.json @@ -77,7 +77,9 @@ "CoC7.HardDifficulty": "hard", "CoC7.ExtremeDifficulty": "extreme", "CoC7.CriticalDifficulty": "critical", +"CoC7.UnknownDifficulty": "unknown", "CoC7.RollDifficulty": "Roll Difficulty", +"CoC7.RollDifficulty.Unknown": "Blind", "CoC7.RollDifficultyRegular": "Regular", "CoC7.RollDifficultyHard": "Hard", "CoC7.RollDifficultyExtreme": "Extreme", @@ -197,5 +199,11 @@ "CoC7.newItemName": "new item", "CoC7.newWeaponName": "new weapon", -"CoC7.creatureFightingSkill": "Fighting" +"CoC7.creatureFightingSkill": "Fighting", + + +"SETTINGS.DefaultDifficulty": "Default check difficulty", +"SETTINGS.DefaultDifficultyHint": "You can choose the default difficulty for checks. Unknown will roll checks without the player knowing the check difficulty.", +"SETTINGS.CheckDifficultyRegular": "Default difficulty", +"SETTINGS.CheckDifficultyUnknown": "Unknown difficulty" } \ No newline at end of file diff --git a/module/apps/roll-dialog.js b/module/apps/roll-dialog.js index 92107894..ea80e609 100644 --- a/module/apps/roll-dialog.js +++ b/module/apps/roll-dialog.js @@ -4,7 +4,8 @@ export class RollDialog { static async create() { - const html = await renderTemplate('systems/CoC7/templates/apps/bonus.html', {difficulty: CoC7Check.difficultyLevel}); + const unknownDifficultyDefault = 'unknown' === game.settings.get('CoC7', 'defaultCheckDifficulty'); + const html = await renderTemplate('systems/CoC7/templates/apps/bonus.html', {difficulty: CoC7Check.difficultyLevel, unknownDifficultyDefault: unknownDifficultyDefault}); return new Promise((resolve) => { let formData = null; const dlg = new Dialog({ diff --git a/module/chat.js b/module/chat.js index 40f668f8..d3fda60b 100644 --- a/module/chat.js +++ b/module/chat.js @@ -629,7 +629,7 @@ export class CoC7Chat{ event.currentTarget.parentElement.dataset.selected = event.currentTarget.dataset.property; } - static _onChatCardToggleSwitch( event){ + static async _onChatCardToggleSwitch( event){ event.preventDefault(); const card = event.currentTarget.closest('.chat-card'); @@ -653,6 +653,10 @@ export class CoC7Chat{ // CoC7Item.updateCardSwitch( event); } + if( card.classList.contains('roll-card')){ + CoC7Check.updateCardSwitch(event); + } + // let visible = event.currentTarget.parentElement.dataset.selected == "true" ? true : false; // let panel = event.currentTarget.parentElement.getElementsByClassName( 'panel-content'); diff --git a/module/check.js b/module/check.js index 34a94c55..f0b09ba7 100644 --- a/module/check.js +++ b/module/check.js @@ -3,7 +3,7 @@ import { CoC7Item } from './items/item.js'; import { chatHelper, CoC7Roll } from './chat/helper.js'; export class CoC7Check { - constructor( actor = null, skill = null, item = null, diceMod = 0, difficulty = CoC7Check.difficultyLevel.regular) { + constructor( actor = null, skill = null, item = null, diceMod = 0, difficulty = null) { this.actor = actor; this.skill = skill; this.item = item; @@ -16,9 +16,15 @@ export class CoC7Check { this.referenceMessageId = null; this.pushing = false; + if( null === difficulty){ + const isUnknown = 'unknown' === game.settings.get('CoC7', 'defaultCheckDifficulty'); + this.difficulty = isUnknown? CoC7Check.difficultyLevel.unknown: CoC7Check.difficultyLevel.regular; + } + } static difficultyLevel = { + unknown: -1, regular: 1, hard: 2, extreme: 3, @@ -107,6 +113,10 @@ export class CoC7Check { this._isBlind = x; } + get unknownDifficulty(){ + return CoC7Check.difficultyLevel.unknown === this.difficulty; + } + get rollMode(){ if( !this._rollMode) this._rollMode = game.settings.get('core', 'rollMode'); return this._rollMode; @@ -239,7 +249,7 @@ export class CoC7Check { async computeCheck(){ - // this.isUnknown = this.isBlind; + this.isUnknown = this.unknownDifficulty; this.tenOnlyOneDie = this.dices.tens.length == 1; @@ -327,11 +337,17 @@ export class CoC7Check { this.difficultyString = game.i18n.format('CoC7.CriticalDifficulty'); this.succesThreshold = this.criticalThreshold; break; + case CoC7Check.difficultyLevel.unknown: + this.difficultyString = game.i18n.format('CoC7.UnknownDifficulty'); + this.succesThreshold = -1; + break; default: this.succesThreshold = this.rawValue; break; } - this.successRequired = game.i18n.format('CoC7.SuccessRequired', {successRequired : this.difficultyString}); + + if( this.unknownDifficulty ) this.successRequired = ''; + else this.successRequired = game.i18n.format('CoC7.SuccessRequired', {successRequired : this.difficultyString}); this.passed = this.succesThreshold >= this.dices.total ? true : false; @@ -361,7 +377,7 @@ export class CoC7Check { if( this.characteristic != null) this.canBePushed = true; if( this.isFumble) this.canBePushed = false; - if( !this.luckSpent && !this.passed && !this.isFumble && this.difficulty!=CoC7Check.difficultyLevel.critical) { + if( !this.luckSpent && !this.passed && !this.isFumble && this.difficulty!=CoC7Check.difficultyLevel.critical && !this.unknownDifficulty) { if( this.skill || this.characteristic){ let luckNeeded = this.dices.total - this.succesThreshold; if( this.actor.luck > luckNeeded){ @@ -378,6 +394,15 @@ export class CoC7Check { // Can't spend luck on pushed rolls. if( !this.pushing && 'lck' != this.attribute && 'san' != this.attribute){ + if( this.unknownDifficulty && this.dices.total > this.regularThreshold){ + let nextLevel = {}; + nextLevel.difficultyName = game.i18n.localize('CoC7.RegularDifficulty'); + nextLevel.difficulty = CoC7Check.difficultyLevel.regular; + nextLevel.luckToSpend = this.dices.total - this.regularThreshold; + nextLevel.hasEnoughLuck = (nextLevel.luckToSpend <= this.actor.luck); + if (nextLevel.luckToSpend <= this.actor.luck) this.increaseSuccess.push(nextLevel); + } + if(this.difficulty <= CoC7Check.difficultyLevel.regular && this.dices.total > this.hardThreshold){ let nextLevel = {}; nextLevel.difficultyName = game.i18n.localize('CoC7.HardDifficulty'); @@ -402,7 +427,7 @@ export class CoC7Check { if( this.isFumble) this.canIncreaseSuccess = false; this.difficultyLevel = this.difficulty; - if( this.passed && this.diceModifier <= 0 && this.skill && !this.skill.data.data.properties.noxpgain &&!this.luckSpent &&!this.forced &&!this.isBlind){ + if( this.passed && this.diceModifier <= 0 && this.skill && !this.skill.data.data.properties.noxpgain &&!this.luckSpent &&!this.forced &&!this.isBlind &&!this.isUnknown){ this.flagForDevelopement(); } } @@ -555,6 +580,20 @@ export class CoC7Check { return msg; } + static async updateCardSwitch(event){ + const card = event.currentTarget.closest('.chat-card'); + const check = await CoC7Check.getFromCard(card); + check.gmDifficultyRegular = false; + check.gmDifficultyHard = false; + check.gmDifficultyExtreme = false; + check.gmDifficultyCritical = false; + if( 'gmDifficultyRegular' === event.currentTarget.dataset.flag){ check.gmDifficultyRegular = true;} + if( 'gmDifficultyHard' === event.currentTarget.dataset.flag){ check.gmDifficultyHard = true;} + if( 'gmDifficultyExtreme' === event.currentTarget.dataset.flag){ check.gmDifficultyExtreme = true;} + if( 'gmDifficultyCritical' === event.currentTarget.dataset.flag){ check.gmDifficultyCritical = true;} + check.updateChatCard(); + } + async shortResult( details = false){ const template = 'systems/CoC7/templates/chat/roll.html'; this.details = details? details : false; diff --git a/module/coc7.js b/module/coc7.js index 98c030eb..0be60cbc 100644 --- a/module/coc7.js +++ b/module/coc7.js @@ -45,6 +45,20 @@ Hooks.once('init', async function() { default: 1, type: Number }); + + // Register deafult check difficulty + game.settings.register('CoC7', 'defaultCheckDifficulty', { + name: 'SETTINGS.DefaultDifficulty', + hint: 'SETTINGS.DefaultDifficultyHint', + scope: 'world', + config: true, + default: 'regular', + type: String, + choices: { + 'regular': 'SETTINGS.CheckDifficultyRegular', + 'unknown': 'SETTINGS.CheckDifficultyUnknown' + }, + }); // Register sheet application classes Actors.unregisterSheet('core', ActorSheet); diff --git a/templates/apps/bonus.html b/templates/apps/bonus.html index 6cc8bb44..fa866cf0 100644 --- a/templates/apps/bonus.html +++ b/templates/apps/bonus.html @@ -5,8 +5,8 @@
- + {{/if}} -
+
{{/unless}}
- + {{#if data.flags.manualCredit}} {{else}} - {{credit.spendingLevel}} + {{credit.pendingLevel}} {{/if}}
- + {{#if data.flags.manualCredit}} {{else}} {{credit.cash}} {{/if}} - +
- + {{#if data.flags.manualCredit}} {{else}} @@ -215,11 +215,11 @@

{{item.name}}

{{/if}}
- +
- +
- +
@@ -228,7 +228,7 @@

{{item.name}}

{{#unless data.flags.locked}}
-
Add new section
+
{{localize 'CoC7.BackgroundNewSection'}}
{{/unless}}
@@ -240,12 +240,12 @@

{{item.name}}

{{else}}
- +
- - {{#unless section.isFirst}}{{/unless}} - {{#unless section.isLast}}{{/unless}} + + {{#unless section.isFirst}}{{/unless}} + {{#unless section.isLast}}{{/unless}}
{{/if}} diff --git a/templates/actors/parts/actor-skills.html b/templates/actors/parts/actor-skills.html index c90d1c24..b4f65083 100644 --- a/templates/actors/parts/actor-skills.html +++ b/templates/actors/parts/actor-skills.html @@ -29,8 +29,8 @@

{{#if skill.data.properties.special}}{{skill.dat {{/if}} {{else}} - - + + {{/if}}

diff --git a/templates/actors/parts/actor-weapons.html b/templates/actors/parts/actor-weapons.html index 77dd35b1..a9ed8c0e 100644 --- a/templates/actors/parts/actor-weapons.html +++ b/templates/actors/parts/actor-weapons.html @@ -1,18 +1,18 @@ {{#unless data.flags.locked}}
-
Add Weapon
+
{{localize 'CoC7.AddWeapon'}}
{{/unless}} -
Melee weapons
+
{{localize 'CoC7.MeleeWeapons'}}
{{#if data.flags.locked}}
-
Name
+
{{localize 'CoC7.WeaponName'}}
-
Skill
-
Alt-skill
+
{{localize 'CoC7.WeaponSkill'}}
+
{{localize 'CoC7.WeaponSkillAlt'}}
-
Damage
+
{{localize 'CoC7.WeaponDamage'}}
{{/if}}
    @@ -113,8 +113,8 @@ {{/if}}
    - - + +
    @@ -128,15 +128,15 @@
-
Range weapons
+
{{localize 'CoC7.RangeWeapons'}}
{{#if data.flags.locked}}
-
Name
+
{{localize 'CoC7.WeaponName'}}
-
Skill
-
Alt-skill
+
{{localize 'CoC7.WeaponSkill'}}
+
{{localize 'CoC7.WeaponSkillAlt'}}
-
Damage
+
{{localize 'CoC7.WeaponDamage'}}
{{/if}}
    @@ -234,8 +234,8 @@ {{/if}}
    - - + +
    @@ -250,12 +250,12 @@ {{#unless data.flags.locked}}
    -
    Add skill
    +
    {{localize 'CoC7.AddSkill'}}
    {{/unless}}
    -

    Melee skills

    +

    {{localize 'CoC7.MeleeSkills'}}

    {{#each meleeSkills as |skill|}}
    @@ -266,8 +266,8 @@

    Me
    - - + +

    {{/if}} @@ -277,7 +277,7 @@

    Me

    -

    Range skills

    +

    {{localize 'CoC7.RangeSkills'}}

    {{#each rangeSkills as |skill|}}
    @@ -288,8 +288,8 @@

    Ra
    - - + +

    {{/if}} From 8b740517030eb3c1334152ac360a6e7d618e8423 Mon Sep 17 00:00:00 2001 From: kael79 Date: Wed, 19 Aug 2020 15:25:45 +0200 Subject: [PATCH 03/11] v3 --- lang/en.json | 26 ++++++++++------ lang/es.json | 16 +++++----- lang/fr.json | 38 ++++++++++++++---------- lang/ja.json | 16 +++++----- module/config.js | 14 ++++----- templates/actors/character-sheet.html | 2 +- templates/actors/creature-sheet.html | 32 ++++++++++---------- templates/actors/npc-sheet.html | 22 +++++++------- templates/actors/parts/actor-skills.html | 8 ++--- templates/actors/parts/npc-combat.html | 4 +-- templates/actors/parts/npc-skills.html | 4 +-- 11 files changed, 99 insertions(+), 83 deletions(-) diff --git a/lang/en.json b/lang/en.json index 23d0ed33..22972e4d 100644 --- a/lang/en.json +++ b/lang/en.json @@ -49,7 +49,11 @@ "CoC7.TemporaryInsanity": "Temporary insanity", "CoC7.IndefiniteInsanity": "Indefinite insanity", "CoC7.UnlockActor": "Unlock Actor", -"CoC7.lockActor": "Lock Actor", +"CoC7.LockActor": "Lock Actor", +"CoC7.NpcRollCharacteristics": "Roll characteristics", +"CoC7.NpcAvarageCharacteristics": "Average characteristics", +"CoC7.NpcCharacteristicsFormula": "Formula", +"CoC7.NpcCharacteristicsValues": "Values", "CoC7.RegularSuccess": "Regular success", "CoC7.HardSuccess": "Hard success", @@ -195,26 +199,30 @@ "CoC7.ErrorInvalidFormula": "{value} is not a valid formula", "CoC7.ErrorInvalid": "invalid", -"CoC7.newBioSectionName": "New Section", +"CoC7.NewBioSectionName": "New Section", -"CoC7.dodgeSkillName": "Dodge", -"CoC7.creditRatingSkillName": "Credit Rating", -"CoC7.fightingSpecializationName": "Fighting", -"CoC7.firearmSpecializationName": "Firearms", +"CoC7.DodgeSkillName": "Dodge", +"CoC7.CreditRatingSkillName": "Credit Rating", +"CoC7.FightingSpecializationName": "Fighting", +"CoC7.FirearmSpecializationName": "Firearms", -"CoC7.newSkillName": "new skill", +"CoC7.NewSkillName": "new skill", "CoC7.AddSkill": "Add skill", "CoC7.DevelopemmentPhase": "Developement Phase", +"CoC7.SkillCantGainXp": "Skill can't gain XP", +"CoC7.SkillUnflagForDevelopement": "Unflag for developement", +"CoC7.SkillFlagForDevelopement": "Flag for developement", +"CoC7.SkillDetail": "Detail", "CoC7.EditSkill": "Edit skill", "CoC7.DeleteSkill": "Delete skill", "CoC7.RangeSkills": "Range Skills", "CoC7.MeleeSkills": "Melee Skills", -"CoC7.newItemName": "new item", +"CoC7.NewItemName": "new item", "CoC7.AddItem": "Add item", "CoC7.EditItem": "Edit item", "CoC7.DeleteItem": "Delete Item", "CoC7.AddWeapon": "Add Weapon", -"CoC7.newWeaponName": "new weapon", +"CoC7.NewWeaponName": "new weapon", "CoC7.EditWeapon": "Edit Weapon", "CoC7.DeleteWeapon": "Delete Weapon", "CoC7.MeleeWeapons": "Melee weapons", diff --git a/lang/es.json b/lang/es.json index 0700fc4a..be407cd1 100644 --- a/lang/es.json +++ b/lang/es.json @@ -153,14 +153,14 @@ "CoC7.ErrorInvalidFormula": "{value} no es una fórmula válida", "CoC7.ErrorInvalid": "inválido", -"CoC7.newBioSectionName": "Nueva Sección", +"CoC7.NewBioSectionName": "Nueva Sección", -"CoC7.dodgeSkillName": "Esquivar", -"CoC7.creditRatingSkillName": "Crédito", -"CoC7.fightingSpecializationName": "Combatir", -"CoC7.firearmSpecializationName": "Armas de fuego", +"CoC7.DodgeSkillName": "Esquivar", +"CoC7.CreditRatingSkillName": "Crédito", +"CoC7.FightingSpecializationName": "Combatir", +"CoC7.FirearmSpecializationName": "Armas de fuego", -"CoC7.newSkillName": "nueva habilidad", -"CoC7.newItemName": "nuevo ítem", -"CoC7.newWeaponName": "nueva arma" +"CoC7.NewSkillName": "nueva habilidad", +"CoC7.NewItemName": "nuevo ítem", +"CoC7.NewWeaponName": "nueva arma" } diff --git a/lang/fr.json b/lang/fr.json index c8ec7553..cfb88a0a 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -49,7 +49,11 @@ "CoC7.TemporaryInsanity": "Folie passagère", "CoC7.IndefiniteInsanity": "Folie persistante", "CoC7.UnlockActor": "Déverrouiller Acteur", -"CoC7.lockActor": "Verrouiller Acteur", +"CoC7.LockActor": "Verrouiller Acteur", +"CoC7.NpcRollCharacteristics": "Générer les caractéristiques aléatoires", +"CoC7.NpcAvarageCharacteristics": "Générer les caractéristiques moyennes", +"CoC7.NpcCharacteristicsFormula": "Formules", +"CoC7.NpcCharacteristicsValues": "Valeurs", "CoC7.RegularSuccess": "Réussite ordinaire", "CoC7.HardSuccess": "Réussite majeur", @@ -144,8 +148,8 @@ "CoC7.WeaponRange": "Portée :", "CoC7.WeaponDamage": "Dégâts :", "CoC7.Weapon.BlastRadius": "Rayon", -"CoC7.WeaponMalfunction": "Panne :", -"CoC7.WeaponUsesPerRound": "Cadence :", +"CoC7.WeaponMalfunction": "Panne", +"CoC7.WeaponUsesPerRound": "Cadence", "CoC7.WeaponSheet.RoundsPerUse.Info": "Combien de tours sont nécessaires pour préparer l'arme à tirer", "CoC7.WeaponMax": "Max/round", "CoC7.BurstSize": "Balles/raffale", @@ -195,26 +199,30 @@ "CoC7.ErrorInvalidFormula": "{value} n'est pas une formule valide", "CoC7.ErrorInvalid": "invalide", -"CoC7.newBioSectionName": "Nouvelle Section", +"CoC7.NewBioSectionName": "Nouvelle Section", -"CoC7.dodgeSkillName": "Esquive", -"CoC7.creditRatingSkillName": "Crédit", -"CoC7.fightingSpecializationName": "Combat rapproché", -"CoC7.firearmSpecializationName": "Combat à distance", +"CoC7.DodgeSkillName": "Esquive", +"CoC7.CreditRatingSkillName": "Crédit", +"CoC7.FightingSpecializationName": "Combat rapproché", +"CoC7.FirearmSpecializationName": "Combat à distance", -"CoC7.newSkillName": "Nouvelle compétence", +"CoC7.NewSkillName": "Nouvelle compétence", "CoC7.AddSkill": "Ajouter une compétence", -"CoC7.EditSkill": "Editer", -"CoC7.DeleteSkill": "Supprimer", +"CoC7.EditSkill": "Editer compétence", +"CoC7.SkillCantGainXp": "La compétence ne peux pas gagner d'XP", +"CoC7.SkillUnflagForDevelopement": "Décocher l'XP", +"CoC7.SkillFlagForDevelopement": "Cocher l'XP", +"CoC7.SkillDetail": "Détails", +"CoC7.DeleteSkill": "Supprimer compétence", "CoC7.RangeSkills": "Compétences de Combat à Distance", "CoC7.MeleeSkills": "Compétences de Combat Rapproché", "CoC7.DevelopemmentPhase": "Phase de développement", -"CoC7.newItemName": "Nouvel objet", +"CoC7.NewItemName": "Nouvel objet", "CoC7.AddItem": "Ajouter un objet", -"CoC7.EditItem": "Éditer", -"CoC7.DeleteItem": "Supprimer", +"CoC7.EditItem": "Éditer objet", +"CoC7.DeleteItem": "Supprimer objet", "CoC7.AddWeapon": "Ajouter une arme", -"CoC7.newWeaponName": "Nouvelle arme", +"CoC7.NewWeaponName": "Nouvelle arme", "CoC7.EditWeapon": "Éditer l'arme", "CoC7.DeleteWeapon": "Supprimer l'arme", "CoC7.MeleeWeapons": "Armes de mêlée", diff --git a/lang/ja.json b/lang/ja.json index ffb66c6e..4705e895 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -153,14 +153,14 @@ "CoC7.ErrorInvalidFormula": "{value} は有効な数式ではありません", "CoC7.ErrorInvalid": "無効です", -"CoC7.newBioSectionName": "New Section", +"CoC7.NewBioSectionName": "New Section", -"CoC7.dodgeSkillName": "回避", -"CoC7.creditRatingSkillName": "信用", -"CoC7.fightingSpecializationName": "近接格闘", -"CoC7.firearmSpecializationName": "射撃", +"CoC7.DodgeSkillName": "回避", +"CoC7.CreditRatingSkillName": "信用", +"CoC7.FightingSpecializationName": "近接格闘", +"CoC7.FirearmSpecializationName": "射撃", -"CoC7.newSkillName": "新技能", -"CoC7.newItemName": "新アイテム", -"CoC7.newWeaponName": "新武器" +"CoC7.NewSkillName": "新技能", +"CoC7.NewItemName": "新アイテム", +"CoC7.NewWeaponName": "新武器" } \ No newline at end of file diff --git a/module/config.js b/module/config.js index c234848d..061ade24 100644 --- a/module/config.js +++ b/module/config.js @@ -97,16 +97,16 @@ COC7.status = { }; -COC7.newSkillName = 'CoC7.newSkillName'; -COC7.newItemName = 'CoC7.newItemName'; -COC7.newWeaponName = 'CoC7.newWeaponName'; +COC7.newSkillName = 'CoC7.NewSkillName'; +COC7.newItemName = 'CoC7.NewItemName'; +COC7.newWeaponName = 'CoC7.NewWeaponName'; COC7.creatureFightingSkill = 'CoC7.creatureFightingSkill'; -COC7.dodgeSkillName = 'CoC7.dodgeSkillName'; -COC7.creditRatingSkillName = 'CoC7.creditRatingSkillName'; -COC7.fightingSpecializationName = 'CoC7.fightingSpecializationName'; -COC7.firearmSpecializationName = 'CoC7.firearmSpecializationName'; +COC7.dodgeSkillName = 'CoC7.DodgeSkillName'; +COC7.creditRatingSkillName = 'CoC7.CreditRatingSkillName'; +COC7.fightingSpecializationName = 'CoC7.FightingSpecializationName'; +COC7.firearmSpecializationName = 'CoC7.FirearmSpecializationName'; COC7.combatCards = { fightBack: 'CoC7.FightBack', diff --git a/templates/actors/character-sheet.html b/templates/actors/character-sheet.html index 7b8cb4db..1b6501ce 100644 --- a/templates/actors/character-sheet.html +++ b/templates/actors/character-sheet.html @@ -120,7 +120,7 @@ {{#if data.flags.locked}} {{else}} - + {{/if}}
    diff --git a/templates/actors/creature-sheet.html b/templates/actors/creature-sheet.html index 52d8affd..1cd55c43 100644 --- a/templates/actors/creature-sheet.html +++ b/templates/actors/creature-sheet.html @@ -141,12 +141,12 @@
    - - - + + + - - + +
    {{#if allowFormula}} @@ -156,22 +156,22 @@ {{#if displayFormula}}
    {{else}} - - + + {{/if}} {{/if}} {{else}}
    {{/if}} {{#if data.flags.locked}} - + {{else}} - + {{#if allowFormula}} {{#if displayFormula}} - + {{else}} - + {{/if}} {{/if}} {{/if}} @@ -190,7 +190,7 @@

    {{localize 'CoC7.Skills'}}

    {{#unless data.flags.locked}}
    - +
    {{/unless}}
    @@ -203,7 +203,7 @@

    {{localize 'CoC7.Skills'}}

    {{localize 'CoC7.Combat'}}

    {{#unless data.flags.locked}}
    - +
    {{/unless}}
    @@ -215,7 +215,7 @@

    {{localize 'CoC7.Combat'}}

    {{localize 'CoC7.Possessions'}}

    {{#unless data.flags.locked}}
    - +
    {{/unless}}
    @@ -227,8 +227,8 @@

    - - + +
    {{/if}} diff --git a/templates/actors/npc-sheet.html b/templates/actors/npc-sheet.html index 472c2fdf..0e4f02eb 100644 --- a/templates/actors/npc-sheet.html +++ b/templates/actors/npc-sheet.html @@ -163,22 +163,22 @@ {{#if displayFormula}}
    {{else}} - - + + {{/if}} {{/if}} {{else}}
    {{/if}} {{#if data.flags.locked}} - + {{else}} - + {{#if allowFormula}} {{#if displayFormula}} - + {{else}} - + {{/if}} {{/if}} {{/if}} @@ -194,7 +194,7 @@

    {{localize 'CoC7.Skills'}}

    {{#unless data.flags.locked}}
    - +
    {{/unless}} @@ -207,7 +207,7 @@

    {{localize 'CoC7.Skills'}}

    {{localize 'CoC7.Combat'}}

    {{#unless data.flags.locked}}
    - +
    {{/unless}} @@ -219,7 +219,7 @@

    {{localize 'CoC7.Combat'}}

    {{localize 'CoC7.Possessions'}}

    {{#unless data.flags.locked}}
    - +
    {{/unless}} @@ -231,8 +231,8 @@

    - - + +
    {{/if}} diff --git a/templates/actors/parts/actor-skills.html b/templates/actors/parts/actor-skills.html index b4f65083..34af0d81 100644 --- a/templates/actors/parts/actor-skills.html +++ b/templates/actors/parts/actor-skills.html @@ -19,15 +19,15 @@

    {{#if skill.data.properties.special}}{{skill.dat
    {{#if ../data.flags.locked}} {{#if skill.data.properties.noxpgain}} - + {{else}} {{#if skill.data.flags.developement}} - + {{else}} - + {{/if}} {{/if}} - + {{else}} diff --git a/templates/actors/parts/npc-combat.html b/templates/actors/parts/npc-combat.html index 5306eef4..a97c9ce0 100644 --- a/templates/actors/parts/npc-combat.html +++ b/templates/actors/parts/npc-combat.html @@ -105,8 +105,8 @@ {{/if}}
    - - + +
    diff --git a/templates/actors/parts/npc-skills.html b/templates/actors/parts/npc-skills.html index 7ff32e18..7fc0a116 100644 --- a/templates/actors/parts/npc-skills.html +++ b/templates/actors/parts/npc-skills.html @@ -8,8 +8,8 @@

    - - + +
    {{/if}}

    From 45bb5fdb4532e311632184a4483d266ab56e3332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=9F=E3=81=A0=E3=81=84=E3=81=BE?= <54084706+tadaimatrpg@users.noreply.github.com> Date: Thu, 20 Aug 2020 07:48:42 +0900 Subject: [PATCH 04/11] Fixed the critical success section. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "クリティカルの成功" in Japan has been corrected to "クリティカル" --- lang/ja.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lang/ja.json b/lang/ja.json index 4705e895..114177f0 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -45,7 +45,7 @@ "CoC7.RegularSuccess": "レギュラー成功", "CoC7.HardSuccess": "ハード成功", "CoC7.ExtremeSuccess": "イクストリーム成功", -"CoC7.CriticalSuccess": "クリティカル成功", +"CoC7.CriticalSuccess": "クリティカル", "CoC7.Fumble": "ファンブル", "CoC7.Failure": "失敗", "CoC7.Malfunction": "{itemName} は故障した!", @@ -153,14 +153,14 @@ "CoC7.ErrorInvalidFormula": "{value} は有効な数式ではありません", "CoC7.ErrorInvalid": "無効です", -"CoC7.NewBioSectionName": "New Section", +"CoC7.newBioSectionName": "New Section", -"CoC7.DodgeSkillName": "回避", -"CoC7.CreditRatingSkillName": "信用", -"CoC7.FightingSpecializationName": "近接格闘", -"CoC7.FirearmSpecializationName": "射撃", +"CoC7.dodgeSkillName": "回避", +"CoC7.creditRatingSkillName": "信用", +"CoC7.fightingSpecializationName": "近接格闘", +"CoC7.firearmSpecializationName": "射撃", -"CoC7.NewSkillName": "新技能", -"CoC7.NewItemName": "新アイテム", -"CoC7.NewWeaponName": "新武器" +"CoC7.newSkillName": "新技能", +"CoC7.newItemName": "新アイテム", +"CoC7.newWeaponName": "新武器" } \ No newline at end of file From 545e3a7937bf67e4d267a06f63b668601eecac0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=9F=E3=81=A0=E3=81=84=E3=81=BE?= <54084706+tadaimatrpg@users.noreply.github.com> Date: Thu, 20 Aug 2020 08:03:40 +0900 Subject: [PATCH 05/11] Ability to roll a die on command It is a function that judges success by the commands I have implemented in my system. In the "esmodules" section of the system.json, you can add [... , "module/dicebot.js"] in the "esmodules" section of the system.json and it won't interfere with other systems. It uses the API feature and is represented in chat messages. If it is possible to represent this in chat-message.html, it is possible to use commands to create combination roles and so on. --- module/dicebot.js | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 module/dicebot.js diff --git a/module/dicebot.js b/module/dicebot.js new file mode 100644 index 00000000..115fcd05 --- /dev/null +++ b/module/dicebot.js @@ -0,0 +1,102 @@ +/** + *CallofCthulhu(7thEd.) Define your own commands + *Here, we receive the chat Messages and determine each command. + *[/CC]Define a command to judge a normal dice. + *[/CBR] Command to define the decision on combination rolls. +*/ +Hooks.on("chatMessage", (html,content) => { +//Read the command + let rgx; + rgx = /(\S+)/g; + let commands = content.match(rgx); + let command = commands[0]; + +//Declare the dice to be used. + //Define a function to read the value + let m = 0; + let n = 0; + let s = 0; + + + //Define errors as debugging. + let res = "

    Error

    "; + + //Normal Dice + let r = new Roll("1d100"); + + //Perform processing for each command. + if(command === "/CC" || command === "/cc"){ + //This time, extract only the numbers. + rgx = /(?:[0-9]+)/g; + commands = content.match(rgx); + m = commands[0]; + + //Determination based on rolls and readings + r.roll(); + //Put the result of the die into s as a number rather than an object. + s = r.result; + if(s <= 1) res = game.i18n.localize("CoC7.CriticalSuccess"); + else if(s >= 100) res= game.i18n.localize("CoC7.Fumble"); + else if(s <= (m/5)) res= game.i18n.localize("CoC7.ExtremeSuccess"); + else if(s <= (m/2)) res= game.i18n.localize("CoC7.HardSuccess"); + else if(s <= m) res= game.i18n.localize("CoC7.RegularSuccess"); + else if(s >= 96){if(m < 50) res= game.i18n.localize("CoC7.Fumble"); + else res= game.i18n.localize("CoC7.Failure");} + else res= game.i18n.localize("CoC7.Failure"); + + //The resulting output. + res += (game.i18n.localize("CoC7.SkillValue") + m); + r.toMessage( + {speaker: ChatMessage.getSpeaker(), + flavor: res, + }); + //return to avoid errors in the command. + return false; + } + + + //I'm currently using it for testing bonus dice. + if(command === "/CBR" || command === "/cbr"){ + //Extracting numbers from combination rolls + rgx = /(?:[0-9]+)/g; + commands = content.match(rgx); + m = commands[0]; + rgx = /(?:,[0-9]+)/g; + commands = content.match(rgx); + n = commands[0].replace(/[^0-9]/g, ''); + + //Determination based on rolls and readings + r.roll(); + //Put the result of the die into s as a number rather than an object. + s = r.result; + //Determine the first number. + if(s <= 1) res = game.i18n.localize("CoC7.CriticalSuccess"); + else if(s >= 100) res= game.i18n.localize("CoC7.Fumble"); + else if(s <= (m/5)) res= game.i18n.localize("CoC7.ExtremeSuccess"); + else if(s <= (m/2)) res= game.i18n.localize("CoC7.HardSuccess"); + else if(s <= m) res= game.i18n.localize("CoC7.RegularSuccess"); + else if(s >= 96){if(m < 50) res= game.i18n.localize("CoC7.Fumble"); + else res= game.i18n.localize("CoC7.Failure");} + else res= game.i18n.localize("CoC7.Failure"); + //Record the first results. + res += (game.i18n.localize("CoC7.SkillValue") + m); + + //Determine the second number. + if(s <= 1) res += game.i18n.localize("CoC7.CriticalSuccess"); + else if(s >= 100) res += game.i18n.localize("CoC7.Fumble"); + else if(s <= (n/5)) res += game.i18n.localize("CoC7.ExtremeSuccess"); + else if(s <= (n/2)) res += game.i18n.localize("CoC7.HardSuccess"); + else if(s <= n) res += game.i18n.localize("CoC7.RegularSuccess"); + else if(s >= 96){if(n < 50) res += game.i18n.localize("CoC7.Fumble"); + else res += game.i18n.localize("CoC7.Failure");} + else res += game.i18n.localize("CoC7.Failure"); + //The resulting output. + res += (game.i18n.localize("CoC7.SkillValue") + n); + r.toMessage( + {speaker: ChatMessage.getSpeaker(), + flavor: res, + }); + //return to avoid errors in the command. + return false; + } + }) From eea5dc125e2fa1b940a786b31b841b25a1069315 Mon Sep 17 00:00:00 2001 From: HavelockV Date: Thu, 20 Aug 2020 04:09:53 +0200 Subject: [PATCH 06/11] Combat flow correction --- lang/en.json | 4 +- module/actors/actor.js | 15 +- module/actors/sheets/base.js | 13 +- module/chat.js | 10 +- module/chat/card-actor.js | 119 ++++ module/chat/combat/melee-initiator.js | 233 ++++++ module/chat/combat/melee-resolution.js | 172 +++++ module/chat/combat/melee-target.js | 311 ++++++++ module/chat/helper.js | 61 +- module/chat/meleecombat.js | 793 --------------------- module/coc7.js | 13 +- templates/chat/combat/melee-initiator.html | 28 +- templates/chat/combat/melee-target.html | 7 +- 13 files changed, 948 insertions(+), 831 deletions(-) create mode 100644 module/chat/card-actor.js create mode 100644 module/chat/combat/melee-initiator.js create mode 100644 module/chat/combat/melee-resolution.js create mode 100644 module/chat/combat/melee-target.js delete mode 100644 module/chat/meleecombat.js diff --git a/lang/en.json b/lang/en.json index bbb7b6de..afafbb29 100644 --- a/lang/en.json +++ b/lang/en.json @@ -205,5 +205,7 @@ "SETTINGS.DefaultDifficulty": "Default check difficulty", "SETTINGS.DefaultDifficultyHint": "You can choose the default difficulty for checks. Unknown will roll checks without the player knowing the check difficulty.", "SETTINGS.CheckDifficultyRegular": "Default difficulty", -"SETTINGS.CheckDifficultyUnknown": "Unknown difficulty" +"SETTINGS.CheckDifficultyUnknown": "Unknown difficulty", +"SETTINGS.UseToken": "Use token image", +"SETTINGS.UseTokenHint": "Use token image instead of portraits in chat-cards" } \ No newline at end of file diff --git a/module/actors/actor.js b/module/actors/actor.js index 1dec34e3..81237bbd 100644 --- a/module/actors/actor.js +++ b/module/actors/actor.js @@ -468,7 +468,7 @@ export class CoCActor extends Actor { } - get tokenId() + get tokenId() //TODO clarifier ca et tokenkey { return this.token ? `${this.token.scene._id}.${this.token.id}` : null; } @@ -525,10 +525,15 @@ export class CoCActor extends Actor { return skills; } - get tokenKey(){ - if( this.isToken){ - return `${this.token.scene.id}.${this.token.id}`; - } + get tokenKey() //Clarifier ca et tokenid + { + //Case 1: the actor is a synthetic actor and has a token, return token key. + if( this.isToken) return `${this.token.scene.id}.${this.token.id}`; + + //Case 2: the actor is not a token (linked actor). If the sheet have an associated token return the token key. + if( this.sheet.token) return `${this.sheet.token.scene.id}.${this.sheet.token.id}`; + + //Case 3: Actor has no token return his ID; return this.id; } diff --git a/module/actors/sheets/base.js b/module/actors/sheets/base.js index f73cce04..e570e296 100644 --- a/module/actors/sheets/base.js +++ b/module/actors/sheets/base.js @@ -2,7 +2,7 @@ import { RollDialog } from '../../apps/roll-dialog.js'; // import { CoC7Dice } from '../../dice.js' import { CoC7Check } from '../../check.js'; import { COC7 } from '../../config.js'; -import { CoC7MeleeInitiator } from '../../chat/meleecombat.js'; +import { CoC7MeleeInitiator } from '../../chat/combat/melee-initiator.js'; import { CoC7RangeInitiator } from '../../chat/rangecombat.js'; import { CoC7DamageRoll } from '../../chat/damagecards.js'; @@ -227,6 +227,10 @@ export class CoC7ActorSheet extends ActorSheet { return parsedFormula; } + get tokenKey(){ + if( this.token) return `${this.token.scene._id}.${this.token.data._id}`; + return this.actor.id; + } /* -------------------------------------------- */ @@ -530,21 +534,20 @@ export class CoC7ActorSheet extends ActorSheet { async _onWeaponRoll(event) { event.preventDefault(); - const actorId = event.currentTarget.closest('form').dataset.actorId; - const tokenKey = event.currentTarget.closest('form').dataset.tokenId; const itemId = event.currentTarget.closest('li').dataset.itemId; const fastForward = event.shiftKey; const weapon = this.actor.getOwnedItem(itemId); + const actorKey = !this.token? this.actor.actorKey : `${this.token.scene._id}.${this.token.data._id}`; if( !weapon.data.data.properties.rngd){ if( game.user.targets.size > 1){ ui.notifications.error('Too many target selected. Keeping only last selected target'); } - const card = new CoC7MeleeInitiator( tokenKey ? tokenKey : actorId, itemId, fastForward); + const card = new CoC7MeleeInitiator( actorKey, itemId, fastForward); card.createChatCard(); } if( weapon.data.data.properties.rngd){ - const card = new CoC7RangeInitiator( tokenKey ? tokenKey : actorId, itemId, fastForward); + const card = new CoC7RangeInitiator( actorKey, itemId, fastForward); card.createChatCard(); } } diff --git a/module/chat.js b/module/chat.js index d3fda60b..f2a23f58 100644 --- a/module/chat.js +++ b/module/chat.js @@ -1,7 +1,9 @@ import { CoC7Dice } from './dice.js'; import { CoC7Check } from './check.js'; import { COC7 } from './config.js'; -import { CoC7MeleeInitiator, CoC7MeleeTarget, CoC7MeleeResoltion } from './chat/meleecombat.js'; +import { CoC7MeleeInitiator} from './chat/combat/melee-initiator.js'; +import { CoC7MeleeTarget} from './chat/combat/melee-target.js'; +import { CoC7MeleeResoltion } from './chat/combat/melee-resolution.js'; import { CoC7RangeInitiator } from './chat/rangecombat.js'; import { CoC7Roll, chatHelper } from './chat/helper.js'; import { CoC7DamageRoll } from './chat/damagecards.js'; @@ -77,8 +79,10 @@ export class CoC7Chat{ } else { const initiator = CoC7MeleeInitiator.getFromMessageId( chatMessage.id); - const resolutionCard = new CoC7MeleeResoltion( chatMessage.id, null, initiator.resolutionCard); - resolutionCard.resolve(); + if( initiator.resolutionCard){ + const resolutionCard = new CoC7MeleeResoltion( chatMessage.id, null, initiator.resolutionCard); + resolutionCard.resolve(); + } } } if( card.classList.contains('target')){ diff --git a/module/chat/card-actor.js b/module/chat/card-actor.js new file mode 100644 index 00000000..22bd0d2d --- /dev/null +++ b/module/chat/card-actor.js @@ -0,0 +1,119 @@ +import { chatHelper} from './helper.js'; + +export class ChatCardActor{ + constructor(actorKey = null, fastForward = false) { + this.actorKey = actorKey; + this.fastForward = fastForward; + } + + + get isBlind(){ + if( !this.rollMode) return null; + return 'blindroll' === this.rollMode; + } + + get rollMode(){ + if( !this._rollMode) this._rollMode = game.settings.get('core', 'rollMode'); + return this._rollMode; + } + + set rollMode(x){ + this._rollMode = x; + } + + get actor(){ + if( !this.actorKey) return null; + return chatHelper.getActorFromKey( this.actorKey); + } + + get token(){ + if( !this.actor) return null; + return chatHelper.getTokenFromKey(this.actorKey); + } + + get item(){ + if( !this.itemId) return null; + return this.actor.getOwnedItem( this.itemId); + } + + get weapon(){ + return this.item; + } + + get targetedTokens(){ + return [...game.user.targets]; + } + + get target(){ + if( this.targetToken) return this.targetToken; + return this.targetActor; + } + + /** + * If a targetKey was provided try to find a token with that key and use it. + * If not targetKey provided return the first target. + */ + get targetToken(){ + if( !this._targetToken){ + if( this._targetKey) + { + this._targetToken = chatHelper.getTokenFromKey( this._targetKey); + } else { + this._targetToken = this.targetedTokens.pop(); + if( this._targetToken) this._targetKey = `${this._targetToken.scene._id}.${this._targetToken.id}`; + else { + this._targetToken = null; + } + } + } + return this._targetToken; + } + + get targetActor(){ + if( !this._targetActor){ + if( this.targetToken) this._targetActor = this.targetToken.actor; + else this._targetActor = chatHelper.getActorFromKey( this._targetKey); + } + return this._targetActor; + } + + get targetKey(){ + if( !this.targetToken && !this.targetActor) return null; + return this._targetKey; + } + + get hasTarget(){ + if( !this.targetToken && !this.targetActor) return false; + return true; + } + + set targetKey(x){ + this._targetKey = x; + } + + get skills(){ + return this.actor.getWeaponSkills( this.itemId); + } + + get targetImg(){ + const img = chatHelper.getActorImgFromKey( this.targetKey); + if( img ) return img; + return '../icons/svg/mystery-man-black.svg'; + } + + get name(){ + if( this.token) return this.token.name; + return this.actor.name; + } + + get targetName(){ + if( !this.target) return 'dummy'; + return this.target.name; + } + + get actorImg(){ + const img = chatHelper.getActorImgFromKey( this.actorKey); + if( img ) return img; + return '../icons/svg/mystery-man-black.svg'; + } +} \ No newline at end of file diff --git a/module/chat/combat/melee-initiator.js b/module/chat/combat/melee-initiator.js new file mode 100644 index 00000000..a95ca6ff --- /dev/null +++ b/module/chat/combat/melee-initiator.js @@ -0,0 +1,233 @@ +import { CoC7Check } from '../../check.js'; +import { chatHelper, CoC7Roll } from '../helper.js'; +import { CoC7Chat } from '../../chat.js'; +import { CoC7MeleeTarget } from './melee-target.js'; +import { CoC7MeleeResoltion } from './melee-resolution.js'; +import { ChatCardActor } from '../card-actor.js'; + +export class CoC7MeleeInitiator extends ChatCardActor{ + constructor(actorKey = null, itemId = null, fastForward = false) { + super( actorKey, fastForward); + this.itemId = itemId; + this.resolved = false; + this.outnumbered = false; + this.surprised = false; + this.autoSuccess = false; + this.advantage = false; + this.disadvantage = false; + this.messageId = null; + this.targetCard = null; + this.rolled = false; + } + + template = 'systems/CoC7/templates/chat/combat/melee-initiator.html'; + + async createChatCard(){ + chatHelper.getActorImgFromKey(this.actorKey); + const html = await renderTemplate(this.template, this); + + const speakerData = {}; + if( this.token) speakerData.token = this.token; + else speakerData.actor = this.actor; + const speaker = ChatMessage.getSpeaker(speakerData); + + const user = this.actor.user ? this.actor.user : game.user; + + const chatData = { + user: user._id, + speaker, + content: html + }; + + if ( ['gmroll', 'blindroll'].includes(this.rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); + if ( this.isBlind ) chatData['blind'] = true; + + const chatMessage = await ChatMessage.create(chatData); + + return chatMessage; + } + + async updateChatCard(){ + let html = await renderTemplate(this.template, this); + + const message = game.messages.get( this.messageId); + + const msg = await message.update({ content: html }); + await ui.chat.updateMessage( msg, false); + return msg; + } + + toggleFlag( flagName){ + const flag = flagName.includes('-') ? chatHelper.hyphenToCamelCase( flagName) : flagName; + this[flag] = !this[flag]; + } + + + async performSkillCheck( skillId = null, publish = false){ + const check = new CoC7Check(); + check.referenceMessageId = this.messageId; + check.rollType= 'opposed'; + check.side = 'initiator'; + check.action = 'attack'; + check.actor = this.actorKey; + check.item = this.itemId; + check.skill = skillId; + check.difficulty = CoC7Check.difficultyLevel.regular; + check.diceModifier = 0; + + if( this.outnumbered) check.diceModifier += 1; + if( this.surprised) check.diceModifier += 1; + if( this.disadvantage) check.diceModifier -= 1; + if( this.advantage) check.diceModifier += 1; + + check.roll(); + this.check = check; + this.rolled = true; + this.resolved = true; + if( publish) check.toMessage(); + + this.criticalDamage = check.successLevel == CoC7Check.successLevel.extreme || check.successLevel == CoC7Check.successLevel.critical; + if( this.hasTarget && !this.autoSuccess){ + const meleeTarget = new CoC7MeleeTarget( this.targetKey, this.messageId, this.fastForward); + meleeTarget.initiatorKey = this.actorKey; + const message = await meleeTarget.createChatCard(); + this.targetCard = message.id; + } + + if( this.autoSuccess && !this.check.isFumble){ + this.check.forcePass(); + } + return check; + } + + async publishCheckResult( check = null){ + if( !check && !this.check) return null; + + if( check) this.check = check; + this.roll = CoC7Roll.getFromCheck( this.check); + this.rolled = true; + + this.roll.rollIcons = []; + if( this.roll.critical){ + this.roll.rollColor = 'goldenrod'; + this.roll.rollTitle = game.i18n.localize('CoC7.CriticalSuccess'); + for( let index = 0; index < 4; index++){ + this.roll.rollIcons.push( 'medal'); + } + } else if( this.roll.fumble) { + this.roll.rollColor = 'darkred'; + this.roll.rollTitle = game.i18n.localize('CoC7.Fumble'); + for( let index = 0; index < 4; index++){ + this.roll.rollIcons.push( 'spider'); + } + }else if( this.roll.success){ + this.roll.rollColor = 'goldenrod'; + if( CoC7Check.successLevel.regular == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.RegularSuccess'); + if( CoC7Check.successLevel.hard == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.HardSuccess'); + if( CoC7Check.successLevel.extreme == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.ExtremeSuccess'); + for (let index = 0; index < this.roll.successLevel; index++) { + this.roll.rollIcons.push( 'star'); + } + } else { + this.roll.rollColor = 'black'; + this.roll.rollTitle = game.i18n.localize('CoC7.Failure'); + this.roll.rollIcons.push( 'skull'); + } + + if( !this.targetCard && !this.autoSuccess && this.hasTarget){ + const resolutionCard = new CoC7MeleeResoltion( this.parentMessageId, this.messageId); + const resolutionMessage = await resolutionCard.preCreateMessage(); + this.resolutionCard = resolutionMessage.id; + } + await this.updateChatCard(); + } + + static getFromCard( card, messageId = null){ + const initiator = new CoC7MeleeInitiator(); + chatHelper.getObjectFromElement( initiator, card); + initiator.roll = CoC7Roll.getFromCard( card); + + if( card.closest('.message')) + initiator.messageId = card.closest('.message').dataset.messageId; + else initiator.messageId = messageId; + return initiator; + } + + static getFromMessageId( messageId){ + const message = game.messages.get( messageId); + if( ! message) return null; + const card = $(message.data.content)[0]; + + const initiator = CoC7MeleeInitiator.getFromCard( card, messageId); + initiator.messageId = messageId; + + return initiator; + } + + static updateCardSwitch( event, publishUpdate = true){ + const card = event.currentTarget.closest('.melee.initiator'); + const flag = event.currentTarget.dataset.flag; + const camelFlag = chatHelper.hyphenToCamelCase(flag); + + //update only for local player + if( !publishUpdate){ + card.dataset[camelFlag] = 'true' == card.dataset[camelFlag] ? false : true; + event.currentTarget.classList.toggle('switched-on'); + event.currentTarget.dataset.selected = card.dataset[camelFlag]; + } else { //update card for all player + const initiator = CoC7MeleeInitiator.getFromCard( card); + initiator.toggleFlag(flag); + initiator.updateChatCard(); + } + } + + upgradeRoll( luckAmount, newSuccessLevel, oldCard){ + if( !this.actor.spendLuck( luckAmount)) ui.notifications.error(`${token.name} didn't have enough luck to pass the check`); + this.roll.value = null; + this.roll.successLevel = newSuccessLevel; + this.roll.luckSpent = true; + oldCard.dataset.processed = false; + + const diceRolls = oldCard.querySelector('.dice-roll'); + diceRolls.dataset.value = null; + diceRolls.dataset.successLevel = newSuccessLevel; + diceRolls.dataset.luckSpent = true; + + const resulDetails = oldCard.querySelector('.result-details'); + const diceTotal = oldCard.querySelector('.dice-total'); + const rollDamageButton = oldCard.querySelector('button[data-action="roll-melee-damage"]'); + if( rollDamageButton) rollDamageButton.classList.remove('invisible'); + + switch (newSuccessLevel) { + case CoC7Check.successLevel.regular: + diceTotal.innerText = game.i18n.localize('CoC7.RegularSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.RegularDifficulty')}); + break; + + case CoC7Check.successLevel.hard: + diceTotal.innerText = game.i18n.localize('CoC7.HardSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.HardDifficulty')}); + break; + + case CoC7Check.successLevel.extreme: + if( rollDamageButton) rollDamageButton.dataset.critical = true; + diceTotal.innerText = game.i18n.localize('CoC7.ExtremeSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.ExtremeDifficulty')}); + break; + + case CoC7Check.successLevel.critical: + if( rollDamageButton) rollDamageButton.dataset.critical = true; + diceTotal.innerText = game.i18n.localize('CoC7.CriticalSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.CriticalDifficulty')}); + break; + + default: + break; + } + + diceTotal.classList.replace( 'failure', 'success'); + oldCard.querySelector('.card-buttons').remove(); + oldCard.querySelector('.dice-tooltip').style.display = 'none'; + CoC7Chat.updateChatCard( oldCard); + } +} diff --git a/module/chat/combat/melee-resolution.js b/module/chat/combat/melee-resolution.js new file mode 100644 index 00000000..28867ca6 --- /dev/null +++ b/module/chat/combat/melee-resolution.js @@ -0,0 +1,172 @@ +import { CoC7Check } from '../../check.js'; +import { chatHelper } from '../helper.js'; +import { CoC7MeleeInitiator } from './melee-initiator.js'; +import { CoC7MeleeTarget } from './melee-target.js'; + +export class CoC7MeleeResoltion{ + constructor(initiatorMessage = null, targetMessage = null, messageId = null) { + this.initiatorMessage = initiatorMessage; + this.targetMessage = targetMessage; + this.messageId = messageId; + } + + async preCreateMessage(){ + const html = await renderTemplate(this.template, this); + + // const speaker = ChatMessage.getSpeaker({actor: this.actor}); + // if( this.actor.isToken) speaker.alias = this.actor.token.name; + + // const user = this.actor.user ? this.actor.user : game.user; + + const chatData = { + user: game.user._id, + content: html + }; + + // Add image to card. + // data.flags = { + // img: this.actor.isToken ? this.actor.token.data.img: this.actor.img + // }; + + let rollMode = game.settings.get('core', 'rollMode'); + if ( ['gmroll', 'blindroll'].includes(rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); + if ( rollMode === 'blindroll' ) chatData['blind'] = true; + + const chatMessage = await ChatMessage.create(chatData); + this.messageId = chatMessage.id; + return chatMessage; + } + + get target(){ + if(this.targetMessage) return CoC7MeleeTarget.getFromMessageId(this.targetMessage); + return null; + } + + get targetToken(){ + if( this.target) return chatHelper.getTokenFromKey( this.target.actorKey); + return null; + } + + get initiator(){ + if(this.initiatorMessage) return CoC7MeleeInitiator.getFromMessageId(this.initiatorMessage); + return null; + } + + get initiatorToken(){ + if( this.initiator) return chatHelper.getTokenFromKey( this.initiator.actorKey); + return null; + } + + + async resolve(){ + if( this.target){ + switch (this.target.action) { + case 'dodge': + if( this.initiator.roll.successLevel <= 0 && this.target.roll.successLevel <= 0){ + this.resultString = 'Both side failed.'; + this.winner = null; + this.rollDamage = false; + } + else if( this.initiator.roll.successLevel > this.target.roll.successLevel){ + this.resultString = `${this.initiator.name} won. Roll damage`; + this.winner = this.initiator; + this.action = 'roll-melee-damage'; + this.rollDamage = true; + } + else if( this.initiator.roll.successLevel <= this.target.roll.successLevel){ + this.resultString = `${this.target.name} dodged.`; + this.winner = this.target; + this.action = 'dodge'; + this.rollDamage = false; + } + + break; + + case 'fightBack': + if( this.initiator.roll.successLevel <= 0 && this.target.roll.successLevel <= 0){ + this.resultString = 'Both side failed.'; + this.winner = null; + this.rollDamage = false; + } + else if( this.initiator.roll.successLevel >= this.target.roll.successLevel){ + this.resultString = `${this.initiator.name} won. Roll damage`; + this.winner = this.initiator; + this.looser = this.target; + this.rollDamage = true; + } + else if( this.initiator.roll.successLevel <= this.target.roll.successLevel){ + this.resultString = `${this.target.name} won. Roll damage`; + this.winner = this.target; + this.looser = this.initiator; + this.rollDamage = true; + } + + break; + + case 'maneuver': + if( this.initiator.roll.successLevel <= 0 && this.target.roll.successLevel <= 0){ + this.resultString = 'Both side failed.'; + this.winner = null; + this.rollDamage = false; + } + else if( this.initiator.roll.successLevel >= this.target.roll.successLevel){ + this.resultString = `${this.initiator.name} won. Roll damage`; + this.winner = this.initiator; + this.looser = this.target; + this.rollDamage = true; + } + else if( this.initiator.roll.successLevel <= this.target.roll.successLevel){ + this.resultString = `${this.target.name} maneuver was successful.`; + this.winner = this.target; + this.looser = this.initiator; + this.rollDamage = false; + } + + break; + + default: + break; + } + } else { + if( this.initiator.roll.successLevel > 0){ + this.resultString = `${this.initiator.name} won. Roll damage`; + this.winner = this.initiator; + this.rollDamage = true; + } else { + this.resultString = `${this.initiator.name} missed.`; + this.winner = this.initiator; + this.rollDamage = false; + + } + } + + if( this.winner){ + if( this.winner.roll.successLevel >= CoC7Check.successLevel.extreme) this.winner.roll.criticalDamage = true; + else this.winner.roll.criticalDamage = false; + } + + + this.resolved = true; + const html = await renderTemplate(this.template, this); + if( this.messageId){ + const message = game.messages.get( this.messageId); + const speaker = this.winner ? ChatMessage.getSpeaker({token: this.winner.token}) : null; + const user = this.winner ? this.winner.actor.user ? this.winner.actor.user : game.user : game.user; + + let msg; + if( speaker) msg = await message.update({ + user: user._id, + speaker, + content: html }); + else msg = await message.update({ + user: user._id, + content: html }); + await ui.chat.updateMessage( msg, false); + return msg; + } + } + + get template(){ + return 'systems/CoC7/templates/chat/combat/melee-resolution.html'; + } +} diff --git a/module/chat/combat/melee-target.js b/module/chat/combat/melee-target.js new file mode 100644 index 00000000..688f2348 --- /dev/null +++ b/module/chat/combat/melee-target.js @@ -0,0 +1,311 @@ +import { CoC7Check } from '../../check.js'; +import { chatHelper, CoC7Roll } from '../helper.js'; +import { CoC7Chat } from '../../chat.js'; +import { ChatCardActor } from '../card-actor.js'; +import { CoC7MeleeResoltion } from './melee-resolution.js'; +import { CoC7MeleeInitiator } from './melee-initiator.js'; + +export class CoC7MeleeTarget extends ChatCardActor{ + constructor(actorKey, parentMessageId = null, fastForward = false) { + super( actorKey, fastForward); + this.actorKey = actorKey; + this.initiatorKey = null; + this.parentMessageId = parentMessageId; + this.fastForward = fastForward; + this.resolved = false; + + this.outnumbered = false; + this.surprised = false; + this.autoSuccess = false; + this.advantage = false; + this.disadvantage = false; + + this.messageId = null; + this.skillId = null; + this.itemId = null; + this.dodging = false; + this.fightingBack = false; + this.maneuvering = false; + } + + get actionSelected(){ + return this.dodging || this.fightingBack || this.maneuvering; + } + + get action(){ + if( this.dodging) return 'dodge'; + if( this.fightingBack) return 'fightBack'; + if( this.maneuvering) return 'maneuver'; + return null; + } + + get weapon(){ + return this.actor.getOwnedItem( this.itemId); + } + + get skill(){ + return this.actor.getOwnedItem( this.skillId); + } + + set initiatorKey(x){ + this._initiatorKey = x; + this.targetKey = x; + } + + get initiatorKey(){ + if( !this._initiatorKey){ + if( !this._initiator && this.parentMessageId) this._initiator = CoC7MeleeInitiator.getFromMessageId( this.parentMessageId); + if( this._initiator) this._initiatorKey = this._initiator.actorKey; + } + if( !this._initiatorKey){ + ui.notifications.error(`No initiator found for target : ${this.actor.name}`); + return null; + } + return this._initiatorKey; + } + + get initiator(){ + if( !this.initiatorKey){ + if( this.parentMessageId){ + this._initiator = CoC7MeleeInitiator.getFromMessageId( this.parentMessageId); + this.initiatorKey = this._initiator.actorKey; + } else return null; + } + return chatHelper.getActorFromKey( this.initiatorKey); + } + + template = 'systems/CoC7/templates/chat/combat/melee-target.html'; + + static getFromMessageId( messageId){ + const message = game.messages.get( messageId); + if( ! message) return null; + const card = $(message.data.content)[0]; + + const target = CoC7MeleeTarget.getFromCard( card, messageId); + target.messageId = messageId; + + return target; + } + + static updateCardSwitch( event, publishUpdate = true){ + const card = event.currentTarget.closest('.melee.target'); + const flag = event.currentTarget.dataset.flag; + const camelFlag = chatHelper.hyphenToCamelCase(flag); + + //update only for local player + if( !publishUpdate){ + card.dataset[camelFlag] = 'true' == card.dataset[camelFlag] ? false : true; + event.currentTarget.classList.toggle('switched-on'); + event.currentTarget.dataset.selected = card.dataset[camelFlag]; + } else { //update card for all player + const target = CoC7MeleeTarget.getFromCard( card); + target.toggleFlag(flag); + target.updateChatCard(); + } + } + + toggleFlag( flagName){ + const flag = flagName.includes('-') ? chatHelper.hyphenToCamelCase( flagName) : flagName; + this[flag] = !this[flag]; + } + + async createChatCard(){ + const html = await renderTemplate(this.template, this); + + const speaker = ChatMessage.getSpeaker({token: this.token}); + if( this.actor.isToken) speaker.alias = this.actor.token.name; + + const user = this.actor.user ? this.actor.user : game.user; + + const chatData = { + user: user._id, + speaker, + content: html + }; + + if ( ['gmroll', 'blindroll'].includes(this.rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); + if ( this.isBlind ) chatData['blind'] = true; + + const message = await ChatMessage.create(chatData); + + this.messageId = message.id; + return message; + } + + async updateChatCard(){ + let html = await renderTemplate(this.template, this); + const message = game.messages.get( this.messageId); + + const msg = await message.update({ content: html }); + await ui.chat.updateMessage( msg, false); + return msg; + } + + async getUpdatedChatCard(){ + renderTemplate(this.template, this).then( html => {return html;}); + } + + static async updateSelected( card, event){ + const target = CoC7MeleeTarget.getFromCard( card); + + switch (event.currentTarget.dataset.action) { + case 'dodge': + target.dodging = true; + target.fightingBack = false; + target.maneuvering = false; + target.skillId = event.currentTarget.dataset.skillId; + target.itemId = null; + break; + + case 'fightBack': + target.dodging = false; + target.fightingBack = true; + target.maneuvering = false; + target.skillId = event.currentTarget.dataset.skillId; + target.itemId = event.currentTarget.dataset.weaponId; + break; + + case 'maneuver': + target.dodging = false; + target.fightingBack = false; + target.maneuvering = true; + target.skillId = event.currentTarget.dataset.skillId; + target.itemId = null; + break; + + default: + break; + } + + target.updateChatCard(); + + return target; + } + + async performSkillCheck( skillId = null, publish = false){ + const check = new CoC7Check(); + check.referenceMessageId = this.messageId; + check.rollType= 'opposed'; + check.side = 'target'; + check.action = this.action; + check.actor = this.actor; + check.item = this.itemId; + check.skill = skillId; + check.difficulty = CoC7Check.difficultyLevel.regular; + check.diceModifier = 0; + + if( this.disadvantage) check.diceModifier -= 1; + if( this.advantage) check.diceModifier += 1; + + check.roll(); + this.check = check; + this.rolled = true; + this.resolved = true; + if( publish) check.toMessage(); + + return check; + } + + async publishCheckResult( check = null){ + if( !check && !this.check) return null; + + if( check) this.check = check; + this.roll = CoC7Roll.getFromCheck( this.check); + this.rolled = true; + + this.roll.rollIcons = []; + if( this.roll.critical){ + this.roll.rollColor = 'goldenrod'; + this.roll.rollTitle = game.i18n.localize('CoC7.CriticalSuccess'); + for( let index = 0; index < 4; index++){ + this.roll.rollIcons.push( 'medal'); + } + } else if( this.roll.fumble) { + this.roll.rollColor = 'darkred'; + this.roll.rollTitle = game.i18n.localize('CoC7.Fumble'); + for( let index = 0; index < 4; index++){ + this.roll.rollIcons.push( 'spider'); + } + }else if( this.roll.success){ + this.roll.rollColor = 'goldenrod'; + if( CoC7Check.successLevel.regular == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.RegularSuccess'); + if( CoC7Check.successLevel.hard == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.HardSuccess'); + if( CoC7Check.successLevel.extreme == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.ExtremeSuccess'); + for (let index = 0; index < this.roll.successLevel; index++) { + this.roll.rollIcons.push( 'star'); + } + } else { + this.roll.rollColor = 'black'; + this.roll.rollTitle = game.i18n.localize('CoC7.Failure'); + this.roll.rollIcons.push( 'skull'); + } + + const resolutionCard = new CoC7MeleeResoltion( this.parentMessageId, this.messageId); + const resolutionMessage = await resolutionCard.preCreateMessage(); + + this.resolutionCard = resolutionMessage.id; + await this.updateChatCard(); + } + + static getFromCard( card, messageId = null){ + const actorKey = card.dataset.actorKey; + const parentMessageId = card.dataset.parentMessageId; + const fastForward = 'true' == card.dataset.fastForward; + const target = new CoC7MeleeTarget( actorKey, parentMessageId, fastForward); + + target.roll = CoC7Roll.getFromCard( card); + chatHelper.getObjectFromElement( target, card); + + if( card.closest('.message')) + target.messageId = card.closest('.message').dataset.messageId; + else target.messageId = messageId; + return target; + + } + + upgradeRoll( luckAmount, newSuccessLevel, oldCard){ + if( !this.actor.spendLuck( luckAmount)) ui.notifications.error(`${token.name} didn't have enough luck to pass the check`); + this.roll.value = null; + this.roll.successLevel = newSuccessLevel; + this.roll.luckSpent = true; + oldCard.dataset.processed = false; + + const diceRolls = oldCard.querySelector('.dice-roll'); + diceRolls.dataset.value = null; + diceRolls.dataset.successLevel = newSuccessLevel; + diceRolls.dataset.luckSpent = true; + + const resulDetails = oldCard.querySelector('.result-details'); + const diceTotal = oldCard.querySelector('.dice-total'); + switch (newSuccessLevel) { + case CoC7Check.successLevel.regular: + diceTotal.innerText = game.i18n.localize('CoC7.RegularSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.RegularDifficulty')}); + break; + + case CoC7Check.successLevel.hard: + diceTotal.innerText = game.i18n.localize('CoC7.HardSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.HardDifficulty')}); + break; + + case CoC7Check.successLevel.extreme: + diceTotal.innerText = game.i18n.localize('CoC7.ExtremeSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.ExtremeDifficulty')}); + break; + + case CoC7Check.successLevel.critical: + diceTotal.innerText = game.i18n.localize('CoC7.CriticalSuccess'); + resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.CriticalDifficulty')}); + break; + + default: + break; + } + + diceTotal.classList.replace( 'failure', 'success'); + oldCard.querySelector('.card-buttons').remove(); + oldCard.querySelector('.dice-tooltip').style.display = 'none'; + CoC7Chat.updateChatCard( oldCard); + } +} + diff --git a/module/chat/helper.js b/module/chat/helper.js index df177996..8e8c4381 100644 --- a/module/chat/helper.js +++ b/module/chat/helper.js @@ -15,14 +15,10 @@ export class chatHelper{ static getActorFromKey(key) { + if( !key) return null; // Case 1 - a synthetic actor from a Token if (key.includes('.')) { - const [sceneId, tokenId] = key.split('.'); - const scene = game.scenes.get(sceneId); - if (!scene) return null; - const tokenData = scene.getEmbeddedEntity('Token', tokenId); - if (!tokenData) return null; - const token = new Token(tokenData); + const token = chatHelper.getTokenFromKey(key); return token.actor; } @@ -46,6 +42,7 @@ export class chatHelper{ } static getTokenFromKey( key){ + if( !key) return null; if (key.includes('.')) { const [sceneId, tokenId] = key.split('.'); const scene = game.scenes.get(sceneId); @@ -55,13 +52,53 @@ export class chatHelper{ const token = new Token(tokenData); return token; } else { - const scene = game.scenes.active; - if (!scene) return null; - const tokens = scene.data.tokens.filter( t => key === t.actorId); - if( !tokens.length) return null; - const token = new Token(tokens[0]); - return token; + const actor = game.actors.get( key); + return chatHelper.getActorToken( actor, false); + } + } + + static getActorToken( actor, verbose = true){ + if( !actor) return null; + // Case 0 - Actor is a token (synthetic actor), return that token. + if(actor.isToken) return actor.token; + else{ + // Case 1 - Actor is not a token, find if a token exist for that actor. + const actorTokens = actor.getActiveTokens(); + if( actorTokens.length){ + // Case 1.1 - If he has only one Token return it. + if( 1 === actorTokens.length) return actorTokens[0]; + + // Case 1.2 - Actor has multiple tokens, find if one of them is the controlled token. + const controlledTokens = actorTokens.filter( t => t._controlled); + if( controlledTokens.length){ + // Return the 1st controlled token, rise a warning if he has multiple controlled tokens. + if( verbose && controlledTokens.length > 1) ui.notifications.warn( `Actor ${actor.name} has ${controlledTokens.length} controlled tokens. Using the first found`); + return controlledTokens[0]; + } + + // Case 1.3 actor doesn't have any active token. Return the first valid token for that actor and raise a warning. + if( verbose) ui.notifications.warn( `Actor ${actor.name} doesn't have any controlled token. Using first token found.`); + return actorTokens[0]; + } + + if( verbose) ui.notifications.error( `Could not fin any token for ${actor.name}.`); + return null; + } + } + + static getActorImgFromKey( actorKey){ + if( !actorKey) return null; + if( game.settings.get('CoC7', 'useToken')){ + // Try to find a token. + const token = chatHelper.getTokenFromKey(actorKey); + if( token) return token.data.img; + } + const actor = chatHelper.getActorFromKey(actorKey); + if( game.settings.get('CoC7', 'useToken')){ + // if no token found for that actor return the prototype token image. + if( actor.data.token) return actor.data.token.img; } + return actor.data.img; } static getDistance( startToken, endToken){ diff --git a/module/chat/meleecombat.js b/module/chat/meleecombat.js deleted file mode 100644 index 7fb50f1f..00000000 --- a/module/chat/meleecombat.js +++ /dev/null @@ -1,793 +0,0 @@ -import { CoC7Check } from '../check.js'; -import { chatHelper, CoC7Roll } from './helper.js'; -import { CoC7Chat } from '../chat.js'; - -export class CoC7MeleeInitiator{ - constructor(actorKey = null, itemId = null, fastForward = false) { - this.actorKey = actorKey; - this.itemId = itemId; - this.fastForward = fastForward; - this.resolved = false; - this.outnumbered = false; - this.surprised = false; - this.autoSuccess = false; - this.advantage = false; - this.disadvantage = false; - this.messageId = null; - this.targetCard = null; - this.rolled = false; - } - - - get isBlind(){ - return 'blindroll' === this.rollMode; - } - - get rollMode(){ - if( !this._rollMode) this._rollMode = game.settings.get('core', 'rollMode'); - return this._rollMode; - } - - set rollMode(x){ - this._rollMode = x; - } - - get actor(){ - return chatHelper.getActorFromKey( this.actorKey); - } - - get token(){ - return chatHelper.getTokenFromKey( this.actorKey); - } - - get item(){ - return this.actor.getOwnedItem( this.itemId); - } - - get weapon(){ - return this.item; - } - - get targets(){ - return [...game.user.targets]; - } - - get target(){ - if( !this._target){ - if( this._targetKey) - { - this._target = chatHelper.getTokenFromKey( this._targetKey); - } else { - this._target = this.targets.pop(); - if( this._target){ - this._targetKey = this._target? `${this._target.scene._id}.${this._target.id}`: null; - } - else this._target = null; - } - } - return this._target; - } - - get targetKey(){ - if( !this.target) return null; - return this._targetKey; - } - - set targetKey(x){ - this._targetKey = x; - } - - get skills(){ - return this.actor.getWeaponSkills( this.itemId); - } - - get targetImg(){ - if( this.target){ - if( this.target.actor.isToken) return this.target.data.img; - return this.target.actor.img; - } - return '../icons/svg/mystery-man-black.svg'; - } - - template = 'systems/CoC7/templates/chat/combat/melee-initiator.html'; - - async createChatCard(){ - const html = await renderTemplate(this.template, this); - - const speaker = ChatMessage.getSpeaker({token: this.token}); - // if( this.actor.isToken) speaker.alias = this.actor.token.name; - - const user = this.actor.user ? this.actor.user : game.user; - - const chatData = { - user: user._id, - speaker, - content: html - }; - - // Add image to card. - // data.flags = { - // img: this.actor.isToken ? this.actor.token.data.img: this.actor.img - // }; - - if ( ['gmroll', 'blindroll'].includes(this.rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); - if ( this.isBlind ) chatData['blind'] = true; - - const chatMessage = await ChatMessage.create(chatData); - - return chatMessage; - } - - async updateChatCard(){ - let html = await renderTemplate(this.template, this); - - const message = game.messages.get( this.messageId); - - const msg = await message.update({ content: html }); - await ui.chat.updateMessage( msg, false); - return msg; - } - - toggleFlag( flagName){ - const flag = flagName.includes('-') ? chatHelper.hyphenToCamelCase( flagName) : flagName; - this[flag] = !this[flag]; - } - - - async performSkillCheck( skillId = null, publish = false){ - const check = new CoC7Check(); - check.referenceMessageId = this.messageId; - check.rollType= 'opposed'; - check.side = 'initiator'; - check.action = 'attack'; - check.actor = this.actorKey; - check.item = this.itemId; - check.skill = skillId; - check.difficulty = CoC7Check.difficultyLevel.regular; - check.diceModifier = 0; - - if( this.outnumbered) check.diceModifier += 1; - if( this.surprised) check.diceModifier += 1; - if( this.disadvantage) check.diceModifier -= 1; - if( this.advantage) check.diceModifier += 1; - - check.roll(); - this.check = check; - this.rolled = true; - this.resolved = true; - if( publish) check.toMessage(); - - if( this.target && !this.autoSuccess){ - const target = new CoC7MeleeTarget( this.targetKey, this.messageId, this.fastForward); - target.initiatorKey = this.actorKey; - const message = await target.createChatCard(); - this.targetCard = message.id; - } - - if( this.autoSuccess && !this.check.isFumble){ - this.check.forcePass(); - } - return check; - } - - async publishCheckResult( check = null){ - if( !check && !this.check) return null; - - if( check) this.check = check; - this.roll = CoC7Roll.getFromCheck( this.check); - this.rolled = true; - - this.roll.rollIcons = []; - if( this.roll.critical){ - this.roll.rollColor = 'goldenrod'; - this.roll.rollTitle = game.i18n.localize('CoC7.CriticalSuccess'); - for( let index = 0; index < 4; index++){ - this.roll.rollIcons.push( 'medal'); - } - } else if( this.roll.fumble) { - this.roll.rollColor = 'darkred'; - this.roll.rollTitle = game.i18n.localize('CoC7.Fumble'); - for( let index = 0; index < 4; index++){ - this.roll.rollIcons.push( 'spider'); - } - }else if( this.roll.success){ - this.roll.rollColor = 'goldenrod'; - if( CoC7Check.successLevel.regular == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.RegularSuccess'); - if( CoC7Check.successLevel.hard == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.HardSuccess'); - if( CoC7Check.successLevel.extreme == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.ExtremeSuccess'); - for (let index = 0; index < this.roll.successLevel; index++) { - this.roll.rollIcons.push( 'star'); - } - } else { - this.roll.rollColor = 'black'; - this.roll.rollTitle = game.i18n.localize('CoC7.Failure'); - this.roll.rollIcons.push( 'skull'); - } - - if( !this.targetCard && !this.autoSuccess){ - const resolutionCard = new CoC7MeleeResoltion( this.parentMessageId, this.messageId); - const resolutionMessage = await resolutionCard.preCreateMessage(); - this.resolutionCard = resolutionMessage.id; - } - await this.updateChatCard(); - } - - static getFromCard( card, messageId = null){ - const initiator = new CoC7MeleeInitiator(); - chatHelper.getObjectFromElement( initiator, card); - initiator.roll = CoC7Roll.getFromCard( card); - - if( card.closest('.message')) - initiator.messageId = card.closest('.message').dataset.messageId; - else initiator.messageId = messageId; - return initiator; - } - - static getFromMessageId( messageId){ - const message = game.messages.get( messageId); - if( ! message) return null; - const card = $(message.data.content)[0]; - - const initiator = CoC7MeleeInitiator.getFromCard( card, messageId); - initiator.messageId = messageId; - - return initiator; - } - - static updateCardSwitch( event, publishUpdate = true){ - const card = event.currentTarget.closest('.melee.initiator'); - const flag = event.currentTarget.dataset.flag; - const camelFlag = chatHelper.hyphenToCamelCase(flag); - - //update only for local player - if( !publishUpdate){ - card.dataset[camelFlag] = 'true' == card.dataset[camelFlag] ? false : true; - event.currentTarget.classList.toggle('switched-on'); - event.currentTarget.dataset.selected = card.dataset[camelFlag]; - } else { //update card for all player - const initiator = CoC7MeleeInitiator.getFromCard( card); - initiator.toggleFlag(flag); - initiator.updateChatCard(); - } - } - - upgradeRoll( luckAmount, newSuccessLevel, oldCard){ - if( !this.actor.spendLuck( luckAmount)) ui.notifications.error(`${token.name} didn't have enough luck to pass the check`); - this.roll.value = null; - this.roll.successLevel = newSuccessLevel; - this.roll.luckSpent = true; - oldCard.dataset.processed = false; - - const diceRolls = oldCard.querySelector('.dice-roll'); - diceRolls.dataset.value = null; - diceRolls.dataset.successLevel = newSuccessLevel; - diceRolls.dataset.luckSpent = true; - - const resulDetails = oldCard.querySelector('.result-details'); - const diceTotal = oldCard.querySelector('.dice-total'); - switch (newSuccessLevel) { - case CoC7Check.successLevel.regular: - diceTotal.innerText = game.i18n.localize('CoC7.RegularSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.RegularDifficulty')}); - break; - - case CoC7Check.successLevel.hard: - diceTotal.innerText = game.i18n.localize('CoC7.HardSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.HardDifficulty')}); - break; - - case CoC7Check.successLevel.extreme: - if( this.autoSuccess){ - const rollDamageButton = oldCard.querySelector('button[data-action="roll-melee-damage"]'); - if( rollDamageButton) rollDamageButton.dataset.critical = true; - } - diceTotal.innerText = game.i18n.localize('CoC7.ExtremeSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.ExtremeDifficulty')}); - break; - - case CoC7Check.successLevel.critical: - if( this.autoSuccess){ - const rollDamageButton = oldCard.querySelector('button[data-action="roll-melee-damage"]'); - if( rollDamageButton) rollDamageButton.dataset.critical = true; - } - diceTotal.innerText = game.i18n.localize('CoC7.CriticalSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.CriticalDifficulty')}); - break; - - default: - break; - } - - diceTotal.classList.replace( 'failure', 'success'); - oldCard.querySelector('.card-buttons').remove(); - oldCard.querySelector('.dice-tooltip').style.display = 'none'; - CoC7Chat.updateChatCard( oldCard); - } -} - -export class CoC7MeleeTarget{ - constructor(actorKey, parentMessageId = null, fastForward = false) { - this.actorKey = actorKey; - this.initiatorKey = null; - this.parentMessageId = parentMessageId; - this.fastForward = fastForward; - this.resolved = false; - - this.outnumbered = false; - this.surprised = false; - this.autoSuccess = false; - this.advantage = false; - this.disadvantage = false; - - this.messageId = null; - this.skillId = null; - this.itemId = null; - this.dodging = false; - this.fightingBack = false; - this.maneuvering = false; - } - - - get isBlind(){ - return 'blindroll' === this.rollMode; - } - - get rollMode(){ - if( !this._rollMode) this._rollMode = game.settings.get('core', 'rollMode'); - return this._rollMode; - } - - set rollMode(x){ - this._rollMode = x; - } - - get actor(){ - return chatHelper.getActorFromKey( this.actorKey); - } - - get token(){ - return chatHelper.getTokenFromKey( this.actorKey); - } - - get weapon(){ - return this.actor.getOwnedItem( this.itemId); - } - - get skill(){ - return this.actor.getOwnedItem( this.skillId); - } - - get actionSelected(){ - return this.dodging || this.fightingBack || this.maneuvering; - } - - get action(){ - if( this.dodging) return 'dodge'; - if( this.fightingBack) return 'fightBack'; - if( this.maneuvering) return 'maneuver'; - return null; - } - - get initiator(){ - if( !this.initiatorKey) return null; - return chatHelper.getTokenFromKey( this.initiatorKey); - } - - get targetImg(){ - if( this.initiator){ - if( this.initiator.actor.isToken) return this.initiator.data.img; - return this.initiator.actor.img; - } - return '../icons/svg/mystery-man-black.svg'; - } - - template = 'systems/CoC7/templates/chat/combat/melee-target.html'; - - static getFromMessageId( messageId){ - const message = game.messages.get( messageId); - if( ! message) return null; - const card = $(message.data.content)[0]; - - const target = CoC7MeleeTarget.getFromCard( card, messageId); - target.messageId = messageId; - - return target; - } - - static updateCardSwitch( event, publishUpdate = true){ - const card = event.currentTarget.closest('.melee.target'); - const flag = event.currentTarget.dataset.flag; - const camelFlag = chatHelper.hyphenToCamelCase(flag); - - //update only for local player - if( !publishUpdate){ - card.dataset[camelFlag] = 'true' == card.dataset[camelFlag] ? false : true; - event.currentTarget.classList.toggle('switched-on'); - event.currentTarget.dataset.selected = card.dataset[camelFlag]; - } else { //update card for all player - const target = CoC7MeleeTarget.getFromCard( card); - target.toggleFlag(flag); - target.updateChatCard(); - } - } - - toggleFlag( flagName){ - const flag = flagName.includes('-') ? chatHelper.hyphenToCamelCase( flagName) : flagName; - this[flag] = !this[flag]; - } - - async createChatCard(){ - const html = await renderTemplate(this.template, this); - - const speaker = ChatMessage.getSpeaker({token: this.token}); - if( this.actor.isToken) speaker.alias = this.actor.token.name; - - const user = this.actor.user ? this.actor.user : game.user; - - const chatData = { - user: user._id, - speaker, - content: html - }; - - // Add image to card. - // data.flags = { - // img: this.actor.isToken ? this.actor.token.data.img: this.actor.img - // }; - - if ( ['gmroll', 'blindroll'].includes(this.rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); - if ( this.isBlind ) chatData['blind'] = true; - - const message = await ChatMessage.create(chatData); - - this.messageId = message.id; - return message; - } - - async updateChatCard(){ - let html = await renderTemplate(this.template, this); - const message = game.messages.get( this.messageId); - - const msg = await message.update({ content: html }); - await ui.chat.updateMessage( msg, false); - return msg; - } - - async getUpdatedChatCard(){ - renderTemplate(this.template, this).then( html => {return html;}); - } - - static async updateSelected( card, event){ - const target = CoC7MeleeTarget.getFromCard( card); - - switch (event.currentTarget.dataset.action) { - case 'dodge': - target.dodging = true; - target.fightingBack = false; - target.maneuvering = false; - target.skillId = event.currentTarget.dataset.skillId; - target.itemId = null; - break; - - case 'fightBack': - target.dodging = false; - target.fightingBack = true; - target.maneuvering = false; - target.skillId = event.currentTarget.dataset.skillId; - target.itemId = event.currentTarget.dataset.weaponId; - break; - - case 'maneuver': - target.dodging = false; - target.fightingBack = false; - target.maneuvering = true; - target.skillId = event.currentTarget.dataset.skillId; - target.itemId = null; - break; - - default: - break; - } - - target.updateChatCard(); - - return target; - } - - async performSkillCheck( skillId = null, publish = false){ - const check = new CoC7Check(); - check.referenceMessageId = this.messageId; - check.rollType= 'opposed'; - check.side = 'target'; - check.action = this.action; - check.actor = this.actor; - check.item = this.itemId; - check.skill = skillId; - check.difficulty = CoC7Check.difficultyLevel.regular; - check.diceModifier = 0; - - if( this.disadvantage) check.diceModifier -= 1; - if( this.advantage) check.diceModifier += 1; - - check.roll(); - this.check = check; - this.rolled = true; - this.resolved = true; - if( publish) check.toMessage(); - - - // const initiator = CoC7MeleeInitiator.getFromMessageId( this.parentMessageId); - - return check; - } - - async publishCheckResult( check = null){ - if( !check && !this.check) return null; - - if( check) this.check = check; - this.roll = CoC7Roll.getFromCheck( this.check); - this.rolled = true; - - this.roll.rollIcons = []; - if( this.roll.critical){ - this.roll.rollColor = 'goldenrod'; - this.roll.rollTitle = game.i18n.localize('CoC7.CriticalSuccess'); - for( let index = 0; index < 4; index++){ - this.roll.rollIcons.push( 'medal'); - } - } else if( this.roll.fumble) { - this.roll.rollColor = 'darkred'; - this.roll.rollTitle = game.i18n.localize('CoC7.Fumble'); - for( let index = 0; index < 4; index++){ - this.roll.rollIcons.push( 'spider'); - } - }else if( this.roll.success){ - this.roll.rollColor = 'goldenrod'; - if( CoC7Check.successLevel.regular == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.RegularSuccess'); - if( CoC7Check.successLevel.hard == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.HardSuccess'); - if( CoC7Check.successLevel.extreme == this.roll.successLevel ) this.roll.rollTitle = game.i18n.localize('CoC7.ExtremeSuccess'); - for (let index = 0; index < this.roll.successLevel; index++) { - this.roll.rollIcons.push( 'star'); - } - } else { - this.roll.rollColor = 'black'; - this.roll.rollTitle = game.i18n.localize('CoC7.Failure'); - this.roll.rollIcons.push( 'skull'); - } - - const resolutionCard = new CoC7MeleeResoltion( this.parentMessageId, this.messageId); - const resolutionMessage = await resolutionCard.preCreateMessage(); - - this.resolutionCard = resolutionMessage.id; - await this.updateChatCard(); - } - - static getFromCard( card, messageId = null){ - const actorKey = card.dataset.actorKey; - const parentMessageId = card.dataset.parentMessageId; - const fastForward = 'true' == card.dataset.fastForward; - const target = new CoC7MeleeTarget( actorKey, parentMessageId, fastForward); - - target.roll = CoC7Roll.getFromCard( card); - chatHelper.getObjectFromElement( target, card); - - if( card.closest('.message')) - target.messageId = card.closest('.message').dataset.messageId; - else target.messageId = messageId; - return target; - - } - - upgradeRoll( luckAmount, newSuccessLevel, oldCard){ - if( !this.actor.spendLuck( luckAmount)) ui.notifications.error(`${token.name} didn't have enough luck to pass the check`); - this.roll.value = null; - this.roll.successLevel = newSuccessLevel; - this.roll.luckSpent = true; - oldCard.dataset.processed = false; - - const diceRolls = oldCard.querySelector('.dice-roll'); - diceRolls.dataset.value = null; - diceRolls.dataset.successLevel = newSuccessLevel; - diceRolls.dataset.luckSpent = true; - - const resulDetails = oldCard.querySelector('.result-details'); - const diceTotal = oldCard.querySelector('.dice-total'); - switch (newSuccessLevel) { - case CoC7Check.successLevel.regular: - diceTotal.innerText = game.i18n.localize('CoC7.RegularSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.RegularDifficulty')}); - break; - - case CoC7Check.successLevel.hard: - diceTotal.innerText = game.i18n.localize('CoC7.HardSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.HardDifficulty')}); - break; - - case CoC7Check.successLevel.extreme: - diceTotal.innerText = game.i18n.localize('CoC7.ExtremeSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.ExtremeDifficulty')}); - break; - - case CoC7Check.successLevel.critical: - diceTotal.innerText = game.i18n.localize('CoC7.CriticalSuccess'); - resulDetails.innerText = game.i18n.format('CoC7.RollResult.LuckSpendText', {luckAmount: luckAmount, successLevel: game.i18n.localize('CoC7.CriticalDifficulty')}); - break; - - default: - break; - } - - diceTotal.classList.replace( 'failure', 'success'); - oldCard.querySelector('.card-buttons').remove(); - oldCard.querySelector('.dice-tooltip').style.display = 'none'; - CoC7Chat.updateChatCard( oldCard); - } -} - -export class CoC7MeleeResoltion{ - constructor(initiatorMessage = null, targetMessage = null, messageId = null) { - this.initiatorMessage = initiatorMessage; - this.targetMessage = targetMessage; - this.messageId = messageId; - } - - async preCreateMessage(){ - const html = await renderTemplate(this.template, this); - - // const speaker = ChatMessage.getSpeaker({actor: this.actor}); - // if( this.actor.isToken) speaker.alias = this.actor.token.name; - - // const user = this.actor.user ? this.actor.user : game.user; - - const chatData = { - user: game.user._id, - content: html - }; - - // Add image to card. - // data.flags = { - // img: this.actor.isToken ? this.actor.token.data.img: this.actor.img - // }; - - let rollMode = game.settings.get('core', 'rollMode'); - if ( ['gmroll', 'blindroll'].includes(rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); - if ( rollMode === 'blindroll' ) chatData['blind'] = true; - - const chatMessage = await ChatMessage.create(chatData); - this.messageId = chatMessage.id; - return chatMessage; - } - - get target(){ - if(this.targetMessage) return CoC7MeleeTarget.getFromMessageId(this.targetMessage); - return null; - } - - get targetToken(){ - if( this.target) return chatHelper.getTokenFromKey( this.target.actorKey); - return null; - } - - get initiator(){ - if(this.initiatorMessage) return CoC7MeleeInitiator.getFromMessageId(this.initiatorMessage); - return null; - } - - get initiatorToken(){ - if( this.initiator) return chatHelper.getTokenFromKey( this.initiator.actorKey); - return null; - } - - - async resolve(){ - if( this.target){ - switch (this.target.action) { - case 'dodge': - if( this.initiator.roll.successLevel <= 0 && this.target.roll.successLevel <= 0){ - this.resultString = 'Both side failed.'; - this.winner = null; - this.rollDamage = false; - } - else if( this.initiator.roll.successLevel > this.target.roll.successLevel){ - this.resultString = `${this.initiator.token.name} won. Roll damage`; - this.winner = this.initiator; - this.action = 'roll-melee-damage'; - this.rollDamage = true; - } - else if( this.initiator.roll.successLevel <= this.target.roll.successLevel){ - this.resultString = `${this.target.token.name} dodged.`; - this.winner = this.target; - this.action = 'dodge'; - this.rollDamage = false; - } - - break; - - case 'fightBack': - if( this.initiator.roll.successLevel <= 0 && this.target.roll.successLevel <= 0){ - this.resultString = 'Both side failed.'; - this.winner = null; - this.rollDamage = false; - } - else if( this.initiator.roll.successLevel >= this.target.roll.successLevel){ - this.resultString = `${this.initiator.token.name} won. Roll damage`; - this.winner = this.initiator; - this.looser = this.target; - this.rollDamage = true; - } - else if( this.initiator.roll.successLevel <= this.target.roll.successLevel){ - this.resultString = `${this.target.token.name} won. Roll damage`; - this.winner = this.target; - this.looser = this.initiator; - this.rollDamage = true; - } - - break; - - case 'maneuver': - if( this.initiator.roll.successLevel <= 0 && this.target.roll.successLevel <= 0){ - this.resultString = 'Both side failed.'; - this.winner = null; - this.rollDamage = false; - } - else if( this.initiator.roll.successLevel >= this.target.roll.successLevel){ - this.resultString = `${this.initiator.token.name} won. Roll damage`; - this.winner = this.initiator; - this.looser = this.target; - this.rollDamage = true; - } - else if( this.initiator.roll.successLevel <= this.target.roll.successLevel){ - this.resultString = `${this.target.token.name} maneuver was successful.`; - this.winner = this.target; - this.looser = this.initiator; - this.rollDamage = false; - } - - break; - - default: - break; - } - } else { - if( this.initiator.roll.successLevel > 0){ - this.resultString = `${this.initiator.token.name} won. Roll damage`; - this.winner = this.initiator; - this.rollDamage = true; - } else { - this.resultString = `${this.initiator.token.name} missed.`; - this.winner = this.initiator; - this.rollDamage = false; - - } - } - - if( this.winner){ - if( this.winner.roll.successLevel >= CoC7Check.successLevel.extreme) this.winner.roll.criticalDamage = true; - else this.winner.roll.criticalDamage = false; - } - - - this.resolved = true; - const html = await renderTemplate(this.template, this); - if( this.messageId){ - const message = game.messages.get( this.messageId); - const speaker = this.winner ? ChatMessage.getSpeaker({token: this.winner.token}) : null; - const user = this.winner ? this.winner.actor.user ? this.winner.actor.user : game.user : game.user; - - let msg; - if( speaker) msg = await message.update({ - user: user._id, - speaker, - content: html }); - else msg = await message.update({ - user: user._id, - content: html }); - await ui.chat.updateMessage( msg, false); - return msg; - } - } - - get template(){ - return 'systems/CoC7/templates/chat/combat/melee-resolution.html'; - } -} diff --git a/module/coc7.js b/module/coc7.js index 0be60cbc..f09548ef 100644 --- a/module/coc7.js +++ b/module/coc7.js @@ -57,9 +57,20 @@ Hooks.once('init', async function() { choices: { 'regular': 'SETTINGS.CheckDifficultyRegular', 'unknown': 'SETTINGS.CheckDifficultyUnknown' - }, + } }); + + // Register deafult check difficulty + game.settings.register('CoC7', 'useToken', { + name: 'SETTINGS.UseToken', + hint: 'SETTINGS.UseTokenHint', + scope: 'world', + config: true, + default: false, + type: Boolean + }); + // Register sheet application classes Actors.unregisterSheet('core', ActorSheet); Actors.registerSheet('CoC7', CoC7NPCSheet, { types: ['npc'] }); diff --git a/templates/chat/combat/melee-initiator.html b/templates/chat/combat/melee-initiator.html index eeff65d1..3d75a578 100644 --- a/templates/chat/combat/melee-initiator.html +++ b/templates/chat/combat/melee-initiator.html @@ -16,9 +16,10 @@
    +

    {{item.name}}

    - +
    @@ -29,10 +30,12 @@

    {{#if disadvantage}}{{localize 'CoC7.Disadvantage'}}{{/if}}

    - {{target.name}} : + {{#if target}} + {{targetName}} : {{#if outnumbered}}{{localize 'CoC7.OutNumbered'}}{{/if}} {{#if surprised}}{{localize 'CoC7.combatCard.surpised'}}{{/if}} {{#if autoSuccess}}{{localize 'CoC7.combatCard.autoSuccess'}}{{/if}} + {{/if}}
    {{/if}} @@ -59,7 +62,7 @@

    {{#if target}} - + {{/if}}
    @@ -70,11 +73,6 @@

    style="text-align:center" data-flag="outnumbered" data-selected={{outnumbered}}>{{localize 'CoC7.OutNumbered'}} - {{check.resultType}}

    {{/unless}} + {{else}} + {{#unless hasTarget}} +
    + +
    + {{/unless}} {{/if}} {{else}}
    diff --git a/templates/chat/combat/melee-target.html b/templates/chat/combat/melee-target.html index a0f333ca..f15ad2a7 100644 --- a/templates/chat/combat/melee-target.html +++ b/templates/chat/combat/melee-target.html @@ -19,20 +19,21 @@
    + {{#if dodging}}

    {{actor.dodgeSkill.name}}

    - + {{else}} {{#if fightingBack}}

    {{weapon.name}}

    - + {{else}} {{#if maneuvering}}

    {{skill.name}}

    - + {{/if}} {{/if}} {{/if}} From c543118ae8b7484b809829637de48d8629a5e8ea Mon Sep 17 00:00:00 2001 From: HavelockV Date: Thu, 20 Aug 2020 15:30:12 +0200 Subject: [PATCH 07/11] dicebot + unknow check difficulty --- lang/en.json | 4 +- module/actors/actor.js | 16 +- module/actors/sheets/base.js | 5 + module/actors/sheets/creature-sheet.js | 10 +- module/actors/sheets/npc-sheet.js | 4 + module/chat.js | 9 +- module/chat/card-actor.js | 5 +- module/chat/combat/melee-resolution.js | 17 +- module/chat/damagecards.js | 75 ++++----- module/check.js | 9 +- module/coc7.js | 15 +- module/dicebot.js | 168 ++++++++++---------- system.json | 3 +- templates/actors/creature-sheet.html | 104 ++++++++---- templates/chat/combat/damage-result.html | 9 +- templates/chat/combat/melee-initiator.html | 2 + templates/chat/combat/melee-resolution.html | 17 +- templates/chat/combat/melee-target.html | 8 +- templates/chat/roll-result.html | 19 +-- 19 files changed, 303 insertions(+), 196 deletions(-) diff --git a/lang/en.json b/lang/en.json index 338f4c48..f416c5f0 100644 --- a/lang/en.json +++ b/lang/en.json @@ -261,5 +261,7 @@ "SETTINGS.CheckDifficultyRegular": "Default difficulty", "SETTINGS.CheckDifficultyUnknown": "Unknown difficulty", "SETTINGS.UseToken": "Use token image", -"SETTINGS.UseTokenHint": "Use token image instead of portraits in chat-cards" +"SETTINGS.UseTokenHint": "Use token image instead of portraits in chat-cards", +"SETTINGS.DisplayActorOnCard": "Display actor on card", +"SETTINGS.DisplayActorOnCardHint": "Display the actor's image/token on combat chat-cards" } \ No newline at end of file diff --git a/module/actors/actor.js b/module/actors/actor.js index 81237bbd..36a8675c 100644 --- a/module/actors/actor.js +++ b/module/actors/actor.js @@ -368,13 +368,10 @@ export class CoCActor extends Actor { async setHp( value){ if( value < 0) value = 0; - if( value > this.hpMax) value = parseInt( this.data.data.attribs.hp.value); + if( value > this.hpMax) value = parseInt( this.hpMax); return await this.update( { 'data.attribs.hp.value': value}); } - get mp(){ - return parseInt(this.data.data.attribs.mp.value); - } get mpMax(){ if( this.data.data.attribs.mp.auto){ @@ -385,13 +382,16 @@ export class CoCActor extends Actor { return parseInt( this.data.data.attribs.mp.max); } + get mp(){ + return parseInt(this.data.data.attribs.mp.value); + } + async setMp( value){ if( value < 0) value = 0; - if( value > parseInt( this.mpMax)) value = parseInt( this.data.data.attribs.mp.value); + if( value > parseInt( this.mpMax)) value = parseInt( this.mpMax); return await this.update( { 'data.attribs.mp.value': value}); } - get san(){ return parseInt(this.data.data.attribs.san.value); } @@ -510,6 +510,10 @@ export class CoCActor extends Actor { await this.update( {[`data.flags.${flagName}`]: true}); } + async unsetActorFlag( flagName){ + await this.update( {[`data.flags.${flagName}`]: false}); + } + getWeaponSkills( itemId){ const weapon = this.getOwnedItem( itemId); if( 'weapon' != weapon.data.type) return null; diff --git a/module/actors/sheets/base.js b/module/actors/sheets/base.js index e570e296..5652f099 100644 --- a/module/actors/sheets/base.js +++ b/module/actors/sheets/base.js @@ -232,6 +232,10 @@ export class CoC7ActorSheet extends ActorSheet { return this.actor.id; } + onCloseSheet(){ + this.actor.locked = true; + } + /* -------------------------------------------- */ /** @@ -663,6 +667,7 @@ export class CoC7ActorSheet extends ActorSheet { if( event.currentTarget.classList.contains('attribute-value')) { + //TODO : check why SAN only ? if( 'data.attribs.san.value' === event.currentTarget.name) { this.actor.setSan(parseInt( event.currentTarget.value)); diff --git a/module/actors/sheets/creature-sheet.js b/module/actors/sheets/creature-sheet.js index dbfa51be..277ad72b 100644 --- a/module/actors/sheets/creature-sheet.js +++ b/module/actors/sheets/creature-sheet.js @@ -18,12 +18,18 @@ export class CoC7CreatureSheet extends CoC7ActorSheet { data.displayFormula = this.actor.getActorFlag( 'displayFormula'); if( data.displayFormula === undefined) data.displayFormula = false; // await this.actor.creatureInit(); - - + data.hasSan = (null !== data.data.attribs.san.value); + data.hasMp = (null !== data.data.attribs.mp.value); + data.hasLuck = (null !== data.data.attribs.lck.value); return data; } + onCloseSheet(){ + this.actor.unsetActorFlag( 'displayFormula'); + super.onCloseSheet(); + } + /* -------------------------------------------- */ diff --git a/module/actors/sheets/npc-sheet.js b/module/actors/sheets/npc-sheet.js index 85ffe120..63cc41cd 100644 --- a/module/actors/sheets/npc-sheet.js +++ b/module/actors/sheets/npc-sheet.js @@ -21,6 +21,10 @@ export class CoC7NPCSheet extends CoC7ActorSheet { return data; } + onCloseSheet(){ + this.actor.unsetActorFlag( 'displayFormula'); + super.onCloseSheet(); + } /* -------------------------------------------- */ diff --git a/module/chat.js b/module/chat.js index f2a23f58..43154ad3 100644 --- a/module/chat.js +++ b/module/chat.js @@ -1126,9 +1126,12 @@ export class CoC7Chat{ } case 'roll-melee-damage':{ const damageCard = new CoC7DamageRoll( button.dataset.weapon, button.dataset.dealer, button.dataset.target, 'true' == button.dataset.critical ); - damageCard.rollDamage( ); - card.querySelectorAll('.card-buttons').forEach( b => b.remove()); - CoC7Chat.updateChatCard( card); + if( originMessage.dataset.messageId) damageCard.messageId = originMessage.dataset.messageId; + damageCard.rollDamage(); + if( originMessage.dataset.messageId) { + card.querySelectorAll('.card-buttons').forEach( b => b.remove()); + CoC7Chat.updateChatCard( card); + } break; } case 'range-initiator-shoot':{ diff --git a/module/chat/card-actor.js b/module/chat/card-actor.js index 22bd0d2d..727bbaba 100644 --- a/module/chat/card-actor.js +++ b/module/chat/card-actor.js @@ -5,7 +5,10 @@ export class ChatCardActor{ this.actorKey = actorKey; this.fastForward = fastForward; } - + + get displayActorOnCard(){ + return game.settings.get('CoC7', 'displayActorOnCard'); + } get isBlind(){ if( !this.rollMode) return null; diff --git a/module/chat/combat/melee-resolution.js b/module/chat/combat/melee-resolution.js index 28867ca6..012620d7 100644 --- a/module/chat/combat/melee-resolution.js +++ b/module/chat/combat/melee-resolution.js @@ -36,7 +36,11 @@ export class CoC7MeleeResoltion{ this.messageId = chatMessage.id; return chatMessage; } - + + get displayActorOnCard(){ + return game.settings.get('CoC7', 'displayActorOnCard'); + } + get target(){ if(this.targetMessage) return CoC7MeleeTarget.getFromMessageId(this.targetMessage); return null; @@ -57,7 +61,6 @@ export class CoC7MeleeResoltion{ return null; } - async resolve(){ if( this.target){ switch (this.target.action) { @@ -145,13 +148,17 @@ export class CoC7MeleeResoltion{ else this.winner.roll.criticalDamage = false; } - this.resolved = true; const html = await renderTemplate(this.template, this); if( this.messageId){ const message = game.messages.get( this.messageId); - const speaker = this.winner ? ChatMessage.getSpeaker({token: this.winner.token}) : null; - const user = this.winner ? this.winner.actor.user ? this.winner.actor.user : game.user : game.user; + const speakerData = {}; + if( this.winner){ + if( this.winner.token) speakerData.token = this.winner.token; + if( this.winner.actor) speakerData.actor = this.winner.actor; + } + const speaker = this.winner ? ChatMessage.getSpeaker(speakerData) : null; + const user = this.winner && this.winner.actor.user ? this.winner.actor.user : game.user; let msg; if( speaker) msg = await message.update({ diff --git a/module/chat/damagecards.js b/module/chat/damagecards.js index b5937d6a..78cdc676 100644 --- a/module/chat/damagecards.js +++ b/module/chat/damagecards.js @@ -1,7 +1,10 @@ -import { chatHelper } from './helper.js'; +// import { chatHelper } from './helper.js'; +import { ChatCardActor } from './card-actor.js'; -export class CoC7DamageRoll{ + +export class CoC7DamageRoll extends ChatCardActor{ constructor(itemId, actorKey, targetKey = null, critical = false, ignoreArmor = false, fastForward = false) { + super( actorKey, fastForward); this.itemId = itemId; this.actorKey = actorKey; this.targetKey = targetKey; @@ -10,35 +13,6 @@ export class CoC7DamageRoll{ this.ignoreArmor = ignoreArmor; } - get weapon(){ - return this.actor.getOwnedItem( this.itemId); - } - - get actor(){ - return chatHelper.getActorFromKey( this.actorKey); - } - - get actorToken(){ - return chatHelper.getTokenFromKey( this.actorKey); - } - - get targets(){ - return [...game.user.targets]; - } - - get target(){ - if( this.targetKey) return chatHelper.getTokenFromKey( this.targetKey); - return this.targets.pop(); - } - - get targetImg(){ - if( this.target){ - if( this.target.actor.isToken) return this.target.data.img; - return this.target.actor.img; - } - return '../icons/svg/mystery-man-black.svg'; - } - /** * * Roll the damage applying the formula provided. @@ -86,24 +60,33 @@ export class CoC7DamageRoll{ const html = await renderTemplate('systems/CoC7/templates/chat/combat/damage-result.html', this); - let speakerData = {}; - if( this.actorToken) speakerData.token = this.actorToken; - else speakerData.actor = this.actor; - const speaker = ChatMessage.getSpeaker(speakerData); - if( this.actor.isToken) speaker.alias = this.actor.token.name; + //TODO : replace the card if possible (can the player mod the message ???) + if( this.messageId){ + const message = game.messages.get( this.messageId); + message.update({ content: html }).then(msg => { + ui.chat.updateMessage( msg, false); + }); + } else { + + let speakerData = {}; + if( this.actorToken) speakerData.token = this.actorToken; + else speakerData.actor = this.actor; + const speaker = ChatMessage.getSpeaker(speakerData); + if( this.actor.isToken) speaker.alias = this.actor.token.name; - const user = this.actor.user ? this.actor.user : game.user; + const user = this.actor.user ? this.actor.user : game.user; - const chatData = { - user: user._id, - speaker, - content: html - }; + const chatData = { + user: user._id, + speaker, + content: html + }; - let rollMode = game.settings.get('core', 'rollMode'); - if ( ['gmroll', 'blindroll'].includes(rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); - if ( rollMode === 'blindroll' ) chatData['blind'] = true; + let rollMode = game.settings.get('core', 'rollMode'); + if ( ['gmroll', 'blindroll'].includes(rollMode) ) chatData['whisper'] = ChatMessage.getWhisperRecipients('GM'); + if ( rollMode === 'blindroll' ) chatData['blind'] = true; - await ChatMessage.create(chatData); + await ChatMessage.create(chatData); + } } } diff --git a/module/check.js b/module/check.js index f0b09ba7..31135d29 100644 --- a/module/check.js +++ b/module/check.js @@ -114,6 +114,7 @@ export class CoC7Check { } get unknownDifficulty(){ + if( this.gmDifficultyCritical || this.gmDifficultyExtreme || this.gmDifficultyHard || this.gmDifficultyRegular) return false; return CoC7Check.difficultyLevel.unknown === this.difficulty; } @@ -251,6 +252,11 @@ export class CoC7Check { this.isUnknown = this.unknownDifficulty; + if( this.gmDifficultyRegular) this.difficulty = CoC7Check.difficultyLevel.regular; + if( this.gmDifficultyHard) this.difficulty = CoC7Check.difficultyLevel.hard; + if( this.gmDifficultyExtreme) this.difficulty = CoC7Check.difficultyLevel.extreme; + if( this.gmDifficultyCritical) this.difficulty = CoC7Check.difficultyLevel.critical; + this.tenOnlyOneDie = this.dices.tens.length == 1; // @@ -575,7 +581,7 @@ export class CoC7Check { let html = await renderTemplate(template, this); const message = game.messages.get( this.messageId); - const msg = await message.update({ content: html }); + const msg = await message.update({ flavor: this.flavor, content: html }); await ui.chat.updateMessage( msg, false); return msg; } @@ -591,6 +597,7 @@ export class CoC7Check { if( 'gmDifficultyHard' === event.currentTarget.dataset.flag){ check.gmDifficultyHard = true;} if( 'gmDifficultyExtreme' === event.currentTarget.dataset.flag){ check.gmDifficultyExtreme = true;} if( 'gmDifficultyCritical' === event.currentTarget.dataset.flag){ check.gmDifficultyCritical = true;} + check.computeCheck(); check.updateChatCard(); } diff --git a/module/coc7.js b/module/coc7.js index f09548ef..e40b7627 100644 --- a/module/coc7.js +++ b/module/coc7.js @@ -46,7 +46,7 @@ Hooks.once('init', async function() { type: Number }); - // Register deafult check difficulty + // Set default check difficulty. game.settings.register('CoC7', 'defaultCheckDifficulty', { name: 'SETTINGS.DefaultDifficulty', hint: 'SETTINGS.DefaultDifficultyHint', @@ -61,7 +61,7 @@ Hooks.once('init', async function() { }); - // Register deafult check difficulty + // Set the use of token instead of portraits. game.settings.register('CoC7', 'useToken', { name: 'SETTINGS.UseToken', hint: 'SETTINGS.UseTokenHint', @@ -71,6 +71,16 @@ Hooks.once('init', async function() { type: Boolean }); + // Set the need to display actor image on chat cards. + game.settings.register('CoC7', 'displayActorOnCard', { + name: 'SETTINGS.DisplayActorOnCard', + hint: 'SETTINGS.DisplayActorOnCardHint', + scope: 'world', + config: true, + default: false, + type: Boolean + }); + // Register sheet application classes Actors.unregisterSheet('core', ActorSheet); Actors.registerSheet('CoC7', CoC7NPCSheet, { types: ['npc'] }); @@ -91,6 +101,7 @@ Hooks.on('updateChatMessage', (chatMessage, chatData, diff, speaker) => CoC7Chat Hooks.on('ready', CoC7Chat.ready); Hooks.on('preCreateActor', (createData) => CoCActor.initToken( createData)); Hooks.on('renderCombatTracker', (combatTracker, html, data) => CoC7Combat.renderCombatTracker(combatTracker, html, data)); +Hooks.on('closeActorSheet', (characterSheet) => characterSheet.onCloseSheet()); // Hooks.on('chatMessage', (chatLog, message, chatData) => { console.log('**************************************************************************************************chatMessage : ' + message);}); diff --git a/module/dicebot.js b/module/dicebot.js index 115fcd05..c551175d 100644 --- a/module/dicebot.js +++ b/module/dicebot.js @@ -4,99 +4,99 @@ *[/CC]Define a command to judge a normal dice. *[/CBR] Command to define the decision on combination rolls. */ -Hooks.on("chatMessage", (html,content) => { +Hooks.on('chatMessage', (html,content) => { //Read the command - let rgx; - rgx = /(\S+)/g; - let commands = content.match(rgx); - let command = commands[0]; + let rgx; + rgx = /(\S+)/g; + let commands = content.match(rgx); + let command = commands[0]; -//Declare the dice to be used. - //Define a function to read the value - let m = 0; - let n = 0; - let s = 0; + //Declare the dice to be used. + //Define a function to read the value + let m = 0; + let n = 0; + let s = 0; - //Define errors as debugging. - let res = "

    Error

    "; + //Define errors as debugging. + let res = '

    Error

    '; - //Normal Dice - let r = new Roll("1d100"); + //Normal Dice + let r = new Roll('1d100'); - //Perform processing for each command. - if(command === "/CC" || command === "/cc"){ - //This time, extract only the numbers. - rgx = /(?:[0-9]+)/g; - commands = content.match(rgx); - m = commands[0]; + //Perform processing for each command. + if(command === '/CC' || command === '/cc'){ + //This time, extract only the numbers. + rgx = /(?:[0-9]+)/g; + commands = content.match(rgx); + m = commands[0]; - //Determination based on rolls and readings - r.roll(); - //Put the result of the die into s as a number rather than an object. - s = r.result; - if(s <= 1) res = game.i18n.localize("CoC7.CriticalSuccess"); - else if(s >= 100) res= game.i18n.localize("CoC7.Fumble"); - else if(s <= (m/5)) res= game.i18n.localize("CoC7.ExtremeSuccess"); - else if(s <= (m/2)) res= game.i18n.localize("CoC7.HardSuccess"); - else if(s <= m) res= game.i18n.localize("CoC7.RegularSuccess"); - else if(s >= 96){if(m < 50) res= game.i18n.localize("CoC7.Fumble"); - else res= game.i18n.localize("CoC7.Failure");} - else res= game.i18n.localize("CoC7.Failure"); + //Determination based on rolls and readings + r.roll(); + //Put the result of the die into s as a number rather than an object. + s = r.result; + if(s <= 1) res = game.i18n.localize('CoC7.CriticalSuccess'); + else if(s >= 100) res= game.i18n.localize('CoC7.Fumble'); + else if(s <= (m/5)) res= game.i18n.localize('CoC7.ExtremeSuccess'); + else if(s <= (m/2)) res= game.i18n.localize('CoC7.HardSuccess'); + else if(s <= m) res= game.i18n.localize('CoC7.RegularSuccess'); + else if(s >= 96){if(m < 50) res= game.i18n.localize('CoC7.Fumble'); + else res= game.i18n.localize('CoC7.Failure');} + else res= game.i18n.localize('CoC7.Failure'); - //The resulting output. - res += (game.i18n.localize("CoC7.SkillValue") + m); - r.toMessage( - {speaker: ChatMessage.getSpeaker(), - flavor: res, - }); - //return to avoid errors in the command. - return false; - } + //The resulting output. + res += (game.i18n.localize('CoC7.SkillValue') + m); + r.toMessage( + {speaker: ChatMessage.getSpeaker(), + flavor: res, + }); + //return to avoid errors in the command. + return false; + } - //I'm currently using it for testing bonus dice. - if(command === "/CBR" || command === "/cbr"){ - //Extracting numbers from combination rolls - rgx = /(?:[0-9]+)/g; - commands = content.match(rgx); - m = commands[0]; - rgx = /(?:,[0-9]+)/g; - commands = content.match(rgx); - n = commands[0].replace(/[^0-9]/g, ''); + //I'm currently using it for testing bonus dice. + if(command === '/CBR' || command === '/cbr'){ + //Extracting numbers from combination rolls + rgx = /(?:[0-9]+)/g; + commands = content.match(rgx); + m = commands[0]; + rgx = /(?:,[0-9]+)/g; + commands = content.match(rgx); + n = commands[0].replace(/[^0-9]/g, ''); - //Determination based on rolls and readings - r.roll(); - //Put the result of the die into s as a number rather than an object. - s = r.result; - //Determine the first number. - if(s <= 1) res = game.i18n.localize("CoC7.CriticalSuccess"); - else if(s >= 100) res= game.i18n.localize("CoC7.Fumble"); - else if(s <= (m/5)) res= game.i18n.localize("CoC7.ExtremeSuccess"); - else if(s <= (m/2)) res= game.i18n.localize("CoC7.HardSuccess"); - else if(s <= m) res= game.i18n.localize("CoC7.RegularSuccess"); - else if(s >= 96){if(m < 50) res= game.i18n.localize("CoC7.Fumble"); - else res= game.i18n.localize("CoC7.Failure");} - else res= game.i18n.localize("CoC7.Failure"); - //Record the first results. - res += (game.i18n.localize("CoC7.SkillValue") + m); + //Determination based on rolls and readings + r.roll(); + //Put the result of the die into s as a number rather than an object. + s = r.result; + //Determine the first number. + if(s <= 1) res = game.i18n.localize('CoC7.CriticalSuccess'); + else if(s >= 100) res= game.i18n.localize('CoC7.Fumble'); + else if(s <= (m/5)) res= game.i18n.localize('CoC7.ExtremeSuccess'); + else if(s <= (m/2)) res= game.i18n.localize('CoC7.HardSuccess'); + else if(s <= m) res= game.i18n.localize('CoC7.RegularSuccess'); + else if(s >= 96){if(m < 50) res= game.i18n.localize('CoC7.Fumble'); + else res= game.i18n.localize('CoC7.Failure');} + else res= game.i18n.localize('CoC7.Failure'); + //Record the first results. + res += (game.i18n.localize('CoC7.SkillValue') + m); - //Determine the second number. - if(s <= 1) res += game.i18n.localize("CoC7.CriticalSuccess"); - else if(s >= 100) res += game.i18n.localize("CoC7.Fumble"); - else if(s <= (n/5)) res += game.i18n.localize("CoC7.ExtremeSuccess"); - else if(s <= (n/2)) res += game.i18n.localize("CoC7.HardSuccess"); - else if(s <= n) res += game.i18n.localize("CoC7.RegularSuccess"); - else if(s >= 96){if(n < 50) res += game.i18n.localize("CoC7.Fumble"); - else res += game.i18n.localize("CoC7.Failure");} - else res += game.i18n.localize("CoC7.Failure"); - //The resulting output. - res += (game.i18n.localize("CoC7.SkillValue") + n); - r.toMessage( - {speaker: ChatMessage.getSpeaker(), - flavor: res, - }); - //return to avoid errors in the command. - return false; - } - }) + //Determine the second number. + if(s <= 1) res += game.i18n.localize('CoC7.CriticalSuccess'); + else if(s >= 100) res += game.i18n.localize('CoC7.Fumble'); + else if(s <= (n/5)) res += game.i18n.localize('CoC7.ExtremeSuccess'); + else if(s <= (n/2)) res += game.i18n.localize('CoC7.HardSuccess'); + else if(s <= n) res += game.i18n.localize('CoC7.RegularSuccess'); + else if(s >= 96){if(n < 50) res += game.i18n.localize('CoC7.Fumble'); + else res += game.i18n.localize('CoC7.Failure');} + else res += game.i18n.localize('CoC7.Failure'); + //The resulting output. + res += (game.i18n.localize('CoC7.SkillValue') + n); + r.toMessage( + {speaker: ChatMessage.getSpeaker(), + flavor: res, + }); + //return to avoid errors in the command. + return false; + } +}); diff --git a/system.json b/system.json index 12674b22..dc1f9e1e 100644 --- a/system.json +++ b/system.json @@ -8,7 +8,8 @@ "compatibleCoreVersion": "0.6.5", "esmodules": [ "module/coc7.js", - "pdfoundry-dist/bundle.js" + "pdfoundry-dist/bundle.js", + "module/dicebot.js" ], "templateVersion": 1, "styles": ["styles/coc7.css"], diff --git a/templates/actors/creature-sheet.html b/templates/actors/creature-sheet.html index 1cd55c43..8ea60872 100644 --- a/templates/actors/creature-sheet.html +++ b/templates/actors/creature-sheet.html @@ -16,6 +16,22 @@
    {{#each data.characteristics as |characteristic key|}} + {{#if ../data.flags.locked}} + {{#if characteristic.value}} +
    +
    + +
    +
    + {{#if characteristic.editable}} + + {{else}} + + {{/if}} +
    +
    + {{/if}} + {{else}}
    @@ -34,11 +50,12 @@
    {{/if}}
    + {{/if}} {{/each}}
    -
    +
    / @@ -53,33 +70,66 @@ {{/unless}}
    -
    - - - / - {{#if data.attribs.mp.auto}} - {{data.attribs.mp.max}} - {{else}} - - {{/if}} + {{#if data.flags.locked}} +
    + {{#if hasMp}} + + + / + {{#if data.attribs.mp.auto}} + {{data.attribs.mp.max}} + {{else}} + + {{/if}} +
    + {{/if}} +
    - {{#unless data.flags.locked}} -
    - {{/unless}} -
    -
    -
    - - - / - -
    -
    -
    - - -
    -
    +
    + {{#if hasSan}} + + + / + +
    + {{/if}} +
    + +
    + {{#if hasLuck}} + + +
    + {{/if}} +
    + {{else}} +
    + + + / + {{#if data.attribs.mp.auto}} + {{data.attribs.mp.max}} + {{else}} + + {{/if}} +
    +
    +
    + +
    + + + / + +
    +
    + +
    + + +
    +
    + {{/if}}
    diff --git a/templates/chat/combat/damage-result.html b/templates/chat/combat/damage-result.html index 3179b42e..2b698c0b 100644 --- a/templates/chat/combat/damage-result.html +++ b/templates/chat/combat/damage-result.html @@ -9,9 +9,12 @@
    - -

    {{weapon.name}}

    - + {{#if displayActorOnCard}} + + {{/if}} + +

    {{item.name}}

    +
    diff --git a/templates/chat/combat/melee-initiator.html b/templates/chat/combat/melee-initiator.html index 3d75a578..7053fcec 100644 --- a/templates/chat/combat/melee-initiator.html +++ b/templates/chat/combat/melee-initiator.html @@ -16,7 +16,9 @@
    + {{#if displayActorOnCard}} + {{/if}}

    {{item.name}}

    diff --git a/templates/chat/combat/melee-resolution.html b/templates/chat/combat/melee-resolution.html index 67d90ae3..df598a67 100644 --- a/templates/chat/combat/melee-resolution.html +++ b/templates/chat/combat/melee-resolution.html @@ -10,17 +10,30 @@ data-resolved="{{resolved}}" >
    + {{#if winner}} +
    + {{#if displayActorOnCard}} + + {{/if}} + +

    {{winner.item.name}}

    + {{#if looser}} + + {{/if}} +
    + {{else}}

    {{resultString}}

    + {{/if}}
    {{#if rollDamage}}
    {{#if looser}} -

    {{looser.token.name}} takes {{winner.weapon.data.data.range.normal.damage}}{{#if winner.weapon.data.data.properties.addb}}+DB{{/if}}{{#if winner.weapon.data.data.properties.ahdb}}+DB/2{{/if}} from {{winner.weapon.name}}

    +

    {{looser.name}} takes {{winner.weapon.data.data.range.normal.damage}}{{#if winner.weapon.data.data.properties.addb}}+DB{{/if}}{{#if winner.weapon.data.data.properties.ahdb}}+DB/2{{/if}} from {{winner.weapon.name}}

    {{else}} -

    {{winner.token.name}} deals {{winner.weapon.data.data.range.normal.damage}}{{#if winner.weapon.data.data.properties.addb}}+DB{{/if}}{{#if winner.weapon.data.data.properties.ahdb}}+DB/2{{/if}} with {{winner.weapon.name}}

    +

    {{winner.name}} deals {{winner.weapon.data.data.range.normal.damage}}{{#if winner.weapon.data.data.properties.addb}}+DB{{/if}}{{#if winner.weapon.data.data.properties.ahdb}}+DB/2{{/if}} with {{winner.weapon.name}}

    {{/if}}
    diff --git a/templates/chat/combat/melee-target.html b/templates/chat/combat/melee-target.html index f15ad2a7..a8834223 100644 --- a/templates/chat/combat/melee-target.html +++ b/templates/chat/combat/melee-target.html @@ -19,24 +19,26 @@
    + {{#if displayActorOnCard}} + {{/if}} {{#if dodging}}

    {{actor.dodgeSkill.name}}

    - {{else}} {{#if fightingBack}}

    {{weapon.name}}

    - {{else}} {{#if maneuvering}}

    {{skill.name}}

    - + {{else}} +

    ...

    {{/if}} {{/if}} {{/if}} +
    diff --git a/templates/chat/roll-result.html b/templates/chat/roll-result.html index 63a9dd03..4a7a8bff 100644 --- a/templates/chat/roll-result.html +++ b/templates/chat/roll-result.html @@ -43,26 +43,27 @@ data-gm-difficulty-extreme="{{gmDifficultyExtreme}}" data-gm-difficulty-critical="{{gmDifficultyCritical}}" {{#if tokenId}}data-token-id="{{tokenId}}"{{/if}}> + {{#if isUnknown}} -
    +
    {{localize 'CoC7.RollDifficultyRegular'}} + data-selected={{gmDifficultyRegular}}>{{localize 'CoC7.RollDifficultyRegular'}} {{regularThreshold}}% {{localize 'CoC7.RollDifficultyHard'}} + data-selected={{gmDifficultyHard}}>{{localize 'CoC7.RollDifficultyHard'}} {{hardThreshold}}% {{localize 'CoC7.RollDifficultyExtreme'}} + data-selected={{gmDifficultyExtreme}}>{{localize 'CoC7.RollDifficultyExtreme'}} {{extremeThreshold}}% {{localize 'CoC7.RollDifficultyCritical'}}
    @@ -71,7 +72,7 @@
    -
    1D% {{#if dices.hasBonus}}{{dices.bonus}} {{dices.bonusType}} {{localize 'CoC7.Dice'}}{{/if}}
    +
    1D% {{#if dices.hasBonus}}{{dices.bonus}} {{dices.bonusType}} {{localize 'CoC7.Dice'}}{{/if}}