Skip to content

Commit

Permalink
Merge pull request dmdorman#1512 from phBalance/phBalance/striking-ap…
Browse files Browse the repository at this point in the history
…pearance-pt2

Ph balance/striking appearance pt2
  • Loading branch information
phBalance authored Nov 24, 2024
2 parents 0fa16f8 + 292593b commit 6539fdf
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 78 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Releases

## Version 4.0.8 [Hero System 6e (Unofficial) v2](https://github.com/dmdorman/hero6e-foundryvtt)
## Version 4.0.8 (So far...) [Hero System 6e (Unofficial) v2](https://github.com/dmdorman/hero6e-foundryvtt)

- Support striking appearance. Can be optionally enabled for presence and interaction skill rolls. [#1509](https://github.com/dmdorman/hero6e-foundryvtt/issues/1509)
- Improved DEADLYBLOW so it does not apply to adjustment powers, sense-affecting powers, or ENTANGLES. GM still has to confirm DEADLYBLOW with applicable powers. [#1493](https://github.com/dmdorman/hero6e-foundryvtt/issues/1493)

## Version 4.0.7
Expand Down
4 changes: 2 additions & 2 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,14 @@ Our support ratings:
| EIDETIC MEMORY | D | |
| ENVIRONMENTAL MOVEMENT | D | |
| LIGHTNING CALCULATOR | D | |
| LIGHTNING REFLEXES | B | A second token in the combat tracker is shown, but up to player/gm to determine when to use |
| LIGHTNING REFLEXES | B | A second token in the combat tracker is shown, but up to player/GM to determine when to use |
| LIGHTSLEEP | D | |
| OFF-HAND DEFENSE | D | |
| PERFECT PITCH | D | |
| RESISTANCE | D | |
| SIMULATE DEATH | D | |
| SPEED READING | D | |
| STRIKING APPEARANCE | D | |
| STRIKING APPEARANCE | B | Up to player/GM to determine when to use |
| UNIVERSAL TRANSLATOR | D | |
| WEAPONMASTER | B | |

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const cardHtml = await damageRoller.render("Knockback roll");
const chatData = {
style: CONST.CHAT_MESSAGE_STYLES.OTHER,
rolls: damageRoller.rawRolls(),
user: game.user._id,
author: game.user._id,
content: cardHtml,
};

Expand Down
83 changes: 70 additions & 13 deletions module/item/skill.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,96 @@ import { HeroRoller } from "../utility/dice.mjs";
import { userInteractiveVerifyOptionallyPromptThenSpendResources } from "./item-attack.mjs";
import { overrideCanAct } from "../settings/settings-helpers.mjs";

export function isAgilitySkill(item) {
return item.system.CHARACTERISTIC === "DEX";
}

export function isBackgroundSkill(item) {
switch (item.system.XMLID) {
case "KNOWLEDGE_SKILL":
case "LANGUAGES":
case "PROFESSIONAL_SKILL":
case "SCIENCE_SKILL":
case "TRANSPORT_FAMILIARITY":
return true;
}

return false;
}

export function isCombatSkill(item) {
if (
item.system.XMLID === "AUTOFIRE_SKILLS" || // Autofire Skills
item.system.XMLID === "COMBAT_LEVELS" || // CSLs
item.system.XMLID === "MENTAL_COMBAT_LEVELS" ||
item.system.XMLID === "DEFENSE_MANEUVER" || // Defense maneuver
item.system.XMLID === "MANEUVER" || // Martial Arts
item.system.XMLID === "PENALTY_SKILL_LEVELS" || // PSLs
item.system.XMLID === "RAPID_ATTACK_HTH" || // Rapid Attack
item.system.XMLID === "RAPID_ATTACK_RANGED" ||
item.system.XMLID === "TWO_WEAPON_FIGHTING_HTH" || // Two Weapon Fighting
item.system.XMLID === "TWO_WEAPON_FIGHTING_RANGED" ||
item.system.XMLID === "WEAPON_FAMILIARITY" // Weapon Familiarity
) {
return true;
}

return false;
}

export function isIntellectSkill(item) {
return item.system.CHARACTERISTIC === "INT";
}

export function isInteractionSkill(item) {
return item.system.CHARACTERISTIC === "PRE";
}

async function _renderSkillForm(item, actor, stateData) {
const token = actor.token;

// Skill Levels (in most cases it will apply so check it)
let skillLevels = Array.from(actor.items.filter((o) => o.system.XMLID === "SKILL_LEVELS"));
for (let s of skillLevels) {
s.system.checked = false;
s.system.active = true;
const skillLevels = actor.items.filter((o) => o.system.XMLID === "SKILL_LEVELS");
for (const skill of skillLevels) {
skill.system.checked = false;
skill.system.active = true;

// OPTION_ALIAS has name of skill
if (s.system.OPTION_ALIAS.toUpperCase().indexOf(item.name.toUpperCase()) > -1) {
s.system.checked = true;
if (skill.system.OPTION_ALIAS.toUpperCase().indexOf(item.name.toUpperCase()) > -1) {
skill.system.checked = true;
}

// OPTION_ALIAS has XMLID of skill
if (s.system.OPTION_ALIAS.toUpperCase().indexOf(item.system.XMLID) > -1) {
s.system.checked = true;
if (skill.system.OPTION_ALIAS.toUpperCase().indexOf(item.system.XMLID) > -1) {
skill.system.checked = true;
}

// CHARACTERISTIC match
if (s.name.toUpperCase().indexOf(item.system.CHARACTERISTIC) > -1) {
s.system.checked = true;
if (skill.name.toUpperCase().indexOf(item.system.CHARACTERISTIC) > -1) {
skill.system.checked = true;
}

// INTERACTION match (really PRE match)
if (s.name.toUpperCase().indexOf("INTERACTION") > -1 && item.system.CHARACTERISTIC === "PRE") {
s.system.checked = true;
if (skill.name.toUpperCase().indexOf("INTERACTION") > -1 && item.system.CHARACTERISTIC === "PRE") {
skill.system.checked = true;
}
}

// Certain skills/talents/powers may help or hinder this roll
const helperItems = [];
if (isInteractionSkill(item)) {
// Striking appearance may help
const strikingAppearance = actor.items.filter((item) => item.system.XMLID === "STRIKING_APPEARANCE");
for (const saTalent of strikingAppearance) {
saTalent.system.checked = false;
saTalent.system.active = true;
helperItems.push(saTalent);
}
}

// Enhanced Perception + Skill Levels
const skillMods = [
...skillLevels,
...helperItems,
...(item.system.XMLID === "PERCEPTION"
? actor.items.filter((o) => o.system.XMLID === "ENHANCEDPERCEPTION")
: []),
Expand Down
55 changes: 44 additions & 11 deletions module/utility/presence-attack.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,76 @@ import { HeroRoller } from "./dice.mjs";
async function _renderForm(actor, stateData) {
const token = actor.token;

// Certain skills/talents/powers may help or hinder this roll
const attackMods = [];
// Striking appearance may help
const strikingAppearance = actor.items.filter((item) => item.system.XMLID === "STRIKING_APPEARANCE");
for (const saTalent of strikingAppearance) {
saTalent.system.checked = false;
saTalent.system.active = true;
attackMods.push(saTalent);
}

const templateData = {
actor: actor.system,
tokenId: token?.uuid || null,
state: stateData,
preAttackMods: attackMods,
};

var path = `systems/${HEROSYS.module}/templates/pop-out/presence-attack-card.hbs`;

const path = `systems/${HEROSYS.module}/templates/pop-out/presence-attack-card.hbs`;
return await renderTemplate(path, templateData);
}

async function presenceAttackRoll(actor, html) {
const form = html[0].querySelector("form");
const rollModifier = parseFloat(form.mod.value);

const presence = parseInt(actor.system.characteristics.pre.value);
const presenceDice = presence / 5;
const partialDice = presenceDice % 1;

const heroRoller = new HeroRoller()
const preAttackRoller = new HeroRoller()
.makeBasicRoll()
.addDice(Math.trunc(presenceDice), "Presence Attack")
.addHalfDice(Math.sign(partialDice) * (Math.abs(partialDice) >= 0.5 ? 1 : 0), "Presence Attack")
.addHalfDice(Math.sign(partialDice) * (Math.abs(partialDice) >= 0.5 ? 1 : 0), "Presence Attack Half Dice")
.addDice(Math.trunc(rollModifier), "Roll Modifier")
.addHalfDice(Math.abs(rollModifier) % 1 >= 0.5 ? 1 : 0, "Roll Modifier");
await heroRoller.roll();

const cardHtml = await heroRoller.render("Presence Attack");
// Presence Attack Modifiers
const preAttackModInputs = form.querySelectorAll("INPUT:checked");
for (const preAttackInput of preAttackModInputs) {
const preAttack = actor.items.get(preAttackInput.id);
const levels = parseInt(preAttack.system.LEVELS || 0);
if (levels > 0) {
preAttackRoller.addDice(levels, preAttack.name);
}
}

await preAttackRoller.roll();

const rollHtml = await preAttackRoller.render("Presence Attack");
const tags = await preAttackRoller.tags();

// render card
const token = actor.token;
const speaker = ChatMessage.getSpeaker({ actor: actor, token });
speaker.alias = actor.name;

const cardData = {
tags: tags.map((tag) => {
return { ...tag, value: tag.value.signedString() };
}),
rolls: preAttackRoller.rawRolls(),
renderedRoll: rollHtml,
user: game.user._id,
speaker: speaker,
};
const template = `systems/${HEROSYS.module}/templates/chat/presence-attack-result-card.hbs`;
const cardHtml = await renderTemplate(template, cardData);

const chatData = {
style: CONST.CHAT_MESSAGE_STYLES.OOC,
rolls: heroRoller.rawRolls(),
rolls: preAttackRoller.rawRolls(),
author: game.user._id,
content: cardHtml,
speaker: speaker,
Expand All @@ -47,7 +82,7 @@ async function presenceAttackRoll(actor, html) {
return ChatMessage.create(chatData);
}

async function presenceAttackPopOut(actor) {
export async function presenceAttackPopOut(actor) {
const content = await _renderForm(actor, {});

// Attack Card as a Pop Out
Expand All @@ -72,5 +107,3 @@ async function presenceAttackPopOut(actor) {
new Dialog(data, options).render(true);
});
}

export { presenceAttackPopOut };
14 changes: 14 additions & 0 deletions templates/chat/presence-attack-result-card.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{ log 'HEROSYS presence-attack-result-card' this }}
<div class="hero chat-card">
<div class="card-section tags">
{{#each tags as |tag id|}}
<span class="tag tag-transparent" {{#if tag.title}}title="{{tag.title}}"{{/if}}>{{tag.name}}
{{tag.value}}
</span>
{{/each}}
</div>

<div class="card-section">
<div class="damage-roll">{{{ renderedRoll }}}</div>
</div>
</div>
75 changes: 25 additions & 50 deletions templates/pop-out/item-skill-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,63 +8,38 @@
</header>
</div>

{{!-- {{#if skillLevels}}
<div class="form-fields csl-attack-list">
<div class="hero chat-card item-card">
<h3>Verify the following Skill Levels apply to this skill.</h3>
</div>
<table>
{{#each skillLevels}}
<tr>
<td>
<input type="checkbox" id="{{this.id}}" {{checked this.system.checked}} data-dtype="Boolean" />
</td>
<td class="left">
<b>{{this.name}}</b>: {{this.system.description}}
</td>
</tr>
{{/each}}
</table>
</div>
{{/if}} --}}

<div class="form-group">
<label>Roll Modifier</label>
<label>Roll Modifier<br>(- is harder, + is easier)</label>
<input type="number" name="mod" value="0" />
</div>

{{#if skillMods.length}}
<div class="form-group">
<label>Skill Mods</label>
<label>Skill Modifiers</label>
<table>
{{#each skillMods}}
{{#if this.system.active}}
<tr>
<td style="width:1%">
<input class="item-toggle" id="{{this.id}}" type="checkbox" {{checked
this.system.checked}} data-dtype="Boolean" {{#if (eq this.system.OPTIONID "ALL")}}disabled{{/if}}/>
</td>
<td style="text-align:left">
{{this.system.description}}
</td>
</tr>
{{else}}
<tr title="This power is inactive" style="opacity:50%">
<td>
<i class="fas fa-ban"></i>
</td>
<td style="text-align:left">
{{this.system.description}}
</td>
</tr>
{{/if}}
{{/each}}
{{#each skillMods}}
{{#if this.system.active}}
<tr>
<td style="width:1%">
<input class="item-toggle" id="{{this.id}}" type="checkbox" {{checked
this.system.checked}} data-dtype="Boolean"/>
</td>
<td style="text-align:left">
{{this.system.description}}
</td>
</tr>
{{else}}
<tr title="This power is inactive" style="opacity:50%">
<td>
<i class="fas fa-ban"></i>
</td>
<td style="text-align:left">
{{this.system.description}}
</td>
</tr>
{{/if}}
{{/each}}
</table>
</div>
</div>
{{/if}}

<hr>
<div>
<center><h4>(- is harder, + is easier)</h4></center>
</div>
</form>
30 changes: 30 additions & 0 deletions templates/pop-out/presence-attack-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,34 @@
<label>Roll Modifier</label>
<input type="number" name="mod" value="0"/>
</div>

{{#if preAttackMods.length}}
<div class="form-group">
<label>Attack Modifiers</label>
<table>
{{#each preAttackMods}}
{{#if this.system.active}}
<tr>
<td style="width:1%">
<input class="item-toggle" id="{{this.id}}" type="checkbox" {{checked
this.system.checked}} data-dtype="Boolean"/>
</td>
<td style="text-align:left">
{{this.system.description}}
</td>
</tr>
{{else}}
<tr title="This power is inactive" style="opacity:50%">
<td>
<i class="fas fa-ban"></i>
</td>
<td style="text-align:left">
{{this.system.description}}
</td>
</tr>
{{/if}}
{{/each}}
</table>
</div>
{{/if}}
</form>

0 comments on commit 6539fdf

Please sign in to comment.