Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to display calculated attack bonus in auto power cards #352

Merged
merged 9 commits into from
Apr 2, 2024
Merged
12 changes: 10 additions & 2 deletions lang/en-au.json
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@
"DND4E.gains": "gains",
"DND4E.Gaze": "Gaze",
"DND4E.Gender": "Gender",
"DND4E.GMNotesAdd": "Add GM Notes",
"DND4E.GrantedAbilities": "Granted Abilities",
"DND4E.HalfLVL": "1/2 LVL",
"DND4E.HalfProficient": "Half Proficient",
Expand Down Expand Up @@ -1126,8 +1127,8 @@
"DND4E.TargetEnemy": "Enemy",
"DND4E.TargetEnemyAdjacent": "Adjacent Enemy",
"DND4E.TargetLine": "Line",
"DND4E.TargetObject": "Object",
"DND4E.TargetMisc": "Misc",
"DND4E.TargetObject": "Object",
"DND4E.TargetPersonal": "Personal",
"DND4E.TargetRadius": "Radius",
"DND4E.TargetSpace": "Space",
Expand All @@ -1139,6 +1140,7 @@
"DND4E.TempHP": "Temp HP",
"DND4E.TempHPTip": "Temporary Hit Points",
"DND4E.Theme": "Theme",
"DND4E.Tier": "Tier",
"DND4E.TimeDay": "Days",
"DND4E.TimeHour": "Hours",
"DND4E.TimeInst": "Instantaneous",
Expand Down Expand Up @@ -1480,7 +1482,9 @@
"DND4EUI.UnknownCondition.Tip": "No match was found for this id in the current status conditions configuration.",
"DND4EUI.Yes": "Yes",
"SETTINGS.4eApplyEffectsToSelectionN": "Buttons to apply effects should apply to SELECTED tokens",
"SETTINGS.4eApplyEffectsToSelectionL": "If checked, apply effect buttons will work over targets that are SELECTED. Otherwise will work over tokens that are TARGETED",
"SETTINGS.4eApplyEffectsToSelectionL": "If checked, apply effect buttons will work over targets that are SELECTED. Otherwise will work over tokens that are TARGETED",
"SETTINGS.4eAutoApplyEffectsL": "Determin if a powers effects/conditions will be autmaticly appled to valid selected targets when a power is used or when an attack roll is made.",
"SETTINGS.4eAutoApplyEffectsN": "Automaticly Apply Effetcs",
"SETTINGS.4eAutoCollapseCardL": "Automatically collapse Item Card descriptions in the Chat Log",
"SETTINGS.4eAutoCollapseCardN": "Collapse Item Cards in Chat",
"SETTINGS.4eAutoDoTsApply": "Apply automatically",
Expand All @@ -1496,6 +1500,10 @@
"SETTINGS.4eAutomationCombatL": "Determine whether the Attack Rolls hits or misses.",
"SETTINGS.4eAutoSpellTemplateL": "When a spell is cast, defaults to begin the process to create the corresponding Measured Template if any (requires TRUSTED or higher player role)",
"SETTINGS.4eAutoSpellTemplateN": "Always place Spell Template",
"SETTINGS.4eCardAtkDisplayL": "When an attack has an associated ability score, how should the auto power card show the name and attack bonus value?",
"SETTINGS.4eCardAtkDisplayN": "Power card attack display",
"SETTINGS.4eCardAtkDisplayBonus": "Display bonus (name/formula in tooltip)",
"SETTINGS.4eCardAtkDisplayStat": "Display name (bonus/formula in tooltip)",
"SETTINGS.4eCollapseSituationalBonusL": "If checked: all common situational modifiers will be computed and added as a single modifier to @bonus. Otherwise each will be displayed individually in the resulting formula",
"SETTINGS.4eCollapseSituationalBonusN": "Collapse Common Attack Mods",
"SETTINGS.4eCurWtL": "Carried currency affects character encumbrance following the rules on PHB pg. 212.",
Expand Down
5 changes: 5 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,7 @@
"DND4E.TempHP": "Temp HP",
"DND4E.TempHPTip": "Temporary Hit Points",
"DND4E.Theme": "Theme",
"DND4E.Tier": "Tier",
"DND4E.TimeDay": "Days",
"DND4E.TimeHour": "Hours",
"DND4E.TimeInst": "Instantaneous",
Expand Down Expand Up @@ -1499,6 +1500,10 @@
"SETTINGS.4eAutomationCombatL": "Determine whether the Attack Rolls hits or misses.",
"SETTINGS.4eAutoSpellTemplateL": "When a spell is cast, defaults to begin the process to create the corresponding Measured Template if any (requires TRUSTED or higher player role)",
"SETTINGS.4eAutoSpellTemplateN": "Always place Spell Template",
"SETTINGS.4eCardAtkDisplayL": "When an attack has an associated ability score, how should the auto power card show the name and attack bonus value?",
"SETTINGS.4eCardAtkDisplayN": "Power card attack display",
"SETTINGS.4eCardAtkDisplayBonus": "Display bonus (name/formula in tooltip)",
"SETTINGS.4eCardAtkDisplayStat": "Display name (bonus/formula in tooltip)",
"SETTINGS.4eCollapseSituationalBonusL": "If checked: all common situational modifiers will be computed and added as a single modifier to @bonus. Otherwise each will be displayed individually in the resulting formula",
"SETTINGS.4eCollapseSituationalBonusN": "Collapse Common Attack Mods",
"SETTINGS.4eCurWtL": "Carried currency affects character encumbrance following the rules on PHB pg. 212.",
Expand Down
6 changes: 5 additions & 1 deletion module/actor/actor-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,11 @@ ${parseInt(data.system.movement.walk.value)} ${game.i18n.localize("DND4E.Movemen

if(item.system.autoGenChatPowerCard){
// let details = $(`<div class="item-details">${Helper._preparePowerCardData(chatData, CONFIG, this.actor.toObject(false))}</div>`);
let details = $(`<div class="item-details">${Helper._preparePowerCardData(chatData, CONFIG, this.actor)}</div>`);
let attackBonus = null;
if(item.hasAttack){
attackBonus = await item.getAttackBonus();
}
let details = $(`<div class="item-details">${Helper._preparePowerCardData(chatData, CONFIG, this.actor, attackBonus)}</div>`);
div.append(details);
}

Expand Down
60 changes: 33 additions & 27 deletions module/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ export class Helper {
}
}

static _preparePowerCardData(chatData, CONFIG, actorData=null) {
static _preparePowerCardData(chatData, CONFIG, actorData=null, attackTotal=null) {
let powerSource = (chatData.powersource && chatData.powersource !== "") ? `${CONFIG.DND4E.powerSource[`${chatData.powersource}`]}` : "";
let powerDetail = `<span class="basics"><span class="usage">${CONFIG.DND4E.powerUseType[`${chatData.useType}`]}</span>`;
let tag = [];
Expand Down Expand Up @@ -952,27 +952,35 @@ export class Helper {
}

if(chatData.attack.isAttack) {
if(chatData.attack.ability === "form"){
//if does not srtart with a number sign add one

let attackForm = this.commonReplace(chatData.attack.formula, actorData);
try {
attackForm = Roll.safeEval(attackForm).toString();
} catch (e) { /* noop */ }


let trimmedForm = attackForm.trim()
if(!(trimmedForm.startsWith("+") || trimmedForm.startsWith("-"))) {
trimmedForm = '+' + trimmedForm;
let attackForm = chatData.attack.formula;
attackForm = chatData.attack.formula.replaceAll('@powerMod',`@${chatData.attack?.ability}Mod`);
const attackValues = this.commonReplace(attackForm, actorData);
if(attackTotal){
//if does not start with a number sign add one
attackTotal = attackTotal.toString();
if(!(attackTotal.startsWith("+") || attackTotal.startsWith("-"))) {
attackTotal = '+' + attackTotal;
}
powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}:</strong> ${trimmedForm} ${game.i18n.localize("DND4E.VS")} ${CONFIG.DND4E.def[chatData.attack.def]}</p>`;
}else if(chatData.attack.ability){
attackTotal = CONFIG.DND4E.abilities[chatData.attack.ability];
}else{
attackTotal = game.i18n.localize("DND4E.Attack");
}

if(chatData.attack.ability === "form"){
powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}:</strong> <a class="attack-bonus" data-tooltip="${attackValues}">${attackTotal}</a>`;
}
else if(chatData.attack.ability){
powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}</strong>: ${CONFIG.DND4E.abilities[chatData.attack.ability]} ${game.i18n.localize("DND4E.VS")} ${CONFIG.DND4E.def[chatData.attack.def]}</p>`;
powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}</strong>: <a class="attack-bonus" data-tooltip="`;
if(game.settings.get("dnd4e","cardAtkDisplay")=="bonus"){
powerDetail += `${CONFIG.DND4E.abilities[chatData.attack.ability]} (${attackValues})">${attackTotal}</a>`;
}else{
powerDetail += `${attackTotal} (${attackValues})">${CONFIG.DND4E.abilities[chatData.attack.ability]}</a>`;
}
} else {
powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}</strong>: ${game.i18n.localize("DND4E.Attack")} ${game.i18n.localize("DND4E.VS")} ${CONFIG.DND4E.def[chatData.attack.def]}</p>`;
powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}</strong>: ${game.i18n.localize("DND4E.Attack")}`;
}
// powerDetail += `<p class="attack"><strong>${game.i18n.localize("DND4E.Attack")}</strong>: ${CONFIG.DND4E.abilities[chatData.attack.ability] || "Attack"} ${game.i18n.localize("DND4E.VS")} ${CONFIG.DND4E.def[chatData.attack.def]}</p>`;
powerDetail += ` ${game.i18n.localize("DND4E.VS")} ${CONFIG.DND4E.def[chatData.attack.def]}</p>`;
}

let highlight = true;
Expand Down Expand Up @@ -1209,13 +1217,12 @@ export class Helper {
return ( idOnly ? firstGM.id : firstGM );
}


/**
/* Function to return the sum of the highest positive value
/* and the lowest negative value in a given set.
/* Intended for getting the correct value from multiple
/* resistances and vulnerabilities.
/* */
* Function to return the sum of the highest positive value
* and the lowest negative value in a given set.
* Intended for getting the correct value from multiple
* resistances and vulnerabilities.
*/
static sumExtremes(values = []){
if (!values.length) return;
let negatives = [0], positives = [0];
Expand All @@ -1232,7 +1239,6 @@ export class Helper {
return Math.max(...positives) + Math.min(...negatives);
}


/**
* Determine if a fastForward key was held during the given click event.
*
Expand All @@ -1259,7 +1265,7 @@ export class Helper {
const foundEffects = power.item.effects.contents.filter(e => effects.includes(e.flags.dnd4e.effectData.powerEffectTypes));
return foundEffects.length > 0;
}

/**
* Use to find the value in a given scale
*
Expand Down Expand Up @@ -1293,7 +1299,7 @@ export class Helper {
}
return result;
}

}

export async function handleApplyEffectToToken(data){
Expand Down Expand Up @@ -1384,4 +1390,4 @@ Handlebars.registerHelper("needsHitOrMissEffectButton", function(power){

Handlebars.registerHelper("applyEffectsToSelection", function(){
return game.settings.get("dnd4e","applyEffectsToSelection")
});
});
8 changes: 6 additions & 2 deletions module/item/item-document.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,11 @@ export default class Item4e extends Item {
const cardData = await ( async () => {
if ((this.type === "power" || this.type === "consumable") && this.system.autoGenChatPowerCard) {
let weaponUse = Helper.getWeaponUse(this.system, this.actor);
let cardString = Helper._preparePowerCardData(await this.getChatData(), CONFIG, this.actor);
let attackBonus = null;
if(this.hasAttack){
attackBonus = await this.getAttackBonus();
}
let cardString = Helper._preparePowerCardData(await this.getChatData(), CONFIG, this.actor, attackBonus);
return Helper.commonReplace(cardString, this.actor, this, weaponUse? weaponUse.system : null, 1);
} else {
return null;
Expand Down Expand Up @@ -1309,7 +1313,7 @@ export default class Item4e extends Item {
rollConfig.options.powerEffects = this.effects;
rollConfig.options.parent = this.parent;
}

// Get the bonus
const bonus = getAttackRollBonus(rollConfig);

Expand Down
13 changes: 13 additions & 0 deletions module/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,4 +342,17 @@ export const registerSystemSettings = function() {
// ],
// precedence: CONST.KEYBINDING_PRECEDENCE.NORMAL,
// });

game.settings.register("dnd4e", "cardAtkDisplay",{
name: "SETTINGS.4eCardAtkDisplayN",
hint: "SETTINGS.4eCardAtkDisplayL",
scope: "client",
config: true,
default: "stat",
type: String,
choices: {
"bonus": "SETTINGS.4eCardAtkDisplayBonus",
"stat": "SETTINGS.4eCardAtkDisplayStat"
}
});
};