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

Dev #21

Merged
merged 4 commits into from
Aug 7, 2022
Merged

Dev #21

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ Aug 1, 2022
## v0.0.8
Aug 2, 2022
* Fix issue with fudges dialog from Times removal

## v0.0.9
Aug 7, 2022
* Lots of refactoring to cleanup code
* Remove fudges for actors
* Simple and Avg Karma
35 changes: 31 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ Currently being (quasi) managed here: https://github.com/users/UranusBytes/proje
Extensive logging is used within the module, with debug logging enabled with the package debugging enabled

## Known Issues
* Raw die rolls for actors not working (even if fudge defined on GM/Player)
* It's possible to define a fudge that is impossible to achieve (especially when considering modifiers. Or to define a fudge of "> 20" for a d20). The failsafe is attempting to fudge 150 times, at which point the closest possible is provided.
* When the fudge config dialog is open, fudge status/list is not updated if any are changed by other GMs and/or PC/Actor rolls
* Completely incompatible with [Better Rolls for 5e](https://github.com/RedReign/FoundryVTT-BetterRolls5e) #6
* If both Fudge and Karma are enabled, a single roll that's being fudged can be influed by karma

# Current module Functionality
## Fudge
Allow the GM to influence raw die rolls (just the dice) or roll totals (dice + modifiers)
## Karma
Keep a history of die rolls per user, and if they are below a threshold over a defined history, either force the next roll to be above a minimum value (Simple), or increase the roll by a small amount until the average is above the threshold (Average)

# Global Config
The individual functionality can be enabled/disabled within the module settings
![die-hard-fudge](docs/die-hard-config.jpg)

# Fudge
![die-hard-fudge](docs/die-hard-fudge.jpg)
Expand Down Expand Up @@ -70,16 +76,37 @@ A green circular arrow means the fudge will re-enable itself after being used (p

![die-hard-fudge-3](docs/die-hard-fudge-3.jpg)

# Mechanics
## Mechanics
The way Fudge works is that the next die roll of that type (either system specific, total result w/ modifiers, or a raw die roll) for that Player or Actor will be evaluated against the formula defined. If it doesn't meet the formula criteria, then the result is rerolled in the background (max of 150 times), with the final result presented to the PC. As it is re-rolling, if the attempted re-roll is "closer" to the desired fudge value, it will be kept. (For circumstances where the fudge can never be achieved, at least get as close as possible) The GM will get a whisper that outlines if the fudge was used (with all failed results), or if it was removed without being used (if first roll met formula criteria). When a fudge is used to influence a die (or would have, but original result was sufficient), then the fudge is disabled (unless persistence is enabled).

![die-hard-fudge-4](docs/die-hard-fudge-4.jpg)

# Karma
![die-hard-fudge](docs/die-hard-karma.jpg)

With the module enabled, a praying hands icon will be displayed above the message tray.

![die-hard-fudge](docs/die-hard-karma-0.jpg)

Clicking on this icon will open a configuration dialog.
The available karma options can be enabled by clicking on the button

![die-hard-fudge](docs/die-hard-karma-1.jpg)

Within the dialog, the logic used to influence each Karma module is adjustable.
The current history of player rolls is displayed.

![die-hard-fudge-2](docs/die-hard-karma-2.jpg)


# Mechanics
Karma only works on raw die rolls; it does not influence total rolls directly (only indirectly by influencing the raw rolls)



# Future Planned Functionality
## Karmic dice
All for gradual adjustment/influence of player dice over time...
## RNG Alternatives
Alternative RNG

# Thanks
None of this module would be possible without the inspiration, and continued guidance/support/feedback, from @apoapostolov. Thank you!
Binary file added docs/die-hard-config.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/die-hard-fudge-2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/die-hard-karma-0.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/die-hard-karma-1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/die-hard-karma-2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/die-hard-karma.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion module.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"title": "Die Hard",
"description": "Adjustments for DND5e & PF2e die rolls like fudging...",
"author": "Jeremy (UranusBytes)",
"version": "0.0.8",
"version": "0.0.9",
"minimumCoreVersion": "9",
"compatibleCoreVersion": "9",
"esmodules": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Because this extends D20Roll, I could not find a clean way to import. I tried m
import D20Roll from '../../../../systems/dnd5e/module/dice/d20-roll.js'
import {dieHardLog} from "../lib/helpers.js";

export default class DieHardFudgeD20Roll extends D20Roll {
export default class DISABLED_DieHardFudgeD20Roll extends D20Roll {
// This is a simple extension
constructor(formula, data, options) {
super(formula, data, options);
Expand Down
251 changes: 222 additions & 29 deletions scripts/classes/DieHard.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,239 @@
import {dieHardLog, insertAfter} from "../lib/helpers.js";
import DieHardFudgeDialog from "./DieHardFudgeDialog.js";
import {dieHardLog, insertAfter} from '../lib/helpers.js';
import DieHardFudgeDialog from './DieHardFudgeDialog.js';
import DieHardKarmaDialog from './DieHardKarmaDialog.js';
import DieHardDnd5e from './DieHardDnd5e.js';
import DieHardPf2e from './DieHardPf2e.js';

export const DieHardSetting = (setting) => game.settings.get('foundry-die-hard', setting);

export default class DieHard {

constructor() {
dieHardLog(true, 'DieHard - constructor');
}

static renderDieHardIcons() {
dieHardLog(false, 'DieHard.renderDieHardIcons')
if (DieHardSetting('dieHardSettings').system == null) {
dieHardLog(false, 'Unsupported system for world; not rendering side bar')
return
}
dieHardLog(false, 'Render side bar')

if (document.querySelector('.die-hard-pause-fudge-icon') === null) {
let fudgeButton = document.createElement('label');
fudgeButton.classList.add('die-hard-fudge-icon');
fudgeButton.innerHTML = '<span title="Fudge Paused"><i id="die-hard-pause-fudge-icon" class="fas fa-pause-circle die-hard-icon-hidden"></i></span><span title="Fudge"><i id="die-hard-fudge-icon" class="fas fa-poop"></i></span>';
fudgeButton.addEventListener('click', async (ev) => {
new DieHardFudgeDialog().render(true);
});
fudgeButton.addEventListener('contextmenu', async (ev) => {
game.settings.get('foundry-die-hard', 'dieHardSettings').system.disableAllFudges();
});

// ToDo: Fix this ugly hack
// the document object isn't existing sometimes yet, so just ignore. It'll eventually render
try {
//insertAfter(pauseButton, document.querySelector('.chat-control-icon'));
insertAfter(fudgeButton, document.querySelector('.chat-control-icon'));
//DieHardSetting('dieHardSettings').system.refreshActiveFudgesIcon()
}
catch (e) { }
}

// Setup default settings;
if (document.querySelector('.die-hard-karma-icon') === null) {
let karmaButton = document.createElement('label');
karmaButton.classList.add('die-hard-karma-icon');
karmaButton.innerHTML = '<span title="Karma"><i id="die-hard-karma-icon" class="fas fa-praying-hands"></i></span>';
karmaButton.addEventListener('click', async (ev) => {
new DieHardKarmaDialog().render(true);
});

// ToDo: Fix this ugly hack
// the document object isn't existing sometimes yet, so just ignore. It'll eventually render
try {
insertAfter(karmaButton, document.querySelector('.chat-control-icon'));
} catch (e) {
}
}
DieHard.refreshDieHardIcons();
}

init() {
dieHardLog(true, 'DieHard - init');
static getDefaultDieHardSettings() {
dieHardLog(false, 'DieHard.getDefaultDieHardSettings')
let dieHardSettings = {
system: null,
debug: {
allActors: true
},
fudgeConfig: {
maxFudgeAttemptsPerRoll: 150,
globalDisable: false
},
gmFudges: []
};

if (game.system.id == 'dnd5e') {
dieHardLog(true, 'Configuring for dndn5e system')
dieHardSettings.system = new DieHardDnd5e;
} else if (game.system.id == 'pf2e') {
dieHardLog(true, 'Configuring for pf2e system')
dieHardSettings.system = new DieHardPf2e;
} else {
dieHardLog(true, 'Unsupport game system: ' + game.system.id)
}
return dieHardSettings
}

static renderFudgeIcon() {
if (game.settings.get('foundry-die-hard', 'dieHardSettings').system == null) {
dieHardLog(false, 'Unsupported system for world; not rendering side bar')
return
static getDefaultSimpleKarmaSettings() {
return {
enabled: true,
history: 5,
threshold: 5,
floor: 5
}
dieHardLog(false, 'Render side bar')
let fudgeButton = document.createElement('label');
//fudgeButton.setAttribute('id', 'die-hard-fudge-icon');
fudgeButton.classList.add('die-hard-fudge-icon');
// fudgeButton.innerHTML = '<div class="die-hard-pause-fudge-overlay"><i id="die-hard-pause-fudge-icon" class="fas fa-pause-circle"></i></div><i id="die-hard-fudge-icon" class="fas fa-poop"></i>';
fudgeButton.innerHTML = '<span title="Fudge Paused"><i id="die-hard-pause-fudge-icon" class="fas fa-pause-circle die-hard-icon-hidden"></i></span><span title="Fudge"><i id="die-hard-fudge-icon" class="fas fa-poop"></i></span>';

fudgeButton.addEventListener("click", async (ev) => {
new DieHardFudgeDialog().render(true);
});
fudgeButton.addEventListener("contextmenu", async (ev) => {
game.settings.get('foundry-die-hard', 'dieHardSettings').system.disableAllFudges();
});

// ToDo: Fix this ugly hack
// the document object isn't existing sometimes yet, so just ignore. It'll eventually render
try {
//insertAfter(pauseButton, document.querySelector('.chat-control-icon'));
insertAfter(fudgeButton, document.querySelector('.chat-control-icon'));
game.settings.get('foundry-die-hard', 'dieHardSettings').system.refreshActiveFudgesIcon()
}

static getAvgSimpleKarmaSettings() {
return {
enabled: true,
history: 5,
threshold: 5,
nudge: 5
}
}

static registerSettings() {
dieHardLog(false, 'DieHard.registerSettings')

// Enables fudge
game.settings.register('foundry-die-hard', 'fudgeEnabled', {
name: 'Fudge Enabled',
hint: 'Fudge Enabled',
scope: 'world',
config: true,
default: true,
type: Boolean,
onChange: DieHard.refreshDieHardStatus
});

// Enables karma
game.settings.register('foundry-die-hard', 'karmaEnabled', {
name: 'Karma Enabled',
hint: 'Karma Enabled',
scope: 'world',
config: true,
default: true,
type: Boolean,
onChange: DieHard.refreshDieHardStatus
});

// Enables debug die
game.settings.register('foundry-die-hard', 'debugDieResultEnabled', {
name: 'Debug Die Result Enabled',
hint: 'Enable the use of Debug Die Result',
scope: 'world',
config: true,
default: true,
type: Boolean
});
game.settings.register('foundry-die-hard', 'debugDieResult', {
name: 'Debug Die Result',
hint: 'Make every initial roll of die value',
scope: 'world',
config: true,
default: 5,
type: Number,
range: {
min: 1,
max: 20,
step: 1
}
});

game.settings.register('foundry-die-hard', 'dieHardSettings', {
name: '',
default: DieHard.getDefaultDieHardSettings(),
type: Object,
scope: 'world',
config: false,
});

// Enables fudge
game.settings.register('foundry-die-hard', 'simpleKarmaSettings', {
name: 'Simple Karma Settings',
hint: 'Simple Karma Settings',
scope: 'world',
config: false,
default: DieHard.getDefaultSimpleKarmaSettings(),
type: Object
});

// Enables karma
game.settings.register('foundry-die-hard', 'avgKarmaSettings', {
name: 'Average Karma Settings',
hint: 'Average Karma Settings',
scope: 'world',
config: false,
default: DieHard.getAvgSimpleKarmaSettings(),
type: Object
});


}

static async refreshDieHardStatus() {
dieHardLog(false, 'DieHard.refreshDieHardStatus');
await DieHard.refreshDieHardIcons()
DieHardSetting('dieHardSettings').system.refreshActiveFudgesIcon()
}

static async refreshDieHardIcons() {
dieHardLog(false, 'DieHard.refreshDieHardIcons');
// Ugly fix for objects not existing yet
// ToDo: clean this up
try{
if (DieHardSetting('fudgeEnabled')) {
if (DieHardSetting('dieHardSettings').fudgeConfig.globalDisable) {
document.getElementById('die-hard-pause-fudge-icon').classList.remove('die-hard-icon-hidden');
document.getElementById('die-hard-fudge-icon').classList.add('die-hard-icon-hidden');
return;
} else {
document.getElementById('die-hard-pause-fudge-icon').classList.add('die-hard-icon-hidden');
document.getElementById('die-hard-fudge-icon').classList.remove('die-hard-icon-hidden');
}
if (DieHardSetting('dieHardSettings').system.hasActiveFudges()) {
document.getElementById('die-hard-fudge-icon').classList.add('die-hard-fudge-icon-active');
} else {
document.getElementById('die-hard-fudge-icon').classList.remove('die-hard-fudge-icon-active');
}
} else {
document.getElementById('die-hard-pause-fudge-icon').classList.add('die-hard-icon-hidden');
document.getElementById('die-hard-fudge-icon').classList.add('die-hard-icon-hidden');
}

if (DieHardSetting('karmaEnabled')) {
document.getElementById('die-hard-karma-icon').classList.remove('die-hard-icon-hidden');
} else {
document.getElementById('die-hard-karma-icon').classList.add('die-hard-icon-hidden');
}
}
catch (e) { }
}

static async dmToGm(message) {
var dm_ids = [];
for (let user of game.users.values()) {
if (user.isGM) {
dm_ids.push(user.id)
}
}
ChatMessage.create({
user: game.user.id,
type: CONST.CHAT_MESSAGE_TYPES.WHISPER,
whisper: dm_ids,
blind: true,
content: message
})
}
}
Loading