initial commit of symbiote files

This commit is contained in:
CPTN Cosmo 2025-05-10 01:47:53 +02:00 committed by GitHub
parent f68347fb48
commit b4c05b8e84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 278 additions and 0 deletions

39
manifest.json Normal file
View file

@ -0,0 +1,39 @@
{
"manifestVersion": 1,
"name": "Daggerheart Dice Roller",
"summary": "A Symbiote to roll duality dice with advantage or disadvantage",
"entryPoint": "/roll.html",
"descriptionFilePath": "/readme.md",
"version": "0.1",
"about": {
"website": "https://example.com",
"authors": [
"Jane Doe",
"John Doe"
]
}, "license": "GPL-3.0",
"api": {
"version": "0.1",
"subscriptions": {
"dice": {
"onRollResults": "handleRollResult"
}
}
},
"environment": {
"webViewBackgroundColor": "#000000",
"capabilities": [
"runInBackground"
],
"extras": [
"fonts",
"colorStyles"
]
}
}

9
readme.md Normal file
View file

@ -0,0 +1,9 @@
This is a very simple Duality Dice Roller for Daggerheart
Just add your modifiers (if any, can be positive or negative),
and if it applies select Advantage/Disatvantage.
As soon as you click the "Roll Duality Dice" Button the roll gets added to the tray,
from which you can roll the dice like any other roll.
The result then gets shown int the chat with colored formatting.

86
roll.css Normal file
View file

@ -0,0 +1,86 @@
/* roll.css */
body {
margin: 0;
padding: 2rem;
background-color: #121212;
color: #e7c74b;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
h1 {
font-size: 2rem;
margin-bottom: 2rem;
color: #e7c74b;
text-align: center;
}
.content-row {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1.5rem;
max-width: 300px;
margin-left: auto;
margin-right: auto;
}
.field-title {
font-size: 1rem;
color: #e7c74b;
}
input[type="number"],
select {
font-size: 1.25rem;
padding: 0.75rem 1rem;
border-radius: 8px;
border: 1px solid #333;
background-color: #1e1e1e;
color: #ffffff;
outline: none;
transition: border-color 0.3s;
}
input[type="number"]:focus,
select:focus {
border-color: #5dade2;
}
button {
padding: 0.75rem 1.5rem;
font-size: 1.25rem;
background-color: #5dade2;
color: #121212;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s;
align-self: center;
}
button:hover {
background-color: #3498db;
}
.spacer {
height: 1rem;
}
/* Prevent scrollbar on dropdown */
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-image: url('data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/></svg>');
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 1rem;
padding-right: 2rem;
}
/* Optional: hide scrollbar in Firefox */
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #ffffff;
}

28
roll.html Normal file
View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Daggerheart Dice Roller</title>
<link rel="stylesheet" href="roll.css">
<script src="roll.js"></script>
</head>
<body>
<h1 style="margin-top: 0">Duality Dice Roll</h1>
<div class="content-row">
<label class="field-title" for="modifier">Modifier</label>
<input id="modifier" type="number" placeholder="0"></input>
</div>
<div class="content-row">
<label class="field-title" for="adv-disadv">Advantage/Disadvantage</label>
<select id="adv-disadv" size="1">
<option value="none">None</option>
<option value="advantage">Advantage</option>
<option value="disadvantage">Disadvantage</option>
</select>
</div>
<div class="content-row">
<span class="spacer"></span>
<button id="roll-duality" onclick="rollDualityDice()">Roll Duality Dice</button>
</div>
</body>
</html>

116
roll.js Normal file
View file

@ -0,0 +1,116 @@
let trackedIds = {};
let isGM = false;
let me;
function roll(type) {
let name = document.getElementById("roll-name").value || "Check";
let dice = document.getElementById("roll-content").value || "1d20";
let typeStr = type == "advantage" ? " (Adv)" : " (Disadv)";
TS.dice.putDiceInTray([{ name: name + typeStr, roll: dice }, { name: name + typeStr, roll: dice }], true).then((diceSetResponse) => {
trackedIds[diceSetResponse] = type;
});
}
async function rollDualityDice() {
const modifier = parseInt(document.getElementById("modifier").value) || 0;
const advDisadv = document.getElementById("adv-disadv").value;
// Define the dice groups
const diceGroups = [
{ name: "Hope", roll: "1d12", color: "yellow" },
{ name: "Fear", roll: "1d12", color: "purple" }
];
// Add advantage/disadvantage if applicable
if (advDisadv === "advantage") {
diceGroups.push({ name: "Advantage", roll: "1d6" });
} else if (advDisadv === "disadvantage") {
diceGroups.push({ name: "Disadvantage", roll: "1d6" });
}
// Roll the dice
const diceSetResponse = await TS.dice.putDiceInTray(diceGroups, true);
trackedIds[diceSetResponse] = { modifier, advDisadv };
}
async function handleRollResult(rollEvent) {
if (!trackedIds[rollEvent.payload.rollId]) {
return;
}
const trackedData = trackedIds[rollEvent.payload.rollId];
const { modifier, advDisadv } = trackedData;
if (rollEvent.kind === "rollResults") {
const roll = rollEvent.payload;
let hopeResult = 0;
let fearResult = 0;
let advDisadvResult = 0;
for (const group of roll.resultsGroups) {
const groupSum = await TS.dice.evaluateDiceResultsGroup(group);
if (group.name === "Hope") {
hopeResult = groupSum;
} else if (group.name === "Fear") {
fearResult = groupSum;
} else if (group.name === "Advantage" || group.name === "Disadvantage") {
advDisadvResult = groupSum;
}
}
// Calculate the final result
let totalResult = hopeResult + fearResult + modifier;
if (advDisadv === "advantage") {
totalResult += advDisadvResult;
} else if (advDisadv === "disadvantage") {
totalResult -= advDisadvResult;
}
// Determine the outcome
let outcome = "";
if (hopeResult === fearResult) {
outcome = "Critical Success!";
} else if (hopeResult > fearResult) {
outcome = "With Hope";
} else {
outcome = "With Fear";
}
// Display the result in the in-game chat message
let outcomeColor = "#FFFFFF";
if (outcome === "Critical Success!") {
outcomeColor = "#00FF00"; // Green
} else if (outcome === "With Hope") {
outcomeColor = "#4FC3F7"; // Light Blue
} else if (outcome === "With Fear") {
outcomeColor = "#E57373"; // Red
}
const chatMessage = {
content:
`<b>Roll Result:</b> ` +
`<color=#FFD700>Hope ${hopeResult}</color> + ` +
`<color=#B388FF>Fear ${fearResult}</color>` +
`${modifier !== 0 ? ` + Modifier ${modifier}` : ""}` +
`${advDisadvResult !== 0 ? ` + <i>${advDisadv === "advantage" ? "Adv" : "Dis"} ${advDisadvResult}</i>` : ""} = ` +
`<br><b><color=#FFFFFF>${totalResult}</color></b> ` +
` <i><color=${outcomeColor}>${outcome}</color></i>`,
rollId: roll.rollId,
expanded: true
};
TS.chat.send(chatMessage.content, "board").catch((response) => console.error("error in sending chat message", response));
// Display the result in the console
console.log(`Total Result: ${totalResult} (${outcome})`);
displayResult(roll.resultsGroups, roll.rollId);
} else if (rollEvent.kind === "rollRemoved") {
delete trackedIds[rollEvent.payload.rollId];
}
}
async function displayResult(resultGroup, rollId) {
TS.dice.sendDiceResult(resultGroup, rollId).catch((response) => console.error("error in sending dice result", response));
}